// Package contract 是 Gateway / Dispatcher / MCP 之间的共享契约: // Task 数据结构与 NATS subject 命名约定。 package contract import "encoding/json" // NATS subject / stream 约定(与 README、各服务 config 保持一致)。 const ( StreamTasks = "SUNDYNIX_TASKS" // JetStream stream 名 SubjectTasks = "sundynix.tasks" // 任务发布主题前缀;实际为 sundynix.tasks. SubjectTasksAll = "sundynix.tasks.>" // stream 捕获的通配 SubjectStream = "sundynix.streams" // Token 回流前缀;实际 sundynix.streams. ConsumerDurable = "dispatchers" // Dispatcher 持久消费者(队列组负载均衡) // HeaderStreamEnd 是 Token 流的结束信号(core NATS 消息头)。 // 置为 "1" 的消息体为空,表示该 task 的 Token 流结束。 HeaderStreamEnd = "X-Stream-End" // MCP 工具调用约定(第 4 层 Dispatcher → 第 5 层 MCP Tools)。 // 用 core NATS request-reply:同步拿结果,队列组内负载均衡。 SubjectToolsGo = "sundynix.tools.go" // Go I/O 型工具前缀;实际 sundynix.tools.go. SubjectToolsGoAll = "sundynix.tools.go.>" // mcp-go 通配订阅 SubjectToolsPy = "sundynix.tools.py" // Python 算法型工具前缀;实际 sundynix.tools.py. SubjectToolsPyAll = "sundynix.tools.py.>" // mcp-py 通配订阅 QueueToolsGo = "mcp-go-workers" // mcp-go 队列组(多副本负载均衡) QueueToolsPy = "mcp-py-workers" // mcp-py 队列组 // MetaUserID 是 Task.Meta 中承载已登录用户标识的键(用于偏好记忆召回)。 MetaUserID = "user_id" // MetaSessionID 是 Task.Meta 中承载会话标识的键(用于短期多轮历史)。 MetaSessionID = "session_id" // 配置控制面按 kind 寻址:sundynix.config..get / .updated。 // Gateway 持有配置,消费方(Dispatcher/mcp-go)经 NATS 取用/订阅变更。 ConfigKindChat = "chat" // 对话模型(Dispatcher 用) ConfigKindEmbedding = "embedding" // 向量模型(mcp-go RAG 用) // 报告生成:Task.Meta[MetaIntent]==IntentReport 时,Dispatcher 走专用多步编排 // (规划大纲 → 各章节并行检索+撰写 → 汇聚 → 渲染 Word),而非通用对话图。 MetaIntent = "intent" IntentReport = "report" MetaTopic = "topic" // 报告主题 MetaKB = "kb" // 报告依据的知识库(可空,则不挂检索) ) // ConfigGetSubject / ConfigUpdatedSubject 返回某类配置的 request / 广播主题。 func ConfigGetSubject(kind string) string { return "sundynix.config." + kind + ".get" } func ConfigUpdatedSubject(kind string) string { return "sundynix.config." + kind + ".updated" } // IngestEvent 是入库流水线的实时进度事件(经 sundynix.streams. 回流给 UI)。 type IngestEvent struct { Stage string `json:"stage"` // 解析/切块/向量化/写Milvus/写Bleve/完成/失败 Msg string `json:"msg,omitempty"` // 文案 Done int `json:"done,omitempty"` // 进度(如已向量化块数) Total int `json:"total,omitempty"` // 总数 Chunks []string `json:"chunks,omitempty"` // 切块预览(切块阶段发一次) Error string `json:"error,omitempty"` } // ModelConfig 是一个模型后端的连接配置(provider 抽象,chat 与 embedding 同形)。 // 开发期指向第三方在线 API(OpenAI 兼容);生产期可换自部署或其它在线模型。 type ModelConfig struct { Provider string `json:"provider"` // openai-compatible / vllm / ... BaseURL string `json:"base_url"` // 如 https://api.deepseek.com APIKey string `json:"api_key,omitempty"` Model string `json:"model"` // 如 deepseek-chat / text-embedding-v3 } // Ready 报告该配置是否足以发起真实推理。 func (m *ModelConfig) Ready() bool { return m != nil && m.BaseURL != "" && m.Model != "" } // Task 是 DSL 解析组装后的可调度任务,在 NATS 上以 JSON 传输。 type Task struct { ID string `json:"id"` Graph json.RawMessage `json:"graph"` // React Flow 导出的 Agent 编排图 Meta map[string]any `json:"meta,omitempty"` } // TaskSubject 返回某任务的发布主题。 func TaskSubject(id string) string { return SubjectTasks + "." + id } // StreamSubject 返回某任务的 Token 回流主题。 func StreamSubject(id string) string { return SubjectStream + "." + id } // ToolSubjectGo / ToolSubjectPy 返回某工具的调用主题。 func ToolSubjectGo(tool string) string { return SubjectToolsGo + "." + tool } func ToolSubjectPy(tool string) string { return SubjectToolsPy + "." + tool } // ToolCall 是 Dispatcher 对一个 MCP 工具的调用请求(NATS request 体)。 type ToolCall struct { Tool string `json:"tool"` // 工具名,如 wiki_search Args map[string]any `json:"args,omitempty"` // 工具参数 TaskID string `json:"task_id,omitempty"` // 触发该调用的任务(便于追踪) } // ToolResult 是 MCP 工具的应答(NATS reply 体)。 type ToolResult struct { OK bool `json:"ok"` Content string `json:"content,omitempty"` // 工具产出(如检索结果文本) Error string `json:"error,omitempty"` // 非空表示工具内部出错 } // Marshal / Unmarshal 便捷方法。 func (t *Task) Marshal() ([]byte, error) { return json.Marshal(t) } func Unmarshal(b []byte) (*Task, error) { var t Task if err := json.Unmarshal(b, &t); err != nil { return nil, err } return &t, nil }