@keyou007/agent-bot 0.1.0

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 (212) hide show
  1. package/.env.example +8 -0
  2. package/CHANGELOG.md +11 -0
  3. package/LICENSE +675 -0
  4. package/README.md +187 -0
  5. package/README.zh.md +187 -0
  6. package/SECURITY.md +13 -0
  7. package/config.example.yaml +56 -0
  8. package/dist/acp/AcpJsonRpcConnection.js +155 -0
  9. package/dist/acp/AcpJsonRpcConnection.js.map +1 -0
  10. package/dist/acp/AcpProcessManager.js +65 -0
  11. package/dist/acp/AcpProcessManager.js.map +1 -0
  12. package/dist/acp/AcpSessionManager.js +164 -0
  13. package/dist/acp/AcpSessionManager.js.map +1 -0
  14. package/dist/acp/acpTypes.js +10 -0
  15. package/dist/acp/acpTypes.js.map +1 -0
  16. package/dist/cli/FeishuAppConfiguration.js +349 -0
  17. package/dist/cli/FeishuAppConfiguration.js.map +1 -0
  18. package/dist/cli/FeishuAppRegistration.js +160 -0
  19. package/dist/cli/FeishuAppRegistration.js.map +1 -0
  20. package/dist/cli/Initializer.js +112 -0
  21. package/dist/cli/Initializer.js.map +1 -0
  22. package/dist/cli/LocalControlClient.js +47 -0
  23. package/dist/cli/LocalControlClient.js.map +1 -0
  24. package/dist/cli/LocalControlServer.js +66 -0
  25. package/dist/cli/LocalControlServer.js.map +1 -0
  26. package/dist/cli/SkillRegistry.js +126 -0
  27. package/dist/cli/SkillRegistry.js.map +1 -0
  28. package/dist/cli/controlProtocol.js +10 -0
  29. package/dist/cli/controlProtocol.js.map +1 -0
  30. package/dist/cli/taskChatRoute.js +23 -0
  31. package/dist/cli/taskChatRoute.js.map +1 -0
  32. package/dist/cli.js +616 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/codex/AppServerConnection.js +131 -0
  35. package/dist/codex/AppServerConnection.js.map +1 -0
  36. package/dist/codex/CodexEventMapper.js +296 -0
  37. package/dist/codex/CodexEventMapper.js.map +1 -0
  38. package/dist/codex/CodexLocalActivityDetector.js +124 -0
  39. package/dist/codex/CodexLocalActivityDetector.js.map +1 -0
  40. package/dist/codex/CodexProcessManager.js +64 -0
  41. package/dist/codex/CodexProcessManager.js.map +1 -0
  42. package/dist/codex/CodexRuntime.js +825 -0
  43. package/dist/codex/CodexRuntime.js.map +1 -0
  44. package/dist/codex/ProjectlessWorkspace.js +74 -0
  45. package/dist/codex/ProjectlessWorkspace.js.map +1 -0
  46. package/dist/codex/protocol.js +10 -0
  47. package/dist/codex/protocol.js.map +1 -0
  48. package/dist/commands/CommandRouter.js +176 -0
  49. package/dist/commands/CommandRouter.js.map +1 -0
  50. package/dist/commands/commandTypes.js +2 -0
  51. package/dist/commands/commandTypes.js.map +1 -0
  52. package/dist/config/loadConfig.js +107 -0
  53. package/dist/config/loadConfig.js.map +1 -0
  54. package/dist/config/paths.js +32 -0
  55. package/dist/config/paths.js.map +1 -0
  56. package/dist/config/schema.js +38 -0
  57. package/dist/config/schema.js.map +1 -0
  58. package/dist/console/ConsoleConnector.js +39 -0
  59. package/dist/console/ConsoleConnector.js.map +1 -0
  60. package/dist/console/ConsoleTurnPresenter.js +60 -0
  61. package/dist/console/ConsoleTurnPresenter.js.map +1 -0
  62. package/dist/feishu/CardRenderer.js +972 -0
  63. package/dist/feishu/CardRenderer.js.map +1 -0
  64. package/dist/feishu/CardUpdateScheduler.js +148 -0
  65. package/dist/feishu/CardUpdateScheduler.js.map +1 -0
  66. package/dist/feishu/ConsoleFeishuClient.js +18 -0
  67. package/dist/feishu/ConsoleFeishuClient.js.map +1 -0
  68. package/dist/feishu/FeishuConnector.js +257 -0
  69. package/dist/feishu/FeishuConnector.js.map +1 -0
  70. package/dist/feishu/FeishuMarkdown.js +37 -0
  71. package/dist/feishu/FeishuMarkdown.js.map +1 -0
  72. package/dist/feishu/FeishuMessageClient.js +459 -0
  73. package/dist/feishu/FeishuMessageClient.js.map +1 -0
  74. package/dist/feishu/FeishuTurnPresenter.js +425 -0
  75. package/dist/feishu/FeishuTurnPresenter.js.map +1 -0
  76. package/dist/feishu/GroupAvatarGenerator.js +86 -0
  77. package/dist/feishu/GroupAvatarGenerator.js.map +1 -0
  78. package/dist/feishu/LocalCardImage.js +13 -0
  79. package/dist/feishu/LocalCardImage.js.map +1 -0
  80. package/dist/feishu/LocalImageMarkdown.js +89 -0
  81. package/dist/feishu/LocalImageMarkdown.js.map +1 -0
  82. package/dist/feishu/contextKey.js +12 -0
  83. package/dist/feishu/contextKey.js.map +1 -0
  84. package/dist/feishu/transport.js +14 -0
  85. package/dist/feishu/transport.js.map +1 -0
  86. package/dist/feishu/types.js +2 -0
  87. package/dist/feishu/types.js.map +1 -0
  88. package/dist/index.js +213 -0
  89. package/dist/index.js.map +1 -0
  90. package/dist/logging/logger.js +22 -0
  91. package/dist/logging/logger.js.map +1 -0
  92. package/dist/presentation/OutboundRouter.js +127 -0
  93. package/dist/presentation/OutboundRouter.js.map +1 -0
  94. package/dist/presentation/TurnStateReducer.js +307 -0
  95. package/dist/presentation/TurnStateReducer.js.map +1 -0
  96. package/dist/presentation/splitMarkdown.js +341 -0
  97. package/dist/presentation/splitMarkdown.js.map +1 -0
  98. package/dist/presentation/turnViewTypes.js +2 -0
  99. package/dist/presentation/turnViewTypes.js.map +1 -0
  100. package/dist/proxy/ProxySessionController.js +2819 -0
  101. package/dist/proxy/ProxySessionController.js.map +1 -0
  102. package/dist/runtime/AcpRuntimeAdapter.js +271 -0
  103. package/dist/runtime/AcpRuntimeAdapter.js.map +1 -0
  104. package/dist/runtime/AgentRuntimeRegistry.js +18 -0
  105. package/dist/runtime/AgentRuntimeRegistry.js.map +1 -0
  106. package/dist/runtime/agentEnvironment.js +11 -0
  107. package/dist/runtime/agentEnvironment.js.map +1 -0
  108. package/dist/runtime/types.js +2 -0
  109. package/dist/runtime/types.js.map +1 -0
  110. package/dist/startup/SessionMetadataHydrator.js +46 -0
  111. package/dist/startup/SessionMetadataHydrator.js.map +1 -0
  112. package/dist/startup/StartupNotifier.js +78 -0
  113. package/dist/startup/StartupNotifier.js.map +1 -0
  114. package/dist/startup/startFeishu.js +6 -0
  115. package/dist/startup/startFeishu.js.map +1 -0
  116. package/dist/state/StateStore.js +893 -0
  117. package/dist/state/StateStore.js.map +1 -0
  118. package/dist/state/migrations.js +129 -0
  119. package/dist/state/migrations.js.map +1 -0
  120. package/dist/supervision/SafeRestartNotifier.js +116 -0
  121. package/dist/supervision/SafeRestartNotifier.js.map +1 -0
  122. package/dist/supervision/SafeRestartScheduler.js +123 -0
  123. package/dist/supervision/SafeRestartScheduler.js.map +1 -0
  124. package/dist/supervision/replacementSupervisor.js +8 -0
  125. package/dist/supervision/replacementSupervisor.js.map +1 -0
  126. package/dist/supervision/restartPolicy.js +16 -0
  127. package/dist/supervision/restartPolicy.js.map +1 -0
  128. package/dist/supervisor.js +94 -0
  129. package/dist/supervisor.js.map +1 -0
  130. package/dist/utils/executeShellCommand.js +76 -0
  131. package/dist/utils/executeShellCommand.js.map +1 -0
  132. package/dist/utils/id.js +5 -0
  133. package/dist/utils/id.js.map +1 -0
  134. package/dist/utils/markdown.js +29 -0
  135. package/dist/utils/markdown.js.map +1 -0
  136. package/dist/utils/spawnCommand.js +21 -0
  137. package/dist/utils/spawnCommand.js.map +1 -0
  138. package/dist/utils/taskTitle.js +10 -0
  139. package/dist/utils/taskTitle.js.map +1 -0
  140. package/docs/technical-reference.md +294 -0
  141. package/docs/technical-reference.zh.md +294 -0
  142. package/npm-shrinkwrap.json +4525 -0
  143. package/package.json +87 -0
  144. package/skills/agent-bot/SKILL.md +141 -0
  145. package/skills/agent-bot/agents/openai.yaml +4 -0
  146. package/src/acp/AcpJsonRpcConnection.ts +212 -0
  147. package/src/acp/AcpProcessManager.ts +87 -0
  148. package/src/acp/AcpSessionManager.ts +227 -0
  149. package/src/acp/acpTypes.ts +99 -0
  150. package/src/cli/FeishuAppConfiguration.ts +473 -0
  151. package/src/cli/FeishuAppRegistration.ts +207 -0
  152. package/src/cli/Initializer.ts +159 -0
  153. package/src/cli/LocalControlClient.ts +48 -0
  154. package/src/cli/LocalControlServer.ts +67 -0
  155. package/src/cli/SkillRegistry.ts +151 -0
  156. package/src/cli/controlProtocol.ts +34 -0
  157. package/src/cli/taskChatRoute.ts +31 -0
  158. package/src/cli.ts +630 -0
  159. package/src/codex/AppServerConnection.ts +159 -0
  160. package/src/codex/CodexEventMapper.ts +351 -0
  161. package/src/codex/CodexLocalActivityDetector.ts +148 -0
  162. package/src/codex/CodexProcessManager.ts +63 -0
  163. package/src/codex/CodexRuntime.ts +1025 -0
  164. package/src/codex/ProjectlessWorkspace.ts +90 -0
  165. package/src/codex/protocol.ts +37 -0
  166. package/src/commands/CommandRouter.ts +179 -0
  167. package/src/commands/commandTypes.ts +28 -0
  168. package/src/config/loadConfig.ts +115 -0
  169. package/src/config/paths.ts +37 -0
  170. package/src/config/schema.ts +46 -0
  171. package/src/console/ConsoleConnector.ts +40 -0
  172. package/src/console/ConsoleTurnPresenter.ts +64 -0
  173. package/src/feishu/CardRenderer.ts +1157 -0
  174. package/src/feishu/CardUpdateScheduler.ts +165 -0
  175. package/src/feishu/ConsoleFeishuClient.ts +22 -0
  176. package/src/feishu/FeishuConnector.ts +277 -0
  177. package/src/feishu/FeishuMarkdown.ts +47 -0
  178. package/src/feishu/FeishuMessageClient.ts +649 -0
  179. package/src/feishu/FeishuTurnPresenter.ts +539 -0
  180. package/src/feishu/GroupAvatarGenerator.ts +102 -0
  181. package/src/feishu/LocalCardImage.ts +13 -0
  182. package/src/feishu/LocalImageMarkdown.ts +92 -0
  183. package/src/feishu/contextKey.ts +14 -0
  184. package/src/feishu/transport.ts +24 -0
  185. package/src/feishu/types.ts +83 -0
  186. package/src/index.ts +228 -0
  187. package/src/logging/logger.ts +28 -0
  188. package/src/presentation/OutboundRouter.ts +205 -0
  189. package/src/presentation/TurnStateReducer.ts +341 -0
  190. package/src/presentation/splitMarkdown.ts +358 -0
  191. package/src/presentation/turnViewTypes.ts +54 -0
  192. package/src/proxy/ProxySessionController.ts +3311 -0
  193. package/src/runtime/AcpRuntimeAdapter.ts +324 -0
  194. package/src/runtime/AgentRuntimeRegistry.ts +20 -0
  195. package/src/runtime/agentEnvironment.ts +14 -0
  196. package/src/runtime/types.ts +215 -0
  197. package/src/startup/SessionMetadataHydrator.ts +46 -0
  198. package/src/startup/StartupNotifier.ts +92 -0
  199. package/src/startup/startFeishu.ts +19 -0
  200. package/src/state/StateStore.ts +1249 -0
  201. package/src/state/migrations.ts +128 -0
  202. package/src/supervision/SafeRestartNotifier.ts +122 -0
  203. package/src/supervision/SafeRestartScheduler.ts +149 -0
  204. package/src/supervision/replacementSupervisor.ts +10 -0
  205. package/src/supervision/restartPolicy.ts +19 -0
  206. package/src/supervisor.ts +106 -0
  207. package/src/utils/executeShellCommand.ts +97 -0
  208. package/src/utils/id.ts +5 -0
  209. package/src/utils/markdown.ts +25 -0
  210. package/src/utils/spawnCommand.ts +35 -0
  211. package/src/utils/taskTitle.ts +9 -0
  212. package/tsconfig.json +19 -0
@@ -0,0 +1,307 @@
1
+ const MAX_TEXT = 6_000;
2
+ const MAX_COMPLETED_TOOLS = 20;
3
+ const MAX_FAILED_TOOLS = 5;
4
+ const MAX_FILES = 30;
5
+ export function createTurnViewState(sessionId, turnId, startedAt, taskTitle, replyTarget, projectCwd, prompt) {
6
+ return {
7
+ sessionId,
8
+ turnId,
9
+ taskTitle,
10
+ prompt,
11
+ projectCwd,
12
+ replyTarget,
13
+ status: "starting",
14
+ startedAt,
15
+ assistantText: "",
16
+ plan: [],
17
+ activities: [],
18
+ totalToolCount: 0,
19
+ completedToolCount: 0,
20
+ failedToolCount: 0,
21
+ toolStatuses: {},
22
+ completedTools: [],
23
+ failedTools: [],
24
+ fileSummary: [],
25
+ };
26
+ }
27
+ export function reduceTurnEvent(state, event) {
28
+ if (event.sessionId !== state.sessionId || event.turnId !== state.turnId)
29
+ return state;
30
+ switch (event.type) {
31
+ case "turn_started":
32
+ return { ...state, status: "running", startedAt: event.startedAt };
33
+ case "agent_text_delta":
34
+ return { ...state, assistantText: bound(`${state.assistantText}${event.text}`) };
35
+ case "token_usage_updated": {
36
+ const lastTokens = normalizeTokenCount(event.lastTokens);
37
+ const cumulativeTokens = normalizeTokenCount(event.cumulativeTokens);
38
+ const previousCumulative = state.tokenUsageCumulative;
39
+ const delta = previousCumulative === undefined
40
+ ? lastTokens
41
+ : Math.max(0, cumulativeTokens - previousCumulative);
42
+ return {
43
+ ...state,
44
+ totalTokens: (state.totalTokens ?? 0) + delta,
45
+ tokenUsageCumulative: Math.max(previousCumulative ?? 0, cumulativeTokens),
46
+ };
47
+ }
48
+ case "progress": {
49
+ const activityUpdate = upsertReasoningActivity(state.activities ?? [], event.activityId ?? "progress", event.text, event.append === true, event.activityId?.startsWith("commentary:") ? "assistant" : "reasoning");
50
+ return {
51
+ ...state,
52
+ progressText: bound(event.text),
53
+ activities: activityUpdate.activities,
54
+ activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
55
+ };
56
+ }
57
+ case "plan_updated":
58
+ return { ...state, plan: event.steps.slice(0, 30).map((step) => ({ ...step, text: bound(step.text) })) };
59
+ case "tool_started": {
60
+ const tool = withToolTiming(state, event.tool);
61
+ const bounded = boundTool(tool);
62
+ const activityUpdate = upsertToolActivity(state.activities ?? [], bounded);
63
+ const tracking = trackToolStatus(state, tool);
64
+ return {
65
+ ...state,
66
+ ...tracking,
67
+ status: "tool_running",
68
+ activeTool: bounded,
69
+ activities: activityUpdate.activities,
70
+ activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
71
+ fileSummary: mergeFiles(state.fileSummary, tool.files),
72
+ };
73
+ }
74
+ case "tool_updated":
75
+ return reduceToolUpdate(state, event.tool);
76
+ case "tool_output_delta":
77
+ return reduceToolOutputDelta(state, event.toolId, event.delta);
78
+ case "approval_requested":
79
+ return { ...state, status: "waiting_for_approval", approval: event.request };
80
+ case "approval_resolved":
81
+ return { ...state, status: state.activeTool ? "tool_running" : "running", approval: undefined };
82
+ case "turn_completed":
83
+ return {
84
+ ...state,
85
+ status: "completed",
86
+ activeTool: undefined,
87
+ approval: undefined,
88
+ completedAt: state.startedAt + (event.durationMs ?? Date.now() - state.startedAt),
89
+ durationMs: event.durationMs ?? Date.now() - state.startedAt,
90
+ finalResponse: event.finalResponse,
91
+ };
92
+ case "turn_cancelled":
93
+ return { ...state, status: "cancelled", activeTool: undefined, approval: undefined, completedAt: Date.now() };
94
+ case "turn_failed":
95
+ return {
96
+ ...state,
97
+ status: "failed",
98
+ activeTool: undefined,
99
+ approval: undefined,
100
+ completedAt: Date.now(),
101
+ error: bound(event.message),
102
+ };
103
+ }
104
+ }
105
+ export function appendSteerMessage(state, id, text) {
106
+ const normalized = text.trim();
107
+ if (!normalized)
108
+ return state;
109
+ const activities = state.activities ?? [];
110
+ const index = activities.findIndex((activity) => activity.id === id);
111
+ const activityUpdate = upsertActivity(activities, index, {
112
+ kind: "user",
113
+ id,
114
+ text: bound(normalized),
115
+ });
116
+ return {
117
+ ...state,
118
+ activities: activityUpdate.activities,
119
+ activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
120
+ };
121
+ }
122
+ function reduceToolOutputDelta(state, toolId, delta) {
123
+ if (!delta)
124
+ return state;
125
+ const tool = findTool(state, toolId);
126
+ if (!tool || tool.status !== "running" || tool.kind !== "command")
127
+ return state;
128
+ return reduceToolUpdate(state, {
129
+ ...tool,
130
+ output: appendBoundedOutput(tool.output, delta),
131
+ });
132
+ }
133
+ function findTool(state, toolId) {
134
+ if (state.activeTool?.id === toolId)
135
+ return state.activeTool;
136
+ const activity = [...(state.activities ?? [])].reverse().find((candidate) => candidate.kind === "tool" && candidate.tool.id === toolId);
137
+ if (activity?.kind === "tool")
138
+ return activity.tool;
139
+ return state.failedTools.find((tool) => tool.id === toolId)
140
+ ?? state.completedTools.find((tool) => tool.id === toolId);
141
+ }
142
+ function withToolTiming(state, tool) {
143
+ const previous = findTool(state, tool.id);
144
+ const now = Date.now();
145
+ const startedAt = tool.startedAt ?? previous?.startedAt ?? tool.completedAt ?? now;
146
+ return {
147
+ ...tool,
148
+ startedAt,
149
+ completedAt: tool.status === "running" ? tool.completedAt : tool.completedAt ?? now,
150
+ };
151
+ }
152
+ function appendBoundedOutput(previous, delta) {
153
+ const combined = `${previous ?? ""}${delta}`;
154
+ if (combined.length <= MAX_TEXT)
155
+ return combined;
156
+ return `…${combined.slice(-(MAX_TEXT - 1))}`;
157
+ }
158
+ function reduceToolUpdate(state, tool) {
159
+ tool = withToolTiming(state, tool);
160
+ const tracking = trackToolStatus(state, tool);
161
+ const bounded = boundTool(tool);
162
+ const activityUpdate = upsertToolActivity(state.activities ?? [], bounded);
163
+ const withoutCompleted = state.completedTools.filter((item) => item.id !== tool.id);
164
+ const withoutFailed = state.failedTools.filter((item) => item.id !== tool.id);
165
+ const activeTool = state.activeTool?.id === tool.id ? undefined : state.activeTool;
166
+ if (tool.status === "running") {
167
+ return {
168
+ ...state,
169
+ ...tracking,
170
+ status: "tool_running",
171
+ activeTool: bounded,
172
+ activities: activityUpdate.activities,
173
+ activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
174
+ completedTools: withoutCompleted,
175
+ failedTools: withoutFailed,
176
+ fileSummary: mergeFiles(state.fileSummary, tool.files),
177
+ };
178
+ }
179
+ if (tool.status === "failed") {
180
+ return {
181
+ ...state,
182
+ ...tracking,
183
+ status: activeTool ? "tool_running" : "running",
184
+ activeTool,
185
+ activities: activityUpdate.activities,
186
+ activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
187
+ completedTools: withoutCompleted,
188
+ failedTools: [...withoutFailed, bounded].slice(-MAX_FAILED_TOOLS),
189
+ fileSummary: mergeFiles(state.fileSummary, tool.files),
190
+ };
191
+ }
192
+ return {
193
+ ...state,
194
+ ...tracking,
195
+ status: activeTool ? "tool_running" : "running",
196
+ activeTool,
197
+ activities: activityUpdate.activities,
198
+ activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
199
+ failedTools: withoutFailed,
200
+ completedTools: [...withoutCompleted, bounded].slice(-MAX_COMPLETED_TOOLS),
201
+ fileSummary: mergeFiles(state.fileSummary, tool.files),
202
+ };
203
+ }
204
+ function trackToolStatus(state, tool) {
205
+ const toolStatuses = state.toolStatuses
206
+ ? { ...state.toolStatuses }
207
+ : legacyToolStatuses(state);
208
+ const previous = toolStatuses[tool.id];
209
+ let totalToolCount = state.totalToolCount ?? Object.keys(toolStatuses).length;
210
+ let completedToolCount = state.completedToolCount
211
+ ?? Object.values(toolStatuses).filter((status) => status === "completed").length;
212
+ let failedToolCount = state.failedToolCount
213
+ ?? Object.values(toolStatuses).filter((status) => status === "failed").length;
214
+ if (previous === undefined)
215
+ totalToolCount += 1;
216
+ if (previous !== tool.status) {
217
+ if (previous === "completed")
218
+ completedToolCount = Math.max(0, completedToolCount - 1);
219
+ if (previous === "failed")
220
+ failedToolCount = Math.max(0, failedToolCount - 1);
221
+ if (tool.status === "completed")
222
+ completedToolCount += 1;
223
+ if (tool.status === "failed")
224
+ failedToolCount += 1;
225
+ }
226
+ toolStatuses[tool.id] = tool.status;
227
+ return { totalToolCount, completedToolCount, failedToolCount, toolStatuses };
228
+ }
229
+ function legacyToolStatuses(state) {
230
+ const statuses = {};
231
+ for (const tool of state.completedTools ?? [])
232
+ statuses[tool.id] = tool.status;
233
+ for (const tool of state.failedTools ?? [])
234
+ statuses[tool.id] = tool.status;
235
+ for (const activity of state.activities ?? []) {
236
+ if (activity.kind === "tool")
237
+ statuses[activity.tool.id] = activity.tool.status;
238
+ }
239
+ if (state.activeTool)
240
+ statuses[state.activeTool.id] = state.activeTool.status;
241
+ return statuses;
242
+ }
243
+ function upsertReasoningActivity(activities, id, text, append, kind) {
244
+ const index = activities.findIndex((activity) => activity.id === id);
245
+ const existing = index >= 0 ? activities[index] : undefined;
246
+ const previousText = existing?.kind === "reasoning" || existing?.kind === "assistant" ? existing.text : "";
247
+ const combined = append ? `${previousText}${text}` : text;
248
+ const next = {
249
+ kind,
250
+ id,
251
+ text: kind === "assistant" ? combined : bound(combined),
252
+ };
253
+ return upsertActivity(activities, index, next);
254
+ }
255
+ function upsertToolActivity(activities, tool) {
256
+ const index = activities.findIndex((activity) => activity.id === tool.id);
257
+ return upsertActivity(activities, index, { kind: "tool", id: tool.id, tool });
258
+ }
259
+ function upsertActivity(activities, index, activity) {
260
+ const updated = [...activities];
261
+ if (index >= 0)
262
+ updated[index] = activity;
263
+ else
264
+ updated.push(activity);
265
+ return {
266
+ activities: updated,
267
+ truncated: false,
268
+ };
269
+ }
270
+ function boundTool(tool) {
271
+ return {
272
+ ...tool,
273
+ title: bound(tool.title),
274
+ command: tool.command === undefined ? undefined : bound(tool.command),
275
+ output: tool.output === undefined ? undefined : bound(tool.output),
276
+ error: tool.error === undefined ? undefined : bound(tool.error),
277
+ files: tool.files?.slice(0, MAX_FILES),
278
+ };
279
+ }
280
+ function mergeFiles(existing, incoming) {
281
+ if (!incoming?.length)
282
+ return existing;
283
+ const merged = new Map(existing.map((file) => [file.path, { ...file }]));
284
+ for (const file of incoming) {
285
+ const previous = merged.get(file.path);
286
+ merged.set(file.path, {
287
+ path: file.path,
288
+ additions: addOptional(previous?.additions, file.additions),
289
+ deletions: addOptional(previous?.deletions, file.deletions),
290
+ });
291
+ }
292
+ return [...merged.values()].slice(-MAX_FILES);
293
+ }
294
+ function addOptional(left, right) {
295
+ if (left === undefined && right === undefined)
296
+ return undefined;
297
+ return (left ?? 0) + (right ?? 0);
298
+ }
299
+ function bound(value) {
300
+ if (value.length <= MAX_TEXT)
301
+ return value;
302
+ return `${value.slice(0, MAX_TEXT - 1)}…`;
303
+ }
304
+ function normalizeTokenCount(value) {
305
+ return Math.max(0, Math.round(value));
306
+ }
307
+ //# sourceMappingURL=TurnStateReducer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TurnStateReducer.js","sourceRoot":"","sources":["../../src/presentation/TurnStateReducer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,341 @@
1
+ export function splitMarkdown(text, maxLength = 4_000) {
2
+ if (maxLength < 32)
3
+ throw new Error("maxLength must be at least 32");
4
+ if (text.length <= maxLength)
5
+ return [text];
6
+ const chunks = [];
7
+ let current = "";
8
+ let fence;
9
+ const lines = text.match(/[^\n]*\n|[^\n]+$/g) ?? [];
10
+ const closingSuffix = () => {
11
+ if (!fence)
12
+ return "";
13
+ return `${current.endsWith("\n") ? "" : "\n"}${fence.delimiter}`;
14
+ };
15
+ const flush = () => {
16
+ if (!current)
17
+ return;
18
+ const continuation = fence;
19
+ chunks.push(`${current}${closingSuffix()}`);
20
+ current = continuation ? `${continuation.opener}\n` : "";
21
+ };
22
+ const appendPlainLine = (line) => {
23
+ const atomicRanges = fence ? [] : markdownAtomicRanges(line);
24
+ let offset = 0;
25
+ while (offset < line.length) {
26
+ // Reserve the worst-case newline plus delimiter because the appended
27
+ // slice may change a newline-terminated buffer into a partial line.
28
+ const reserve = fence ? fence.delimiter.length + 1 : 0;
29
+ const available = maxLength - current.length - reserve;
30
+ if (available <= 0) {
31
+ flush();
32
+ continue;
33
+ }
34
+ const continuationPrefix = fence ? `${fence.opener}\n` : "";
35
+ const hasPayload = current.length > continuationPrefix.length;
36
+ const remainingLength = line.length - offset;
37
+ if (remainingLength > available && hasPayload) {
38
+ // Prefer a line boundary over filling the previous chunk. Apart from
39
+ // producing more readable pages, this gives inline Markdown such as
40
+ // links and code spans the full capacity of the next chunk.
41
+ flush();
42
+ continue;
43
+ }
44
+ let partLength = Math.min(remainingLength, available);
45
+ if (!fence && remainingLength > available) {
46
+ partLength = findSafeMarkdownSplit(line, offset, available, atomicRanges);
47
+ // A Markdown construct may itself be larger than the message limit.
48
+ // It cannot be kept intact, so retain the lossless hard-split fallback.
49
+ if (partLength <= 0)
50
+ partLength = available;
51
+ }
52
+ const part = line.slice(offset, offset + partLength);
53
+ current += part;
54
+ offset += part.length;
55
+ if (offset < line.length)
56
+ flush();
57
+ }
58
+ };
59
+ const appendTable = (tableLines) => {
60
+ const header = tableLines[0];
61
+ const delimiter = tableLines[1];
62
+ if (!header || !delimiter)
63
+ return;
64
+ const continuationPrefix = `${header}${delimiter}`;
65
+ const firstRow = tableLines[2];
66
+ const headerLength = header.length + delimiter.length;
67
+ const initialTableLength = firstRow && headerLength + firstRow.length <= maxLength
68
+ ? headerLength + firstRow.length
69
+ : headerLength;
70
+ if (current && initialTableLength <= maxLength && current.length + initialTableLength > maxLength)
71
+ flush();
72
+ if (headerLength <= maxLength) {
73
+ current += header;
74
+ current += delimiter;
75
+ }
76
+ else {
77
+ appendPlainLine(header);
78
+ appendPlainLine(delimiter);
79
+ }
80
+ for (const row of tableLines.slice(2)) {
81
+ if (current.length + row.length <= maxLength) {
82
+ current += row;
83
+ continue;
84
+ }
85
+ flush();
86
+ if (continuationPrefix.length + row.length <= maxLength) {
87
+ current = continuationPrefix;
88
+ current += row;
89
+ continue;
90
+ }
91
+ // A single data row can itself exceed the card limit. There is no way
92
+ // to preserve it as one Markdown table row in that case, so retain the
93
+ // existing lossless hard-split fallback.
94
+ current = continuationPrefix;
95
+ appendPlainLine(row);
96
+ }
97
+ };
98
+ for (let index = 0; index < lines.length; index += 1) {
99
+ const line = lines[index];
100
+ if (!fence && isTableHeader(line, lines[index + 1])) {
101
+ const tableLines = [line, lines[index + 1]];
102
+ index += 2;
103
+ while (index < lines.length && isTableRow(lines[index])) {
104
+ tableLines.push(lines[index]);
105
+ index += 1;
106
+ }
107
+ index -= 1;
108
+ appendTable(tableLines);
109
+ continue;
110
+ }
111
+ const fenceLine = parseFence(line);
112
+ if (fenceLine) {
113
+ const isClosing = fence !== undefined && fenceLine.delimiter.startsWith(fence.delimiter.slice(0, 3));
114
+ const nextFence = isClosing ? undefined : fence ?? fenceLine;
115
+ const reserve = nextFence ? suffixLength(current + line, nextFence.delimiter) : 0;
116
+ if (current && current.length + line.length + reserve > maxLength)
117
+ flush();
118
+ current += line;
119
+ fence = nextFence;
120
+ continue;
121
+ }
122
+ appendPlainLine(line);
123
+ }
124
+ flush();
125
+ return chunks;
126
+ }
127
+ function isTableHeader(line, nextLine) {
128
+ return isTableRow(line) && nextLine !== undefined && isTableDelimiter(nextLine);
129
+ }
130
+ function isTableRow(line) {
131
+ const value = line.trim();
132
+ return value.length > 0 && unescapedPipeCount(value) > 0;
133
+ }
134
+ function isTableDelimiter(line) {
135
+ const cells = tableCells(line);
136
+ return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell.trim()));
137
+ }
138
+ function tableCells(line) {
139
+ const value = line.trim().replace(/^\|/, "").replace(/\|$/, "");
140
+ const cells = [];
141
+ let current = "";
142
+ let escaped = false;
143
+ for (const character of value) {
144
+ if (character === "|" && !escaped) {
145
+ cells.push(current);
146
+ current = "";
147
+ }
148
+ else {
149
+ current += character;
150
+ }
151
+ if (character === "\\" && !escaped)
152
+ escaped = true;
153
+ else
154
+ escaped = false;
155
+ }
156
+ cells.push(current);
157
+ return cells;
158
+ }
159
+ function unescapedPipeCount(value) {
160
+ let count = 0;
161
+ let escaped = false;
162
+ for (const character of value) {
163
+ if (character === "|" && !escaped)
164
+ count += 1;
165
+ if (character === "\\" && !escaped)
166
+ escaped = true;
167
+ else
168
+ escaped = false;
169
+ }
170
+ return count;
171
+ }
172
+ function findSafeMarkdownSplit(value, start, limit, ranges) {
173
+ if (value.length - start <= limit)
174
+ return value.length - start;
175
+ let boundary = start + limit;
176
+ const activeRanges = ranges.filter((range) => range.start >= start);
177
+ for (const range of activeRanges) {
178
+ if (range.start < boundary && boundary < range.end) {
179
+ boundary = range.start;
180
+ break;
181
+ }
182
+ }
183
+ if (boundary <= start)
184
+ return 0;
185
+ // Prefer a natural reading boundary, provided it is not inside another
186
+ // protected Markdown construct. Whitespace remains in the preceding chunk,
187
+ // so concatenating plain-text chunks is lossless.
188
+ for (let index = boundary; index > start; index -= 1) {
189
+ if (/\s/.test(value[index - 1]) && isSafeBoundary(index, activeRanges))
190
+ return index - start;
191
+ }
192
+ for (let index = boundary; index > start; index -= 1) {
193
+ if (/[,。;:、,.!?;:]/.test(value[index - 1]) && isSafeBoundary(index, activeRanges))
194
+ return index - start;
195
+ }
196
+ return isSafeBoundary(boundary, activeRanges) ? boundary - start : 0;
197
+ }
198
+ function markdownAtomicRanges(value) {
199
+ const ranges = [];
200
+ collectCodeSpans(value, ranges);
201
+ collectLinksAndImages(value, ranges);
202
+ collectAngleSpans(value, ranges);
203
+ collectEmphasisSpans(value, ranges);
204
+ return mergeRanges(ranges);
205
+ }
206
+ function collectCodeSpans(value, ranges) {
207
+ for (let index = 0; index < value.length;) {
208
+ if (value[index] !== "`" || isEscaped(value, index)) {
209
+ index += 1;
210
+ continue;
211
+ }
212
+ const delimiterLength = repeatedCharacterLength(value, index, "`");
213
+ const end = findClosingRun(value, index + delimiterLength, "`", delimiterLength);
214
+ if (end === -1) {
215
+ index += delimiterLength;
216
+ continue;
217
+ }
218
+ ranges.push({ start: index, end: end + delimiterLength });
219
+ index = end + delimiterLength;
220
+ }
221
+ }
222
+ function collectLinksAndImages(value, ranges) {
223
+ for (let index = 0; index < value.length; index += 1) {
224
+ if (value[index] !== "[" || isEscaped(value, index))
225
+ continue;
226
+ const labelEnd = findMatchingDelimiter(value, index, "[", "]");
227
+ if (labelEnd === -1)
228
+ continue;
229
+ const start = index > 0 && value[index - 1] === "!" && !isEscaped(value, index - 1)
230
+ ? index - 1
231
+ : index;
232
+ let end = labelEnd + 1;
233
+ if (value[end] === "(") {
234
+ const destinationEnd = findMatchingDelimiter(value, end, "(", ")");
235
+ if (destinationEnd !== -1)
236
+ end = destinationEnd + 1;
237
+ }
238
+ else if (value[end] === "[") {
239
+ const referenceEnd = findMatchingDelimiter(value, end, "[", "]");
240
+ if (referenceEnd !== -1)
241
+ end = referenceEnd + 1;
242
+ }
243
+ ranges.push({ start, end });
244
+ index = end - 1;
245
+ }
246
+ }
247
+ function collectAngleSpans(value, ranges) {
248
+ for (let index = 0; index < value.length; index += 1) {
249
+ if (value[index] !== "<" || isEscaped(value, index))
250
+ continue;
251
+ const end = findUnescaped(value, ">", index + 1);
252
+ if (end !== -1) {
253
+ ranges.push({ start: index, end: end + 1 });
254
+ index = end;
255
+ }
256
+ }
257
+ }
258
+ function collectEmphasisSpans(value, ranges) {
259
+ const delimiters = ["***", "___", "**", "__", "~~", "*", "_"];
260
+ for (let index = 0; index < value.length; index += 1) {
261
+ if (isEscaped(value, index))
262
+ continue;
263
+ const delimiter = delimiters.find((candidate) => value.startsWith(candidate, index));
264
+ if (!delimiter || /\s/.test(value[index + delimiter.length] ?? ""))
265
+ continue;
266
+ const end = findUnescaped(value, delimiter, index + delimiter.length, (candidate) => (candidate > index + delimiter.length
267
+ && !/\s/.test(value[candidate - 1] ?? "")));
268
+ if (end === -1)
269
+ continue;
270
+ ranges.push({ start: index, end: end + delimiter.length });
271
+ index = end + delimiter.length - 1;
272
+ }
273
+ }
274
+ function findMatchingDelimiter(value, start, opener, closer) {
275
+ let depth = 0;
276
+ for (let index = start; index < value.length; index += 1) {
277
+ if (isEscaped(value, index))
278
+ continue;
279
+ if (value[index] === opener)
280
+ depth += 1;
281
+ else if (value[index] === closer) {
282
+ depth -= 1;
283
+ if (depth === 0)
284
+ return index;
285
+ }
286
+ }
287
+ return -1;
288
+ }
289
+ function findClosingRun(value, start, character, length) {
290
+ const delimiter = character.repeat(length);
291
+ return findUnescaped(value, delimiter, start, (index) => (value[index - 1] !== character && value[index + length] !== character));
292
+ }
293
+ function findUnescaped(value, needle, start, accept = () => true) {
294
+ let index = value.indexOf(needle, start);
295
+ while (index !== -1) {
296
+ if (!isEscaped(value, index) && accept(index))
297
+ return index;
298
+ index = value.indexOf(needle, index + 1);
299
+ }
300
+ return -1;
301
+ }
302
+ function repeatedCharacterLength(value, start, character) {
303
+ let end = start;
304
+ while (value[end] === character)
305
+ end += 1;
306
+ return end - start;
307
+ }
308
+ function isEscaped(value, index) {
309
+ let slashes = 0;
310
+ for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1)
311
+ slashes += 1;
312
+ return slashes % 2 === 1;
313
+ }
314
+ function mergeRanges(ranges) {
315
+ const sorted = [...ranges].sort((left, right) => left.start - right.start || left.end - right.end);
316
+ const merged = [];
317
+ for (const range of sorted) {
318
+ const previous = merged.at(-1);
319
+ if (!previous || range.start >= previous.end) {
320
+ merged.push({ ...range });
321
+ }
322
+ else if (range.end > previous.end) {
323
+ previous.end = range.end;
324
+ }
325
+ }
326
+ return merged;
327
+ }
328
+ function isSafeBoundary(index, ranges) {
329
+ return ranges.every((range) => index <= range.start || index >= range.end);
330
+ }
331
+ function parseFence(line) {
332
+ const trimmed = line.trimEnd();
333
+ const match = trimmed.match(/^\s*((?:`{3,})|(?:~{3,}))(.*)$/);
334
+ if (!match?.[1])
335
+ return undefined;
336
+ return { opener: trimmed.trimStart(), delimiter: match[1] };
337
+ }
338
+ function suffixLength(value, delimiter) {
339
+ return (value.endsWith("\n") ? 0 : 1) + delimiter.length;
340
+ }
341
+ //# sourceMappingURL=splitMarkdown.js.map