Browse Source

完善空海医院动线感知方案文档

WangKang 1 week ago
parent
commit
083a7a3553

+ 3 - 0
.gitignore

@@ -60,3 +60,6 @@ logs
 .claude
 openspec
 .agents
+
+back-info/*
+.env

+ 7 - 7
docs/superpowers/plans/2026-06-02-terminal-demo-vertical-task-breakdown.md

@@ -532,13 +532,13 @@ Web 客户端能通过统一入口发起对话,并收到稳定 SSE 事件和
 
 | 小组/人 | 建议负责 |
 | --- | --- |
-| 后端 A | T1 SQLite Mock HIS |
-| 后端 B | T2 MCP Tool + T5 Card Action |
-| 后端 C / AI | T3 OpenPlatform SSE + T4 AgentRouter/Task/Dify |
-| 前端 A | T6 UI Shell + 医生形象 + 品牌视觉 |
-| 前端 B | T7 对话/SSE + T8 卡片流 |
-| 全栈/QA | T9 支付成功联合闭环 + T10 验收脚本 |
-| 技术负责人 | T0 契约冻结、跨任务 review、最终架构测试 |
+| 王康 | T1 SQLite Mock HIS |
+| 高力 | T2 MCP Tool + T5 Card Action |
+| 高力 | T3 OpenPlatform SSE + T4 AgentRouter/Task/Dify |
+| 韩朝 | T6 UI Shell + 医生形象 + 品牌视觉 |
+| 韩朝 | T7 对话/SSE + T8 卡片流 |
+| 一起 | T9 支付成功联合闭环 + T10 验收脚本 |
+| 王康 | T0 契约冻结、跨任务 review、最终架构测试 |
 
 ## 工作量汇总
 

+ 101 - 3
docs/接口文档/emoon-ai-openplatform-api-v1.2.openapi.yaml

@@ -1,8 +1,8 @@
 openapi: 3.0.3
 info:
   title: EMOON AI OpenPlatform External API
-  version: 1.2.1
-  description: 医梦 AI 中台对外接口契约 v1.2.1,正式联调基准版。P0/P1 为厂商联调主基线;P2 为受控规划接口。FHIR 映射从主 YAML 移出,避免误解为当前交付承诺。统一入口客户端调用 Agent 时可不传 agentId,由后端 AgentRouter 决定最终智能体。
+  version: 1.2.3
+  description: 医梦 AI 中台对外接口契约 v1.2.3,正式联调基准版。P0/P1 为厂商联调主基线;P2 为受控规划接口。FHIR 映射从主 YAML 移出,避免误解为当前交付承诺。统一入口客户端调用 Agent 时可不传 agentId,由后端 AgentRouter 结合设备、场景、感知上下文和服务端推导的动线阶段决定最终智能体。
 servers:
 - url: https://api.{hospital}.emoon.local/api/v1
   variables:
@@ -2654,6 +2654,73 @@ components:
       required:
       - deviceId
       description: 设备上下文。门诊设备原则上由医梦 Device Registry 管理;住院侧类型(nurse_pda / nursing_whiteboard / bedside_screen / ward_robot)通常通过迪耐克/鸿蒙病房体系映射接入,医梦只负责 AI 能力、事件互通和审计,不承担住院硬件基础管理责任。
+    PerceptionContext:
+      type: object
+      description: 感知上下文。用于统一入口客户端上报最近一次身份、空间、业务、设备或风险感知事实;服务端仍以授权、HIS/叫号/任务状态为最终依据。P0 不允许上传连续轨迹。
+      properties:
+        identityBindingId:
+          type: string
+          description: 患者身份与终端/设备/会话绑定记录 ID。
+        locationLevel:
+          type: string
+          enum:
+          - L0
+          - L1
+          - L2
+          - L3
+          description: 感知级别。L0=扫码/人工;L1=NFC/刷卡;L2=BLE/Wi-Fi 区域;L3=星闪/鸿蒙/UWB 等高精度。
+        zoneCode:
+          type: string
+          description: 服务区域编码,如 clinic_room_301_door、outpatient_hall_kiosk。
+        source:
+          type: string
+          enum:
+          - QR_SCANNED
+          - NFC_TOUCH
+          - CARD_READ
+          - BLE_ZONE_DETECT
+          - WIFI_ZONE_DETECT
+          - MANUAL_CONFIRM
+          - BUSINESS_STATE
+          - DEVICE_EVENT
+          - CUSTOM
+        occurredAt:
+          type: string
+          format: date-time
+        confidence:
+          type: number
+          format: double
+          minimum: 0
+          maximum: 1
+    JourneyState:
+      type: object
+      readOnly: true
+      description: 患者当前动线阶段。由服务端根据 VisitTimeline、TaskState、DeviceContext、DeviceEvent、CardAction 和院内系统状态推导;P0 仅用于服务端返回给客户端展示,客户端请求不得传入该对象,也不得据此自行放开高风险能力。
+      properties:
+        stageCode:
+          type: string
+          description: 动线阶段编码,如 WAITING_CHECKIN、WAITING_CALL、WAITING_PAYMENT、WAITING_EXAM、REPORT_READY、FOLLOW_UP。
+        stageName:
+          type: string
+          description: 动线阶段中文名。
+        nextAction:
+          type: string
+          description: 推荐下一步动作,如 CHECK_IN、PAYMENT_GUIDE、NAVIGATE_TO_EXAM、REPORT_EXPLAIN。
+        source:
+          type: string
+          enum:
+          - SERVER_DERIVED
+          - HIS_STATE
+          - CARD_ACTION
+          - DEVICE_EVENT
+        confidence:
+          type: number
+          format: double
+          minimum: 0
+          maximum: 1
+        requiresConfirm:
+          type: boolean
+          description: 是否必须患者或医护确认后才能执行。
     BillingContext:
       type: object
       properties:
@@ -2707,6 +2774,8 @@ components:
           $ref: '#/components/schemas/UserContext'
         deviceContext:
           $ref: '#/components/schemas/DeviceContext'
+        perceptionContext:
+          $ref: '#/components/schemas/PerceptionContext'
         message:
           $ref: '#/components/schemas/ChatMessage'
         inputs:
@@ -2727,6 +2796,8 @@ components:
           type: array
           items:
             $ref: '#/components/schemas/CardRef'
+        journeyState:
+          $ref: '#/components/schemas/JourneyState'
         riskLevel:
           type: string
           enum:
@@ -3142,6 +3213,33 @@ components:
           items:
             type: string
           description: 设备硬件能力列表(如 touch/camera/id_card_ocr/file_upload)。
+        perceptionCapabilities:
+          type: array
+          items:
+            type: string
+            enum:
+            - QR_IDENTITY_BINDING
+            - NFC_TOUCH
+            - CARD_READ
+            - BLE_ZONE_DETECT
+            - WIFI_ZONE_DETECT
+            - HARMONY_NEARBY
+            - MANUAL_CONFIRM
+          description: 该设备支持的感知能力。P0 推荐 QR/NFC/刷卡/人工确认,BLE/鸿蒙近场仅作为可选试点。
+        journeyPolicy:
+          type: object
+          description: 动线服务策略。用于终端决定是否展示动线区和服务找人入口,不能用于绕过后端权限。
+          properties:
+            mode:
+              type: string
+              enum:
+              - DISABLED
+              - MVP_STATIC
+              - SERVER_DERIVED
+            serviceFindPatientEnabled:
+              type: boolean
+            requiresPatientConfirm:
+              type: boolean
         allowedCards:
           type: array
           items:
@@ -3206,7 +3304,7 @@ components:
         eventPayload:
           type: object
           additionalProperties: true
-          description: 事件附加数据(如 screen/action 等)
+          description: 事件附加数据。按 eventType 校验必要字段:QR_SCANNED 建议 qrType/visitId;CARD_READ 建议 cardType;NEARBY_DETECTED 建议 zoneCode/level;TOUCH_INTERACTION 建议 screen/action。未识别扩展字段只作为审计摘要,不直接触发高风险业务
         occurredAt:
           type: string
           format: date-time

+ 49 - 0
docs/接口文档/terminal-client-mvp-contract.md

@@ -9,6 +9,8 @@
 
 ## 1. 接口总览
 
+统一入口客户端引入后,接口契约的核心不是“前端传一个 `agentId` 后端回答”,而是“终端上报设备和感知事实,后端返回场景配置、动线阶段、下一步服务和可执行卡片”。MVP 保持接口数量不扩张,优先在现有 `/devices/{deviceId}/scene`、`/devices/{deviceId}/events`、`/agent/chat/stream` 中增加可选字段。
+
 ### 1.1 终端调用白名单
 
 前端/终端 **只允许** 调用以下接口:
@@ -197,6 +199,17 @@ curl -X GET https://api.demo.emoon.local/api/v1/devices/EMOON-KIOSK-001/scene \
     ],
     "blockedIntents": [],
     "capabilities": ["touch", "camera", "id_card_ocr", "file_upload"],
+    "perceptionCapabilities": [
+      "QR_IDENTITY_BINDING",
+      "NFC_TOUCH",
+      "CARD_READ",
+      "BLE_ZONE_DETECT"
+    ],
+    "journeyPolicy": {
+      "mode": "MVP_STATIC",
+      "serviceFindPatientEnabled": true,
+      "requiresPatientConfirm": true
+    },
     "allowedCards": [
       "department-selection",
       "doctor-selection",
@@ -238,6 +251,22 @@ curl -N -X POST https://api.demo.emoon.local/api/v1/agent/chat/stream \
 
 > **`agentId` 是可选的。** 统一入口客户端不传 `agentId`,由后端 AgentRouter 根据设备类型、场景配置、用户输入和任务状态自动决定路由到哪个智能体。
 
+感知上下文为可选字段,P0 客户端可以不传;支持 NFC/刷卡/近场能力的终端可传入最近一次感知事实,后端仍以服务端 HIS/叫号/任务状态为准。
+
+```json
+{
+  "perceptionContext": {
+    "identityBindingId": "bind_001",
+    "locationLevel": "L1",
+    "zoneCode": "clinic_room_301_door",
+    "source": "NFC_TOUCH",
+    "occurredAt": "2026-06-03T09:30:00+08:00"
+  }
+}
+```
+
+客户端请求不得传入 `journeyState`。P0 阶段服务端完全忽略任何通过 `inputs` 或扩展字段伪造的动线状态,动线状态只能由服务端通过 HIS/叫号/任务状态/卡片动作/设备事件推导后返回。断线恢复使用 `conversationId` 和卡片查询接口,不使用客户端回传的动线对象。
+
 ### 4.2 SSE 事件类型
 
 | 事件 | 说明 | MVP 必达 |
@@ -246,6 +275,7 @@ curl -N -X POST https://api.demo.emoon.local/api/v1/agent/chat/stream \
 | `message_completed` | 文本完成 `{"messageId":"msg_xxx","conversationId":"conv_xxx"}` | ✅ |
 | `card_created` | 卡片已创建 `{"cardInstanceId":"card_xxx","cardKey":"department-selection"}` | ✅ |
 | `task_updated` | 任务状态变更 `{"taskType":"REGISTRATION","currentStep":"COLLECT_SYMPTOM","status":"ACTIVE"}` | ✅ |
+| `journey_updated` | 动线阶段变更 `{"stageCode":"WAITING_CHECKIN","nextAction":"CHECK_IN","source":"SERVER_DERIVED"}` | ✅ |
 | `usage_reported` | 用量事件(P1) | ❌ |
 | `error` | 错误 `{"code":"xxx","message":"..."}` | ✅ |
 | `completed` | 本次 SSE 结束 `{"conversationId":"conv_xxx"}` | ✅ |
@@ -256,6 +286,9 @@ curl -N -X POST https://api.demo.emoon.local/api/v1/agent/chat/stream \
 event: task_updated
 data: {"taskType":"REGISTRATION","currentStep":"COLLECT_SYMPTOM","status":"ACTIVE","taskId":"task_001"}
 
+event: journey_updated
+data: {"stageCode":"REGISTRATION_IN_PROGRESS","nextAction":"SELECT_DEPARTMENT","source":"SERVER_DERIVED","taskId":"task_001"}
+
 event: message_delta
 data: {"text":"好的,我来帮您走挂号流程。请先简单描述您的症状或选择目标科室。"}
 
@@ -470,6 +503,8 @@ curl -X POST https://api.demo.emoon.local/api/v1/devices/EMOON-ROBOT-001/command
 
 ## 8. 设备事件上报
 
+设备事件是感知事实的入口,但不是自动业务动作。比如 `NEARBY_DETECTED` 只能说明患者或终端进入服务区域,后端还必须结合身份授权、HIS/叫号状态和患者确认,才能创建签到、缴费、导航等卡片。
+
 ```bash
 curl -X POST https://api.demo.emoon.local/api/v1/devices/EMOON-KIOSK-001/events \
   -H "Content-Type: application/json" \
@@ -485,6 +520,20 @@ curl -X POST https://api.demo.emoon.local/api/v1/devices/EMOON-KIOSK-001/events
   }'
 ```
 
+`eventPayload` 采用“事件类型固定字段 + 扩展字段”的方式,不要求所有事件共用同一个扁平结构。服务端按 `eventType` 校验必要字段,未识别字段只作为审计摘要保存,不参与高风险业务判断。
+
+常用感知事件:
+
+| eventType | 必要 eventPayload | 后端用途 |
+|---|---|---|
+| `QR_SCANNED` | `{ "qrType": "visit", "visitId": "..." }` | 身份/就诊绑定 |
+| `CARD_READ` | `{ "cardType": "hospital_card" }` | 身份确认,不在日志保存完整卡号 |
+| `NEARBY_DETECTED` | `{ "zoneCode": "clinic_room_301_door", "level": "L2" }` | 推导是否进入服务区域 |
+| `TOUCH_INTERACTION` | `{ "screen": "home", "action": "tap_checkin" }` | 记录用户主动触发 |
+| `CUSTOM` | `{ "businessState": "WAITING_PAYMENT" }` | 联调阶段承载厂商扩展状态 |
+
+隐私约束:P0 不上报连续坐标、不保存患者移动轨迹;位置字段只能表达服务区域,如诊区、诊室门口、自助机点位。
+
 ---
 
 ## 9. 错误响应格式

+ 49 - 25
docs/接口文档/医梦AI中台对外接口设计文档_v1.2_正式联调基准版.md

@@ -2,9 +2,9 @@
 
 > 文档定位:厂商对接接口全貌 + MVP 可落地接口契约说明  
 > 适用对象:HIS/EMR/LIS/PACS/叫号/支付厂商、机器人厂商、自助机/导诊屏/诊室屏/大屏厂商、四诊仪厂商、迪耐克/鸿蒙病房互通方、医院信息科、医梦内部研发与测试  
-> OpenAPI 文件:`emoon-ai-openplatform-api-v1.2.openapi.yaml`(文件名沿用 v1.2,`info.version` 为 1.2.1
-> 版本:v1.2.1
-> 生成时间:2026-05-31 18:00
+> OpenAPI 文件:`emoon-ai-openplatform-api-v1.2.openapi.yaml`(文件名沿用 v1.2,`info.version` 为 1.2.3
+> 版本:v1.2.3
+> 生成时间:2026-06-03 18:00
 
 ---
 
@@ -20,7 +20,11 @@
 
 本版在 v1.1 基础上采纳本轮审查中合理的问题,形成正式联调基准版:补充文件删除幂等、文件上传幂等语义、`clientFileId`、`sha256`、`retentionPolicy`、住院设备映射边界、工具风险等级、`/meter/events` 查询范围收敛,并将 FHIR 可选映射从主 OpenAPI YAML 移出,避免厂商误解为当前交付承诺。
 
-2026-05-31 补充统一入口客户端口径:本次不新增 P0 URL,而是收敛终端调用白名单、AgentRouter/TaskState 内部职责和前后端工程边界。OpenAPI YAML 文件名沿用 v1.2,`info.version` 升级为 1.2.1,并将 `AgentChatRequest.agentId` 改为可选以支持后端路由。
+2026-05-31 补充统一入口客户端口径:本次不新增 P0 URL,而是收敛终端调用白名单、AgentRouter/TaskState 内部职责和前后端工程边界。OpenAPI YAML 文件名沿用 v1.2,`info.version` 当时升级为 1.2.1,并将 `AgentChatRequest.agentId` 改为可选以支持后端路由。
+
+2026-06-03 根据空海医院会议补充“动线 + 感知”口径:本次仍不新增 P0 URL,只在现有场景、设备事件和对话接口中增加可选 `perceptionContext`、服务端返回 `journeyState`、`perceptionCapabilities`、`journeyPolicy`,用于支撑“同一设备、不同用户、不同动线阶段展示不同智能体服务”。P0 只做扫码/NFC/刷卡/人工确认和服务区域级事件,不承诺全院无感定位、连续轨迹、自动签到、自动缴费。
+
+2026-06-03 交叉 review 后修正:`journeyState` 只允许服务端返回,客户端请求不得传入;`journey_updated` 作为 P0 SSE 事件,避免前端从 `task_updated/card_created` 反推动线阶段。
 
 
 
@@ -31,6 +35,7 @@
 | 文件删除幂等 | `DELETE /files/{fileId}` 增加 `X-Emoon-Idempotency-Key`,重复删除返回首次结果或已删除状态 | 防止敏感文件删除操作重试时审计不一致 |
 | 文件上传幂等 | `FileUploadRequest` 增加 `clientFileId`、`sha256`、`source`、`retentionPolicy` | 支撑舌诊、面诊、报告、音频等文件的安全上传与重复上传识别 |
 | 住院设备边界 | `DeviceContext` 增加 `managementMode`、`externalSystem`、`externalDeviceId` | 区分医梦直管门诊设备与迪耐克/鸿蒙病房映射设备 |
+| 动线与感知 | `AgentChatRequest` 增加可选 `perceptionContext`,响应和 SSE 返回 `journeyState`,`DeviceSceneData` 增加 `perceptionCapabilities/journeyPolicy` | 支撑服务找人和同设备差异化能力,但不扩大 P0 URL 面 |
 | 工具风险等级 | `ToolInvokeRequest` / `ToolCatalogItem` 增加 `riskLevel` | 明确查询、敏感查询、业务写入、财务动作、医疗正式写入的不同控制要求 |
 | 计量查询收敛 | `/meter/events` P0 只支持 `billingEpisodeId` / `traceId` 精确查询 | 防止普通厂商误以为可查询完整项目账单或全量成本明细 |
 | FHIR 降噪 | `/fhir/{resourceType}/$translate` 从主 YAML 移除,仅保留为远期可选规划 | 避免 HIS 厂商误解医梦当前要提供完整 FHIR 网关 |
@@ -44,7 +49,7 @@
 5. **设备上下文进入每次关键调用**:`deviceContext` 进入 chat、card action、device event、meter event。
 6. **P0 能真实联调,P1/P2 先给全貌**:防止接口规划缺口导致未来返工。
 
-### 0.1 v1.2.1 统一入口客户端补充口径
+### 0.1 v1.2.3 统一入口客户端补充口径
 
 | 主题 | 接口口径 | 原因 |
 |---|---|---|
@@ -55,6 +60,8 @@
 | 舌诊底层接口 | 终端只能走 `/files/upload` + `/agent/chat/stream` + `/cards/{id}/actions/{name}`,不得直连舌诊 SDK/API | 舌象图片属于敏感医疗数据,必须统一文件审计和工具审计 |
 | HIS Mock/Real Adapter | Mock 阶段和真实阶段对终端接口不变,差异只在后端 `HospitalAdapter` 配置 | 便于 MVP 先联调,后续替换真实 HIS 不改终端 |
 | 前后端工程边界 | 后端能力仍在 AI 中台统一工程;前端/移动端另起 `emoon-terminal-client` | 符合团队资源现状,避免一个仓库混合终端构建、后端模块和 Demo 服务 |
+| 动线/感知字段 | `perceptionContext` 是终端上报的最近一次感知事实,`journeyState` 只由后端结合 HIS/叫号/任务状态推导后返回 | 前端不得传入或自行判断已签到、可缴费、可挂号成功 |
+| 设备能力差异 | `/devices/{deviceId}/scene` 返回 `allowedAgents/allowedCards/perceptionCapabilities/journeyPolicy` | 同一设备面向患者、医护、访客和不同动线阶段时能力不同 |
 
 ### 0.2 本接口边界的行业依据
 
@@ -298,7 +305,7 @@ SHA256_HEX(request_body)
 | 接口类型 | 幂等键建议 |
 |---|---|
 | 对话请求 | `projectId + resolvedAgentId/routeKey + clientMessageId`;统一入口客户端未传 `agentId` 时由后端路由结果补齐 |
-| 设备事件 | `projectId + deviceId + eventType + clientEventId` |
+| 设备事件 | `projectId + deviceId + eventType + eventId` |
 | 卡片动作 | `projectId + cardInstanceId + actionName + clientActionId` |
 | Tool 写操作 | `projectId + toolName + businessKey` |
 | 文件上传 | `projectId + sha256 + clientFileId` |
@@ -371,9 +378,12 @@ SHA256_HEX(request_body)
 | `conversationId` | 可为空;为空时平台自动创建并返回 |
 | `user` | 用户上下文,预留 `patientId/visitId/encounterId/authorizationId` |
 | `deviceContext` | 设备上下文,设备调用必须传 |
+| `perceptionContext` | 可选。终端最近一次感知事实,如扫码、NFC、刷卡、服务区域事件;服务端仍以授权和院内系统状态为准 |
 | `message` | 文本、图片、音频、文件引用;多模态内容使用 `fileId` |
 | `billingContext` | 场景和计量上下文 |
 
+`journeyState` 只存在于响应、SSE 和查询结果中。客户端请求不得传入该对象;即使通过 `inputs` 扩展字段伪造,P0 服务端也必须完全忽略,并以服务端事实重新推导。
+
 ### 5.2 文件上传接口
 
 `POST /files/upload`
@@ -430,24 +440,35 @@ MVP 只处理:
 
 | eventType | 说明 |
 |---|---|
-| `qr_scanned` | 扫码完成 |
-| `card_read` | 身份证/医保卡读取 |
-| `print_completed` | 打印成功 |
-| `print_failed` | 打印失败 |
-| `nearby_detected` | 近场检测到患者或临时授权令牌 |
-| `navigation_started` | 机器人开始导航 |
-| `navigation_completed` | 机器人导航完成 |
-| `device_error` | 设备异常 |
-| `user_interaction` | 触控、点击、语音交互摘要 |
-
-`nearby_detected` 推荐 payload:
+| `QR_SCANNED` | 扫码完成 |
+| `CARD_READ` | 身份证/医保卡读取 |
+| `PRINT_COMPLETED` | 打印成功 |
+| `PRINT_FAILED` | 打印失败 |
+| `NEARBY_DETECTED` | 近场检测到患者或临时授权令牌 |
+| `NAVIGATION_STARTED` | 机器人开始导航 |
+| `NAVIGATION_COMPLETED` | 机器人导航完成 |
+| `DEVICE_ERROR` | 设备异常 |
+| `TOUCH_INTERACTION` | 触控、点击、语音交互摘要 |
+| `CUSTOM` | 厂商扩展事件,P0 只能承载联调所需的非敏感摘要 |
+
+`eventPayload` 按 `eventType` 校验必要字段,不强制所有事件使用同一个扁平结构:
+
+| eventType | 必要 eventPayload | 说明 |
+|---|---|---|
+| `QR_SCANNED` | `qrType`、`visitId` 或临时授权 token | 身份/就诊绑定 |
+| `CARD_READ` | `cardType` | 不允许上传完整身份证号、医保卡号 |
+| `NEARBY_DETECTED` | `zoneCode`、`level` | 只表示进入服务区域,不表示已签到 |
+| `TOUCH_INTERACTION` | `screen`、`action` | 用户主动触发摘要 |
+| `CUSTOM` | 项目约定字段 | 仅用于联调扩展,正式上线前需进入白名单 |
+
+`NEARBY_DETECTED` 推荐 `eventPayload`:
 
 ```json
 {
-  "eventType": "nearby_detected",
-  "clientEventId": "evt_001",
+  "eventType": "NEARBY_DETECTED",
+  "eventId": "evt_001",
   "occurredAt": "2026-05-29T10:00:00+08:00",
-  "payload": {
+  "eventPayload": {
     "subject": {
       "type": "temporary_token",
       "value": "tmp_nearby_token_xxx"
@@ -462,7 +483,7 @@ MVP 只处理:
 }
 ```
 
-注意:不要让设备直接上报身份证号、手机号等敏感信息。服务找人只保存“到达诊室门口服务区域”的必要事件,不保存连续轨迹。
+注意:不要让设备直接上报身份证号、手机号等敏感信息。服务找人只保存“到达诊室门口服务区域”的必要事件,不保存连续轨迹。设备事件只形成感知事实,不能自动触发签到、缴费、挂号等高风险业务动作,必须由后端结合身份授权、HIS/叫号状态和患者确认后生成卡片。
 
 ### 5.4 卡片动作接口
 
@@ -542,13 +563,15 @@ Content-Type: application/json
 | `message_delta` | P0 | 文本增量 |
 | `message_completed` | P0 | 文本完成,返回 messageId/conversationId |
 | `card_created` | P0 | 平台已创建卡片实例,前端可渲染 |
+| `task_updated` | P0 | 任务状态变更,返回 taskId/taskType/currentStep/status |
+| `journey_updated` | P0 | 动线阶段变更,返回 stageCode/nextAction/source;前端动线区必须以该事件或响应中的 `journeyState` 为准 |
 | `error` | P0 | 流式错误 |
 | `usage_reported` | P1 | 本次调用用量或能力值事件,仅展示用途,不作为账本唯一来源 |
 
 断线恢复:
 
 1. 客户端记录 `conversationId` 和最后收到的 `eventId`。
-2. 断线后调用 `GET /conversations/{'{conversationId}'}/messages` 查询最终消息和卡片。
+2. 断线后调用 `GET /conversations/{'{conversationId}'}/messages` 查询最终消息、任务状态、动线状态和卡片。
 3. 卡片实例以 `GET /cards/{'{cardInstanceId}'}` 为准。
 
 ---
@@ -710,7 +733,7 @@ Content-Type: application/json
 
 ```text
 医梦AI中台厂商对接资料包/
-├── 医梦AI中台对外接口设计文档_v1.2.1_正式联调基准版.md
+├── 医梦AI中台对外接口设计文档_v1.2.3_正式联调基准版.md
 ├── emoon-ai-openplatform-api-v1.2.openapi.yaml
 ├── Postman Collection
 ├── HMAC签名示例-Java
@@ -723,9 +746,9 @@ Content-Type: application/json
 当前这版已经可以作为内部评审和厂商预沟通底稿。若要发正式联调版,应再补 Postman Collection、HMAC 示例和 HIS Mock Server。
 
 
-## 12. v1.2.1 正式联调基准结论
+## 12. v1.2.3 正式联调基准结论
 
-v1.2.1 可以作为厂商正式联调基准。它不扩大主 OpenAPI YAML 的 P0 接口面,只补充统一入口客户端的调用边界和工程归属。仍需坚持以下边界:
+v1.2.3 可以作为厂商正式联调基准。它不扩大主 OpenAPI YAML 的 P0 接口面,只补充统一入口客户端的调用边界、工程归属、动线阶段和感知上下文。仍需坚持以下边界:
 
 1. **主 YAML 只代表当前联调基准**:P0/P1 是主要联调范围;P2 只做规划说明,不代表春节前承诺。
 2. **FHIR 不在主基线内**:如医院已有 FHIR 网关,需要单独评估后另出 FHIR 映射文件。
@@ -733,6 +756,7 @@ v1.2.1 可以作为厂商正式联调基准。它不扩大主 OpenAPI YAML 的 P
 4. **文件和工具接口是高风险区域**:文件必须有用途、来源、保存策略和幂等;工具必须有 riskLevel、scope、幂等和审计。
 5. **计量查询不是账单接口**:`/meter/events` 只用于联调排障和计量核验,正式对账以后续账单中心为准。
 6. **统一入口客户端不直连底层能力**:终端前端不得持有 Dify Key,不得调用 HIS Tool,不得直连舌诊底层接口,不得写计量账本。
+7. **动线和感知不等于自动业务动作**:终端只能上报感知事实和展示后端返回的 `journeyState`,签到、缴费、挂号、报告解读等动作仍必须走卡片确认、审计和幂等链路。
 
 对外发送建议:
 

+ 148 - 4
docs/架构文档/AI中台二期+三期需求技术方案.md

@@ -7,8 +7,8 @@
 | 二期主题 | OpenPlatform + Dify Workflow + MCP Server + Card Runtime + Terminal Runtime + Device Registry/Adapter |
 | 三期主题 | 能力值预付账户、设备授权、设备维度计量、额度、账单、统计、运营、审计 |
 | 计费主粒度 | 项目 / 医院客户;科室、智能体、用户、设备、场景作为分摊与统计维度 |
-| 版本 | v6.1 |
-| 更新时间 | 2026-05-31 |
+| 版本 | v6.3 |
+| 更新时间 | 2026-06-03 |
 
 ## 1. 结论摘要
 
@@ -18,6 +18,8 @@
 
 医院确认版方案带来的新增结论是:门诊侧由医梦主导整体入口总包,重点不是医梦生产所有硬件,而是控制门诊软硬件入口标准、统一客户端、设备准入、联调验收和持续运营;住院侧不做硬件总包,应收敛为“AI 大脑层”,与迪耐克 / 鸿蒙病房体系互通,医梦负责智能体、IoMT 预警解释、护理任务、病历质控、出院随访等 AI 闭环。
 
+空海医院最新会议进一步把方案主轴从“多设备统一入口”提升为“动线 + 感知”:感知负责识别患者身份、空间位置、业务状态、设备能力和风险约束;动线负责判断患者当前处于就医流程的哪个阶段、下一步该做什么;AI 中台负责把感知结果转成可确认、可审计、可计量的智能体服务;统一入口客户端负责在机器人、自助机、导诊屏、诊室屏等设备前外显这些服务。该主轴不改变“医梦不做全院物联网硬件平台”的边界,反而要求第一期更克制:先做低门槛、可验收的动线节点感知和服务找人闭环。
+
 三期应优先建设商业闭环,而不是继续堆业务场景。原因是公司商业口径已经明确为“能力值包 + 项目实施费 + 综合运营服务费 / 合理不限量服务包”,且新方案增加了设备集成服务费、统一入口客户端授权费、设备运维服务费、鸿蒙服务找人 POC、机器人场景服务费等收费项。当前工程只有 token 级调用日志,尚不能支撑真实合同、设备维度授权、设备用量统计、预扣款、超量控制、分摊对账和运营报告。
 
 关键架构决策速查:
@@ -30,6 +32,8 @@
 | 设备授权和能力值分流 | 设备授权费覆盖入口运行,高级 AI 能力按合同进入能力值或服务包 | 通过 `charge_policy` 避免重复收费 |
 | 事件可靠性优先 | 业务成功不能丢审计、不能漏计量、不能重复扣费 | Outbox + 幂等键 + 账本不可变流水 |
 | 服务找人最小化 | 主动签到只处理诊室门口到达事件,不保存连续轨迹 | BLE/NFC/二维码兜底,患者确认后才签到 |
+| 动线驱动服务 | 同一设备面向不同用户、不同动线阶段,展示不同智能体、卡片和工具权限 | MVP 不新增复杂规则引擎,先用 `VisitTimeline + TaskState + DeviceContext + DeviceEvent` 推导 `journeyState` |
+| 感知分级落地 | 身份、空间、业务、设备、风险五类感知分层接入 | P0 用扫码/NFC/刷卡/人工确认,P1 才做 BLE 区域感知,P2 才评估星闪/UWB/鸿蒙高精度 |
 
 ### 1.1 行业参考与本方案取舍
 
@@ -44,6 +48,7 @@
 | Dify Workflow | 官方文档已有 Chatflow/Workflow 版本控制、发布、历史版本和恢复能力 | 编排平台已有能力应复用,不重复造轮子 | 医梦只做 Dify 版本映射、输出校验、配置灰度和回滚指针 | 不自研完整 Workflow 发布系统 |
 | 中医四诊仪公开产品 | 公开产品通常包含舌诊、面诊、脉诊、问诊和多模态采集/AI 分析 | 四诊仪不是普通屏幕,必须依赖厂商 SDK/API 或专精模型 | 首期只做舌/面采集、分析结果卡片和医生确认 | 不自研四诊硬件,不训练全量四诊模型 |
 | 《个人信息保护法》 | 医疗健康、行踪轨迹属于敏感个人信息,处理需特定目的、必要性和严格保护措施 | 服务找人和医疗数据链路必须最小化 | 主动签到只保留诊室门口到达事件,支持拒绝授权后降级 | 不保存患者连续轨迹,不做无感自动签到 |
+| 空海医院会议反馈 | 信息科主任认可“系统知道患者是谁、设备是谁、当前位置和下一步业务,主动把签到/结算/导航服务外显出来”的价值,同时强调门槛低、先做一个场景、不能假设全院蓝牙/星闪 | 动线和感知是本项目差异化表达,但必须按低门槛方案起步 | 第一阶段只做关键节点感知和服务卡片推送,优先老人、特殊人群、诊区签到、缴费/检查提醒 | 不把电梯控制、全院无感定位、腕带体系作为 P0 |
 
 参考来源:
 
@@ -70,6 +75,8 @@
 | Device Registry | 中 | 设备身份、心跳、位置、版本、准入 | 只管门诊 P0 设备;住院只记映射 | P1/P2 设备批量接入后置 |
 | Terminal Runtime | 高 | 多端兼容、扫码/读卡/打印/语音 Bridge、现场升级 | 首期 Web/H5 + Android WebView 壳,优先导诊屏/自助机/诊室屏 | Electron/Harmony 原生能力后置 |
 | Scene Orchestrator | 中 | 场景规则容易复杂化 | 先做设备到默认场景、默认智能体、UI 模板的静态绑定 | 动态位置/时间/用户状态规则后置 |
+| Journey Context | 中 | 业务状态来自 HIS/叫号/卡片动作/设备事件,容易变成复杂状态机 | P0 不独立建服务,先在 OpenPlatform 里用任务状态和设备事件生成 `journeyState` | 全院患者动线引擎、复杂路径优化后置 |
+| Perception Event | 中高 | 身份绑定、近场准确率、授权、误触发、安全合规 | P0 只接扫码/NFC/刷卡/人工确认和诊室门口事件 | 连续轨迹、全院定位、自动化触发后置 |
 | 服务找人 POC | 高 | 近场准确率、授权、误触发、叫号/HIS 联动 | 诊室门口小屏 + BLE/NFC/二维码兜底,只做主动签到 | 全院定位、路线推送后置 |
 | IoMT Event Hub | 高 | 病房设备边界、事件标准化、护理闭环 | 只接迪耐克/鸿蒙病房网关标准预警事件 | 原始体征流、复杂风险模型后置 |
 | 四诊仪 | 高 | 专用硬件、图像质量、厂商算法、医生采纳 | 舌/面图片采集 + 结果卡片 + 医生确认 | 脉诊、多厂商统一后置 |
@@ -103,6 +110,113 @@
 
 该取舍与行业实践一致:东软类智慧医院平台强调统一信息平台集成各子系统,华为/医惠类病房方案强调物联平台统一接入设备,Dify 官方已提供 Workflow 版本能力。医梦作为创业团队,应只做 AI 入口层、卡片闭环、设备场景治理和必要适配,不复制大厂完整医院平台和物联网底座。
 
+### 1.5 空海会议新增主轴:动线 + 感知
+
+空海会议中甲方真正感兴趣的不是“多接几个设备”,而是设备能理解患者当前处于哪条就医动线、应该外显哪个服务。产品表达应统一为:
+
+> 医梦 AI 未来医院不是简单接入智能设备,而是通过统一入口客户端和 AI 中台,把患者身份、当前位置、业务状态和设备能力统一感知起来,再基于患者全流程动线主动推送下一步服务,实现“患者少找路、少找窗口、少找设备,医院服务主动找人”。
+
+感知模型分为五类,P0 只做能低成本验证的部分:
+
+| 感知类型 | 含义 | P0 落地 | 不做 |
+| --- | --- | --- | --- |
+| 身份感知 | 知道当前服务对象是谁 | 扫码、刷卡、NFC、患者确认后绑定 `patientId/visitId/deviceId/terminalSessionId` | 无授权人脸识别、长期腕带绑定 |
+| 空间感知 | 知道患者在哪个服务区域 | 设备位置 + 诊室门口扫码/NFC/BLE 区域事件 | 全院连续轨迹、高精度室内定位 |
+| 业务状态感知 | 知道患者就医流程状态 | HIS/叫号/卡片动作返回:已挂号、待签到、候诊、待缴费、待检查、报告已出 | 跨系统大数据画像 |
+| 设备状态感知 | 知道当前设备能提供什么服务 | Device Registry 返回设备能力、场景、允许卡片和允许智能体 | 未准入设备进入核心业务 |
+| 风险感知 | 知道哪些动作必须确认或人工接管 | 高风险卡片 `confirm=true`,特殊人群优先提示,失败转人工 | 自动签到、自动缴费、自动诊断 |
+
+动线模型不是大型流程引擎,MVP 只做可解释的状态推导:
+
+```text
+VisitTimeline + TaskState + DeviceContext + DeviceEvent + CardAction
+→ JourneyContext
+→ Scene Orchestrator / AgentRouter
+→ 智能体、卡片、设备命令
+→ 用户确认
+→ 状态回写
+```
+
+第一期只实现 4 个可验收动线节点:
+
+| 动线节点 | 触发条件 | 外显服务 | 验收方式 |
+| --- | --- | --- | --- |
+| 到院/到诊区 | 患者扫码/NFC/刷卡或诊区近场事件 | 建档、签到、候诊提醒 | 能产生 `journeyState=WAITING_CHECKIN/WAITING_CALL` |
+| 就诊后待缴费 | HIS 或 Mock 返回缴费/处置单状态 | 缴费提醒、窗口/自助机引导 | 前端展示待办卡片,用户确认后跳转或转人工 |
+| 待检查/检验 | 医嘱/检查单状态 + 设备位置 | 检查导航、注意事项 | 机器人/屏幕能生成导航命令或路线卡 |
+| 报告已出/诊后 | 报告状态或就诊结束状态 | 报告解读卡、诊后小结/随访提醒 | 只展示辅助解释,不自动给诊断结论 |
+
+同一台设备必须按用户和动线阶段动态裁剪能力。例如诊室门口屏对普通患者只展示签到、候诊、缴费提醒;对医护人员可展示队列管理和人工接管;对未授权访客只展示公共导诊和科室介绍。这个差异通过 `sceneProfile + userContext + 服务端 journeyState + allowedAgents/allowedCards` 决定,前端不得自行放开能力。
+
+#### 1.5.1 SceneOrchestrator 与 AgentRouter 边界
+
+`SceneOrchestrator` 和 `AgentRouter` 都使用上下文,但职责不同,不能混成一个“大路由器”。
+
+| 组件 | 决策层级 | 输入 | 输出 | 调用时机 |
+| --- | --- | --- | --- | --- |
+| SceneOrchestrator | 设备/场景级 | `deviceId/deviceType`、设备状态、用户身份、服务端 `journeyState`、项目配置 | `homeTemplate`、`allowedAgents`、`allowedCards`、`blockedIntents`、`perceptionCapabilities`、`journeyPolicy` | `GET /devices/{deviceId}/scene`;每次 `/agent/chat/stream` 前复核 |
+| AgentRouter | 对话/任务级 | 用户输入、`TaskState`、等待卡片、服务端 `journeyState`、`allowedAgents/blockedIntents` | 具体 `agentId`、任务类型、是否创建卡片或设备命令 | 每次 `/agent/chat/stream` 内部执行 |
+
+调用顺序固定为:
+
+```text
+Device Registry / SceneOrchestrator
+→ 服务端 JourneyContext 推导
+→ AgentRouter 在 allowedAgents 范围内路由
+→ Dify / Direct / Mock
+→ Card Runtime / Device Command
+```
+
+禁止反向依赖:AgentRouter 不得绕过 SceneOrchestrator 放开设备不允许的智能体;前端不得用本地配置覆盖 `allowedAgents/allowedCards`。
+
+#### 1.5.2 感知能力配置与安全模型
+
+`perceptionCapabilities` 和 `journeyPolicy` 不是终端自声明字段。MVP 阶段配置来源如下:
+
+| 配置 | 来源 | 维护人 | P0 实现 |
+| --- | --- | --- | --- |
+| `perceptionCapabilities` | Device Registry 设备能力配置 | 医梦运维 / 项目交付 | 管理后台或 SQL 种子配置,终端只读取 |
+| `journeyPolicy` | 设备场景绑定配置 | 医梦运维 / 项目交付 | `MVP_STATIC`,控制是否展示动线区和服务找人入口 |
+| `allowedAgents/allowedCards` | 设备场景白名单 | 医梦运维 / 项目交付 | 后端强制校验,前端只渲染 |
+| 身份绑定策略 | 项目授权和患者确认策略 | 医院信息科 / 医梦交付 | 绑定、解绑、过期、拒绝授权降级 |
+
+感知事件安全链路:
+
+| 风险 | P0 防护 |
+| --- | --- |
+| 伪造设备事件 | 只有已注册、已激活、归属当前项目的设备可调用事件接口;请求必须通过 HMAC/Bearer 鉴权 |
+| 重放事件 | `eventId + deviceId + projectId` 幂等,服务端校验时间窗口和 nonce/signature |
+| 伪造动线阶段 | 客户端请求不得传 `journeyState`;即使通过扩展字段伪造,服务端也完全忽略 |
+| 近场误触发 | `NEARBY_DETECTED` 只作为感知事实,必须结合身份授权、HIS/叫号状态和患者确认后才生成卡片 |
+| 安全校验失败 | 降级为 L0 扫码、NFC、人工确认,不自动执行业务动作 |
+
+#### 1.5.3 P0 动线验收标准
+
+P0 验收采用 Given-When-Then,避免“到诊区”“服务找人”等概念不可测试。
+
+| 场景 | Given | When | Then |
+| --- | --- | --- | --- |
+| 到诊区主动签到 | 患者已挂号,设备已激活并绑定诊区,患者已授权身份绑定 | 患者在诊室门口屏刷卡/NFC 或扫描签到二维码 | SSE 返回 `journey_updated.stageCode=WAITING_CHECKIN`;创建主动签到卡;用户确认后才调用签到工具 |
+| 候诊提醒 | 患者已签到,叫号系统返回候诊状态 | 患者靠近候诊屏或自助机,或主动询问“还要等多久” | 返回 `journeyState.stageCode=WAITING_CALL`;展示候诊提醒卡,不暴露他人队列隐私 |
+| 就诊后缴费引导 | HIS/Mock 返回待缴费或处置状态 | 患者靠近自助机/导诊屏或发起缴费咨询 | 返回 `journeyState.stageCode=WAITING_PAYMENT`;展示缴费引导卡;P0 不做真实支付 |
+| 待检查导航 | HIS/Mock 返回待检查/检验状态,设备具备路线或导航能力 | 患者在机器人/导诊屏请求检查路线 | 返回 `journeyState.stageCode=WAITING_EXAM`;生成路线卡或机器人导航命令 |
+| 报告已出解释入口 | 报告状态已出,患者身份授权有效 | 患者在受控终端请求解读报告 | 返回报告解读入口卡;文件和报告内容走 File Service;不自动给正式诊断 |
+
+医护电梯场景拆分处理:普通患者电梯控制不进入 P0/P1;医护授权电梯可作为 P1 可选试点,前提是医院已有电梯控制 API 或物联平台能力。医梦只通过 MCP/Adapter 调用,不改造电梯系统,不把医护电梯作为门诊 MVP 交付前置条件。
+
+#### 1.5.4 运维配置闭环
+
+为支撑交付,管理后台至少需要形成以下配置能力。MVP 可以先用种子数据或内部配置页实现,但必须有明确归属。
+
+| 配置页面 | 关键字段 | MVP 要求 |
+| --- | --- | --- |
+| 设备准入审核 | `deviceId`、设备类型、院区/楼层/区域、`activateStatus`、准入等级 | P0 必须能激活/拒绝设备 |
+| 设备能力配置 | `capabilities`、`perceptionCapabilities`、Bridge 能力、厂商信息 | P0 可配置扫码/NFC/刷卡/摄像头/导航 |
+| 场景绑定配置 | `homeTemplate`、`allowedAgents`、`allowedCards`、`blockedIntents`、`journeyPolicy` | P0 必须支持按设备切换场景 |
+| 身份绑定策略 | 授权方式、绑定有效期、解绑规则、拒绝授权降级 | P0 可用固定项目配置 |
+| 动线规则配置 | `stageCode`、触发事件、依赖 HIS/Mock 状态、推荐卡片 | P0 可硬编码 + 文档化,P1 再后台化 |
+| 感知事件审计 | `eventId`、设备、区域、事件类型、处理结果、traceId | P0 必须可查询和回放 |
+
 ## 2. 当前工程基线
 
 ### 2.1 后端工程结构
@@ -271,6 +385,8 @@ flowchart TD
     WardEmbed["住院 AI 嵌入端<br/>护理白板 / 床头屏<br/>通过迪耐克/鸿蒙生态接入"]
     Device["Device Registry / Adapter<br/>设备身份 / 能力 / 心跳 / 厂商 SDK"]
     Scene["Scene Orchestrator<br/>设备-位置-场景-智能体绑定"]
+    Journey["Journey Context<br/>动线阶段 / 下一步任务 / 服务找人"]
+    Perception["Perception Event<br/>身份 / 空间 / 业务 / 设备 / 风险感知"]
     WardGateway["迪耐克/鸿蒙病房网关<br/>床头屏 / 护理白板 / IoMT 标准事件"]
     OpenAPI["OpenPlatform API<br/>签名鉴权 / 租户项目授权 / 限流 / 审计"]
     Engine["AgentEngine 路由层<br/>Dify / Direct / Mock"]
@@ -284,7 +400,10 @@ flowchart TD
 
     Client --> Device
     Device --> Scene
-    Scene --> OpenAPI
+    Device --> Perception
+    Perception --> Journey
+    Scene --> Journey
+    Journey --> OpenAPI
     Client --> OpenAPI
     WardEmbed --> WardGateway
     WardGateway --> Event
@@ -294,6 +413,7 @@ flowchart TD
     Dify --> MCP
     MCP --> HIS
     Device --> Event
+    Event --> Perception
     Event --> OpenAPI
     Dify --> OpenAPI
     OpenAPI --> Card
@@ -303,6 +423,7 @@ flowchart TD
     Card -.动作事件.-> Meter
     Device -.设备维度事件.-> Meter
     Event -.业务闭环事件.-> Meter
+    Journey -.动线服务事件.-> Meter
 ```
 
 ### 4.1 组件职责
@@ -314,6 +435,8 @@ flowchart TD
 | Device Registry | 设备身份、型号、位置、能力、状态、版本、智能体绑定、SLA 等级 | 直接调用 HIS 写业务 |
 | Device Adapter | 厂商 SDK/API、屏幕、机器人、自助机、四诊仪;住院侧仅适配迪耐克/鸿蒙病房标准接口 | 决定临床结果、财务扣费;不直接接管病房硬件设备 |
 | Scene Orchestrator | 根据设备、位置、时间、用户和业务状态选择 UI、智能体、工具权限 | 替代 Dify Workflow 的多轮医学编排 |
+| Perception Event | 接收和归一身份、空间、业务、设备、风险事件,形成可审计的感知事实 | 采集全院连续轨迹、替代医院物联平台 |
+| Journey Context | 根据 `VisitTimeline/TaskState/DeviceContext/DeviceEvent/CardAction` 推导患者当前动线阶段、下一步服务和允许动作 | 建设复杂路径优化引擎、自动完成高风险业务 |
 | Dify Workflow | 多轮对话、意图识别、条件分支、RAG、工具编排、自然语言回复 | 合同账本、额度扣减、财务结算 |
 | MCP Server | 院内系统工具封装、协议适配、幂等、熔断、降级、工具审计 | UI 渲染、合同管理 |
 | Card Runtime | 卡片定义、卡片实例、动作状态机、交互结果回传 | 直接绕过 MCP 操作 HIS |
@@ -465,6 +588,8 @@ C4Container
 | 设备注册服务 | system/mcp API 或新 Device Core | 设备注册、心跳、位置、能力 | `DeviceProfile`、在线状态、版本、智能体绑定 | 设备必须绑定医院/科室/位置,不能匿名接入核心闭环 |
 | 设备适配服务 | Device Core + 厂商 Adapter | SDK/API/驱动事件 | 标准设备能力协议 | 第三方设备只能通过适配层进入中台 |
 | 场景编排服务 | Device Core / OpenPlatform | 设备、位置、时间、用户、业务状态 | `sceneProfile`、UI 模板、Agent 绑定、工具权限 | 解决“同一设备不同场景加载什么” |
+| 动线上下文服务 | `emoon-openplatform` 内部服务,P1 可下沉到 Agent Core | `TaskState`、HIS/叫号状态、设备事件、卡片动作 | `journeyState`、下一步服务、推荐卡片 | MVP 不独立建微服务,不做全院路径优化 |
+| 感知事件接入 | Device Core / OpenPlatform | 扫码、NFC、刷卡、近场、业务状态回调 | 标准 `perceptionEvent`、审计记录 | 只存业务必要事件,不保存连续轨迹 |
 | Agent 编排服务 | `emoon-openplatform` | 对话请求、项目上下文 | `AgentResponse` | 查智能体、查引擎配置、路由引擎、写会话 |
 | Dify 引擎适配器 | `emoon-openplatform` 或 `emoon-mcp-api` 实现类 | `AgentRequest` | `AgentResponse` | 只负责协议转换,不负责计费、不直接调 HIS |
 | 卡片运行时服务 | `emoon-mcp-api` + 实现模块 | `cardKey`、卡片数据、动作请求 | 卡片实例、动作结果 | 创建快照、校验状态、动作幂等 |
@@ -910,7 +1035,7 @@ flowchart LR
 
 #### 5.10.3 服务找人主动签到 POC
 
-鸿蒙协同不应写成全院设备自动互联,而应落到“服务找人”的小闭环。第一期推荐主动签到 POC。
+鸿蒙协同不应写成全院设备自动互联,而应落到“服务找人”的小闭环。第一期推荐主动签到 POC。空海会议后,本节的正式口径应从“某个近场设备触发签到”升级为“感知到患者动线阶段后,把下一步服务外显到当前设备”,但 P0 仍只做诊区/诊室门口的低门槛场景。
 
 ```mermaid
 sequenceDiagram
@@ -935,6 +1060,25 @@ sequenceDiagram
 
 兜底路径必须同时存在:鸿蒙生态设备发现、星闪/近场通信、BLE Beacon、Wi-Fi/院内定位、二维码/NFC、小程序位置授权。签到、支付、挂号等动作都必须由患者确认,不能因为“服务找人”而自动完成高风险操作。
 
+感知能力分级:
+
+| 级别 | 能力 | 适用阶段 | 医梦职责 |
+| --- | --- | --- | --- |
+| L0 | 二维码、人工确认、终端点选 | 所有医院可用,P0 必备 | 提供卡片、接口和审计 |
+| L1 | NFC 碰一碰、刷卡、手机/手表确认 | P0 推荐 | 提供绑定和解绑流程,不保存长期轨迹 |
+| L2 | BLE Beacon / Wi-Fi 区域判断 | P1 试点 | 只判断是否进入服务区域,事件需患者确认后生效 |
+| L3 | 星闪 / 鸿蒙近场 / UWB 高精度 | 标杆 POC | 只在医院和设备方已有能力时接入,不作为首期交付前置条件 |
+
+服务找人触发表:
+
+| 动线状态 | 感知事实 | 推荐服务卡片 | 必须确认 |
+| --- | --- | --- | --- |
+| 已挂号未签到 | 患者到达诊区或诊室门口 | 主动签到卡、候诊队列提醒 | 是 |
+| 已就诊待缴费 | HIS/Mock 产生缴费或处置状态,患者靠近自助机/屏幕 | 缴费引导卡、窗口/自助机导航 | 是 |
+| 已缴费待检查 | 检查/检验状态存在,患者靠近机器人/导诊屏 | 检查导航卡、注意事项卡 | 否,导航可直接展示 |
+| 报告已出 | 报告状态更新,患者再次到院或打开终端 | 报告解读入口卡 | 是,涉及个人报告 |
+| 特殊人群 | 老人、孕产妇、轮椅、急诊等标签或人工标记 | 人工协助、优先引导、无障碍路线 | 是或人工确认 |
+
 近场设备硬件策略:
 
 | 方案 | 定位 | 适用条件 | 医梦责任 |

+ 63 - 0
docs/架构文档/空海会议动线感知方案影响说明.md

@@ -0,0 +1,63 @@
+# 空海医院会议对 AI 未来医院方案的影响说明
+
+| 项目 | 内容 |
+| --- | --- |
+| 文档定位 | 会议结论到需求、架构、接口设计的映射说明 |
+| 会议资料 | `back-info/会议总结.md`、`back-info/空海医院信息科主任.md`、空海医院演示 PDF 与功能清单 |
+| 适用文档 | `AI中台二期+三期需求技术方案.md`、`统一入口客户端技术设计文档_v1.0.md`、`terminal-client-mvp-contract.md`、OpenAPI v1.2 |
+| 更新时间 | 2026-06-03 |
+
+## 1. 核心结论
+
+空海医院会议把方案重点从“AI 中台接多种设备”推进到“动线 + 感知”:
+
+```text
+感知:知道患者是谁、设备在哪、当前业务状态是什么、设备能做什么、哪些动作有风险
+动线:判断患者处于就医流程哪个阶段,下一步该得到什么服务
+AI 中台:把感知事实转化为可确认、可审计、可计量的智能体服务
+统一入口客户端:在机器人、自助机、导诊屏、诊室屏等设备前把服务外显出来
+```
+
+对外表达应统一为:
+
+> 医梦 AI 未来医院不是简单接入智能设备,而是通过统一入口客户端和 AI 中台,把患者身份、当前位置、业务状态和设备能力统一感知起来,再基于患者全流程动线主动推送下一步服务,实现“患者少找路、少找窗口、少找设备,医院服务主动找人”。
+
+## 2. 甲方关注点
+
+| 关注点 | 方案影响 |
+| --- | --- |
+| “服务找人要外显化” | 统一入口客户端必须有动线区和下一步服务卡片,不应只是聊天页 |
+| “同一设备,不同用户能力不同” | `sceneProfile` 必须结合 `userContext/journeyState` 裁剪 `allowedAgents/allowedCards` |
+| “门槛越低越好,不能假设每家医院有星闪、蓝牙信标” | 感知能力必须分级,P0 从扫码/NFC/刷卡/人工确认起步 |
+| “只要能起步,先干一个场景,不要贪多” | 第一阶段只做诊区签到、缴费/检查提醒、路线导航等关键节点 |
+| “智能化和信息化结合是空白点” | 价值不在位置技术本身,而在 HIS/叫号/卡片动作/设备事件合并判断下一步 |
+| “物联网边界先确定” | 医梦不做全院物联平台,物联能力像 HIS 一样通过 MCP/Adapter 接入 |
+
+## 3. MVP 设计取舍
+
+| 能力 | P0 做法 | 暂不做 |
+| --- | --- | --- |
+| 身份感知 | 扫码、刷卡、NFC、患者确认绑定 `patientId/visitId/deviceId/sessionId` | 无授权人脸识别、长期腕带体系 |
+| 空间感知 | 设备点位 + 诊区/诊室门口服务区域事件 | 全院连续轨迹、高精度室内定位 |
+| 业务状态感知 | HIS/Mock、叫号、卡片动作、任务状态共同推导 | 跨系统大数据画像 |
+| 动线阶段 | `VisitTimeline + TaskState + DeviceContext + DeviceEvent + CardAction` 推导 `journeyState` | 独立复杂流程引擎、全院路径优化 |
+| 服务找人 | 主动签到、候诊提醒、缴费/检查/报告卡片 | 自动签到、自动缴费、自动诊断 |
+| 设备能力差异 | 后端返回 `allowedAgents/allowedCards/perceptionCapabilities/journeyPolicy` | 前端自行放开能力 |
+
+## 4. 文档修改映射
+
+| 文档 | 变更章节 | 已更新内容 |
+| --- | --- | --- |
+| `AI中台二期+三期需求技术方案.md` | §1.5、§1.5.1-§1.5.4、§4.1、§4.6、§5.10.3 | 新增“动线 + 感知”主轴、Scene/Router 边界、感知事件安全模型、运维配置闭环、服务找人触发表和 P0 验收标准 |
+| `统一入口客户端技术设计文档_v1.0.md` | §0.1、§2.2、§3.1、§3.2、§7.1 | 将统一入口客户端定义为“患者动线承载端 + 多设备 AI 场景运行时”,补充动线区、感知状态、服务端 `journeyState` 和 Router 动线优先 |
+| `terminal-client-mvp-contract.md` | §3.3、§4.1-§4.3、§8 | 增加可选 `perceptionContext`;明确 `journeyState` 只由服务端返回;`journey_updated` 为 P0;补充事件 payload 约束 |
+| `emoon-ai-openplatform-api-v1.2.openapi.yaml` | `PerceptionContext`、`JourneyState`、`AgentChatRequest`、`AgentChatData`、`DeviceSceneData`、`DeviceEventRequest` | 新增感知上下文、服务端只读动线状态、场景感知能力、动线策略和事件 payload 说明 |
+| `统一入口客户端前端工程启动指南.md` | §2、§3、§5、§7 | 明确前端布局、动线区、感知状态、P0 `journey_updated` 处理、禁止前端自行推断动线阶段 |
+
+## 5. 执行原则
+
+1. 先做节点感知,不做全院定位。
+2. 先做服务卡片外显,不做无感自动业务动作。
+3. 先做门诊关键动线,不扩展住院硬件责任。
+4. 先复用 OpenPlatform、Device Registry、TaskState、Card Runtime,不新增独立微服务。
+5. 先以患者确认和人工兜底保证安全,再逐步提升自动化体验。

+ 22 - 0
docs/架构文档/统一入口客户端前端工程启动指南.md

@@ -34,6 +34,8 @@ emoon-terminal-client
 | API SDK (`api-client`) | ✅ 统一调用 OpenPlatform | 无 |
 | 卡片组件 (`medical-cards`) | ✅ 科室卡、医生卡、号源卡、路线卡、舌诊卡 | 不同终端的 `allowedCards` 限制不同 |
 | Bridge (`terminal-bridge`) | ✅ 统一 JSBridge 抽象接口 | 机器人有导航;自助机有读卡/打印;导诊大屏能力最少 |
+| 动线区 (`journey-panel`) | ✅ 渲染后端 `journeyState` 和下一步服务 | 导诊屏偏公共导流,自助机偏业务办理,机器人偏导航 |
+| 感知状态 (`perception-status`) | ✅ 展示身份绑定、授权、扫码/NFC/刷卡状态 | 不同终端感知能力来自 `perceptionCapabilities` |
 | 主题 (`terminal-theme`) | ✅ 医梦主题 + 医院主题 | 屏幕尺寸、字体、按钮密度不同 |
 | 首页 | ✅ 聊天主控件可复用 | 三类终端首页布局不同 |
 
@@ -44,6 +46,8 @@ loadConfig(hospitalId, accessKey)
   → POST /devices/register        # 拿到 deviceId + activateStatus
   → setInterval 30s: POST /devices/{deviceId}/heartbeat
   → GET /devices/{deviceId}/scene  # 拿到 homeTemplate + allowedAgents + allowedCards
+  → initPerception(scene.perceptionCapabilities)
+  → initJourneyPanel(scene.journeyPolicy)
   → renderHome(homeTemplate)       # 根据 sceneCode 渲染首页
 ```
 
@@ -53,6 +57,18 @@ loadConfig(hospitalId, accessKey)
 - `activateStatus = "rejected"` → 展示拒绝原因 + 联系运维入口
 - `activateStatus = "activated"` → 正常进入
 
+首页推荐布局:
+
+```text
+顶部:设备/院区/身份绑定/授权状态
+左侧:公共快捷入口、人工服务、无障碍入口
+中央:AI 对话、虚拟形象、业务卡片
+右侧:当前动线阶段、下一步任务、排队/缴费/检查提醒
+底部:通知、异常、扫码/NFC/人工降级入口
+```
+
+`journeyState` 只能由后端返回后展示。前端可以上报扫码、NFC、刷卡、近场等 `perceptionContext` 或设备事件,但不能自行判断“已签到”“可缴费”“可挂号成功”。
+
 ## 4. 卡片组件渲染 MVP(P0 必须支持)
 
 | cardKey | 渲染要求 |
@@ -102,6 +118,10 @@ eventSource.on("card_created", (data) => {
   fetchAndRenderCard(data.cardInstanceId)  // 拉取卡片详情并渲染
 })
 
+eventSource.on("journey_updated", (data) => {
+  renderJourneyPanel(data)        // P0 必须处理;前端不得从 task/card 反推动线
+})
+
 eventSource.on("completed", (data) => {
   saveConversationId(data.conversationId)  // 记录,用于断线恢复
 })
@@ -130,6 +150,8 @@ npx openapi-typescript \
 | 直连 Dify API | 前端不决定流程编排 |
 | 直连 HIS / 舌诊底层接口 | 必须通过卡片动作闭环 |
 | 自行构造医疗建议文本 | 只展示后端返回的文本和卡片 |
+| 自行推导动线阶段并放开能力 | 动线阶段由后端结合 HIS/叫号/任务状态判断 |
+| 保存患者连续位置轨迹 | P0 只允许服务区域级事件,不保存移动路线 |
 | 隐藏 Mock 标识 | 后端返回 `"mock":true` 时必须标注"联调演示" |
 | 不传 `idempotencyKey` | 卡片动作必须带幂等键 |
 

+ 48 - 9
docs/架构文档/统一入口客户端技术设计文档_v1.0.md

@@ -10,9 +10,9 @@
 
 ## 0. 文档结论
 
-统一入口客户端不是一个普通聊天页面,也不是现有 Demo 的简单产品化。它应被定义为:
+统一入口客户端不是一个普通聊天页面,也不是现有 Demo 的简单产品化。空海医院会议后,它应被定义为:
 
-> **部署在机器人、自助机、导诊大屏等门诊终端上的多设备 AI 场景运行时。前端负责统一交互,后端负责设备上下文、会话任务、Agent 路由、Dify 编排、卡片动作、工具调用、文件治理、审计计量。**
+> **部署在机器人、自助机、导诊大屏、诊室门口屏等门诊终端上的患者动线承载端 + 多设备 AI 场景运行时。前端负责把当前动线阶段、下一步服务和业务卡片外显出来;后端负责身份/空间/业务/设备/风险感知、设备上下文、会话任务、Agent 路由、Dify 编排、卡片动作、工具调用、文件治理、审计计量。**
 
 一期建设目标不是“大而全 AI 医院”,而是先打穿三条生产级主链路:
 
@@ -27,6 +27,7 @@
 ```text
 统一入口客户端
 → 设备注册 / 场景配置
+→ 感知事件 / 患者动线阶段
 → 会话与任务状态
 → AgentRouter 后端路由
 → Dify Workflow 场景编排
@@ -46,6 +47,32 @@
 | 当前没有 HIS 接口时必须显式使用 `HisMockAdapter` | 禁止把随机医生、随机号源写在前端、Dify 或 ChatService 中 |
 | 导诊大屏不处理患者隐私 | 不允许身份证上传、舌象采集、报告解读、个人挂号确认 |
 | 舌诊已有接口也必须纳入中台 | 统一走 File Service + TongueDiagnosisAdapter,不允许前端直连 |
+| 动线和感知不由前端推断 | 前端只上报设备事件和用户确认,`journeyState` 由后端结合 HIS/叫号/任务状态推导 |
+
+### 0.1 空海会议后的产品定位修正:动线 + 感知
+
+甲方认可的核心不是“屏幕会聊天”,而是“任何一个设备面前,设备可以感知到你的动线阶段,并按当前阶段提供智能体服务”。因此统一入口客户端的第一屏不应只围绕对话框设计,而应同时呈现:
+
+| 区域 | 作用 | MVP 规则 |
+|---|---|---|
+| 顶部状态区 | 设备、院区、场景、身份绑定状态 | 未绑定身份时只显示公共服务 |
+| 左侧快捷区 | 高频公共服务、人工服务、无障碍入口 | 不出现该设备不允许的能力 |
+| 中央交互区 | AI 对话、虚拟形象、业务卡片 | 卡片动作必须走后端 Card Runtime |
+| 右侧动线区 | 当前就医阶段、下一步任务、排队/缴费/检查提醒 | 数据来自后端 `journeyState`,前端不得自行推断 |
+| 底部通知区 | 设备异常、授权提醒、降级入口 | 位置/身份授权失败时必须可扫码或人工处理 |
+
+同一台设备面向不同用户必须有不同能力。例如诊室门口屏对未授权访客只展示科室介绍;对已挂号患者展示签到/候诊;对医护人员展示队列和人工接管。该差异由 `sceneProfile + userContext + 服务端 journeyState + allowedAgents/allowedCards` 决定。
+
+感知能力按低门槛优先:
+
+| 级别 | 能力 | 一期采用 |
+|---|---|---|
+| L0 | 扫码、人工确认、终端点选 | 必做 |
+| L1 | NFC 碰一碰、刷卡、手机确认 | 推荐 |
+| L2 | BLE Beacon / Wi-Fi 区域判断 | 可试点 |
+| L3 | 星闪 / 鸿蒙 / UWB 高精度 | 只作为标杆 POC,不作为交付前置 |
+
+第一期只承诺关键节点感知,不承诺全院无感定位、连续轨迹、自动签到、自动缴费和自动诊断。
 
 ---
 
@@ -118,6 +145,8 @@
 |---|---|---|
 | P0 | Device Registry MVP | 设备注册、心跳、能力、场景绑定 |
 | P0 | Scene Profile | 不同终端加载不同首页、Agent 和卡片权限 |
+| P0 | Perception Event MVP | 扫码、NFC、刷卡、设备交互和诊区近场事件接入 |
+| P0 | Journey Context MVP | 根据任务状态、设备事件和 HIS/Mock 状态返回当前动线阶段 |
 | P0 | Agent Chat Stream | 统一替换 Demo `/chat/messages` |
 | P0 | AgentRouter | 后端统一路由到不同 Dify App |
 | P0 | Conversation Service | 会话和消息持久化、断线恢复 |
@@ -139,6 +168,7 @@
 医保结算
 退号退费
 全院鸿蒙无感定位
+患者连续轨迹
 医生站插件
 住院入口
 完整账单中心
@@ -164,6 +194,8 @@ flowchart TB
         Auth["鉴权与项目上下文 AuthContextResolver"]
         Device["设备上下文 DeviceContextResolver"]
         Scene["场景配置 SceneProfileService"]
+        Perception["感知事件 PerceptionEventService"]
+        Journey["动线上下文 JourneyContextService"]
         Conversation["会话服务 ConversationService"]
         Task["任务状态机 TaskStateService"]
         Router["AgentRouter:设备策略 + 任务状态 + 规则 + LLM 分类"]
@@ -193,7 +225,7 @@ flowchart TB
     Kiosk --> OpenPlatform
     Screen --> OpenPlatform
 
-    OpenPlatform --> Auth --> Device --> Scene --> Conversation --> Task --> Router --> Dispatcher
+    OpenPlatform --> Auth --> Device --> Scene --> Perception --> Journey --> Conversation --> Task --> Router --> Dispatcher
 
     Dispatcher --> Guide
     Dispatcher --> Triage
@@ -222,6 +254,8 @@ flowchart TB
 | Terminal Client | 交互、卡片展示、语音/摄像头/扫码/导航 Bridge | 不做最终业务判断 |
 | Device Registry | 设备身份、能力、位置、心跳、版本、场景绑定 | 不处理医疗业务 |
 | Scene Profile | 根据设备类型返回首页模板、允许 Agent、允许卡片、禁止意图 | 不调用模型 |
+| PerceptionEventService | 接收扫码、NFC、刷卡、近场、设备交互和业务状态事件 | 不保存患者连续轨迹,不自建全院定位平台 |
+| JourneyContextService | 推导当前动线阶段、下一步服务、可展示卡片和服务找人触发条件 | 不自动签到、自动缴费、自动诊断 |
 | Conversation Service | 会话、消息、上下文、断线恢复 | 不做意图判断 |
 | TaskStateService | 多轮任务实例、currentStep、任务上下文 | 不调用 Dify |
 | AgentRouter | 统一路由到 Dify App | 不生成医学回答 |
@@ -233,6 +267,8 @@ flowchart TB
 | TongueDiagnosisAdapter | 封装已有舌诊接口 | 不允许前端直连 |
 | Audit/Meter/Trace | 审计、计量、链路追踪、排障 | 不参与医疗判断 |
 
+`Scene Profile` 和 `AgentRouter` 的边界必须固定:`Scene Profile` 负责设备/场景级权限裁剪,返回 `allowedAgents/allowedCards/homeTemplate/perceptionCapabilities/journeyPolicy`;`AgentRouter` 只能在 `allowedAgents` 范围内,根据用户输入、任务状态和服务端 `journeyState` 选择具体 Dify App。前端不得用本地配置覆盖场景白名单。
+
 ---
 
 ## 4. 前端工程设计
@@ -477,6 +513,7 @@ SSE 事件示例:
 ```text
 设备策略
 + 当前场景
++ 当前动线阶段
 + 当前会话
 + 当前任务状态
 + 等待卡片状态
@@ -490,17 +527,19 @@ SSE 事件示例:
 | 顺序 | 决策层 | 说明 |
 |---:|---|---|
 | 1 | 设备策略 | 当前终端能不能做这件事 |
-| 2 | 当前任务 | 有 activeTask 时优先推进当前任务 |
-| 3 | 等待卡片 | 有待操作卡片时优先处理卡片动作或提示 |
-| 4 | 确定性规则 | 舌诊、挂号、带我去、我要建档 |
-| 5 | FAQ / 知识库 | 公共问答优先走导诊 Agent |
-| 6 | LLM 分类 | 规则无法判断时兜底 |
-| 7 | 反问澄清 | 低置信度时不强行进入流程 |
+| 2 | 动线阶段 | 已挂号未签到、待缴费、待检查等状态优先推荐下一步服务 |
+| 3 | 当前任务 | 有 activeTask 时优先推进当前任务 |
+| 4 | 等待卡片 | 有待操作卡片时优先处理卡片动作或提示 |
+| 5 | 确定性规则 | 舌诊、挂号、带我去、我要建档 |
+| 6 | FAQ / 知识库 | 公共问答优先走导诊 Agent |
+| 7 | LLM 分类 | 规则无法判断时兜底 |
+| 8 | 反问澄清 | 低置信度时不强行进入流程 |
 
 一期 MVP 不实现完整规则推理引擎,也不把 `deterministicRouter`、`faqRouter`、`llmIntentClassifier` 做成三套复杂子系统。第一期路由收敛为:
 
 ```text
 设备策略
+→ 动线阶段优先
 → 活跃任务优先
 → 等待卡片优先
 → 少量确定性关键词(挂号 / 舌诊 / 带我去 / 建档 / 查科室)

+ 100 - 0
reasonix.toml

@@ -0,0 +1,100 @@
+# Reasonix configuration.
+# Resolution order: flag > ./reasonix.toml > ~/.config/reasonix/config.toml > built-in defaults.
+# Secrets come from the environment via api_key_env; never put keys here.
+
+default_model = "deepseek-flash"
+language      = "zh"   # ui/model language; empty = auto-detect from $LANG / $REASONIX_LANG
+
+[ui]
+theme = "auto"   # auto|dark|light; CLI colors only; REASONIX_THEME can override per run
+# theme_style = "graphite"   # graphite|ember|aurora|midnight|sandstone|porcelain|linen|glacier
+
+[network]
+proxy_mode = "auto"   # auto|env|custom|off; auto currently uses env proxy
+# proxy_url  = "socks5://127.0.0.1:7890"   # optional custom override
+# no_proxy   = "localhost,127.0.0.1,.local"   # honored for proxy_mode = "custom"
+
+[network.proxy]
+type = "socks5"   # http|https|socks5|socks5h
+# server = "127.0.0.1"
+# port = 7890
+# username = ""
+# password = "${REASONIX_PROXY_PASSWORD}"   # optional; supports ${VAR} expansion
+
+[agent]
+system_prompt = """
+You are Reasonix, a coding agent focused on executing code tasks.
+Use the provided tools to read and write files and run shell commands.
+Principles: understand the request before acting; verify with tools instead of
+guessing; keep changes minimal and correct; briefly summarize what you did.
+When the request leaves a real choice to the user — which approach or library,
+the scope, or a consequential or ambiguous decision — call the ask tool to offer
+2-4 concrete options rather than guessing or burying the question in prose. Skip
+it when there's an obvious default; don't ask just to confirm.
+For multi-step work, track progress with the todo_write tool: lay out the steps,
+keep exactly one in_progress, and flip each to completed as you finish it — update
+the list as you go, not just at the end.
+In plan mode the harness blocks writer tools: do read-only research, then write a
+concise plan as your reply and stop. The user is asked to approve before anything
+is changed; once approved, work through the steps, updating the task list as you go."""
+# system_prompt_file = "prompts/system.md"   # overrides system_prompt when set
+max_steps   = 0
+temperature = 0.0
+auto_plan   = "ask"   # off|ask|on; ask/on auto-enter plan mode for complex tasks
+# auto_plan_classifier = "deepseek-flash"   # optional; only used for borderline tasks
+# planner_model = "mimo"   # optional: enable two-model collaboration
+# subagent_model = "deepseek-pro"   # optional default for runAs=subagent skills
+# subagent_models = { review = "deepseek-pro", security_review = "deepseek-pro" }   # per-skill overrides
+# output_style = "explanatory"   # explanatory | learning | concise | custom; empty = default
+
+[[providers]]
+name        = "deepseek-flash"
+kind        = "openai"
+base_url    = "https://api.deepseek.com"
+models      = ["deepseek-v4-flash"]
+default     = "deepseek-v4-flash"
+api_key_env = "DEEPSEEK_API_KEY"
+balance_url = "https://api.deepseek.com/user/balance"   # optional; wallet-balance endpoint shown in the status bar
+context_window = 1000000   # tokens; compaction triggers near this limit
+price       = { cache_hit = 0.02, input = 1, output = 2, currency = "¥" }   # per 1M tokens
+
+[tools]
+enabled = []   # empty = all built-in tools
+
+[skills]
+# paths = ["~/my-skills", "../shared/skills"]   # extra custom skill roots
+
+[permissions]
+# Per-call gating. mode = writer fallback when no rule matches: ask|allow|deny.
+# Readers always default to allow. Precedence: deny > ask > allow > fallback.
+# Rules are "ToolName" or "ToolName(glob)"; '*' matches any run, '?' one char.
+mode  = "ask"
+# deny = ["bash(rm -rf*)", "bash(git push*)"]   # hard-blocked in every mode
+# allow = ["bash(go test*)", "bash(git status*)"]   # never prompted
+# ask = ["write_file"]   # force a prompt even if otherwise allowed
+
+[sandbox]
+# Confine tool blast radius. File-writers (write_file/edit_file/multi_edit)
+# may only write under workspace_root (empty = current dir) + allow_write.
+# bash = "enforce" (default) jails each command in an OS sandbox (macOS now;
+# graceful fallback elsewhere); "off" disables it. network allows egress.
+# workspace_root = ""            # default: current working directory
+# allow_write = ["/tmp"]          # extra dirs writers may also modify
+bash    = "enforce"
+network = true
+
+[statusline]
+# A custom status line: a command whose first stdout line replaces the built-in
+# data row. It receives {"model","contextUsed","contextWindow"} as JSON on stdin.
+# command = "my-statusline.sh"
+
+# External MCP servers. type: "stdio" (default, a subprocess) | "http" | "sse".
+# ${VAR} / ${VAR:-default} are expanded from the environment in command/args/env/url/headers.
+# [[plugins]]
+# name    = "example"
+# command = "reasonix-plugin-example"
+# [[plugins]]                                  # a remote server over Streamable HTTP
+# name    = "stripe"
+# type    = "http"
+# url     = "https://mcp.stripe.com"
+# headers = { Authorization = "Bearer ${STRIPE_KEY}" }