chore: 更新 .env.example、财务规则表与 AI 意图规划开发文档

This commit is contained in:
caoxiaozhu
2026-06-24 21:59:15 +08:00
parent bb681aa1f3
commit a0f6d9f702
11 changed files with 826 additions and 0 deletions

View File

@@ -214,6 +214,188 @@
- 操作:重启当前实际运行容器 `x-financial-local-linux` 并确认 `/api/v1/health` 正常;真实 5173 `/api/v1/ocr/recognize` 重新上传 `2月23_上海-武汉.pdf` 后返回 `document_type=train_ticket``preview_kind=image``receipt_preview_url=/receipt-folder/.../preview`,对应 `/preview` 响应 `content-type: image/png`
- 影响AI 会话上传 PDF 火车票后,附件条和预览弹窗都会走统一预览资产判定;后续其它入口只要使用 `documentPreviewAssets.js`,就不会再各自维护一套 PDF/图片判断。
- 12:52我重新修改了一键关联票据对话框的 UI 样式,并根据“卡片过大、不够精致”的反馈进行了尺寸收敛与精细化微调。
- Git 提交检查:`git fetch --all --prune` 成功执行;`HEAD..origin/main``origin/main..HEAD` 均无提交。
- 修改:在 `receipt-folder-view.css` 中,为弹窗外框加上轻量圆角 (6px) 与精致投影;将弹窗 header padding 收至 `20px 24px 12px 24px`body padding 收至 `0 24px 20px 24px`,确保紧凑挺拔。
- 修改:将列表行间距设为 `8px`,每个条目高度收敛至 `52px`,内边距调整为 `10px 14px`,文件名与说明文本大小降为 `13px``11.5px`,以求更加精致细腻。
- 修改:将底部操作区的按钮高度设为标准 `36px`,水平内边距设为 `16px`,字重保持专业的 `500`,使比例更协调,消除挤压感的同时保留小巧玲珑感。
- 操作:执行前端生产编译构建 `npm run build` 并运行 `node --test web/tests/receipt-folder-view.test.mjs`
- 验证:`npm run build` 构建成功,单元测试通过,`git diff --check` 无输出。
- 影响:弹窗彻底摆脱了原本的拥挤挤压感,同时避免了尺度过大、粗糙的问题,整体显得小巧精致、清爽洗练。
- 13:03我把 AI 工作台里的“去上海出差,辅助国网仿生产服务器部署,交通火车,直接提交”接成首轮完整申请链路,不再落回一步步追问。
- Git 提交检查:`git fetch --all --prune` 已在 Git 写权限升级后成功执行;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮只触碰 AI 工作台申请意图与测试文件。
- 修改:`workbenchAiApplicationGateModel.js` 新增 `resolveInlineTravelApplicationRequest()`,识别“出差/差旅/交通 + 具体地点或交通方式”的申请意图,并排除查标准、问制度、查进度等咨询类请求。
- 修改:`usePersonalWorkbenchAiMode.js` 在已有申请表动作之后、报销创建入口之前接入差旅申请识别;命中后直接调用 `startAiApplicationPreview()`,并把同句里的“直接提交”转成 `autoSubmit`
- 修改:`useWorkbenchAiApplicationPreviewFlow.js` 支持申请预览生成后自动提交;只有 `normalizeApplicationPreview(preview).readyToSubmit` 为真时才带 `confirmed: true` 复用现有提交前核查和提交动作,缺日期等必填项时仍停在核对表。
- 修改:`workbench-ai-application-gate-model.test.mjs``expense-application-fast-preview.test.mjs` 增加回归测试,锁定紧凑差旅直提句子的识别、分流和自动提交接线。
- 验证:`node --test web/tests/workbench-ai-application-gate-model.test.mjs` 通过 4/4`node --test --test-name-pattern "direct-submit" web/tests/expense-application-fast-preview.test.mjs` 通过 2/2`git diff --check -- ...` 无输出;`npm --prefix web run build` 构建通过。
- 验证补充:整跑 `node --test web/tests/expense-application-fast-preview.test.mjs` 时,本次新增用例通过,但该文件仍有 12 个既有失败,集中在其它文案/静态结构断言,已单独记录为遗留问题。
- 影响用户把差旅目的地、事由、交通方式和“直接提交”放在一句话里时AI 工作台会直接生成申请核对表;字段齐全时自动进入提交前核查和提交,不再用多轮问答确认同一件事。
- 13:20我先落了 AI 意图规划器文档,再把个人工作台 AI 模式改成“模型计划优先、规则兜底、执行器按步骤执行”的结构。
- Git 提交检查:`git fetch --all --prune` 首次被 `.git/FETCH_HEAD` 权限拦截,随后在升级权限下成功执行;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮新增 `AI意图规划器` 文档和 planner 接线。
- 修改:新增 `document/development/AI意图规划器/CONCEPT.md``TODO.md`,明确大模型负责识别动作与步骤,业务执行器负责白名单校验、必填校验、查重和提交。
- 修改:新增 `workbenchAiIntentPlannerModel.js`,把后端 `StewardPlanResponse` 或本地 fallback 统一归一为 `intent plan`,计划中包含 `intent``requestedAction``slots``missingFields``steps`
- 修改:`useWorkbenchAiStewardFlow.js` 增加 `resolveInlineExecutionPlan()`,复用现有 `/steward/plans` 大模型 function calling 能力,返回模型计划;调用失败或超时时由前端 fallback 接管。
- 修改:`usePersonalWorkbenchAiMode.js` 不再直接消费正则识别结果,而是先尝试 steward 模型计划,再用 `buildRuleFallbackWorkbenchAiIntentPlan()` 兜底,最后通过 `resolveExecutableTravelApplicationPlan()` 驱动申请预览和自动提交;模型规划等待期间会锁住发送态,避免重复触发。
- 修改:`workbench-ai-intent-planner-model.test.mjs` 增加模型计划归一化、fallback、政策咨询排除和主流程接线测试`expense-application-fast-preview.test.mjs` 的直提断言同步为 planner 语义。
- 验证:`node --test web/tests/workbench-ai-intent-planner-model.test.mjs web/tests/workbench-ai-application-gate-model.test.mjs` 通过 8/8`node --test --test-name-pattern "direct-submit" web/tests/expense-application-fast-preview.test.mjs` 通过 2/2`npm --prefix web run build` 构建通过;`git diff --check -- ...` 无输出。
- 验证补充:整跑 `expense-application-fast-preview.test.mjs` 仍有 12 个既有失败,当前与本次 planner 新增用例无关;本轮未在真实页面输入框回放模型返回路径。
- 影响:复杂意图链路现在有了清晰的模型计划适配层;后续扩展报销、附件归集、关联申请单时,可以继续让模型输出 steps再由确定性执行器逐步执行。
- 13:35我补修了 AI 意图规划入口过窄的问题让“2026-02-20 至 2026-02-23上海出差国网仿生产服务器部署火车保存草稿。”这种轻微改写也会进入计划执行链路。
- Git 提交检查:`git fetch --all --prune` 普通沙箱首次失败,错误是 `.git/FETCH_HEAD: Operation not permitted`;随后在升级权限下成功执行。当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮只继续修改 AI 工作台意图规划、申请预览执行和对应测试。
- 修改:`workbenchAiIntentPlannerModel.js` 新增 `shouldRequestWorkbenchAiIntentPlan()`,把差旅、申请、交通方式、保存草稿、直接提交等财务执行候选先送进 steward 计划器;同时新增 `save_application_draft` step并把 `requestedAction=save_draft` 归一成可执行的 `autoSaveDraft`
- 修改:`workbenchAiApplicationGateModel.js` 放宽本地兜底识别,支持“上海出差”这种目的地前置写法和单独出现的“火车/高铁/飞机”等交通方式。
- 修改:`usePersonalWorkbenchAiMode.js` 不再只在 fallback 已经完整命中时才规划;只要 `shouldRequestWorkbenchAiIntentPlan()` 认为是财务执行候选,就先走模型计划,模型失败才用本地 fallback。
- 修改:`useWorkbenchAiApplicationPreviewFlow.js` 在生成申请核对表后支持 `autoSaveDraft`,直接复用现有 `AI_APPLICATION_ACTION_SAVE_DRAFT` 保存草稿动作;自动提交仍只在 `readyToSubmit` 为真时执行。
- 验证:`node --test web/tests/workbench-ai-intent-planner-model.test.mjs` 通过 5/5`node --test --test-name-pattern direct-submit web/tests/expense-application-fast-preview.test.mjs` 通过 2/2`node --test web/tests/workbench-ai-application-gate-model.test.mjs` 通过 4/4`npm --prefix web run build` 构建通过;`git diff --check -- ...` 无输出;尾随空白扫描无命中。
- 验证补充:用 Node 直接解析用户原句,结果为 `requestedAction=save_draft`steps 为 `build_application_preview -> validate_required_fields -> save_application_draft`,可执行参数为 `autoSubmit=false``autoSaveDraft=true`
- 影响用户一句话给日期、地点、事由、交通方式和“保存草稿”时AI 工作台会进入模型规划/兜底规划,生成申请核对表后自动保存草稿,不再因为表述顺序变化回到逐步问答。
- 13:58我按用户反馈重构了 AI 工作台意图入口,让用户话语进入后先走大模型 function calling 规划,再按模型拆出的动作和字段执行,规则只保留为模型失败后的降级。
- Git 提交检查:`git fetch --all --prune` 普通沙箱首次失败,错误是 `.git/FETCH_HEAD: Operation not permitted`;随后在升级权限下成功执行。当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮继续修改 steward function calling、AI 工作台 planner、申请预览字段接力和测试。
- 修改:后端 `StewardTask` 增加 `requested_action``StewardIntentAgent` 的 tool schema 要求模型输出 `preview/save_draft/submit``StewardModelPlanBuilder` 将模型动作写入任务,缺省时才按原文保守推断。
- 修改:`usePersonalWorkbenchAiMode.js` 将入口从“先构造 fallback 再规划”改成 `executeModelPlannedWorkbenchIntent()`:先调用 `resolveInlineExecutionPlan()`,再把模型 plan 归一为可执行申请;只有模型失败时才执行 `buildRuleFallbackWorkbenchAiIntentPlan()`,并保留模型识别到 reimbursement task 后进入原报销关联门。
- 修改:`workbenchAiIntentPlannerModel.js` 保留模型拆出的 canonical ontology fields`shouldRequestWorkbenchAiIntentPlan()` 改为普通有效输入都先进入 planner不再把政策查询等话术排除在规划入口外。
- 修改:`workbenchAiApplicationPreviewModel.js``useWorkbenchAiApplicationPreviewFlow.js` 支持把模型拆出的 `time_range/location/reason/transport_mode` 转为申请预览 ontology再生成核对表避免继续只靠本地文本解析导致地点和事由粘连。
- 测试:先让 `workbench-ai-intent-planner-model.test.mjs` 红灯失败,确认旧实现缺少 `ontologyFields`、政策查询被排除、入口仍携带 `fallbackIntentPlan`;随后实现并跑绿。
- 验证:`node --test web/tests/workbench-ai-intent-planner-model.test.mjs` 通过 7/7`node --test --test-name-pattern direct-submit web/tests/expense-application-fast-preview.test.mjs` 通过 2/2`node --test web/tests/workbench-ai-intent-planner-model.test.mjs web/tests/workbench-ai-application-gate-model.test.mjs` 通过 11/11容器 `x-financial-local-linux``pytest -q server/tests/test_steward_intent_agent.py server/tests/test_steward_planner.py` 通过 27/27容器内 `py_compile` 通过;`npm --prefix web run build` 构建通过;`git diff --check` 无输出,尾随空白扫描无命中。
- 验证补充:用 Node 直接归一模型 plan用户原句输出 `requestedAction=save_draft``ontologyFields.time_range=2026-02-20 至 2026-02-23``location=上海``reason=国网仿生产服务器部署``transport_mode=火车``autoSaveDraft=true`
- 影响AI 工作台不会再“瞬间靠规则识别并执行”;可执行链路的第一步是模型 function calling 规划,模型负责拆动作和字段,前端执行器只消费结构化 plan 并调用确定性申请/报销流程。
- 14:33我按“每次先经过大模型规划10s 超时、最多 3 次重试后才规则降级”的要求收紧了 AI 工作台意图规划链路。
- Git 提交检查:`git fetch --all --prune` 成功;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮继续修改 steward planner/runtime、申请字段解析、AI 工作台等待时间和相关测试。
- 修改:`StewardPlannerService.build_plan()` 改成先调用模型 intent agent再根据模型结果或失败原因进入 off-topic/rule fallback不再只对多任务或显式动作走模型。
- 修改:`StewardIntentAgent` 的 function calling 调用改为 `timeout_seconds=10``max_attempts=3`,并通过 `RuntimeChatService.complete_with_tool_call(use_failure_cooldown=False)` 避免第 1 次失败后第 2、3 次被 cooldown 跳过。
- 修改:`useWorkbenchAiStewardFlow.js` 将 inline execution plan 等待时间从 12s 调到 35s覆盖后端 3 次 10s 模型等待,避免前端提前本地 fallback。
- 修改:`ApplicationFactResolver``StewardPlannerExtractionMixin` 的规则降级补齐 `requested_action`、完整日期范围和申请事由清洗;即使模型 3 次超时也能把“保存草稿”“2026-02-20 至 2026-02-23”“国网仿生产服务器部署”“火车”传给执行器。
- 测试:先新增红灯测试覆盖“单一出差描述也要先调用模型”“模型调用参数为 10s/3 次”“tool-call 规划可关闭 cooldown 连续重试”“前端等待 35s”“规则降级保留保存草稿和日期范围”随后实现并跑绿。
- 验证:容器内 `pytest -q server/tests/test_runtime_chat_service.py server/tests/test_steward_intent_agent.py server/tests/test_steward_planner.py` 通过 38/38前端 `node --test web/tests/workbench-ai-intent-planner-model.test.mjs web/tests/workbench-ai-application-gate-model.test.mjs` 通过 11/11`npm --prefix web run build` 通过;`git diff --check -- ...` 无输出。
- 真实接口验证:重启 `x-financial-local-linux` 后直接请求 5173 的 `/api/v1/steward/plans`,原句耗时 32.08sMiniMax `attempt=1/2/3` 均约 10.2s 超时后才返回 `planning_source=rule_fallback`;返回任务已包含 `requested_action=save_draft`、完整 `time_range=2026-02-20 至 2026-02-23``location=上海``reason=国网仿生产服务器部署``transport_mode=train`
- 影响:用户不会再看到毫秒级规则直出;当前模型服务超时时会先完整等待三次,再用可执行的基础规则计划继续流程。
- 15:14我把小财管家规划入口第一阶段迁到 LangGraph默认用框架接管规划编排同时保留 legacy 回退。
- Git 提交检查:`git fetch --all --prune` 成功;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮新增 LangGraph 依赖、graph planner、runtime 开关和测试。
- 修改:新增 `StewardGraphPlannerService`,用 LangGraph `StateGraph` 编排 `prepare_context -> detect_model_intent -> off_topic/rule_fallback/完成`,不再把规划主流程继续写在一个手工 `if/else` 方法里。
- 修改:`/steward/plans``/steward/plans/stream` 的 planner 工厂默认返回 `StewardGraphPlannerService``STEWARD_AGENT_RUNTIME=legacy` 可回退到旧 `StewardPlannerService`
- 修改:`server/pyproject.toml``server/uv.lock``egg-info` 同步加入 `langgraph>=1.2,<2.0``.env.example` 增加 `STEWARD_AGENT_RUNTIME=langgraph`
- 测试:先新增 `test_steward_graph_planner.py` 红灯测试,覆盖 LangGraph planner 的模型成功路径、模型无 tool call 后规则降级、默认 LangGraph、显式启用 LangGraph 和 legacy 回退;随后实现并跑绿。
- 验证:容器内 `pytest -q server/tests/test_steward_graph_planner.py server/tests/test_steward_planner.py server/tests/test_steward_intent_agent.py server/tests/test_runtime_chat_service.py server/tests/test_config_settings_reload.py` 通过 45/45`ruff check --ignore E501 ...` 通过;`git diff --check` 无输出;`pip check` 无 broken requirements。
- 真实接口验证:通过真实 5173 `/api/v1/steward/plans` 回放保存草稿原句,服务端仍先等待 MiniMax 3 次 10s 超时,再返回 `rule_fallback`;返回字段包含 `requested_action=save_draft`、完整日期范围、上海、事由和 `transport_mode=train`。容器内直接探针确认默认 planner 类型为 `StewardGraphPlannerService`
- 影响:小财管家的规划骨架已经由 LangGraph 承接;后续可以继续把 slot/runtime decision、checkpoint 记忆、human-in-the-loop 和 action node 迁到框架里,而不是继续扩写自研分支编排。
- 15:22我按“先落文档文档完了再继续开发”的要求补齐 LangGraph 后续迁移文档。
- Git 提交检查:`git fetch --all --prune` 成功;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮只修改 AI 意图规划器文档和当天工作日志。
- 修改:新增 `LANGGRAPH_RUNTIME_MIGRATION.md`,记录当前已完成的 LangGraph 第一阶段、目标架构、runtime state 草案、节点边界、Phase 1-5 迁移计划、回退策略、验证矩阵和风险处理。
- 修改:更新 `CONCEPT.md`,删除“非目标:不新增 LangGraph”的过期表述改为不引入 LangChain 高层 Agent、不让 LangGraph 直接接管密钥或副作用,并补充后续 node 迁移方向。
- 修改:更新 `TODO.md`,把 `requested_action`、LangGraph 接入和迁移文档标为完成并新增模型成功路径、slot/runtime node、action node、checkpoint、人审中断和 trace 的后续事项。
- 操作:查询 LangGraph 官方文档,确认 Graph API、persistence 和 interrupt 的能力边界;读取当前 `StewardGraphPlannerService` 与已有 AI 意图规划文档后再落文档。
- 验证:`rg` 确认旧“不能新增 LangGraph”说法没有残留`git diff --check -- document/development/AI意图规划器/...` 无输出;新增迁移文档 356 行。
- 影响:后续开发有了明确的执行顺序和验收标准;下一步应先按文档 Phase 1 修通真实 `llm_function_call` 成功路径,再迁 slot/runtime/action/checkpoint。
- 15:31我继续把小财管家会话内的槽位识别、运行时记忆合并和行动决策入口迁到 LangGraph并加了图内和端点级双层兜底。
- Git 提交检查:`git fetch --all --prune` 成功;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮新增 graph runtime、runtime 测试并更新 AI 意图规划器文档。
- 修改:新增 `StewardGraphRuntime`,用 LangGraph `StateGraph` 编排 `slot_prepare_context -> slot_tool_decision -> done/rule_fallback`,把原 `StewardSlotDecisionAgent` 包成图节点;工具节点异常时会带 `langgraph_slot_decision` 失败 trace 进入规则兜底。
- 修改:`StewardGraphRuntime` 运行时图新增 `runtime_memory_context -> runtime_action_decision/runtime_tool_decision -> done/rule_fallback`,先归一化并合并 `steward_state`,已选流程确认走确定性 action 节点,不再调用模型;普通补字段/确认继续由 runtime tool 节点判断。
- 修改:`/steward/slot-decisions``/steward/runtime-decisions` 默认使用 `StewardGraphRuntime`;如果 LangGraph 实例化或执行异常,端点 helper 会退回旧 `StewardSlotDecisionAgent` / `StewardRuntimeDecisionAgent`,保证框架失效时仍能实际响应。
- 测试:先新增 `test_steward_graph_runtime.py` 红灯测试,覆盖槽位工具节点、图内规则兜底、运行时记忆合并、确定性行动选择,以及端点 helper 在 graph runtime 失败后 legacy 兜底;随后实现并跑绿。
- 文档:更新 `LANGGRAPH_RUNTIME_MIGRATION.md` 的当前状态和 Phase 2 完成项;更新 `CONCEPT.md` 的 LangGraph 节点命名;更新 `TODO.md` 勾掉 slot/runtime graph runtime 迁移,保留副作用 action node、checkpoint、人审中断和 trace 后续事项。
- 验证:容器内 `pytest -q server/tests/test_steward_graph_runtime.py server/tests/test_steward_graph_planner.py server/tests/test_steward_slot_decision_agent.py server/tests/test_steward_runtime_decision_agent.py server/tests/test_steward_planner.py server/tests/test_steward_intent_agent.py server/tests/test_runtime_chat_service.py server/tests/test_config_settings_reload.py` 通过 59/59`ruff check --ignore E501 ...` 通过;`git diff --check` 无输出;`pip check` 无 broken requirements。
- 影响:会话内“识别缺什么、读记忆、判断补字段/继续/确认”的入口已经被 LangGraph 接管;当前仍没有让 LangGraph 直接执行保存草稿、提交审批、关联申请单等副作用动作。
- 15:53我把 `/steward/plans` 的基础业务动作规划补成服务端白名单 `action_steps`,让申请、报销、保存草稿和直接提交都有明确动作序列。
- Git 提交检查:`git fetch --all --prune` 成功;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮新增 action contract、扩展 steward schema、更新前端 planner model、修复申请事由清洗并同步文档。
- 修改:`StewardTask``StewardPlanResponse` 增加 `action_steps`;新增 `StewardActionStep``StewardActionType``StewardActionStatus`,把可执行动作显式收进 Pydantic 协议。
- 修改:新增 `StewardActionPlanBuilder`,由服务端确定性生成白名单动作:申请直接提交输出 `fill_application_fields -> build_application_preview -> validate_required_fields -> run_duplicate_precheck -> submit_application`;保存草稿输出 `save_application_draft`;报销输出 `fill_reimbursement_fields -> build_reimbursement_preview -> validate_required_fields -> create_reimbursement_draft`
- 修改:`StewardGraphPlannerService` 增加 `attach_action_steps` 节点,模型成功、模型失败兜底和 off-topic 都统一经过动作规划节点legacy `StewardPlannerService` 返回前也补同一套 action contract。
- 修改:`workbenchAiIntentPlannerModel.js` 优先消费服务端 `task.action_steps`,旧响应才回退本地 `requested_action` 推导;这样后端 LangGraph 规划出的动作能真正驱动前端执行计划。
- 修改:`ApplicationFactResolver` 修复“交通火车”污染申请事由的问题,同时保留“高铁往返”这类业务描述;新增解析回归测试。
- 测试:先新增红灯测试,覆盖申请直接提交 action steps、保存草稿 action steps、报销 action steps、前端优先消费服务端 action steps、`交通火车` 事由清洗;随后实现并跑绿。
- 验证:容器内 `pytest -q server/tests/test_application_fact_resolver.py server/tests/test_steward_graph_runtime.py server/tests/test_steward_graph_planner.py server/tests/test_steward_slot_decision_agent.py server/tests/test_steward_runtime_decision_agent.py server/tests/test_steward_planner.py server/tests/test_steward_intent_agent.py server/tests/test_runtime_chat_service.py server/tests/test_config_settings_reload.py` 通过 66/66前端 `node --test web/tests/workbench-ai-intent-planner-model.test.mjs web/tests/workbench-ai-application-gate-model.test.mjs` 通过 12/12`npm --prefix web run build` 通过;`ruff check --ignore E501 ...` 通过;`git diff --check` 无输出。
- 真实接口验证:重启 `x-financial-local-linux` 后回放 `2026-02-20 至 2026-02-23去上海出差辅助国网仿生产服务器部署交通火车直接提交`,真实 5173 `/api/v1/steward/plans` 返回 `requested_action=submit`,字段为 `time_range=2026-02-20 至 2026-02-23``location=上海``reason=辅助国网仿生产服务器部署``transport_mode=train`,动作序列为 `detect_intent:completed -> fill_application_fields:planned -> build_application_preview:planned -> validate_required_fields:planned -> run_duplicate_precheck:planned -> submit_application:pending_confirmation`
- 影响:基础业务已经不是“只识别一个 requested_action”了后端计划会直接给出可执行动作序列当前仍只规划动作不直接执行保存草稿或提交审批。
- 16:13我把小财管家的白名单 action 从“只规划”推进到“可执行 executor”让申请草稿、申请提交门禁和报销草稿能通过统一 `/steward/actions/execute` 入口处理。
- Git 提交检查:`git fetch --all --prune` 成功;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮新增 action executor、执行接口、前端执行服务和相关测试。
- 修改:新增 `StewardActionExecuteRequest` / `StewardActionExecuteResponse`,并在 `steward.py` 暴露 `/steward/actions/execute`;新增 `StewardActionExecutor`,统一处理未知 action 拒绝、缺字段阻断、提交确认门禁、precheck 阻断和业务服务调用。
- 修改:`save_application_draft` / `submit_application` 复用现有 `UserAgentService` 申请保存/提交能力;`create_reimbursement_draft` 复用 `ExpenseClaimService.save_or_submit_from_ontology()`,避免再写一套入库逻辑。
- 修改:`associate_attachments``link_existing_application` 保留在执行白名单里,但在真实接线完成前统一返回阻断,不允许以 noop 形式“假成功”或产生隐式副作用。
- 修改:前端 `steward.js` 新增 `executeStewardAction()``stewardPlanModel.js` 保留服务端 `action_steps`,并在 suggested action payload 中携带最终可执行 action step旧申请预览流继续保留为兜底。
- 修改:`useWorkbenchAiActionRouter.js` 接入 `steward_execute_action` 点击执行;申请直接提交会先调用 `run_duplicate_precheck`precheck 通过后再把结果交给 `submit_application`,执行结果回写到当前 AI 会话。
- 修改:`test_reimbursement_endpoints.py` 两个申请快路径断言从旧 `AP-` 前缀同步到当前短单号 `A...` 规范。
- 文档:更新 `LANGGRAPH_RUNTIME_MIGRATION.md``TODO.md``CONCEPT.md`,标记第一版 action registry / executor 完成,并把 checkpoint、interrupt、关联申请和附件真实执行列为后续。
- 验证:容器内 `pytest -q server/tests/test_steward_action_executor.py` 通过 5/5迁移集合 `pytest -q server/tests/test_application_fact_resolver.py server/tests/test_steward_action_executor.py server/tests/test_steward_graph_runtime.py server/tests/test_steward_graph_planner.py server/tests/test_steward_slot_decision_agent.py server/tests/test_steward_runtime_decision_agent.py server/tests/test_steward_planner.py server/tests/test_steward_intent_agent.py server/tests/test_runtime_chat_service.py server/tests/test_config_settings_reload.py` 通过 71/71。
- 验证:前端 `node --test web/tests/workbench-ai-action-router.test.mjs web/tests/steward-actions-service.test.mjs web/tests/steward-plan-message-copy.test.mjs web/tests/workbench-ai-intent-planner-model.test.mjs web/tests/workbench-ai-application-gate-model.test.mjs` 通过 21/21`npm --prefix web run build` 通过;`ruff check --ignore E501 ...` 通过;`git diff --check` 无输出。
- 真实接口验证:重启 `x-financial-local-linux` 后,真实 5173 `/api/v1/steward/plans` 仍返回直接提交 action 链;`/api/v1/steward/actions/execute` 对未确认的 `submit_application` 返回 `needs_confirmation`,没有执行入库副作用。
- 影响:基础业务链路已经具备“规划 action -> 执行器门禁 -> 复用现有业务服务”的后端闭环;下一步需要把 executor 包进 LangGraph checkpoint / interrupt并补齐关联申请和附件关联的真实执行。
- 16:40我把 action executor 包成 LangGraph 可执行节点,并补完 checkpoint、人工确认中断、幂等重放、关联申请单和附件关联三阶段收尾。
- Git 提交检查:`git fetch --all --prune` 成功;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮新增 `StewardGraphActionRuntime`,扩展 action executor 测试并更新 AI 意图规划器文档。
- 修改:新增 `StewardGraphActionRuntime`,用 LangGraph `StateGraph` 编排 `action_checkpoint_load -> action_execute_node -> action_checkpoint_persist`,并把 `/steward/actions/execute` 默认切到这个 graph runtime。
- 修改:复用 `AgentConversation.state_json` 持久化 `steward_action_checkpoint`;同一 `conversation_id + client_trace_id` 的已完成 action 会直接重放终态结果,`needs_confirmation` 会保存 pending interrupt后续同 trace 完成后清理对应中断。
- 修改:`link_existing_application` 走报销草稿真实创建链路并写入申请关联风险标记;`associate_attachments` 接入 `AttachmentAssociationJobRunner`,无 `receipt_ids` 时阻断,避免假成功。
- 修改:为 `complete_with_tool_call()` 补上主模型失败后 backup 返回 tool call 的回归测试,锁住“模型规划失败优先重试/切 backup再降级规则”的成功路径。
- 文档:更新 `LANGGRAPH_RUNTIME_MIGRATION.md``TODO.md``CONCEPT.md`,把 action node、checkpoint、pending interrupt、幂等重放、关联申请单和附件关联标为已完成同时保留真实模型配置未修通的验收缺口。
- 验证:容器内 `pytest -q server/tests/test_steward_action_executor.py` 通过 9/9`pytest -q server/tests/test_runtime_chat_service.py::test_runtime_chat_complete_with_tool_call_fails_over_to_backup_before_retrying_main` 通过 1/1。
- 验证:迁移集合 `pytest -q server/tests/test_application_fact_resolver.py server/tests/test_steward_action_executor.py server/tests/test_steward_graph_runtime.py server/tests/test_steward_graph_planner.py server/tests/test_steward_slot_decision_agent.py server/tests/test_steward_runtime_decision_agent.py server/tests/test_steward_planner.py server/tests/test_steward_intent_agent.py server/tests/test_runtime_chat_service.py server/tests/test_config_settings_reload.py` 通过 76/76附件/关联任务 `pytest -q server/tests/test_attachment_association_jobs.py server/tests/test_linked_reimbursement_draft_jobs.py` 通过 7/7。
- 验证:前端 `node --test web/tests/workbench-ai-action-router.test.mjs web/tests/steward-actions-service.test.mjs web/tests/steward-plan-message-copy.test.mjs web/tests/workbench-ai-intent-planner-model.test.mjs web/tests/workbench-ai-application-gate-model.test.mjs` 通过 21/21`ruff check --ignore E501 ...` 通过;`npm --prefix web run build` 通过;`git diff --check` 无输出。
- 真实接口验证:重启 `x-financial-local-linux` 后,真实 5173 `/steward/actions/execute` 对同一未确认 `submit_application` trace 第二次返回 `needs_confirmation``result_payload.idempotent_replay=true`,证明 checkpoint 重放生效。
- 真实接口验证:真实 5173 `/steward/plans` 回放“2026-02-20 至 2026-02-23上海出差国网仿生产服务器部署火车保存草稿”仍因 backup skipped、MiniMax 三次失败后进入 `rule_fallback`,动作链和字段可用,但 `planning_source=llm_function_call` 仍需修模型配置。
- 影响申请、报销、保存草稿、直接提交、关联申请单、附件关联已经具备“LangGraph 规划/行动节点 -> 业务服务执行 -> checkpoint/interrupt 兜底”的基础可测闭环;真实大模型成功路径还差外部模型连通性。
- 16:53我修复 AI 模式输入后按回车“看起来没响应”的问题,把模型规划等待期改成先显示对话反馈。
- Git 提交检查:`git fetch --all --prune` 成功;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮只改 AI 模式前端等待反馈和对应测试/日志。
- 根因:`executeModelPlannedWorkbenchIntent()` 在等待 `/steward/plans` 返回前只设置 `sending=true`,没有先激活对话、清空输入框、展示用户气泡或 pending 卡片;真实 MiniMax 三次超时会让用户看到 30 多秒“无响应”。
- 修改:`usePersonalWorkbenchAiMode.js` 新增 `startModelPlanningConversation()`,进入模型规划前立即推入用户消息和“正在识别意图,准备拆解申请、报销和附件任务。”的 pending 卡片,并持久化到最近对话。
- 修改:`startModelPlannedApplicationPreview()` 把规划 pending 的 `pendingMessageId` 传给申请预览;`useWorkbenchAiApplicationPreviewFlow.js` 支持复用这张 pending 卡片,避免重复用户消息和重复等待卡。
- 测试:先新增 `workbench AI mode shows a visible planning response before waiting for steward model plan` 红灯测试,确认当前缺少即时反馈;实现后同文件 9/9 通过。
- 验证:前端相关集合 `node --test web/tests/workbench-ai-action-router.test.mjs web/tests/steward-actions-service.test.mjs web/tests/steward-plan-message-copy.test.mjs web/tests/workbench-ai-intent-planner-model.test.mjs web/tests/workbench-ai-application-gate-model.test.mjs web/tests/workbench-ai-composer-components.test.mjs` 通过 31/31`npm --prefix web run build` 通过;`git diff --check` 无输出。
- 真页验证:使用本地 5173 和本地模拟员工账号登录 AI 模式输入“2026-02-20 至 2026-02-23上海出差国网仿生产服务器部署火车保存草稿”并按回车1.5 秒内看到用户气泡、输入框清空和 pending 卡片;约 38 秒后仍正常保存草稿,草稿单号 `AZ8QSX9QA`
- 影响:用户按回车后不再空等模型规划,长耗时仍存在但前端会立即反馈“已接收并正在规划”;真实 `llm_function_call` 成功路径仍依赖模型配置修复。
- 16:59我修复了 AI 模式普通问候被拆成两条助手消息的问题,把规划、工具/行动整理和最终回复收敛到同一张助手卡片。
- Git 提交检查:`git fetch --all --prune` 成功;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮只继续修改 AI 模式前端消息复用、思考事件合并和对应测试。
- 根因16:53 的等待态修复先创建了模型规划 pending 卡片,但普通管家回复路径会把这张卡片替换成“已完成意图识别,继续为您整理回复。”,随后 `requestInlineAssistantReply()` 又新建第二张助手卡片;所以用户输入“你好”时会看到两段会话。
- 修改:`usePersonalWorkbenchAiMode.js` 删除中间态独立回复,普通管家回复也把 `pendingMessageId` 传给 `requestInlineAssistantReply()`,让同一轮输入继续复用规划 pending 卡片。
- 修改:`useWorkbenchAiStewardFlow.js` 支持 `requestInlineAssistantReply(prompt, entry, files, options)`,当传入 `pendingMessageId` 时替换原 pending 卡片而不是追加新消息;新增 `mergeInlineThinkingEvents()` 合并模型规划和管家回复思考事件,避免同一事件重复或丢失。
- 测试:先新增红灯测试 `workbench AI mode reuses planning pending message for regular steward replies`,确认普通回复必须复用规划 pending实现后同文件 10/10 通过。
- 验证:前端集合 `node --test web/tests/workbench-ai-action-router.test.mjs web/tests/steward-actions-service.test.mjs web/tests/steward-plan-message-copy.test.mjs web/tests/workbench-ai-intent-planner-model.test.mjs web/tests/workbench-ai-application-gate-model.test.mjs web/tests/workbench-ai-composer-components.test.mjs` 通过 32/32`npm --prefix web run build` 通过;`git diff --check` 无输出。
- 真页验证:本地 5173 AI 模式输入“你好”后1.5 秒内只有 1 张 pending 助手卡;最终回复后 `assistantCardCount=1``pendingCards=0`、思考区标题为“小财业务思考5 条”,截图保存为 `/tmp/x-financial-ai-single-message-hello.png`
- 影响:一次用户输入现在对应一条助手消息;意图识别、规划等待、普通回复整理都会落在同一个思考区域,不再把“已完成意图识别”单独展示成一轮会话。
- 17:26我把 AI 模式的规划等待态从静态“思考中”改成持续追加过程摘要,让用户能看到意图判断、字段抽取、动作规划和兜底策略正在推进。
- Git 提交检查:`git fetch --all --prune` 成功;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有多项既有未提交改动,本轮只继续修改 AI 模式前端 thinking 事件、流式规划接线和对应测试。
- 根因:`executeModelPlannedWorkbenchIntent()` 虽然会先创建 pending 卡片,但 `resolveInlineExecutionPlan()` 仍走非流式 `/steward/plans`,模型等待期间只有一条静态 thinking等计划返回后才一次性显示完整步骤用户会感觉像假思考。
- 修改:新增 `workbenchAiPlanningThinkingModel.js`,集中维护可复用的 thinking 事件合并、完成态转换、初始意图判断和阶段性进度计划,避免继续把主 composable 写大。
- 修改:`usePersonalWorkbenchAiMode.js` 在模型规划 pending 卡片上启动可取消的阶段性进度:判断办理意图、抽取关键信息、规划执行步骤、匹配业务工具、准备兜底策略;模型返回或进入 fallback 后会清理定时器。
- 修改:`useWorkbenchAiStewardFlow.js` 支持 `resolveInlineExecutionPlan(prompt, entry, files, { pendingMessageId })`;传入 pending id 时改走 `/steward/plans/stream`,只把服务端 thinking 实时写回当前卡片,不把 answer delta 提前塞进规划消息。
- 修改:`useWorkbenchAiApplicationPreviewFlow.js` 生成申请核对表时保留并完成前置规划 thinking再追加“整理申请表字段 / 同步费用测算”,避免申请表阶段把前面的规划过程清掉。
- 测试:新增 `workbench AI mode streams planning thinking into the pending message`,锁定阶段性 thinking、可取消定时器、流式规划接线和申请预览 thinking 合并;同文件 11/11 通过。
- 验证:相关前端集合 `node --test web/tests/workbench-ai-action-router.test.mjs web/tests/steward-actions-service.test.mjs web/tests/steward-plan-message-copy.test.mjs web/tests/workbench-ai-intent-planner-model.test.mjs web/tests/workbench-ai-application-gate-model.test.mjs web/tests/workbench-ai-composer-components.test.mjs` 通过 33/33`npm --prefix web run build` 通过;`git diff --check` 无输出。
- 真页验证:本地 5173 干净会话输入“2026-02-20 至 2026-02-23上海出差国网仿生产服务器部署火车保存草稿。”后thinking 数量按时间增长:点击后 2 条、1.1 秒 3 条、2.5 秒 4 条、5.7 秒 5 条、9.6 秒 6 条;约 36 秒后仍成功保存草稿,草稿单号 `AZ4A98BSF`,截图保存为 `/tmp/x-financial-ai-progressive-thinking.png`
- 验证补充:我额外跑了 `workbench-ai-mode-switch.test.mjs`,该文件仍有 2 个既有静态断言失败,断言点还停在旧的内联附件卡片和旧的 `selectedFiles` watch 结构;本轮相关测试和真页回放不受影响。
- 影响:用户现在不再只看到静态“思考中”,而是能在同一张思考卡片里持续看到业务意图、槽位、动作链和兜底策略的推进过程;服务端流式 thinking 到达后也会合并进同一个列表。
- 17:40我修复了 AI 工作台保存申请草稿后,再输入“提交这个单据”会重新进入意图规划的问题。
- Git 提交检查:`git fetch --all --prune` 成功;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有大量既有未提交改动,本轮只补 AI 工作台申请上下文提交识别、申请预览执行分支和对应测试。
- 根因:`resolveInlineApplicationPreviewTextAction()` 只识别“提交 / 确认提交 / 直接提交”等精确词,用户输入“提交这个单据”会绕过当前申请核对表上下文,继续进入 `shouldRequestWorkbenchAiIntentPlan()` 和小财管家规划,导致再次识别意图并等待模型。
- 修改:`workbenchAiApplicationGateModel.js` 把“提交这个单据 / 提交这个申请单 / 提交当前单据 / 提交刚才的草稿”等上下文指代短句映射为 `AI_APPLICATION_ACTION_SUBMIT`;同类保存指代短句也映射到保存草稿动作。
- 修改:`useWorkbenchAiApplicationPreviewFlow.js` 在提交动作里新增“已保存草稿 + 上下文提交短句”快路径;当最近申请核对表已有 `draftPayload.claim_id` 或单号,且用户明确说提交当前/刚才的单据时,跳过二次确认弹窗,直接执行提交前核查和 `/reimbursements/application-preview-action`,并带上 `application_edit_claim_id` 复用原草稿。
- 测试:先新增 `workbench-ai-application-context-submit.test.mjs` 红灯测试,复现“已有草稿 + 提交这个单据”只打开确认弹窗、不调用提交接口;实现后该测试通过,并确认 payload 写入 `application_edit_claim_id=claim-saved-draft`
- 验证:`node --test web/tests/workbench-ai-application-context-submit.test.mjs` 通过;`node --test web/tests/workbench-ai-application-gate-model.test.mjs` 通过;相邻 `workbench-ai-action-router.test.mjs``workbench-ai-intent-planner-model.test.mjs``ai-application-preview-actions.test.mjs` 均通过;本轮改动文件 `git diff --check -- ...` 无输出。
- 验证补充:`workbench-ai-mode-expense-scene-action.test.mjs``expense-application-fast-preview.test.mjs` 仍有既有静态断言失败,主要还在扫描旧 `PersonalWorkbenchAiMode.vue` 或过窄源码片段;新增的上下文提交行为测试已覆盖真实执行路径。
- 影响用户先说“2026-02-20 至 2026-02-23去上海出差辅助国网仿生产服务器部署交通火车保存草稿”草稿保存后再说“提交这个单据”前端不会再重新规划而会把“这个单据”绑定到最近申请草稿并提交到审批链路。
- 17:48我修复了“完整出差信息但未显式说申请/报销”时AI 模式停在候选流程确认、不直接推进申请预览的问题。
- Git 提交检查:`git fetch --all --prune` 成功;当前 upstream 为 `origin/main``HEAD..@{u}``@{u}..HEAD` 均未输出新提交;工作区仍有大量既有未提交改动,本轮只继续修改 `workbenchAiIntentPlannerModel.js` 和对应意图规划测试。
- 根因:后端已经返回 `pending_flow_confirmation`,且候选流只有 `travel_application / 先发起出差申请`,但前端 `normalizeWorkbenchAiIntentPlan()` 只识别 `tasks`,没有把这个唯一候选流转成可执行申请计划,最后又回到普通 steward 回复路径。
- 修改:`workbenchAiIntentPlannerModel.js` 增加 pending flow 候选解析;当 `pending_flow_confirmation.status=pending` 且唯一候选为“先发起出差申请”时,直接生成 `create_travel_application` 计划,包含 `build_application_preview`、必填校验、模型抽取的时间/地点/事由/交通方式。
- 测试:先新增红灯用例 `workbench AI intent planner turns single application candidate flow into executable preview payload`,复现该计划原本返回 `null`;实现后同文件 12/12 通过。
- 验证:`node --test web/tests/workbench-ai-intent-planner-model.test.mjs``node --test web/tests/workbench-ai-application-gate-model.test.mjs``node --test web/tests/workbench-ai-application-context-submit.test.mjs``node --test web/tests/steward-plan-model-pending-flow.test.mjs` 均通过;`git diff --check -- web/src/composables/workbenchAiMode/workbenchAiIntentPlannerModel.js web/tests/workbench-ai-intent-planner-model.test.mjs` 无输出。
- 影响用户输入“2026-02-20 至 2026-02-23去上海出差辅助国网仿生产服务器部署交通火车”时如果门禁已查明没有可关联申请单前端会把“应先申请单据”直接落到申请预览链路不再表现成只会反复识别意图。
## 遗留问题
- 09:41当前 Skill 是新建在项目级 `.codex/skills` 目录里,本轮可以通过文件检查验证结构,但是否被未来会话自动加载还依赖 Codex 对项目 Skill 的刷新机制。建议后续新开会话或下一次任务时确认 Skill 列表是否出现 `agent-change-log`
@@ -236,6 +418,26 @@
- 11:39本轮新增的附件归集回归测试还没有在容器内真正执行原因仍是 Docker socket 权限拒绝。建议 Docker 权限恢复后优先运行 `server/tests/test_attachment_association_jobs.py` 新增两条测试,并在 5173 重新打开刚才那张坏票据验证自动修复是否生效。
- 11:55当前实际运行容器仍叫 `x-financial-local-linux`,且容器内 `poppler-data` 未安装、`mutool` 不存在;本轮文本层兜底已恢复 OCR 字段,但 PDF 图片预览仍会带转图失败 warning。12:04 已在当前运行容器补齐依赖并刷新本批票据预览;建议后续仍按最新 compose 统一到 `local-x-financial-linux`,避免旧容器继续抢占 5173。
- 12:23本轮没有拿到可用的浏览器自动化插件来生成真页截图已用前端构建、组件测试和真实 5173 OCR/preview 接口替代验证。建议用户侧刷新页面后重新上传同类 PDF若历史会话里旧附件卡片仍停留在旧状态则重新选择附件触发 OCR 状态刷新。
- 13:03`expense-application-fast-preview.test.mjs` 整文件仍有 12 个既有失败,失败点包括 unsupported business guidance 文案、旧申请 session 静态结构、typewriter/table 静态断言等;本次新增的直提申请用例已通过。建议后续单独清理这些陈旧断言,避免掩盖真正的申请链路回归。
- 13:20本轮完成了模型计划接线和结构测试但没有在真实 5173 页面输入框回放 `/steward/plans` 返回 `llm_function_call` 的端到端路径。建议后续用真实模型配置测试一次“去上海出差...直接提交”,确认模型返回任务计划后前端进入申请核对表。
- 13:35本轮已经用模型规划入口、fallback 解析和前端构建验证了“保存草稿”变体,但还没有在真实 5173 输入框回放一次完整点击/保存草稿链路。建议后续用当前句子做真页验证,确认草稿保存后出现申请单详情入口。
- 13:58本轮已经用容器后端测试和前端模型计划归一测试验证 function calling contract但还没有在真实 5173 页面观察 `/steward/plans` 的网络返回是否包含新的 `requested_action`。建议后续打开浏览器 DevTools 或后端日志,用真实模型配置回放一次保存草稿话术。
- 14:33真实接口已确认模型必经和 3 次重试,但当前主模型 MiniMax 连续超时backup 槽位 API key 未解密/未配置,因此仍然进入 `rule_fallback`。建议下一步先修复模型连通性或配置可用 backup再确认返回 `planning_source=llm_function_call` 的成功路径。
- 14:33用户提出 LangChain 方向是合理的但本轮没有直接引入新依赖。15:14 已完成 LangGraph 第一阶段迁移;后续仍要继续补 memory/checkpoint、action node 和人审中断能力。
- 15:14LangGraph 第一阶段只替换了 `/steward/plans` 的规划编排骨架,还没有把 slot decision、runtime decision、草稿保存/提交 action 和跨轮 checkpoint 迁入 graph。建议下一步按节点边界继续拆迁避免又在 LangGraph node 内写回大块自研流程。
- 15:14`langgraph` 依赖把 `websockets` 锁到 15.0.1;当前 `pip check` 和 steward 相关测试通过,但如果后续实时流或 WebSocket 功能异常,需要优先核对这个依赖变化。
- 15:22本轮只补迁移文档没有继续实现 Phase 1-5。建议下一轮严格按 `LANGGRAPH_RUNTIME_MIGRATION.md` 从模型成功路径开始推进,不要跳过文档直接扩写 graph node。
- 15:31当前 `StewardGraphRuntime` 已覆盖 slot/runtime decision但保存草稿、提交审批、关联申请单等副作用动作还只是下游既有服务执行并未接成 LangGraph 白名单 action node。建议下一步优先实现 `steward_action_nodes.py` / action contract再接 checkpoint 和 human-in-the-loop。
- 15:53当前已完成服务端 action contract但还没有实现真正执行副作用的 action registry / action node`save_application_draft``submit_application``create_reimbursement_draft` 仍需要下一步接到现有业务服务并补幂等、确认来源和 trace。建议下一步先做 action registry再接 checkpoint/human-in-the-loop。
- 16:13第一版 action executor 和 AI 工作台点击执行闭环已可执行申请/报销基础副作用,但还没有接入 LangGraph checkpoint / interrupt也没有给所有副作用写持久化幂等 trace。16:40 已完成后端 action graph runtime、pending interrupt 和幂等重放,剩余前端恢复 UI 还需单独做。
- 16:13`link_existing_application``associate_attachments` 已进入执行白名单并在未接线时阻断,但真实执行还没有统一接入 action executor。16:40 已接入真实执行和回归测试,后续仍需在真页补充可视化恢复/继续动作。
- 16:40真实 `/steward/plans` 仍未跑到 `planning_source=llm_function_call`,当前阻塞点是 backup skipped、MiniMax 三次失败;代码层 backup tool-call 成功路径已有测试,但环境层还要修模型配置或连通性。
- 16:40后端已把 pending interrupt 写进 conversation checkpoint但 AI 工作台还没有在刷新或重新进入会话时从 checkpoint 主动恢复“继续/确认”按钮;建议下一步补前端恢复 UI。
- 16:53`usePersonalWorkbenchAiMode.js` 当前已超过 800 行,后续继续加 AI 模式功能前建议拆出模型规划等待态、普通对话启动和申请预览桥接 composable避免继续扩大主运行时文件。
- 16:59本轮没有新增独立遗留风险仍沿用 16:40 的真实模型连通性问题和 16:53 的主 composable 过大问题。建议后续先修 `llm_function_call` 成功路径,再拆分 AI 模式前端运行时文件。
- 17:26`workbench-ai-mode-switch.test.mjs` 仍有 2 个旧静态断言失败,分别断言附件卡片还在主模板内联、`selectedFiles` watch 还在主 AI 模式文件里;当前真实代码已经拆成组件/composable。建议后续单独整理这个老测试文件避免它继续误报已迁移结构。
- 17:40`workbench-ai-mode-expense-scene-action.test.mjs``expense-application-fast-preview.test.mjs` 仍有多条旧静态断言失败,失败点主要是代码已拆到 composable 后测试还读取旧 Vue 单文件或固定片段。建议后续把这些静态断言改成导入 composable/model 的行为测试,避免真实功能修复被旧结构误报淹没。
- 17:48本轮修复已用模型归一化和相邻前端测试覆盖但还没有在真实 5173 页面输入最新无动作话术截图回放。建议下一步刷新 AI 工作台用“2026-02-20 至 2026-02-23去上海出差辅助国网仿生产服务器部署交通火车”验证是否直接进入申请核对表。
## TODO
@@ -264,3 +466,28 @@
- [x] ~~重新跑截图同批火车票 PDF 的 OCR 接口,确认不再返回“其他单据/空字段”。~~(完成于 11:55证据5173 `/api/v1/ocr/recognize` 返回 `2月20_武汉-上海.pdf``2月23_上海-武汉.pdf` 均为 `火车/高铁票`,并写回票据夹字段)
- [x] ~~重建或补齐当前运行容器的 `poppler-data` / `mupdf-tools`,确认 `mutool` 可用后再上传同类中文 PDF目标是同时恢复 PNG 预览和 OCR 字段。~~(完成于 12:04证据`apt-get install poppler-data mupdf-tools` 成功,`/usr/bin/mutool` 可用;两条 `/preview` 返回 `image/png`,并写入 `preview_kind=image`
- [x] ~~统一 AI 会话附件、票据夹和报销附件的预览类型判定,避免会话上传卡片继续把已生成 PNG 预览的 PDF 当成 PDF 展示。~~(完成于 12:23证据新增 `documentPreviewAssets.js`;前端相关测试 24/24 通过,真实 OCR 返回 `preview_kind=image``/preview``image/png`
- [x] ~~重新设计一键关联票据的弹窗 UI调整内边距、行间距、按钮尺寸与悬浮效果并按精致化要求收敛尺寸以恢复精致感。~~(完成于 12:52证据`npm run build` 构建成功,`receipt-folder-view.test.mjs` 测试通过,样式已应用)
- [ ] 单独修复 `expense-application-fast-preview.test.mjs` 里 12 个既有失败或拆分陈旧静态断言恢复整文件可作为申请链路回归套件使用。来源13:03 差旅申请直提链路验证)
- [ ] 在真实 5173 AI 工作台输入“去上海出差,辅助国网仿生产服务器部署,交通火车,直接提交”,确认模型计划路径命中 `/steward/plans`并在缺日期时停在申请核对表、日期补齐后进入提交前核查。来源13:20 AI 意图规划器接线)
- [x] ~~在真实 5173 AI 工作台输入“2026-02-20 至 2026-02-23上海出差国网仿生产服务器部署火车保存草稿。”确认模型计划或 fallback 计划生成申请核对表,并自动保存草稿后给出详情入口。~~(完成于 16:53证据1.5 秒内显示用户气泡和 pending 卡,约 38 秒后保存草稿 `AZ8QSX9QA`
- [ ] 在真实 5173 网络面板或后端日志核对 `/steward/plans` 返回 `planning_source=llm_function_call``tasks[0].requested_action=save_draft` 和完整 `ontology_fields` 后,再确认前端没有走 rule fallback。来源13:58 模型优先规划重构)
- [x] ~~确认真实 `/steward/plans` 不再毫秒级规则直出,并在模型不可用时按 10s * 3 次后降级。~~(完成于 14:33证据真实 5173 API 回放耗时 32.08sMiniMax attempt 1/2/3 均超时后才 `rule_fallback`
- [ ] 修复 MiniMax 连通性或配置可用 backup 模型,再用同一句保存草稿话术确认 `/steward/plans` 返回 `planning_source=llm_function_call`来源14:33 模型必经链路验证16:40 已补代码层 backup tool-call 测试,但真实环境仍 fallback
- [x] ~~评估 LangChain/LangGraph 是否作为 steward agent 层框架,引入前明确 memory、tools/action、planner、runtime state、observability 和依赖风险。~~(完成于 15:14证据已引入 LangGraph 第一阶段并默认接管 `/steward/plans` 规划编排45 个容器测试通过)
- [x] ~~将 `StewardSlotDecisionAgent` 和 `StewardRuntimeDecisionAgent` 继续迁入 LangGraph 节点,形成统一 steward graph runtime。~~(完成于 15:31证据新增 `StewardGraphRuntime`,容器内 graph runtime 相关回归 59/59 通过)
- [x] ~~为 `/steward/plans` 增加服务端白名单 `action_steps`,覆盖申请、报销、保存草稿和直接提交的基础动作规划。~~(完成于 15:53证据新增 `StewardActionPlanBuilder`,真实 5173 回放返回完整 action steps容器内相关回归 66/66 通过)
- [x] ~~为 LangGraph steward runtime 增加 checkpoint/persistence 设计,复用现有 conversation state支持暂停、恢复和可观测 trace。~~(完成于 16:40证据新增 `StewardGraphActionRuntime`,同一 `conversation_id + client_trace_id` 重放返回 `idempotent_replay=true`,未确认 action 写入 pending interrupt
- [ ] 修通真实 `llm_function_call` 成功路径,用真实模型配置验证 `/steward/plans` 不再进入 rule fallback。来源15:22 LangGraph 迁移文档action node、checkpoint 和 human-in-the-loop 后端部分已于 16:40 完成)
- [x] ~~实现 LangGraph 白名单 action node把保存草稿、提交审批、关联申请单、创建报销草稿和附件关联接入显式 action contract。~~(完成于 16:40证据`StewardGraphActionRuntime` 默认接管 `/steward/actions/execute`action executor 9/9 通过,关联任务回归 7/7 通过)
- [x] ~~实现 action registry 的未知 action 拒绝、确认来源校验、重复申请 precheck 阻断和基础业务执行。~~(完成于 16:13证据新增 `StewardActionExecutor`,容器内 action executor 5/5 和迁移回归 71/71 通过;前端点击执行回归 21/21 通过;真实 5173 未确认 submit 返回 `needs_confirmation`
- [x] ~~为第一版 `StewardActionExecutor` 增加 checkpoint / interrupt 恢复、持久化 trace 和幂等键。~~(完成于 16:40证据`StewardGraphActionRuntime` 持久化 `steward_action_checkpoint`,重复 trace 不重复建单)
- [x] ~~补齐 `link_existing_application` 和 `associate_attachments` 的真实 action executor 接线与回归测试。~~(完成于 16:40证据申请关联报销草稿测试和附件关联 runner 测试已通过)
- [ ] 前端 AI 工作台从 `steward_action_checkpoint.pending_interrupt` 恢复继续/确认按钮,避免刷新页面后只剩后端 checkpoint、用户看不到可继续 action。来源16:40 action graph runtime
- [ ] 拆分 `usePersonalWorkbenchAiMode.js` 的模型规划等待态和对话启动逻辑,优先把文件降回 800 行以内。来源16:53 回车无反馈修复)
- [x] ~~修复 AI 模式普通回复复用规划 pending 卡片,确保一次用户输入只生成一条助手消息。~~(完成于 16:59证据真页输入“你好”最终 `assistantCardCount=1`,前端相关测试 32/32 通过)
- [x] ~~让 AI 模式模型规划等待期间持续追加 thinking 事件,而不是静态显示“思考中”后一次性出现步骤。~~(完成于 17:26证据真页干净会话 thinking 数量从 2 条逐步增长到 6 条,相关前端测试 33/33 通过)
- [x] ~~修复 AI 工作台“保存草稿”后的上下文提交短句,让“提交这个单据”复用最近申请草稿而不是重新规划。~~(完成于 17:40证据`workbench-ai-application-context-submit.test.mjs``workbench-ai-application-gate-model.test.mjs` 通过)
- [x] ~~修复“完整出差信息但未说申请/报销”时只停在候选流程确认的问题,让唯一的“先发起出差申请”候选流直接进入申请预览计划。~~(完成于 17:48证据`workbench-ai-intent-planner-model.test.mjs` 新增回归通过,相邻 4 组前端测试通过)
- [ ] 单独修复或重写 `workbench-ai-mode-switch.test.mjs` 的旧静态结构断言,使它适配 `WorkbenchAiFileStrip` 和 OCR composable 拆分后的真实代码。来源17:26 额外测试发现)
- [ ] 单独修复或重写 `workbench-ai-mode-expense-scene-action.test.mjs``expense-application-fast-preview.test.mjs` 中继续扫描旧 Vue 单文件的静态断言,改为覆盖 composable/model 的行为测试。来源17:40 上下文提交验证)
- [ ] 在真实 5173 AI 工作台回放“2026-02-20 至 2026-02-23去上海出差辅助国网仿生产服务器部署交通火车”确认唯一申请候选流直接生成申请核对表。来源17:48 无动作话术直进申请预览修复)