修正 SuperAgent 来源消息 ID 契约

This commit is contained in:
andy
2026-07-08 11:12:11 +08:00
parent fb82386fdb
commit b58c6baafe
12 changed files with 254 additions and 84 deletions

View File

@@ -12,7 +12,7 @@
- `GET /api/source-messages/{id}/original`受控读取邮件原文、HTML 和媒体 URL并记录访问审计。
- `GET /api/system/agentbus-probe`:查看 AgentBus WebSocket 连接状态和安全计数器。
- AgentBus WebSocket 入站链路:默认关闭,开启后只把业务 frame 写入 SourceMessage Inbox。
- SuperAgent 任务结果接收接口:接收一个 `source_message_id` 下的 AI 任务结果,写入 AI 过渡层、订单、任务和任务卡。
- SuperAgent 任务结果接收接口:接收一个外部 `source_message_id` 下的 AI 任务结果,反查 SourceMessage Inbox 后写入 AI 过渡层、订单、任务和任务卡。
- Reservation 任务详情接口:返回任务字段、队列可处理状态和 OPERA 模拟操作摘要。
- Reservation 任务草稿保存和最终确认接口:按任务卡矩阵做第一版后端校验,确认后生成 `confirmed_payload_json`
- Reservation OPERA 模拟骨架已确认任务固定生成两条模拟操作支持执行、失败重试、attempt 记录和任务审计列表。
@@ -97,6 +97,8 @@
- 查询接口和任务结果通知接口使用同一套 Header、签名串、secret、timestamp 和 nonce 规则。
- SuperAgent 侧也需要配置同一个 secret并按原始请求体计算 SHA-256。
- 当前第一版只支持一个 HMAC secretsecret 轮换需要协调部署窗口。
- 任务结果通知接口里的 `source_message_id` 是外部来源消息 ID对应 AgentBus `source.external_message_id`;正式请求必须带 `hotel_id`,后端用 `hotel_id + provider + channel + external_message_id` 反查内部 SourceMessage Inbox。
- SuperAgent 查询上下文接口中的 `source_message_id``source_event_index` 第一版仅兼容接收,不参与查询和校验;不要依赖它们限制查询范围。
## 4. 数据库上线注意事项

View File

@@ -4,7 +4,7 @@
| 项目 | 内容 |
| --- | --- |
| 文档版本 | 0.1 |
| 文档版本 | 0.2 |
| 日期 | 2026-07-08 |
| 状态 | 第一版后端已实现接口契约 |
| 适用范围 | SuperAgent 调用本系统查询上下文、提交 AI 任务结果 |
@@ -73,9 +73,22 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
8. 查询接口校验 `Content-Type` 是否为 `application/json`
9. 鉴权和协议校验通过后再解析业务 JSON。
## 3. 接口 1查询订单上下文
## 3. SourceMessage ID 口径
### 3.1 请求
本系统存在两个容易混淆的 ID
| 名称 | 中文说明 | 使用位置 |
| --- | --- | --- |
| 外部来源消息 ID | AgentBus 邮件 payload 中的 `source.external_message_id`SuperAgent / Main Agent 在最终 JSON 中原样带回为 `source_message_id` | SuperAgent 任务结果通知接口入参和响应回显 |
| 内部 SourceMessage Inbox ID | `platform_source_message_inbox.id`,本系统数据库内部主键 | `workflow_*` 表的 `source_message_id` 外键、前端和运维排查 |
SuperAgent 不应知道或依赖内部 SourceMessage Inbox ID。任务结果通知接口收到外部 `source_message_id` 后,后端使用 `hotel_id + provider + channel + external_message_id` 反查内部 Inbox 记录,再用内部 ID 写入业务表。
查询接口 1、2 在 SuperAgent 查询阶段不依赖当前邮件是否已经入库。若请求体兼容旧契约传入 `source_message_id``source_event_index`,第一版后端会接收但忽略,不校验它们的格式,也不把它们作为查询边界。
## 4. 接口 1查询订单上下文
### 4.1 请求
| 项目 | 内容 |
| --- | --- |
@@ -85,13 +98,11 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
| Content-Type | `application/json` |
| 业务动作 | 只读查询,不创建任务、不修改订单、不写 OPERA |
### 3.2 请求体
### 4.2 请求体
```json
{
"hotel_id": "HOTEL-TEST",
"source_message_id": "1900000000000000001",
"source_event_index": 1,
"group_code": "GRP-001",
"confirmation_number": null,
"reservation_no": null,
@@ -106,8 +117,6 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
| 字段 | 是否必填 | 中文说明 |
| --- | --- | --- |
| `hotel_id` | 是 | 酒店上下文 ID |
| `source_message_id` | 否 | 当前 SourceMessage ID全局上下文查询时可不传只作为审计和排查字段 |
| `source_event_index` | 否 | 当前 AI 事件序号;全局上下文查询可不传,传入时必须为正整数 |
| `group_code` | 条件必填 | Group / Allotment 查询 key |
| `confirmation_number` | 条件必填 | FIT Confirmation Number 查询 key |
| `reservation_no` | 条件必填 | OPERA reservation no当前系统无可靠表源只传该字段时会返回人工复核原因 |
@@ -117,9 +126,9 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
`group_code``confirmation_number``reservation_no` 至少一个非空。当前稳定查询能力优先支持 `group_code``confirmation_number`
全局上下文查询只依赖 `hotel_id + 业务 key``source_message_id``source_event_index` 仅用于审计、追踪或排查,不作为查询边界。
全局上下文查询只依赖 `hotel_id + 业务 key``source_message_id``source_event_index` 不作为查询边界,传入时也不会影响查询结果
### 3.3 成功响应
### 4.3 成功响应
```json
{
@@ -152,7 +161,7 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
}
```
### 3.4 主要数据来源
### 4.4 主要数据来源
| 返回字段 | 来源 |
| --- | --- |
@@ -161,9 +170,9 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
| `terminated_records[]` | 订单 `ENDED` / `LOGIC_DELETED`,任务 `FAILED` / `COMPLETED` |
| `active_workflows[]` | 当前无独立 workflow 表,固定空数组 |
## 4. 接口 2查询对象详情
## 5. 接口 2查询对象详情
### 4.1 请求
### 5.1 请求
| 项目 | 内容 |
| --- | --- |
@@ -173,7 +182,7 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
| Content-Type | `application/json` |
| 业务动作 | 只读查询对象详情,不创建任务、不修改订单、不写 OPERA |
### 4.2 请求体
### 5.2 请求体
```json
{
@@ -191,7 +200,7 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
| `object_id` | 是 | 查询对象 ID第一版只支持 `ORDER:{order_id}` |
| `object_type` | 否 | 调用方对象类型提示,第一版不作为强校验 |
### 4.3 成功响应
### 5.3 成功响应
```json
{
@@ -237,9 +246,11 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
}
```
## 5. 接口 3SuperAgent 通知 AI 任务结果
说明:接口 2 响应中的 `source_message_id` 当前是本系统内部 SourceMessage Inbox ID用于对象溯源和排查不要把该字段当作 SuperAgent 任务结果通知接口的外部 `source_message_id` 使用。
### 5.1 请求
## 6. 接口 3SuperAgent 通知 AI 任务结果
### 6.1 请求
| 项目 | 内容 |
| --- | --- |
@@ -249,11 +260,12 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
| Content-Type | `application/json` |
| 业务动作 | 接收 AI 任务结果,写入 AI 过渡层、订单、任务和任务卡 |
### 5.2 请求体
### 6.2 请求体
```json
{
"source_message_id": "1900000000000000001",
"hotel_id": "HOTEL-TEST",
"source_message_id": "mail-20260708-0001",
"ai_task_results": [
{
"source_event_index": 1,
@@ -287,7 +299,10 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
| 字段 | 是否必填 | 中文说明 |
| --- | --- | --- |
| `source_message_id` | 是 | 本系统 SourceMessage ID一次请求只能有一个 |
| `hotel_id` | 是 | 酒店上下文 ID用于反查 SourceMessage Inbox 幂等键 |
| `source_message_id` | 是 | SuperAgent / Main Agent 原样带回的外部来源消息 ID对应 AgentBus `source.external_message_id`,一次请求只能有一个 |
| `source_provider` | 否 | 来源提供方,第一版缺省为 `AGENTBUS` |
| `source_channel` | 否 | 来源渠道,第一版缺省为 `EMAIL` |
| `ai_task_results[]` | 是 | AI 拆分出的任务结果列表,必须保留数组顺序 |
| `ai_task_results[].source_event_index` | 是 | AI current 事件序号 |
| `ai_task_results[].catalog_code` | 是 | Skill 目录代码 |
@@ -298,12 +313,14 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
| `ai_task_results[].case_keys` | 否 | 订单关联候选键 |
| `ai_task_results[].extracted_fields` | 否 | 业务字段主体 |
### 5.3 成功响应
正式联调时,后端通过 `hotel_id + source_provider(默认 AGENTBUS) + source_channel(默认 EMAIL) + source_message_id` 查找 `platform_source_message_inbox.external_message_id`。如果没有找到,返回 `SOURCE_MESSAGE_NOT_FOUND`。本地旧夹具允许在缺少 `hotel_id` 时使用内部数字 SourceMessage ID但该兼容路径不作为 SuperAgent 正式契约。
### 6.3 成功响应
```json
{
"request_id": "req-003",
"source_message_id": "1900000000000000001",
"source_message_id": "mail-20260708-0001",
"batch_id": "1900000000000000200",
"idempotent_replay": false,
"accepted_count": 1,
@@ -324,9 +341,9 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
}
```
## 6. 错误响应
## 7. 错误响应
### 6.1 查询接口错误响应
### 7.1 查询接口错误响应
```json
{
@@ -343,7 +360,7 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
}
```
### 6.2 任务结果通知接口错误响应
### 7.2 任务结果通知接口错误响应
```json
{
@@ -354,7 +371,7 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
}
```
### 6.3 常见错误码
### 7.3 常见错误码
| 错误码 | HTTP 状态 | 中文说明 |
| --- | --- | --- |
@@ -368,9 +385,10 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
| `REQUEST_BODY_INVALID` | 400 | JSON 不合法 |
| `QUERY_KEY_REQUIRED` | 400 | 查询接口缺少可用业务 key |
| `OBJECT_NOT_FOUND` | 404 | 对象详情查询目标不存在 |
| `SOURCE_MESSAGE_NOT_FOUND` | 400 | 任务结果通知引用的 SourceMessage 不存在 |
| `HOTEL_ID_REQUIRED` | 400 | 任务结果通知使用外部 `source_message_id` 时缺少 `hotel_id` |
| `SOURCE_MESSAGE_NOT_FOUND` | 404 | 任务结果通知引用的外部来源消息尚未写入 SourceMessage Inbox |
## 7. HMAC 上线配置
## 8. HMAC 上线配置
上线需要配置:

View File

@@ -32,7 +32,7 @@
- `body_current` 才能触发业务动作;`body_thread` 只能作为目标绑定证据。
- 如果查询 key 来自历史线程,调用方必须传 `target_key_source=body_thread_evidence``body_thread_used_only_as_evidence=true`
- 第一版不伪造 OPERA 字段。当前系统没有可靠来源的字段返回 `null`,并在 `warnings``hard_validation_warnings` 中说明。
- SuperAgent 允许作为全局上下文查询方按任意业务 key 查询;`source_message_id``source_event_index` 只作为可选审计和排查字段,不作为查询边界。
- SuperAgent 允许作为全局上下文查询方按任意业务 key 查询;`source_message_id``source_event_index` 在查询阶段对本系统没有业务作用,第一版接收但忽略,不做格式校验,也不作为查询边界。
- 导入契约没有显式要求 `hotel_id`,但本系统订单、任务和 AI 过渡表均按 `hotel_id` 隔离。第一版请求体必须显式传 `hotel_id`
## 3. Skill 对接口 1、2 的实际需要
@@ -120,7 +120,7 @@ POST
适用字段包括:
- `source_message_id`
- `source_message_id`,响应中的内部 SourceMessage Inbox ID查询请求中若出现同名字段则视为 SuperAgent 透传字段,后端忽略
- `order_id`
- `task_id`
- `record_id`
@@ -141,8 +141,8 @@ POST /api/ai-query/v1/case-context
| 字段 | 是否必填 | 中文说明 | 当前系统来源或用途 |
| --- | --- | --- | --- |
| `hotel_id` | 是 | 酒店或业务上下文 ID | 用于隔离 `workflow_reservation_*` 表 |
| `source_message_id` | 否 | 当前 SourceMessage ID | 全局上下文查询可不传;传入时只做格式校验和排查辅助 |
| `source_event_index` | 否 | 当前 current 事件序号 | 全局上下文查询可不传;传入时必须为正整数 |
| `source_message_id` | 否 | SuperAgent 透传的外部来源消息 ID | 全局上下文查询可不传;传入时后端接收但忽略,不做格式校验 |
| `source_event_index` | 否 | SuperAgent 透传的 current 事件序号 | 全局上下文查询可不传;传入时后端接收但忽略,不做正整数校验 |
| `group_code` | 条件必填 | Group / Allotment 优先业务 key | 查询 `GROUP_CODE` 类型订单和 AI 过渡记录 |
| `confirmation_number` | 条件必填 | FIT 优先业务 key | 查询 `CONFIRMATION_NUMBER` 类型订单和 AI 过渡记录 |
| `reservation_no` | 否 | OPERA reservation no | 当前无可靠表源,第一版不作为主查询条件 |
@@ -185,7 +185,7 @@ POST /api/ai-query/v1/case-context
| --- | --- | --- | --- |
| `task_id` | 是 | 本系统任务 ID | `workflow_reservation_task.id` |
| `order_id` | 是 | 任务当前挂靠订单 | `workflow_reservation_task.order_id` |
| `source_message_id` | 是 | 任务来源消息 ID | `workflow_reservation_task.source_message_id` |
| `source_message_id` | 是 | 任务来源内部 SourceMessage Inbox ID | `workflow_reservation_task.source_message_id` |
| `source_event_index` | 是 | AI current 事件序号 | `workflow_reservation_ai_transition.source_event_index` |
| `catalog_code` | 否 | Skill 目录代码 | `workflow_reservation_ai_transition.catalog_code` |
| `skill_id` | 否 | Skill 标识 | `workflow_reservation_ai_transition.skill_id` |
@@ -203,6 +203,8 @@ POST /api/ai-query/v1/case-context
| `blocked_until_parent_completed` | 是 | 是否等待父任务完成 | `workflow_reservation_task.blocked_until_parent_completed` |
| `last_updated_at` | 是 | 最近更新时间 | `workflow_reservation_task.updated_at` |
说明:响应字段中的 `source_message_id` 来自 `workflow_reservation_task.source_message_id`,表示本系统内部 SourceMessage Inbox ID它不同于查询请求和任务结果通知请求中 SuperAgent 透传的外部来源消息 ID。
第一版 `pending_or_open_tasks[]` 至少包含状态为 `PENDING_CONFIRM``READY``EXECUTING` 的任务。`FAILED` 在本系统第一版视为结束状态,不阻塞后续任务。
#### `active_workflows[]`
@@ -336,7 +338,7 @@ POST /api/ai-query/v1/object-detail
| `temporary_order_code` | 是 | 临时订单编号 | `workflow_reservation_order.temporary_order_code` |
| `display_name` | 是 | 用户可读展示名 | `workflow_reservation_order.display_name` |
| `status` | 是 | 订单状态 | `workflow_reservation_order.order_status` |
| `source_message_id` | 是 | 首次创建订单的来源消息 | `workflow_reservation_order.source_message_id` |
| `source_message_id` | 是 | 首次创建订单的内部 SourceMessage Inbox ID | `workflow_reservation_order.source_message_id` |
| `created_from_task_id` | 否 | 首次创建订单的任务 ID | `workflow_reservation_order.created_from_task_id` |
| `created_at` | 是 | 创建时间 | `workflow_reservation_order.created_at` |
| `last_updated_at` | 是 | 最近更新时间 | `workflow_reservation_order.updated_at` |
@@ -455,7 +457,7 @@ POST /api/ai-query/v1/object-detail
已落地能力:
- 接口 1 可按 `hotel_id + group_code``hotel_id + confirmation_number` 查询订单上下文,允许不传 `source_message_id``source_event_index` 的全局上下文查询。
- 接口 1 可按 `hotel_id + group_code``hotel_id + confirmation_number` 查询订单上下文,允许不传 `source_message_id``source_event_index` 的全局上下文查询;即使传入这两个字段,后端也不把它们作为查询或校验条件
- 接口 1 返回 `matched_order_records``pending_or_open_tasks``active_workflows``terminated_records``target_object_validation``key_relationships`
- `active_workflows` 当前无独立表源,固定返回空数组。
- 接口 2 支持 `ORDER:{order_id}` 查询本系统订单快照。

View File

@@ -89,7 +89,7 @@ Controller、Service、Service 实现类的方法必须有中文注释。Entity
目标:
- 建立 AI 接收批次表和 AI 过渡表。
- 保存 `source_message_id + ai_task_results[] + extraction_warnings[]`
- 保存外部 `source_message_id + ai_task_results[] + extraction_warnings[]`,并将外部来源消息 ID 反查为内部 SourceMessage Inbox ID 后落业务表
- 实现系统生成幂等键,保证重复提交不重复创建记录。
建议范围:
@@ -98,13 +98,13 @@ Controller、Service、Service 实现类的方法必须有中文注释。Entity
- Entity、Mapper、Repository。
- 批次幂等键生成。
- item 幂等键生成。
- `source_message_id` 存在性校验。
- 外部 `source_message_id` 存在性校验:通过 `hotel_id + provider + channel + external_message_id` 查找 SourceMessage Inbox
- 保存 AI 原始 JSON 和常用物理列。
验收标准:
- 同一请求重复提交返回幂等重放,不重复插入。
- 同一 `source_message_id` 不同请求体第一版返回 `409`
- 同一外部 `source_message_id` 不同请求体第一版返回 `409`
- 每个 item 保存 `array_index``source_event_index``execution_order`
- 保存 `ai_payload_json`,用户后续修改不得覆盖该字段。

View File

@@ -82,7 +82,7 @@ AI 聚合输出的顶层结构应包含:
| 字段 | 中文说明 |
| --- | --- |
| `source_message_id` | 关联的 SourceMessage ID |
| `source_message_id` | SuperAgent / Main Agent 原样带回的外部来源消息 ID对应 AgentBus `source.external_message_id`,不是本系统内部 SourceMessage Inbox 主键 |
| `ai_task_results[]` | AI 拆分出的一个或多个任务结果,顺序必须保留 |
| `extraction_warnings[]` | 抽取警告,不直接等同于业务任务 |
@@ -108,7 +108,7 @@ AI 聚合输出的顶层结构应包含:
| `additional_operations` | AI 建议的附加动作 |
| `idempotency_key` | 幂等键,最终来源和生成规则待确认 |
待补充的 HTTP 契约包括 URL、Method、Header、鉴权、幂等策略、错误响应格式、是否允许重复推送同一个 `source_message_id`
HTTP 契约已在 `docs/project/requirements/M002-superagent-task-result-api-contract.md``docs/project/integrations/superagent-api-contract.md` 中补充。正式契约要求任务结果通知携带 `hotel_id + source_message_id`,其中 `source_message_id` 是外部来源消息 ID后端会反查内部 SourceMessage Inbox ID 后再写入 `workflow_*`
## 6. AI 过渡层数据要求
@@ -131,7 +131,7 @@ AI 聚合输出的顶层结构应包含:
| 物理列 | 中文说明 |
| --- | --- |
| `source_message_id` | 来源消息 ID |
| `source_message_id` | 内部 SourceMessage Inbox ID来自外部 `source_message_id` 反查后的 `platform_source_message_inbox.id` |
| `source_event_index` | AI 事件序号 |
| `catalog_code` | Skill 目录代码 |
| `skill_id` | Skill 标识 |
@@ -484,6 +484,7 @@ Fallback 处理规则:
- SuperAgent 创建任务接口的 URL、Method、Header、鉴权和错误响应格式。
- SuperAgent 查询上下文接口 1、2 已实现最小字段版,并已启用与任务结果接收接口一致的 HMAC接口 3 文件解析和接口 4 订单及任务查询仍需后续确认与实现,后续梳理未完成事项时必须持续提醒。
- SuperAgent 任务结果通知中的 `source_message_id` 已确认是外部来源消息 ID对应 AgentBus `source.external_message_id`;查询接口中的 `source_message_id``source_event_index` 第一版接收但忽略。
- `source_event_index`、批次 item index、`execution_order` 的最终编号规则是否都从 1 开始。
- SuperAgent 查询上下文接口 3、4 的 URL、入参、返回字段和鉴权方式。
- `Message Notification` 是否需要在前端订单列表上单独标识为只读提醒。

View File

@@ -4,7 +4,7 @@
| 项目 | 内容 |
| --- | --- |
| 文档版本 | 0.1 |
| 文档版本 | 0.2 |
| 日期 | 2026-07-07 |
| 状态 | 后端接口契约草稿 |
| 适用范围 | SuperAgent / Main Agent 调用本系统提交 AI 任务结果 |
@@ -34,6 +34,21 @@
- SuperAgent 不直连数据库,只能通过本接口提交任务结果。
- 本接口只做技术校验和系统接收,不替代用户确认和 OPERA 模拟操作。
### 2.1 SourceMessage ID 口径
本接口请求体中的 `source_message_id` 是 SuperAgent / Main Agent 从通用溯源字段中原样带回的外部来源消息 ID对应 AgentBus 邮件 payload 的 `source.external_message_id`,不是 `platform_source_message_inbox.id`
后端正式处理路径:
```text
hotel_id + source_provider(默认 AGENTBUS) + source_channel(默认 EMAIL) + source_message_id
→ platform_source_message_inbox.external_message_id
→ platform_source_message_inbox.id
→ workflow_* 表 source_message_id 内部外键
```
数据库 `workflow_*` 表中的 `source_message_id` 仍然保存内部 SourceMessage Inbox ID。只有对外接口的 `source_message_id` 使用外部来源消息 ID。无 `hotel_id` 时仅兼容本地旧夹具使用内部数字 ID正式 SuperAgent 调用不得依赖该兼容路径。
## 3. 鉴权方案
第一版使用 HMAC-SHA256 签名,做到简单、可实现、可防重放。
@@ -106,7 +121,8 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
```json
{
"source_message_id": "1900000000000000001",
"hotel_id": "HOTEL-TEST",
"source_message_id": "mail-20260708-0001",
"ai_task_results": [
{
"source_event_index": 1,
@@ -140,7 +156,10 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
| 字段 | 是否必填 | 中文说明 |
| --- | --- | --- |
| `source_message_id` | 是 | 关联本系统 SourceMessage ID一次请求只能有一个 |
| `hotel_id` | 是 | 酒店上下文 ID用于反查 SourceMessage Inbox 幂等键 |
| `source_message_id` | 是 | 外部来源消息 ID对应 AgentBus `source.external_message_id`;一次请求只能有一个 |
| `source_provider` | 否 | 来源提供方,第一版缺省为 `AGENTBUS` |
| `source_channel` | 否 | 来源渠道,第一版缺省为 `EMAIL` |
| `ai_task_results[]` | 是 | AI 拆分出的任务结果列表,必须保留数组顺序 |
| `extraction_warnings[]` | 否 | 抽取警告;不直接等同于业务任务 |
@@ -177,8 +196,9 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
- 鉴权签名合法。
- 请求体大小不超过限制。
- JSON 可解析。
- `hotel_id` 存在。仅本地旧夹具兼容缺少 `hotel_id``source_message_id` 为内部数字 ID 的调用。
- 顶层只有一个 `source_message_id`
- `source_message_id` 对应的 SourceMessage 存在
- `source_message_id` 对应的外部来源消息已经写入 SourceMessage Inbox
- `ai_task_results[]` 是非空数组。
- `result_type` 属于允许值。
- `task_type` 属于当前系统可识别的稳定值或可进入 Fallback 处理。
@@ -214,7 +234,7 @@ request_payload_sha256 = sha256(raw_request_body)
batch_idempotency_key =
sha256(
"superagent-task-result-batch:v1"
+ "|" + source_message_id
+ "|" + source_message_internal_id
+ "|" + request_payload_sha256
)
```
@@ -222,7 +242,7 @@ sha256(
作用:
- 相同请求体重复提交时识别为幂等重放。
- 同一个 `source_message_id` 如果提交了不同请求体,不会被误认为同一个批次。
- 同一个外部 `source_message_id` 解析到的内部 SourceMessage 如果提交了不同请求体,不会被误认为同一个批次。
### 6.3 item 幂等键
@@ -232,7 +252,7 @@ sha256(
item_idempotency_key =
sha256(
"superagent-task-result-item:v1"
+ "|" + source_message_id
+ "|" + source_message_internal_id
+ "|" + source_event_index
+ "|" + array_index
+ "|" + catalog_code
@@ -255,7 +275,7 @@ sha256(
| 场景 | 处理方式 |
| --- | --- |
| 完全相同请求体重复提交 | 返回已有 batch 和 item不重复创建任务 |
| 同一 `source_message_id` 不同请求体 | 作为潜在冲突处理,第一版建议拒绝并返回 `IDEMPOTENCY_CONFLICT`,除非后续明确支持重新抽取版本 |
| 同一外部 `source_message_id` 不同请求体 | 作为潜在冲突处理,第一版建议拒绝并返回 `IDEMPOTENCY_CONFLICT`,除非后续明确支持重新抽取版本 |
| 同一请求内 item 幂等键重复 | 拒绝请求,返回 `DUPLICATE_TASK_RESULT_ITEM` |
## 7. 系统映射规则
@@ -286,7 +306,7 @@ sha256(
```json
{
"request_id": "req-20260707-0001",
"source_message_id": "1900000000000000001",
"source_message_id": "mail-20260708-0001",
"batch_id": "1900000000000001001",
"idempotent_replay": false,
"accepted_count": 1,
@@ -315,7 +335,7 @@ sha256(
```json
{
"request_id": "req-20260707-0002",
"source_message_id": "1900000000000000001",
"source_message_id": "mail-20260708-0001",
"batch_id": "1900000000000001001",
"idempotent_replay": true,
"accepted_count": 1,
@@ -352,8 +372,9 @@ sha256(
| 409 | `AUTH_NONCE_REPLAY` | Nonce 重放 |
| 413 | `REQUEST_BODY_TOO_LARGE` | 请求体过大 |
| 400 | `INVALID_JSON` | JSON 不可解析 |
| 400 | `HOTEL_ID_REQUIRED` | 使用外部 `source_message_id` 时缺少 `hotel_id` |
| 400 | `SOURCE_MESSAGE_REQUIRED` | `source_message_id` 缺失 |
| 404 | `SOURCE_MESSAGE_NOT_FOUND` | SourceMessage 不存在 |
| 404 | `SOURCE_MESSAGE_NOT_FOUND` | 外部来源消息尚未写入 SourceMessage Inbox |
| 400 | `TASK_RESULTS_EMPTY` | `ai_task_results[]` 为空 |
| 400 | `TASK_RESULT_UNSUPPORTED_TYPE` | `result_type``task_type` 不可识别 |
| 400 | `DUPLICATE_TASK_RESULT_ITEM` | 同一请求内 item 重复 |
@@ -371,8 +392,8 @@ sha256(
- nonce 重放时返回 `409`
- 签名错误时返回 `401`
- 一个请求只能包含一个 `source_message_id`
- `source_message_id` 不存在时返回 `404`
- 外部 `source_message_id` 未匹配 SourceMessage Inbox 时返回 `404`
- 相同请求重复提交不会重复创建任务。
- 同一 `source_message_id` 不同请求体重复提交返回 `409`
- 同一外部 `source_message_id` 不同请求体重复提交返回 `409`
- 成功接收后能保存 AI 过渡层记录,并返回 batch、task 和 order 标识。
- 日志和响应不暴露 secret、签名原文、完整邮件正文或附件 URL。