打通前端 ws.ts 里那批死消费者事件(thinking/mood/tool_used/subagent_event/
task_output/device_update/reminder/backthink),并给 loop 接真 token 流式。
- wire.go:loop 建时传 OnStream(streamChunk 闭包把 delta 发 bus ws.stream_chunk);
gateway.Deps 注入 Scheduler/Tasks/Streaming;iot 接共享总线 iot.WithBus(a.bus)。
- ws_bridge.go:hub 额外订阅 iot.>/task.>/automation.>/reminder.>/cyrene.agent.*.event,
normalizeEvent 归一为 ws.*(device_update/task_output/task_done/automation_result/
reminder/subagent_event);不订阅 cyrene.agent.> 以免 ask/reply 内部事件进 relay。
- ws_route.go:voice_input→ws.voice_input;subagent_ask→Scheduler.AuditContext(真实
上下文审计,替换 pending stub);task_output_query→Manager.TaskOutput(真实输出,
替换空 {})。
- server.go:新增 SubagentAuditor/TaskOutputStore 接口 + Deps.Scheduler/Tasks/Streaming。
- orchestration/auditcontext.go:Scheduler.AuditContext(full/tail/keyword)。
- task/manager.go:Manager.TaskOutput(id)。
- backthink:record() 补发 ws.backthink 事件。
- json tag 修正(device_update/reminder/task output 结构体加小写 tag + DeviceUpdate
补 message),使前端分支能真正渲染。
实机验证:WS 握手 101、task manager ready、iot manager initialized(WithBus 生效)。
go build/vet/test 全绿;TestHubBridgeDeviceUpdate/TestHubBridgeSubagentProgress 覆盖
映射。dev 推至后续版本。
58 lines
1.8 KiB
Go
58 lines
1.8 KiB
Go
package orchestration
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/orchestration/audit"
|
|
)
|
|
|
|
// TestSchedulerAuditContext exercises the subagent_ask audit path across the full,
|
|
// tail and keyword windows, plus the not-found and blank-query errors.
|
|
func TestSchedulerAuditContext(t *testing.T) {
|
|
t.Parallel()
|
|
s := New(Options{MaxParallel: 2, AgentID: "orchestrator"})
|
|
ctx := context.Background()
|
|
|
|
msgs := []model.Message{
|
|
model.TextMessage(model.RoleUser, "hello"),
|
|
model.TextMessage(model.RoleAssistant, "hi there"),
|
|
}
|
|
s.mu.Lock()
|
|
s.agents["sub-1"] = &SubAgent{ID: "sub-1", Goal: "do it", Context: msgs, status: StatusRunning}
|
|
s.mu.Unlock()
|
|
|
|
full, err := s.AuditContext(ctx, "sub-1", AuditFull, 0, "")
|
|
if err != nil {
|
|
t.Fatalf("audit full: %v", err)
|
|
}
|
|
if full.AgentID != "sub-1" || full.Status != StatusRunning || len(full.Messages) != 2 {
|
|
t.Fatalf("full = %+v, want sub-1/running/2 msgs", full)
|
|
}
|
|
|
|
tail, err := s.AuditContext(ctx, "sub-1", AuditTail, 1, "")
|
|
if err != nil {
|
|
t.Fatalf("audit tail: %v", err)
|
|
}
|
|
if len(tail.Messages) != 1 || tail.Messages[0].Content[0].Text != "hi there" {
|
|
t.Fatalf("tail = %+v, want last message 'hi there'", tail)
|
|
}
|
|
|
|
kw, err := s.AuditContext(ctx, "sub-1", AuditKeyword, 0, "hello")
|
|
if err != nil {
|
|
t.Fatalf("audit keyword: %v", err)
|
|
}
|
|
if kw.Line != 1 || len(kw.Messages) != 2 {
|
|
t.Fatalf("keyword = %+v, want line 1 with 2 surrounding msgs", kw)
|
|
}
|
|
|
|
if _, err := s.AuditContext(ctx, "nope", AuditFull, 0, ""); !errors.Is(err, ErrAgentNotFound) {
|
|
t.Fatalf("want ErrAgentNotFound, got %v", err)
|
|
}
|
|
if _, err := s.AuditContext(ctx, "sub-1", AuditKeyword, 0, " "); !errors.Is(err, audit.ErrQueryEmpty) {
|
|
t.Fatalf("want ErrQueryEmpty, got %v", err)
|
|
}
|
|
}
|