Commit Graph

27 Commits

Author SHA1 Message Date
wandering ceefe3c4eb 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 提交纪律)。
2026-10-20 10:44:57 +08:00
wandering 1725244faf feat(mcp): 浏览器分步填报 P3——7 个 browser 工具 + 单线程 actor + 磁盘锁
填报从「一把梭」变成分步:Agent 可以开浏览器、登录、建单、按步填、看页面、关,每步有截图,
中途失败不必从头重来。提交不在本步——提交不可逆,留给 P4 的 submit_preview/submit_execute。

- src/infra/browser/actor.py(新):Playwright 单线程 actor(sync API 的 greenlet 线程亲和要求所有
  调用回到创建线程)+ 会话注册表 + cases/<id>/.browser.lock(PID/started_at/heartbeat/url,
  心跳 180 秒过期才允许接管;锁文件损坏按无锁处理;atexit 尽力关浏览器)。与 COM actor 分开。
- base.py:login_portal 拆成 submit_login + wait_for_portal(返回布尔不抛异常),新增 portal_reached/
  human_required;_screenshot 支持 screenshot_dir 并按 001-步骤名.png 编号、返回路径、失败只告警
- src/mcp/tools/browser.py(新):browser_open/login/new_form/fill/steps/page_state/close,工具 17 → 24
  · need_human 用 ok:true + logged_in:false 返回(扫码不是失败,避免宿主当错误重试或另开窗口)
  · 步骤顺序硬约束,跳步拒绝并用 next_action 指回该补的一步;步骤报错回传 detail.screenshot
  · browser_close 明确不提交不存草稿;travel 五步、normal 四步(无 subsidy)
- tests/test_mcp_browser.py(新,17 例,FakeBot/FakePage 不起浏览器):锁四种情形、need_human 分支与
  截图落点、重复登录幂等、未打开时各工具拒绝、类型推断与两 info 并存时拒猜、未登录拒建单、跳步拦截、
  步骤推进与 remaining、未知步骤、报错截图、close 释放会话与锁、open 复用、steps 两种流程
- 文档:docs/MCP.md 工具段按 wire schema 重生成(24 工具);AGENTS/SKILL/操作指南/README/浏览器 README
  同步分步流程、锁与心跳、有头默认、提交必须交人工;方案文档 §13 记录实现、取舍与未完成项

验证:
- 联机跑通 open(3.1s 起有头 Chromium)→ 锁写入(pid/heartbeat)→ page_state(about:blank,
  001-state.png 4721 字节)→ 重复 open 复用(already_open=true,不多开窗)→ close(锁释放、注册表清空)
- 登录与填报的联机验证需要用户在场(SSO 可能扫码),本轮未做
- 门禁:ruff / format --check / mypy src / deptry / pytest 129 passed / mcp_smoke 24 工具
  instructions 2109 字节。仍用 --no-verify 提交并手跑等价检查(原因见 AGENTS 提交纪律)。
2026-10-20 00:46:23 +08:00
wandering 9c6f5be56b docs: 方案文档里不要再抄一遍真实工号
§12 记录清洗动作时我把真实工号原样写进了替换说明里,等于在 HEAD 里把它重新引入一次
(全新克隆扫描就是它报的命中)。改成 2024***1(真实值已隐去)。
教训:写「删掉了什么」的记录时,值本身也要脱敏,否则清洗白做。
2026-10-20 00:02:02 +08:00
wandering d3728bfe51 docs: 记录 git 历史清洗,并把文档里的提交号重映射到新历史
- 方案文档新增 §12:为什么洗(公开文档含真实工号/姓名/16 位公务卡号/内网 LLM 地址与 key,
  历史 config.json 含真实登录密码;另发现两份 .xls 是真实申购单、四组样本发票无法证明不含个人信息)、
  怎么做(git-filter-repo 删 19 条路径 + 全历史替换六类特征)、怎么验证(重扫 608 个 blob 零命中、
  与备份 HEAD 逐文件对比只有预期差异)、善后(改密码、轮换 Gitea token、旧 clone 重新拉、删备份 bundle)
- §11.5 第 3 项(模板选择)标记完成
- 按 .git/filter-repo/commit-map 把文档引用的 6 个提交号重映射(6 文件 10 处),
  否则所有「看提交 xxx」的指引在重写后的历史里都是死链
- src/infra/documents/README.md 改写模板章节;docs/MCP.md 文档产物段、README 结构表、
  AGENTS 重要约束同步模板解析顺序与 REQUISITION_TEMPLATE
- 另记一笔:.git/filter-repo/already_ran 时间戳是 2026-06-12,这个仓库六月中已洗过一次历史
2026-10-19 23:57:49 +08:00
wandering 7e900ebdea fix(requisition): 模板三级解析,空白模板入库,产物只写会话 artifacts
历史清洗删掉了根目录两份 低值易耗品申购*.xls——它们其实是**已填写的真实申购单**
(半导体型号、单价、项目名都在),不是模板;同时旧实现「项目根 glob 取名字最大者」会把
上一次生成的产物当模板,所以一并修掉:

- 新增 resolve_requisition_template():REQUISITION_TEMPLATE 环境变量 → templates/ → 项目根(兼容旧位置);
  环境变量指向不存在的文件时告警并继续回退,不静默失败
- 入库 templates/低值易耗品申购.xls 空白件(由旧文件删掉第 3 行起的全部内容得到,UsedRange 只剩 2 行:
  标题 + 表头;真实采购明细不进仓库)
- generate_requisition 默认输出改为 <会话>/artifacts/低值易耗品申购<ts>.xls,不再写模板旁边
- mcp/tools/documents.py 的 _find_template 改为复用同一解析函数,避免两处规则漂移
- 模块 docstring 与 CLI help 里 src/web/uploads 的过时示例改为 cases/
- tests:5 个纯单测覆盖解析优先级(env 优先 / templates 胜过根目录 / 根目录取最新 /
  env 指向不存在的文件时回退 / 全都没有时返回 None),不依赖 COM

验证:真实 Excel COM 端到端 2 项 → 产物 UsedRange 5 行(标题/表头/2 明细/合计),第 6 行起为空,
无旧明细残留;fill_requisition_excel 原本就会先删第 3 行起内容,这条也实测确认过。
门禁:ruff / format --check / mypy src / deptry 全绿,pytest 112 passed,mcp_smoke 17 工具。
2026-10-19 23:57:44 +08:00
wandering e1acf2de84 docs: 文档全面对齐 MCP 架构,并脱敏公开操作指南
接口与入门:
- 新增 docs/MCP.md:注册方法(DSH patch + 通用 client)、返回信封、会话目录布局、标准流程、
  硬约束与未实现清单;工具参考段由**运行时 input_schema 自动生成**,与代码同源不会漂移
- 删除 docs/API.md(856 行 Flask 路由/SSE 文档,描述的端点已不存在)
- 重写根 README.md:为什么放弃自带前端、职责分工表、快速开始、注册配置、流程链、结构与风险
- 重写 AGENTS.md:命令表换成 mcp/mcp-smoke/upload;mypy 目标改 src;新增「提交纪律」
  (pre-commit 的 stash 窗口会回滚未暂存改动)、COM 与 Playwright 线程约束、多进程共存提醒

包文档:src/README.md 与各包 README 按现状重写;新增 src/mcp/README.md(写工具的规矩、
宿主侧四个坑)与 src/upload/README.md(路由表与安全边界);tests/scripts/config 三处索引更新。

提示词迁移:src/infra/llm/ 整个删除,三份系统提示词迁到 .agents/skills/reimbursement/references/
(invoice-fields / travel-info-fields / normal-info-fields),删掉 can_submit 与 suggestion
(save_info 也会主动剥离),「严格只输出 JSON」改为「交给对应工具落盘」;新增 SKILL.md 作为
宿主侧操作纪律(已被 DSH 热加载为 reimbursement 技能)。

作废处理:删除 .agents/docs/guides/系统事件流全景图.md(SSE 与 file_events/agent_events 通道已整体
移除,现在没有任何事件流);给项目架构全景图与架构分析-2026-06-15 加「已过时」横幅保留历史;
config.example.json 去 consumable_storage 加 upload_pin;.env.example 去 LLM 段并说明已不再自动加载 .env。

安全:docs/报销操作指南.md 的示例配置里原来写着**真实姓名、16 位公务卡号、内网 LLM 地址与工号**
(自 9fe5d70/2026-05-25 起在版本历史里),本次全部换成占位符。历史清洗与令牌轮换另议。

门禁(改动含 src/infra/llm 删除,故重跑全部门禁):
  ruff check PASS | ruff format --check PASS(42) | mypy src PASS(34) | deptry PASS(36) |
  pytest 107 passed | scripts/mcp_smoke.py PASS(17 工具 / instructions 1449 字节 / case_list ok)
申购单在依赖清理后另已实机复测:2.4s 生成,产物单元格读回正确。
2026-10-19 22:40:06 +08:00
wandering 87b4080b1b refactor!: 删除 Web/CLI 应用层与内置 LLM 抽取,出库单功能下线(2b)
入口只剩 MCP 服务器;编排由宿主 Agent 负责,本项目只留工具与确定性内核。

删除:
- src/web/(Flask 路由、SSE 轮询、自研聊天前端、模板与静态资源,约 3400 行)
- src/main.py、src/pipeline.py、src/pipeline_core.py(CLI 全流程入口与两套重复管道)
- core/extraction/{extractor,llm_extractor}.py(内置 LLM 抽取、llm_stream.log、file_events.log、并行抽取)
- infra/documents/consumable.py 与 infra/documents/pdf.py:出库单功能下线(Word 模板 4fbb4c3 起已不在仓库,
  该路径此前一直静默失败),PDF 渲染由 core/extraction/render.py 取代
- mcp__arb__doc_consumable 工具;exceptions.ExtractionError;config 的 consumable_storage / get_llm_config /
  load_session_config / SESSION_CONFIG_KEYS(Web 专属,已无引用)
- 针对被删代码的 tests/test_extractor.py、tests/test_llm_extractor.py 与 scripts/ 下的 LLM 调试脚本
- 依赖:llama-index、llama-index-llms-openai-like、python-dotenv(连同其 50+ 传递依赖)
- 提交进来的调试截图 src/images/、根目录 images/ 与 .coverage(并补 .gitignore)

保留与新增:
- 材料入口改为独立进程 src/upload(手机扫码/PC 上传 → cases/<id>/inbox/)
- runner.py 自带 save_invoice_groups,不再依赖 pipeline_core
- scripts/mcp_smoke.py:stdio 自检(拉起自身、列工具、调 case_list、验证 instructions 下发)
- make mcp / mcp-smoke / upload 取代 make run;check 的 mypy 目标从 src/main.py 扩到 src

验证:mcp_smoke 通过(17 个工具、instructions 1449 字节、case_list 正常);申购单实机生成此前已验证。
门禁:ruff check / format --check(43) / mypy src(36 文件) / deptry / pytest 107 passed。
注:仍用 --no-verify 提交并手动跑等价检查(原因见 2f08bbd 提交说明)。
2026-10-19 22:04:25 +08:00
wandering b2d271c5ed feat(mcp): 申购单/出库单生成与抽取结果局部修正(2a)
- src/infra/com_thread.py:Office COM 调用的单线程串行 actor。Word/Excel 并发驱动会互相抢
  ActiveDocument 与模态框,因此所有 COM 操作排队在同一线程执行(与 P3 的 Playwright actor 分开,
  COM 套间与 greenlet 约束不同)
- mcp__arb__doc_requisition:Excel 申购单,产物写 cases/<id>/artifacts/,支持 exclude 关键词与
  project 覆盖。实机验证:2 张普通发票 + 1 笔支付 → 排除「万用表」后生成 19456 字节 .xls,5.0s
- mcp__arb__doc_consumable:Word 出库单;纯差旅返回 skipped 而非报错。当前被缺模板挡住(见下)
- mcp__arb__case_patch_extraction:只改传入的键,回显每个字段的 from/to,未知键告警但仍写入,
  与现值相同时不写(避免无意义重抽),金额/日期仍走 normalize
- server.py:工具数 15 → 18,playbook 增加第 6 步(文档产物)与核对修正说明

发现(未处理,需产品决定):Word 模板「易耗品、出库单.doc」在 4fbb4c3(2026-08-31,同一提交新增
requisition.py)被删除,至今不在仓库里。因此 consumable.py 的出库单路径自那以后一直不可用;
Web 端 _try_fill_consumable_doc 捕获异常后只记日志,所以普通发票提交一直在静默跳过出库单生成。
已确认历史版本是空白校用表单(无姓名、无卡号、无长数字串),是否恢复或改为配置模板路径待定。

门禁:ruff / format --check / mypy / deptry 全绿,pytest 132 passed。
2026-10-19 20:07:38 +08:00
wandering 2f08bbd6e8 refactor: 删除自研 Agent 状态机与 SSE 事件通道
编排(提取-校验-修正循环、轮次上限、补充材料、终态保护)由宿主 Agent 承担,本项目不再自建运行时。

- 删除 src/agent/:AgentSession/AgentState 状态机、校验-修正循环、agent_events.log 事件通道(共 878 行)
- src/web/routes.py:移除 5 个 Agent 端点与 _emit_ready_and_submit(READY 即自动提交财务系统的逻辑一并消失),
  SSE 不再轮询 agent_events.log;_run_agent_task 更名 _run_session_task;824→490 行,18→13 端点
- src/infra/documents/requisition.py:项目名来源改为 .invoice_cache/normal_info.json → travel_info.json →
  旧 agent_state.json(兼容历史会话目录)→ 默认值
- AGENTS.md:架构章节改写为 MCP 模式,CLI 与 Web 标注为遗留待删;补两条集成约束
  (required 键必须存在、宿主侧路径用正斜杠)
- tests:requisition 回退链 +3 用例;Web 冒烟确认 GET / 与保留端点正常、/api/agent/* 返回 404

门禁:ruff check / format --check / mypy src/main.py / deptry 全绿,pytest 132 passed。
注:用 --no-verify 提交——上一轮 pre-commit 在暂存-回滚窗口内被中断,把工作区里几个未暂存
文件回滚成了 HEAD 版本(已重放并逐项核对)。本仓库 pre-commit 只跑 ruff,等价检查已手动执行。
2026-10-19 19:55:26 +08:00
wandering 14b6b4c2d7 feat: MCP 服务器与上传收件器,确立 cases/ 会话模型
- src/mcp: 15 个工具(材料 / 抽取交接 / 匹配 / 校验 / 骨架),stdio 入口 python -m src.mcp.server
- src/upload: 独立进程的扫码上传收件器(服务端 segno 二维码、零 CDN、令牌强制、只写不读)
- src/cases.py: 会话目录唯一实现,阶段由产物推导,不再存在状态机文件
- core/extraction: 拆出 cache.py(纯 IO)与 render.py(PDF 渲染 + 文本层 + 自动转正)
- core/matching: runner.py 从缓存匹配,输出 review_required 而非只给贪心结果
- schemas.py: 抽取字段定义单一真源;payment 补 merchant(validator 早已要求却从未采集)
- config: 修 _CONFIG_PATH 多一层 parent 导致 username/password 恒为空;新增 upload_pin
- 类型: validator.py 10 处与 browser/__init__ 2 处既存 mypy 错误一并修掉(行为以快照 diff 验证不变)
- 依赖: +mcp 2.3.0 +segno;cases/ 与 .mnemon/ 进 .gitignore
- 实测记录: .agents/docs/plans/MCP化改造方案-2026-10-19.md(含 DSH 注册与热重连结论)

注: 本提交用 --no-verify 跳过 pre-commit,等价的 ruff/format 检查已手动跑过(见下条提交说明)。
2026-10-19 19:54:48 +08:00
wandering 4fbb4c36ed 增加生成学校易耗品填写的转换程序 2026-08-31 18:25:35 +08:00
wandering 44496a54e6 fix: 补充 __init__.py 导出符号,修复测试导入错误
- src/core/extraction/__init__.py: 导出 _image_to_base64
- src/core/matching/__init__.py: 导出所有内部函数(_build_invoice_summary, _build_payment_records, _invoices_to_records, _match, _match_by_filename, _match_one_to_many, _match_one_to_one, _relative_tolerance, _safe_float)
- src/infra/documents/__init__.py: 导出 INVOICE_LEVEL_COLUMNS, PAYMENT_RECORD_COLUMNS
- tests/test_extractor.py: 修正 monkeypatch 路径为模块级引用
2026-07-02 18:51:59 +08:00
wandering 8a9c144637 feat: 上传文件后不再自动处理,需用户发送'可以开始'触发
- upload.js/sync.js: 移除 checkAutoStart() 自动调用
- config.js: promptMissingConfig 提示用户手动触发;sendUserMessage 识别'可以开始'等指令
- index.html: 更新欢迎消息
2026-07-02 18:45:53 +08:00
wandering 9043886b6f refactor: 架构重组 — doc/bot → core/infra,新增 Agent 调度模块
- src/doc/ 拆分为 src/core/extraction/, matching/, validation/(核心业务逻辑)
- src/bot/ 重命名为 src/infra/browser/(浏览器自动化基础设施)
- fill_consumable_doc.py → src/infra/documents/consumable.py
- 新增 Agent 调度模块:coordinator.py, events.py, session.py,重构 orchestrator.py
- 更新 AGENTS.md、README.md 及所有子目录 README
2026-07-02 18:36:19 +08:00
wandering e9e0252638 agent 模式补充文件功能已经实现 2026-06-15 10:39:01 +08:00
wandering 62360baf5c 实现Agent对话,合格自动提交,不合格补充材料的能力 2026-06-14 13:38:04 +08:00
wandering 01d4686ceb 实现Agent对话,合格自动提交,不合格补充材料的能力 2026-06-14 12:56:33 +08:00
wandering ef9e1d771b 差旅报销和普通报销都已经完成 2026-06-12 12:08:27 +08:00
wandering 07f5872027 日常报销和差旅报销都可以走通 2026-06-12 12:06:06 +08:00
wandering 3bd325e827 完成差旅发票录入流程 2026-06-11 19:22:34 +08:00
wandering a3d77307aa chore: 从版本控制中移除 uploads 上传文件 2026-06-09 16:30:03 +08:00
wandering 07c0126741 重构项目为LLM 驱动 2026-06-09 16:25:20 +08:00
wandering d52a189587 fix: 出库单金额使用刷卡金额,单价由刷卡金额反算 2026-05-27 10:35:41 +08:00
wandering 1e3a4a7f3e feat: Web 表格编辑、易耗品出库单自动生成与文档完善
- 新增 fill_consumable_doc,根据 CSV 填写 Word 出库单(宋体五号)
- Web 处理完成后自动生成出库单并提供下载
- 前端拆分为 static 资源,支持在线编辑 CSV 与分步提交财务系统
- 补充 API.md、README(含 Mermaid 数据流)及 config.example.json

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-26 14:17:26 +08:00
wandering 31a629df82 清理示例文件和敏感数据 2026-05-25 13:51:57 +08:00
wandering c7110b44b8 增加手机上传图片的功能 2026-05-25 12:00:06 +08:00
wandering 9fe5d7073d Initial commit: Auto-Finance 财务报销自动化系统 2026-05-25 11:18:12 +08:00