Files
th-hotel-simple/docs/project/integrations/superagent-api-contract.md
2026-07-12 01:27:42 +08:00

33 KiB
Raw Blame History

TH Hotel SuperAgent API 对接契约

文档信息

项目 内容
文档版本 0.7
日期 2026-07-11
状态 当前代码契约已支持 V2 ai_task_results[] 兼容、结构化 S10/S99、V3 业务根基础解析、旧 S000/S999 兼容和单酒店 hotel_id 后端解析
适用范围 SuperAgent 调用本系统查询上下文、查询邮件会话、提交 AI 任务结果
主要读者 SuperAgent 对接方、后端、测试、运维

联调参数区

以下参数供 SuperAgent 联调时手动修改。该区块只用于 dev/test 联调,不作为生产 Secret 管理方式。

参数 当前联调值 中文说明
TH_HOTEL_API_BASE_URL http://8.138.234.141:18087 本系统后端基础地址;本地联调用 8080部署环境改为实际网关或服务地址。
SYSTEM_HOTEL 后端平台酒店表唯一 ACTIVE 酒店 SuperAgent 不需要配置或传入 hotel_id;单酒店阶段由 TH Hotel 后端从 platform_hotel 解析。
SUPERAGENT_CLIENT_ID superagent-debug SuperAgent 调用方 ID对应 Header X-TH-Hotel-SuperAgent-Client-Id
SUPERAGENT_HMAC_SECRET th-hotel-superagent-debug-20260709-change-before-prod dev/test 联调临时 HMAC 密钥;生产上线前必须更换为新的高强度随机密钥。

生产注意:

  • 生产环境必须更换 SUPERAGENT_HMAC_SECRET,不得继续使用上述联调临时密钥。
  • 生产密钥不得写入 SuperAgent skill 文件、仓库文档、前端代码、镜像或普通日志,只能通过部署 Secret / 环境变量注入。
  • 本系统后端按 profile 优先读取环境专属密钥dev 使用 SUPERAGENT_DEV_TASK_RESULT_HMAC_SECRETtest 使用 SUPERAGENT_TEST_TASK_RESULT_HMAC_SECRETprod 使用 SUPERAGENT_PROD_TASK_RESULT_HMAC_SECRET;旧通用变量 SUPERAGENT_TASK_RESULT_HMAC_SECRET 仅作为兼容兜底。当前查询接口和任务结果通知接口共用同一个 HMAC secret。

1. 基础约定

请求地址先使用占位符:

{TH_HOTEL_API_BASE_URL}

上线或联调时由环境提供实际域名,例如 UAT、生产内网域名或 API Gateway 地址。本文所有接口均为 SuperAgent 到本系统的服务到服务调用,不给前端直接调用。

2. 通用 HMAC 鉴权

查询接口和任务结果通知接口使用同一套 HMAC-SHA256 规则。

2.1 通用 Header

Header 是否必填 中文说明
Content-Type 查询接口固定 application/json;任务结果通知接口支持 application/jsontext/plain
X-TH-Hotel-SuperAgent-Client-Id SuperAgent 调用方客户端 ID
X-TH-Hotel-SuperAgent-Timestamp UTC ISO-8601 时间,例如 2026-07-08T01:30:00Z
X-TH-Hotel-SuperAgent-Nonce 每次请求唯一随机值,用于防重放
X-TH-Hotel-SuperAgent-Signature HMAC 签名,格式 sha256=<lowercase-hex>
X-TH-Hotel-Request-Id 调用方请求 ID用于日志串联
X-TH-Hotel-AI-Trace-Id AI 运行链路 ID查询接口会原样带回 trace_id

2.2 签名串

签名串使用接口 path不包含域名、query string 或 fragment。

POST
<request_path>
<X-TH-Hotel-SuperAgent-Timestamp>
<X-TH-Hotel-SuperAgent-Nonce>
<X-TH-Hotel-SuperAgent-Client-Id>
<lowercase-hex-sha256-of-raw-body>

签名算法:

signature = HMAC_SHA256(SUPERAGENT_HMAC_SECRET, canonical_string)

Header 写法:

X-TH-Hotel-SuperAgent-Signature: sha256=<lowercase-hex-signature>

2.3 服务端校验顺序

  1. 校验请求体大小。
  2. 查询接口校验 Content-Type 是否为 application/json;任务结果通知接口校验是否为 application/jsontext/plain,不支持的媒体类型不消耗 nonce。
  3. 校验 HMAC 相关 Header 是否存在。
  4. 校验 timestamp 是否在允许时间窗口内。
  5. 计算原始请求体 SHA-256。
  6. 使用共享 secret 重新计算 HMAC。
  7. 常量时间比较签名。
  8. 校验并记录 client_id + nonce,防止重放。
  9. 鉴权和协议校验通过后再解析业务 JSON、结构化 S10/S99、V3 业务根或 S000/S999 文本结果。

3. SourceMessage ID 口径

本系统存在两个容易混淆的 ID

名称 中文说明 使用位置
外部来源消息 ID AgentBus 邮件 payload 中的 source.external_message_idSuperAgent / 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_idsource_event_index,第一版后端会接收但忽略,不校验它们的格式,也不把它们作为查询边界。

查询接口 3、4 面向已经入库的邮件会话:缺省酒店由后端解析,external_conversation_id 最终仍按 hotel_id + source_provider + source_channel + external_conversation_id 查询;source_message_id 表示外部来源消息 ID可作为锚点反查该邮件所属会话。

3.1 M002 V3 迁移提醒

2026-07-11 起,项目需求基线已确认采用 docs/project/requirements/M002-order-task-workflow-v3.md

  • 新入口结果将从旧文本 S000/S999 迁移为结构化 S10/S99
  • 新业务输出将从旧 ai_task_results[] 迁移为 source_message + message_events[] + case_candidates[] + extraction_warnings[] + unhandled_current_intents[]
  • 后端会完整保存 AI 三元组、route_code 和系统处理分类;S10/S99 仍以只读源邮件通知卡展示,任务列表可见,订单列表不可见。
  • S000/S999 数据继续兼容展示,语义上分别映射到 S10/S99

当前后端已完成 M002 V3 CP1-CP6

  • 已建立 42 条 P0 路由枚举 / 稳定配置。
  • 已支持结构化 S10/S99 入站,创建只读 SOURCE_MESSAGE_ONLY 任务。
  • 已支持 V3 业务根 source_message + message_events[] 的基础解析;可派生到现有任务模型的 event 会创建业务任务,无法派生、显式契约错误或基础 manual_review / parent split 结构不完整的 event 只落 adapter_contract_error transition不创建业务任务。
  • 已支持 unhandled_current_intents[] 最小落库:只写 UNHANDLED_CURRENT_INTENT transition不创建业务任务也不按 adapter 契约错误返回。
  • 已在 workflow_reservation_ai_transition 保存 route_codesystem_process_categoryadapter_error_codeadapter_error_message
  • 已支持 type-known manual review 同卡解阻、当前订单归属确认、P0 fixtures 回归测试和 V3 typed infrastructure_input_error 响应。

尚未完成:真实 OPERA / OHIP、普通任务切换订单、字段矩阵从当前扁平结构整体迁移到 0711 P0 新结构。

4. 接口 1查询订单上下文

4.1 请求

项目 内容
Method POST
URL {TH_HOTEL_API_BASE_URL}/api/ai-query/v1/case-context
request_path /api/ai-query/v1/case-context
Content-Type application/json
业务动作 只读查询,不创建任务、不修改订单、不写 OPERA

4.2 请求体

{
  "group_code": "GRP-001",
  "confirmation_number": null,
  "reservation_no": null,
  "object_type_hint": "group_block",
  "target_key_source": "body_current",
  "body_thread_used_only_as_evidence": false
}

字段说明:

字段 是否必填 中文说明
hotel_id 酒店上下文 IDSuperAgent 默认不传,后端按平台酒店表唯一 ACTIVE 酒店解析。若兼容旧契约传入,单酒店阶段必须与系统酒店一致。
group_code 条件必填 Group / Allotment 查询 key
confirmation_number 条件必填 FIT Confirmation Number 查询 key
reservation_no 条件必填 OPERA reservation no当前系统无可靠表源只传该字段时会返回人工复核原因
object_type_hint 调用方推测的对象类型,只作为提示
target_key_source key 来源,例如 body_currentbody_thread_evidence
body_thread_used_only_as_evidence 历史线程 key 是否仅作为证据

group_codeconfirmation_numberreservation_no 至少一个非空。当前稳定查询能力优先支持 group_codeconfirmation_number

全局上下文查询最终依赖“后端解析出的酒店 ID + 业务 key”source_message_idsource_event_index 不作为查询边界,传入时也不会影响查询结果。

4.3 成功响应

{
  "success": true,
  "request_id": "req-001",
  "trace_id": "trace-001",
  "data": {
    "matched_order_records": [],
    "pending_or_open_tasks": [],
    "active_workflows": [],
    "terminated_records": [],
    "target_object_validation": {
      "status": "none",
      "matched_object_id": null,
      "matched_object_type": null,
      "can_create_new_booking_task": true,
      "can_create_update_task": false,
      "can_create_cancel_task": false,
      "can_attach_voucher": false,
      "can_attach_rooming_list": false,
      "needs_manual_review_reason": null
    },
    "key_relationships": {
      "group_code_and_confirmation_same_object": null,
      "relationship_evidence": ""
    }
  },
  "warnings": [],
  "error": null
}

4.4 主要数据来源

返回字段 来源
matched_order_records[] workflow_reservation_order
pending_or_open_tasks[] workflow_reservation_task + workflow_reservation_ai_transition
terminated_records[] 订单 ENDED / LOGIC_DELETED,任务 FAILED / COMPLETED
active_workflows[] 当前无独立 workflow 表,固定空数组

5. 接口 2查询对象详情

5.1 请求

项目 内容
Method POST
URL {TH_HOTEL_API_BASE_URL}/api/ai-query/v1/object-detail
request_path /api/ai-query/v1/object-detail
Content-Type application/json
业务动作 只读查询对象详情,不创建任务、不修改订单、不写 OPERA

5.2 请求体

{
  "object_id": "ORDER:1900000000000000100",
  "object_type": "group_block"
}

字段说明:

字段 是否必填 中文说明
hotel_id 酒店上下文 IDSuperAgent 默认不传,后端解析系统酒店。
object_id 查询对象 ID第一版只支持 ORDER:{order_id}
object_type 调用方对象类型提示,第一版不作为强校验

5.3 成功响应

{
  "success": true,
  "request_id": "req-002",
  "trace_id": "trace-001",
  "data": {
    "object_id": "ORDER:1900000000000000100",
    "object_type": "group_block",
    "order_id": "1900000000000000100",
    "order_key_type": "GROUP_CODE",
    "group_code": "GRP-001",
    "confirmation_number": null,
    "reservation_no": null,
    "block_id": null,
    "temporary_order_code": "TMP-1900000000000000100",
    "display_name": "GRP-001",
    "status": "ACTIVE",
    "source_message_id": "1900000000000000001",
    "created_from_task_id": null,
    "created_at": "2026-07-08T01:00:00Z",
    "last_updated_at": "2026-07-08T01:10:00Z",
    "arrival_date": null,
    "departure_date": null,
    "nights": null,
    "guest_count": null,
    "room_items": [],
    "rate_code": null,
    "rate_code_price": null,
    "reservation_type": null,
    "cancel_status": "not_cancelled",
    "can_update": true,
    "can_cancel": true,
    "hard_validation_warnings": [
      {
        "code": "OPERA_PROJECTION_UNAVAILABLE",
        "message": "当前系统尚未接入 OPERA 对象投影,日期、房型、房价等字段无法确认。"
      }
    ]
  },
  "warnings": [],
  "error": null
}

说明:接口 2 响应中的 source_message_id 当前是本系统内部 SourceMessage Inbox ID用于对象溯源和排查不要把该字段当作 SuperAgent 任务结果通知接口的外部 source_message_id 使用。

6. 接口 3查询邮件会话下所有任务

6.1 请求

项目 内容
Method POST
URL {TH_HOTEL_API_BASE_URL}/api/ai-query/v1/message-conversation/tasks
request_path /api/ai-query/v1/message-conversation/tasks
Content-Type application/json
业务动作 只读查询邮件会话下任务,不创建任务、不修改订单、不写 OPERA

6.2 请求体

按外部邮件会话 ID 查询:

{
  "source_provider": "AGENTBUS",
  "source_channel": "EMAIL",
  "external_conversation_id": "thread-20260708-0001"
}

按外部来源消息 ID 作为锚点反查会话:

{
  "source_provider": "AGENTBUS",
  "source_channel": "EMAIL",
  "source_message_id": "mail-20260708-0001"
}

字段说明:

字段 是否必填 中文说明
hotel_id 酒店上下文 IDSuperAgent 默认不传,后端解析系统酒店。
source_provider 来源提供方,按会话 ID 查询和按 source_message_id 反查时都参与隔离,缺省为 AGENTBUS
source_channel 来源渠道,按会话 ID 查询和按 source_message_id 反查时都参与隔离,缺省为 EMAIL
external_conversation_id 条件必填 外部邮件会话 ID对应 AgentBus source.external_conversation_id
source_message_id 条件必填 外部来源消息 ID对应 AgentBus source.external_message_id,不是内部 Inbox ID

external_conversation_idsource_message_id 至少一个非空。两者同时传入时,第一版以后端直接按 external_conversation_id 查询为准。

6.3 成功响应

{
  "success": true,
  "request_id": "req-003",
  "trace_id": "trace-001",
  "data": {
    "hotel_id": "HOTEL-DEV",
    "external_conversation_id": "thread-20260708-0001",
    "task_count": 2,
    "tasks": [
      {
        "task_id": "1900000000000000400",
        "order_id": "1900000000000000300",
        "external_source_message_id": "mail-20260708-0001",
        "external_conversation_id": "thread-20260708-0001",
        "source_received_at": "2026-07-08T01:00:00Z",
        "source_event_index": 1,
        "catalog_code": "S02",
        "skill_id": "update_booking_amendment_skill",
        "result_type": "normal_task",
        "task_type": "Update Booking",
        "system_task_type": "UPDATE_BOOKING",
        "task_card_type": "UPDATE_BOOKING",
        "task_subtype": "update_stay_dates",
        "task_status": "PENDING_CONFIRM",
        "queue_participation": true,
        "execution_order": 1,
        "parent_task_id": null,
        "parent_source_event_index": null,
        "linked_task_group_id": null,
        "blocked_until_parent_completed": false,
        "completed_at": null,
        "task_created_at": "2026-07-08T01:01:00Z",
        "task_updated_at": "2026-07-08T01:01:00Z"
      }
    ]
  },
  "warnings": [],
  "error": null
}

排序规则:

  1. 先按邮件 received_at 正序。
  2. 同一封邮件下,再按任务 created_at 正序。
  3. 若时间相同,再按 task_id 正序稳定排序。

7. 接口 4查询邮件会话下所有受控正文

7.1 请求

项目 内容
Method POST
URL {TH_HOTEL_API_BASE_URL}/api/ai-query/v1/message-conversation/messages
request_path /api/ai-query/v1/message-conversation/messages
Content-Type application/json
业务动作 只读查询邮件会话受控正文,不返回附件 URL 或原始未清洗 HTML

7.2 请求体

请求体字段与接口 3 相同,可按 external_conversation_id 查询,也可按外部 source_message_id 锚点反查会话。

{
  "source_provider": "AGENTBUS",
  "source_channel": "EMAIL",
  "source_message_id": "mail-20260708-0001"
}

7.3 成功响应

{
  "success": true,
  "request_id": "req-004",
  "trace_id": "trace-001",
  "data": {
    "hotel_id": "HOTEL-DEV",
    "external_conversation_id": "thread-20260708-0001",
    "message_count": 2,
    "messages": [
      {
        "external_source_message_id": "mail-20260708-0001",
        "external_conversation_id": "thread-20260708-0001",
        "sender_summary": "guest@example.test",
        "subject": "Booking update",
        "received_at": "2026-07-08T01:00:00Z",
        "source_sent_at": "2026-07-08T00:59:00Z",
        "text_body": "Please update arrival date...",
        "html_body_sanitized": "<html><body>Please update arrival date...</body></html>",
        "html_sanitize_required": true,
        "html_render_mode": "SANITIZED_HTML"
      }
    ]
  },
  "warnings": [],
  "error": null
}

安全边界:

  • messages[] 按邮件 received_at 正序返回。
  • 不返回 html_body 原始未清洗 HTML。
  • 不返回 attachmentsinline_imagesexternal_url、附件 URL 或 HTML 中的 href/src 外链属性。
  • 后端读取正文时会写入 SourceMessage 原文访问审计。

8. 接口 5SuperAgent 通知 AI 任务结果

8.1 请求

项目 内容
Method POST
URL {TH_HOTEL_API_BASE_URL}/api/integrations/superagent/task-results
request_path /api/integrations/superagent/task-results
Content-Type application/jsontext/plain
业务动作 接收 AI 任务结果V3 JSON 支持结构化 S10/S99 和业务根V2 JSON 继续兼容,旧 S000/S999 文本创建只读特殊任务

8.2 V3 S10/S99 结构化请求体

S10 示例:

{
  "source_message": {
    "source_message_id": "mail-20260708-0001",
    "subject": null,
    "from": null,
    "cc": [],
    "received_at": null,
    "source_channel": "Email"
  },
  "route_code": "S10",
  "handler_type": "main_agent_outcome",
  "result_type": "source_message_review_notification",
  "current_or_history": "current",
  "agent_assessment": {
    "status": "no_booking_action_detected",
    "reason_code": "no_booking_action_detected",
    "automation_action": "none"
  },
  "notification": {
    "required": true,
    "notification_type": "source_message_review",
    "show_source_message": true,
    "requires_user_decision": true,
    "visible_message": "未匹配到当前 Agent 支持的业务事件类型,请查看原邮件并决定是否需要回复或进行其他处理。"
  },
  "manual_review": null
}

S99 与 S10 使用相同结构,但 route_code=S99agent_assessment.status=material_package_unavailable,且 manual_review 必须是完整入口复核对象。

8.3 V3 业务根请求体

{
  "source_message": {
    "source_message_id": "mail-20260708-0002",
    "subject": "New booking",
    "from": null,
    "cc": [],
    "received_at": null,
    "source_channel": "Email"
  },
  "message_events": [
    {
      "event_type": "New Booking",
      "event_role": "travel_agent_request",
      "source_event_index": "E1",
      "current_or_history": "current",
      "case_keys": {
        "group_code": null,
        "confirmation_number": "CNF-001",
        "reservation_number": null,
        "block_code": null
      },
      "relevant_message_excerpt": "Please create a new FIT reservation.",
      "attachments": [],
      "file_references": [],
      "context_used": {},
      "extracted_fields": {
        "booking_object_type": "FIT Reservation",
        "arrival_date": "2026-09-01",
        "departure_date": "2026-09-03",
        "room_quantity": 2,
        "room_type": "Deluxe King",
        "pms_room_type_code": "RM2"
      },
      "manual_review": null
    }
  ],
  "case_candidates": [],
  "extraction_warnings": [],
  "unhandled_current_intents": []
}

V3 字段说明:

字段 是否必填 中文说明
source_message.source_message_id 外部来源消息 ID对应 SourceMessage Inbox 的 external_message_id;缺失时返回技术错误且不落库
route_code S10/S99 必填 只允许 S10S99,用于区分入口通知结果
result_type S10/S99 必填 固定为 source_message_review_notification
message_events[] 业务根必填 SuperAgent 最终业务事件列表,本系统逐 event 派生路由
message_events[].event_type V3 active event 或 Need Manual Review
message_events[].event_role 事件来源角色,第一版必须是非空字符串
message_events[].source_event_index 可为 E1 或数字;后端会归一为数字序号
message_events[].current_or_history 第一版只接受 current
message_events[].case_keys 必须包含 group_codeconfirmation_numberreservation_numberblock_code 四个字段,值为 string 或 null
message_events[].relevant_message_excerpt 当前事件的邮件证据摘录,必须是字符串
message_events[].attachments 当前事件引用附件数组,无附件传空数组
message_events[].file_references 当前事件引用文件数组,无文件传空数组
message_events[].context_used 当前事件使用的上下文对象,无上下文传空对象
message_events[].extracted_fields 业务字段主体和 subtype 判别字段,必须是对象
message_events[].manual_review null 表示普通任务;对象表示 type-known manual review
unhandled_current_intents[] 第一版只保存 UNHANDLED_CURRENT_INTENT transition不自动创建业务任务

当前已支持的 V3 行为:

  • 42 条 P0 路由进入后端枚举 / 稳定配置。
  • 结构化 S10/S99 创建只读 SOURCE_MESSAGE_ONLY 任务,任务列表可见,订单列表不可见。
  • 业务 event 能派生到稳定路由时,复用现有订单 / 任务 / 任务卡创建链路。
  • event 判别字段不完整、显式携带 contract_errors、根 missing_fields、不完整 manual_review 或不完整 parent split 候选时,写入 adapter_contract_error transition不创建订单和任务同一邮件其他 sibling event 继续处理。
  • unhandled_current_intents[] 写入 UNHANDLED_CURRENT_INTENT transition不返回 adapter_error_code
  • V3 message_events[].relevant_message_excerpt 入站后会归一化到任务卡 AI payload 根路径供旧字段矩阵读取证据字段SuperAgent 仍只需要按 V3 event 契约提供该字段。
  • type-known manual review 第一版在同一业务任务卡解阻New Booking 房型字段主路径已迁移为 room_items[0],例如 /extracted_fields/room_items/0/pms_room_type_code。旧扁平字段仍可作为过渡提交 key解阻接口也支持提交 P0 主 field_path 或旧扁平 field_path,响应会归一化为 P0 主 field_path

source_message.source_message_id 缺失时返回 HTTP 400,响应体不使用通用错误包装:

{
  "result_type": "infrastructure_input_error",
  "error_code": "missing_source_message_id",
  "retryable": true,
  "missing_fields": [
    "source_message.source_message_id"
  ]
}

8.4 V2 JSON 兼容请求体

{
  "source_message_id": "mail-20260708-0001",
  "ai_task_results": [
    {
      "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
      },
      "visible_reason": "邮件正文包含新建预订请求。",
      "relevant_message_excerpt": "Please create a new booking...",
      "attachments": [],
      "file_references": [],
      "context_used": {},
      "extracted_fields": {},
      "manual_review": null,
      "informational_message": null,
      "additional_operations": [],
      "idempotency_key": null
    }
  ],
  "extraction_warnings": []
}

字段说明:

字段 是否必填 中文说明
hotel_id 酒店上下文 IDSuperAgent 默认不传,后端解析系统酒店后用于反查 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 目录代码
ai_task_results[].skill_id Skill 标识
ai_task_results[].result_type 当前代码契约只接受 normal_taskmanual_reviewinformational_message 仅历史兼容
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。后端通过系统酒店 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 正式契约。

informational_message 结构化任务仅用于历史兼容。新数据如果是纯信息类邮件或无法形成业务素材包,应优先使用 V3 结构化 S10/S99;旧联调或兼容场景仍可使用下面的 S000/S999 文本请求体。

8.5 S000/S999 文本请求体

纯信息类邮件:

S000,mail-20260708-0001

无法形成业务素材包:

S999,mail-20260708-0001

字段规则:

片段 中文说明
S000 纯信息类邮件,不需要形成业务任务。
S999 入口阶段无法形成业务素材包,不需要进入业务执行。
mail-20260708-0001 外部来源消息 ID对应 SourceMessage Inbox 的 external_message_id

S000/S999 不在 body 里传 hotel_id,后端使用平台酒店表唯一 ACTIVE 酒店查询 SourceMessage Inbox。命中后创建 SOURCE_MESSAGE_ONLY 只读特殊任务:任务列表可见,订单列表不可见,不允许编辑、确认、转换订单、执行 OPERA 或重试 OPERA也不参与同订单任务执行顺序阻塞。该文本格式仅为兼容路径新数据优先使用结构化 S10/S99

8.6 成功响应

{
  "request_id": "req-003",
  "source_message_id": "mail-20260708-0001",
  "batch_id": "1900000000000000200",
  "idempotent_replay": false,
  "accepted_count": 1,
  "items": [
    {
      "source_event_index": 1,
      "array_index": 1,
      "ai_transition_id": "1900000000000000250",
      "route_code": "R01_NEW_FIT_RESERVATION_NORMAL",
      "system_process_category": "BUSINESS_TASK",
      "adapter_error_code": null,
      "order_id": "1900000000000000300",
      "task_id": "1900000000000000400",
      "system_task_type": "NEW_BOOKING",
      "task_card_type": "NEW_BOOKING",
      "task_status": "PENDING_CONFIRM",
      "order_status": "TEMPORARY",
      "execution_order": 1
    }
  ],
  "warnings": []
}

S000/S999 成功响应示例:

{
  "request_id": "req-004",
  "source_message_id": "mail-20260708-0001",
  "batch_id": "1900000000000000500",
  "idempotent_replay": false,
  "accepted_count": 1,
  "items": [
    {
      "source_event_index": 1,
      "array_index": 1,
      "ai_transition_id": "1900000000000000550",
      "route_code": "S10",
      "system_process_category": "SOURCE_MESSAGE_NOTIFICATION",
      "adapter_error_code": null,
      "order_id": "1900000000000000600",
      "task_id": "1900000000000000700",
      "system_task_type": "SOURCE_MESSAGE_ONLY",
      "task_card_type": "SOURCE_MESSAGE_ONLY",
      "task_status": "COMPLETED",
      "order_status": "TEMPORARY",
      "execution_order": 1
    }
  ],
  "warnings": []
}

V3 adapter_contract_error 响应中的 items[] 不会包含 order_id / task_id

{
  "source_event_index": 2,
  "array_index": 1,
  "ai_transition_id": "1900000000000000800",
  "route_code": null,
  "system_process_category": "ADAPTER_CONTRACT_ERROR",
  "adapter_error_code": "EVENT_ROUTE_UNSUPPORTED",
  "order_id": null,
  "task_id": null,
  "system_task_type": "ADAPTER_CONTRACT_ERROR",
  "task_card_type": "ADAPTER_CONTRACT_ERROR",
  "task_status": null,
  "order_status": null,
  "execution_order": null
}

9. 错误响应

9.1 查询接口错误响应

{
  "success": false,
  "request_id": "req-001",
  "trace_id": "trace-001",
  "data": null,
  "warnings": [],
  "error": {
    "code": "AUTH_SIGNATURE_INVALID",
    "message": "签名校验失败。",
    "details": {}
  }
}

9.2 任务结果通知接口错误响应

{
  "request_id": null,
  "error_code": "AUTH_SIGNATURE_INVALID",
  "message": "签名校验失败。",
  "details": []
}

9.3 常见错误码

错误码 HTTP 状态 中文说明
AUTH_HEADER_MISSING 401 HMAC 必要 Header 缺失
AUTH_HEADER_INVALID 401 HMAC Header 格式或长度无效
AUTH_TIMESTAMP_INVALID 401 timestamp 格式错误或超出时间窗口
AUTH_SIGNATURE_INVALID 401 签名不匹配或服务端未配置 secret
AUTH_NONCE_REPLAY 409 nonce 已被使用
REQUEST_BODY_TOO_LARGE 413 请求体超过大小限制
REQUEST_CONTENT_TYPE_UNSUPPORTED 415 查询接口 Content-Type 不是 application/json,或任务结果通知接口不是 application/json / text/plain
REQUEST_BODY_INVALID 400 JSON 不合法,或 S000/S999 文本格式不符合 结果码,source_message_id
QUERY_KEY_REQUIRED 400 查询接口缺少可用业务 key
MESSAGE_CONVERSATION_QUERY_KEY_REQUIRED 400 会话查询缺少 external_conversation_idsource_message_id
OBJECT_NOT_FOUND 404 对象详情查询目标不存在
MESSAGE_CONVERSATION_NOT_FOUND 404 外部邮件会话尚未写入 SourceMessage Inbox
SYSTEM_HOTEL_NOT_CONFIGURED 409 平台酒店表没有可用 ACTIVE 酒店
SYSTEM_HOTEL_AMBIGUOUS 409 单酒店阶段平台酒店表存在多家 ACTIVE 酒店
HOTEL_ACCESS_DENIED 403 显式传入的 hotel_id 与系统酒店或当前用户授权酒店不一致
SOURCE_MESSAGE_NOT_FOUND 404 任务结果通知或会话锚点引用的外部来源消息尚未写入 SourceMessage Inbox
missing_source_message_id 400 V3 请求缺少 source_message.source_message_id,响应体为 typed infrastructure_input_error

10. HMAC 上线配置

上线需要配置:

配置项 是否必填 中文说明
SUPERAGENT_DEV_TASK_RESULT_HMAC_SECRET dev 必填 dev HMAC 共享密钥;查询接口和任务结果通知接口共用
SUPERAGENT_TEST_TASK_RESULT_HMAC_SECRET test 必填 test HMAC 共享密钥;查询接口和任务结果通知接口共用
SUPERAGENT_PROD_TASK_RESULT_HMAC_SECRET prod 必填 prod HMAC 共享密钥;生产不能为空,只能通过 Secret 注入
SUPERAGENT_TASK_RESULT_HMAC_SECRET 兼容兜底 旧通用 HMAC 变量;优先使用环境专属变量
SUPERAGENT_TASK_RESULT_CLOCK_SKEW_SECONDS 请求时间允许偏移,默认 300
SUPERAGENT_TASK_RESULT_NONCE_TTL_SECONDS nonce 防重放保存时间,默认 600
SUPERAGENT_TASK_RESULT_MAX_BODY_BYTES 请求体最大字节数,默认 1048576

上线注意事项:

  • 本系统和 SuperAgent 必须配置同一个 HMAC secret。
  • 生产 secret 只能放在部署平台 Secret 或环境变量中,不能写入仓库、镜像、前端配置或普通文档。
  • SuperAgent 必须使用原始请求体计算 SHA-256不能使用格式化后 JSON。
  • HMAC canonical string 的第二行必须使用 request_path,例如 /api/ai-query/v1/case-context
  • SuperAgent 每次请求必须生成全新的 nonce同一个 client_id + nonce 在 TTL 窗口内不能重复使用。
  • 调用双方服务器时间必须同步,建议使用 NTP。
  • 建议所有接口只暴露在 HTTPS 和可信网络边界内。
  • 轮换 secret 时需要安排双写或短窗口切换;当前第一版后端只支持一个 secret轮换窗口内需要协调发布顺序。