# Divination Run Protocol (Frontend <-> Backend) This document defines the structured contract for divination run input, backend hexagram derivation, and run event output. Protocol verification status: - Backend route source: `backend/src/v1/agent/router.py` - Backend derivation source: `backend/src/core/divination/derivation.py` - Runtime payload schema source: `backend/src/schemas/domain/divination.py` ## Compatibility strategy - Current strategy: additive evolution only. - Existing required fields cannot be removed or renamed without migration notes. - Canonical divination terminology values must remain Chinese. ## Route overview - Submit run: `POST /api/v1/agent/runs` - Stream events: `GET /api/v1/agent/runs/{threadId}/events?runId=...` - History snapshot: `GET /api/v1/agent/history` ## Run request contract `RunAgentInput` uses AG-UI shape. This protocol constrains two sections: 1) `messages[0].content` (question text) 2) `forwardedProps.divinationPayload` (structured divination input) ### Required request shape ```json { "threadId": "uuid", "runId": "run_20260403_xxx", "state": {}, "messages": [ { "id": "msg_run_20260403_xxx_user_0", "role": "user", "content": "我最近换工作是否合适?" } ], "tools": [], "context": [], "forwardedProps": { "runtime_mode": "chat", "client_time": { "device_timezone": "Asia/Shanghai", "client_now_iso": "2026-04-03T20:30:00+08:00", "client_epoch_ms": 1775219400000 }, "divinationPayload": { "divinationMethod": "手动起卦", "questionType": "事业", "question": "我最近换工作是否合适?", "divinationTimeIso": "2026-04-03T20:30:00+08:00", "yaoLines": [ "少阳", "少阴", "老阳", "少阴", "少阳", "老阴" ] } } } ``` ### AG-UI required base fields - `state`: required object, frontend sends `{}` by default. - `messages[0].id`: required string id for user message. - `tools`: required array, frontend sends empty array when no tools requested. - `context`: required array, frontend sends empty array when no extra context. ### `divinationPayload` strict rules - `divinationMethod`: enum, allowed values `手动起卦 | 自动起卦` - `questionType`: non-empty string, recommended Chinese category labels - `question`: non-empty string - `divinationTimeIso`: RFC3339 datetime with timezone offset - `yaoLines`: exactly 6 items, order is `初爻 -> 上爻` - `yaoLines` item enum: `少阳 | 少阴 | 老阳 | 老阴` - Additional fields are forbidden. ## Event output contract During run streaming, backend emits standard AG-UI lifecycle events and two divination-relevant payload events: ### 1) `DIVINATION_DERIVED` - Emitted once after backend derives hexagram data. - Payload field: `divination` (strict object). `divination` object: ```json { "question": "我最近换工作是否合适?", "questionType": "事业", "divinationMethod": "手动起卦", "divinationTime": "2026年04月03日 20:30", "binaryCode": "101001", "changedBinaryCode": "100001", "guaName": "山火贲", "upperName": "艮", "lowerName": "离", "targetGuaName": "山雷颐", "worldPosition": 1, "responsePosition": 4, "hasChangingYao": true, "ganzhi": { "yearGanZhi": "丙午", "monthGanZhi": "壬辰", "dayGanZhi": "辛亥", "timeGanZhi": "乙巳", "yearKongWang": "子丑", "monthKongWang": "午未", "dayKongWang": "寅卯", "timeKongWang": "戌亥", "yueJian": "辰土", "riChen": "亥水", "yuePo": "戌土", "riChong": "巳火" }, "wuXingStatuses": { "木": "囚", "火": "休", "土": "旺", "金": "相", "水": "死" }, "yaoInfoList": [ { "position": 1, "spiritName": "虎", "relationName": "官鬼", "tiganName": "卯", "elementName": "木", "isYang": true, "isChanging": false, "specialMark": "世" } ], "targetYaoInfoList": [], "fushenPositions": [2], "fushenInfoList": [ { "position": 2, "relationName": "父母", "tiganName": "午", "elementName": "火" } ] } ``` ### 2) `TEXT_MESSAGE_END` - Standard final answer event. - Existing fields remain canonical: `sign_level`, `summary`, `conclusion`, `focus_points`, `advice`, `keywords`, `answer`. Frontend should combine: - structural divination data from `DIVINATION_DERIVED` - interpretation text from `TEXT_MESSAGE_END` ## History snapshot contract `GET /api/v1/agent/history` is the canonical replay source for frontend history list and result reconstruction. ### Required response shape ```json { "scope": "history_day", "threadId": "uuid|null", "day": "2026-04-05|null", "hasMore": false, "messages": [ { "id": "uuid", "seq": 12, "role": "assistant", "content": "...", "timestamp": "2026-04-05T12:34:56+00:00", "agent_output": { "status": "success", "sign_level": "中上签", "summary": "...", "conclusion": ["..."], "focus_points": ["..."], "advice": ["..."], "keywords": ["..."], "answer": "...", "key_points": ["..."], "result_type": "structured_payload", "suggested_actions": ["..."], "divination_derived": { "binaryCode": "101001", "changedBinaryCode": "100001", "guaName": "山火贲" } } }, { "id": "uuid", "seq": 11, "role": "user", "content": "我最近换工作是否合适?", "timestamp": "2026-04-05T12:34:12+00:00", "attachments": [ { "mimeType": "image/png", "url": "https://...signed..." } ] } ] } ``` Rules: - `assistant` message MUST provide `agent_output` when backend has valid worker output metadata. - `agent_output.divination_derived` uses the same shape as `DIVINATION_DERIVED.divination` payload. - Frontend reconstructs divination result page from `agent_output` data, not from local mock data. - `agent_output.sign_level` allowed values: `上上签` / `中上签` / `中下签` / `下下签`. ### Breaking change note - `ui_schema` is removed from history response and is no longer part of this project protocol. - This repository currently accepts non-backward-compatible protocol evolution (no production compatibility burden). ## Error contract linkage - All errors use RFC7807 with extension `code` and optional `params`. - Error code registry source: `docs/protocols/common/http-error-codes.md`.