cdc5b3a847
把任务执行做成可观测:Dispatcher 在每个节点/阶段发结构化 ExecEvent, 经独立 NATS 通道回流,前端逐节点点亮(状态/耗时/工具入参产出)。 - shared: contract.ExecEvent + ExecSubject(sundynix.exec.<id>,与 Token 流分流); bus.PublishExec/CompleteExec/SubscribeExec(core NATS,复用结束头) - dispatcher: execTracer(自增 Seq 保序 + span 自动计耗时); Orchestrator 加 ExecSink;通用图(init 召回 / 各 tool 入参→产出 / prompt / model 首token+token数)与报告编排(规划大纲 / 各章并行 start-end / 渲染)全程埋点 - gateway: SubscribeExec + GET /tasks/:id/exec SSE(与 token 流并行) - desktop: streamExec + deriveNodes(按 node 归并 start/end/error/info); 复用组件 ExecTrace(竖向轨道,按 kind 着色,运行中脉冲灯); 新 RunsView(运行·观测:轨迹+输出双栏);BottomDrawer 轨迹/工具调用 tab 接真实数据; ReportView 加执行轨迹栏;左导航「运行」置就绪 实测: - 报告任务 /exec:规划(2680ms,4章) → 4 章并行(seq 交错,各~7-8s 重叠=真并行, 每章带 docs 知识库检索预览+成稿字数) → 渲染(docx 落盘) - 通用图 /exec:tool:kb_search(678ms,入参→Milvus 产出) → prompt(2消息) → model(首token 860ms / 4 tokens) - 浏览器(Preview):报告页执行轨迹逐节点点亮、章节带耗时/字数/检索片段,完成后下载 Word Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
80 lines
2.7 KiB
Go
80 lines
2.7 KiB
Go
// Package nats 是网关对共享 bus 的薄封装(发布任务 / 订阅 Token 回流)。
|
|
package nats
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"log"
|
|
|
|
sharedbus "github.com/sundynix/sundynix-shared/bus"
|
|
"github.com/sundynix/sundynix-shared/contract"
|
|
)
|
|
|
|
// Bus 包装共享 bus,向网关其余代码暴露发布能力。
|
|
type Bus struct {
|
|
inner *sharedbus.Bus
|
|
}
|
|
|
|
// MustConnect 接入 NATS 并确保任务流存在。
|
|
func MustConnect(url string) *Bus {
|
|
inner, err := sharedbus.Connect(url)
|
|
if err != nil {
|
|
log.Fatalf("[nats] connect: %v", err)
|
|
}
|
|
if err := inner.EnsureTaskStream(context.Background()); err != nil {
|
|
log.Fatalf("[nats] ensure stream: %v", err)
|
|
}
|
|
log.Printf("[nats] connected %s, task stream ready", url)
|
|
return &Bus{inner: inner}
|
|
}
|
|
|
|
// PublishTask 把组装后的 Task 发布到 sundynix.tasks.<id>。
|
|
func (b *Bus) PublishTask(ctx context.Context, t *contract.Task) error {
|
|
seq, err := b.inner.PublishTask(ctx, t)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Printf("[nats] published task %s (seq=%d)", t.ID, seq)
|
|
return nil
|
|
}
|
|
|
|
// SubscribeTokens 订阅 sundynix.streams.<taskID> 的 Token 回流,
|
|
// 每个 Token 触发 onToken,流结束触发 onDone,返回 unsub。
|
|
func (b *Bus) SubscribeTokens(taskID string, onToken func([]byte), onDone func()) (func() error, error) {
|
|
return b.inner.SubscribeTokens(taskID, onToken, onDone)
|
|
}
|
|
|
|
// SubscribeExec 订阅 sundynix.exec.<taskID> 的执行轨迹事件(用于"运行·观测"SSE)。
|
|
func (b *Bus) SubscribeExec(taskID string, onEvent func([]byte), onDone func()) (func() error, error) {
|
|
return b.inner.SubscribeExec(taskID, onEvent, onDone)
|
|
}
|
|
|
|
// CallTool 经 NATS 同步调用一个 MCP 工具(用于网关侧写偏好记忆等)。
|
|
func (b *Bus) CallTool(ctx context.Context, subject string, call *contract.ToolCall) (*contract.ToolResult, error) {
|
|
return b.inner.CallTool(ctx, subject, call)
|
|
}
|
|
|
|
// ServeConfig 让网关作为配置控制面,响应某 kind 的配置请求。
|
|
func (b *Bus) ServeConfig(kind string, provide func() *contract.ModelConfig) (func() error, error) {
|
|
return b.inner.ServeConfig(kind, provide)
|
|
}
|
|
|
|
// PublishConfigUpdated 广播某 kind 的配置变更。
|
|
func (b *Bus) PublishConfigUpdated(kind string, cfg *contract.ModelConfig) error {
|
|
return b.inner.PublishConfigUpdated(kind, cfg)
|
|
}
|
|
|
|
// PublishIngest 把一条入库进度事件发到 sundynix.streams.<jobID>。
|
|
func (b *Bus) PublishIngest(jobID string, ev *contract.IngestEvent) error {
|
|
data, err := json.Marshal(ev)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return b.inner.PublishToken(jobID, data)
|
|
}
|
|
|
|
// CompleteStream 发送入库流结束信号。
|
|
func (b *Bus) CompleteStream(jobID string) error { return b.inner.CompleteStream(jobID) }
|
|
|
|
func (b *Bus) Close() { b.inner.Close() }
|