@whispering233/ai-editor-db 0.0.29 → 0.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/connection.js +1 -1
  2. package/dist/connection.js.map +1 -1
  3. package/dist/index.d.ts +0 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +4 -2
  6. package/dist/index.js.map +1 -1
  7. package/dist/migrations/003_timepoint.js +1 -1
  8. package/dist/migrations/003_timepoint.js.map +1 -1
  9. package/dist/migrations/004_setting_tags.js +2 -2
  10. package/dist/migrations/004_setting_tags.js.map +1 -1
  11. package/dist/migrations/005_reference.js +2 -2
  12. package/dist/migrations/005_reference.js.map +1 -1
  13. package/dist/migrations/006_sessions_jsonl.d.ts +4 -0
  14. package/dist/migrations/006_sessions_jsonl.d.ts.map +1 -0
  15. package/dist/migrations/006_sessions_jsonl.js +95 -0
  16. package/dist/migrations/006_sessions_jsonl.js.map +1 -0
  17. package/dist/migrations/index.d.ts +8 -3
  18. package/dist/migrations/index.d.ts.map +1 -1
  19. package/dist/migrations/index.js +13 -5
  20. package/dist/migrations/index.js.map +1 -1
  21. package/dist/migrations/legacy-sessions.d.ts +24 -0
  22. package/dist/migrations/legacy-sessions.d.ts.map +1 -0
  23. package/dist/migrations/legacy-sessions.js +69 -0
  24. package/dist/migrations/legacy-sessions.js.map +1 -0
  25. package/dist/queries/compute-state.d.ts +3 -3
  26. package/dist/queries/compute-state.js +5 -5
  27. package/dist/queries/delta.d.ts +4 -4
  28. package/dist/queries/delta.d.ts.map +1 -1
  29. package/dist/queries/delta.js +5 -5
  30. package/dist/queries/delta.js.map +1 -1
  31. package/dist/queries/entity.d.ts +11 -11
  32. package/dist/queries/entity.d.ts.map +1 -1
  33. package/dist/queries/entity.js +30 -30
  34. package/dist/queries/entity.js.map +1 -1
  35. package/dist/queries/migration.d.ts +13 -9
  36. package/dist/queries/migration.d.ts.map +1 -1
  37. package/dist/queries/migration.js +16 -11
  38. package/dist/queries/migration.js.map +1 -1
  39. package/dist/queries/outline-ops.d.ts +11 -11
  40. package/dist/queries/outline-ops.d.ts.map +1 -1
  41. package/dist/queries/outline-ops.js +15 -15
  42. package/dist/queries/outline-ops.js.map +1 -1
  43. package/dist/queries/relation.d.ts +6 -6
  44. package/dist/queries/relation.d.ts.map +1 -1
  45. package/dist/queries/relation.js +9 -9
  46. package/dist/queries/relation.js.map +1 -1
  47. package/dist/queries/trash.d.ts +3 -3
  48. package/dist/queries/trash.d.ts.map +1 -1
  49. package/dist/queries/trash.js +3 -3
  50. package/dist/queries/trash.js.map +1 -1
  51. package/dist/query-db.js +1 -1
  52. package/dist/query-db.js.map +1 -1
  53. package/dist/schema.d.ts +5 -3
  54. package/dist/schema.d.ts.map +1 -1
  55. package/dist/schema.js +6 -4
  56. package/dist/schema.js.map +1 -1
  57. package/dist/storage/atomic.d.ts +1 -1
  58. package/dist/storage/atomic.js +3 -3
  59. package/dist/storage/atomic.js.map +1 -1
  60. package/dist/storage/outline.js +1 -1
  61. package/dist/storage/project.d.ts +2 -2
  62. package/dist/storage/project.js +3 -3
  63. package/dist/storage/project.js.map +1 -1
  64. package/dist/tables.d.ts +3 -162
  65. package/dist/tables.d.ts.map +1 -1
  66. package/dist/tables.js +14 -40
  67. package/dist/tables.js.map +1 -1
  68. package/package.json +3 -4
  69. package/dist/queries/chat.d.ts +0 -85
  70. package/dist/queries/chat.d.ts.map +0 -1
  71. package/dist/queries/chat.js +0 -248
  72. package/dist/queries/chat.js.map +0 -1
@@ -1,85 +0,0 @@
1
- import { type ChatMessage, type ChatMessageRow, type ChatRole, type ChatSessionSummary } from "@whispering233/ai-editor-shared";
2
- import type { Db } from "../connection.js";
3
- /** 会话列表 lastMessage 截断长度( 仅要求「截断」,长度为本实现约定,未入文档) */
4
- export declare const SESSION_LAST_MESSAGE_MAX_LEN = 50;
5
- /**
6
- * 插入一条对话消息。
7
- *
8
- * id 生成约定:chat_messages 表 id 无文档前缀( id 约定仅覆盖
9
- * char-/set-/loc-/hook-、sc-/ch-/vol-、proj- 与运行时 prop_/sess_/call_),
10
- * 省略 id 时直接用 nanoid 生成(与消息 id 前缀空缺保持一致)。
11
- *
12
- * 存储形态转换:row.tool_calls 按 shared 类型为「解析后的数组」,
13
- * 本函数负责 JSON.stringify 落库(列存 TEXT);created_at 必须由调用方
14
- * 提供 ISO 8601 字符串(应用层写入)。
15
- */
16
- export declare function insertChatMessage(db: Db, row: Pick<ChatMessageRow, "session_id" | "project_id" | "role" | "created_at"> & Partial<Pick<ChatMessageRow, "id" | "content" | "tool_calls" | "tool_call_id">>): void;
17
- /**
18
- * 会话归属迁移(B2.2 审核 P1-1):
19
- * 跨项目恢复(备份包内 project_id ≠ 当前项目 id)后,chat_messages 的 project_id
20
- * 从旧 id 批量迁移为当前项目 id——「保留 id 保会话」的理由在跨项目场景同样成立:
21
- * 不迁移则恢复后聊天面板静默为空、旧会话行成孤儿数据(会话按 project_id 隔离)。
22
- *
23
- * @param fromProjectId 备份包内 project.json 的 id(旧归属)
24
- * @param toProjectId 当前项目 id(迁移目标;调用方保证两者不等)
25
- * @returns 受影响行数(0 = 无该旧 id 的消息;重复执行幂等——第二次起返回 0)
26
- */
27
- export declare function migrateChatMessagesProject(db: Db, fromProjectId: string, toProjectId: string): number;
28
- /**
29
- * 会话列表(GET /api/v1/chat/sessions):
30
- * - 按 project_id 隔离(会话按项目隔离)
31
- * - 仅返回含消息的会话;updatedAt = 该会话最后一条消息的 created_at
32
- * - 按最后活动时间(updatedAt)倒序,同时间戳按 session_id 升序保证稳定
33
- * - lastMessage = 最后一条消息的 content 截断(无 content 时为空串)
34
- */
35
- export declare function listSessions(db: Db, projectId: string): ChatSessionSummary[];
36
- /**
37
- * 解析 chat_messages.tool_calls 的 JSON 文本列为数组(ChatMessage.toolCalls)。
38
- * 防御性处理:NULL / 非法 JSON / 非数组一律返回 null(视为无工具调用)。
39
- */
40
- export declare function parseToolCalls(json: string | null): unknown[] | null;
41
- /**
42
- * 消息历史(GET /api/v1/chat/sessions/:id/messages):
43
- * - 按 project_id 隔离
44
- * - 按 created_at 升序,同时间戳按 rowid(插入序)升序保证稳定
45
- * - 存储形态 → API 形态:tool_calls JSON 解析、tool_call_id → toolCallId、snake_case → camelCase
46
- */
47
- export declare function listMessages(db: Db, sessionId: string, projectId: string): ChatMessage[];
48
- /**
49
- * 消息历史原始行(S7.6 续聊重建专用):
50
- * - listMessages 输出 API 形态(camelCase,供 GET /messages);本函数输出**存储形态**
51
- * (snake_case ChatMessageRow,tool_calls 已解析为数组)——直供 agent 包
52
- * loadHistory/restoreSession( 成对重组),避免 server 层做 API→存储形态反映射。
53
- * - 查询语义与 listMessages 一致:按 project_id 隔离、created_at 升序 + rowid 稳定序。
54
- */
55
- export declare function listMessageRows(db: Db, sessionId: string, projectId: string): ChatMessageRow[];
56
- /** 成对重组后喂给 LLM 的历史消息形态(DeepSeek 要求 tool_call 与 tool 结果严格配对) */
57
- export interface ReassembledChatMessage {
58
- role: ChatRole;
59
- content?: string | null;
60
- /** assistant 消息的工具调用数组(仅当该组全部调用均成对成功时保留) */
61
- toolCalls?: unknown[];
62
- /** tool 消息关联的调用 id(与所属 assistant 消息 tool_calls[].id 配对) */
63
- toolCallId?: string | null;
64
- }
65
- /**
66
- * 成对重组历史消息(assistant.tool_calls[].id ↔ tool.tool_call_id 成对重组喂回模型)。
67
- *
68
- * 用途:服务重启后凭 session_id 重建「继续上次对话」上下文,或会话级滑动窗口裁剪前的重组。
69
- * 注意:本函数是纯函数,输入为 ChatMessageRow(tool_calls 已按 shared 类型为解析后的数组,
70
- * 由调用方先经 parseToolCalls / 直接构造)。
71
- *
72
- * 算法:
73
- * 1. 按 created_at 升序稳定排序(同时间戳保持输入顺序)
74
- * 2. 第一遍收集 tool 消息:tool_call_id → content(同一 id 多条结果取最先到达者,防御性处理)
75
- * 3. 第二遍顺序扫描:
76
- * - user 消息:原样保留
77
- * - assistant 消息(无 tool_calls):原样保留
78
- * - assistant 消息(有 tool_calls):逐个调用校验——任一调用缺 id 或缺对应 tool 结果
79
- * 即判定为孤儿半对,该 assistant 消息与其工具结果**整组丢弃**(
80
- * 孤儿半对整对丢弃,不返回 409 也不部分保留);全部配对成功则输出 assistant 消息,
81
- * 工具结果按 tool_calls 数组顺序紧随其后(tool 消息保留 toolCallId 供模型配对)
82
- * - tool 消息:不单独输出——未被任何保留的 assistant 消息引用的即孤儿,整对丢弃
83
- */
84
- export declare function reassembleMessages(rows: ChatMessageRow[]): ReassembledChatMessage[];
85
- //# sourceMappingURL=chat.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/queries/chat.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAY,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,KAAK,QAAQ,EAAE,KAAK,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAC1I,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAI3C,oDAAoD;AACpD,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,EAAE,EACN,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,YAAY,GAAG,YAAY,GAAG,MAAM,GAAG,YAAY,CAAC,GAC5E,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,GAAG,SAAS,GAAG,YAAY,GAAG,cAAc,CAAC,CAAC,GAChF,IAAI,CAcN;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAOrG;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAqC5E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,EAAE,GAAG,IAAI,CASpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,CAoCxF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,cAAc,EAAE,CAmC9F;AAED,+DAA+D;AAC/D,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,4CAA4C;IAC3C,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;IACvB,2DAA2D;IAC1D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,sBAAsB,EAAE,CAwCnF"}
@@ -1,248 +0,0 @@
1
- // @whispering233/ai-editor-db 对话历史数据层查询(T2.3)
2
- //
3
- // (chat/sessions 会话列表、chat/sessions/:id/messages 消息历史)。
4
- // 时间约定():created_at 统一 ISO 8601 字符串、由应用层写入,本模块不生成时间。
5
- // 注意:本模块只处理 chat_messages 表,不涉及会话元数据——会话列表信息(createdAt/updatedAt/
6
- // messageCount/lastMessage)全部由消息行实时聚合得出,无独立会话表。
7
- //
8
- // 批次十五(15.4 卡 3):**查询经 queryDb 走 drizzle 构建器**(混合风格 4A)。
9
- // 语义逐句对照旧实现:
10
- // - INSERT 命名参数 ↔ insert(chatMessages).values({...})(tool_calls JSON.stringify 落库不变)
11
- // - UPDATE ... SET project_id ↔ update.set({ project_id }).where(eq(...))
12
- // - WHERE session_id = ? AND project_id = ? ↔ and(eq,eq);ORDER BY created_at ASC, rowid ASC ↔
13
- // orderBy(chatMessages.created_at, sql`rowid ASC`)(rowid 为 SQLite 内部列,经 sql 模板原样透传)
14
- // - listSessions 为相关子查询 + GROUP BY 聚合 + rowid 排序的复合 SQL,**保留 sql 模板**表达
15
- // (builder 强行翻译需三层嵌套别名,违背 4A「需要 SQL 技巧就原生,不强行翻译」);
16
- // projectId 两次注入均走 sql 模板参数绑定(安全,防注入)
17
- // - parseToolCalls / reassembleMessages 为纯函数,不涉及 SQL,未改动
18
- // - JSON 列 tool_calls 保持 text 模式:drizzle 行读出来是 string,解析防御仍在 parseToolCalls
19
- import { nanoid } from "nanoid";
20
- import { and, eq, sql } from "drizzle-orm";
21
- import { truncate } from "@whispering233/ai-editor-shared";
22
- import { queryDb } from "../query-db.js";
23
- import { chatMessages } from "../tables.js";
24
- /** 会话列表 lastMessage 截断长度( 仅要求「截断」,长度为本实现约定,未入文档) */
25
- export const SESSION_LAST_MESSAGE_MAX_LEN = 50;
26
- /**
27
- * 插入一条对话消息。
28
- *
29
- * id 生成约定:chat_messages 表 id 无文档前缀( id 约定仅覆盖
30
- * char-/set-/loc-/hook-、sc-/ch-/vol-、proj- 与运行时 prop_/sess_/call_),
31
- * 省略 id 时直接用 nanoid 生成(与消息 id 前缀空缺保持一致)。
32
- *
33
- * 存储形态转换:row.tool_calls 按 shared 类型为「解析后的数组」,
34
- * 本函数负责 JSON.stringify 落库(列存 TEXT);created_at 必须由调用方
35
- * 提供 ISO 8601 字符串(应用层写入)。
36
- */
37
- export function insertChatMessage(db, row) {
38
- queryDb(db)
39
- .insert(chatMessages)
40
- .values({
41
- id: row.id ?? nanoid(),
42
- session_id: row.session_id,
43
- project_id: row.project_id,
44
- role: row.role,
45
- content: row.content ?? null,
46
- tool_calls: row.tool_calls == null ? null : JSON.stringify(row.tool_calls),
47
- tool_call_id: row.tool_call_id ?? null,
48
- created_at: row.created_at,
49
- })
50
- .run();
51
- }
52
- /**
53
- * 会话归属迁移(B2.2 审核 P1-1):
54
- * 跨项目恢复(备份包内 project_id ≠ 当前项目 id)后,chat_messages 的 project_id
55
- * 从旧 id 批量迁移为当前项目 id——「保留 id 保会话」的理由在跨项目场景同样成立:
56
- * 不迁移则恢复后聊天面板静默为空、旧会话行成孤儿数据(会话按 project_id 隔离)。
57
- *
58
- * @param fromProjectId 备份包内 project.json 的 id(旧归属)
59
- * @param toProjectId 当前项目 id(迁移目标;调用方保证两者不等)
60
- * @returns 受影响行数(0 = 无该旧 id 的消息;重复执行幂等——第二次起返回 0)
61
- */
62
- export function migrateChatMessagesProject(db, fromProjectId, toProjectId) {
63
- const info = queryDb(db)
64
- .update(chatMessages)
65
- .set({ project_id: toProjectId })
66
- .where(eq(chatMessages.project_id, fromProjectId))
67
- .run();
68
- return info.changes;
69
- }
70
- /**
71
- * 会话列表(GET /api/v1/chat/sessions):
72
- * - 按 project_id 隔离(会话按项目隔离)
73
- * - 仅返回含消息的会话;updatedAt = 该会话最后一条消息的 created_at
74
- * - 按最后活动时间(updatedAt)倒序,同时间戳按 session_id 升序保证稳定
75
- * - lastMessage = 最后一条消息的 content 截断(无 content 时为空串)
76
- */
77
- export function listSessions(db, projectId) {
78
- // 相关子查询(取每会话最后一条消息)+ GROUP BY 聚合(count/min/max)的复合 SQL:
79
- // sql 模板表达(4A 混合风格),projectId 两次注入走参数绑定
80
- const rows = queryDb(db).all(sql `
81
- SELECT
82
- t.session_id AS id,
83
- t.message_count,
84
- t.created_at,
85
- t.updated_at,
86
- (SELECT lm.content FROM chat_messages lm
87
- WHERE lm.session_id = t.session_id AND lm.project_id = ${projectId}
88
- ORDER BY lm.created_at DESC, lm.rowid DESC LIMIT 1) AS last_content
89
- FROM (
90
- SELECT session_id,
91
- COUNT(*) AS message_count,
92
- MIN(created_at) AS created_at,
93
- MAX(created_at) AS updated_at
94
- FROM chat_messages
95
- WHERE project_id = ${projectId}
96
- GROUP BY session_id
97
- ) t
98
- ORDER BY t.updated_at DESC, t.session_id ASC
99
- `);
100
- return rows.map((r) => ({
101
- id: r.id,
102
- lastMessage: truncate(r.last_content ?? "", SESSION_LAST_MESSAGE_MAX_LEN),
103
- messageCount: r.message_count,
104
- createdAt: r.created_at,
105
- updatedAt: r.updated_at,
106
- }));
107
- }
108
- /**
109
- * 解析 chat_messages.tool_calls 的 JSON 文本列为数组(ChatMessage.toolCalls)。
110
- * 防御性处理:NULL / 非法 JSON / 非数组一律返回 null(视为无工具调用)。
111
- */
112
- export function parseToolCalls(json) {
113
- if (json === null)
114
- return null;
115
- try {
116
- const parsed = JSON.parse(json);
117
- return Array.isArray(parsed) ? parsed : null;
118
- }
119
- catch {
120
- // 非法 JSON:按无工具调用处理,不向上抛(查询层不阻断会话恢复)
121
- return null;
122
- }
123
- }
124
- /**
125
- * 消息历史(GET /api/v1/chat/sessions/:id/messages):
126
- * - 按 project_id 隔离
127
- * - 按 created_at 升序,同时间戳按 rowid(插入序)升序保证稳定
128
- * - 存储形态 → API 形态:tool_calls JSON 解析、tool_call_id → toolCallId、snake_case → camelCase
129
- */
130
- export function listMessages(db, sessionId, projectId) {
131
- const rows = queryDb(db)
132
- .select({
133
- id: chatMessages.id,
134
- session_id: chatMessages.session_id,
135
- project_id: chatMessages.project_id,
136
- role: chatMessages.role,
137
- content: chatMessages.content,
138
- tool_calls: chatMessages.tool_calls,
139
- tool_call_id: chatMessages.tool_call_id,
140
- created_at: chatMessages.created_at,
141
- })
142
- .from(chatMessages)
143
- .where(and(eq(chatMessages.session_id, sessionId), eq(chatMessages.project_id, projectId)))
144
- .orderBy(chatMessages.created_at, sql `rowid ASC`)
145
- .all();
146
- return rows.map((r) => ({
147
- id: r.id,
148
- sessionId: r.session_id,
149
- projectId: r.project_id,
150
- role: r.role,
151
- content: r.content,
152
- toolCalls: parseToolCalls(r.tool_calls) ?? undefined,
153
- toolCallId: r.tool_call_id,
154
- createdAt: r.created_at,
155
- }));
156
- }
157
- /**
158
- * 消息历史原始行(S7.6 续聊重建专用):
159
- * - listMessages 输出 API 形态(camelCase,供 GET /messages);本函数输出**存储形态**
160
- * (snake_case ChatMessageRow,tool_calls 已解析为数组)——直供 agent 包
161
- * loadHistory/restoreSession( 成对重组),避免 server 层做 API→存储形态反映射。
162
- * - 查询语义与 listMessages 一致:按 project_id 隔离、created_at 升序 + rowid 稳定序。
163
- */
164
- export function listMessageRows(db, sessionId, projectId) {
165
- const rows = queryDb(db)
166
- .select({
167
- id: chatMessages.id,
168
- session_id: chatMessages.session_id,
169
- project_id: chatMessages.project_id,
170
- role: chatMessages.role,
171
- content: chatMessages.content,
172
- tool_calls: chatMessages.tool_calls,
173
- tool_call_id: chatMessages.tool_call_id,
174
- created_at: chatMessages.created_at,
175
- })
176
- .from(chatMessages)
177
- .where(and(eq(chatMessages.session_id, sessionId), eq(chatMessages.project_id, projectId)))
178
- .orderBy(chatMessages.created_at, sql `rowid ASC`)
179
- .all();
180
- return rows.map((r) => ({
181
- id: r.id,
182
- session_id: r.session_id,
183
- project_id: r.project_id,
184
- role: r.role,
185
- content: r.content,
186
- tool_calls: parseToolCalls(r.tool_calls), // TEXT 列 → 解析后的数组(NULL/损坏 → null)
187
- tool_call_id: r.tool_call_id,
188
- created_at: r.created_at,
189
- }));
190
- }
191
- /**
192
- * 成对重组历史消息(assistant.tool_calls[].id ↔ tool.tool_call_id 成对重组喂回模型)。
193
- *
194
- * 用途:服务重启后凭 session_id 重建「继续上次对话」上下文,或会话级滑动窗口裁剪前的重组。
195
- * 注意:本函数是纯函数,输入为 ChatMessageRow(tool_calls 已按 shared 类型为解析后的数组,
196
- * 由调用方先经 parseToolCalls / 直接构造)。
197
- *
198
- * 算法:
199
- * 1. 按 created_at 升序稳定排序(同时间戳保持输入顺序)
200
- * 2. 第一遍收集 tool 消息:tool_call_id → content(同一 id 多条结果取最先到达者,防御性处理)
201
- * 3. 第二遍顺序扫描:
202
- * - user 消息:原样保留
203
- * - assistant 消息(无 tool_calls):原样保留
204
- * - assistant 消息(有 tool_calls):逐个调用校验——任一调用缺 id 或缺对应 tool 结果
205
- * 即判定为孤儿半对,该 assistant 消息与其工具结果**整组丢弃**(
206
- * 孤儿半对整对丢弃,不返回 409 也不部分保留);全部配对成功则输出 assistant 消息,
207
- * 工具结果按 tool_calls 数组顺序紧随其后(tool 消息保留 toolCallId 供模型配对)
208
- * - tool 消息:不单独输出——未被任何保留的 assistant 消息引用的即孤儿,整对丢弃
209
- */
210
- export function reassembleMessages(rows) {
211
- // 1. 按 created_at 升序稳定排序
212
- const sorted = [...rows].sort((a, b) => a.created_at.localeCompare(b.created_at));
213
- // 2. 收集 tool 消息:tool_call_id → content
214
- const toolResults = new Map();
215
- for (const r of sorted) {
216
- if (r.role === "tool" && r.tool_call_id !== null && !toolResults.has(r.tool_call_id)) {
217
- toolResults.set(r.tool_call_id, r.content);
218
- }
219
- }
220
- // 3. 顺序扫描重组
221
- const out = [];
222
- for (const r of sorted) {
223
- if (r.role === "user") {
224
- out.push({ role: "user", content: r.content });
225
- continue;
226
- }
227
- if (r.role === "assistant") {
228
- const calls = r.tool_calls ?? [];
229
- if (calls.length === 0) {
230
- out.push({ role: "assistant", content: r.content });
231
- continue;
232
- }
233
- const callIds = calls.map((c) => c.id);
234
- // 任一调用缺 id 或缺对应结果 → 整组丢弃
235
- const allPaired = callIds.every((cid) => typeof cid === "string" && toolResults.has(cid));
236
- if (!allPaired)
237
- continue;
238
- out.push({ role: "assistant", content: r.content, toolCalls: calls });
239
- for (const cid of callIds) {
240
- out.push({ role: "tool", toolCallId: cid, content: toolResults.get(cid) });
241
- }
242
- continue;
243
- }
244
- // role === "tool":仅作为上面对应的结果被引用;孤儿在此自然丢弃
245
- }
246
- return out;
247
- }
248
- //# sourceMappingURL=chat.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/queries/chat.ts"],"names":[],"mappings":"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"}