@downcity/agent 1.1.217 → 1.1.222

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 (147) hide show
  1. package/bin/agent/local/services/AgentSessions.d.ts.map +1 -1
  2. package/bin/agent/local/services/AgentSessions.js +1 -4
  3. package/bin/agent/local/services/AgentSessions.js.map +1 -1
  4. package/bin/agent/remote/RemoteSession.d.ts +9 -3
  5. package/bin/agent/remote/RemoteSession.d.ts.map +1 -1
  6. package/bin/agent/remote/RemoteSession.js +19 -4
  7. package/bin/agent/remote/RemoteSession.js.map +1 -1
  8. package/bin/agent/remote/RemoteTransport.d.ts +7 -3
  9. package/bin/agent/remote/RemoteTransport.d.ts.map +1 -1
  10. package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts +5 -2
  11. package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts.map +1 -1
  12. package/bin/agent/remote/transports/HttpRemoteAgentTransport.js +25 -11
  13. package/bin/agent/remote/transports/HttpRemoteAgentTransport.js.map +1 -1
  14. package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts +5 -2
  15. package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts.map +1 -1
  16. package/bin/agent/remote/transports/RpcRemoteAgentTransport.js +5 -2
  17. package/bin/agent/remote/transports/RpcRemoteAgentTransport.js.map +1 -1
  18. package/bin/executor/types/SessionRecords.d.ts +2 -0
  19. package/bin/executor/types/SessionRecords.d.ts.map +1 -1
  20. package/bin/executor/types/SessionRecords.js.map +1 -1
  21. package/bin/index.d.ts +5 -2
  22. package/bin/index.d.ts.map +1 -1
  23. package/bin/index.js +1 -0
  24. package/bin/index.js.map +1 -1
  25. package/bin/rpc/Client.d.ts +11 -4
  26. package/bin/rpc/Client.d.ts.map +1 -1
  27. package/bin/rpc/Client.js +14 -3
  28. package/bin/rpc/Client.js.map +1 -1
  29. package/bin/session/Session.d.ts +13 -3
  30. package/bin/session/Session.d.ts.map +1 -1
  31. package/bin/session/Session.js +47 -18
  32. package/bin/session/Session.js.map +1 -1
  33. package/bin/session/recorder/JsonlSessionMessageStore.d.ts +45 -0
  34. package/bin/session/recorder/JsonlSessionMessageStore.d.ts.map +1 -0
  35. package/bin/session/recorder/JsonlSessionMessageStore.js +127 -0
  36. package/bin/session/recorder/JsonlSessionMessageStore.js.map +1 -0
  37. package/bin/session/recorder/SessionMessageCodec.d.ts +20 -0
  38. package/bin/session/recorder/SessionMessageCodec.d.ts.map +1 -0
  39. package/bin/session/recorder/SessionMessageCodec.js +252 -0
  40. package/bin/session/recorder/SessionMessageCodec.js.map +1 -0
  41. package/bin/session/recorder/SessionMessageReducer.d.ts +12 -0
  42. package/bin/session/recorder/SessionMessageReducer.d.ts.map +1 -0
  43. package/bin/session/recorder/SessionMessageReducer.js +109 -0
  44. package/bin/session/recorder/SessionMessageReducer.js.map +1 -0
  45. package/bin/session/recorder/SessionRecorder.d.ts +177 -0
  46. package/bin/session/recorder/SessionRecorder.d.ts.map +1 -0
  47. package/bin/session/recorder/SessionRecorder.js +610 -0
  48. package/bin/session/recorder/SessionRecorder.js.map +1 -0
  49. package/bin/session/recorder/SessionRecorderCompaction.d.ts +18 -0
  50. package/bin/session/recorder/SessionRecorderCompaction.d.ts.map +1 -0
  51. package/bin/session/recorder/SessionRecorderCompaction.js +141 -0
  52. package/bin/session/recorder/SessionRecorderCompaction.js.map +1 -0
  53. package/bin/session/recorder/SessionRecorderHistoryStore.d.ts +66 -0
  54. package/bin/session/recorder/SessionRecorderHistoryStore.d.ts.map +1 -0
  55. package/bin/session/recorder/SessionRecorderHistoryStore.js +195 -0
  56. package/bin/session/recorder/SessionRecorderHistoryStore.js.map +1 -0
  57. package/bin/session/runtime/SessionMessageEventHub.d.ts +15 -0
  58. package/bin/session/runtime/SessionMessageEventHub.d.ts.map +1 -0
  59. package/bin/session/runtime/SessionMessageEventHub.js +28 -0
  60. package/bin/session/runtime/SessionMessageEventHub.js.map +1 -0
  61. package/bin/session/runtime/SessionPromptRuntime.d.ts +7 -13
  62. package/bin/session/runtime/SessionPromptRuntime.d.ts.map +1 -1
  63. package/bin/session/runtime/SessionPromptRuntime.js +13 -13
  64. package/bin/session/runtime/SessionPromptRuntime.js.map +1 -1
  65. package/bin/session/services/SessionStateService.d.ts +7 -3
  66. package/bin/session/services/SessionStateService.d.ts.map +1 -1
  67. package/bin/session/services/SessionStateService.js +132 -72
  68. package/bin/session/services/SessionStateService.js.map +1 -1
  69. package/bin/session/services/SessionTurnService.d.ts +4 -0
  70. package/bin/session/services/SessionTurnService.d.ts.map +1 -1
  71. package/bin/session/services/SessionTurnService.js +82 -52
  72. package/bin/session/services/SessionTurnService.js.map +1 -1
  73. package/bin/session/services/SessionViewService.d.ts +8 -3
  74. package/bin/session/services/SessionViewService.d.ts.map +1 -1
  75. package/bin/session/services/SessionViewService.js +10 -5
  76. package/bin/session/services/SessionViewService.js.map +1 -1
  77. package/bin/session/storage/Persistence.d.ts +6 -0
  78. package/bin/session/storage/Persistence.d.ts.map +1 -1
  79. package/bin/session/storage/Persistence.js +7 -0
  80. package/bin/session/storage/Persistence.js.map +1 -1
  81. package/bin/session/storage/RuntimeSessionPort.d.ts +3 -2
  82. package/bin/session/storage/RuntimeSessionPort.d.ts.map +1 -1
  83. package/bin/session/storage/RuntimeSessionPort.js.map +1 -1
  84. package/bin/types/agent/SessionActor.d.ts +10 -4
  85. package/bin/types/agent/SessionActor.d.ts.map +1 -1
  86. package/bin/types/rpc/RpcProtocol.d.ts +20 -6
  87. package/bin/types/rpc/RpcProtocol.d.ts.map +1 -1
  88. package/bin/types/runtime/agent/AgentContext.d.ts +4 -3
  89. package/bin/types/runtime/agent/AgentContext.d.ts.map +1 -1
  90. package/bin/types/runtime/agent/AgentContext.js.map +1 -1
  91. package/bin/types/sdk/AgentSessionEvent.d.ts +2 -1
  92. package/bin/types/sdk/AgentSessionEvent.d.ts.map +1 -1
  93. package/bin/types/session/SessionMessage.d.ts +217 -0
  94. package/bin/types/session/SessionMessage.d.ts.map +1 -0
  95. package/bin/types/session/SessionMessage.js +8 -0
  96. package/bin/types/session/SessionMessage.js.map +1 -0
  97. package/bin/types/session/SessionMessageMutation.d.ts +92 -0
  98. package/bin/types/session/SessionMessageMutation.d.ts.map +1 -0
  99. package/bin/types/session/SessionMessageMutation.js +21 -0
  100. package/bin/types/session/SessionMessageMutation.js.map +1 -0
  101. package/package.json +3 -3
  102. package/scripts/agent-env.test.mjs +4 -4
  103. package/scripts/session-action-message.test.mjs +98 -27
  104. package/scripts/session-list-title.test.mjs +6 -19
  105. package/scripts/session-prompt-runtime.test.mjs +4 -16
  106. package/scripts/session-recorder.test.mjs +245 -0
  107. package/scripts/session-title-event.test.mjs +10 -18
  108. package/src/agent/local/services/AgentSessions.ts +1 -3
  109. package/src/agent/remote/RemoteSession.ts +35 -7
  110. package/src/agent/remote/RemoteTransport.ts +17 -6
  111. package/src/agent/remote/transports/HttpRemoteAgentTransport.ts +45 -13
  112. package/src/agent/remote/transports/RpcRemoteAgentTransport.ts +19 -6
  113. package/src/executor/types/SessionRecords.ts +2 -0
  114. package/src/index.ts +23 -5
  115. package/src/rpc/Client.ts +29 -8
  116. package/src/session/Session.ts +65 -31
  117. package/src/session/recorder/JsonlSessionMessageStore.ts +162 -0
  118. package/src/session/recorder/SessionMessageCodec.ts +279 -0
  119. package/src/session/recorder/SessionMessageReducer.ts +155 -0
  120. package/src/session/recorder/SessionRecorder.ts +812 -0
  121. package/src/session/recorder/SessionRecorderCompaction.ts +187 -0
  122. package/src/session/recorder/SessionRecorderHistoryStore.ts +276 -0
  123. package/src/session/runtime/SessionMessageEventHub.ts +35 -0
  124. package/src/session/runtime/SessionPromptRuntime.ts +23 -24
  125. package/src/session/services/SessionStateService.ts +151 -80
  126. package/src/session/services/SessionTurnService.ts +88 -59
  127. package/src/session/services/SessionViewService.ts +25 -13
  128. package/src/session/storage/Persistence.ts +13 -0
  129. package/src/session/storage/RuntimeSessionPort.ts +6 -4
  130. package/src/types/agent/SessionActor.ts +26 -6
  131. package/src/types/rpc/RpcProtocol.ts +20 -6
  132. package/src/types/runtime/agent/AgentContext.ts +8 -2
  133. package/src/types/sdk/AgentSessionEvent.ts +2 -0
  134. package/src/types/session/SessionMessage.ts +247 -0
  135. package/src/types/session/SessionMessageMutation.ts +121 -0
  136. package/tsconfig.tsbuildinfo +1 -1
  137. package/bin/session/SessionEventMapper.d.ts +0 -32
  138. package/bin/session/SessionEventMapper.d.ts.map +0 -1
  139. package/bin/session/SessionEventMapper.js +0 -131
  140. package/bin/session/SessionEventMapper.js.map +0 -1
  141. package/bin/types/sdk/InternalUiChunkEvent.d.ts +0 -100
  142. package/bin/types/sdk/InternalUiChunkEvent.d.ts.map +0 -1
  143. package/bin/types/sdk/InternalUiChunkEvent.js +0 -9
  144. package/bin/types/sdk/InternalUiChunkEvent.js.map +0 -1
  145. package/scripts/session-history-archive.test.mjs +0 -188
  146. package/src/session/SessionEventMapper.ts +0 -148
  147. package/src/types/sdk/InternalUiChunkEvent.ts +0 -108
@@ -0,0 +1,127 @@
1
+ /**
2
+ * 基于单一 messages.jsonl 的 SessionMessage mutation store。
3
+ *
4
+ * 文件中每行是一条完整 mutation。消息快照通过 reducer 重放得到,不维护第二份文件。
5
+ */
6
+ import fs from "fs-extra";
7
+ import { open, readFile, stat } from "node:fs/promises";
8
+ import path from "node:path";
9
+ import { generateId } from "../../utils/Id.js";
10
+ import { reduce_session_messages } from "../../session/recorder/SessionMessageReducer.js";
11
+ /** 单一 JSONL mutation store。 */
12
+ export class JsonlSessionMessageStore {
13
+ session_id;
14
+ messages_file_path;
15
+ lock_file_path;
16
+ constructor(options) {
17
+ this.session_id = String(options.session_id || "").trim();
18
+ this.messages_file_path = path.resolve(options.file_path);
19
+ this.lock_file_path = `${this.messages_file_path}.lock`;
20
+ if (!this.session_id) {
21
+ throw new Error("JsonlSessionMessageStore requires session_id");
22
+ }
23
+ }
24
+ /** 创建空文件并校验已有 Mutation 可重放。 */
25
+ async initialize() {
26
+ await this.ensure_layout();
27
+ reduce_session_messages(await this.read_mutations_unsafe());
28
+ }
29
+ /** 读取全部合法 mutation;损坏行会带行号抛错,避免静默产生错误历史。 */
30
+ async list_mutations() {
31
+ await this.ensure_layout();
32
+ return await this.read_mutations_unsafe();
33
+ }
34
+ /** 重放全部 mutation,得到当前 canonical 消息列表。 */
35
+ async list_messages() {
36
+ return reduce_session_messages(await this.list_mutations());
37
+ }
38
+ /**
39
+ * 在跨进程文件锁内计算并追加 mutation。
40
+ * 发布动作必须由调用方在此 Promise 成功后执行。
41
+ */
42
+ async commit(build_mutation) {
43
+ return await this.with_write_lock(async () => {
44
+ const mutations = await this.read_mutations_unsafe();
45
+ const messages = reduce_session_messages(mutations);
46
+ const mutation = build_mutation({
47
+ commit_sequence: (mutations[mutations.length - 1]?.commit_sequence || 0) + 1,
48
+ message_sequence: messages.reduce((value, message) => Math.max(value, message.sequence + 1), 1),
49
+ messages,
50
+ });
51
+ await fs.appendFile(this.messages_file_path, `${JSON.stringify(mutation)}\n`, "utf8");
52
+ return mutation;
53
+ });
54
+ }
55
+ async ensure_layout() {
56
+ await fs.ensureDir(path.dirname(this.messages_file_path));
57
+ await fs.ensureFile(this.messages_file_path);
58
+ }
59
+ async read_mutations_unsafe() {
60
+ const raw = await fs.readFile(this.messages_file_path, "utf8").catch(() => "");
61
+ const mutations = [];
62
+ const lines = raw.split("\n");
63
+ for (let index = 0; index < lines.length; index += 1) {
64
+ const line = lines[index]?.trim();
65
+ if (!line)
66
+ continue;
67
+ try {
68
+ const mutation = JSON.parse(line);
69
+ if (mutation.session_id !== this.session_id) {
70
+ throw new Error("session_id mismatch");
71
+ }
72
+ mutations.push(mutation);
73
+ }
74
+ catch (error) {
75
+ throw new Error(`Invalid session mutation at line ${String(index + 1)}: ${error instanceof Error ? error.message : String(error)}`);
76
+ }
77
+ }
78
+ return mutations;
79
+ }
80
+ async with_write_lock(callback) {
81
+ await this.ensure_layout();
82
+ const token = `${process.pid}:${Date.now()}:${generateId()}`;
83
+ const stale_ms = 30_000;
84
+ const started_at = Date.now();
85
+ while (true) {
86
+ try {
87
+ const file = await open(this.lock_file_path, "wx");
88
+ await file.writeFile(token, "utf8");
89
+ await file.close();
90
+ break;
91
+ }
92
+ catch (error) {
93
+ const code = error.code;
94
+ if (code !== "EEXIST")
95
+ throw error;
96
+ try {
97
+ const lock_stat = await stat(this.lock_file_path);
98
+ if (Date.now() - lock_stat.mtimeMs > stale_ms) {
99
+ await fs.remove(this.lock_file_path);
100
+ continue;
101
+ }
102
+ }
103
+ catch {
104
+ continue;
105
+ }
106
+ if (Date.now() - started_at > stale_ms * 2) {
107
+ throw new Error(`Session message lock timeout: ${this.lock_file_path}`);
108
+ }
109
+ await new Promise((resolve) => setTimeout(resolve, 40));
110
+ }
111
+ }
112
+ try {
113
+ return await callback();
114
+ }
115
+ finally {
116
+ try {
117
+ if ((await readFile(this.lock_file_path, "utf8")).trim() === token) {
118
+ await fs.remove(this.lock_file_path);
119
+ }
120
+ }
121
+ catch {
122
+ // 锁文件已被清理时无需额外处理。
123
+ }
124
+ }
125
+ }
126
+ }
127
+ //# sourceMappingURL=JsonlSessionMessageStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JsonlSessionMessageStore.js","sourceRoot":"","sources":["../../../src/session/recorder/JsonlSessionMessageStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * SessionMessage 与 AI SDK UIMessage 的内部投影转换。
3
+ *
4
+ * 关键点(中文)
5
+ * - SessionMessage 是唯一持久化事实;UIMessage 只在 Executor/Composer 边界临时构造。
6
+ * - action/error 不转换为模型消息。
7
+ * - part_id 只服务 Session Message identity,不传入模型协议。
8
+ */
9
+ import type { UIMessage } from "ai";
10
+ import type { SessionAssistantMessage, SessionAssistantMessagePart, SessionMessage, SessionUserMessagePart } from "../../types/session/SessionMessage.js";
11
+ import type { SessionMessageRecordV1 } from "../../executor/types/SessionRecords.js";
12
+ /** 把 Session Message 投影成 Executor 可消费的 UIMessage。 */
13
+ export declare function to_executor_ui_message(message: SessionMessage): SessionMessageRecordV1 | null;
14
+ /** 把 AI SDK user parts 转换成可持久化 Session parts。 */
15
+ export declare function from_ui_user_parts(parts: UIMessage["parts"] | null | undefined): SessionUserMessagePart[];
16
+ /** 把最终 AI SDK assistant parts 转换成 Session parts。 */
17
+ export declare function from_ui_assistant_parts(parts: UIMessage["parts"] | null | undefined): SessionAssistantMessagePart[];
18
+ /** 提取 Assistant Message 的最终可见文本。 */
19
+ export declare function extract_session_assistant_text(message: SessionAssistantMessage | null | undefined): string;
20
+ //# sourceMappingURL=SessionMessageCodec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionMessageCodec.d.ts","sourceRoot":"","sources":["../../../src/session/recorder/SessionMessageCodec.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,EACV,uBAAuB,EACvB,2BAA2B,EAC3B,cAAc,EAEd,sBAAsB,EACvB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EACV,sBAAsB,EAEvB,MAAM,oCAAoC,CAAC;AAE5C,qDAAqD;AACrD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,cAAc,GACtB,sBAAsB,GAAG,IAAI,CAmC/B;AAED,iDAAiD;AACjD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,GAC3C,sBAAsB,EAAE,CAgC1B;AAED,oDAAoD;AACpD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,GAC3C,2BAA2B,EAAE,CAsD/B;AAED,oCAAoC;AACpC,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,uBAAuB,GAAG,IAAI,GAAG,SAAS,GAClD,MAAM,CAMR"}
@@ -0,0 +1,252 @@
1
+ /**
2
+ * SessionMessage 与 AI SDK UIMessage 的内部投影转换。
3
+ *
4
+ * 关键点(中文)
5
+ * - SessionMessage 是唯一持久化事实;UIMessage 只在 Executor/Composer 边界临时构造。
6
+ * - action/error 不转换为模型消息。
7
+ * - part_id 只服务 Session Message identity,不传入模型协议。
8
+ */
9
+ /** 把 Session Message 投影成 Executor 可消费的 UIMessage。 */
10
+ export function to_executor_ui_message(message) {
11
+ if (message.type !== "user" && message.type !== "assistant")
12
+ return null;
13
+ const metadata = {
14
+ v: 1,
15
+ ts: message.updated_at,
16
+ sessionId: message.session_id,
17
+ turnId: message.turn_id,
18
+ source: message.type === "user"
19
+ ? "ingress"
20
+ : message.kind === "summary"
21
+ ? "compact"
22
+ : "egress",
23
+ kind: message.type === "assistant" && message.kind === "summary"
24
+ ? "summary"
25
+ : "normal",
26
+ extra: {
27
+ sequence: message.sequence,
28
+ revision: message.revision,
29
+ visibility: message.visibility,
30
+ ...(message.type === "user"
31
+ ? { inputType: message.input_type }
32
+ : { segmentIndex: message.segment_index, status: message.status }),
33
+ },
34
+ };
35
+ return {
36
+ id: message.message_id,
37
+ role: message.type,
38
+ metadata,
39
+ parts: message.type === "user"
40
+ ? to_ui_user_parts(message.parts)
41
+ : to_ui_assistant_parts(message.parts),
42
+ };
43
+ }
44
+ /** 把 AI SDK user parts 转换成可持久化 Session parts。 */
45
+ export function from_ui_user_parts(parts) {
46
+ if (!Array.isArray(parts))
47
+ return [];
48
+ return parts.flatMap((part, index) => {
49
+ if (!part || typeof part !== "object")
50
+ return [];
51
+ const candidate = part;
52
+ if (candidate.type === "text") {
53
+ return [{
54
+ part_id: `user-text:${index + 1}`,
55
+ type: "text",
56
+ text: String(candidate.text || ""),
57
+ state: "done",
58
+ }];
59
+ }
60
+ if (candidate.type === "file") {
61
+ return [{
62
+ part_id: `user-file:${index + 1}`,
63
+ type: "file",
64
+ url: String(candidate.url || ""),
65
+ media_type: String(candidate.mediaType || "application/octet-stream"),
66
+ ...(candidate.filename ? { filename: String(candidate.filename) } : {}),
67
+ }];
68
+ }
69
+ if (String(candidate.type || "").startsWith("data-")) {
70
+ return [{
71
+ part_id: `user-data:${index + 1}`,
72
+ type: "data",
73
+ data_type: String(candidate.type),
74
+ data: to_json_value(candidate.data),
75
+ }];
76
+ }
77
+ return [];
78
+ });
79
+ }
80
+ /** 把最终 AI SDK assistant parts 转换成 Session parts。 */
81
+ export function from_ui_assistant_parts(parts) {
82
+ if (!Array.isArray(parts))
83
+ return [];
84
+ return parts.flatMap((part, index) => {
85
+ if (!part || typeof part !== "object")
86
+ return [];
87
+ const candidate = part;
88
+ const type = String(candidate.type || "");
89
+ if (type === "text" || type === "reasoning") {
90
+ return [{
91
+ part_id: `${type}:${index + 1}`,
92
+ type: type,
93
+ text: String(candidate.text || ""),
94
+ state: "done",
95
+ }];
96
+ }
97
+ if (type === "file") {
98
+ return [{
99
+ part_id: `file:${index + 1}`,
100
+ type: "file",
101
+ url: String(candidate.url || ""),
102
+ media_type: String(candidate.mediaType || "application/octet-stream"),
103
+ ...(candidate.filename ? { filename: String(candidate.filename) } : {}),
104
+ }];
105
+ }
106
+ if (type === "dynamic-tool" || type.startsWith("tool-")) {
107
+ const state = String(candidate.state || "");
108
+ return [{
109
+ part_id: String(candidate.toolCallId || `tool:${index + 1}`),
110
+ type: "tool",
111
+ tool_call_id: String(candidate.toolCallId || `tool:${index + 1}`),
112
+ tool_name: String(candidate.toolName || "").trim() ||
113
+ type.replace(/^tool-/, "") ||
114
+ "unknown",
115
+ state: state === "output-available"
116
+ ? "completed"
117
+ : state === "output-error" || state === "output-denied"
118
+ ? "failed"
119
+ : state === "approval-requested"
120
+ ? "approval-required"
121
+ : state === "input-streaming"
122
+ ? "input-streaming"
123
+ : "running",
124
+ ...(candidate.input !== undefined
125
+ ? { input: to_json_value(candidate.input) }
126
+ : {}),
127
+ ...(candidate.output !== undefined
128
+ ? { output: to_json_value(candidate.output) }
129
+ : {}),
130
+ ...(candidate.errorText ? { error: String(candidate.errorText) } : {}),
131
+ }];
132
+ }
133
+ return [];
134
+ });
135
+ }
136
+ /** 提取 Assistant Message 的最终可见文本。 */
137
+ export function extract_session_assistant_text(message) {
138
+ if (!message)
139
+ return "";
140
+ return message.parts
141
+ .flatMap((part) => part.type === "text" ? [part.text] : [])
142
+ .join("")
143
+ .trim();
144
+ }
145
+ function to_ui_user_parts(parts) {
146
+ return parts.map((part) => {
147
+ if (part.type === "text") {
148
+ return { type: "text", text: part.text, state: part.state };
149
+ }
150
+ if (part.type === "file") {
151
+ return {
152
+ type: "file",
153
+ url: part.url,
154
+ mediaType: part.media_type,
155
+ ...(part.filename ? { filename: part.filename } : {}),
156
+ };
157
+ }
158
+ return {
159
+ type: part.data_type,
160
+ data: part.data,
161
+ };
162
+ });
163
+ }
164
+ function to_ui_assistant_parts(parts) {
165
+ return parts.map((part) => {
166
+ if (part.type === "text" || part.type === "reasoning") {
167
+ return { type: part.type, text: part.text, state: part.state };
168
+ }
169
+ if (part.type === "file") {
170
+ return {
171
+ type: "file",
172
+ url: part.url,
173
+ mediaType: part.media_type,
174
+ ...(part.filename ? { filename: part.filename } : {}),
175
+ };
176
+ }
177
+ if (part.type === "data") {
178
+ return {
179
+ type: part.data_type,
180
+ data: part.data,
181
+ };
182
+ }
183
+ if (!("tool_call_id" in part)) {
184
+ throw new Error(`Unsupported Assistant part: ${part.type}`);
185
+ }
186
+ const input = part.input ?? parse_json(part.input_text);
187
+ if (part.state === "completed") {
188
+ return {
189
+ type: "dynamic-tool",
190
+ toolName: part.tool_name,
191
+ toolCallId: part.tool_call_id,
192
+ state: "output-available",
193
+ input,
194
+ output: part.output,
195
+ };
196
+ }
197
+ if (part.state === "failed") {
198
+ return {
199
+ type: "dynamic-tool",
200
+ toolName: part.tool_name,
201
+ toolCallId: part.tool_call_id,
202
+ state: "output-error",
203
+ input,
204
+ errorText: part.error || "Tool failed",
205
+ };
206
+ }
207
+ if (part.state === "approval-required") {
208
+ return {
209
+ type: "dynamic-tool",
210
+ toolName: part.tool_name,
211
+ toolCallId: part.tool_call_id,
212
+ state: "approval-requested",
213
+ input,
214
+ approval: { id: part.approval_id || `approval:${part.tool_call_id}` },
215
+ };
216
+ }
217
+ return {
218
+ type: "dynamic-tool",
219
+ toolName: part.tool_name,
220
+ toolCallId: part.tool_call_id,
221
+ state: part.state === "input-streaming" ? "input-streaming" : "input-available",
222
+ input,
223
+ };
224
+ });
225
+ }
226
+ function parse_json(input) {
227
+ const value = String(input || "").trim();
228
+ if (!value)
229
+ return {};
230
+ try {
231
+ return JSON.parse(value);
232
+ }
233
+ catch {
234
+ return value;
235
+ }
236
+ }
237
+ function to_json_value(input) {
238
+ if (input === undefined || input === null)
239
+ return null;
240
+ if (typeof input === "string" ||
241
+ typeof input === "number" ||
242
+ typeof input === "boolean") {
243
+ return input;
244
+ }
245
+ try {
246
+ return JSON.parse(JSON.stringify(input));
247
+ }
248
+ catch {
249
+ return String(input);
250
+ }
251
+ }
252
+ //# sourceMappingURL=SessionMessageCodec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionMessageCodec.js","sourceRoot":"","sources":["../../../src/session/recorder/SessionMessageCodec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Session Message Mutation reducer。
3
+ *
4
+ * 历史重放与实时消费者共享 message、part、delta 三种归并语义。
5
+ */
6
+ import type { SessionMessage } from "../../types/session/SessionMessage.js";
7
+ import type { SessionMessageMutation } from "../../types/session/SessionMessageMutation.js";
8
+ /** 将单条 Mutation 应用到已有 Message。 */
9
+ export declare function reduce_session_message(current_message: SessionMessage | undefined, mutation: SessionMessageMutation): SessionMessage;
10
+ /** 按 commit_sequence 重放 Mutation,恢复线性 Message snapshot。 */
11
+ export declare function reduce_session_messages(mutations: SessionMessageMutation[]): SessionMessage[];
12
+ //# sourceMappingURL=SessionMessageReducer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionMessageReducer.d.ts","sourceRoot":"","sources":["../../../src/session/recorder/SessionMessageReducer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAA2B,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACjG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAExF,kCAAkC;AAClC,wBAAgB,sBAAsB,CACpC,eAAe,EAAE,cAAc,GAAG,SAAS,EAC3C,QAAQ,EAAE,sBAAsB,GAC/B,cAAc,CAkDhB;AAED,2DAA2D;AAC3D,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,sBAAsB,EAAE,GAClC,cAAc,EAAE,CAmBlB"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Session Message Mutation reducer。
3
+ *
4
+ * 历史重放与实时消费者共享 message、part、delta 三种归并语义。
5
+ */
6
+ /** 将单条 Mutation 应用到已有 Message。 */
7
+ export function reduce_session_message(current_message, mutation) {
8
+ if (mutation.variant === "message") {
9
+ validate_message_snapshot(current_message, mutation);
10
+ return structuredClone(mutation.message);
11
+ }
12
+ if (!current_message) {
13
+ throw new Error(`Session Message does not exist: ${mutation.message_id}`);
14
+ }
15
+ validate_next_revision(current_message, mutation);
16
+ const assistant = require_streaming_assistant(current_message);
17
+ if (mutation.variant === "part") {
18
+ if (mutation.part.part_id !== mutation.part_id) {
19
+ throw new Error(`Part Mutation identity mismatch: ${mutation.part_id}`);
20
+ }
21
+ if (mutation.part.type !== mutation.type) {
22
+ throw new Error(`Part Mutation type mismatch: ${mutation.part_id}`);
23
+ }
24
+ const exists = assistant.parts.some((part) => part.part_id === mutation.part_id);
25
+ const parts = exists
26
+ ? assistant.parts.map((part) => part.part_id === mutation.part_id
27
+ ? structuredClone(mutation.part)
28
+ : part)
29
+ : [...assistant.parts, structuredClone(mutation.part)];
30
+ return with_revision(assistant, mutation, { parts });
31
+ }
32
+ const existing_part = assistant.parts.find((part) => part.part_id === mutation.part_id);
33
+ if (!existing_part ||
34
+ (existing_part.type !== "text" && existing_part.type !== "reasoning")) {
35
+ throw new Error(`Delta target Part does not exist: ${mutation.part_id}`);
36
+ }
37
+ if (existing_part.type !== mutation.type) {
38
+ throw new Error(`Delta type changed for Part: ${mutation.part_id}`);
39
+ }
40
+ const parts = assistant.parts.map((part) => part.part_id === mutation.part_id &&
41
+ (part.type === "text" || part.type === "reasoning")
42
+ ? { ...part, text: part.text + mutation.delta }
43
+ : part);
44
+ return with_revision(assistant, mutation, { parts });
45
+ }
46
+ /** 按 commit_sequence 重放 Mutation,恢复线性 Message snapshot。 */
47
+ export function reduce_session_messages(mutations) {
48
+ const messages = new Map();
49
+ const ordered = [...mutations].sort((left, right) => left.commit_sequence - right.commit_sequence);
50
+ let previous_commit_sequence = 0;
51
+ for (const mutation of ordered) {
52
+ if (mutation.commit_sequence <= previous_commit_sequence) {
53
+ throw new Error(`Duplicate commit_sequence: ${String(mutation.commit_sequence)}`);
54
+ }
55
+ messages.set(mutation.message_id, reduce_session_message(messages.get(mutation.message_id), mutation));
56
+ previous_commit_sequence = mutation.commit_sequence;
57
+ }
58
+ return [...messages.values()].sort((left, right) => left.sequence - right.sequence);
59
+ }
60
+ function validate_message_snapshot(current_message, mutation) {
61
+ if (mutation.message.message_id !== mutation.message_id) {
62
+ throw new Error(`Message Mutation identity mismatch: ${mutation.message_id}`);
63
+ }
64
+ if (mutation.message.type !== mutation.type) {
65
+ throw new Error(`Message Mutation type mismatch: ${mutation.message_id}`);
66
+ }
67
+ if (mutation.message.sequence !== mutation.sequence) {
68
+ throw new Error(`Message Mutation sequence mismatch: ${mutation.message_id}`);
69
+ }
70
+ if (mutation.message.revision !== mutation.revision) {
71
+ throw new Error(`Message Mutation revision mismatch: ${mutation.message_id}`);
72
+ }
73
+ if (!current_message) {
74
+ if (mutation.revision !== 1) {
75
+ throw new Error(`New Message revision must be 1: ${mutation.message_id}`);
76
+ }
77
+ return;
78
+ }
79
+ validate_next_revision(current_message, mutation);
80
+ if (current_message.type !== mutation.type) {
81
+ throw new Error(`Message type changed: ${mutation.message_id}`);
82
+ }
83
+ if (current_message.sequence !== mutation.sequence) {
84
+ throw new Error(`Message sequence changed: ${mutation.message_id}`);
85
+ }
86
+ }
87
+ function validate_next_revision(current_message, mutation) {
88
+ if (mutation.revision !== current_message.revision + 1) {
89
+ throw new Error(`Invalid Message revision for ${mutation.message_id}: expected ${String(current_message.revision + 1)}, received ${String(mutation.revision)}`);
90
+ }
91
+ }
92
+ function require_streaming_assistant(message) {
93
+ if (message.type !== "assistant") {
94
+ throw new Error(`Session Message is not assistant: ${message.message_id}`);
95
+ }
96
+ if (message.status !== "streaming") {
97
+ throw new Error(`Assistant Message is already closed: ${message.message_id}`);
98
+ }
99
+ return message;
100
+ }
101
+ function with_revision(message, mutation, changes) {
102
+ return {
103
+ ...message,
104
+ ...changes,
105
+ revision: mutation.revision,
106
+ updated_at: mutation.created_at,
107
+ };
108
+ }
109
+ //# sourceMappingURL=SessionMessageReducer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionMessageReducer.js","sourceRoot":"","sources":["../../../src/session/recorder/SessionMessageReducer.ts"],"names":[],"mappings":"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"}