@@ -56,7 +56,7 @@ scripts/start-tui.sh # 启动 TUI(RELAY_PORT=3001)
5656
5757** [ TRAP] ** 多工具并发的结果处理循环中,P3/P4 错误路径提前返回会导致后续 tool_result 缺失。必须用 deferred_error 模式——先收集所有错误,循环结束后统一判断。所有 tool_result 必须始终写入 state。(详见 spec/global/domains/agent.md#issue_2026-05-14-orphaned-tool-use-without-tool-result,spec/global/domains/agent.md#issue_2026-05-15-tool-execution-error-stops-agent,spec/global/domains/agent.md#issue_2026-05-18-agent-tool-calls-execute-serially)
5858
59- ** [ TRAP] ** ` prepended_ids ` 必须只追踪 ` prepend_message ` 插入的消息,不能计入 ` add_message ` 。` before_agent ` 中间件有两种注入方式:` prepend_message ` (头部 insert System)和 ` add_message ` (尾部 push Ai/Tool)。cleanup 时只能清理前者。旧逻辑用 ` len_after - len_before ` 从头部取 N 条 ID,会把 ` add_message ` 的尾部追加也计入 N,导致从头部误删原始消息,破坏 Ai[ ToolUse] /Tool[ ToolResult] 配对,产生 Anthropic 400 孤儿 tool_result。正确做法:` take_while(|m| m.is_system()) ` 只收集头部连续 System 消息。** 新增中间件在 ` before_agent ` 中使用 ` add_message ` 注入非 System 消息时,不会受 cleanup 影响,但绝不能假设 cleanup 会帮你清理这些消息。** (详见 spec/issues/2026 -05-26-skillpreload-anthropic-400-tool-result-orphan.md )
59+ ** [ TRAP] ** ` prepended_ids ` 必须只追踪 ` prepend_message ` 插入的消息,不能计入 ` add_message ` 。` before_agent ` 中间件有两种注入方式:` prepend_message ` (头部 insert System)和 ` add_message ` (尾部 push Ai/Tool)。cleanup 时只能清理前者。旧逻辑用 ` len_after - len_before ` 从头部取 N 条 ID,会把 ` add_message ` 的尾部追加也计入 N,导致从头部误删原始消息,破坏 Ai[ ToolUse] /Tool[ ToolResult] 配对,产生 Anthropic 400 孤儿 tool_result。正确做法:` take_while(|m| m.is_system()) ` 只收集头部连续 System 消息。** 新增中间件在 ` before_agent ` 中使用 ` add_message ` 注入非 System 消息时,不会受 cleanup 影响,但绝不能假设 cleanup 会帮你清理这些消息。** (详见 spec/global/domains/agent.md#issue_2026 -05-26-skillpreload-anthropic-400-tool-result-orphan)
6060
6161** 消息类型** :` BaseMessage ` (Human/Ai/System/Tool),` ContentBlock ` (Text/Image/Document/ToolUse/ToolResult/Reasoning/Unknown)。
6262
@@ -70,7 +70,7 @@ scripts/start-tui.sh # 启动 TUI(RELAY_PORT=3001)
7070
7171** [ INFO] ** ` MessageViewModel ` 已不再包含 ` message_id ` 字段。SubAgentGroup 使用 ` instance_id: Option<String> ` 标识。新增 VM 变体时注意身份标识字段与显示字段分离。
7272
73- ** [ TRAP] ** ` Interrupted ` /` Error ` + ` Done ` 互斥:` Interrupted ` /` Error ` 先 ` request_rebuild() ` + 添加通知,设 ` reconcile_already_done=true ` ,后续 ` Done ` 跳过 ` request_rebuild() ` 防止覆盖通知。(详见 spec/global/domains/agent.md#issue_2026-05-25-interrupt-undo-last-user-message)
73+ ** [ TRAP] ** ` Interrupted ` /` Error ` + ` Done ` 互斥:` Interrupted ` /` Error ` 先 ` request_rebuild() ` + 添加通知,设 ` reconcile_already_done=true ` ,后续 ` Done ` 跳过 ` request_rebuild() ` 防止覆盖通知。(详见 spec/global/domains/agent.md#issue_2026-05-25-interrupt-undo-last-user-message)** [ TRAP ] ** Cancel 后历史不应无条件截断:ACP server 在 ` result.ok==false ` 时无条件 truncate history 会丢失 agent 已写入 state 的消息,导致 agent 失忆。应检查 ` result.messages.len() ` 判断是否有进展,有则保留。(详见 spec/global/domains/agent.md#issue_2026-05-26-ctrl-c-interrupt-causes-agent-amnesia)
7474
7575** [ TRAP] ** frozen_subagent_vms:` frozen_subagent_vms: Vec<MessageViewModel> ` 按 agent_id + 位置匹配(先 instance_id 精确匹配,失败后按顺序 agent_id 匹配)。轮次作用域状态(frozen_vms、ephemeral_notes)在 ` begin_round() ` 时显式清空;` done() ` 不清空 frozen_subagent_vms(允许 build_tail_vms 在 Done 到下一轮之间消费)。(详见 spec/global/domains/message-pipeline.md#issue_2026-05-16-frozen-subagent-vms-cross-round-accumulation-duplication)
7676
@@ -191,7 +191,7 @@ session/new → chrono::Local::now() → frozen_date
191191- ` DISABLE_COMPACT ` / ` DISABLE_AUTO_COMPACT ` / ` COMPACT_THRESHOLD ` :每轮读取 env,且被 executor 和 builder ** 重复读取两次**
192192- ` peri_config ` 、Provider Snapshot、context_window、context_1m:每轮从 ` Arc<RwLock<>> ` 克隆快照
193193- 整个中间件链、AgentState、Cancel Token、Langfuse Tracer:每轮全新构造
194- - ** SubAgent 系统提示词** :调用 ` build_system_prompt(None, ...) ` 不走 frozen 路径,完全重建
194+ - ** SubAgent 系统提示词** :调用 ` build_system_prompt(None, ...) ` 不走 frozen 路径,完全重建。 ** [ TRAP ] ** 这会导致 SubAgent 使用当前 runtime config 而非 frozen 值(如 language),在同一会话中与 Main Agent 产生漂移。所有 frozen 字段必须通过 ` AcpAgentConfig ` 传递到 SubAgent builder。(详见 spec/global/domains/system-prompt.md#issue_2026-05-27-language-injection-subagent-drift-cache-isolation)
195195
196196** 核心文件** :
197197| 文件 | 职责 |
@@ -267,7 +267,7 @@ session/new → chrono::Local::now() → frozen_date
267267| ` peri-agent/src/agent/compact/re_inject.rs ` | ` re_inject() ` :重新注入文件/技能上下文 |
268268| ` peri-agent/src/agent/compact/config.rs ` | ` CompactConfig ` :阈值、开关、环境变量覆盖 |
269269| ` peri-agent/src/agent/compact/invariant.rs ` | 消息轮次分组(工具调用配对完整性检查) |
270- | ` peri-middlewares/src/compact_middleware.rs ` | ` CompactMiddleware ` :` before_model ` 钩子,在 ReAct 循环内触发 compact |
270+ | ` peri-middlewares/src/compact_middleware.rs ` | ` CompactMiddleware ` :` before_model ` 钩子,在 ReAct 循环内触发 compact。 ** [ TRAP ] ** Micro compact 必须加 once-per-prompt 守卫(AtomicBool),否则每轮都重复触发。(详见 spec/global/domains/compact.md#issue_2026-05-23-micro-compact-repeated-triggering) |
271271| ` peri-acp/src/session/executor.rs ` | executor 中 compact 触发判断(阈值检查) |
272272| ` peri-tui/src/acp_server/compact.rs ` | 手动 compact 入口:` full_compact() ` + ` re_inject() ` |
273273| ` peri-tui/src/command/session/compact.rs ` | ` /compact ` 命令路由 |
@@ -309,7 +309,7 @@ session/new → chrono::Local::now() → frozen_date
309309
310310` .claude/agents/{agent_id}/agent.md ` 定义。` tools ` 为空继承父工具(排除 Agent 防递归),有值仅保留允许列表,` disallowedTools ` 额外排除。插件 agent 通过 ` scan_agents_with_extra_dirs ` 追加搜索路径。
311311
312- **[TRAP]** Background agent 工具完全依赖 `register_tool` 传递,跨 async 边界需确保 Arc 引用生命周期。多语义叠加(fork+background)需明确优先级,跨轮次累积数据(frozen_vms)必须有清理机制。**[TRAP]** Normal/Fork 子 Agent 透传 event_handler 导致事件溢出,StateSnapshot/ContextWarning/LlmRetrying 缺少 in_subagent() 守卫——新增事件类型时必须同步检查所有事件处理路径的守卫。**[TRAP]** 并发 SubAgent 场景:事件路由必须用 `source_agent_id` 精确匹配而非位置堆栈;流式循环必须 `tokio::select!` 竞争取消令牌防止 Ctrl+C 死锁;事件通道容量:主 executor 用 `unbounded_channel()`(无界),`bg_event_tx` 用 `channel(128)`。(详见 spec/global/domains/agent.md#issue_2026-05-12-background-agent-display-and-continuation-bugs,spec/global/domains/agent.md#issue_2026-05-13-sync-subagent-events-leak-to-parent,spec/global/domains/tui.md#issue_2026-05-15-concurrent-subagent-display-delay,spec/global/domains/agent.md#issue_2026-05-16-concurrent-subagent-tool-call-routing-and-background,spec/global/domains/agent.md#issue_2026-05-18-agent-tool-calls-execute-serially,spec/global/domains/agent.md#issue_2026-05-19-concurrent-subagent-duplicate-id,spec/global/domains/agent.md#issue_2026-05-24-concurrent-bg-agent-only-one-completion,spec/global/domains/agent.md#issue_2026-05-26-sync-subagent-cancel-fix-attempts-log)
312+ **[TRAP]** Background agent 工具完全依赖 `register_tool` 传递,跨 async 边界需确保 Arc 引用生命周期。多语义叠加(fork+background)需明确优先级,跨轮次累积数据(frozen_vms)必须有清理机制。**[TRAP]** Normal/Fork 子 Agent 透传 event_handler 导致事件溢出,StateSnapshot/ContextWarning/LlmRetrying 缺少 in_subagent() 守卫——新增事件类型时必须同步检查所有事件处理路径的守卫。**[TRAP]** 并发 SubAgent 场景:事件路由必须用 `source_agent_id` 精确匹配而非位置堆栈;流式循环必须 `tokio::select!` 竞争取消令牌防止 Ctrl+C 死锁;事件通道容量:主 executor 用 `unbounded_channel()`(无界),`bg_event_tx` 用 `channel(128)`。(详见 spec/global/domains/agent.md#issue_2026-05-12-background-agent-display-and-continuation-bugs,spec/global/domains/agent.md#issue_2026-05-13-sync-subagent-events-leak-to-parent,spec/global/domains/tui.md#issue_2026-05-15-concurrent-subagent-display-delay,spec/global/domains/agent.md#issue_2026-05-16-concurrent-subagent-tool-call-routing-and-background,spec/global/domains/agent.md#issue_2026-05-18-agent-tool-calls-execute-serially,spec/global/domains/agent.md#issue_2026-05-19-concurrent-subagent-duplicate-id,spec/global/domains/agent.md#issue_2026-05-24-concurrent-bg-agent-only-one-completion,spec/global/domains/agent.md#issue_2026-05-26-sync-subagent-cancel-fix-attempts-log)**[TRAP]** 同步 SubAgent 取消传播:父 Agent 的 cancel token 必须传播到同步 SubAgent 执行上下文,否则 Ctrl+C 无法中断 SubAgent。(详见 spec/global/domains/agent.md#issue_2026-05-25-ctrl-c-cannot-interrupt-sync-subagent)
313313
314314## LSP 中间件
315315
@@ -438,3 +438,4 @@ Command trait 的 `description()` 接收 `&LcRegistry` 参数并返回 `String`
438438- ** ` app/mod.rs ` 模块组织** :使用 ` include! ` 按功能类别分组声明(` modules_panels.inc ` /` modules_agent.inc ` /` modules_state.inc ` /` modules_system.inc ` ),每个 ` .inc ` 文件声明一组相关模块。新增模块按类别加入对应的 ` .inc ` 文件,避免 ` app/mod.rs ` 膨胀。
439439- ** ` app/edit_utils.rs ` ** :从 ` app/mod.rs ` 拆出的文本编辑辅助函数(` build_textarea ` /` handle_edit_key ` /` ensure_cursor_visible ` /` edit_display_parts ` ),供多面板共用。
440440- ** 插件面板拆分** :handler 从 ` plugin_panel/handlers.rs ` 拆分为 ` handlers/plugin_handlers/ ` 9 个子模块(delete/discover_detail/discover_list/discover_search/install/installed_detail/marketplace/persistence/mod)。渲染从 ` panels/plugin.rs ` 拆分为 ` panels/plugin/mod.rs ` + ` plugin_render/ ` 6 个子模块(add_marketplace/detail/discover_detail/discover_list/discover_search/list)。
441+ - ** 跨平台 spawn [ TRAP] ** :所有子进程 spawn 必须通过平台感知的统一 wrapper(` shell_command()/spawn_shell() ` ),Windows 用 ` cmd /C ` 、Unix 用 ` bash -c ` 。三处调用点(MCP transport、Hooks executor、Bash 工具)已统一,新增 spawn 时必须复用。(详见 spec/global/domains/mcp.md#issue_2026-05-27-cross-platform-spawn-wrapper)
0 commit comments