claude-code-best/docs/serve/serve-event-standardization-todo.md

199 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# csc serve 事件标准化 — 实施任务清单
> 关联文档:`docs/serve/serve-event-standardization-proposal.md`
> 原则:**不做双写**csc serve 直接输出 canonical 格式,旧 cs-cloud passthrough 兼容
---
## Phase 1sessionMessageRouter 路由增强
### 1.1 新建 StreamStateTracker
- [x] 创建 `src/server/streamStateTracker.ts`
- [x] 实现 `SessionStreamState` 状态结构messageID、activeBlocks、usage、stopReason
- [x] 实现 `processStreamEvent()` — Anthropic stream_event → canonical 事件转换
- [x] `message_start``message.updated` + `step-start` part
- [x] `content_block_start` (text) → `message.part.updated { type: "text" }`
- [x] `content_block_start` (thinking) → `message.part.updated { type: "reasoning" }`
- [x] `content_block_start` (redacted_thinking) → `message.part.updated { type: "reasoning", redacted: true }`
- [x] `content_block_start` (tool_use) → `message.part.updated { type: "tool", status: "pending" }`
- [x] `content_block_delta` (text_delta) → `message.part.delta { field: "text" }`
- [x] `content_block_delta` (thinking_delta) → `message.part.delta { field: "text" }`
- [x] `content_block_delta` (input_json_delta) → `message.part.delta { field: "input" }`
- [x] `content_block_stop` (tool_use) → `message.part.updated { status: "running" }`
- [x] `content_block_stop` (text/thinking) → finalize timing
- [x] `message_delta` → 提取 usage.outputTokens + stopReason不输出事件
- [x] `message_stop``message.part.updated { type: "step-finish" }` + reset state
- [x] 工具名规范化函数(`Bash` → `bash`、`Read` → `read` 等,复用现有 `toPermissionKey` 映射)
- [x] tool input JSON 累积 + try/catch 解析 fallback
- [x] 多 steptool_use 循环)场景:每次 `message_start` 生成新 messageID
### 1.2 改造 stream_event 路由
- [x] `sessionMessageRouter.ts``case 'stream_event'` 改用 StreamStateTracker
- [x] 移除旧 `ctx.emitEvent('stream_event', msg)` — 不再做 raw 转发
- [x] Tracker 产出的 canonical 事件通过 `ctx.emitOpencodeEvent()` 发出
### 1.3 system 子类型分发
- [x] `case 'system'` — 替换当前的统一 `ctx.emitEvent('message', msg)`
- [x] `task_notification``ctx.emitOpencodeEvent('task.completed', { taskID, status, summary, usage, ... })`
- [x] `task_started``ctx.emitOpencodeEvent('task.started', { taskID, description, taskType, ... })`
- [x] `task_progress``ctx.emitOpencodeEvent('task.progress', { taskID, usage, summary, workflowProgress, ... })`
- [x] `api_error` / `api_retry``ctx.emitOpencodeEvent('session.error', { error: { subtype, message, retryInMs, ... } })`
- [x] `compact_boundary` / `microcompact_boundary``ctx.emitOpencodeEvent('message.part.updated', { part: { type: "compaction", auto, overflow } })`
- [x] `stop_hook_summary``ctx.emitOpencodeEvent('session.hook_summary', { ... })`
- [x] `turn_duration``ctx.emitOpencodeEvent('session.metrics', { ... })`
- [x] `cache_warning``ctx.emitOpencodeEvent('session.warning', { ... })`
- [x] `informational``ctx.emitOpencodeEvent('session.info', { ... })`
- [x] `post_turn_summary``ctx.emitOpencodeEvent('session.info', { ... })`
- [x] `session_state_changed``ctx.emitOpencodeEvent('session.status', { ... })`
- [x] `status``ctx.emitOpencodeEvent('session.status', { ... })`
- [x] `default``ctx.emitOpencodeEvent('session.info', { subtype, ...msg })`
### 1.4 新增 attachment 路由
- [x] `case 'attachment'` — 当前 default:break 丢弃
- [x] 转发为 `ctx.emitOpencodeEvent('message.attachment', { attachmentType, attachment })`
- [x] 关键 attachment 子类型至少覆盖:
- [x] `hook_success` / `hook_error` / `hook_cancelled`
- [x] `relevant_memories` / `nested_memory`
- [x] `task_status` / `task_reminder`
- [x] `diagnostics`
- [x] `token_usage` / `budget_usd`
- [x] `invoked_skills`
> attachment 路由不区分子类型,统一通过 `attachmentType` 字段透传。消费端按需过滤。
### 1.5 新增 progress 路由
- [x] `case 'progress'` — 当前 default:break 丢弃
- [x] 转发为 `ctx.emitOpencodeEvent('tool.progress', { toolUseID, parentToolUseID, data })`
### 1.6 新增 tombstone 路由
- [x] `src/QueryEngine.ts` — serve 模式下将 tombstone 消息 yield 到 stdout
- [x] `sessionMessageRouter.ts``case 'tombstone'`
- [x] 转发为 `ctx.emitOpencodeEvent('message.removed', { messageID })`
### 1.7 handleResultMessage 增强
- [x] 提取 `stop_reason` 传播到 `session.result` 的 reason 字段
- [x] 提取 `usage` / `cost_usd` 透传到 `session.result` 事件
- [x] `subtype !== 'success'` 时发射 `session.error` 事件
- [x] 区分 result 子类型:`success` / `error_max_turns` / `error_max_budget` / `error_doom_loop` / `error`
### 1.8 handleAssistantMessage 增强(非流式 / 历史加载场景)
- [x] 完整 assistant 消息到达时,发射 `message.updated` 事件(含 role/modelID/cost/tokens/parentID
- [x] 遍历 content blocks为每个 block 发射 `message.part.updated`
- [x] `text` block → text part
- [x] `thinking` block → reasoning part
- [x] `redacted_thinking` block → reasoning part (redacted)
- [x] `tool_use` block → tool part (status: running)
---
## Phase 2REST API 适配
### 2.1 消息历史端点标准化
- [x] `GET /session/{id}/message` — 返回 parts-based 格式(对标 opencode
- [x] assistant 消息content blocks 分解为 parts 数组
- [x] user 消息text/tool_result 分解为 parts
- [x] 新增 `format=parts` query parameter 消费端按需选择
- [ ] system 消息compaction_boundary → compaction part
- [ ] attachment 消息:保留原始数据但增加 part 包装
- [ ] `GET /session/{id}/todo` — 适配响应格式
---
## Phase 3EventBus / SSE 层调整
### 3.1 emitEvent → emitOpencodeEvent 统一
- [x] 审计 `sessionHandle.ts` 中所有 `ctx.emitEvent()` 调用
- [x] `emitEvent('message', ...)``emitOpencodeEvent('message.updated', ...)`
- [x] `emitEvent('result', ...)``emitOpencodeEvent('session.result', ...)`
- [x] `emitEvent('ready', ...)``emitOpencodeEvent('session.updated', ...)`
- [x] `emitEvent('deleted', ...)``emitOpencodeEvent('session.deleted', ...)`
- [x] `emitEvent('stream_event', ...)` → 移除Phase 1.2 已由 StreamStateTracker 替代)
- [x] `emitEvent('control_request', ...)` → 保留(已有独立 opencode 事件)
- [x] `emitEvent('permission_replied', ...)` / `emitEvent('question_replied', ...)` → 保留(低级别确认)
### 3.2 SSE 事件名映射
- [x] 确认 `emitOpencodeEvent` 输出的 SSE event name 格式
- [x] 全部统一为 opencode 风格(无 `session.` 前缀)
---
## Phase 4测试
### 4.1 单元测试
- [x] `src/server/__tests__/streamStateTracker.test.ts` (18 tests, 35 assertions)
- [x] message_start → message.updated + step-start
- [x] text content_block 完整流程 (start → delta → stop)
- [x] thinking content_block 完整流程
- [x] redacted_thinking 处理
- [x] tool_use 完整流程 (start → input_delta → stop → running)
- [x] message_delta 提取 usage/stopReason
- [x] message_stop → step-finish + reset
- [x] 多 step 场景tool_use 循环产生多个 message_start/stop
- [x] input_json_delta 累积 + 损坏 JSON fallback
- [x] `src/server/__tests__/sessionMessageRouter.test.ts` (29 tests, 57 assertions)
- [x] system.task_notification → task.completed
- [x] system.task_started → task.started
- [x] system.task_progress → task.progress
- [x] system.api_error → session.error
- [x] system.compact_boundary → compaction part
- [x] attachment 路由
- [x] progress 路由
- [x] tombstone → message.removed
- [x] result 子类型区分
- [x] assistant 非流式消息 → parts 分解
- [x] init → session.updated
- [x] user → message.updated
### 4.2 集成测试
- [ ] 启动 csc serve发送 prompt验证 SSE 流包含完整 canonical 事件序列
- [ ] 后台 agent 场景:验证 task.started → task.progress → task.completed
- [ ] API 错误场景:验证 session.error 事件
- [ ] 压缩场景:验证 compaction part
- [ ] 历史消息加载:验证 parts-based 格式
### 4.3 兼容性测试
- [ ] 旧版 cs-cloud + 新 csc serve确认旧 adapter 正常处理保留的事件名
- [ ] 旧版 cs-cloud passthrough 新事件:消费端不报错
- [ ] 新版 cs-cloud + 新 csc serve确认 adapter 切换到新事件后功能不降级
---
## Phase 5cs-cloud Adapter 精简cs-cloud 侧)
### 5.1 切换到新事件源
- [ ] cs-cloud adapter 优先消费 `message.part.updated` / `message.part.delta` 而非 `session.stream_event`
- [ ] cs-cloud adapter 消费 `task.started` / `task.progress` / `task.completed` 而非从 `session.message` 推断
- [ ] cs-cloud adapter 消费 `session.error` 而非丢弃 system 子类型
### 5.2 移除适配代码
- [ ] 移除 `adapter_sse_stream.go`StreamStateTracker 已在 csc 侧完成)
- [ ] 移除 `adapter_sse_message.go`parts 分解已在 csc 侧完成)
- [ ] 移除 `adapter_parts.go`part 构建已在 csc 侧完成)
- [ ] 保留 `adapter_json.go`REST API 响应仍需适配,直到 Phase 2 完成)
- [ ] adapter 降级为 thin proxy仅 SSE passthrough + REST 路由)
---
## 不在本次范围
- Event Sourcing / CQRS架构变更过大
- 多 Workspace 实例隔离cs-cloud 多进程模型已解决)
- File snapshot / patch 追踪(依赖文件系统监控基础设施)
- Session fork / share 功能实现(需要 csc 核心逻辑支持)