package core import ( "encoding/json" "strings" ) // 事件信封:后端 → 前端的唯一增量通道(SSE),持久化后转发,Seq 在会话内单调。 // 消费方对未知 Type 静默忽略(原则 6 前向兼容)。 // 项目流(D50):项目频道事件以伪会话键 "project:" 复用同一机制 // (独立 seq、持久化、断线重放),信封以 ProjectID 标识归属(会话流事件为空)。 type StreamEvent struct { Seq int64 `json:"seq"` RunID ID `json:"runId,omitempty"` ConversationID ID `json:"conversationId"` ProjectID ID `json:"projectID,omitempty"` // 项目流事件的项目归属(D50;只增不删) TS string `json:"ts"` // RFC3339 V int `json:"v"` Type StreamEventType `json:"type"` Payload json.RawMessage `json:"payload,omitempty"` } type StreamEventType string // 项目流频道约定(D50):项目频道以伪会话键 "project:" 复用会话 // 事件的持久化/seq/重放机制;信封 ProjectID 由该键派生(发布与重放同源)。 const projectChannelPrefix = "project:" // ProjectChannelKey 返回项目流的事件频道键。 func ProjectChannelKey(projectID ID) ID { return ID(projectChannelPrefix + string(projectID)) } // ProjectFromChannel 反解项目流频道键;非项目流频道返回 false。 func ProjectFromChannel(key ID) (ID, bool) { pid, ok := strings.CutPrefix(string(key), projectChannelPrefix) return ID(pid), ok && pid != "" } const ( EvMessageDelta StreamEventType = "message.delta" EvThinkingDelta StreamEventType = "thinking.delta" EvToolCallDelta StreamEventType = "tool.call.delta" // 参数增量:工具开始执行前即可上屏 EvToolCall StreamEventType = "tool.call" EvToolOutput StreamEventType = "tool.output" // 执行中的 stdout/stderr 增量 EvToolResult StreamEventType = "tool.result" EvRunPhase StreamEventType = "run.phase" EvRunCheck StreamEventType = "run.check" // 终轮自动检查,过程区一行 EvHITLRequest StreamEventType = "hitl.request" EvHITLResolved StreamEventType = "hitl.resolved" EvPlanUpdate StreamEventType = "plan.update" EvTodoUpdate StreamEventType = "todo.update" EvAgentSpawn StreamEventType = "agent.spawn" EvAgentProgress StreamEventType = "agent.progress" EvAgentResult StreamEventType = "agent.result" EvArtifactCreated StreamEventType = "artifact.created" EvArtifactUpdated StreamEventType = "artifact.updated" EvRunCompleted StreamEventType = "run.completed" EvRunFailed StreamEventType = "run.failed" EvError StreamEventType = "error" // 收件箱卡片(activity.go):前端右栏收件箱的唯一数据源(投影语义,服务端权威)。 EvCardCreated StreamEventType = "card.created" EvCardUpdated StreamEventType = "card.updated" EvCardStatus StreamEventType = "card.status" EvCardResolved StreamEventType = "card.resolved" ) // ProtocolVersion 是事件信封与 payload 词汇的当前版本。 const ProtocolVersion = 1 // ---- 各事件 payload(新增字段只增不删;消费方忽略未知字段)---- // MessageDeltaPayload:正文增量。Index 标识目标 Part 序号(流式聚合用)。 type MessageDeltaPayload struct { Index int `json:"index"` Text string `json:"text"` } type ThinkingDeltaPayload struct { Index int `json:"index"` Text string `json:"text"` } type ToolCallPayload struct { CallID string `json:"callId"` Name string `json:"name"` Arguments string `json:"arguments,omitempty"` } // ToolCallDeltaPayload 是模型正在编写的工具参数增量。Index 标识同轮第几次调用 // (与供应商 tool_calls 下标一致);Name/CallID 往往只在首个分片出现。 type ToolCallDeltaPayload struct { Index int `json:"index"` CallID string `json:"callId,omitempty"` Name string `json:"name,omitempty"` Delta string `json:"delta"` } // ToolOutputPayload 是工具执行过程中的输出增量。Stream 为 stdout 或 stderr。 type ToolOutputPayload struct { CallID string `json:"callId"` Stream string `json:"stream"` Text string `json:"text"` } type ToolResultPayload struct { CallID string `json:"callId"` Status string `json:"status"` Summary string `json:"summary,omitempty"` Truncated bool `json:"truncated,omitempty"` DurationMs float64 `json:"durationMs,omitempty"` } type RunPhasePayload struct { Phase RunPhase `json:"phase"` } // RunCheckPayload 与 CheckPart 同形,让运行中和重新加载后的检查行一致。 type RunCheckPayload struct { Passed bool `json:"passed"` Reason string `json:"reason,omitempty"` } type HITLResolvedPayload struct { CardID ID `json:"cardId"` Answer string `json:"answer,omitempty"` Kind string `json:"kind"` // choice | free | timeout | cancelled } type PlanUpdatePayload struct { Plan PlanSnapshot `json:"plan"` } type TodoUpdatePayload struct { List TodoList `json:"list"` } // AgentSpawnPayload:子代理派生;AgentRun 即子 Run(父子关系即任务树)。 type AgentSpawnPayload struct { AgentRun ID `json:"agentRun"` Name string `json:"name"` Task string `json:"task"` } type AgentProgressPayload struct { AgentRun ID `json:"agentRun"` Note string `json:"note,omitempty"` Phase RunPhase `json:"phase,omitempty"` } type AgentResultPayload struct { AgentRun ID `json:"agentRun"` Status RunStatus `json:"status"` Summary string `json:"summary,omitempty"` // Text 为子代理完整文本产出(squad 步骤交付物用;截断摘要见 Summary)。 Text string `json:"text,omitempty"` } type ArtifactPayload struct { Artifact Artifact `json:"artifact"` } type RunCompletedPayload struct { Usage Usage `json:"usage"` // Context 为该次运行的上下文组装观测(4.10/4.17:构成 + 裁剪记录;可解释性)。 Context *ContextObservation `json:"context,omitempty"` } // ContextSection 是组装结果里一段的估算。EstTokens 用 UTF-8 字节数 / 3.35, // 再按上一请求的真实用量校准。 type ContextSection struct { Name string `json:"name"` EstTokens int `json:"estTokens"` } // ContextObservation 记录一次模型输入的实际构成与预算裁剪(ctxasm 产出)。 type ContextObservation struct { Items []string `json:"items"` // 如 system(画像) / history(12) / attachments(1) / knowledge(3) Truncations []string `json:"truncations,omitempty"` // 裁剪记录(历史超窗/工具结果超限/附件截断) EstChars int `json:"estChars"` // 估算输入量(token;字段名保持兼容) Sections []ContextSection `json:"sections,omitempty"` PrefixHash string `json:"prefixHash,omitempty"` // 系统前缀哈希,前缀不变时保持稳定 } type RunFailedPayload struct { Code string `json:"code"` Message string `json:"message"` } type ErrorPayload struct { Code string `json:"code"` Message string `json:"message"` RunID ID `json:"runId,omitempty"` } // CardPayload:card.created / card.updated 携带整卡投影(服务端权威,前端整体替换)。 type CardPayload struct { Card ActivityCard `json:"card"` } // CardStatusPayload:card.status 携带状态迁移(含 Tone,便于轻量更新状态灯)。 type CardStatusPayload struct { CardID ID `json:"cardId"` Status CardStatus `json:"status"` Tone string `json:"tone,omitempty"` Note string `json:"note,omitempty"` } // CardResolvedPayload:card.resolved 携带所点动作语义——确认结论回写对话时间线 // (AI 回执)并写入审计;Answer 为自由输入文本(如有)。 type CardResolvedPayload struct { CardID ID `json:"cardId"` ActionID string `json:"actionId,omitempty"` Answer string `json:"answer,omitempty"` }