feat(gateway): 面 1 补齐 —— 消息读取面 toolCalls[](工具回看)
前提由 FV2 提供(图自 v0.77 起带每路 turnId、每路各落一行)。本片:
- 迁移 0023:flow_graphs 加「按路查询键」(写入时回填图的 TurnID),老行按缺席处理
- GET /api/v1/sessions/{id}/messages 加**可选** toolCalls[],形状严格照 Docs/api-client.md
v0.76 ① 已登记的:{name, status(ok|error|unknown), durationMs, argsSummary, resultSummary}
- 🔴 图取不到 ⇒ **字段整体缺席**(绝不回空数组冒充「没调过工具」)
- 一条批量 SQL(按页内 turnId 集合),禁 N+1;单条 ≤20 个工具、resultSummary ≤500 字符(常量+依据)
- 只放图里已有的、已脱敏内容,不放宽脱敏通道
This commit is contained in:
1 parent
99a644d545
commit
c907a34510
10 files changed
+1429
-16
No files matched your search
@@ -0,0 +1,8 @@
|
||||
-- 0023 的回滚:先删索引、再删列(SQLite 3.35+ 的 DROP COLUMN;索引必须先走,
|
||||
-- 否则「被索引的列不能删」会让回滚失败)。
|
||||
--
|
||||
-- 本迁移只**加**一列与一个索引,不改任何既有列/行语义 ⇒ 回滚不触碰 0022 的
|
||||
-- 表结构、唯一键与保留期索引,也不丢图(图仍在 graph_json 里)。
|
||||
DROP INDEX IF EXISTS idx_flow_graphs_lane_turn_id;
|
||||
|
||||
ALTER TABLE flow_graphs DROP COLUMN lane_turn_id;
|
||||
@@ -0,0 +1,48 @@
|
||||
-- 0023_flow_graphs_lane_turn_id: 给 `flow_graphs` 一张**按路查询的键**(切片 CODE-TC)。
|
||||
--
|
||||
-- 动因(安卓侧需求,主人 2026-10-05 裁定):`GET /api/v1/sessions/{id}/messages`
|
||||
-- 要能回看「这条回复当时调了什么工具」,数据源是**已落盘的轮次链路图**
|
||||
-- (`flow_graphs`,迁移 0022),**不从正文反解、不靠时间窗猜**。要做到这一点,
|
||||
-- 消息行里的 `chat_messages.turn_id`(= 编排器生成的**路标识**,迁移 0018)必须能
|
||||
-- 按**等值**查到它那一轮的图 —— 而 0022 的 `turn_id` 列存的是 `trace.FlowGraph.ID`
|
||||
-- (形如 `web-7` / `web-7#turn-a`),与消息的 turn_id **不同源**。这正是
|
||||
-- Docs/api-client.md v0.76 把 `toolCalls[]` 登记为「未实现」的实测阻塞。
|
||||
--
|
||||
-- 列名刻意**不叫** `turn_id`(那个名字已被 0022 占用,语义是图 id)。`lane_turn_id`
|
||||
-- 的语义一句话:**这一路**的权威回合标识,与 `chat_messages.turn_id` 同值同源
|
||||
-- (`trace.FlowGraph.TurnID` / design/15 §2.5.9)。写入侧 `RecordRound` 每次都盖;
|
||||
-- 它为空时该行**不可按路查到**,读取侧据此让 `toolCalls` 整体缺席。
|
||||
--
|
||||
-- 兼容老行(三类,都不做假):
|
||||
-- ① **v0.77 起写入的真并行路行**:图 JSON 里已带 `$.turnId` ⇒ 本迁移用
|
||||
-- `json_extract` 就地回填,不必重跑任何轮次;
|
||||
-- ② **v0.77 之前写入的行**:图里根本没有这个字段(那时还没加)⇒ 回填后仍是 `''`;
|
||||
-- ③ **单路回合的行**:它的图**当前不带** `$.turnId`(该键只对真并行路存在,
|
||||
-- 见 `internal/runtime/loop/flow.go` 的 `flowOwner`)⇒ 同样回填成 `''`。
|
||||
-- ②③ 的空串是**诚实的空**:读侧因此查不到这一轮的工具、`toolCalls` 整体缺席 ——
|
||||
-- 正是契约登记的语义(「图取不到 ⇒ 字段缺席」,**绝不回空数组**冒充「没调过工具」)。
|
||||
-- 这三类都不是本迁移能补齐的(缺口在写侧),因此本迁移只**如实落列**、不编造值。
|
||||
--
|
||||
-- 列口径与 0018 的 `chat_messages.turn_id` 逐字一致:`TEXT NOT NULL DEFAULT ''`,
|
||||
-- **绝不用 NULL** ⇒「旧行」与「没写」是同一个值,读侧只有一种空情形要处理。
|
||||
-- 命名沿用既有迁移口径(表名复数、索引 idx_{table}_{col};援引 AGENTS §10 的
|
||||
-- 已登记例外)。
|
||||
|
||||
ALTER TABLE flow_graphs ADD COLUMN lane_turn_id TEXT NOT NULL DEFAULT '';
|
||||
|
||||
-- 一次性回填:只碰**还空着**的行。本迁移是第一次写这一列,此刻全空;条件仍写上,
|
||||
-- 使本语句重复执行时幂等,且日后绝不会抹掉 RecordRound 写进去的值。
|
||||
-- `json_type(...) = 'text'` 把「不是字符串的值」(畸形外部改动)排除在外;
|
||||
-- `json_valid` 兜底被写坏的 JSON。两者都不成立的行保持 `''` —— 让整次迁移因一条
|
||||
-- 坏行而回滚、后端起不来,是远超它应有代价的处置。
|
||||
UPDATE flow_graphs
|
||||
SET lane_turn_id = json_extract(graph_json, '$.turnId')
|
||||
WHERE lane_turn_id = ''
|
||||
AND json_valid(graph_json)
|
||||
AND json_type(graph_json, '$.turnId') = 'text';
|
||||
|
||||
-- 读侧的**唯一**依赖:一页消息的路标识集合一次 `IN` 查完(禁 N+1)。
|
||||
-- 前导列是 session_id —— 所有查询都带 `session_id = ?` 收敛到本会话,只索引
|
||||
-- lane_turn_id 一列会让规划器退化成扫本会话全表。
|
||||
CREATE INDEX IF NOT EXISTS idx_flow_graphs_lane_turn_id
|
||||
ON flow_graphs (session_id, lane_turn_id);
|
||||
Reference in new issue
Block a user