@tencent-ai/agent-sdk 0.2.2 → 0.3.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 (43) hide show
  1. package/cli/CHANGELOG.md +18 -0
  2. package/cli/dist/codebuddy.js +3 -3
  3. package/cli/package.json +1 -1
  4. package/cli/product.cloudhosted.json +2 -2
  5. package/cli/product.internal.json +2 -2
  6. package/cli/product.ioa.json +2 -2
  7. package/cli/product.json +2 -2
  8. package/cli/product.selfhosted.json +2 -2
  9. package/lib/acp/index.d.ts +7 -11
  10. package/lib/acp/index.d.ts.map +1 -1
  11. package/lib/acp/index.js +7 -14
  12. package/lib/acp/index.js.map +1 -1
  13. package/lib/acp/tool-converter.d.ts +98 -53
  14. package/lib/acp/tool-converter.d.ts.map +1 -1
  15. package/lib/acp/tool-converter.js +574 -387
  16. package/lib/acp/tool-converter.js.map +1 -1
  17. package/lib/index.d.ts +0 -2
  18. package/lib/index.d.ts.map +1 -1
  19. package/lib/index.js +1 -4
  20. package/lib/index.js.map +1 -1
  21. package/lib/query.d.ts +0 -25
  22. package/lib/query.d.ts.map +1 -1
  23. package/lib/query.js +38 -167
  24. package/lib/query.js.map +1 -1
  25. package/lib/session.d.ts +17 -4
  26. package/lib/session.d.ts.map +1 -1
  27. package/lib/session.js +152 -14
  28. package/lib/session.js.map +1 -1
  29. package/lib/transport/index.d.ts +7 -0
  30. package/lib/transport/index.d.ts.map +1 -1
  31. package/lib/transport/index.js.map +1 -1
  32. package/lib/transport/process-transport.d.ts +30 -0
  33. package/lib/transport/process-transport.d.ts.map +1 -1
  34. package/lib/transport/process-transport.js +177 -1
  35. package/lib/transport/process-transport.js.map +1 -1
  36. package/lib/types.d.ts +36 -0
  37. package/lib/types.d.ts.map +1 -1
  38. package/lib/types.js.map +1 -1
  39. package/package.json +2 -1
  40. package/lib/acp/acp-client.d.ts +0 -62
  41. package/lib/acp/acp-client.d.ts.map +0 -1
  42. package/lib/acp/acp-client.js +0 -256
  43. package/lib/acp/acp-client.js.map +0 -1
@@ -1,436 +1,623 @@
1
1
  "use strict";
2
2
  /**
3
- * Tool Converter Utility
3
+ * ACP Message Transformer
4
4
  *
5
5
  * Converts SDK internal tool formats to ACP (Agent Client Protocol) format and vice versa.
6
6
  *
7
+ * Uses official @agentclientprotocol/sdk types for compatibility with the ACP specification.
8
+ *
7
9
  * Critical Design Principle: NO DATA LOSS
8
10
  * - SDK tool inputs are preserved completely in rawInput
9
11
  * - Tool IDs are maintained throughout the conversion
10
12
  * - Tool results are preserved with error state tracking
11
13
  */
12
14
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.convertSdkToolUseToAcpToolCall = convertSdkToolUseToAcpToolCall;
14
- exports.convertAcpToolResultToSdk = convertAcpToolResultToSdk;
15
- exports.extractToolUseBlocks = extractToolUseBlocks;
16
- exports.extractTextContent = extractTextContent;
17
- // ============= Conversion: SDK Tool Use → ACP Tool Call =============
15
+ exports.AcpTransformer = void 0;
16
+ // ============= ACP Message Transformer (Stateless Utility) =============
18
17
  /**
19
- * Convert SDK ToolUseContentBlock to ACP Tool Call
20
- * Preserves all input data in rawInput field
18
+ * Bidirectional converter between SDK internal format (JSON Lines) and ACP (Agent Client Protocol) format.
19
+ *
20
+ * This is an abstract utility class with only static methods - do not instantiate.
21
21
  *
22
- * @param toolUse - SDK tool use block
23
- * @returns ACP tool call with complete data preservation
22
+ * Key features:
23
+ * - Converts SDK tool use/result to ACP format
24
+ * - Converts ACP messages to SDK format
25
+ * - Extracts and manipulates tool/text blocks
26
+ * - Complete data preservation in roundtrip conversions
27
+ * - Type-safe message routing
24
28
  */
25
- function convertSdkToolUseToAcpToolCall(toolUse) {
26
- const toolName = toolUse.name;
27
- const toolInput = toolUse.input;
28
- return {
29
- toolCallId: toolUse.id,
30
- status: 'pending',
31
- title: generateToolTitle(toolName, toolInput),
32
- kind: getToolKind(toolName),
33
- rawInput: toolInput,
34
- content: generateToolContent(toolName, toolInput),
35
- locations: extractToolLocations(toolName, toolInput),
36
- };
37
- }
38
- // ============= Title Generation by Tool Type =============
39
- function generateToolTitle(toolName, input) {
40
- switch (toolName) {
41
- case 'Read':
42
- case 'read': {
43
- const filePath = input.file_path;
44
- const offset = input.offset;
45
- const limit = input.limit;
46
- if (!filePath)
47
- return 'Read';
48
- if (limit) {
49
- return `Read ${filePath} (${(offset !== null && offset !== void 0 ? offset : 0) + 1} - ${(offset !== null && offset !== void 0 ? offset : 0) + limit})`;
29
+ class AcpTransformer {
30
+ // ============= Public API: SDK Tool Use ↔ ACP Tool Call =============
31
+ /**
32
+ * Convert SDK ToolUseContentBlock to ACP Tool Call
33
+ * Preserves all input data in rawInput field
34
+ */
35
+ static convertSdkToolUseToAcpToolCall(toolUse) {
36
+ const toolName = toolUse.name;
37
+ const toolInput = toolUse.input;
38
+ return {
39
+ toolCallId: toolUse.id,
40
+ status: 'pending',
41
+ title: AcpTransformer.generateToolTitle(toolName, toolInput),
42
+ kind: AcpTransformer.getToolKind(toolName),
43
+ rawInput: toolInput,
44
+ content: AcpTransformer.generateToolContent(toolName, toolInput),
45
+ locations: AcpTransformer.extractToolLocations(toolName, toolInput),
46
+ };
47
+ }
48
+ // ============= Public API: Bidirectional Tool Conversion =============
49
+ /**
50
+ * Convert ACP Tool Result to SDK ToolResultContentBlock
51
+ * Preserves tool_use_id and ensures error state is tracked
52
+ */
53
+ static convertAcpToolResultToSdk(toolCallId, acpResult) {
54
+ const isError = acpResult.status === 'failed';
55
+ const content = acpResult.content ? AcpTransformer.formatAcpContentForSdk(acpResult.content) : '';
56
+ return {
57
+ type: 'tool_result',
58
+ tool_use_id: toolCallId,
59
+ content: content,
60
+ is_error: isError,
61
+ };
62
+ }
63
+ /**
64
+ * Convert SDK ToolResultContentBlock to ACP ToolResult
65
+ * Enables bidirectional conversion for tool results
66
+ */
67
+ static convertSdkToolResultToAcpToolResult(toolResult) {
68
+ const content = [];
69
+ if (toolResult.content) {
70
+ if (typeof toolResult.content === 'string') {
71
+ if (toolResult.content) {
72
+ content.push({
73
+ type: 'content',
74
+ content: { type: 'text', text: toolResult.content },
75
+ });
76
+ }
50
77
  }
51
- else if (offset) {
52
- return `Read ${filePath} (from line ${(offset !== null && offset !== void 0 ? offset : 0) + 1})`;
78
+ else if (Array.isArray(toolResult.content)) {
79
+ for (const block of toolResult.content) {
80
+ if ('type' in block && block.type === 'text') {
81
+ const textBlock = block;
82
+ content.push({
83
+ type: 'content',
84
+ content: { type: 'text', text: textBlock.text },
85
+ });
86
+ }
87
+ }
53
88
  }
54
- return `Read ${filePath}`;
55
- }
56
- case 'Write':
57
- case 'write': {
58
- const filePath = input.file_path;
59
- return filePath ? `Write ${filePath}` : 'Write';
60
89
  }
61
- case 'Edit':
62
- case 'edit':
63
- case 'MultiEdit': {
64
- const filePath = input.file_path;
65
- return filePath ? `Edit \`${filePath}\`` : 'Edit';
90
+ return {
91
+ toolCallId: toolResult.tool_use_id,
92
+ status: toolResult.is_error ? 'failed' : 'completed',
93
+ content: content.length > 0 ? content : undefined,
94
+ rawOutput: toolResult.content,
95
+ };
96
+ }
97
+ // ============= Public API: Message Transformation =============
98
+ /**
99
+ * Convert ACP message to SDK internal format (JSON Lines)
100
+ *
101
+ * Converts all ACP message types to corresponding SDK messages:
102
+ * - session/prompt: User input → UserMessage
103
+ * - session/cancel: Cancellation request → ControlRequest
104
+ * - session/update (tool_call_update): Tool result → UserMessage with tool_result block
105
+ */
106
+ static acpToSdk(acpMessage) {
107
+ if (acpMessage.method === 'session/prompt') {
108
+ const params = acpMessage.params;
109
+ const sessionId = params === null || params === void 0 ? void 0 : params.sessionId;
110
+ const prompt = params === null || params === void 0 ? void 0 : params.prompt;
111
+ const content = AcpTransformer.privateExtractPromptText(prompt);
112
+ return {
113
+ type: 'user',
114
+ session_id: sessionId || 'unknown',
115
+ message: {
116
+ role: 'user',
117
+ content: content,
118
+ },
119
+ parent_tool_use_id: null,
120
+ };
66
121
  }
67
- case 'Bash':
68
- case 'bash': {
69
- const command = input.command;
70
- if (!command)
71
- return 'Terminal';
72
- // Escape backticks in command (replace all occurrences)
73
- const escaped = command.split('`').join('\\`');
74
- return `\`${escaped}\``;
122
+ if (acpMessage.method === 'session/cancel') {
123
+ return {
124
+ type: 'control_request',
125
+ request: { subtype: 'interrupt' },
126
+ };
75
127
  }
76
- case 'BashOutput':
77
- case 'bash_output':
78
- return 'Tail Logs';
79
- case 'KillShell':
80
- case 'kill_shell':
81
- return 'Kill Process';
82
- case 'Glob':
83
- case 'glob': {
84
- let label = 'Find';
85
- const path = input.path;
86
- const pattern = input.pattern;
87
- if (path)
88
- label += ` \`${path}\``;
89
- if (pattern)
90
- label += ` \`${pattern}\``;
91
- return label;
128
+ // Handle session/update with tool_call_update
129
+ if (acpMessage.method === 'session/update') {
130
+ const params = acpMessage.params;
131
+ const sessionId = params === null || params === void 0 ? void 0 : params.sessionId;
132
+ const update = params === null || params === void 0 ? void 0 : params.update;
133
+ if ((update === null || update === void 0 ? void 0 : update.sessionUpdate) === 'tool_call_update') {
134
+ // Convert tool_call_update back to SDK tool result format
135
+ const toolCallId = update.toolCallId;
136
+ const status = update.status;
137
+ const content = update.content;
138
+ if (toolCallId) {
139
+ // Create an AcpToolResult from the update
140
+ const acpResult = {
141
+ toolCallId,
142
+ status: status || 'completed',
143
+ content: content,
144
+ };
145
+ return AcpTransformer.privateCreateToolResultMessage({ params: { sessionId } }, acpResult);
146
+ }
147
+ }
92
148
  }
93
- case 'Grep':
94
- case 'grep': {
95
- let label = 'grep';
96
- // Add flags
97
- if (input['-i'])
98
- label += ' -i';
99
- if (input['-n'])
100
- label += ' -n';
101
- if (input['-C'] !== undefined)
102
- label += ` -C ${input['-C']}`;
103
- if (input['-A'] !== undefined)
104
- label += ` -A ${input['-A']}`;
105
- if (input['-B'] !== undefined)
106
- label += ` -B ${input['-B']}`;
107
- if (input.multiline)
108
- label += ' -P';
109
- if (input.glob)
110
- label += ` --include="${input.glob}"`;
111
- if (input.type)
112
- label += ` --type=${input.type}`;
113
- // Add pattern and path
114
- const pattern = input.pattern;
115
- const path = input.path;
116
- if (pattern)
117
- label += ` "${pattern}"`;
118
- if (path)
119
- label += ` ${path}`;
120
- return label;
149
+ return null;
150
+ }
151
+ /**
152
+ * Convert SDK internal message to ACP format
153
+ *
154
+ * Converts all SDK message types to corresponding ACP messages:
155
+ * - AssistantMessage with tool_use blocks → tool_call messages
156
+ * - AssistantMessage with text → session/text messages
157
+ * - Other message types are skipped
158
+ */
159
+ static sdkToAcp(message) {
160
+ const messages = [];
161
+ // Handle assistant messages (contain tool calls and text from the model)
162
+ if ('type' in message && message.type === 'assistant') {
163
+ const assistantMsg = message;
164
+ if (assistantMsg.message.content && Array.isArray(assistantMsg.message.content)) {
165
+ // Extract and convert tool use blocks
166
+ const toolUseBlocks = AcpTransformer.privateExtractToolUseBlocks(assistantMsg.message.content);
167
+ for (const toolUse of toolUseBlocks) {
168
+ const acpToolCall = AcpTransformer.convertSdkToolUseToAcpToolCall(toolUse);
169
+ const toolCallMsg = {
170
+ jsonrpc: '2.0',
171
+ method: 'tool_call',
172
+ params: acpToolCall,
173
+ };
174
+ messages.push(toolCallMsg);
175
+ }
176
+ // Extract and send text content if present
177
+ const textContent = AcpTransformer.privateExtractTextContent(assistantMsg.message.content);
178
+ if (textContent) {
179
+ messages.push({
180
+ jsonrpc: '2.0',
181
+ method: 'session/text',
182
+ params: {
183
+ content: textContent,
184
+ },
185
+ });
186
+ }
187
+ return messages;
188
+ }
121
189
  }
122
- case 'WebFetch':
123
- case 'web_fetch': {
124
- const url = input.url;
125
- return url ? `Fetch ${url}` : 'Fetch';
190
+ // Handle user messages with tool results
191
+ if ('type' in message && message.type === 'user') {
192
+ const userMsg = message;
193
+ if (userMsg.message.content && Array.isArray(userMsg.message.content)) {
194
+ // Look for tool result blocks
195
+ const toolResultBlocks = userMsg.message.content.filter((block) => typeof block === 'object' &&
196
+ block !== null &&
197
+ 'type' in block &&
198
+ block.type === 'tool_result');
199
+ // Convert tool results to ACP tool_call_update format (via session/update)
200
+ for (const toolResultBlock of toolResultBlocks) {
201
+ const acpResult = AcpTransformer.convertSdkToolResultToAcpToolResult(toolResultBlock);
202
+ // Wrap tool result as session/update with tool_call_update
203
+ const updateMsg = {
204
+ jsonrpc: '2.0',
205
+ method: 'session/update',
206
+ params: {
207
+ sessionId: userMsg.session_id || 'unknown',
208
+ update: {
209
+ sessionUpdate: 'tool_call_update',
210
+ toolCallId: acpResult.toolCallId,
211
+ status: acpResult.status,
212
+ content: acpResult.content,
213
+ },
214
+ },
215
+ };
216
+ messages.push(updateMsg);
217
+ }
218
+ }
126
219
  }
127
- case 'WebSearch':
128
- case 'web_search': {
129
- const query = input.query;
130
- if (!query)
131
- return 'Search';
132
- let label = `"${query}"`;
133
- const allowedDomains = input.allowed_domains;
134
- const blockedDomains = input.blocked_domains;
135
- if (allowedDomains === null || allowedDomains === void 0 ? void 0 : allowedDomains.length)
136
- label += ` (allowed: ${allowedDomains.join(', ')})`;
137
- if (blockedDomains === null || blockedDomains === void 0 ? void 0 : blockedDomains.length)
138
- label += ` (blocked: ${blockedDomains.join(', ')})`;
139
- return label;
220
+ // Handle result messages (marks the end of a turn)
221
+ if ('type' in message && message.type === 'result') {
222
+ messages.push({
223
+ jsonrpc: '2.0',
224
+ method: 'session/result',
225
+ params: {
226
+ sessionId: message.session_id || 'unknown',
227
+ result: message,
228
+ },
229
+ });
230
+ return messages;
140
231
  }
141
- case 'NotebookRead':
142
- case 'notebook_read': {
143
- const path = input.notebook_path;
144
- return path ? `Read Notebook ${path}` : 'Read Notebook';
232
+ // Handle error messages
233
+ if ('type' in message && message.type === 'error') {
234
+ messages.push({
235
+ jsonrpc: '2.0',
236
+ method: 'session/error',
237
+ params: {
238
+ sessionId: message.session_id || 'unknown',
239
+ error: message.error,
240
+ },
241
+ });
242
+ return messages;
145
243
  }
146
- case 'NotebookEdit':
147
- case 'notebook_edit': {
148
- const path = input.notebook_path;
149
- return path ? `Edit Notebook ${path}` : 'Edit Notebook';
244
+ // Skip system, tool_progress, stream_event (partial), compact_boundary and other internal messages
245
+ return messages;
246
+ }
247
+ // ============= Private: Title Generation by Tool Type =============
248
+ static generateToolTitle(toolName, input) {
249
+ switch (toolName) {
250
+ case 'Read':
251
+ case 'read': {
252
+ const filePath = input.file_path;
253
+ const offset = input.offset;
254
+ const limit = input.limit;
255
+ if (!filePath)
256
+ return 'Read';
257
+ if (limit) {
258
+ return `Read ${filePath} (${(offset !== null && offset !== void 0 ? offset : 0) + 1} - ${(offset !== null && offset !== void 0 ? offset : 0) + limit})`;
259
+ }
260
+ else if (offset) {
261
+ return `Read ${filePath} (from line ${(offset !== null && offset !== void 0 ? offset : 0) + 1})`;
262
+ }
263
+ return `Read ${filePath}`;
264
+ }
265
+ case 'Write':
266
+ case 'write': {
267
+ const filePath = input.file_path;
268
+ return filePath ? `Write ${filePath}` : 'Write';
269
+ }
270
+ case 'Edit':
271
+ case 'edit':
272
+ case 'MultiEdit': {
273
+ const filePath = input.file_path;
274
+ return filePath ? `Edit \`${filePath}\`` : 'Edit';
275
+ }
276
+ case 'Bash':
277
+ case 'bash': {
278
+ const command = input.command;
279
+ if (!command)
280
+ return 'Terminal';
281
+ const escaped = command.split('`').join('\\`');
282
+ return `\`${escaped}\``;
283
+ }
284
+ case 'BashOutput':
285
+ case 'bash_output':
286
+ return 'Tail Logs';
287
+ case 'KillShell':
288
+ case 'kill_shell':
289
+ return 'Kill Process';
290
+ case 'Glob':
291
+ case 'glob': {
292
+ let label = 'Find';
293
+ const path = input.path;
294
+ const pattern = input.pattern;
295
+ if (path)
296
+ label += ` \`${path}\``;
297
+ if (pattern)
298
+ label += ` \`${pattern}\``;
299
+ return label;
300
+ }
301
+ case 'Grep':
302
+ case 'grep': {
303
+ let label = 'grep';
304
+ if (input['-i'])
305
+ label += ' -i';
306
+ if (input['-n'])
307
+ label += ' -n';
308
+ if (input['-C'] !== undefined)
309
+ label += ` -C ${input['-C']}`;
310
+ if (input['-A'] !== undefined)
311
+ label += ` -A ${input['-A']}`;
312
+ if (input['-B'] !== undefined)
313
+ label += ` -B ${input['-B']}`;
314
+ if (input.multiline)
315
+ label += ' -P';
316
+ if (input.glob)
317
+ label += ` --include="${input.glob}"`;
318
+ if (input.type)
319
+ label += ` --type=${input.type}`;
320
+ const pattern = input.pattern;
321
+ const path = input.path;
322
+ if (pattern)
323
+ label += ` "${pattern}"`;
324
+ if (path)
325
+ label += ` ${path}`;
326
+ return label;
327
+ }
328
+ case 'WebFetch':
329
+ case 'web_fetch': {
330
+ const url = input.url;
331
+ return url ? `Fetch ${url}` : 'Fetch';
332
+ }
333
+ case 'WebSearch':
334
+ case 'web_search': {
335
+ const query = input.query;
336
+ if (!query)
337
+ return 'Search';
338
+ let label = `"${query}"`;
339
+ const allowedDomains = input.allowed_domains;
340
+ const blockedDomains = input.blocked_domains;
341
+ if (allowedDomains === null || allowedDomains === void 0 ? void 0 : allowedDomains.length)
342
+ label += ` (allowed: ${allowedDomains.join(', ')})`;
343
+ if (blockedDomains === null || blockedDomains === void 0 ? void 0 : blockedDomains.length)
344
+ label += ` (blocked: ${blockedDomains.join(', ')})`;
345
+ return label;
346
+ }
347
+ case 'NotebookRead':
348
+ case 'notebook_read': {
349
+ const path = input.notebook_path;
350
+ return path ? `Read Notebook ${path}` : 'Read Notebook';
351
+ }
352
+ case 'NotebookEdit':
353
+ case 'notebook_edit': {
354
+ const path = input.notebook_path;
355
+ return path ? `Edit Notebook ${path}` : 'Edit Notebook';
356
+ }
357
+ case 'Task':
358
+ case 'task': {
359
+ const description = input.description;
360
+ return description || 'Task';
361
+ }
362
+ case 'TodoWrite':
363
+ case 'todo_write': {
364
+ return 'Update TODOs';
365
+ }
366
+ case 'AskUserQuestion':
367
+ case 'ask_user_question':
368
+ return 'Ask User';
369
+ case 'SlashCommand':
370
+ case 'slash_command': {
371
+ const command = input.command;
372
+ return command ? `Run: ${command}` : 'Slash Command';
373
+ }
374
+ case 'Skill':
375
+ case 'skill': {
376
+ const command = input.command;
377
+ return command ? `Skill: ${command}` : 'Skill';
378
+ }
379
+ case 'LSP':
380
+ case 'lsp': {
381
+ const operation = input.operation;
382
+ return operation ? `LSP: ${operation}` : 'LSP';
383
+ }
384
+ case 'EnterPlanMode':
385
+ case 'enter_plan_mode':
386
+ return 'Enter Plan Mode';
387
+ case 'ExitPlanMode':
388
+ case 'exit_plan_mode':
389
+ return 'Exit Plan Mode';
390
+ case 'TaskOutput':
391
+ case 'task_output':
392
+ return 'Get Task Output';
393
+ default:
394
+ return toolName || 'Unknown Tool';
150
395
  }
151
- case 'Task':
152
- case 'task': {
153
- const description = input.description;
154
- return description || 'Task';
396
+ }
397
+ // ============= Private: Tool Kind Classification =============
398
+ static getToolKind(toolName) {
399
+ switch (toolName) {
400
+ case 'Read':
401
+ case 'read':
402
+ case 'NotebookRead':
403
+ case 'notebook_read':
404
+ case 'Glob':
405
+ case 'glob':
406
+ return 'read';
407
+ case 'Write':
408
+ case 'write':
409
+ case 'Edit':
410
+ case 'edit':
411
+ case 'MultiEdit':
412
+ case 'NotebookEdit':
413
+ case 'notebook_edit':
414
+ return 'edit';
415
+ case 'Bash':
416
+ case 'bash':
417
+ case 'BashOutput':
418
+ case 'bash_output':
419
+ case 'KillShell':
420
+ case 'kill_shell':
421
+ case 'TaskOutput':
422
+ case 'task_output':
423
+ return 'execute';
424
+ case 'Grep':
425
+ case 'grep':
426
+ case 'WebSearch':
427
+ case 'web_search':
428
+ return 'search';
429
+ case 'WebFetch':
430
+ case 'web_fetch':
431
+ return 'fetch';
432
+ case 'Task':
433
+ case 'task':
434
+ case 'TodoWrite':
435
+ case 'todo_write':
436
+ case 'EnterPlanMode':
437
+ case 'enter_plan_mode':
438
+ case 'ExitPlanMode':
439
+ case 'exit_plan_mode':
440
+ return 'think';
441
+ default:
442
+ return 'other';
155
443
  }
156
- case 'TodoWrite':
157
- case 'todo_write': {
158
- return 'Update TODOs';
444
+ }
445
+ // ============= Private: Content Generation by Tool Type =============
446
+ static generateToolContent(toolName, input) {
447
+ const content = [];
448
+ switch (toolName) {
449
+ case 'Edit':
450
+ case 'edit':
451
+ case 'MultiEdit': {
452
+ const filePath = input.file_path;
453
+ const oldString = input.old_string;
454
+ const newString = input.new_string;
455
+ if (filePath && oldString !== undefined && newString !== undefined) {
456
+ content.push({
457
+ type: 'diff',
458
+ path: filePath,
459
+ oldText: oldString || null,
460
+ newText: newString,
461
+ });
462
+ }
463
+ break;
464
+ }
465
+ case 'Bash':
466
+ case 'bash': {
467
+ const description = input.description;
468
+ if (description) {
469
+ content.push({
470
+ type: 'content',
471
+ content: { type: 'text', text: description },
472
+ });
473
+ }
474
+ break;
475
+ }
476
+ case 'Task':
477
+ case 'task': {
478
+ const prompt = input.prompt;
479
+ if (prompt) {
480
+ content.push({
481
+ type: 'content',
482
+ content: { type: 'text', text: prompt },
483
+ });
484
+ }
485
+ break;
486
+ }
487
+ case 'WebFetch':
488
+ case 'web_fetch': {
489
+ const prompt = input.prompt;
490
+ if (prompt) {
491
+ content.push({
492
+ type: 'content',
493
+ content: { type: 'text', text: prompt },
494
+ });
495
+ }
496
+ break;
497
+ }
159
498
  }
160
- case 'AskUserQuestion':
161
- case 'ask_user_question':
162
- return 'Ask User';
163
- case 'SlashCommand':
164
- case 'slash_command': {
165
- const command = input.command;
166
- return command ? `Run: ${command}` : 'Slash Command';
499
+ return content.length > 0 ? content : undefined;
500
+ }
501
+ // ============= Private: Location Extraction by Tool Type =============
502
+ static extractToolLocations(toolName, input) {
503
+ const locations = [];
504
+ const filePath = input.file_path;
505
+ const notebookPath = input.notebook_path;
506
+ const path = input.path;
507
+ if (filePath) {
508
+ locations.push({
509
+ path: filePath,
510
+ line: input.offset,
511
+ });
167
512
  }
168
- case 'Skill':
169
- case 'skill': {
170
- const command = input.command;
171
- return command ? `Skill: ${command}` : 'Skill';
513
+ else if (notebookPath) {
514
+ locations.push({ path: notebookPath });
172
515
  }
173
- case 'LSP':
174
- case 'lsp': {
175
- const operation = input.operation;
176
- return operation ? `LSP: ${operation}` : 'LSP';
516
+ else if (path && (toolName === 'Glob' || toolName === 'glob')) {
517
+ locations.push({ path });
177
518
  }
178
- case 'EnterPlanMode':
179
- case 'enter_plan_mode':
180
- return 'Enter Plan Mode';
181
- case 'ExitPlanMode':
182
- case 'exit_plan_mode':
183
- return 'Exit Plan Mode';
184
- case 'TaskOutput':
185
- case 'task_output':
186
- return 'Get Task Output';
187
- default:
188
- return toolName || 'Unknown Tool';
519
+ return locations.length > 0 ? locations : undefined;
189
520
  }
190
- }
191
- // ============= Tool Kind Classification =============
192
- function getToolKind(toolName) {
193
- switch (toolName) {
194
- case 'Read':
195
- case 'read':
196
- case 'NotebookRead':
197
- case 'notebook_read':
198
- case 'Glob':
199
- case 'glob':
200
- return 'read';
201
- case 'Write':
202
- case 'write':
203
- case 'Edit':
204
- case 'edit':
205
- case 'MultiEdit':
206
- case 'NotebookEdit':
207
- case 'notebook_edit':
208
- return 'edit';
209
- case 'Bash':
210
- case 'bash':
211
- case 'BashOutput':
212
- case 'bash_output':
213
- case 'KillShell':
214
- case 'kill_shell':
215
- case 'TaskOutput':
216
- case 'task_output':
217
- return 'execute';
218
- case 'Grep':
219
- case 'grep':
220
- case 'WebSearch':
221
- case 'web_search':
222
- return 'search';
223
- case 'WebFetch':
224
- case 'web_fetch':
225
- return 'fetch';
226
- case 'Task':
227
- case 'task':
228
- case 'TodoWrite':
229
- case 'todo_write':
230
- case 'EnterPlanMode':
231
- case 'enter_plan_mode':
232
- case 'ExitPlanMode':
233
- case 'exit_plan_mode':
234
- return 'think';
235
- default:
236
- return 'other';
237
- }
238
- }
239
- // ============= Content Generation by Tool Type =============
240
- function generateToolContent(toolName, input) {
241
- switch (toolName) {
242
- case 'Edit':
243
- case 'edit':
244
- case 'MultiEdit': {
245
- const filePath = input.file_path;
246
- const oldString = input.old_string;
247
- const newString = input.new_string;
248
- if (filePath && oldString !== undefined && newString !== undefined) {
249
- return [{
250
- type: 'diff',
251
- content: {
252
- path: filePath,
253
- oldText: oldString || null,
254
- newText: newString,
255
- },
256
- }];
257
- }
258
- return undefined;
521
+ // ============= Private: Content Format Conversion =============
522
+ static formatAcpContentForSdk(toolCallContent) {
523
+ var _a;
524
+ if (toolCallContent.length === 0) {
525
+ return '';
259
526
  }
260
- case 'Bash':
261
- case 'bash': {
262
- const description = input.description;
263
- if (description) {
264
- return [{
265
- type: 'text',
266
- content: { type: 'text', text: description },
267
- }];
527
+ const blocks = [];
528
+ for (const item of toolCallContent) {
529
+ if (item.type === 'diff') {
530
+ const diff = item;
531
+ const diffText = `--- ${diff.path}
532
+ +++ ${diff.path}
533
+ ${AcpTransformer.formatDiffHunk((_a = diff.oldText) !== null && _a !== void 0 ? _a : null, diff.newText)}`;
534
+ blocks.push({
535
+ type: 'text',
536
+ text: diffText,
537
+ });
268
538
  }
269
- return undefined;
270
- }
271
- case 'Task':
272
- case 'task': {
273
- const prompt = input.prompt;
274
- if (prompt) {
275
- return [{
539
+ else if (item.type === 'content') {
540
+ const contentItem = item;
541
+ if (contentItem.content && contentItem.content.type === 'text' && contentItem.content.text) {
542
+ blocks.push({
276
543
  type: 'text',
277
- content: { type: 'text', text: prompt },
278
- }];
544
+ text: contentItem.content.text,
545
+ });
546
+ }
279
547
  }
280
- return undefined;
281
- }
282
- case 'WebFetch':
283
- case 'web_fetch': {
284
- const prompt = input.prompt;
285
- if (prompt) {
286
- return [{
548
+ else if (item.type === 'terminal') {
549
+ const terminalItem = item;
550
+ if (terminalItem.terminalId) {
551
+ blocks.push({
287
552
  type: 'text',
288
- content: { type: 'text', text: prompt },
289
- }];
553
+ text: `[Terminal: ${terminalItem.terminalId}]`,
554
+ });
555
+ }
290
556
  }
291
- return undefined;
292
557
  }
293
- default:
294
- return undefined;
558
+ if (blocks.length === 1 && blocks[0].type === 'text') {
559
+ return blocks[0].text;
560
+ }
561
+ return blocks.length > 0 ? blocks : '';
295
562
  }
296
- }
297
- // ============= Location Extraction by Tool Type =============
298
- function extractToolLocations(toolName, input) {
299
- const locations = [];
300
- // File path based tools
301
- const filePath = input.file_path;
302
- const notebookPath = input.notebook_path;
303
- const path = input.path;
304
- // Add file location if present
305
- if (filePath) {
306
- locations.push({
307
- path: filePath,
308
- line: input.offset,
309
- });
563
+ static formatDiffHunk(oldText, newText) {
564
+ const oldLines = oldText ? oldText.split('\n') : [];
565
+ const newLines = newText.split('\n');
566
+ const hunks = [];
567
+ hunks.push(`@@ -1,${oldLines.length} +1,${newLines.length} @@`);
568
+ for (const line of oldLines) {
569
+ hunks.push(`-${line}`);
570
+ }
571
+ for (const line of newLines) {
572
+ hunks.push(`+${line}`);
573
+ }
574
+ return hunks.join('\n');
310
575
  }
311
- else if (notebookPath) {
312
- locations.push({ path: notebookPath });
576
+ // ============= Private: Prompt and Result Helpers =============
577
+ static privateExtractPromptText(prompt) {
578
+ let content = '';
579
+ if (prompt && Array.isArray(prompt)) {
580
+ for (const block of prompt) {
581
+ if (block.type === 'text' && block.text) {
582
+ content += block.text;
583
+ }
584
+ }
585
+ }
586
+ return content;
313
587
  }
314
- else if (path && (toolName === 'Glob' || toolName === 'glob')) {
315
- locations.push({ path });
588
+ // ============= Private: Content Block Extraction =============
589
+ static privateExtractToolUseBlocks(contentBlocks) {
590
+ if (!Array.isArray(contentBlocks))
591
+ return [];
592
+ return contentBlocks.filter((block) => typeof block === 'object' &&
593
+ block !== null &&
594
+ 'type' in block &&
595
+ block.type === 'tool_use');
316
596
  }
317
- return locations.length > 0 ? locations : undefined;
318
- }
319
- // ============= Conversion: ACP Tool Result → SDK Tool Result =============
320
- /**
321
- * Convert ACP Tool Result to SDK ToolResultContentBlock
322
- * Preserves tool_use_id and ensures error state is tracked
323
- *
324
- * @param toolCallId - Original tool call ID
325
- * @param acpResult - ACP tool result
326
- * @returns SDK ToolResultContentBlock
327
- */
328
- function convertAcpToolResultToSdk(toolCallId, acpResult) {
329
- const isError = acpResult.status === 'failed';
330
- const content = acpResult.content ? formatAcpContentForSdk(acpResult.content) : '';
331
- return {
332
- type: 'tool_result',
333
- tool_use_id: toolCallId,
334
- content: content,
335
- is_error: isError,
336
- };
337
- }
338
- // ============= Content Format Conversion =============
339
- /**
340
- * Convert ACP content format to SDK content format
341
- */
342
- function formatAcpContentForSdk(acpContent) {
343
- if (acpContent.length === 0) {
344
- return '';
345
- }
346
- // If all content is text type, combine into single string
347
- if (acpContent.every(c => c.type === 'text')) {
348
- return acpContent
349
- .map(c => {
350
- if (c.content && 'text' in c.content) {
351
- return c.content.text;
352
- }
597
+ static privateExtractTextContent(contentBlocks) {
598
+ if (!Array.isArray(contentBlocks))
353
599
  return '';
354
- })
600
+ return contentBlocks
601
+ .filter((block) => typeof block === 'object' &&
602
+ block !== null &&
603
+ 'type' in block &&
604
+ block.type === 'text')
605
+ .map((block) => block.text)
355
606
  .join('\n');
356
607
  }
357
- // Otherwise, convert to ContentBlock array
358
- const blocks = [];
359
- for (const item of acpContent) {
360
- const block = convertAcpContentToContentBlock(item);
361
- if (block) {
362
- blocks.push(block);
363
- }
364
- }
365
- return blocks.length > 0 ? blocks : '';
366
- }
367
- /**
368
- * Convert single ACP content item to ContentBlock
369
- */
370
- function convertAcpContentToContentBlock(acpContent) {
371
- if (acpContent.type === 'text' && acpContent.content && 'text' in acpContent.content) {
372
- const textBlock = {
373
- type: 'text',
374
- text: acpContent.content.text,
375
- };
376
- return textBlock;
377
- }
378
- if (acpContent.type === 'diff' && acpContent.content && 'path' in acpContent.content) {
379
- // For now, convert diff back to text representation
380
- const diff = acpContent.content;
381
- const diffText = `--- ${diff.path}
382
- +++ ${diff.path}
383
- ${formatDiffHunk(diff.oldText, diff.newText)}`;
384
- const textBlock = {
385
- type: 'text',
386
- text: diffText,
608
+ static privateCreateToolResultMessage(acpMessage, acpResult) {
609
+ var _a;
610
+ const toolResultBlock = AcpTransformer.convertAcpToolResultToSdk(acpResult.toolCallId, acpResult);
611
+ return {
612
+ type: 'user',
613
+ session_id: ((_a = acpMessage.params) === null || _a === void 0 ? void 0 : _a.sessionId) || 'unknown',
614
+ message: {
615
+ role: 'user',
616
+ content: [toolResultBlock],
617
+ },
618
+ parent_tool_use_id: acpResult.toolCallId,
387
619
  };
388
- return textBlock;
389
620
  }
390
- return null;
391
- }
392
- /**
393
- * Format diff hunks for display
394
- */
395
- function formatDiffHunk(oldText, newText) {
396
- const oldLines = oldText ? oldText.split('\n') : [];
397
- const newLines = newText.split('\n');
398
- const hunks = [];
399
- hunks.push(`@@ -1,${oldLines.length} +1,${newLines.length} @@`);
400
- // Add old lines
401
- for (const line of oldLines) {
402
- hunks.push(`-${line}`);
403
- }
404
- // Add new lines
405
- for (const line of newLines) {
406
- hunks.push(`+${line}`);
407
- }
408
- return hunks.join('\n');
409
- }
410
- // ============= Helper: Extract Tool Use Blocks =============
411
- /**
412
- * Extract tool use blocks from content blocks array
413
- */
414
- function extractToolUseBlocks(contentBlocks) {
415
- if (!Array.isArray(contentBlocks))
416
- return [];
417
- return contentBlocks.filter((block) => typeof block === 'object' &&
418
- block !== null &&
419
- 'type' in block &&
420
- block.type === 'tool_use');
421
- }
422
- /**
423
- * Extract text content from content blocks array
424
- */
425
- function extractTextContent(contentBlocks) {
426
- if (!Array.isArray(contentBlocks))
427
- return '';
428
- return contentBlocks
429
- .filter((block) => typeof block === 'object' &&
430
- block !== null &&
431
- 'type' in block &&
432
- block.type === 'text')
433
- .map((block) => block.text)
434
- .join('\n');
435
621
  }
622
+ exports.AcpTransformer = AcpTransformer;
436
623
  //# sourceMappingURL=tool-converter.js.map