fischer-agentkit/docs/plans/2026-07-02-002-fix-transien...

28 KiB
Raw Blame History

date type title status
2026-07-02 fix 修复私董会 transient state 残留 + ReAct 工具调用引导不足 in-progress

Summary

收尾两个独立 bug(1) 前端 store-level transient stateboardState / debateState / collaborationState)在 createConversation / selectConversation / deleteConversation 三个动作下的重置口径不一致,导致新建对话后私董会顶部标题残留、跨会话状态泄漏;(2) ReAct 引擎 _build_tool_use_prompt 规则 3 "如果不需要工具就能回答,直接回答即可" 给 LLM 留出偷懒窗口,且工具调用提示被后置的 tool section 覆盖,导致复杂需求(涉及外部数据 / 多步分析)下 LLM 倾向于直接回答而非调用 web_search / baidu_search。Bug 1 覆盖前端 3 个 action 路径对称重置Bug 2 仅做 L0提示规则调整L1工具描述扩展与 L2PLAN_EXEC 启用)按用户决策拆为独立 plan。

Progress

Unit 状态 验证 提交
U1 createConversation 重置 done 5 前端单测 pass 7376005
U2 selectConversation 条件重置 done 5 前端单测 pass 7376005
U3 deleteConversation 补全 done 5 前端单测 pass 7376005
U4 ReAct prompt 规则重排 done 6 后端单测 pass 7376005
U5 端到端验证测试 done 11 单测全 pass 7376005
U6 Bug 2 L4 真实 LLM smoke test done 3/4 tool-call + 1/1 direct pass (本 commit)
U7 工作树未提交变更清理 done git status 干净 + vitest 138/139 pass 9e2ccf5..44f4f1c

Bug 2 状态L4 verifiedL0 规则重排在真实 LLM 调用下生效)

L4 smoke test 结果2026-07-02bailian-coding/qwen3.7-plus

  • Probe #1 external_info: PASS8 次 web_search 调用99.9s
  • Probe #2 realtime_data: ERROR120s 超时,非 LLM 不调用工具)
  • Probe #3 multi_step: PASS8 次 web_search 调用62.6s
  • Probe #4 realtime_data_simple: PASS3 次 web_search 调用23.8s
  • Probe #5 no_tool_escape_hatch: PASS0 次工具调用直接回答4.2s
  • 判定3/4 tool-call pass达阈值 ≥3/4+ 1/1 direct pass → L4 verified

PR: http://8.153.107.96/gitea/fischer/fischer-agentkit/pulls/17 ce-code-review: mode:agent, 无 actionable findings ce-test-browser: agent-browser 已安装U6 用脚本直接验证,未走前端)

Problem Frame

Bug 1私董会顶部标题在新对话后残留

根因(chatStore.ts:333-345createConversation() 仅清空 streamingSteps未重置 stream.boardState.value / debateState.value / collaborationState.valueStickyModeHeader.vue:113-117mode computed 依赖 chatStore.boardState 渲染"私董会"模式(带旧专家头像行),新对话切换时状态未清空 → 旧私董会标题持续显示。

同源问题散落三处:

  • createConversation (chatStore.ts:333-345) — 三个 state 全漏
  • selectConversation (chatStore.ts:219-330) — 仅在 404 分支line 266-267重置 board/debate主流程 line 222 仅重置 collaboration正常切换不重置 board/debate
  • deleteConversation (chatStore.ts:348-372) — line 364-365 重置 board/debatecollaborationState

Bug 2Agent 面对复杂需求时倾向直接回答

根因(react.py:1605-1616_build_tool_use_prompt 拼接的规则 3

3. 如果不需要工具就能回答,直接回答即可

此规则是 LLM 偷懒的合法依据。base_promptserver/app.py:200-206)已有正向引导"当你不确定事实信息、时事新闻或任何你不确信的话题时,你必须先使用搜索工具",但位置在 system prompt 前部假设:后注入的 tool section 可能在注意力分配上弱化了 base_prompt 的正向引导(此假设未经 ablation 验证,但规则重排本身的风险可控 — 见 KTDweb_search / baidu_search 工具描述也无"何时使用"的触发条件。

预测Bug 1:若在 createConversation 末尾加 stream.boardState.value = null; stream.debateState.value = null; stream.collaborationState.value = null;StickyModeHeadermode 返回 nullv-if="mode" 不渲染 → 标题消失;同源问题在 selectConversation / deleteConversation 也应统一口径。

预测Bug 2:若规则 3 措辞改为"涉及外部信息、实时数据、多步骤分析或你不确定的事实时必须使用工具;仅在确实无需工具时可直接回答",且重排为规则 1(先说"何时必须",再列"何时不必"LLM 面对"GitHub Trending + 商业价值分析"类需求时调用 web_search 的概率显著提升(实证需 L4 真实 LLM smoke test 验证)。

Requirements

R1Bug 1createConversation 末尾重置 stream.boardState.value = null; stream.debateState.value = null; stream.collaborationState.value = null;(与现有 stream.clearConvSteps 顺序一致,先 stream-owned transient 后 streaming 步骤清理,避免响应式 watcher 误触发)

R2Bug 1selectConversation 在切换到不同 conversation 时(即非 404 分支、亦非 selectConversation(sameId)),替换 line 222 的无条件 collaborationState 重置为顶部条件性三 state 重置(仅当 prevConvId !== id 时触发 boardState / debateState / collaborationState 置 null避免 force-reload 同一会话时误清空状态

R3Bug 1deleteConversation 删除后切换到下一个会话时,若当前会话非 currentConversationId,三个 state 不动;若当前会话被删,三个 state 全部置 null包括 collaborationState),与 selectConversation 口径一致

R4Bug 2 L0_build_tool_use_prompt 规则重排为:

1. 涉及外部信息、实时数据、多步骤分析或你不确定的事实时必须使用工具
2. 每次只调用一个工具
3. 等待工具返回结果后再决定下一步
4. 仅在确实无需工具时可直接回答
5. 不要在回答中重复工具的输出,而是基于结果给出有用的总结

R5Bug 2 L0保持 base_prompt 不动(按用户决策 L1/L2 拆为独立 plan

R6Bug 2 L0不在本次改 web_search / baidu_search 工具 description

Key Technical Decisions

  • 三个 transient state 的重置时机选择:选在 createConversation / selectConversation / deleteConversation action 内统一重置(而非在 useChatStream 初始化时按 conversationId 拆分 ref理由是当前 useChatStream 是 store-level 单例stream-owned state 全部是单一 ref。重构为"按 conversationId 拆分的 reactive map"是更大的架构变更(影响所有读取 stream.boardState 的组件),不在本 plan 范围内
  • selectConversation 切换检测:以 currentConversationId 是否变化为重置条件(即 id !== currentConversationId.value 才重置),避免 selectConversation(sameId, true) 这种 force-reload 误清空
  • createConversation 中重置顺序:先 transient stateboard/debate/collaborationclearConvSteps。理由transient state 派生渲染StickyModeHeader、CollaborationGraph清空它会触发对应组件卸载clearConvSteps 删除 streaming 步骤,触发 streaming UI 收尾。先 transient 后 streaming 保证 UI 状态先稳定再清理流
  • R4 规则重排而非删除:保留原规则 3 的语义("无需工具时可直接回答")作为规则 4仅位置后移 + 措辞收敛。理论选择:本 plan 的修复理论是"位置优先" — 在同一 prompt block 内,靠前的规则获得更多注意力权重。此理论未经 ablation 验证但规则重排的回归风险可控trivial 输入走 DIRECT_CHAT 不进 ReAct。保留 rule 4 的真实理由:非 trivial 但无需外部工具的输入(如"总结这段文字"、"改写这段话")会进入 ReAct 循环,此类输入不应被强制工具化,需要一个 escape hatch。"你好/介绍下自己"类 L1 trivial 输入已走 DIRECT_CHAT不构成保留理由
  • 不动 web_search / baidu_search description:按用户决策推迟到独立 plan。L0 调整后若真实 LLM 行为改善有限再决定 L1
  • 不在 L0 引入 PhasePolicy / PLAN_EXECL2启用 PLAN_EXEC 让复杂需求先输出计划再执行)按用户决策拆为独立 plan
  • 测试策略Bug 1 用 vitest 单元测试覆盖三个 action 的状态重置矩阵Bug 2 L0 用 pytest 单元测试断言 _build_tool_use_prompt 输出文本包含新规则 + 不包含旧规则 3 措辞;不强制跑真实 LLM依赖 API key 与网络,且不稳定),但写一个 mock-based test 验证 web_search 描述出现在 prompt 中
  • Bug 2 验收门槛L0 文本断言通过后Bug 2 状态标记为"hypothesis applied, pending L4 verification"(非"fixed")。在 L1/L2 独立 plan 中包含真实 LLM smoke test用 5 个 probe query如"GitHub Trending 分析"、"最新 AI 新闻"等),对比 fix 前后 web_search 调用率,目标 ≥4/5 触发工具调用。L0 plan 不包含此 smoke test 但在 Verification 中显式记录此降级状态

Implementation Units

U1. createConversation 补全 transient state 重置

Goal: 修复 Bug 1 的第一处泄漏点 — createConversation 创建新会话时同步重置 boardState / debateState / collaborationState 三个 stream-owned ref。

Requirements: R1

Dependencies:

Files:

  • src/agentkit/server/frontend/src/stores/chatStore.ts修改 line 333-345 createConversation
  • src/agentkit/server/frontend/tests/unit/stores/chatStore.test.ts追加测试

Approach:

  • createConversationstream.clearConvSteps(newConversation.id) 之前插入三行:
    stream.boardState.value = null;
    stream.debateState.value = null;
    stream.collaborationState.value = null;
    
  • 不动 stream.collaborationState 已有逻辑line 222 在 selectConversation 顶部重置)
  • 不动 pendingConversations / pendingLastUsedAt(与本 bug 无关)

Patterns to follow:

  • chatStore.ts:264-281 的 404 fallback 中 stream.boardState.value = null; stream.debateState.value = null; 的写法line 266-267— 同样模式
  • chatStore.ts:222stream.collaborationState.value = null; — 单行重置

Test scenarios:

  • Happy pathcreateConversation() 后,chatStore.boardState === nullchatStore.debateState === nullchatStore.collaborationState === null
  • Edge caseselectConversation 一个含 board_started 的旧会话boardState 非 nullcreateConversation() → 三个 state 全为 null
  • Edge casecreateConversation()currentConversationId 指向新会话 ID且新会话的 streamingStepsByConv entry 被清空(已有 stream.clearConvSteps 行为,回归测试)

Verification: cd src/agentkit/server/frontend && npm run test:unit -- --reporter=verbose 2>&1 | grep -E "chatStore|transient" 通过;手动验证:先开 @board再点新建对话StickyModeHeader 不再显示私董会专家头像行

U2. selectConversation 统一 transient state 重置口径

Goal: 修复 Bug 1 的第二处泄漏点 — selectConversation 从带 boardState 的会话切到其他会话时残留旧 boardState同时与 createConversation / deleteConversation 口径对齐。

Requirements: R2

Dependencies: 无(与 U1 并行可合入)

Files:

  • src/agentkit/server/frontend/src/stores/chatStore.ts修改 line 219-330 selectConversation
  • src/agentkit/server/frontend/tests/unit/stores/chatStore.test.ts追加测试

Approach:

  • selectConversation 顶部 line 220 currentConversationId.value = id 之后,判断是否切换到不同会话:
    const isSwitching = currentConversationId.value !== id; // 注意line 220 已写入 id此处判断为切换条件需对比旧值
    
    line 220 已先写入新 id所以需要先把旧 id 缓存到临时变量,再 line 220 写入新 id再判断
  • 若 isSwitching 为 true 且新会话不含 board_startedrestoreBoardStateFromMessages 返回 null三个 state 置 null
    • 由于后续 line 307 stream.boardState.value = restoreBoardStateFromMessages(...) 会覆盖,所以"先置 null 再被覆盖"是安全的
    • 但若旧会话的 boardState 包含 stream-derived 数据(如 liveColorByName可能丢失 — 实际上 boardState.value 被整体覆盖为新对象,旧 stream-derived map 在 allExperts computed 中会基于新 boardState 重新构建(StickyModeHeader.vue:160-184),所以无副作用
  • 简化方案:直接删除 line 222 的 stream.collaborationState.value = null; 无条件重置,替换为 line 219 顶部统一三行:
    const prevConvId = currentConversationId.value;
    currentConversationId.value = id;
    if (prevConvId !== id) {
      stream.boardState.value = null;
      stream.debateState.value = null;
      stream.collaborationState.value = null;
    }
    
  • 保留 404 分支line 258-281的现有逻辑404 时 boardState / debateState 也置 nullline 266-267与主流程口径一致

Patterns to follow:

  • chatStore.ts:222 已有无条件 collaborationState 重置 — 升级为条件性三 state 重置
  • 404 分支 line 264-281 的多 state 重置 + 切换到下一个会话模式

Test scenarios:

  • Happy path从有 boardState 的会话 A 切到会话 B无 boardStateboardState === null debateState === null collaborationState === null
  • Edge case从会话 A 切回 Aforce-reload 同一 id→ 三个 state 保持原值(不被无脑清空)
  • Edge case从会话 A 切到会话 B也无 boardState→ 三个 state 保持 null无变化也无副作用
  • Edge case404 后 createConversation() 流程(已有 fallback 测试)— 三个 state 全 null

Verification: cd src/agentkit/server/frontend && npm run test:unit 通过;手动验证:开 @board再点另一普通会话StickyModeHeader 切到普通模式(不显示私董会头像)

U3. deleteConversation 补全 collaborationState 重置

Goal: 修复 Bug 1 的第三处泄漏点 — deleteConversation 删除当前会话时漏了 collaborationState 重置,与其他两个 action 口径对齐。

Requirements: R3

Dependencies: 无(与 U1/U2 并行可合入)

Files:

  • src/agentkit/server/frontend/src/stores/chatStore.ts修改 line 362-371 deleteConversation 分支)
  • src/agentkit/server/frontend/tests/unit/stores/chatStore.test.ts追加测试

Approach:

  • deleteConversationif (currentConversationId.value === id) 分支 line 364 之后追加一行:
    stream.collaborationState.value = null;
    
  • 与现有 line 364-365 的 board/debate 重置并列
  • 不影响"删除非当前会话"分支line 357 仅从列表移除,三个 state 不变 — 这是正确行为,因为当前会话不切换)

Patterns to follow:

  • chatStore.ts:364-365stream.boardState.value = null; stream.debateState.value = null; 已有模式

Test scenarios:

  • Happy path当前会话有 collaborationState来自 collaboration_graph 消息)→ deleteConversation(currentId)collaborationState === null
  • Edge case删除非当前会话 → 当前会话的三个 state 不变(无副作用)
  • Edge case删除当前会话后自动 createConversation() → 三个 state 全 null与 U1 联动)

Verification: cd src/agentkit/server/frontend && npm run test:unit 通过

U4. ReAct _build_tool_use_prompt 规则重排 + 措辞调整

Goal: 修复 Bug 2 L0 — 重排 _build_tool_use_prompt 规则列表,让"何时必须使用工具"排在"何时可以不用工具"之前,并收窄规则 3 的措辞,去除"偷懒窗口"。

Requirements: R4, R5, R6

Dependencies:

Files:

  • src/agentkit/core/react.py修改 line 1605-1616 _build_tool_use_prompt 返回的 rules 字符串)
  • tests/unit/test_react_engine.py追加测试 TestReActToolUsePromptRules

Approach:

  • 修改 return ( 起的多行字符串中规则部分:
    • 现有规则 3 改为规则 4措辞从"如果不需要工具就能回答,直接回答即可"改为"仅在确实无需工具时可直接回答"
    • 现有规则 1 改为规则 2语义不变"每次只调用一个工具"
    • 现有规则 2 改为规则 3语义不变"等待工具返回结果后再决定下一步"
    • 现有规则 4 改为规则 5语义不变"不要在回答中重复工具的输出"
    • 新增规则 1(在最前):"涉及外部信息、实时数据、多步骤分析或你不确定的事实时必须使用工具"
  • 不动 core_tools / extended_tools 渲染逻辑
  • 不动 _render_core_tools / _render_extended_tools / _maybe_add_tool_search
  • 不动 system_prompt 拼接line 608-611_build_tool_use_prompt 仍以同样方式被追加

Patterns to follow:

  • react.py:1605-1616 现有规则结构 — 替换为 5 条而非删除

Test scenarios:

  • Happy path调用 _build_tool_use_prompt([web_search_tool, read_file_tool]) → 输出包含"必须使用工具"且规则序号正确1 在 2 前)
  • Edge casetools 列表为空 → 走 fast-path不调用 _build_tool_use_prompt),无变化
  • 文本断言:输出不包含"如果不需要工具就能回答,直接回答即可"(旧规则 3
  • 文本断言:输出包含"涉及外部信息、实时数据、多步骤分析或你不确定的事实时必须使用工具"(新规则 1
  • 文本断言:输出包含 <tool_use> XML 格式示例(保持向后兼容)

Verification: pytest tests/unit/test_react_engine.py -k ToolUsePromptRules 通过;pytest tests/unit/test_react_engine.py 全套通过(不破坏现有 200+ 测试)

U5. 端到端验证测试Bug 1 + Bug 2 联动)

Goal: 写一个端到端测试覆盖 Bug 1 的前端 store 行为链 + Bug 2 的后端 prompt 文本,验证两个 fix 在测试套件中都被回归保护。

Requirements: 全部 R1-R6

Dependencies: U1, U2, U3, U4

Files:

  • src/agentkit/server/frontend/tests/unit/stores/chatStore.test.ts追加 describe('transient state reset matrix') 块)
  • tests/unit/test_react_engine.py追加 describe('Bug 2 L0 prompt rules') 块)

Approach:

  • Bug 1 联动测试:在 chatStore.test.ts 写一个"建私董会 → 切新对话 → 切回旧私董会"三步流程,断言中间步骤的三个 state 全为 null最终回到旧私董会时通过 restoreBoardStateFromMessages 重建(注意:此 case 测的是 store-level 状态切换,不依赖后端响应)
  • Bug 2 联动测试:在 test_react_engine.py 写一个"注册 web_search 工具 → 调 _build_tool_use_prompt → 断言 prompt 文本"测试,验证新规则 1 出现在 prompt 头部、web_search 工具描述完整(包含 description + parameters
  • 不跑真实 LLM依赖 API key仅文本层断言

Patterns to follow:

  • chatStore.test.ts:18-81boardStartedMsg / speechMsg / conclusionMsg fixture 模式
  • test_react_engine.py:402-420TestReActSystemPrompt 模式mock gateway + 调 execute + 断言 messages

Test scenarios:

  • Bug 1 三步流程:建私董会(注入 board_started fixturecreateConversation() → 断言三 state null → selectConversation(originalId) → 断言 boardState 重建
  • Bug 1 跨 session建会话 A 含 boardState → selectConversation(B)B 无 board→ 断言三 state null → selectConversation(A) 重新触发 restore → 断言 boardState 重建
  • Bug 2 规则顺序:调 _build_tool_use_prompt → 用 regex r'1\.[^2]*2\.' 断言规则 1 出现在规则 2 之前
  • Bug 2 web_search 描述:调 _build_tool_use_prompt([web_search_tool]) → 断言输出包含 "搜索互联网信息"description 内容)

Verification: cd src/agentkit/server/frontend && npm run test:unit + pytest tests/unit/test_react_engine.py 全部通过

U6. Bug 2 L4 真实 LLM smoke test 验证

Goal: 验证 U4 的 L0 规则重排在真实 LLM 调用中是否生效 — Agent 面对复杂需求(外部信息 / 实时数据 / 多步分析)时是否调用 web_search 而非直接回答。将 Bug 2 状态从 "hypothesis applied, pending L4 verification" 升级为 "verified" 或回退并触发 L1/L2。

Requirements: R4 验证闭环

Dependencies: U4已 donePR #17 合入后执行

Files:

  • tests/manual/test_react_l4_smoke.py新建手动 smoke test 脚本,不进 CI

Approach:

  • 准备 5 个 probe query覆盖外部信息 / 实时数据 / 多步分析 / 不确定事实 / 混合类型:
    1. "收集 GitHub Trending 前 10 个项目信息并分析商业价值"(原 bug 复现 query
    2. "最新 AI 领域有什么重要新闻?"(实时数据)
    3. "对比 React 和 Vue 3 在大型项目中的性能差异"(多步分析 + 外部信息)
    4. "今天上海天气怎么样?"(实时数据,简单)
    5. "请帮我总结这段文字:..."(无需工具,验证 escape hatch 规则 4 仍有效)
  • 对每个 query 跑 ReActEngine.execute(),记录是否触发 web_search tool call
  • query 1-4 期望触发工具调用≥3/4 pass 算通过query 5 期望不触发
  • 如通过率 < 3/4触发 L1工具描述扩展并创建独立 plan
  • 使用 agent-browser 打开 http://localhost:15173 进行前端层验证(可选):在 chat 中输入 probe query观察是否出现 tool_call step

Test scenarios:

  • probe query 1-4ReAct 循环中至少出现一次 web_search tool call
  • probe query 5ReAct 循环中无 tool call直接回答
  • 回归断言U4 单测仍 passL0 文本未变)

Verification: python3 tests/manual/test_react_l4_smoke.py 输出报告5 个 query 的 tool call 统计 + pass/fail 判定。通过后更新本 plan Progress 表 U6 状态为 doneBug 2 状态升级为 "L4 verified"

U7. 工作树未提交变更清理

Goal: 清理工作树中 32 个来自前序 session 的未提交变更,按 concern 分组提交,使工作树恢复干净状态。避免后续开发时 diff 噪声干扰 review。

Requirements: 无(工程治理)

Dependencies: 无(可与 U6 并行)

Files (按 concern 分组):

分组 文件 来源 session 建议提交方式
A. expert avatar emoji 移除 configs/experts/*.yaml (15 个) emoji 移除 plan (2026-07-02-001) 单独 commit refactor: expert avatar 改为首字符
B. dev 环境配置 docker-compose.yaml, scripts/dev-start.sh, docker-compose.dev.yml, .env.dev, src/agentkit/server/config.py dev 环境修复 session 单独 commit fix: dev 环境配置 + 端口隔离
C. board 元数据持久化 src/agentkit/experts/board_orchestrator.py, src/agentkit/server/routes/chat.py 私董会持久化修复 session 单独 commit fix: board_speech/round_summary 持久化 avatar/color 元数据
D. 前端方案B + board UI StickyModeHeader.vue, expertIdentity.ts, useMessageRenderer.ts, BoardRoundCard.vue, MessageShell.vue, Scene4BoardDiscussion.vue, chatStream.ts, types.ts, LoginView.vue 方案B + 私董会限制 session 需 review 后 commit部分可能已通过 PR #15 合入
E. .understand-anything .understand-anything/* (3 tracked + untracked) knowledge graph 工具 加入 .gitignore 或单独 commit
F. 未跟踪 plan/brainstorm 文档 docs/brainstorms/2026-07-02-.md, docs/plans/2026-07-02-001-.md ce-plan/ce-brainstorm 产物 commit 为决策记录

Approach:

  • 对每组 git diff HEAD -- <files> 检查变更内容,确认无冲突
  • 分组 commit每组 commit message 遵循 conventional commits 格式
  • D 组需特别注意:检查是否与已合入的 PR #15 内容重叠,避免重复提交
  • E 组(.understand-anything建议加入 .gitignore 而非 commit是工具生成的本地索引
  • 如某组变更属于未完成的 feature如方案B则 stash 而非 commit待对应 plan 完成后再提交

Test scenarios:

  • 每组 commit 后 git status --short 该组文件不再出现
  • 全部完成后 git status --short 仅显示 untracked.understand-anything 等 gitignored 项)
  • npm run typecheck + ruff check src/ 仍通过(确认无回归)

Verification: git status --short 输出为空(或仅 gitignored 项);npm run test:unit + pytest tests/unit/ -x -q 全套通过

Out of Scope

  • L1工具描述扩展web_search / baidu_search / web_crawl 工具 description 添加"何时使用"触发关键词(如"需要最新互联网信息、新闻、Trending、股价时使用 web_search")。按用户决策推迟为独立 plan
  • L2PLAN_EXEC 启用):在 default agent 上注入 PhasePolicy 让复杂需求先输出 Plan 再执行。涉及 phase 配置、auto-advance 阈值、违规处理、phase event WS 协议。影响面较大,按用户决策拆为独立 plan
  • 重构 stream-owned state 为按 conversationId 拆分:当前是 store-level 单 ref导致每次"切换会话"必须显式重置。改为 Map<conversationId, BoardState> 可从根上消除泄漏,但影响所有 chatStore.boardState 读取点StickyModeHeader / useMessageRenderer 等),属于架构重构
  • base_prompt 调整:保持原样,按用户决策
  • 私董会生命周期 / Skill 路由策略 / tool registry 架构 / LLM gateway:均不动

Risks & Dependencies

  • R-U4-1(低):规则重排可能影响现有 LLM 行为 — 风险点在某些 LLM 训练分布下"正向规则 1"可能让 LLM 过度工具化trivial 输入也调工具)。缓解:测试覆盖 trivial 输入走 DIRECT_CHAT 不进 ReAct 循环request_preprocessor 已保证pytest 单元测试断言新规则在 prompt 中但不验证 LLM 行为
  • R-U1/2/3-1state 重置顺序在同步代码路径createConversation、deleteConversation 重置块)中不会触发中间态渲染 — Vue 响应式批量更新在 microtask 中合并。但 selectConversation 有 async 路径:await apiClient.getConversation(id) 位于顶部 resetboardState → null和 post-fetch restoreline 307 restoreBoardStateFromMessages)之间。在 fetch 期间 Vue 会渲染一帧 boardState=null导致 StickyModeHeader 卸载再重载。这是期望行为("无旧数据残留"),非 race condition。切换两个私董会会话时 header 会短暂消失再出现 — 若需平滑过渡可在 follow-up 中加 skeleton placeholder
  • D-frontend-build(低):前端改动需要重新 build staticnpm run build:frontend)才能被 backend 静态服务拾取。AGENTS.md 已记录此风险

Deferred to Follow-Up Work

  • L1web_search / baidu_search 工具 description 扩展(独立 plan— 仅在 U6 L4 smoke test 未通过时触发
  • L2启用 PLAN_EXEC phase policy 处理复杂需求(独立 plan— 仅在 U6 通过但工具调用率仍不理想时触发
  • 重构 stream-owned state 为按 conversationId 拆分(架构性,独立 plan

Verification (per unit, summary)

  • U1/U2/U3cd src/agentkit/server/frontend && npm run test:unit 全套通过;新增 3 个 describe 块共 8+ test cases
  • U4pytest tests/unit/test_react_engine.py -k ToolUsePromptRules 通过;新增 1 个 test class 4-5 个 test cases已 doneBug 2 状态声明L0 文本断言通过后 Bug 2 标记为 "hypothesis applied, pending L4 verification"(非 "fixed"),真实 LLM smoke test 在 U6 中执行
  • U5完整套件通过端到端 4-5 个联动测试(已 done11 单测全 pass
  • U6python3 tests/manual/test_react_l4_smoke.py 输出 5 个 probe query 的 tool call 统计≥3/4 外部信息 query 触发 web_search + query 5 不触发 → Bug 2 状态升级为 "L4 verified"
  • U7git status --short 为空(或仅 gitignored 项);npm run test:unit + pytest tests/unit/ -x -q 全套通过
  • 集成:python3 -m pytest tests/unit/ -x -qAGENTS.md 硬约束) + cd src/agentkit/server/frontend && npm run test:unit 通过
  • Lintruff check src/ && ruff format src/AGENTS.md 硬约束)通过
  • TypeScriptcd src/agentkit/server/frontend && npm run typecheck 通过