feat(invoice-organizer): 新增发票整理助手 Agent / add Invoice Organizer agent (#117)

新增官方 inline Agent「发票整理助手」(`invoice-organizer`)。

Adds an official inline Agent, **Invoice Organizer**, that turns
invoices scattered across
mailboxes and local folders into a reconcilable, reusable ledger.

## 它做什么 / What it does

七步固定流程,每一步幂等:**接入检查 → 收集 → 解析 → 去重 → 归档 → 台账 → 报告**。

- **收集**:从已接入的邮箱(Gmail / Outlook / IMAP)找出候选发票邮件,附件用 `MailOperations` 的
  `save_to` 直接落盘,base64 不进模型上下文
- **解析**:OFD(三个结构化来源分别处理)、PDF 文字层、扫描件走视觉;每个字段带 `extractedBy` 与置信度
- **去重**:发票号码为主键,跨格式识别同一张票(PDF 与照片、重复下载);近重复不自动合并
- **归档**:`归档/年/月/YYYYMMDD_销售方_金额_发票号码.ext`,原件一个不动
- **台账**:xlsx 四张表(明细 / 月度汇总 / 按销售方汇总 / 异常),发票号码强制文本格式;
  装不上 openpyxl 时降级为 UTF-8 BOM CSV
- **报告**:Markdown 月度报告,收尾固定报五个计数(范围 / 候选 / 成功 / 待复核 / 失败)
- **自动化**:邮件规则 `agent_handle` + `ManageSchedule` 定时出账

## 明确的能力边界 / Explicit boundaries

- **不做发票真伪查验**,也不暗示做过——只做形式校验与勾稽校验,给出官方查验平台入口让用户自己核验
- **不删除、不移动、不转发用户的邮件**
- **票面内容不外流**:不外发、不代发、不上传第三方接口或在线查验站点
- **不做汇率换算**;不承诺「已找全」,只报「在给定范围内找到 N 封候选、成功解析 M 张」

## 结构 / Structure

```
agents/invoice-organizer/
├── agent.json  persona.md  principles.md  LICENSE
├── USAGE.zh-CN.md  USAGE.en-US.md
├── catalog-metadata.v1.json      # availability: listing-only(可安装化见下)
├── assets/avatar.webp
└── skills/
    ├── invoice-workflow/         # 七步总纲、目录布局、落盘顺序、去重主键、幂等
    ├── invoice-extract/          # 三种载体的解析细则、置信度分档、特殊票据
    │   └── references/票面文本形态.md
    ├── invoice-ledger/           # 台账结构、人民币约定(覆盖 xlsx 技能的默认口径)
    │   └── references/月度报告模板.md
    └── invoice-automation/       # 邮件规则与定时调度的参数模板与排查
```

`manifest.json` 的 `stats.totalAgents` 3 → 4。

## 事实性核对 / Fact-checking

技能里引用的**每一个**端点 / 工具名 / 参数名 / 返回字段都对着 DesireCore 主仓库实现逐条核对过,
并经过一轮对抗式 review。review 抓到的、已修正的主要事实错误:

- OFD 一节原本只覆盖 2020 年式样;已改为按**三个来源**分述
  (内嵌附件 / 2024 数电票的 `Tags/CustomTag.xml` 标引 / `DocInfo/CustomDatas`),
  键名从 `Buyer/BuyerName` 改为真实的点号路径 `Buyer.BuyerName`,置信度按来源分档
- **`DocInfo/CustomDatas` 的「合计金额」是不含税金额**,误当 `totalAmount` 会让每张 2024
数电票少记税额
  ——已写成硬规则
- Gmail 本地缓存搜索的 `q` **实际只按主题过滤**(正文过滤在主题收窄之后才跑),
  原文写成「搜主题与正文」会导致静默漏邮件
- 「轮询只覆盖收件箱」只对 IMAP 成立,Gmail / Outlook 是整个邮箱
- `POST /rules/{id}/test` 走另一份内联实现、**没有 `matches_regex` 分支**,
  不能用它验证正则规则
- 邮件列表项里 Gmail / IMAP **是带** `attachments[]` 的,只有 Outlook 不带;
  `labelIds` 是 Gmail 专有

## 真机验证 / Verified on a live instance

在 dev 实例上以一句话指令处理 31 个混合文件(数电票 / 旧版票 / OFD / 扫描件 / 行程单,
外加重复、近重复、作废、零额与 4 个非发票负样本):

- 23 张归档,字段与夹具 ground truth **逐条吻合**
- 4 个非发票**全部正确拒绝**并写明理由(施工许可证 / 对账单 / 技术服务合同 / 邮件通知)
- 4 个跨格式重复(3 张扫描件 + 1 次重复下载)**全部靠发票号码主键识破**,隔离而非删除
- 近重复正确未合并;作废票归档但不计入合计;低置信度定额发票标为待复核
- 台账 xlsx 四张表、报告含五个计数、`SendUserMessage` 带附件交付
- `待整理/` 31 个原件一个未动

## 校验 / Validation

```
validate_catalog_metadata.py --require-complete   0 error, agents=4, sidecars=74   exit=0
validate-i18n.py                                  0 error                          exit=0
translate.py --check                                                               exit=0
gen-collection-children.py --check                                                 exit=0
```
129 条 warning 全部来自 `skills/*` 的存量条目,改前改后一字不差,`invoice-organizer` 零命中。
另核实:`agent.json` 过 `marketAgentSchema`(详情页)与收窄后过
`agentConfigSchema`(安装),
persona / principles 的 6 个 canonical key 用平台真实解析器全部解得出,全树敏感信息扫描通过
(所有公司名 / 税号 / 银行账号均为 `示例`/`示范`/`虚构`/`样例` 前缀的合成值)。

## 后续 / Follow-up

本 PR 为 `availability: listing-only`。可安装化需要把 `agent.json#contentSource` 与
sidecar 的 `provenance.content` **逐字一致地** pin 到本 PR 的合并 commit,
并补 `governance.compliance` 与 `timestamps.reviewedAt`——那是紧接着的第二个 PR。
This commit is contained in:
2026-09-04 07:28:03 -04:00
committed by GitHub
parent 61c82782c4
commit 42a29e99a0
15 changed files with 1889 additions and 2 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 DesireCore
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.