@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.
- package/cli/CHANGELOG.md +18 -0
- package/cli/dist/codebuddy.js +3 -3
- package/cli/package.json +1 -1
- package/cli/product.cloudhosted.json +2 -2
- package/cli/product.internal.json +2 -2
- package/cli/product.ioa.json +2 -2
- package/cli/product.json +2 -2
- package/cli/product.selfhosted.json +2 -2
- package/lib/acp/index.d.ts +7 -11
- package/lib/acp/index.d.ts.map +1 -1
- package/lib/acp/index.js +7 -14
- package/lib/acp/index.js.map +1 -1
- package/lib/acp/tool-converter.d.ts +98 -53
- package/lib/acp/tool-converter.d.ts.map +1 -1
- package/lib/acp/tool-converter.js +574 -387
- package/lib/acp/tool-converter.js.map +1 -1
- package/lib/index.d.ts +0 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -4
- package/lib/index.js.map +1 -1
- package/lib/query.d.ts +0 -25
- package/lib/query.d.ts.map +1 -1
- package/lib/query.js +38 -167
- package/lib/query.js.map +1 -1
- package/lib/session.d.ts +17 -4
- package/lib/session.d.ts.map +1 -1
- package/lib/session.js +152 -14
- package/lib/session.js.map +1 -1
- package/lib/transport/index.d.ts +7 -0
- package/lib/transport/index.d.ts.map +1 -1
- package/lib/transport/index.js.map +1 -1
- package/lib/transport/process-transport.d.ts +30 -0
- package/lib/transport/process-transport.d.ts.map +1 -1
- package/lib/transport/process-transport.js +177 -1
- package/lib/transport/process-transport.js.map +1 -1
- package/lib/types.d.ts +36 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js.map +1 -1
- package/package.json +2 -1
- package/lib/acp/acp-client.d.ts +0 -62
- package/lib/acp/acp-client.d.ts.map +0 -1
- package/lib/acp/acp-client.js +0 -256
- package/lib/acp/acp-client.js.map +0 -1
|
@@ -1,436 +1,623 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
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.
|
|
14
|
-
|
|
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
|
-
*
|
|
20
|
-
*
|
|
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
|
-
*
|
|
23
|
-
*
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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 (
|
|
52
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
const command = input.command;
|
|
171
|
-
return command ? `Skill: ${command}` : 'Skill';
|
|
513
|
+
else if (notebookPath) {
|
|
514
|
+
locations.push({ path: notebookPath });
|
|
172
515
|
}
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
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
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
|
|
278
|
-
}
|
|
544
|
+
text: contentItem.content.text,
|
|
545
|
+
});
|
|
546
|
+
}
|
|
279
547
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
289
|
-
}
|
|
553
|
+
text: `[Terminal: ${terminalItem.terminalId}]`,
|
|
554
|
+
});
|
|
555
|
+
}
|
|
290
556
|
}
|
|
291
|
-
return undefined;
|
|
292
557
|
}
|
|
293
|
-
|
|
294
|
-
return
|
|
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
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
-
|
|
312
|
-
|
|
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
|
-
|
|
315
|
-
|
|
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
|
-
|
|
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
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
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
|