人工智能AI 应用AI Agent交互助手MCP Clients本地部署【免费下载链接】CodePilotA multi-model AI agent desktop client — connect any AI provider, extend with MCP skills, control from your phone. Built with Electron Next.js.项目地址https://gitcode.com/gh_mirrors/co0dep/CodePilot点击查看免费下载本指南以 CodePilot 仓库中的docs/guardrails/StreamSession.md为核心骨架结合stream-session-manager.ts、useSSEStream.ts、chat-collect-stream-response.ts等源码实现系统讲解 CodePilot 聊天主路径的流会话状态机、SSE 事件解析、双入口状态隔离、服务端持久化 checkpoint、子 Agent 生命周期与跨 Runtime 一致性契约。读完你将掌握为什么/chat与/chat/[id]必须各自独立管理 effort/thinking 状态rewind point 何时才会被触发切换聊天只是 detach、显式 Stop 才叫中断的取消权设计以及 assistant 消息如何在流式进行中落库、在进程重启后以interrupted收口。1. 背景为什么聊天主路径需要一份专门的守护文档CodePilot 是 Electron Next.js 构建的多模型 AI Agent 桌面客户端。其聊天主路径涉及双入口/chat首页负责首条消息的发送/chat/[id]负责既有会话的续聊。每一次 SDK 接入Claude Code SDK、Native Runtime、Codex Runtime都会触及这条主路径——文档标题里的上一次 SDK 0.2.111 接入的重灾区正是指双入口的 effort / thinking / runtime override 传递问题。这份守护文档的核心价值在于它把聊天流从前端拿到一段文本渲染出来上升为一套可验证的系统契约覆盖了流式渲染、服务端持久化、子 Agent 生命周期、权限归属、取消语义、token 统计等相互咬合的边界。任何改动只要触碰其中一个环节都必须对照 32 条不变量与改动检查表回归验证。2. 词汇表与核心概念先明确三个贯穿全文的基础概念详见原文档词汇表术语含义对应源码stream-session-manager客户端流会话状态机管理startedAt/snapshot/finalMessageContentsrc/lib/stream-session-manager.tsuseSSEStreamServer-Sent Events 解析 hooksrc/hooks/useSSEStream.tsrewind pointprompt-level user message 的回退锚点不为 tool_result / autoTrigger 触发useSSEStream.ts中onRewindPoint回调其中stream-session-manager采用globalThis单例模式与conversation-registry.ts相同的写法用__streamSessionManager__/__streamSessionListeners__两个全局键存放MapsessionId, ActiveStream与监听器注册表目的是在 Next.js HMR 和组件卸载重挂之后仍然保留流的状态。这一点从源码注释可以确认当用户切换会话时旧ChatView卸载但流继续在 manager 中运行新的 ChatView 通过subscribe(sessionId, listener)订阅即可获得当前 snapshot。3. 不变量 / 契约表32 条核心约束原文档用一张 32 行的契约表划定了聊天主路径的全部边界。按主题可以归并为六组3.1 双入口状态隔离不变量 #1、#13、#15、#26、#30#1 双入口独立管理状态/chat首消息page.tsx与/chat/[id]后续消息ChatView.tsx必须各自独立持有 effort / thinking / runtime override 状态并各自传给/api/chat不依赖跨 page 共享状态。原文档明确这是上一次 SDK 0.2.111 接入的重灾区也是 Phase 6 上下文可视化将触及的核心点。#13 流式期间必须先 checkpoint 再落库Assistant 流不能等 SSE 完全关闭后才首次写库。首个有效 text/thinking/tool block 即创建streamingcheckpoint后续增量更新同一个 message id终态原位收口进程重启只把遗留streaming行改成interrupted。刷新后的历史 UI 轮询该行到终态不得把 checkpoint 当完成或插入重复回复。这由chat-collect-stream-response.ts的persistCheckpoint/persistTerminal与db.ts的addMessage/updateMessageStreamCheckpoint共同守门。#15 客户端 detach 不等于取消Renderer 切换聊天、刷新或 fetch transport 断开只表示客户端 detach不能取消 server-owned Runtime/collector只有显式 Stop 调用/api/chat/interrupt才能向父/child abort 传播。首轮/chat的 Stop 也必须先发 interrupt再终止本地 fetch。组合信号必须兼容仓库 Node 18 开发基线不能裸依赖AbortSignal.any。#26 内部 lifecycle envelope 不外泄Runtime 内部{ kind, payload }envelope 不得经通用 status fallback 原样出现在聊天中未知 Codex kind 降级为通用人类状态双聊天入口均不得暴露 server id、payload JSON 或协议 kind。#30 首次 execution 先 binding每个父聊天第一次 execution 必须先完成 Runtime binding再 resolve Provider 或启动 childlegacy/unbound 的自动执行必须在任何 transcript、工具调用和费用发生前 fail closed。3.2 rewind point 与能力缓存不变量 #2、#3#2 rewind point 的触发规则仅对 prompt-level user messageparent_tool_use_id null发出autoTrigger / tool_result 不触发。useSSEStream.ts在解析rewind_pointSSE 事件时仅接受携带合法userMessageId的载荷。#3 capability cache 必须 per-provider缓存类型为Mapstring, ProviderCapabilityCache所有调用者显式传 providerId。源码中agent-sdk-capabilities.ts的缓存 TTL 为 5 分钟CACHE_TTL_MS并提供invalidateCapabilityCache(providerId)在 Provider 行被编辑或删除时主动失效——否则旧配置下捕获的模型列表与账户信息会继续服务长达 5 分钟。3.3 tool id 与历史配对不变量 #4、#5、#27#4 保留真实 tool idAgent/Task的 tool_use 与 tool_result以及 Codex 原生 collab 的单次 action start/result必须保留同一个真实 tool id历史消息不得改写成hist-N后丢失归属。Codex collab action id不是child thread id不能拿来充当 Sub-agent identity。#5 子 Agent 渲染分流子 Agent 在 streaming 与历史两条渲染链都必须从普通ToolActionsGroup分流StreamingMessage.tsxMessageItem.tsx普通工具维持原折叠行为。#27 tool-call/result 配对完整性持久化并重放给 AI SDK 的每个非 provider-executed tool-call在下一条 user/system 或 transcript 结束前必须有匹配 tool-result。回合结束仍未收到结果时只能补 app-owned、is_error:true的未收到结果事实MISSING_TOOL_RESULT_CONTENT [CodePilot: no tool result was received before this turn ended.]不能伪造工具成功/执行失败。这正是tool-history-integrity.ts的repairIncompleteToolHistory做的事它只闭合未完成的段synthesizedResults与droppedOrphanResults分别计数orphan result 留在 UI/DB 审计但不得原样进模型 prompt。3.4 子 Agent 生命周期不变量 #6–#12、#14、#16–#24这是契约表最密集的区域核心思想可概括为只有 durable 的结构化 lifecycle 事实才能判定终态#7/#12 先建 durable running row三条 managed RuntimeCodePilot / Claude / Codex的每个 physical child 都必须在调用 child之前创建subagent_runs.running行持久化失败则不启动 child只有第一次结构化 terminal 可收口。Codex UI toolId DB runId后续回合状态来自subagent_runs不得从update_plan、正文、耗时或工作区文件推断。#8/#10/#11 终态判定规则Claude background Agent 的async_launched只是运行回执只有task_notification的 completed/failed/stopped 才能写终态同 tool id last-wins 且终态不可被乱序回执覆盖SDKsubtypesuccess只表示协议拿到 resultis_errortrue或api_error_status失败必须进入 failedmaxTurns / timeout 分别进入 partial / timed_out。Codex child 的turn.statuscompleted只证明回合结束任务结果还必须读取 child 的结构化 outcome显式无法完成与 completed 声明冲突时fail closed。#14 权限归属managed child 的 permission request 与 timeout resolved 事件必须携带同一agentRunId/childSessionIdrequest 另带用户可见agentName。PermissionPrompt必须显示发起者不能把 child 写入审批伪装成父 Agent 请求。#16 可续期超时模型Claude managed child 的超时区分可续期 idle deadline 与不可续期 hard cap任何 SDK activity 都续期 idle。运行中 assistant 正文/effective model 必须 bounded checkpoint 到仍为terminal0的 runtimeout/cancel 保留部分正文terminal 后迟到 checkpoint 不得覆盖终态。#18 logical run / physical attemptSub-agent 的用户任务 identity 是 logical run不是 tool call。显式 retry 复用logical_run_id物理调用使用新的 attempt id/number聊天胶囊和父进展快照只展示最新 attempt 的一个 logical task详情保留全部 attempt。#19/#20 settling 屏障与 typed lifecycle eventchild 回合停止后先进入settling此时用户状态仍不得显示 completed只有 structured result/provenance 与 terminal lifecycle event durable 后才进入 terminal。当前活动、tool、permission 与 partial progress 必须写 typed lifecycle eventsubagent_run_events详情 UI 从 SQLite 读取不从 prompt、自由文本或文件变化猜测。#21/#22 超时归属与探测冷却Claude managed MCP 的 SDK tool-use id 必须成为 durable physical attempt idchild 的超时 owner 是 child 内部可续期 idle deadline hard cap父回合通用 tool timeout 不得在 300 秒整 abort managed spawn。详情 API 的 404/5xx/网络异常先做有界快速探测5 次随后进入低频冷却恢复每 30 秒一次不得永久每秒请求。#23/#24 Codex 双委派通道用户指定 CodePilot Provider / Model 时只能走 app-serverdynamicTools暴露的 managedcodepilot_spawn_subagentCodex 原生spawn_agent只表示继承父 route 的 native worker。动态工具仅在thread/start注册且 initialize 必须声明experimentalApi每个真实 Codex thread 使用独立 dispatcher route不能用进程级单 handler 互相抢占。managed local tool 的 app-server mirror lifecycle 必须抑制同一调用只能出现一次 tool_use / tool_result最终 wire result 必须重读 terminal-immutable durable row。3.5 渲染与展示诚实性不变量 #9、#25、#26、#28、#29、#32#9 卡片渲染位置子 Agent 卡片在父输出之后渲染随正文向下滚动首轮/chat在 session 创建后立即绑定真实 sessionId允许 Details 拉起 Workspace Sidebar。#25 Thinking 动画语义Thinking 动画只增强已有事实不自行声称模型在 reasoning。首 token 前的普通等待使用working只有真实 thinking delta 行使用solving可访问语义仍由现有文字承担canvas 必须 decorative 并尊重 reduced-motion / visibility pause。#28 单终态 Stream 所有权由多个异步 callback 写入的 server-sideReadableStream必须把 enqueue/close 的唯一所有权交给SingleOwnerStreamWriter。consumer cancel 先原子宣告 terminal再 kill/abort producer取消后的迟到写入必须 no-op。这正是single-owner-stream-writer.ts的实现attach只能调用一次enqueue/close/cancel在 terminal 后一律返回false。#29 token usage 运行时 shape 验证DBtoken_usage是跨 Runtime/历史版本输入历史消息展示前必须验证input_tokens/output_tokens都是有限非负安全整数缺失/非法时隐藏整项统计不得补假 0。assistantaddMessage的 insert、session timestamp update 与 row read 必须在同一同步 SQLite transaction 中完成。#32 v2 usage 的 unknown 语义missing cache/cost 是 unknown 不是 0Native 必须核对 provider raw usage不能接受 AI SDK 合成的缓存零聚合与 UI 只有在每轮 denominator/source 完整时才显示 rate/金额。3.6 跨会话与 route 身份不变量 #17、#31以及 #685 节#17 事实来源纪律事实/研究 child handoff 必须让 source URL 与 claim 同行无来源的精确日期、数字、排名和引语不得升格成已验证事实失败 child 后父 Agent 接管时最终说明必须区分 child 失败与 parent 产物。#31 跨 Runtime 只能新 session handoff目标首轮从runtime_handofffragment 消费同一份有边界、可截断、已脱敏事实不得复制原生 SDK/thread ref也不得把 handoff card 写成用户消息。#685 已选路由与运行时回报分离2026-09-14chat_sessions.model是用户提交的 route model identitySDK/Nativestatus.model是运行时观察值collector 不得用它覆盖 route也不得借 status 绕过route_revisionCAS。resolveChatMessageRoute是普通消息的 identity gateProvider 未随请求回显时仍固定使用 session Provider不能回退默认/env明确不同 Provider 立即拒绝。旧版已写成 upstream 的会话只作读取且必须在同一 Provider 的 live enabled catalog 唯一匹配、当前 Runtime 兼容、实际 resolver upstream 一致无法无歧义恢复的旧会话继续要求明确重选。4. 保存失败的后台与客户端边界2026-09-07 专项原文档用独立小节专门划定了保存失败时的后台/客户端边界要点如下collector 的 rejection 归属/api/chat启动 collector 后立即用observeChatCollection拥有 rejection客户端 detach 后仍捕获一次安全遥测失败处理自身不得产生新的未处理拒绝。done ≠ 保存确认runtime SSE 的 done 不是保存确认。响应结束前只等待 terminal persistence 的独立 one-shot 信号不能等待 collector finally 中的 onboarding/check-in 模型调用或通知。失败发送固定CODEPILOT_CHAT_SAVE_UNCONFIRMED双聊天入口通过共同错误映射显示未确认保存、先复制后刷新的双语提示。后续 finally 失败不能撤销已经确认的保存。首条保存未确认不跳转首条聊天保存未确认时不得自动跳转到 DB 历史页在/chat内把真实 session 与内存消息交给 ChatView后续发送复用该 session 和既有 route CAS / 权限 / Stop 行为。只重读 session metadata不能重读历史覆盖正文。错误码透传明确保存错误通过 SSE parser 的原始码传到snapshot.saveUnconfirmed再写入 renderer-onlyMessage.saveUnconfirmed不能解析翻译后正文猜状态。ChatView 的 DB reconcile 在 state updater 内检查未确认回复后续成功回合也不能将其覆盖流在页面切走后结束时恢复从 snapshot 追加本地正文不用 DB 替代。tee cancel 语义client tee branch cancel 不能取消 server collector也不能 await 需要另一分支结束的 tee cancel Promise。所有追加 SSE/关闭走SingleOwnerStreamWriter。fail-closed 事务语义不修改 DB 空读的 fail-closed 事务语义不声称修复初始空读或保证数据已落库。测试必须同时覆盖正常保存和首次/兜底保存失败并验证失败时 cleanup/lock 释放。回归测试覆盖chat-collection-response.test.ts真实 onboarding 处理器的模型请求被测试 fetch 阻塞时 SSE 已关闭、finally 在 onComplete 前抛错仍有 owner、chat-collection-telemetry.test.ts、chat-save-warning.spec.ts中英文、双入口、失败后续聊同 session、长会话裁剪、离页恢复、正常首条跳转对照。5. 关键文件与责任分工原文档的关键文件 责任表是后续阅读源码的最佳索引整理如下文件守护的不变量src/lib/claude-client.tsSDK streaming core capProviderId 派生src/lib/stream-session-manager.tssnapshot 生命周期、停止语义、消息队列src/hooks/useSSEStream.tsSSE 事件解析 rewind point 发出规则 status 安全降级src/app/chat/page.tsx首消息入口session 创建 首轮 SSE 手解析src/components/chat/ChatView.tsx后续消息入口src/components/chat/MessageItem.tsx历史 tool 配对保持真实 tool id子 Agent 分流src/lib/token-usage-display.ts历史/跨 Runtime token usage 运行时 shape 验证src/components/chat/StreamingMessage.tsx流式子 Agent 卡片分流src/components/ai-elements/tool-actions-group.tsx流式 reasoning 行与工具活动折叠展示src/lib/subagent-view.tsrequested/effective/runtime/status 的诚实归一化src/lib/subagent-status.tsClaude task lifecycle → last-wins tool_result 状态标记src/lib/subagent-run-context.tsCodex durable run 快照与只读查询src/lib/db.ts三 Runtime 的subagent_runsrunning→terminal、terminal immutablesrc/lib/tools/agent.tsCodePilot managed child durable lifecyclesrc/lib/claude-subagent-mcp.tsClaude managed child durable lifecyclesrc/lib/codex/proxy/builtin-bridge.tsCodex managed child durable lifecyclesrc/lib/codex/dynamic-tool-bridge.tsCodex Account app-server dynamic tool per-thread 路由src/lib/codex/turn-interrupt-registry.tsCodex 父 turn AbortController 的 HMR-safe 所有权src/lib/chat-collect-stream-response.tsassistant checkpoint 增量写入、owner gate、同 id 终态收口src/lib/tool-history-integrity.tsStop/partial delivery 后的 call/result 完整性修复src/lib/single-owner-stream-writer.tsserver-produced Web Stream 的单终态所有权6. 从源码看两条关键实现链路6.1 客户端snapshot 生命周期与 idle 双层预算stream-session-manager.ts中每个ActiveStream维护startedAt、可变的accumulatedText/accumulatedThinking/toolUsesArray/toolResultsArray等累积器每次emit()都通过buildSnapshot()生成新的 snapshot 对象引用保证 React 状态可正常触发重渲染并同步派发stream-session-event窗口事件供 AppShell 消费。idle 超时采用#635 双层预算首 token 前的等待给 10 分钟STREAM_IDLE_PRE_FIRST_TOKEN_MS上游可能在慢代理排队一旦sawUpstreamModelOutput为 true 收紧到 5.5 分钟STREAM_IDLE_POST_FIRST_TOKEN_MS。注意只有 text / thinking / tool_use 这类模型输出事件才会置位该标志status/init、tool_result 与 terminal result 不算。快照发射带 100ms 节流TEXT_THROTTLE_MStext/thinking/tool_output/tool_progress 四个高频回调共享同一个合并定时器而终态转换与 onToolUse 会先flushTextThrottle()保证没有 pending 帧丢失。clearSnapshot()的修复历史值得一提原文档常见坑第一条曾因把startedAt重置为 0 导致长 idle 后getSnapshot()返回 null、输出不显示。2026-06-10 修复为只清finalMessageContent防 remount 重复 append其余状态保留到 GC5 分钟宽限GC_DELAY_MS回收且 GC 定时器在 Node 进程内会unref()以免拖住单元测试进程。6.2 服务端collector 的 checkpoint 增量写入与 owner gatechat-collect-stream-response.ts的collectStreamResponse是服务端持久化的核心。它维护contentBlocks: MessageContentBlock[]与currentText/thinkingText两个滚动缓冲并遵守checkpoint 间隔ASSISTANT_CHECKPOINT_INTERVAL_MS 120非 force 且距上次写入不足 120ms 时跳过。owner gateI1/DP1每一次 session-level 写sdk_session_id、SDK tasks、assistantaddMessage都先过isLockOwner(sessionId, lockId)。被新 send 取代的旧 turn 迟到到达时必须不写只把既有 checkpoint 标记interrupted避免把旧输出拼接进新 owner 的时间线1.9 排序 bug 的根因。同 id 原位收口首个有效块用addMessage(..., { stream_status: streaming })创建行之后updateMessageStreamCheckpoint(msgId, content, streaming)增量更新终态用completed/error原位收口刷新后的历史 UI 轮询该行到终态。错误可见性兜底流只有 error 事件无 text/thinking/tool时持久化**Error:** message兜底块避免刷新后看起来助手没理我。finally 顺序纪律onPersistenceSettled在任何异步完成效果onboarding/check-in 模型调用、通知之前发布——后续 finally 失败不能撤销已确认的保存。6.3 SSE 事件解析与安全降级useSSEStream.ts的handleSSEEvent覆盖 20 余种事件类型text / thinking / tool_use / tool_result / tool_output / status / result / rate_limit / context_usage / permission_request / permission_resolved / permission_review / tool_timeout / mode_changed / file_changed / task_update / rewind_point / keep_alive / error / done。其中 status 事件的降级策略尤其值得关注不变量 #26 的落地codex.mcpServerReady直接静默handled: true无文本codex.mcpServerStartupFailed显示本地化工具连接失败未知codex.*kind 统一显示本地化运行时状态已更新结构化对象、以及以{/[开头的残缺 JSON一律降级为本地化文案绝不把内部协议 envelope 渲染进聊天正文。useSSEStream()hook 通过 ref 代理转发全部回调包括曾遗漏的 onSkillNudge / onContextCompressed / onFileChanged避免调用方拿到陈旧闭包。7. 改动检查表改之前先过一遍原文档列出的检查表是团队给维护者的防回归清单任何触碰聊天主路径的改动都应逐条核对。核心条目按模块归纳能力与 rewind改 capability 相关代码时确认 providerId 显式传递改 rewind 逻辑时确认 autoTrigger / tool_result 不被错误触发改首消息 page 时同步检查 ChatView 是否独立持有同一状态。tool 配对与子 Agent改 tool block 配对时确认真实 tool_use_id 保留新 Runtime 的子 Agent 事件只能填它能证明的 model/runtime/status未知值留空Claude background Agent 必须用 task_notification 判终态改 managed child 终态时必须覆盖success is_error、maxTurns、timeout改 Codex 原生 collab 映射时使用真实协议 fixturetool receiverThreadIds agentsStates。持久化与取消改 assistant persistence 时覆盖刷新中途 checkpoint、同 id terminal、真正进程重启 interrupted、活进程重复 DB init 不误中断、stale owner 不落新内容改 fetch/Abort 接线时覆盖切换聊天只 detach、显式 Stop 才调用 interrupt不要把request.signal直接接到 Runtime AbortController。子 Agent 详情与超时改 child approval wrapper 时覆盖 permission request 与 timeout resolved 的同 run 归属改 Claude child timeout 时同时覆盖 idle activity renewal、hard cap 不续期、partial 保留、terminal immutable改研究/写作委派提示词时保留 source→claim 与 parent fallback provenance。渲染与 Stream改 Thinking 动画时保持 first-token wait 与真实 reasoning 语义分离并验证 20px inline preset、decorative canvas、reduced-motion 不回退成无限动画升级thinking-orbs前重新人工审阅发布 diff新增 subprocess/callback 驱动的ReadableStream时使用SingleOwnerStreamWriter。8. 常见坑速查每条坑都有真实事故背书原文档的常见坑段落是团队用生产事故换来的教训清单最值得精读的几条不要用已有 tool_result推断 child 完成——Claude background Agent 会先返回 async launch receipt。不要用 Claude SDK 的subtypesuccess或非空result单独推断 managed child 完成——Provider 403 等错误也可能装在 success envelope 的正文里。不要相信父模型写出的已提交/仍在后台处理——CodePilot managed Agent 是 blocking foreground工具返回时 child 已终止UI 只认结构化 lifecycle 事实。不要把 Codexturn.statuscompleted当作任务成功——它也会包住网络不可用无法完成任务的正常 final answer。不要只在 SSEdone后addMessage——页面刷新、renderer 重载或 dev 进程重启会让整个回复和 Sub-agent tool blocks 从历史消失。不要把 renderer fetch 的断连当成用户 Stop——页面切换会自然 abort 客户端请求但 server collector 应继续完成并持久化。不要让父回合的普通工具 300 秒 timeout 包住 Claude managed child——它会越过 child activity renewal在健康 research run 上精确触发取消2026-07-24 真实会话67d5266867332d91b8a5f88ddbe1d1be两个 child 被精确 300 秒超时误杀后引入 idle renewal hard cap。不要在ReadableStream.cancel()里只 kill producer同时让 exit/error callback 继续裸controller.enqueue/close——这是 Controller is already closed 的稳定竞态2026-08-24 marketplace/CLI/media 生产 Sentry 修复。9. 测试覆盖契约如何被验证原文档的测试覆盖表把每条契约映射到具体测试文件其中高价值的测试锚点包括契约测试文件Rewind emissionsession-runtime-immunity.test.ts等clearSnapshot 只消费 finalMessageContentclear-snapshot-preserves-state.test.tsProvider 编辑/删除后 capability cache 失效capability-cache-invalidation.test.ts子 Agent view、真实 id、侧栏去重subagent-orchestration.test.ts三 Runtime managed run 持久化、terminal immutablesubagent-run-persistence.test.tsCodex collab action/child identity 分流、匿名 wait 反例codex-event-mapper.test.tsAssistant 流式 checkpoint、同 id 收口、startup interruptedcollect-owner-gate.test.ts切换聊天 detach 与显式 Stop interrupt 分离first-turn-nav-guard.test.ts、interrupt-route-runtime-fanout.test.tsCodex Account dynamic tool surface、per-thread dispatchcodex-builtin-bridge.test.ts、codex-dynamic-tool-bridge.test.ts等terminal missing result、legacy repair 与真实MissingToolResults对照codex-tool-only-completion.test.tsagent-loop-messages.test.tstool-history-integrity.test.tssubprocess stream cancel 与单终态single-owner-stream-writer.test.tstoken usage 非法/缺字段隐藏且不补 0token-usage-display.test.tsmessage-persistence.test.ts从测试组织方式可以看出守护文档的落地路径几乎所有不变量都有行为测试背书且大量测试使用真实协议 fixture而非 mock 理想数据例如 Codex collab 的匿名 wait 反例、真实AI_MissingToolResultsError正/反对照。10. 设计决策日志关键修复的时间线原文档的设计决策日志完整记录了 2026-06 至 2026-08 的主要修复这些条目解释了当前契约为何长成今天的样子2026-07-22用户实测发现 async launch 被误判完成、卡片固定在正文上方、首轮详情打不开终态改以 task_notification 为事实源卡片移到正文末尾/chat首轮侧栏随真实 session 提前可用。2026-07-23真实 Codex 会话da6880f2bd89ed3fd030ee20abcf63d0中三次 managed call 已 foreground await 到终态但父模型仍声称后台处理中——wire 增加显式terminal同一会话后续进展怎么样证明瞬时 side-channel 不足以承担历史事实Codex managed physical run 改写入subagent_runs。同日 Qwen 会话1ff7d214c15e2ed2ba590b3183fe1293证明 app-server turn 正常结束不等于任务成功引入首行结构化 outcome 与 fail-closed。2026-07-24会话ba4855b4c4d272afc85f3a70bbb5b5f4暴露活进程内重复 DB module 初始化误执行 restart sweep 与 transport disconnect 被接到 Runtime abort 两个根因——recovery 移出 schema 初始化并受 live process owner 守门。同日引入 logical run / physical attempt、settling 屏障与 typed lifecycle。2026-07-25Claude follow-up 证明 fail-closed 不能等于永久隐藏——统一为 5 次快速 probe 每 30 秒低频恢复。2026-08-24marketplace 与 CLI/media subprocess stream 的 cancel/exit 同时争抢 controller生产出现 closed-controller Sentry——统一由SingleOwnerStreamWriter认领终态。2026-08-27生产 Sentry 暴露合法 JSON 缺output_tokens使历史 UI 崩溃、非原子回读可能访问saved.id——UI 改为运行时 shape 验证addMessage改为同事务 insert/update/select。11. 结论这套契约的工程价值回顾整份 StreamSession guardrail其工程价值可以归纳为三点双入口对称性无论用户从/chat发起首条消息还是从/chat/[id]续聊状态管理、SSE 解析、取消语义、保存确认都必须行为一致——这是 SDK 0.2.111 接入血泪教训的沉淀。事实比叙述可信原则子 Agent 的完成与否、模型选择是否正确、token 是否真实一律以 durable 的结构化事实subagent_runs、typed lifecycle event、provider raw usage为准父模型写出的正文、SDK 的 envelope、UI 的加载动画都不能越权宣称事实。取消与持久化解耦客户端 detach 与显式 Stop 是两种完全不同的语义服务端 collector 拥有独立的 rejection owner 与 checkpoint 生命周期用户刷新、切换、甚至进程重启都不丢已生成内容。对于要在 CodePilot 上新增 Runtime、改造聊天 UI 或修复流式问题的开发者本文的 32 条不变量、关键文件表、改动检查表与测试锚点构成了完整的防破坏边界。任何新功能接入前建议先对照 测试覆盖 确认行为测试存在再动手改代码。赞分享人工智能AI 应用AI Agent交互助手MCP Clients本地部署【免费下载链接】CodePilotA multi-model AI agent desktop client — connect any AI provider, extend with MCP skills, control from your phone. Built with Electron Next.js.项目地址https://gitcode.com/gh_mirrors/co0dep/CodePilot点击查看免费下载相关推荐CodePilot Harness Home 守护规约实战指南可移植身份、Capability Package 与一致性仓库契约CodePilot Harness Home 守护规约实战指南可移植身份、Capability Package 与一致性仓库契约 Harness Home 是人工智能AI 应用AI Agent交互助手MCP Clients本地部署CodePilot Electron 主进程安全与发布门禁实战指南从窗口生命周期到 packaged 产物的一揽子契约CodePilot Electron 主进程安全与发布门禁实战指南从窗口生命周期到 packaged 产物的一揽子契约 CodePilot 是一个基于 Ele人工智能AI 应用AI Agent交互助手MCP Clients本地部署TrueForge 会话持久化契约ISessionStore 接口、契约测试套件与 CI 路径同步指南TrueForge 会话持久化契约ISessionStore 接口、契约测试套件与 CI 路径同步指南 本文基于 packages/trueforge cor上一篇5个技巧让fish-shell飞起来从卡顿到丝滑的终端优化指南下一篇Jadx项目Java版本兼容性问题解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考