实现 M002 V4 入站解析基线

This commit is contained in:
andy
2026-07-18 17:32:07 +07:00
parent b949177feb
commit 6be14f2b40
9 changed files with 1445 additions and 31 deletions

View File

@@ -4,9 +4,9 @@
| 项目 | 内容 |
| --- | --- |
| 文档版本 | 0.7 |
| 日期 | 2026-07-11 |
| 状态 | 当前代码契约已支持 V2 `ai_task_results[]` 兼容、结构化 S10/S99、V3 业务根基础解析、旧 S000/S999 兼容和单酒店 hotel_id 后端解析 |
| 文档版本 | 0.8 |
| 日期 | 2026-07-18 |
| 状态 | 当前代码契约已支持 V4 入站解析基线、V2 `ai_task_results[]` 兼容、结构化 S10/S99、V3 业务根基础解析、旧 S000/S999 兼容和单酒店 hotel_id 后端解析 |
| 适用范围 | SuperAgent 调用本系统查询上下文、查询邮件会话、提交 AI 任务结果 |
| 主要读者 | SuperAgent 对接方、后端、测试、运维 |
@@ -88,7 +88,7 @@ X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>
6. 使用共享 secret 重新计算 HMAC。
7. 常量时间比较签名。
8. 校验并记录 `client_id + nonce`,防止重放。
9. 鉴权和协议校验通过后再解析业务 JSON、结构化 S10/S99、V3 业务根或 S000/S999 文本结果。
9. 鉴权和协议校验通过后再解析业务 JSON、V4 包、结构化 S10/S99、V3 业务根或 S000/S999 文本结果。
## 3. SourceMessage ID 口径
@@ -455,9 +455,124 @@ SuperAgent 不应知道或依赖内部 SourceMessage Inbox ID也不需要为
| URL | `{TH_HOTEL_API_BASE_URL}/api/integrations/superagent/task-results` |
| request_path | `/api/integrations/superagent/task-results` |
| Content-Type | `application/json``text/plain` |
| 业务动作 | 接收 AI 任务结果V3 JSON 支持结构化 S10/S99 和业务根V2 JSON 继续兼容,旧 S000/S999 文本创建只读特殊任务 |
| 业务动作 | 接收 AI 任务结果V4 JSON 支持 S10/S99 和业务根入站基线V3 / V2 JSON 继续兼容,旧 S000/S999 文本创建只读特殊任务 |
### 8.2 V3 S10/S99 结构化请求体
### 8.2 V4 JSON 请求体(当前推荐)
V4 普通业务包示例:
```json
{
"route_code": null,
"source_message": {
"source_message_id": "mail-20260718-0001",
"conversation_id": "thread-001",
"subject": "Group booking and payment",
"sender": "agent@example.test",
"sent_at": "2026-07-18T02:10:00Z",
"body": "Please create group GRP-001 and note payment attached.",
"body_content_type": "text/plain",
"attachments": [
{
"id": "att-pay-1",
"name": "payment-slip.jpg",
"content_type": "image/jpeg",
"url": "https://oss.example.test/payment-slip.jpg",
"size": 251524
}
]
},
"order_contexts": [
{
"order_ref": "order-1",
"basic_information": {
"account_code": "QBD_TRAVEL",
"manual_review": null
}
}
],
"message_events": [
{
"order_ref": "order-1",
"event_type": "NEW_BOOKING",
"target_order": {
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "GRP-001"
},
"arrival_date": "2026-07-26",
"departure_date": "2026-07-29",
"rate_code": "BAR",
"booking_scenario": "STANDARD",
"room_items": [
{
"room_type_code": "TWN",
"room_count": 2
}
],
"manual_review": null
},
{
"order_ref": "order-1",
"event_type": "PAYMENT",
"target_order": {
"booking_type": "GROUP",
"locator_type": "GROUP_CODE",
"locator_value": "GRP-001"
},
"attachment_ids": ["att-pay-1"],
"manual_review": null
}
]
}
```
V4 纯通知包示例:
```json
{
"route_code": "S10",
"source_message": {
"source_message_id": "mail-20260718-0002",
"conversation_id": "thread-002",
"subject": "Thanks",
"sender": "guest@example.test",
"sent_at": "2026-07-18T02:10:00Z",
"body": "Noted with thanks.",
"body_content_type": "text/plain",
"attachments": []
},
"order_contexts": [],
"message_events": []
}
```
V4 字段说明:
| 字段 | 是否必填 | 中文说明 |
| --- | --- | --- |
| `route_code` | 是 | 普通业务固定为 `null`;入口通知第一版支持 `S10/S99`,当前新业务语义以 `S10` 为准,`S99` 仅作为兼容入口保留。 |
| `source_message.source_message_id` | 是 | 外部来源消息 ID对应 SourceMessage Inbox 的 `external_message_id`。 |
| `source_message.body_content_type` | 是 | 只能是 `text/plain``text/html`。 |
| `source_message.attachments[]` | 是 | 包级附件数组;每个附件必须有 `id/name/content_type/url``size` 可省略或为 `null`。 |
| `order_contexts[]` | 普通业务必填 | 每个 `order_ref` 一项,第一版必须带 `basic_information.account_code``basic_information.manual_review`。 |
| `message_events[]` | 普通业务必填 | 逐 event 入站,后端按数组顺序处理。 |
| `message_events[].event_type` | 是 | 第一版支持 `NEW_BOOKING``UPDATE_BOOKING``CANCEL_BOOKING``TRACE_RESERVATION_NOTES``ROOMING_LIST``PAYMENT`。 |
| `message_events[].target_order` | 是 | `GROUP + GROUP_CODE`,或 `FIT + BOOKING_CODE / CONFIRMATION_NUMBER`。 |
| `message_events[].manual_review` | 是 | 只能是 `null` 或布尔 `true``true` 必须能由当前对象中的未解决字段解释。 |
| `PAYMENT.attachment_ids[]` | PAYMENT 必填 | 必须引用同包 `source_message.attachments[].id`。 |
当前已支持的 V4 行为:
- 命中 SourceMessage 后保存 AI batch / transition并按 `message_events[]` 顺序处理。
- 可映射 event 先复用现有订单 / 任务 / 任务卡链路,`ai_payload_json` 会保留 `v4_source_message``v4_order_context``v4_message_event`
- `route_code=S10/S99` 创建只读 `SOURCE_MESSAGE_ONLY` 任务,任务列表可见,订单列表不可见。
- `PAYMENT.attachment_ids[]` 引用不存在的附件、`UPDATE_BOOKING` 携带 `rate_code`、以及其他 V4 event 契约错误,只写 `adapter_contract_error` transition不创建用户可处理业务任务。
- 技术契约错误不会自动转为 S10/S99也不会创建前端可处理业务任务。
当前 V4 入站仍未完成完整多卡模型Basic Information 独立卡、V4 页面模型、真实 OPERA / OHIP、普通任务切换订单均后置。
### 8.3 V3 S10/S99 结构化请求体
S10 示例:
@@ -493,7 +608,7 @@ S10 示例:
S99 与 S10 使用相同结构,但 `route_code=S99``agent_assessment.status=material_package_unavailable`,且 `manual_review` 必须是完整入口复核对象。
### 8.3 V3 业务根请求体
### 8.4 V3 业务根请求体
```json
{
@@ -589,7 +704,7 @@ V3 字段说明:
}
```
### 8.4 V2 JSON 兼容请求体
### 8.5 V2 JSON 兼容请求体
```json
{
@@ -645,7 +760,7 @@ V3 字段说明:
`informational_message` 结构化任务仅用于历史兼容。新数据如果是纯信息类邮件或无法形成业务素材包,应优先使用 V3 结构化 `S10/S99`;旧联调或兼容场景仍可使用下面的 `S000/S999` 文本请求体。
### 8.5 S000/S999 文本请求体
### 8.6 S000/S999 文本请求体
纯信息类邮件:
@@ -669,7 +784,7 @@ S999,mail-20260708-0001
S000/S999 不在 body 里传 `hotel_id`,后端使用平台酒店表唯一 `ACTIVE` 酒店和外部消息 ID 查询 SourceMessage Inbox。命中后创建 `SOURCE_MESSAGE_ONLY` 只读特殊任务:任务列表可见,订单列表不可见,不允许编辑、确认、转换订单、执行 OPERA 或重试 OPERA也不参与同订单任务执行顺序阻塞。该文本格式仅为兼容路径新数据优先使用结构化 `S10/S99`
### 8.6 成功响应
### 8.7 成功响应
```json
{