feat(gateway): 地基③ 打通实时信号 producer→前端WS + loop 真流式 + 上行路由补全
打通前端 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 推至后续版本。
This commit is contained in:
1 parent
04bfa2c7a7
commit
9b207a31e8
14 files changed
+673
-109
No files matched your search
@@ -43,25 +43,25 @@ var (
|
||||
// reaches a terminal state. It carries everything the agent needs to consume the
|
||||
// result without a second lookup.
|
||||
type DoneEvent struct {
|
||||
ID string
|
||||
Kind Kind
|
||||
Status Status
|
||||
Output Output
|
||||
ExitCode int
|
||||
Truncated bool
|
||||
Error string
|
||||
StartedAt time.Time
|
||||
FinishedAt time.Time
|
||||
ID string `json:"id"`
|
||||
Kind Kind `json:"kind"`
|
||||
Status Status `json:"status"`
|
||||
Output Output `json:"output"`
|
||||
ExitCode int `json:"exitCode"`
|
||||
Truncated bool `json:"truncated"`
|
||||
Error string `json:"error,omitempty"`
|
||||
StartedAt time.Time `json:"startedAt"`
|
||||
FinishedAt time.Time `json:"finishedAt"`
|
||||
}
|
||||
|
||||
// OutputEvent is the payload published to the "task.output" subject as output
|
||||
// becomes available.
|
||||
type OutputEvent struct {
|
||||
ID string
|
||||
Kind Kind
|
||||
Status Status
|
||||
Output Output
|
||||
Truncated bool
|
||||
ID string `json:"id"`
|
||||
Kind Kind `json:"kind"`
|
||||
Status Status `json:"status"`
|
||||
Output Output `json:"output"`
|
||||
Truncated bool `json:"truncated"`
|
||||
}
|
||||
|
||||
// Manager owns the task registry and the execution lifecycle. It owns an
|
||||
@@ -230,6 +230,27 @@ func (m *Manager) Get(ctx context.Context, id string) (*Task, error) {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// TaskOutput returns the current output snapshot of task id for external
|
||||
// consumers (the gateway's task_output_query WS route). It never waits for the
|
||||
// task to finish: for a running background task it returns the output captured so
|
||||
// far. It wraps ErrNotFound with %w so callers can classify with errors.Is.
|
||||
func (m *Manager) TaskOutput(ctx context.Context, id string) (OutputEvent, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return OutputEvent{}, fmt.Errorf("task: output %q: %w", id, err)
|
||||
}
|
||||
t := m.get(id)
|
||||
if t == nil {
|
||||
return OutputEvent{}, fmt.Errorf("task: output %q: %w", id, ErrNotFound)
|
||||
}
|
||||
return OutputEvent{
|
||||
ID: t.ID,
|
||||
Kind: t.Kind,
|
||||
Status: t.Status(),
|
||||
Output: t.Output(),
|
||||
Truncated: t.Truncated(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Abort cancels the task for id. It returns ErrNotFound if there is no such task
|
||||
// and ErrAlreadyDone if the task has already finished.
|
||||
func (m *Manager) Abort(ctx context.Context, id string) error {
|
||||
|
||||
Reference in new issue
Block a user