wave-agent-sdk 1.0.5 → 1.0.6

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 (193) hide show
  1. package/dist/agent.d.ts +23 -1
  2. package/dist/agent.js +34 -4
  3. package/dist/managers/aiManager.d.ts +36 -0
  4. package/dist/managers/aiManager.js +240 -8
  5. package/dist/managers/messageManager.d.ts +1 -3
  6. package/dist/managers/messageManager.js +13 -6
  7. package/dist/managers/slashCommandManager.js +28 -0
  8. package/dist/managers/subagentManager.d.ts +0 -2
  9. package/dist/telemetry/instrumentation.d.ts +1 -1
  10. package/dist/telemetry/instrumentation.js +57 -28
  11. package/dist/tools/bashTool.js +16 -6
  12. package/dist/tools/grepTool.js +11 -3
  13. package/dist/types/index.d.ts +3 -0
  14. package/dist/types/messaging.d.ts +2 -0
  15. package/dist/utils/containerSetup.js +0 -3
  16. package/dist/utils/messageOperations.d.ts +2 -1
  17. package/dist/utils/messageOperations.js +2 -1
  18. package/dist/utils/notificationXml.js +5 -0
  19. package/dist/utils/ripgrep.d.ts +4 -4
  20. package/dist/utils/ripgrep.js +4 -27
  21. package/package.json +20 -8
  22. package/bin/rg +0 -79
  23. package/dist/managers/forkedAgentManager.d.ts +0 -50
  24. package/dist/managers/forkedAgentManager.js +0 -130
  25. package/scripts/install_ripgrep.js +0 -111
  26. package/scripts/postinstall.js +0 -38
  27. package/src/agent.ts +0 -1271
  28. package/src/constants/subagents.ts +0 -4
  29. package/src/constants/toolLimits.ts +0 -15
  30. package/src/constants/tools.ts +0 -24
  31. package/src/core/plugin.ts +0 -237
  32. package/src/core/session.ts +0 -9
  33. package/src/index.ts +0 -38
  34. package/src/managers/MemoryRuleManager.ts +0 -198
  35. package/src/managers/aiManager.ts +0 -2429
  36. package/src/managers/backgroundTaskManager.ts +0 -480
  37. package/src/managers/bangManager.ts +0 -119
  38. package/src/managers/cronManager.ts +0 -401
  39. package/src/managers/foregroundTaskManager.ts +0 -30
  40. package/src/managers/forkedAgentManager.ts +0 -216
  41. package/src/managers/hookManager.ts +0 -1089
  42. package/src/managers/liveConfigManager.ts +0 -445
  43. package/src/managers/lspManager.ts +0 -470
  44. package/src/managers/mcpManager.ts +0 -1010
  45. package/src/managers/messageManager.ts +0 -1184
  46. package/src/managers/messageQueue.ts +0 -157
  47. package/src/managers/permissionManager.ts +0 -1140
  48. package/src/managers/planManager.ts +0 -112
  49. package/src/managers/pluginManager.ts +0 -330
  50. package/src/managers/pluginScopeManager.ts +0 -124
  51. package/src/managers/reversionManager.ts +0 -178
  52. package/src/managers/skillManager.ts +0 -578
  53. package/src/managers/slashCommandManager.ts +0 -564
  54. package/src/managers/subagentManager.ts +0 -915
  55. package/src/managers/toolManager.ts +0 -489
  56. package/src/managers/workflowManager.ts +0 -493
  57. package/src/prompts/autoMemory.ts +0 -33
  58. package/src/prompts/autoMemoryExtraction.ts +0 -146
  59. package/src/prompts/index.ts +0 -506
  60. package/src/prompts/planModeReminders.ts +0 -126
  61. package/src/services/GitService.ts +0 -131
  62. package/src/services/MarketplaceService.ts +0 -1052
  63. package/src/services/MemoryRuleService.ts +0 -71
  64. package/src/services/aiService.ts +0 -919
  65. package/src/services/authService.ts +0 -565
  66. package/src/services/autoMemoryService.ts +0 -280
  67. package/src/services/configurationService.ts +0 -1520
  68. package/src/services/fileWatcher.ts +0 -319
  69. package/src/services/hook.ts +0 -348
  70. package/src/services/initializationService.ts +0 -357
  71. package/src/services/interactionService.ts +0 -229
  72. package/src/services/jsonlHandler.ts +0 -295
  73. package/src/services/memory.ts +0 -234
  74. package/src/services/pluginLoader.ts +0 -252
  75. package/src/services/remoteSettingsService.ts +0 -366
  76. package/src/services/reversionService.ts +0 -122
  77. package/src/services/session.ts +0 -917
  78. package/src/services/taskManager.ts +0 -321
  79. package/src/telemetry/events.ts +0 -65
  80. package/src/telemetry/instrumentation.ts +0 -499
  81. package/src/telemetry/sessionTracing.ts +0 -348
  82. package/src/tools/agentTool.ts +0 -322
  83. package/src/tools/askUserQuestion.ts +0 -160
  84. package/src/tools/bashTool.ts +0 -621
  85. package/src/tools/buildTool.ts +0 -61
  86. package/src/tools/cronCreateTool.ts +0 -161
  87. package/src/tools/cronDeleteTool.ts +0 -51
  88. package/src/tools/cronListTool.ts +0 -47
  89. package/src/tools/editTool.ts +0 -313
  90. package/src/tools/enterPlanMode.ts +0 -124
  91. package/src/tools/enterWorktreeTool.ts +0 -190
  92. package/src/tools/exitPlanMode.ts +0 -139
  93. package/src/tools/exitWorktreeTool.ts +0 -236
  94. package/src/tools/globTool.ts +0 -167
  95. package/src/tools/grepTool.ts +0 -399
  96. package/src/tools/lspTool.ts +0 -883
  97. package/src/tools/readTool.ts +0 -426
  98. package/src/tools/skillTool.ts +0 -248
  99. package/src/tools/taskManagementTools.ts +0 -574
  100. package/src/tools/taskStopTool.ts +0 -78
  101. package/src/tools/types.ts +0 -137
  102. package/src/tools/webFetchTool.ts +0 -373
  103. package/src/tools/workflowTool.ts +0 -205
  104. package/src/tools/writeTool.ts +0 -267
  105. package/src/types/agent.ts +0 -128
  106. package/src/types/auth.ts +0 -19
  107. package/src/types/commands.ts +0 -30
  108. package/src/types/config.ts +0 -43
  109. package/src/types/configuration.ts +0 -168
  110. package/src/types/core.ts +0 -105
  111. package/src/types/cron.ts +0 -13
  112. package/src/types/environment.ts +0 -106
  113. package/src/types/fileSearch.ts +0 -4
  114. package/src/types/history.ts +0 -7
  115. package/src/types/hooks.ts +0 -256
  116. package/src/types/index.ts +0 -41
  117. package/src/types/lsp.ts +0 -98
  118. package/src/types/marketplace.ts +0 -71
  119. package/src/types/mcp.ts +0 -43
  120. package/src/types/memoryRule.ts +0 -31
  121. package/src/types/messaging.ts +0 -114
  122. package/src/types/permissions.ts +0 -80
  123. package/src/types/plugins.ts +0 -39
  124. package/src/types/processes.ts +0 -99
  125. package/src/types/reversion.ts +0 -29
  126. package/src/types/session.ts +0 -12
  127. package/src/types/skills.ts +0 -108
  128. package/src/types/tasks.ts +0 -13
  129. package/src/types/telemetry.ts +0 -98
  130. package/src/types/tools.ts +0 -44
  131. package/src/types/workflow.ts +0 -6
  132. package/src/utils/abortUtils.ts +0 -118
  133. package/src/utils/atomicWrite.ts +0 -61
  134. package/src/utils/bashParser.ts +0 -899
  135. package/src/utils/cacheControlUtils.ts +0 -426
  136. package/src/utils/commandArgumentParser.ts +0 -161
  137. package/src/utils/commandPathResolver.ts +0 -88
  138. package/src/utils/configPaths.ts +0 -220
  139. package/src/utils/configValidator.ts +0 -100
  140. package/src/utils/constants.ts +0 -39
  141. package/src/utils/container.ts +0 -92
  142. package/src/utils/containerSetup.ts +0 -371
  143. package/src/utils/convertMessagesForAPI.ts +0 -326
  144. package/src/utils/cronTasks.ts +0 -128
  145. package/src/utils/cronTasksLock.ts +0 -182
  146. package/src/utils/cronToHuman.ts +0 -99
  147. package/src/utils/customCommands.ts +0 -95
  148. package/src/utils/editUtils.ts +0 -20
  149. package/src/utils/fileFormat.ts +0 -40
  150. package/src/utils/fileSearch.ts +0 -151
  151. package/src/utils/fileUtils.ts +0 -223
  152. package/src/utils/gitUtils.ts +0 -315
  153. package/src/utils/globalLogger.ts +0 -128
  154. package/src/utils/groupMessagesByApiRound.ts +0 -121
  155. package/src/utils/hookMatcher.ts +0 -176
  156. package/src/utils/markdownParser.ts +0 -317
  157. package/src/utils/mcpUtils.ts +0 -138
  158. package/src/utils/messageOperations.ts +0 -659
  159. package/src/utils/modelCapabilities.ts +0 -30
  160. package/src/utils/nameGenerator.ts +0 -99
  161. package/src/utils/notificationXml.ts +0 -57
  162. package/src/utils/openaiClient.ts +0 -251
  163. package/src/utils/parseCronExpression.ts +0 -78
  164. package/src/utils/path.ts +0 -72
  165. package/src/utils/pathEncoder.ts +0 -400
  166. package/src/utils/pathSafety.ts +0 -40
  167. package/src/utils/promptHistory.ts +0 -168
  168. package/src/utils/ripgrep.ts +0 -35
  169. package/src/utils/shellResolver.ts +0 -190
  170. package/src/utils/skillParser.ts +0 -246
  171. package/src/utils/stringUtils.ts +0 -156
  172. package/src/utils/subagentParser.ts +0 -279
  173. package/src/utils/taskReminder.ts +0 -96
  174. package/src/utils/tokenCalculation.ts +0 -43
  175. package/src/utils/tokenEstimate.ts +0 -34
  176. package/src/utils/toolResultStorage.ts +0 -117
  177. package/src/utils/worktreeSession.ts +0 -26
  178. package/src/utils/worktreeUtils.ts +0 -786
  179. package/src/workflow/budgetTracker.ts +0 -34
  180. package/src/workflow/concurrencyLimiter.ts +0 -47
  181. package/src/workflow/journal.ts +0 -95
  182. package/src/workflow/progressReporter.ts +0 -141
  183. package/src/workflow/runState.ts +0 -65
  184. package/src/workflow/scriptRuntime.ts +0 -274
  185. package/src/workflow/structuredOutput.ts +0 -123
  186. package/src/workflow/types.ts +0 -101
  187. package/src/workflow/workflowApis.ts +0 -410
  188. package/vendor/ripgrep/linux-aarch64/rg +0 -0
  189. package/vendor/ripgrep/linux-x86_64/rg +0 -0
  190. package/vendor/ripgrep/macos-aarch64/rg +0 -0
  191. package/vendor/ripgrep/macos-x86_64/rg +0 -0
  192. package/vendor/ripgrep/windows-aarch64/rg.exe +0 -0
  193. package/vendor/ripgrep/windows-x86_64/rg.exe +0 -0
@@ -1,659 +0,0 @@
1
- import { randomUUID } from "crypto";
2
- import type {
3
- Message,
4
- Usage,
5
- ToolBlock,
6
- TaskNotificationBlock,
7
- } from "../types/index.js";
8
- import { MessageSource } from "../types/index.js";
9
- import { readFileSync } from "fs";
10
- import { extname } from "path";
11
- import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
12
- import { logger } from "./globalLogger.js";
13
-
14
- // Base user message parameters interface
15
- export interface UserMessageParams {
16
- content: string;
17
- customCommandContent?: string;
18
- images?: Array<{ path: string; mimeType: string }>;
19
- source?: MessageSource;
20
- isMeta?: boolean;
21
- }
22
-
23
- // Parameter interfaces for message operations
24
- export interface AddUserMessageParams extends UserMessageParams {
25
- messages: Message[];
26
- id?: string;
27
- }
28
-
29
- export interface UpdateToolBlockParams {
30
- messages: Message[];
31
- id: string;
32
- messageId?: string; // Optional message ID to target a specific message
33
- parameters?: string;
34
- result?: string;
35
- success?: boolean;
36
- error?: string;
37
- /**
38
- * Tool execution stage:
39
- * - 'start': Tool call initiated during AI streaming
40
- * - 'streaming': Tool parameters being received incrementally
41
- * - 'running': Tool execution in progress
42
- * - 'end': Tool execution completed with final result
43
- */
44
- stage?: "start" | "streaming" | "running" | "end";
45
- name?: string;
46
- shortResult?: string;
47
- startLineNumber?: number;
48
- images?: Array<{ data: string; mediaType?: string }>;
49
- compactParams?: string;
50
- parametersChunk?: string; // Incremental parameter updates for streaming
51
- isManuallyBackgrounded?: boolean;
52
- timestamp?: number;
53
- }
54
-
55
- // Agent specific interfaces (without messages parameter)
56
- export type AgentToolBlockUpdateParams = Omit<
57
- UpdateToolBlockParams,
58
- "messages"
59
- >;
60
-
61
- // Callback payload type — SDK always fills messageId (required)
62
- export type ToolBlockUpdateCallbackParams = Omit<
63
- AgentToolBlockUpdateParams,
64
- "messageId"
65
- > & {
66
- messageId: string;
67
- };
68
-
69
- export interface AddErrorBlockParams {
70
- messages: Message[];
71
- error: string;
72
- }
73
-
74
- export interface AddBangParams {
75
- messages: Message[];
76
- command: string;
77
- }
78
-
79
- export interface UpdateBangParams {
80
- messages: Message[];
81
- command: string;
82
- output: string;
83
- }
84
-
85
- export interface CompleteBangParams {
86
- messages: Message[];
87
- command: string;
88
- exitCode: number;
89
- output?: string;
90
- }
91
-
92
- /**
93
- * Convert image file path to base64 format
94
- * @param imagePath Image file path
95
- * @returns base64 format image data URL
96
- */
97
- export const convertImageToBase64 = (imagePath: string): string => {
98
- try {
99
- const imageBuffer = readFileSync(imagePath);
100
- const ext = extname(imagePath).toLowerCase().substring(1);
101
-
102
- // Determine MIME type based on file extension
103
- let mimeType = "image/png"; // Default
104
- switch (ext) {
105
- case "jpg":
106
- case "jpeg":
107
- mimeType = "image/jpeg";
108
- break;
109
- case "png":
110
- mimeType = "image/png";
111
- break;
112
- case "gif":
113
- mimeType = "image/gif";
114
- break;
115
- case "webp":
116
- mimeType = "image/webp";
117
- break;
118
- case "bmp":
119
- mimeType = "image/bmp";
120
- break;
121
- default:
122
- mimeType = "image/png";
123
- }
124
-
125
- const base64String = imageBuffer.toString("base64");
126
- return `data:${mimeType};base64,${base64String}`;
127
- } catch (error) {
128
- logger.error(`Failed to convert image to base64: ${imagePath}`, error);
129
- // Return an error placeholder or throw error
130
- return `data:image/png;base64,`; // Empty base64, avoid program crash
131
- }
132
- };
133
-
134
- export const generateMessageId = (): string => `msg-${randomUUID()}`;
135
-
136
- // Add user message
137
- export const addUserMessageToMessages = ({
138
- messages,
139
- content,
140
- customCommandContent,
141
- images,
142
- source,
143
- id,
144
- isMeta,
145
- }: AddUserMessageParams): Message[] => {
146
- const blocks: Message["blocks"] = [];
147
-
148
- // Create text block with optional source and customCommandContent
149
- const textBlock = {
150
- type: "text" as const,
151
- content,
152
- stage: "end" as const,
153
- ...(customCommandContent && { customCommandContent }),
154
- ...(source && { source }),
155
- };
156
- blocks.push(textBlock);
157
-
158
- // If there are images, add image block
159
- if (images && images.length > 0) {
160
- const imageUrls = images.map((img) => img.path);
161
- blocks.push({
162
- type: "image",
163
- imageUrls,
164
- });
165
- }
166
-
167
- const userMessage: Message = {
168
- id: id || generateMessageId(),
169
- role: "user",
170
- blocks,
171
- timestamp: new Date().toISOString(),
172
- ...(isMeta !== undefined && { isMeta }),
173
- };
174
- return [...messages, userMessage];
175
- };
176
-
177
- /**
178
- * Update a user message's content by its ID.
179
- */
180
- export const updateUserMessageInMessages = (
181
- messages: Message[],
182
- id: string,
183
- params: Partial<UserMessageParams>,
184
- ): Message[] => {
185
- return messages.map((msg) => {
186
- if (msg.id === id && msg.role === "user") {
187
- const newBlocks = msg.blocks.map((block) => {
188
- if (block.type === "text") {
189
- return {
190
- ...block,
191
- ...(params.content !== undefined && { content: params.content }),
192
- ...(params.customCommandContent !== undefined && {
193
- customCommandContent: params.customCommandContent,
194
- }),
195
- ...(params.source !== undefined && { source: params.source }),
196
- };
197
- }
198
- return block;
199
- });
200
- return {
201
- ...msg,
202
- blocks: newBlocks,
203
- ...(params.isMeta !== undefined && { isMeta: params.isMeta }),
204
- };
205
- }
206
- return msg;
207
- });
208
- };
209
-
210
- // Add assistant message (support one-time addition of answer and tool calls)
211
- export const addAssistantMessageToMessages = (
212
- messages: Message[],
213
- content?: string,
214
- toolCalls?: ChatCompletionMessageFunctionToolCall[],
215
- usage?: Usage,
216
- additionalFields?: Record<string, unknown>,
217
- ): Message[] => {
218
- const blocks: Message["blocks"] = [];
219
-
220
- // If there's answer content, add text block
221
- if (content) {
222
- blocks.push({ type: "text", content: content });
223
- }
224
-
225
- // If there are tool calls, add tool blocks
226
- if (toolCalls && toolCalls.length > 0) {
227
- toolCalls.forEach((toolCall) => {
228
- blocks.push({
229
- type: "tool",
230
- parameters: toolCall.function.arguments || "",
231
- result: "",
232
- id: toolCall.id || "",
233
- name: toolCall.function?.name || "",
234
- stage: "start",
235
- });
236
- });
237
- }
238
-
239
- const initialAssistantMessage: Message = {
240
- id: generateMessageId(),
241
- role: "assistant",
242
- blocks,
243
- timestamp: new Date().toISOString(),
244
- usage, // Include usage data if provided
245
- ...(additionalFields ? { additionalFields: { ...additionalFields } } : {}),
246
- };
247
-
248
- return [...messages, initialAssistantMessage];
249
- };
250
-
251
- /**
252
- * Add a tool block to a specific message by ID.
253
- */
254
- export const addToolBlockToMessageInMessages = (
255
- messages: Message[],
256
- messageId: string,
257
- params: Omit<AgentToolBlockUpdateParams, "id">,
258
- ): { messages: Message[]; toolBlockId: string } => {
259
- const toolBlockId = randomUUID();
260
- const newMessages = messages.map((msg) => {
261
- if (msg.id === messageId) {
262
- return {
263
- ...msg,
264
- blocks: [
265
- ...msg.blocks,
266
- {
267
- type: "tool" as const,
268
- id: toolBlockId,
269
- name: params.name || "unknown",
270
- parameters: params.parameters || "",
271
- result: params.result || "",
272
- stage: "start",
273
- ...params,
274
- } as ToolBlock,
275
- ],
276
- };
277
- }
278
- return msg;
279
- });
280
- return { messages: newMessages, toolBlockId };
281
- };
282
-
283
- // Update Tool Block of the last assistant or user message
284
- export const updateToolBlockInMessage = ({
285
- messages,
286
- id,
287
- messageId,
288
- parameters,
289
- result,
290
- success,
291
- error,
292
- stage,
293
- name,
294
- shortResult,
295
- startLineNumber,
296
- images,
297
- compactParams,
298
- parametersChunk,
299
- isManuallyBackgrounded,
300
- }: UpdateToolBlockParams): { messages: Message[]; messageId?: string } => {
301
- const newMessages = [...messages];
302
-
303
- // If messageId is provided, target that specific message
304
- if (messageId) {
305
- const messageIndex = newMessages.findIndex((msg) => msg.id === messageId);
306
- if (messageIndex !== -1) {
307
- const toolBlockIndex = newMessages[messageIndex].blocks.findIndex(
308
- (block) => block.type === "tool" && block.id === id,
309
- );
310
-
311
- if (toolBlockIndex !== -1) {
312
- const toolBlock = newMessages[messageIndex].blocks[toolBlockIndex];
313
- if (toolBlock.type === "tool") {
314
- if (parameters !== undefined) toolBlock.parameters = parameters;
315
- if (result !== undefined) toolBlock.result = result;
316
- if (shortResult !== undefined) toolBlock.shortResult = shortResult;
317
- if (startLineNumber !== undefined)
318
- toolBlock.startLineNumber = startLineNumber;
319
- if (images !== undefined) toolBlock.images = images;
320
- if (success !== undefined) toolBlock.success = success;
321
- if (error !== undefined) toolBlock.error = error;
322
- if (stage !== undefined) toolBlock.stage = stage;
323
- if (compactParams !== undefined)
324
- toolBlock.compactParams = compactParams;
325
- if (parametersChunk !== undefined)
326
- toolBlock.parametersChunk = parametersChunk;
327
- if (isManuallyBackgrounded !== undefined)
328
- toolBlock.isManuallyBackgrounded = isManuallyBackgrounded;
329
- }
330
- }
331
- }
332
- return { messages: newMessages, messageId };
333
- }
334
-
335
- // Find the last assistant or user message
336
- for (let i = newMessages.length - 1; i >= 0; i--) {
337
- if (newMessages[i].role === "assistant" || newMessages[i].role === "user") {
338
- const toolBlockIndex = newMessages[i].blocks.findIndex(
339
- (block) => block.type === "tool" && block.id === id,
340
- );
341
-
342
- if (toolBlockIndex !== -1) {
343
- const toolBlock = newMessages[i].blocks[toolBlockIndex];
344
- if (toolBlock.type === "tool") {
345
- if (parameters !== undefined) toolBlock.parameters = parameters;
346
- if (result !== undefined) toolBlock.result = result;
347
- if (shortResult !== undefined) toolBlock.shortResult = shortResult;
348
- if (startLineNumber !== undefined)
349
- toolBlock.startLineNumber = startLineNumber;
350
- if (images !== undefined) toolBlock.images = images; // Add image data update
351
- if (success !== undefined) toolBlock.success = success;
352
- if (error !== undefined) toolBlock.error = error;
353
- if (stage !== undefined) toolBlock.stage = stage;
354
- if (compactParams !== undefined)
355
- toolBlock.compactParams = compactParams;
356
- if (parametersChunk !== undefined)
357
- toolBlock.parametersChunk = parametersChunk;
358
- if (isManuallyBackgrounded !== undefined)
359
- toolBlock.isManuallyBackgrounded = isManuallyBackgrounded;
360
- }
361
- const foundMessageId = newMessages[i].id;
362
- return { messages: newMessages, messageId: foundMessageId };
363
- } else if (newMessages[i].role === "assistant") {
364
- // If existing block not found in assistant message, create new one
365
- // This handles cases where we're streaming tool parameters before execution
366
- newMessages[i].blocks.push({
367
- type: "tool",
368
- parameters: parameters,
369
- result: result || "",
370
- shortResult: shortResult,
371
- startLineNumber: startLineNumber,
372
- images: images, // Add image data
373
- id: id,
374
- name: name || "unknown",
375
- success: success,
376
- error: error,
377
- stage: stage ?? "start",
378
- compactParams: compactParams,
379
- parametersChunk: parametersChunk,
380
- isManuallyBackgrounded: isManuallyBackgrounded,
381
- });
382
- const foundMessageId = newMessages[i].id;
383
- return { messages: newMessages, messageId: foundMessageId };
384
- }
385
- }
386
- }
387
- return { messages: newMessages };
388
- };
389
-
390
- // Add Error Block to the last assistant message
391
- export const addErrorBlockToMessage = ({
392
- messages,
393
- error,
394
- }: AddErrorBlockParams): Message[] => {
395
- const newMessages = [...messages];
396
-
397
- // Check if the last message is an assistant message
398
- const lastMessage = newMessages[newMessages.length - 1];
399
- if (lastMessage && lastMessage.role === "assistant") {
400
- // Create a new message object with the error block added
401
- newMessages[newMessages.length - 1] = {
402
- ...lastMessage,
403
- blocks: [
404
- ...lastMessage.blocks,
405
- {
406
- type: "error",
407
- content: error,
408
- },
409
- ],
410
- };
411
- } else {
412
- // If the last message is not an assistant message, create a new assistant message
413
- newMessages.push({
414
- id: generateMessageId(),
415
- role: "assistant",
416
- blocks: [
417
- {
418
- type: "error",
419
- content: error,
420
- },
421
- ],
422
- timestamp: new Date().toISOString(),
423
- });
424
- }
425
-
426
- return newMessages;
427
- };
428
-
429
- // Add bang block to message list
430
- export const addBangMessage = ({
431
- messages,
432
- command,
433
- }: AddBangParams): Message[] => {
434
- const outputMessage: Message = {
435
- id: generateMessageId(),
436
- role: "user",
437
- blocks: [
438
- {
439
- type: "bang",
440
- command,
441
- output: "",
442
- stage: "running" as const,
443
- exitCode: null,
444
- },
445
- ],
446
- timestamp: new Date().toISOString(),
447
- };
448
-
449
- return [...messages, outputMessage];
450
- };
451
-
452
- // Update output content of bang block
453
- export const updateBangInMessage = ({
454
- messages,
455
- command,
456
- output,
457
- }: UpdateBangParams): Message[] => {
458
- const newMessages = [...messages];
459
- // Find the last user message with a bang block for this command
460
- for (let i = newMessages.length - 1; i >= 0; i--) {
461
- const msg = newMessages[i];
462
- if (msg.role === "user") {
463
- const commandBlock = msg.blocks.find(
464
- (block) =>
465
- block.type === "bang" &&
466
- block.command === command &&
467
- block.stage === "running",
468
- );
469
- if (commandBlock && commandBlock.type === "bang") {
470
- commandBlock.output = output.trim();
471
- break;
472
- }
473
- }
474
- }
475
- return newMessages;
476
- };
477
-
478
- // Complete bang execution, update exit status
479
- export const completeBangInMessage = ({
480
- messages,
481
- command,
482
- exitCode,
483
- output,
484
- }: CompleteBangParams): Message[] => {
485
- const newMessages = [...messages];
486
- // Find the last user message with a bang block for this command
487
- for (let i = newMessages.length - 1; i >= 0; i--) {
488
- const msg = newMessages[i];
489
- if (msg.role === "user") {
490
- const commandBlock = msg.blocks.find(
491
- (block) =>
492
- block.type === "bang" &&
493
- block.command === command &&
494
- block.stage === "running",
495
- );
496
- if (commandBlock && commandBlock.type === "bang") {
497
- commandBlock.stage = "end";
498
- commandBlock.exitCode = exitCode;
499
- if (output !== undefined) {
500
- commandBlock.output = output.trim();
501
- }
502
- break;
503
- }
504
- }
505
- }
506
- return newMessages;
507
- };
508
-
509
- /**
510
- * Helper to count tool blocks in messages
511
- */
512
- export function countToolBlocks(messages: Message[]): number {
513
- let toolCount = 0;
514
- messages.forEach((msg) => {
515
- msg.blocks.forEach((block) => {
516
- if (block.type === "tool") {
517
- toolCount++;
518
- }
519
- });
520
- });
521
- return toolCount;
522
- }
523
-
524
- /**
525
- * Remove the last user message from the conversation
526
- * Used for hook error handling when the user prompt needs to be erased
527
- */
528
- export const removeLastUserMessage = (messages: Message[]): Message[] => {
529
- const newMessages = [...messages];
530
- for (let i = newMessages.length - 1; i >= 0; i--) {
531
- if (newMessages[i].role === "user") {
532
- newMessages.splice(i, 1);
533
- break;
534
- }
535
- }
536
- return newMessages;
537
- };
538
-
539
- /**
540
- * Efficiently clone a message for UI freezing.
541
- * Clones the message object and its blocks array, but reuses string references.
542
- */
543
- export function cloneMessage(message: Message): Message {
544
- return {
545
- ...message,
546
- blocks: message.blocks.map((block) => {
547
- const clonedBlock = { ...block };
548
- // Deep clone arrays/objects within blocks if they exist
549
- if (clonedBlock.type === "tool" && clonedBlock.images) {
550
- clonedBlock.images = clonedBlock.images.map((img) => ({ ...img }));
551
- } else if (clonedBlock.type === "image" && clonedBlock.imageUrls) {
552
- clonedBlock.imageUrls = [...clonedBlock.imageUrls];
553
- } else if (clonedBlock.type === "file_history" && clonedBlock.snapshots) {
554
- clonedBlock.snapshots = clonedBlock.snapshots.map((s) => ({ ...s }));
555
- }
556
- return clonedBlock;
557
- }) as Message["blocks"],
558
- // Clone additionalFields if it exists
559
- ...(message.additionalFields
560
- ? { additionalFields: { ...message.additionalFields } }
561
- : {}),
562
- };
563
- }
564
-
565
- /**
566
- * Helper to format tool and token summary
567
- */
568
- export function formatToolTokenSummary(
569
- toolCount: number,
570
- tokens: number,
571
- ): string {
572
- if (toolCount === 0) {
573
- return "";
574
- }
575
- let summary = `(${toolCount} tools`;
576
- if (tokens > 0) {
577
- summary += ` | ${tokens.toLocaleString()} tokens`;
578
- }
579
- summary += ")";
580
- return summary;
581
- }
582
-
583
- /**
584
- * Fold a message list at the last compact boundary — returns only messages from
585
- * the most recent compact summary forward. Mirrors what is sent to the LLM
586
- * (convertMessagesForAPI stops at the last compact block), so the display layer
587
- * matches the AI context. The session file keeps the full history; folding is
588
- * display-only.
589
- */
590
- export function sliceFromLastCompact(messages: Message[]): Message[] {
591
- let lastCompactIndex = -1;
592
- for (let i = messages.length - 1; i >= 0; i--) {
593
- if (messages[i].blocks?.some((b) => b.type === "compact")) {
594
- lastCompactIndex = i;
595
- break;
596
- }
597
- }
598
- return lastCompactIndex >= 0 ? messages.slice(lastCompactIndex) : messages;
599
- }
600
-
601
- /**
602
- * Extracts displayable text from a Message object, handling various block types.
603
- * Returns the first available content block.
604
- */
605
- export function getMessageContent(message: Message): string {
606
- // Find first available content block
607
- const textBlock = message.blocks.find((block) => block.type === "text");
608
- if (textBlock && "content" in textBlock) {
609
- return textBlock.content;
610
- }
611
-
612
- const bangBlock = message.blocks.find((block) => block.type === "bang");
613
- if (bangBlock && "command" in bangBlock) {
614
- return `!${bangBlock.command}`;
615
- }
616
-
617
- const compactBlock = message.blocks.find((block) => block.type === "compact");
618
- if (compactBlock && "content" in compactBlock) {
619
- return compactBlock.content;
620
- }
621
-
622
- return "";
623
- }
624
-
625
- export interface AddNotificationMessageParams {
626
- messages: Message[];
627
- taskId: string;
628
- taskType: "shell" | "agent" | "workflow";
629
- status: "completed" | "failed" | "killed" | "aborted";
630
- summary: string;
631
- outputFile?: string;
632
- }
633
-
634
- export const addNotificationMessageToMessages = ({
635
- messages,
636
- taskId,
637
- taskType,
638
- status,
639
- summary,
640
- outputFile,
641
- }: AddNotificationMessageParams): Message[] => {
642
- const block: TaskNotificationBlock = {
643
- type: "task_notification",
644
- taskId,
645
- taskType,
646
- status,
647
- summary,
648
- ...(outputFile !== undefined && { outputFile }),
649
- };
650
-
651
- const notificationMessage: Message = {
652
- id: generateMessageId(),
653
- role: "user",
654
- blocks: [block],
655
- timestamp: new Date().toISOString(),
656
- };
657
-
658
- return [...messages, notificationMessage];
659
- };
@@ -1,30 +0,0 @@
1
- /**
2
- * Model Capability Detection
3
- *
4
- * Pure declarative capability accessors. Capabilities are configured per-model
5
- * via the `capabilities` field in `ModelConfig` (settings.json), not via regex
6
- * or environment variables.
7
- */
8
-
9
- import type { ModelCapabilities } from "../types/config.js";
10
-
11
- /**
12
- * Determines if a model supports prompt caching.
13
- * @param capabilities - Declarative model capabilities
14
- * @returns True if promptCaching is explicitly enabled (default: false)
15
- */
16
- export function supportsPromptCaching(
17
- capabilities?: ModelCapabilities,
18
- ): boolean {
19
- return capabilities?.promptCaching ?? false;
20
- }
21
-
22
- /**
23
- * Determines if a model supports image/vision recognition.
24
- * Opt-out semantics: by default all models are assumed to support vision.
25
- * @param capabilities - Declarative model capabilities
26
- * @returns True unless vision is explicitly disabled (default: true)
27
- */
28
- export function supportsVision(capabilities?: ModelCapabilities): boolean {
29
- return capabilities?.vision ?? true;
30
- }