收口MCP提交为V4契约
This commit is contained in:
@@ -4,9 +4,9 @@
|
||||
|
||||
| 项目 | 内容 |
|
||||
| --- | --- |
|
||||
| 文档版本 | 0.10 |
|
||||
| 日期 | 2026-07-20 |
|
||||
| 状态 | 当前代码契约已支持 V4 订单任务 + 多卡入站、V4 S10/S99 来源通知、V2 `ai_task_results[]` 兼容、V3 业务根兼容、旧 S000/S999 兼容、M011 Booking Excel 调 SuperAgent 前预处理增强和单酒店 hotel_id 后端解析 |
|
||||
| 文档版本 | 0.11 |
|
||||
| 日期 | 2026-07-22 |
|
||||
| 状态 | 当前代码契约已支持 V4 订单任务 + 多卡入站、V4 S10/S99 来源通知、REST 历史 V2 `ai_task_results[]` / V3 业务根兼容、旧 S000/S999 兼容、M011 Booking Excel 调 SuperAgent 前预处理增强和单酒店 hotel_id 后端解析;MCP `th_hotel_submit_task_results` 已收口为 M002 V4-only,不再接受 V2/V3 submit payload |
|
||||
| 适用范围 | SuperAgent 调用本系统查询上下文、查询邮件会话、提交 AI 任务结果 |
|
||||
| 主要读者 | SuperAgent 对接方、后端、测试、运维 |
|
||||
|
||||
@@ -714,9 +714,9 @@ V3 字段说明:
|
||||
|
||||
当前已支持的 V3 行为:
|
||||
|
||||
- 如果通过 MCP `th_hotel_submit_task_results` 调用,MCP adapter 会在进入业务入站服务前按 `message_events[]` 顺序把 Agent 内部事件 ID 映射为本系统一基 `source_event_index`,并校验 `related_source_event_index`、`parent_source_event_index` 和 `related_source_event_indices[]` 是否悬空或重复;成功响应会额外返回 `mapping_diagnostics`,该诊断不写入业务 JSON。
|
||||
- MCP adapter 只拦 transport 层问题,例如未知字段、缺失或重复 `source_event_index`、关系引用悬空或重复、V2 item schema 不完整;V3 event 的业务契约问题,例如 unsupported `event_type`、不完整 `case_keys`、不完整 `manual_review`,继续由业务入站层保存为 `adapter_contract_error` transition。
|
||||
- MCP 路径缺失 `source_message.source_message_id` 或整个 `source_message` 时,保留业务入站层 `MISSING_SOURCE_MESSAGE_ID` 错误语义。
|
||||
- 仅 REST 历史兼容路径仍可接收 V3 业务根;MCP `th_hotel_submit_task_results` 已收口为 V4-only,旧 V3 payload 会返回 `MCP_SUBMIT_V4_REQUIRED`。
|
||||
- REST 历史兼容路径中,V3 event 的业务契约问题,例如 unsupported `event_type`、不完整 `case_keys`、不完整 `manual_review`,继续由业务入站层保存为 `adapter_contract_error` transition。
|
||||
- REST 历史兼容路径缺失 `source_message.source_message_id` 或整个 `source_message` 时,保留业务入站层 `MISSING_SOURCE_MESSAGE_ID` 错误语义。
|
||||
- 40 条 P0.1 路由进入后端枚举 / 稳定配置。
|
||||
- `route_code` 是稳定代码,不因路由总数从 42 调整为 40 而重编号;联调方不要按数字连续性判断合法性。
|
||||
- V3 结构化 `S10/S99` 兼容路径创建只读 `SOURCE_MESSAGE_ONLY` 任务,任务列表可见,订单列表不可见;V4 新入站不走该模型,改用来源通知。
|
||||
@@ -788,13 +788,13 @@ V3 字段说明:
|
||||
| `ai_task_results[].source_event_index` | 是 | AI current 事件序号 |
|
||||
| `ai_task_results[].catalog_code` | 是 | Skill 目录代码 |
|
||||
| `ai_task_results[].skill_id` | 是 | Skill 标识 |
|
||||
| `ai_task_results[].result_type` | 是 | 当前代码契约接受 `normal_task`、`manual_review`;`informational_message` 仅历史兼容;MCP 路径会在 adapter 层校验 |
|
||||
| `ai_task_results[].result_type` | 是 | 当前 REST 历史兼容契约接受 `normal_task`、`manual_review`;`informational_message` 仅历史兼容;MCP submit 已不接受 V2 `ai_task_results[]` |
|
||||
| `ai_task_results[].task_type` | 是 | AI 原始任务类型 |
|
||||
| `ai_task_results[].task_subtype` | 否 | 业务动作 subtype |
|
||||
| `ai_task_results[].case_keys` | 否 | 订单关联候选键 |
|
||||
| `ai_task_results[].extracted_fields` | 否 | 业务字段主体 |
|
||||
|
||||
正式联调时,SuperAgent 不需要传 `hotel_id`。后端通过系统酒店和外部 `source_message_id` 查找唯一 `platform_source_message_inbox.external_message_id`,真实 provider/channel 以 Inbox 入库值为准。如果没有找到,返回 `SOURCE_MESSAGE_NOT_FOUND`;如果同一系统酒店下匹配到多条,返回 `SOURCE_MESSAGE_AMBIGUOUS`。本地旧夹具允许在缺少 `hotel_id` 时使用内部数字 SourceMessage ID,但该兼容路径不作为 SuperAgent 正式契约。
|
||||
正式联调时,SuperAgent 不需要传 `hotel_id`。后端通过系统酒店和外部 `source_message_id` 查找唯一 `platform_source_message_inbox.external_message_id`,真实 provider/channel 以 Inbox 入库值为准。如果没有找到,返回 `SOURCE_MESSAGE_NOT_FOUND`;如果同一系统酒店下匹配到多条,返回 `SOURCE_MESSAGE_AMBIGUOUS`。本节为 REST 历史兼容说明;MCP submit 已不接受顶层 `source_message_id + ai_task_results[]`。
|
||||
|
||||
`informational_message` 结构化任务仅用于历史兼容。新数据如果是纯信息类邮件或无法形成业务素材包,应优先使用 V4 `S10/S99` 来源通知;V3 结构化 `S10/S99` 和下面的 `S000/S999` 文本请求体仅作为旧联调或兼容路径。
|
||||
|
||||
@@ -958,6 +958,8 @@ V3 `adapter_contract_error` 响应中的 `items[]` 不会包含 `order_id` / `ta
|
||||
| `SOURCE_MESSAGE_NOT_FOUND` | 404 | 任务结果通知或会话锚点引用的外部来源消息尚未写入 SourceMessage Inbox |
|
||||
| `SOURCE_MESSAGE_AMBIGUOUS` | 409 | 任务结果通知的外部来源消息在同一系统酒店下匹配到多条 Inbox 记录,后端拒绝随机选择 |
|
||||
| `missing_source_message_id` | 400 | V3 请求缺少 `source_message.source_message_id`,响应体为 typed `infrastructure_input_error` |
|
||||
| `MCP_SUBMIT_V4_REQUIRED` | 200 tool error | MCP `th_hotel_submit_task_results` 收到的不是 M002 V4 根结构,例如旧 V2/V3 payload |
|
||||
| `MCP_SUBMIT_PAYLOAD_INVALID` | 200 tool error | MCP submit 已具备 V4 根字段,但 transport 字段类型、未知字段或 V4 `source_message` / `attachments` 结构无效 |
|
||||
|
||||
## 10. HMAC 上线配置
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ server/src/main/java/cn/nianxx/thhotel/integrations/mcp/superagent/
|
||||
| --- | --- |
|
||||
| `integration-guide.md` | MCP 总体接入说明和调用顺序 |
|
||||
| `tools.md` | 5 个 MCP tools 的工具契约 |
|
||||
| `submit-payload-mapping.md` | `th_hotel_submit_task_results` 的 V3/P0.1 payload adapter、事件索引映射和提交前校验 |
|
||||
| `submit-payload-mapping.md` | `th_hotel_submit_task_results` 的 M002 V4-only payload adapter、schema validator 和提交前校验 |
|
||||
| `inbound-diagnostics.md` | MCP 入站诊断链路,说明如何受控保存原始工具参数、adapter 后 payload 和安全错误摘要 |
|
||||
| `security-policy.md` | 鉴权、权限、正文、附件和日志边界 |
|
||||
| `deployment-guide.md` | 部署参数、环境变量和上线顺序 |
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
|
||||
## 2. 背景
|
||||
|
||||
SuperAgent 通过 MCP `th_hotel_submit_task_results` 提交业务结果时,当前后端会把 MCP
|
||||
`params.arguments` 转换为本系统 `ReservationAiTaskIntakeService` 可接收的业务 payload。
|
||||
SuperAgent 通过 MCP `th_hotel_submit_task_results` 提交业务结果时,当前后端只接受 M002 V4
|
||||
`params.arguments`,并把通过 V4 transport 校验的 payload 交给本系统
|
||||
`ReservationAiTaskIntakeService`。
|
||||
当业务入站失败时,如果只看到最终错误,例如 `SOURCE_MESSAGE_NOT_FOUND` 或
|
||||
`MCP_SUBMIT_PAYLOAD_INVALID`,很难判断问题来自:
|
||||
|
||||
@@ -54,7 +55,7 @@ platform_superagent_mcp_call_diagnostic
|
||||
| `raw_body_json` | 原始 MCP JSON-RPC 请求体,受控诊断字段 |
|
||||
| `arguments_json` | `params.arguments` 原始 JSON,受控诊断字段 |
|
||||
| `adapted_payload_json` | submit adapter 转换后送入业务入站层的 JSON;非 submit 或转换失败为空 |
|
||||
| `mapping_diagnostics_json` | submit adapter 事件索引映射诊断 |
|
||||
| `mapping_diagnostics_json` | submit adapter 诊断;V4-only 模式下通常为空对象,旧 V3 事件索引映射已废弃 |
|
||||
| `response_summary_json` | MCP 响应安全摘要,不保存完整查询结果或正文 |
|
||||
| `call_status` | `RECEIVED`、`SUCCEEDED`、`FAILED` |
|
||||
| `safe_error_code` | 安全错误码,例如 `SOURCE_MESSAGE_NOT_FOUND` |
|
||||
@@ -71,11 +72,15 @@ platform_superagent_mcp_call_diagnostic
|
||||
| body 超限 | 不写诊断表,直接返回原有 body too large 错误 |
|
||||
| JSON 解析失败 | 鉴权通过后写入失败诊断,保存 body hash 和 raw body |
|
||||
| tools/list / query tool | 写入原始请求和参数,只保存响应安全摘要 |
|
||||
| submit adapter 成功 | 补写 `adapted_payload_json` 和 `mapping_diagnostics_json` |
|
||||
| submit adapter 成功 | 补写 `adapted_payload_json` 和 `mapping_diagnostics_json`;V4-only 模式下 `adapted_payload_json` 通常与 `arguments_json` 相同 |
|
||||
| submit adapter 失败 | 保留 `arguments_json`,记录 adapter 安全错误码 |
|
||||
| 业务入站失败 | 保留 `arguments_json` 和可用的 `adapted_payload_json`,记录业务安全错误码 |
|
||||
| 调用成功 | 标记 `SUCCEEDED`,保存响应安全摘要 |
|
||||
|
||||
因此,鉴权通过且 body 未超限的旧 V2 / V3 submit payload 会写入本表,`call_status=FAILED`,
|
||||
`safe_error_code=MCP_SUBMIT_V4_REQUIRED`,`adapted_payload_json` 为空;这表示请求已被 MCP
|
||||
adapter 拒绝,没有进入业务入站 Service。
|
||||
|
||||
## 6. 排障 SQL
|
||||
|
||||
按外部 SourceMessage ID 查询 SuperAgent 传入的原始 MCP 参数:
|
||||
@@ -113,7 +118,7 @@ WHERE id = <diagnostic_id>;
|
||||
## 7. 与现有链路关系
|
||||
|
||||
- REST `POST /api/integrations/superagent/task-results` 仍使用现有 batch / transition 追踪。
|
||||
- MCP `th_hotel_submit_task_results` 会同时拥有 MCP 入站诊断和业务 batch / transition 追踪。
|
||||
- MCP `th_hotel_submit_task_results` 会同时拥有 MCP 入站诊断和业务 batch / transition 追踪;如果返回 `MCP_SUBMIT_V4_REQUIRED`,说明 SuperAgent 仍提交旧 V2/V3 schema,不会进入业务写入 Service。
|
||||
- Debug EML、AgentBus dispatch run 不改原逻辑;如果 SuperAgent 最终通过 MCP 回写,才进入本诊断表。
|
||||
- 第一版不新增前端页面和查询接口;DB 权限和运维访问由部署环境控制。
|
||||
|
||||
|
||||
@@ -130,11 +130,9 @@ REST request
|
||||
5. 必要时调用 `th_hotel_list_message_conversation_tasks` 查询同一邮件会话下已有任务。
|
||||
6. 最终只在明确产出任务结果时调用 `th_hotel_submit_task_results`。
|
||||
|
||||
写入工具里的 `source_message_id` 必须来自 AgentBus payload 的 `source.external_message_id`。SuperAgent 不需要传数据库层 provider/channel;TH Hotel 后端按系统酒店和外部消息 ID 匹配唯一 SourceMessage Inbox,真实 channel 可能是 `OUTLOOK`。
|
||||
写入工具里的 `source_message.source_message_id` 必须来自 AgentBus payload 的 `source.external_message_id`。SuperAgent 不需要传数据库层 `hotel_id` / provider / channel;TH Hotel 后端按系统酒店和外部消息 ID 匹配唯一 SourceMessage Inbox,真实 channel 可能是 `OUTLOOK`。
|
||||
|
||||
M002 V3 后,写入工具优先接收结构化 `S10/S99` 或 `source_message + message_events[]` 业务根。`message_events[].source_event_index` 可以是 SuperAgent 内部事件 ID,例如 `E_CHILD_1`;MCP adapter 会在提交前按数组顺序映射为本系统一基数字索引,并校验跨事件关系是否悬空或重复。详细映射规则见 `submit-payload-mapping.md`。
|
||||
|
||||
V3 业务根写入成功时,MCP tool result 会返回 `mapping_diagnostics.source_event_index_mapping[]`,用于联调排查原始事件 ID 到本系统索引的映射;该字段不是业务任务字段,不会写入 TH Hotel 业务 payload。
|
||||
M002 V4 后,写入工具只接收 V4 包级结构:`route_code + source_message + order_contexts[] + message_events[]`。旧 V2 `ai_task_results[]`、旧 V3 `case_candidates[]` / `unhandled_current_intents[]`、旧 V3 S10/S99 入口通知都会返回 `MCP_SUBMIT_V4_REQUIRED`,不会进入业务写入 Service。详细规则见 `submit-payload-mapping.md`。
|
||||
|
||||
## 9. 当前 checkpoint
|
||||
|
||||
@@ -150,6 +148,6 @@ checkpoint-superagent-mcp-embedded-endpoint
|
||||
- 5 个 MCP tools 均可通过 `tools/list` 发现。
|
||||
- 只读 tool 直接复用现有查询 Service。
|
||||
- 写入 tool 受 `MCP_ENABLE_SUBMIT_TASK_RESULTS` 开关控制。
|
||||
- 写入 tool 已提供 V3/P0.1 submit payload adapter 和提交前 schema validator。
|
||||
- 写入 tool 已提供 M002 V4-only submit payload adapter 和提交前 schema validator。
|
||||
- MCP endpoint 使用 Bearer Token 鉴权。
|
||||
- 文档不包含生产 Secret、真实客户数据、附件 URL 或原始邮件正文。
|
||||
|
||||
@@ -56,13 +56,14 @@ MCP endpoint 与后端业务 Service 同进程,不再通过 HMAC REST 调用
|
||||
| `th_hotel_query_object_detail` | 只读 | 不写订单、不写任务、不写 OPERA |
|
||||
| `th_hotel_list_message_conversation_tasks` | 只读 | 不创建任务、不修改任务 |
|
||||
| `th_hotel_list_message_conversation_messages` | 受控读取 | 读取正文会写后端访问审计 |
|
||||
| `th_hotel_submit_task_results` | 写入 | 写 AI 过渡层、订单、任务和任务卡 |
|
||||
| `th_hotel_submit_task_results` | 写入 | 只接受 M002 V4 payload;写 AI 过渡层、V4 订单任务、V4 任务卡或 V4 来源通知,不写旧 V2/V3 任务 |
|
||||
|
||||
写入工具要求:
|
||||
|
||||
- dev/test 可以用于联调。
|
||||
- prod 必须经过上线审批后启用。
|
||||
- 生产建议保留独立开关,例如 `MCP_ENABLE_SUBMIT_TASK_RESULTS=true`。
|
||||
- 旧 V2/V3 submit payload 必须返回 `MCP_SUBMIT_V4_REQUIRED`,不能进入业务写入 Service。
|
||||
- 日志必须能定位调用方、request id、trace id 和 source message,但不能输出正文和 Secret。
|
||||
|
||||
## 5. 邮件正文和附件边界
|
||||
|
||||
@@ -4,22 +4,24 @@
|
||||
|
||||
| 项目 | 内容 |
|
||||
| --- | --- |
|
||||
| 文档版本 | 0.2 |
|
||||
| 日期 | 2026-07-12 |
|
||||
| 状态 | 已落地第一版 |
|
||||
| 适用范围 | `th_hotel_submit_task_results` 的 V3/P0.1 payload adapter、schema validator 和一次提交规则 |
|
||||
| 文档版本 | 0.3 |
|
||||
| 日期 | 2026-07-22 |
|
||||
| 状态 | 当前有效:M002 V4-only |
|
||||
| 适用范围 | `th_hotel_submit_task_results` 的 M002 V4 payload adapter、schema validator 和一次提交规则 |
|
||||
|
||||
## 2. 核心原则
|
||||
|
||||
`th_hotel_submit_task_results` 接收的是 SuperAgent 已经冻结的业务结果。MCP 层只负责把业务结果转换为本系统可接收的提交 payload,不重新解释业务含义,不调用 Skill,不根据字段名猜测任务类型。
|
||||
`th_hotel_submit_task_results` 只接收 M002 V4 任务结果包。MCP 层只做 transport 形态校验和 V4 根结构防错,不重新解释业务含义、不调用 Skill、不根据字段名猜测任务类型。
|
||||
|
||||
当前开发阶段已确认不维护 V2/V3 submit 兼容。旧 `source_message + message_events[] + case_candidates[]`、旧结构化 `S10/S99`、`source_message_id + ai_task_results[]` 都不会再通过 MCP submit 写入业务层。
|
||||
|
||||
目标链路:
|
||||
|
||||
```text
|
||||
SuperAgent 业务结果
|
||||
SuperAgent M002 V4 业务结果
|
||||
-> MCP Submit Payload Adapter
|
||||
-> MCP Submit Schema Validator
|
||||
-> ReservationAiTaskIntakeService
|
||||
-> ReservationAiTaskIntakeService V4 入站
|
||||
-> V4 order task / V4 task card / V4 source notification
|
||||
-> MCP tool result
|
||||
```
|
||||
|
||||
@@ -34,321 +36,204 @@ server/src/main/java/cn/nianxx/thhotel/integrations/mcp/superagent/service/impl/
|
||||
|
||||
| 形态 | 判断方式 | 处理方式 |
|
||||
| --- | --- | --- |
|
||||
| V3 业务根 | 包含 `message_events` | 校验根结构、source message、event transport 字段和关系索引,再按 `message_events[]` 顺序映射 `source_event_index`;event 业务合法性仍交给业务入站层落 `adapter_contract_error` |
|
||||
| V3 S10/S99 入口通知 | 包含 `route_code` 或入口通知 `result_type` | 校验 S10/S99 根字段和 source message 后透传给业务入站服务 |
|
||||
| V2 兼容任务结果 | 包含 `ai_task_results` | 保留旧 `source_message_id + ai_task_results[]` 兼容路径,并在 MCP 层校验完整 item schema |
|
||||
| V4 普通业务包 | 根字段包含 `route_code=null`、`source_message`、`order_contexts[]`、`message_events[]` | MCP adapter 校验根结构和 V4 `source_message` 后原样透传;业务入站层创建 V4 订单任务和任务卡 |
|
||||
| V4 来源通知包 | 根字段包含 `route_code=S10/S99`、`source_message`、空 `order_contexts[]`、空 `message_events[]` | MCP adapter 校验根结构和 V4 `source_message` 后原样透传;业务入站层创建 V4 来源通知 |
|
||||
|
||||
不再支持的输入形态:
|
||||
|
||||
| 旧形态 | 示例特征 | 当前处理 |
|
||||
| --- | --- | --- |
|
||||
| V3 业务根 | `case_candidates`、`extraction_warnings`、`unhandled_current_intents`、旧 `source_message.from` | 返回 `MCP_SUBMIT_V4_REQUIRED`,不调用业务写入 Service |
|
||||
| V3 S10/S99 | `handler_type`、`result_type=source_message_review_notification`、旧 `source_message.received_at` | 返回 `MCP_SUBMIT_V4_REQUIRED`,不调用业务写入 Service |
|
||||
| V2 任务结果 | 顶层 `source_message_id + ai_task_results[]` | 返回 `MCP_SUBMIT_V4_REQUIRED`,不调用业务写入 Service |
|
||||
|
||||
未知根字段会在 MCP 层被拒绝,错误码为 `MCP_SUBMIT_PAYLOAD_INVALID`。
|
||||
|
||||
`source_message_id` 缺失或整个 `source_message` 缺失属于既有基础设施输入错误,MCP adapter 不改写该错误通道;业务入站服务会返回 `MISSING_SOURCE_MESSAGE_ID`。
|
||||
## 4. V4 根结构
|
||||
|
||||
V3 业务根和 S10/S99 如果携带 MCP schema 中的兼容字段 `hotel_id`、`source_provider`、`source_channel`,adapter 会接受并在转交业务入站层前移除。业务定位仍以系统酒店和 `source_message.source_message_id` 为准。
|
||||
```json
|
||||
{
|
||||
"route_code": null,
|
||||
"source_message": {},
|
||||
"order_contexts": [],
|
||||
"message_events": []
|
||||
}
|
||||
```
|
||||
|
||||
## 4. source_message_id 定义
|
||||
字段规则:
|
||||
|
||||
| 字段 | 规则 |
|
||||
| --- | --- |
|
||||
| `source_message.source_message_id` | V3 必填;必须来自 AgentBus 原始 payload 的外部消息 ID,对应 `platform_source_message_inbox.external_message_id` |
|
||||
| `source_message_id` | V2 兼容必填;同样对应 `platform_source_message_inbox.external_message_id` |
|
||||
| `hotel_id` | SuperAgent 正式提交不需要传;本系统按平台唯一 ACTIVE 酒店解析 |
|
||||
| `route_code` | 必须存在;普通业务为 `null`,来源通知为 `S10` 或 `S99` |
|
||||
| `source_message` | 必须存在;结构见本文第 5 节 |
|
||||
| `order_contexts[]` | 必须存在且为数组;普通业务至少一条,来源通知为空数组 |
|
||||
| `message_events[]` | 必须存在且为数组;普通业务至少一条,来源通知为空数组 |
|
||||
|
||||
`source_message_id` 不是本系统数据库主键,也不是 `platform_source_message_inbox.id`。
|
||||
MCP adapter 不再映射 `source_event_index`。V4 `message_events[]` 的数组顺序就是业务处理顺序;业务层使用数组位置派生一基 event index。
|
||||
|
||||
## 5. source_event_index 映射
|
||||
|
||||
SuperAgent 业务结果中的 `E1`、`E_CHILD_1`、`E_PARENT` 等值只是 Agent 内部事件 ID,不能直接当成本系统的 `source_event_index`。
|
||||
|
||||
MCP adapter 按 `message_events[]` 数组顺序生成一基数字索引:
|
||||
|
||||
| 业务事件 ID | 数组位置 | 本系统 `source_event_index` |
|
||||
| --- | --- | --- |
|
||||
| `E_CHILD_1` | 第 1 个 event | `1` |
|
||||
| `E_CHILD_2` | 第 2 个 event | `2` |
|
||||
| `E_PARENT` | 第 3 个 event | `3` |
|
||||
| `E_TRACE` | 第 4 个 event | `4` |
|
||||
|
||||
映射规则:
|
||||
|
||||
- `message_events[].source_event_index` 输出为数字。
|
||||
- `related_source_event_index` 输出为字符串数字,例如 `"1"`。
|
||||
- `parent_source_event_index` 输出为数字。
|
||||
- `related_source_event_indices[]` 输出为字符串数字数组,保持原顺序。
|
||||
- 悬空引用、重复引用、缺失事件 ID 都在 MCP 层拒绝。
|
||||
- MCP tool result 会返回 `mapping_diagnostics.source_event_index_mapping[]`,记录原始事件 ID 到本系统索引的映射;该诊断不写入 `workflow_reservation_ai_transition.ai_payload_json`。
|
||||
|
||||
## 6. ai_task_results[] 兼容 item schema
|
||||
|
||||
V2 兼容路径仍保留,`ai_task_results[]` item 以 REST 总契约为准。当前 MCP `tools/list` 已暴露 item schema,adapter 也会在提交业务层前校验必填字段、字段类型、允许 `result_type`、未知字段和根级 `extraction_warnings`。
|
||||
|
||||
必填字段:
|
||||
|
||||
- `source_event_index`
|
||||
- `catalog_code`
|
||||
- `skill_id`
|
||||
- `result_type`
|
||||
- `task_type`
|
||||
|
||||
允许的 `result_type`:
|
||||
|
||||
- `normal_task`
|
||||
- `manual_review`
|
||||
- `informational_message`,仅历史兼容
|
||||
|
||||
建议 item 结构:
|
||||
## 5. source_message
|
||||
|
||||
```json
|
||||
{
|
||||
"source_event_index": 1,
|
||||
"catalog_code": "S01",
|
||||
"skill_id": "S01_new_booking_skill",
|
||||
"result_type": "normal_task",
|
||||
"task_type": "New Booking",
|
||||
"task_subtype": "new_fit_reservation",
|
||||
"current_or_history": "current",
|
||||
"case_keys": {
|
||||
"group_code": null,
|
||||
"confirmation_number": null,
|
||||
"reservation_number": null,
|
||||
"block_code": null
|
||||
},
|
||||
"relevant_message_excerpt": "Please create a new booking.",
|
||||
"attachments": [],
|
||||
"file_references": [],
|
||||
"context_used": {},
|
||||
"extracted_fields": {},
|
||||
"manual_review": null,
|
||||
"additional_operations": [],
|
||||
"idempotency_key": null
|
||||
"source_message_id": "mail-20260722-0001",
|
||||
"conversation_id": "thread-001",
|
||||
"subject": "Update Booking",
|
||||
"sender": "agent@example.test",
|
||||
"sent_at": "2026-07-22T08:00:00Z",
|
||||
"body": "Please update the booking.",
|
||||
"body_content_type": "text/plain",
|
||||
"attachments": []
|
||||
}
|
||||
```
|
||||
|
||||
新数据优先使用 V3 业务根或 V3 S10/S99,不建议继续新增 V2 `ai_task_results[]`。
|
||||
字段规则:
|
||||
|
||||
## 7. extraction_warnings 规则
|
||||
|
||||
| 形态 | 规则 |
|
||||
| 字段 | 规则 |
|
||||
| --- | --- |
|
||||
| V3 业务根 | `extraction_warnings` 必须存在且为数组,无警告传 `[]` |
|
||||
| V2 兼容 | `extraction_warnings` 可存在且为数组;缺省由业务层按空数组处理 |
|
||||
| `source_message_id` | 必填非空;必须来自 AgentBus 原始 payload 的外部消息 ID,对应 `platform_source_message_inbox.external_message_id` |
|
||||
| `conversation_id` | 可缺省;出现时必须为字符串或 `null` |
|
||||
| `subject` | 必须出现,可为 `null` |
|
||||
| `sender` | 必须出现,可为 `null` |
|
||||
| `sent_at` | 必须出现,可为 `null`;时间点使用 UTC ISO-8601 |
|
||||
| `body` | 必须出现,可为 `null`;当前邮件原文,不摘要、不翻译、不重排 |
|
||||
| `body_content_type` | 必填;只能为 `text/plain` 或 `text/html` |
|
||||
| `attachments[]` | 必填数组;附件结构见第 6 节 |
|
||||
|
||||
MCP 层不解释 warning 语义,不因为 warning 自动创建任务。
|
||||
旧 V3 的 `from`、`cc`、`received_at`、`source_channel` 不再属于 MCP submit 契约。`hotel_id`、`source_provider`、`source_channel` 也不需要 SuperAgent 传入。
|
||||
|
||||
## 8. 成功示例:Parent Split
|
||||
|
||||
提交给 MCP tool 的业务结果可以使用 Agent 内部事件 ID:
|
||||
## 6. attachments
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "att-1",
|
||||
"name": "payment-slip.jpg",
|
||||
"content_type": "image/jpeg",
|
||||
"url": "https://upstream-storage.example/payment-slip.jpg",
|
||||
"size": 251524
|
||||
}
|
||||
```
|
||||
|
||||
字段规则:
|
||||
|
||||
| 字段 | 规则 |
|
||||
| --- | --- |
|
||||
| `id` | 必填非空;包内稳定附件引用 |
|
||||
| `name` | 必填非空;原始文件名 |
|
||||
| `content_type` | 必填非空;MIME 类型 |
|
||||
| `url` | 必填非空;上游文件 URL,普通 V4 task detail 不直接返回 |
|
||||
| `size` | 可省略或为 `null`;有值时必须是数字 |
|
||||
|
||||
Payment 事件只能通过 `attachment_ids[]` 引用 `source_message.attachments[].id`,不能复制完整附件对象或按文件名猜测。
|
||||
|
||||
## 7. 成功示例
|
||||
|
||||
### 7.1 普通业务
|
||||
|
||||
```json
|
||||
{
|
||||
"route_code": null,
|
||||
"source_message": {
|
||||
"source_message_id": "mail-20260712-parent-split-001",
|
||||
"subject": "Parent split booking request",
|
||||
"from": "agent@example.test",
|
||||
"cc": [],
|
||||
"received_at": "2026-07-12T04:00:00Z",
|
||||
"source_channel": "Email"
|
||||
},
|
||||
"message_events": [
|
||||
{
|
||||
"event_type": "New Booking",
|
||||
"event_role": "travel_agent_request",
|
||||
"source_event_index": "E_CHILD_1",
|
||||
"current_or_history": "current",
|
||||
"case_keys": {
|
||||
"group_code": "CHILD-A",
|
||||
"confirmation_number": null,
|
||||
"reservation_number": null,
|
||||
"block_code": null
|
||||
},
|
||||
"relevant_message_excerpt": "Create child group A.",
|
||||
"attachments": [],
|
||||
"file_references": [],
|
||||
"context_used": {},
|
||||
"extracted_fields": {
|
||||
"booking_object_type": "Group Block"
|
||||
},
|
||||
"manual_review": null
|
||||
},
|
||||
{
|
||||
"event_type": "New Booking",
|
||||
"event_role": "travel_agent_request",
|
||||
"source_event_index": "E_CHILD_2",
|
||||
"current_or_history": "current",
|
||||
"case_keys": {
|
||||
"group_code": "CHILD-B",
|
||||
"confirmation_number": null,
|
||||
"reservation_number": null,
|
||||
"block_code": null
|
||||
},
|
||||
"relevant_message_excerpt": "Create child group B.",
|
||||
"attachments": [],
|
||||
"file_references": [],
|
||||
"context_used": {},
|
||||
"extracted_fields": {
|
||||
"booking_object_type": "Group Block"
|
||||
},
|
||||
"manual_review": null
|
||||
},
|
||||
{
|
||||
"event_type": "Cancel Allotment",
|
||||
"event_role": "travel_agent_request",
|
||||
"source_event_index": "E_PARENT",
|
||||
"current_or_history": "current",
|
||||
"case_keys": {
|
||||
"group_code": "PARENT",
|
||||
"confirmation_number": null,
|
||||
"reservation_number": null,
|
||||
"block_code": "PARENT"
|
||||
},
|
||||
"relevant_message_excerpt": "Release parent after child split.",
|
||||
"attachments": [],
|
||||
"file_references": [],
|
||||
"context_used": {},
|
||||
"related_event_type": "New Booking",
|
||||
"requires_downstream_hard_validation": true,
|
||||
"related_source_event_indices": ["E_CHILD_1", "E_CHILD_2"],
|
||||
"extracted_fields": {
|
||||
"relationship_type": "linked_parent_release_after_child_split",
|
||||
"parent_group_code": "PARENT",
|
||||
"cancel_scope": "entire_allotment_control_block",
|
||||
"parent_release_or_cancel_candidate": true,
|
||||
"release_reason": "parent_to_child_allocation_split",
|
||||
"allocation_split_from_parent": true,
|
||||
"child_group_codes": ["CHILD-A", "CHILD-B"]
|
||||
},
|
||||
"manual_review": null
|
||||
}
|
||||
],
|
||||
"case_candidates": [],
|
||||
"extraction_warnings": [],
|
||||
"unhandled_current_intents": []
|
||||
}
|
||||
```
|
||||
|
||||
MCP adapter 进入业务层前会把父事件关系映射为:
|
||||
|
||||
```json
|
||||
{
|
||||
"source_event_index": 3,
|
||||
"related_source_event_indices": ["1", "2"]
|
||||
}
|
||||
```
|
||||
|
||||
MCP tool result 同时返回非业务诊断:
|
||||
|
||||
```json
|
||||
{
|
||||
"mapping_diagnostics": {
|
||||
"mapping_policy": "message_events_array_order_1_based",
|
||||
"source_event_index_mapping": [
|
||||
"source_message_id": "mail-mcp-v4-business-001",
|
||||
"conversation_id": "thread-mcp-v4-business-001",
|
||||
"subject": "Group booking and payment",
|
||||
"sender": "agent@example.test",
|
||||
"sent_at": "2026-07-18T02:10:00Z",
|
||||
"body": "Please create group GRP-MCP-V4-001 and note payment attached.",
|
||||
"body_content_type": "text/plain",
|
||||
"attachments": [
|
||||
{
|
||||
"original_source_event_index": "E_CHILD_1",
|
||||
"mapped_source_event_index": 1
|
||||
},
|
||||
{
|
||||
"original_source_event_index": "E_CHILD_2",
|
||||
"mapped_source_event_index": 2
|
||||
},
|
||||
{
|
||||
"original_source_event_index": "E_PARENT",
|
||||
"mapped_source_event_index": 3
|
||||
"id": "att-pay-1",
|
||||
"name": "payment-slip.jpg",
|
||||
"content_type": "image/jpeg",
|
||||
"url": "https://upstream-storage.example/payment-slip.jpg",
|
||||
"size": 251524
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 成功示例:跨 Child Trace
|
||||
|
||||
当 Trace 覆盖完整 Parent split 的全部 Child 时,不能只绑定第一个 Child。业务结果应保留全部 Child 引用:
|
||||
|
||||
```json
|
||||
{
|
||||
"event_type": "Trace",
|
||||
"source_event_index": "E_TRACE",
|
||||
"related_source_event_indices": ["E_CHILD_1", "E_CHILD_2"],
|
||||
"extracted_fields": {
|
||||
"trace_subtype": "general_request"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
MCP adapter 会把它映射为:
|
||||
|
||||
```json
|
||||
{
|
||||
"source_event_index": 4,
|
||||
"related_source_event_indices": ["1", "2"]
|
||||
}
|
||||
```
|
||||
|
||||
## 10. 拒绝示例
|
||||
|
||||
未知字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"source_message": {},
|
||||
"message_events": [],
|
||||
"case_candidates": [],
|
||||
"extraction_warnings": [],
|
||||
"unhandled_current_intents": [],
|
||||
"unexpected_root": true
|
||||
}
|
||||
```
|
||||
|
||||
返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"isError": true,
|
||||
"structuredContent": {
|
||||
"success": false,
|
||||
"error": {
|
||||
"code": "MCP_SUBMIT_PAYLOAD_INVALID",
|
||||
"details": {
|
||||
"field": "unexpected_root"
|
||||
},
|
||||
"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-MCP-V4-001"
|
||||
},
|
||||
"arrival_date": "2026-07-26",
|
||||
"departure_date": "2026-07-29",
|
||||
"rate_code": "GRPA2-850UP",
|
||||
"booking_scenario": "STANDARD",
|
||||
"room_items": [
|
||||
{
|
||||
"room_type_code": "RM2",
|
||||
"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-MCP-V4-001"
|
||||
},
|
||||
"attachment_ids": ["att-pay-1"],
|
||||
"manual_review": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
悬空关系:
|
||||
### 7.2 S99 来源通知
|
||||
|
||||
```json
|
||||
{
|
||||
"related_source_event_indices": ["E_CHILD_1", "E_UNKNOWN_CHILD"]
|
||||
"route_code": "S99",
|
||||
"source_message": {
|
||||
"source_message_id": "mail-mcp-v4-s99-001",
|
||||
"conversation_id": "thread-mcp-v4-s99-001",
|
||||
"subject": "Cannot form material package",
|
||||
"sender": "guest@example.test",
|
||||
"sent_at": "2026-07-18T02:10:00Z",
|
||||
"body": "The input does not contain enough business material.",
|
||||
"body_content_type": "text/plain",
|
||||
"attachments": []
|
||||
},
|
||||
"order_contexts": [],
|
||||
"message_events": []
|
||||
}
|
||||
```
|
||||
|
||||
同样返回 `MCP_SUBMIT_PAYLOAD_INVALID`,`details.field=related_source_event_indices`,不会调用业务写入 Service。
|
||||
## 8. 错误码
|
||||
|
||||
## 11. 一次提交和失败不重试
|
||||
| 错误码 | 中文说明 |
|
||||
| --- | --- |
|
||||
| `MCP_SUBMIT_V4_REQUIRED` | MCP submit 收到的不是 M002 V4 根结构,通常是旧 V2/V3 payload |
|
||||
| `MCP_SUBMIT_PAYLOAD_INVALID` | 已具备 V4 根字段,但字段类型、未知字段或 V4 `source_message` / `attachments` 结构不符合 MCP transport 校验 |
|
||||
| `SOURCE_MESSAGE_NOT_FOUND` | V4 `source_message.source_message_id` 无法匹配 SourceMessage Inbox |
|
||||
| `SOURCE_MESSAGE_AMBIGUOUS` | 同一系统酒店下外部 `source_message_id` 匹配多条 Inbox |
|
||||
| `ADAPTER_CONTRACT_ERROR` | V4 包或 event 通过 MCP transport,但不满足业务入站契约,业务层记录 adapter contract error |
|
||||
|
||||
当前 MCP endpoint 与后端业务 Service 同进程:
|
||||
MCP adapter 校验失败时不会调用业务写入 Service,不会创建 AI batch、V4 order task、V4 card、V4 source notification 或旧任务。
|
||||
|
||||
- adapter 校验失败时,不调用 `ReservationAiTaskIntakeService`。
|
||||
- adapter 校验通过后,只调用一次 `ReservationAiTaskIntakeService.accept`。
|
||||
- MCP endpoint 不做自动重试。
|
||||
- 业务结果不会因为 MCP 响应被回写或污染。
|
||||
## 9. 诊断
|
||||
|
||||
当前回归测试:
|
||||
MCP 入站诊断表仍保存:
|
||||
|
||||
```text
|
||||
./mvnw -Dtest=SuperAgentMcpControllerTest,SuperAgentMcpSubmitEnabledControllerTest test
|
||||
```
|
||||
- `arguments_json`:SuperAgent 调用 MCP tool 的原始 arguments。
|
||||
- `adapted_payload_json`:MCP adapter 后交给业务入站层的 payload;V4-only 模式下通常与 arguments 相同。
|
||||
- `mapping_diagnostics_json`:当前 V4-only 模式下为空对象;旧 V3 事件 ID 映射已经废弃。
|
||||
- `safe_error_code` / `safe_error_summary`:安全错误摘要。
|
||||
|
||||
覆盖内容:
|
||||
|
||||
- `tools/list` 暴露 V3 submit schema。
|
||||
- `tools/list` 暴露 V2 `ai_task_results[]` item schema 和 V3 `relationship_type`。
|
||||
- 缺失 `source_message_id` 或整个 `source_message` 保持既有 `MISSING_SOURCE_MESSAGE_ID` 错误。
|
||||
- 未知根字段在业务层前被拒绝。
|
||||
- V2 item 缺必填字段在业务层前被拒绝。
|
||||
- 悬空 `related_source_event_indices` 在业务层前被拒绝。
|
||||
- 重复 `related_source_event_indices` 在业务层前被拒绝。
|
||||
- `E_CHILD_1/E_CHILD_2/E_PARENT` 按数组顺序映射为 `1/2/3`。
|
||||
- 跨 Child Trace 关系映射为完整 `["1", "2"]`,不压缩到第一个 Child。
|
||||
- S10/S99 可通过 MCP 写入工具创建只读来源消息任务。
|
||||
- V3 event 业务契约错误由业务入站层保存为 `adapter_contract_error` transition。
|
||||
- 合法 Parent split 只创建一个 AI batch,并返回 `accepted_count=3`。
|
||||
排障时先对比 `arguments_json` 和 `adapted_payload_json`。如果二者均为 V4 且业务层返回 `ADAPTER_CONTRACT_ERROR`,说明问题在 SuperAgent V4 业务契约内容或业务校验;如果错误为 `MCP_SUBMIT_V4_REQUIRED`,说明 SuperAgent 仍在按旧 schema 输出。
|
||||
|
||||
@@ -84,37 +84,30 @@
|
||||
|
||||
| 用例 ID | 场景 | 输入要点 | 期望结果 |
|
||||
| --- | --- | --- | --- |
|
||||
| MCP-T05-001 | 提交单个 normal task | `ai_task_results` 1 条 | 返回 `accepted_count=1` |
|
||||
| MCP-T05-002 | 提交 manual review | `result_type=manual_review` | 写入人工复核任务 |
|
||||
| MCP-T05-003 | 提交 informational message | `result_type=informational_message` | 写入提示类信息 |
|
||||
| MCP-T05-004 | source message 不存在 | 不存在的外部 `source_message_id` | 返回 `SOURCE_MESSAGE_NOT_FOUND` |
|
||||
| MCP-T05-005 | 缺省 hotel id | 不传 `hotel_id`,source message 属于系统酒店 | 后端按系统唯一 ACTIVE 酒店写入成功 |
|
||||
| MCP-T05-006 | 重复提交同一幂等任务 | 使用相同幂等信息 | 不重复创建业务任务 |
|
||||
| MCP-T05-007 | hotel id 不一致 | 显式传非系统酒店 `hotel_id` | 返回 `HOTEL_ID_MISMATCH` |
|
||||
| MCP-T05-008 | source message 入库渠道为 OUTLOOK | 不传 `source_channel`,只传外部 `source_message_id` | 后端按真实 Inbox 渠道写入成功 |
|
||||
| MCP-T05-009 | source message 多渠道重复 | 同一酒店存在相同外部 `source_message_id` 的多条 Inbox | 返回 `SOURCE_MESSAGE_AMBIGUOUS` |
|
||||
| MCP-T05-010 | V3 Parent split 使用 Agent 内部事件 ID | `message_events[].source_event_index=E_CHILD_1/E_CHILD_2/E_PARENT` | MCP adapter 按数组顺序映射为 `1/2/3`,返回 `accepted_count=3` |
|
||||
| MCP-T05-011 | V3 缺失 source message id | `source_message.source_message_id` 缺失 | 返回既有 `MISSING_SOURCE_MESSAGE_ID` typed infrastructure error |
|
||||
| MCP-T05-012 | V3 多事件关系悬空 | `related_source_event_indices` 引用不存在的事件 ID | 返回 `MCP_SUBMIT_PAYLOAD_INVALID`,不写 AI batch、订单或任务 |
|
||||
| MCP-T05-013 | V3 多事件关系重复 | `related_source_event_indices=["E_CHILD_1","E_CHILD_1"]` | 返回 `MCP_SUBMIT_PAYLOAD_INVALID`,不写 AI batch、订单或任务 |
|
||||
| MCP-T05-014 | V3 根节点未知字段 | 根节点存在 `unexpected_root` | 返回 `MCP_SUBMIT_PAYLOAD_INVALID`,不调用业务写入 Service |
|
||||
| MCP-T05-015 | V3 跨 Child Trace | Trace event 关联全部 Child event | `related_source_event_indices[]` 保留全量关系并映射为真实索引,不压缩到第一个 Child |
|
||||
| MCP-T05-016 | V3 缺失整个 source_message | 业务根或 S10/S99 没有 `source_message` | 返回既有 `MISSING_SOURCE_MESSAGE_ID` typed infrastructure error |
|
||||
| MCP-T05-017 | V2 item 缺必填字段 | `ai_task_results[]` item 缺 `task_type` 等必填字段 | 返回 `MCP_SUBMIT_PAYLOAD_INVALID`,不调用业务写入 Service |
|
||||
| MCP-T05-018 | V3 event 业务契约错误 | event_type unsupported 但 transport 字段完整 | MCP adapter 不整批拒绝,业务入站层保存 `adapter_contract_error` transition |
|
||||
| MCP-T05-019 | V3 S10 入口通知 | `route_code=S10` | 通过 MCP 写入只读 `SOURCE_MESSAGE_ONLY` 任务 |
|
||||
| MCP-T05-020 | V3 S99 入口通知 | `route_code=S99` 且 `manual_review` 完整 | 通过 MCP 写入只读 `SOURCE_MESSAGE_ONLY` 任务 |
|
||||
| MCP-T05-001 | V4 普通业务包 | `route_code=null + source_message + order_contexts[] + message_events[]` | 返回 `accepted_count`;只创建 V4 order task / cards,不创建旧 `workflow_reservation_task` |
|
||||
| MCP-T05-001A | V4 普通业务包缺省 conversation_id | `source_message` 不传 `conversation_id` | 返回 `accepted_count`;仍只创建 V4 order task / cards |
|
||||
| MCP-T05-002 | V4 type-known manual review | V4 `message_events[].manual_review=true`,业务字段可由 V4 入站识别 | 创建 V4 `REVIEW_REQUIRED` 卡,后续通过 V4 复核接口解阻 |
|
||||
| MCP-T05-003 | V4 S10 来源通知 | `route_code=S10`,`order_contexts=[]`,`message_events=[]` | 创建 V4 source notification,不创建订单和旧任务 |
|
||||
| MCP-T05-004 | V4 S99 来源通知 | `route_code=S99`,`order_contexts=[]`,`message_events=[]` | 创建 V4 source notification,不创建订单和旧任务 |
|
||||
| MCP-T05-005 | source message 不存在 | V4 `source_message.source_message_id` 无法匹配 Inbox | 返回 `SOURCE_MESSAGE_NOT_FOUND` |
|
||||
| MCP-T05-006 | 缺省 hotel id | 不传 `hotel_id`,source message 属于系统酒店 | 后端按系统唯一 ACTIVE 酒店写入成功 |
|
||||
| MCP-T05-007 | source message 入库渠道为 OUTLOOK | 不传 `source_channel`,只传 V4 `source_message.source_message_id` | 后端按真实 Inbox 渠道写入成功 |
|
||||
| MCP-T05-008 | source message 多渠道重复 | 同一酒店存在相同外部 `source_message_id` 的多条 Inbox | 返回 `SOURCE_MESSAGE_AMBIGUOUS` |
|
||||
| MCP-T05-009 | V4 根结构缺字段 | 缺少 `order_contexts` 或 `message_events` | 返回 `MCP_SUBMIT_V4_REQUIRED`,不调用业务写入 Service |
|
||||
| MCP-T05-010 | V4 source_message 字段错误 | 使用旧 `from/received_at/source_channel` 或缺少 `sender/body_content_type` | 返回 `MCP_SUBMIT_PAYLOAD_INVALID`,不调用业务写入 Service |
|
||||
| MCP-T05-011 | V4 附件字段错误 | 附件缺少 `id/name/content_type/url` 或 `size` 不是数字 | 返回 `MCP_SUBMIT_PAYLOAD_INVALID`,不调用业务写入 Service |
|
||||
| MCP-T05-012 | V4 event 业务契约错误 | event_type unsupported 或 Payment `attachment_ids[]` 不匹配同包附件 | 由业务入站层保存 `adapter_contract_error`,不创建用户可处理卡 |
|
||||
| MCP-T05-013 | 旧 V3 业务根 | 含 `case_candidates` / `unhandled_current_intents` | 返回 `MCP_SUBMIT_V4_REQUIRED`,不调用业务写入 Service |
|
||||
| MCP-T05-014 | 旧 V3 S10/S99 | 含 `handler_type` / `result_type=source_message_review_notification` | 返回 `MCP_SUBMIT_V4_REQUIRED`,不调用业务写入 Service |
|
||||
| MCP-T05-015 | 旧 V2 task results | 顶层 `source_message_id + ai_task_results[]` | 返回 `MCP_SUBMIT_V4_REQUIRED`,不调用业务写入 Service |
|
||||
|
||||
写入验证:
|
||||
|
||||
- `ai_task_results[]` 顺序不能被 MCP endpoint 改变。
|
||||
- V3 `message_events[]` 顺序是 `source_event_index` 的唯一基准,MCP endpoint 不能重排。
|
||||
- `E1/E2/E_PARENT` 等 Agent 内部事件 ID 只能由 MCP adapter 转换,不能作为本系统最终 `source_event_index`。
|
||||
- V4 `message_events[]` 顺序不能被 MCP endpoint 改变;业务层按数组顺序派生 event index。
|
||||
- MCP endpoint 不能在日志输出完整 `extracted_fields` 中的敏感内容。
|
||||
- 失败响应应保留后端错误码和 message。
|
||||
- MCP adapter 校验失败时不进入业务写入 Service,且不自动重试。
|
||||
- V3 成功响应返回 `mapping_diagnostics.source_event_index_mapping[]`,但 AI transition 业务 payload 不包含该诊断字段。
|
||||
- V3 `relationship_type` 可在 event 根节点透传,也可在 `extracted_fields` 中作为业务关系字段;MCP adapter 不据此派生业务含义。
|
||||
- V4-only 模式下 `mapping_diagnostics_json` 为空对象;旧 V3 事件 ID 映射已经废弃。
|
||||
|
||||
## 9. MCP 鉴权和开关测试
|
||||
|
||||
@@ -143,9 +136,9 @@
|
||||
- 5 个工具正常成功调用。
|
||||
- 查询接口错误 envelope 不丢失。
|
||||
- 任务结果写入成功和幂等重放正常。
|
||||
- V3 submit payload adapter 的事件索引映射、mapping 诊断、悬空关系拒绝、重复关系拒绝和未知字段拒绝正常。
|
||||
- V2 `ai_task_results[]` item schema 和 adapter 校验正常。
|
||||
- S10/S99 结构化入口通知可通过 MCP 写入工具。
|
||||
- V4 submit payload adapter 的根结构、source_message、attachments 校验正常。
|
||||
- 旧 V2/V3 submit payload 统一返回 `MCP_SUBMIT_V4_REQUIRED`,不会进入业务写入 Service。
|
||||
- V4 S10/S99 来源通知可通过 MCP 写入工具。
|
||||
- provider/channel 隔离正常。
|
||||
- 受控正文不返回附件 URL。
|
||||
- MCP auth 失败不进入业务 Service。
|
||||
|
||||
@@ -330,37 +330,33 @@ POST /api/ai-query/v1/message-conversation/messages
|
||||
|
||||
### 7.1 用途
|
||||
|
||||
提交 SuperAgent 对单封外部来源消息的 AI 任务识别结果。该工具会写入 AI 过渡层、订单、任务和任务卡。
|
||||
提交 SuperAgent 对单封外部来源消息的 M002 V4 任务识别结果。该工具会写入 AI 过渡层、V4 订单任务、V4 任务卡或 V4 来源通知。
|
||||
|
||||
### 7.2 何时使用
|
||||
|
||||
- SuperAgent 已完成当前邮件的最终任务拆分。
|
||||
- 已确认外部 `source_message_id` 来自 AgentBus payload;`hotel_id` 由 TH Hotel 后端解析。
|
||||
- 不需要为写入工具传数据库层 `source_provider` / `source_channel`;后端会按系统酒店和外部消息 ID 匹配真实 Inbox 记录。
|
||||
- 已确认 `source_message.source_message_id` 来自 AgentBus payload 的外部消息 ID;`hotel_id` 由 TH Hotel 后端解析。
|
||||
- 不需要为写入工具传数据库层 `hotel_id` / `source_provider` / `source_channel`;后端会按系统酒店和外部消息 ID 匹配真实 Inbox 记录。
|
||||
- 需要把 AI 任务结果交给 TH Hotel 后端进入人工确认流程。
|
||||
|
||||
### 7.3 不应使用
|
||||
|
||||
- 不应在试探、草稿、未完成推理阶段调用。
|
||||
- 不应把历史邮件中的外部来源消息 ID 当作当前邮件 ID 提交。
|
||||
- 不应在缺少 `source_message_id` 时调用;`hotel_id` 不需要 SuperAgent 提供。
|
||||
- 不应在缺少 V4 `source_message.source_message_id` 时调用。
|
||||
- 不应继续提交 V2 `ai_task_results[]` 或 V3 `case_candidates` / `unhandled_current_intents` 结构。
|
||||
|
||||
### 7.4 输入 Schema
|
||||
|
||||
当前 MCP tool 已支持三种输入形态,真实机器可读 schema 以 `/mcp` 的 `tools/list` 返回为准:
|
||||
|
||||
1. V3 业务根:`source_message + message_events[]`。
|
||||
2. V3 S10/S99 入口通知:`source_message + route_code`。
|
||||
3. V2 兼容任务结果:`source_message_id + ai_task_results[]`。
|
||||
|
||||
MCP 层会先调用 `SuperAgentMcpSubmitPayloadAdapter` 做提交前校验和事件索引映射。`E1`、`E_CHILD_1`、`E_PARENT` 等 Agent 内部事件 ID 不会直接进入业务层;adapter 会按 `message_events[]` 顺序生成本系统一基数字 `source_event_index`,并同步映射 `related_source_event_index`、`parent_source_event_index` 和 `related_source_event_indices[]`。
|
||||
当前 MCP tool 只支持 M002 V4 包级结构,真实机器可读 schema 以 `/mcp` 的 `tools/list` 返回为准。
|
||||
|
||||
补充规则:
|
||||
|
||||
- V3 业务根或 S10/S99 如果携带 `hotel_id`、`source_provider`、`source_channel`,MCP adapter 会接受这些兼容字段,但转交业务入站层前会移除;业务定位仍以系统酒店和外部 `source_message_id` 为准。
|
||||
- 缺失 `source_message.source_message_id` 或整个 `source_message` 时,MCP adapter 不改写错误,业务入站层返回 `MISSING_SOURCE_MESSAGE_ID`。
|
||||
- V3 event 业务合法性问题,例如 unsupported `event_type`、不完整 `case_keys`、不完整 `manual_review`,由业务入站层保存为 `adapter_contract_error` transition;MCP adapter 只拦 transport 必需问题,包括未知字段、`source_event_index` 缺失/重复、关系悬空/重复。
|
||||
- V2 `ai_task_results[]` item 已在 MCP schema 和 adapter 中完整校验,必填字段为 `source_event_index`、`catalog_code`、`skill_id`、`result_type`、`task_type`。
|
||||
- V4 普通业务包:`route_code=null + source_message + order_contexts[] + message_events[]`。
|
||||
- V4 来源通知包:`route_code=S10/S99 + source_message + order_contexts=[] + message_events=[]`。
|
||||
- MCP adapter 只校验 V4 根结构和 V4 `source_message` / `attachments` transport 形态;event 业务契约问题由业务入站层记录 `adapter_contract_error`。
|
||||
- 旧 V2/V3 payload 返回 `MCP_SUBMIT_V4_REQUIRED`,不会调用业务写入 Service。
|
||||
- V4 根字段外的 `hotel_id`、`source_provider`、`source_channel`、`handler_type`、`result_type`、`ai_task_results`、`case_candidates` 等字段都会被拒绝。
|
||||
|
||||
下面 JSON 是关键结构节选;不要手工复制为最终 schema,联调时应以 `tools/list` 实时返回为准。
|
||||
|
||||
@@ -369,158 +365,122 @@ MCP 层会先调用 `SuperAgentMcpSubmitPayloadAdapter` 做提交前校验和事
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"hotel_id": {
|
||||
"route_code": {
|
||||
"type": ["string", "null"],
|
||||
"description": "可选酒店上下文 ID;默认由 TH Hotel 后端解析"
|
||||
},
|
||||
"source_provider": {
|
||||
"type": ["string", "null"],
|
||||
"description": "兼容字段;写入工具通常不需要传,后端写入定位不使用该字段"
|
||||
},
|
||||
"source_channel": {
|
||||
"type": ["string", "null"],
|
||||
"description": "兼容字段;写入工具通常不需要传,后端写入定位不使用该字段,AgentBus 实际入库渠道可能是 OUTLOOK"
|
||||
"description": "M002 V4 包级路由;普通业务必须为 null,来源通知为 S10 或 S99"
|
||||
},
|
||||
"source_message": {
|
||||
"type": "object",
|
||||
"description": "V3 来源邮件元数据;source_message_id 对应 AgentBus source.external_message_id",
|
||||
"properties": {
|
||||
"source_message_id": {
|
||||
"type": "string"
|
||||
"source_message_id": { "type": "string" },
|
||||
"conversation_id": { "type": ["string", "null"] },
|
||||
"subject": { "type": ["string", "null"] },
|
||||
"sender": { "type": ["string", "null"] },
|
||||
"sent_at": { "type": ["string", "null"] },
|
||||
"body": { "type": ["string", "null"] },
|
||||
"body_content_type": {
|
||||
"type": "string",
|
||||
"enum": ["text/plain", "text/html"]
|
||||
},
|
||||
"subject": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"from": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"cc": {
|
||||
"attachments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["id", "name", "content_type", "url"],
|
||||
"properties": {
|
||||
"id": { "type": "string" },
|
||||
"name": { "type": "string" },
|
||||
"content_type": { "type": "string" },
|
||||
"url": { "type": "string" },
|
||||
"size": { "type": ["number", "null"] }
|
||||
}
|
||||
}
|
||||
},
|
||||
"received_at": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"source_channel": {
|
||||
"type": "string",
|
||||
"enum": ["Email"]
|
||||
}
|
||||
},
|
||||
"required": ["source_message_id", "subject", "from", "cc", "received_at", "source_channel"]
|
||||
"required": ["source_message_id", "subject", "sender", "sent_at", "body", "body_content_type", "attachments"]
|
||||
},
|
||||
"route_code": {
|
||||
"type": ["string", "null"],
|
||||
"description": "V3 S10/S99 入口通知路由码"
|
||||
},
|
||||
"handler_type": {
|
||||
"type": ["string", "null"],
|
||||
"description": "V3 Main Agent 输出处理器类型"
|
||||
},
|
||||
"result_type": {
|
||||
"type": ["string", "null"],
|
||||
"description": "V3 入口通知或 V2 任务结果类型"
|
||||
},
|
||||
"current_or_history": {
|
||||
"type": ["string", "null"],
|
||||
"description": "V3 current/history 标记"
|
||||
},
|
||||
"agent_assessment": {
|
||||
"type": "object",
|
||||
"description": "V3 S10/S99 入口判断摘要"
|
||||
},
|
||||
"notification": {
|
||||
"type": "object",
|
||||
"description": "V3 S10/S99 通知展示信息"
|
||||
},
|
||||
"manual_review": {
|
||||
"type": ["object", "null"],
|
||||
"description": "V3 人工复核对象;S10 可为空,S99 必须完整"
|
||||
},
|
||||
"message_events": {
|
||||
"order_contexts": {
|
||||
"type": "array",
|
||||
"description": "V3 业务事件数组;MCP Adapter 会按数组顺序生成一基 source_event_index",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"case_candidates": {
|
||||
"type": "array",
|
||||
"description": "V3 订单候选数组,无候选传空数组",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"unhandled_current_intents": {
|
||||
"type": "array",
|
||||
"description": "V3 未覆盖当前意图数组,无意图传空数组",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"source_message_id": {
|
||||
"type": "string",
|
||||
"description": "V2 兼容字段:外部来源消息 ID,对应 AgentBus source.external_message_id"
|
||||
},
|
||||
"ai_task_results": {
|
||||
"type": "array",
|
||||
"description": "V2 兼容字段:AI 拆分出的任务结果,必须保留数组顺序",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["source_event_index", "catalog_code", "skill_id", "result_type", "task_type"],
|
||||
"required": ["order_ref", "basic_information"],
|
||||
"properties": {
|
||||
"source_event_index": {
|
||||
"type": ["integer", "string"]
|
||||
},
|
||||
"catalog_code": {
|
||||
"type": "string"
|
||||
},
|
||||
"skill_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"result_type": {
|
||||
"type": "string",
|
||||
"enum": ["normal_task", "manual_review", "informational_message"]
|
||||
},
|
||||
"task_type": {
|
||||
"type": "string"
|
||||
"order_ref": { "type": "string" },
|
||||
"basic_information": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["account_code", "manual_review"],
|
||||
"properties": {
|
||||
"account_code": { "type": ["string", "null"] },
|
||||
"manual_review": { "type": ["boolean", "null"] }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"extraction_warnings": {
|
||||
"message_events": {
|
||||
"type": "array",
|
||||
"description": "AI 抽取警告;V3/V2 都允许,缺省按空数组处理",
|
||||
"items": {
|
||||
"type": "object"
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"required": ["order_ref", "event_type", "target_order", "manual_review"],
|
||||
"properties": {
|
||||
"order_ref": { "type": "string" },
|
||||
"event_type": {
|
||||
"type": "string",
|
||||
"enum": ["NEW_BOOKING", "UPDATE_BOOKING", "CANCEL_BOOKING", "TRACE_RESERVATION_NOTES", "ROOMING_LIST", "PAYMENT"]
|
||||
},
|
||||
"target_order": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["booking_type", "locator_type", "locator_value"],
|
||||
"properties": {
|
||||
"booking_type": { "type": ["string", "null"] },
|
||||
"locator_type": { "type": ["string", "null"] },
|
||||
"locator_value": { "type": ["string", "null"] }
|
||||
}
|
||||
},
|
||||
"manual_review": {
|
||||
"type": ["boolean", "null"]
|
||||
},
|
||||
"arrival_date": { "type": ["string", "null"] },
|
||||
"departure_date": { "type": ["string", "null"] },
|
||||
"rate_code": { "type": ["string", "null"] },
|
||||
"booking_scenario": { "type": ["string", "null"] },
|
||||
"guest_name": { "type": ["string", "null"] },
|
||||
"room_items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["room_type_code", "room_count"],
|
||||
"properties": {
|
||||
"room_type_code": { "type": ["string", "null"] },
|
||||
"room_count": { "type": ["integer", "null"] }
|
||||
}
|
||||
}
|
||||
},
|
||||
"after": { "type": "object" },
|
||||
"trace_items": { "type": "array" },
|
||||
"attachment_ids": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
"oneOf": [
|
||||
{
|
||||
"required": ["source_message", "message_events", "case_candidates", "extraction_warnings", "unhandled_current_intents"]
|
||||
},
|
||||
{
|
||||
"required": ["source_message", "route_code", "handler_type", "result_type", "current_or_history", "agent_assessment", "notification", "manual_review"]
|
||||
},
|
||||
{
|
||||
"required": ["source_message_id", "ai_task_results"]
|
||||
}
|
||||
]
|
||||
"required": ["route_code", "source_message", "order_contexts", "message_events"]
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- V3 业务根字段、S10/S99 字段和 V2 `ai_task_results[]` item 完整语义以 `superagent-api-contract.md` 第 8 节为准。
|
||||
- BusinessResult 到 MCP payload 的稳定映射、`source_event_index` 正式定义、跨 Child Trace 示例和拒绝示例见 `submit-payload-mapping.md`。
|
||||
- MCP endpoint 不应重排 V2 `ai_task_results[]`,也不应重排 V3 `message_events[]`。
|
||||
- `source_message_id` 必须是 AgentBus payload 的 `source.external_message_id`,不是内部 `platform_source_message_inbox.id`;写入工具不要求 SuperAgent 知道 Inbox 的真实 channel。
|
||||
- V4 字段完整语义以 `superagent-api-contract.md` 第 8 节和 `M002-v4-agent-callback-field-contract.md` 为准。
|
||||
- `source_message.source_message_id` 必须是 AgentBus payload 的 `source.external_message_id`,不是内部 `platform_source_message_inbox.id`;写入工具不要求 SuperAgent 知道 Inbox 的真实 channel。
|
||||
- 同一系统酒店下如果外部 `source_message_id` 匹配多条 Inbox,业务 Service 返回 `SOURCE_MESSAGE_AMBIGUOUS`,MCP tool result 应原样保留该错误码和 message。
|
||||
- MCP adapter 校验失败时返回 `MCP_SUBMIT_PAYLOAD_INVALID`,不会调用业务写入 Service,也不会自动重试。
|
||||
- 旧 V2/V3 payload 会返回 `MCP_SUBMIT_V4_REQUIRED`;V4 transport 校验失败返回 `MCP_SUBMIT_PAYLOAD_INVALID`。两者都不会调用业务写入 Service,也不会自动重试。
|
||||
|
||||
### 7.5 输出
|
||||
|
||||
@@ -537,9 +497,8 @@ POST /api/integrations/superagent/task-results
|
||||
- `accepted_count`:接收数量。
|
||||
- `items[].ai_transition_id`:AI 过渡层 ID。
|
||||
- `items[].order_id`:订单 ID。
|
||||
- `items[].task_id`:任务 ID。
|
||||
- `items[].task_status`:任务状态。
|
||||
- `mapping_diagnostics`:仅 MCP 写入工具在 V3 业务根映射时返回,记录 Agent 原始事件 ID 到本系统一基索引的映射;不写入业务 JSON。
|
||||
- `items[].task_id`:V4 主线不再返回旧任务 ID,通常为 `null`。
|
||||
- `items[].task_status`:V4 主线不再返回旧任务状态,通常为 `null`。
|
||||
|
||||
完整字段以 `superagent-api-contract.md` 第 8 节为准。
|
||||
|
||||
@@ -574,5 +533,6 @@ MCP 层新增错误建议:
|
||||
| `MCP_REQUEST_BODY_TOO_LARGE` | MCP 请求体超过 10MB 默认限制或环境配置限制 |
|
||||
| `MCP_METHOD_NOT_FOUND` | MCP 方法不存在 |
|
||||
| `MCP_TOOL_NOT_FOUND` | MCP 工具不存在 |
|
||||
| `MCP_SUBMIT_V4_REQUIRED` | 写入工具收到的不是 M002 V4 根结构,例如旧 V2/V3 payload |
|
||||
| `MCP_SUBMIT_PAYLOAD_INVALID` | 写入工具 payload 未通过 MCP adapter 提交前校验 |
|
||||
| `MCP_INTERNAL_ERROR` | MCP endpoint 内部异常 |
|
||||
|
||||
Reference in New Issue
Block a user