feat(mcp): P3 联机验证通过,新增 browser_open_form 断点续填,修 4 个联机才暴露的真 bug
联机跑通 open→login→new_form→fill(basic)→page_state→close:财务系统真的落库(单据编号 202610020850,
basic 页点「下一步」即保存)。据此补上续填能力并把测试草稿清理干净(删除前后截图 + 复查 0 命中)。
- 新增第 25 个工具 browser_open_form:列表页 #seacher 定位 → 唯一命中 → 行内单选 → #update 修改,
读回 #EXPENEXPLAIN 证明数据还在;preview_only 只定位不点开并回显 bill_no/state/amount;
命中多张直接拒绝并回 candidates,不替用户猜单据
- 修 4 个真 bug(都是单元测试看不见的):
1) navigate_to_reimburse 单点硬等 5 秒偶发超时 → 全程轮询 + 失败带页面文字与截图;
并查明直达报销 URL 不建立会话(会被踢「长时间未操作,请重新登录!」),门户点击链是必经
2) actor.close_all 用 atexit 注册无效:concurrent.futures.thread 的钩子走 threading._register_atexit,
比 atexit 早跑,executor 已 shutdown → close 提交不进去。改为注册到同一列表,实测 close
在 playwright_0 线程执行,退出不再漏浏览器
3) wait_rows_loaded 只认 <a>,真实「查看」是 <button>,每次白等满 20 秒(也拖慢了测试套件)
4) 空结果「没有找到匹配的记录」被当成加载中,搜不到时再白等 20 秒
- browser_page_state 语义修正:logged_in 判门户 URL,进报销系统后必然 false 会误导 → 拆成
at_portal / in_reimburse_system / on_form_page
- case_status 补齐 info_both / screenshots / browser(锁持有者与心跳年龄)/ warnings(混合 info、
陈旧抽取、他人持锁);.browser.lock 文件名由 cases.py 单一定义,actor 反向引用
- 列表页结构实测写进 AGENTS:btSelectItem 单选、#insert/#update/#delete、行内「查看」是 gzlc 流程图、
可见搜索框是 #seacher 而 #expenexplain 在收起面板(fill 会卡 30 秒)
- 测试:FakeBot 绑 BaseBot 真实行逻辑,新增 5 例续填用例(唯一命中/歧义拒绝/未命中/preview/空关键词),
134 passed 0.36s;文档 docs/MCP.md 工具参考按 wire schema 重生成(25 工具),SKILL 增「断了不要重来,
用 browser_open_form 续填」与破坏性操作纪律;方案文档 §13.5 记录联机结果、4 个 bug 与未完成项
验证:mcp_smoke 25 工具 / ruff / format / mypy / deptry / pytest 134 passed 全绿;
联机时间线见方案文档 §13.5。仍用 --no-verify 提交并手跑等价检查(原因见 AGENTS 提交纪律)。
This commit is contained in:
+36
-20
@@ -103,11 +103,10 @@ cases/<case_id>/
|
||||
|
||||
# 工具参考
|
||||
|
||||
以下内容由运行中的服务器 schema 自动生成,与代码同源(`scripts/mcp_smoke.py` 会打印同一份清单)。
|
||||
|
||||
以下内容由运行中的服务器 schema 自动生成,与代码同源(`scripts/mcp_smoke.py` 打印同一份清单)。
|
||||
## 会话与材料
|
||||
|
||||
每个报销任务是一个会话目录 `cases/<case_id>/`,阶段由产物推导。
|
||||
每个报销任务是一个会话目录 cases/<case_id>/,阶段由产物推导。
|
||||
|
||||
### `mcp__arb__case_create`
|
||||
|
||||
@@ -163,7 +162,7 @@ cases/<case_id>/
|
||||
| 参数 | 类型 | 必填 | 默认 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| `case_id` | string | 是 | — | — |
|
||||
| `scope` | string | 否 | `"extractions"` | — |
|
||||
| `scope` | string | 否 | "extractions" | — |
|
||||
|
||||
## 抽取交接
|
||||
|
||||
@@ -180,8 +179,8 @@ cases/<case_id>/
|
||||
|------|------|------|------|------|
|
||||
| `case_id` | string | 是 | — | — |
|
||||
| `files` | array/null | 否 | — | — |
|
||||
| `dpi` | integer | 否 | `150` | — |
|
||||
| `force` | boolean | 否 | `false` | — |
|
||||
| `dpi` | integer | 否 | 150 | — |
|
||||
| `force` | boolean | 否 | false | — |
|
||||
|
||||
### `mcp__arb__case_read_text`
|
||||
|
||||
@@ -228,7 +227,7 @@ cases/<case_id>/
|
||||
|
||||
## 匹配与校验
|
||||
|
||||
匹配与校验都是确定性代码;结论以 `validate_info` 为准,不要自己宣布可提交。
|
||||
匹配与校验都是确定性代码;结论以 validate_info 为准,不要自己宣布可提交。
|
||||
|
||||
### `mcp__arb__match_payments`
|
||||
|
||||
@@ -288,7 +287,7 @@ cases/<case_id>/
|
||||
|
||||
## 文档产物
|
||||
|
||||
Excel COM,需本机装有 Microsoft Excel;仅普通发票需要。模板顺序:`REQUISITION_TEMPLATE` → `templates/` → 项目根。
|
||||
Excel COM,需本机装有 Microsoft Excel;仅普通发票需要。模板顺序:REQUISITION_TEMPLATE → templates/ → 项目根。
|
||||
|
||||
### `mcp__arb__doc_requisition`
|
||||
|
||||
@@ -305,7 +304,7 @@ Excel COM,需本机装有 Microsoft Excel;仅普通发票需要。模板顺
|
||||
|
||||
## 浏览器分步填报
|
||||
|
||||
需要本机已 `uv run playwright install chromium`。默认有头;归属由 `cases/<id>/.browser.lock` 记录(PID+心跳,180 秒未心跳可被接管)。**提交不在这里**:填完交人工核对。
|
||||
需先 `uv run playwright install chromium`。默认**有头**;归属由 `cases/<id>/.browser.lock` 记录 (PID + 心跳,180 秒未心跳可被接管)。中途断了不必重来:用 `browser_open_form` 从列表页找回原单据 续填,**不要再 `browser_new_form` 重复建单**。提交不在这里,填完交人工核对。
|
||||
|
||||
### `mcp__arb__browser_open`
|
||||
|
||||
@@ -317,7 +316,7 @@ Excel COM,需本机装有 Microsoft Excel;仅普通发票需要。模板顺
|
||||
| 参数 | 类型 | 必填 | 默认 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| `case_id` | string | 是 | — | — |
|
||||
| `headless` | boolean | 否 | `false` | — |
|
||||
| `headless` | boolean | 否 | false | — |
|
||||
|
||||
### `mcp__arb__browser_login`
|
||||
|
||||
@@ -326,7 +325,7 @@ Excel COM,需本机装有 Microsoft Excel;仅普通发票需要。模板顺
|
||||
| 参数 | 类型 | 必填 | 默认 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| `case_id` | string | 是 | — | — |
|
||||
| `wait_seconds` | integer | 否 | `25` | — |
|
||||
| `wait_seconds` | integer | 否 | 25 | — |
|
||||
|
||||
### `mcp__arb__browser_new_form`
|
||||
|
||||
@@ -337,6 +336,21 @@ Excel COM,需本机装有 Microsoft Excel;仅普通发票需要。模板顺
|
||||
| `case_id` | string | 是 | — | — |
|
||||
| `kind` | null/string | 否 | — | — |
|
||||
|
||||
### `mcp__arb__browser_open_form`
|
||||
|
||||
从列表页找回已存在的单据接着填(中途断了不必重来)。
|
||||
|
||||
match 用报销说明里的关键词,必须在当前列表页唯一命中;命中多张直接失败,
|
||||
让宿主把关键词收紧——财务系统里点错别人的单据是不能接受的后果。preview_only=true
|
||||
只搜索定位、不点开单据,用来先确认是哪一张。
|
||||
|
||||
| 参数 | 类型 | 必填 | 默认 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| `case_id` | string | 是 | — | — |
|
||||
| `match` | string | 是 | — | — |
|
||||
| `kind` | null/string | 否 | — | — |
|
||||
| `preview_only` | boolean | 否 | false | — |
|
||||
|
||||
### `mcp__arb__browser_fill`
|
||||
|
||||
执行一步填报。step 按 browser_new_form 返回的 steps 顺序,不能跳步。
|
||||
@@ -346,6 +360,17 @@ Excel COM,需本机装有 Microsoft Excel;仅普通发票需要。模板顺
|
||||
| `case_id` | string | 是 | — | — |
|
||||
| `step` | string | 是 | — | — |
|
||||
|
||||
### `mcp__arb__browser_page_state`
|
||||
|
||||
看当前页面:URL、标题、命中的表单标记、已完成步骤、最近截图。
|
||||
|
||||
at_portal 只表示在信息门户;进了报销系统要用 in_reimburse_system 与 on_form_page 判断。
|
||||
|
||||
| 参数 | 类型 | 必填 | 默认 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| `case_id` | string | 是 | — | — |
|
||||
| `screenshot` | boolean | 否 | true | — |
|
||||
|
||||
### `mcp__arb__browser_steps`
|
||||
|
||||
列出该会话单据类型的步骤顺序与含义(不要求浏览器已打开)。
|
||||
@@ -354,15 +379,6 @@ Excel COM,需本机装有 Microsoft Excel;仅普通发票需要。模板顺
|
||||
|------|------|------|------|------|
|
||||
| `case_id` | string | 是 | — | — |
|
||||
|
||||
### `mcp__arb__browser_page_state`
|
||||
|
||||
看当前页面:URL、标题、命中的表单标记、已完成步骤、最近截图。
|
||||
|
||||
| 参数 | 类型 | 必填 | 默认 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| `case_id` | string | 是 | — | — |
|
||||
| `screenshot` | boolean | 否 | `true` | — |
|
||||
|
||||
### `mcp__arb__browser_close`
|
||||
|
||||
关闭浏览器并释放锁。不会提交也不会存草稿,填了一半的内容会丢。
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ last_reviewed: 2026-10-19
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `MCP.md` | MCP 工具完整契约:注册方法、返回信封、会话目录、标准流程、24 个工具的参数表 |
|
||||
| `MCP.md` | MCP 工具完整契约:注册方法、返回信封、会话目录、标准流程、25 个工具的参数表 |
|
||||
| `报销操作指南.md` | 面向最终用户的报销口径与材料准备说明 |
|
||||
|
||||
> 旧的 `API.md`(Flask 路由/SSE 文档)已随 Web 界面删除;需要历史接口形态时看 git 提交 `b2d271c`。
|
||||
|
||||
+5
-2
@@ -37,7 +37,7 @@ last_reviewed: 2026-10-19
|
||||
2. **配好** `scripts/data/config.json`(参考根目录 `config.example.json`)
|
||||
3. **要手机拍照上传时**启动收件器:`make upload`(默认 `0.0.0.0:5055`)
|
||||
|
||||
自检:`make mcp-smoke` 会真起 stdio 子进程握手并列出 24 个工具。
|
||||
自检:`make mcp-smoke` 会真起 stdio 子进程握手并列出 25 个工具。
|
||||
|
||||
---
|
||||
|
||||
@@ -84,6 +84,9 @@ last_reviewed: 2026-10-19
|
||||
- 步骤不能跳:travel 是 basic/details/payment/subsidy/attachments,normal 没有 subsidy
|
||||
- 每步截图按 `001-步骤名.png` 落在 `cases/<id>/screenshots/`;失败时截图路径在返回的 `detail.screenshot`
|
||||
- **`browser_close` 不提交也不存草稿**,填了一半会丢;提交本身仍未实现(P4),必须人工核对后自己点
|
||||
- 中途断了不必重来:重新开浏览器登录后用 `browser_open_form`(先 `preview_only=true` 核对**单据编号**,
|
||||
命中多张会直接拒绝)从列表页找回原单续填;**别再 `browser_new_form`**,那会多建一张单
|
||||
- 列表页那个「查看」按钮是看审批流程图,不是打开单据;要接着填是选中行后点「修改」
|
||||
|
||||
**`ok: true` 的含义有限**:`match_payments` 成功只代表贪心跑完。一对多凑额、发票总额小于支付总额、
|
||||
未匹配项都会进 `review_required`,必须逐条确认——等额发票尤其容易配错。
|
||||
@@ -293,6 +296,6 @@ uv run python -m src.infra.documents.requisition --session cases/<case_id> --exc
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [docs/MCP.md](./MCP.md) — 24 个工具的参数与返回约定
|
||||
- [docs/MCP.md](./MCP.md) — 25 个工具的参数与返回约定
|
||||
- [.agents/skills/reimbursement/SKILL.md](../.agents/skills/reimbursement/SKILL.md) — 宿主 Agent 的操作纪律
|
||||
- [AGENTS.md](../AGENTS.md) — 开发约束与踩坑记录
|
||||
|
||||
Reference in New Issue
Block a user