修正 SuperAgent 来源消息 ID 契约
This commit is contained in:
@@ -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。
|
||||
|
||||
Reference in New Issue
Block a user