@codebolt/agent 6.0.0 → 6.0.1
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/dist/index.d.ts +2 -0
- package/dist/index.js +41 -0
- package/dist/processor-pieces/messageModifiers/chatHistoryMessageModifier.js +2 -4
- package/dist/processor-pieces/messageModifiers/contextAssemblyModifier.d.ts +81 -0
- package/dist/processor-pieces/messageModifiers/contextAssemblyModifier.js +316 -0
- package/dist/processor-pieces/messageModifiers/coreSystemPromptModifier.js +2 -19
- package/dist/processor-pieces/messageModifiers/directoryContextModifier.js +2 -6
- package/dist/processor-pieces/messageModifiers/environmentContextModifier.js +2 -7
- package/dist/processor-pieces/messageModifiers/ideContextModifier.js +2 -21
- package/dist/processor-pieces/messageModifiers/index.d.ts +3 -0
- package/dist/processor-pieces/messageModifiers/index.js +7 -1
- package/dist/processor-pieces/messageModifiers/toolInjectionModifier.js +2 -1
- package/dist/processor-pieces/postToolCallProcessors/conversationCompactorModifier.d.ts +34 -5
- package/dist/processor-pieces/postToolCallProcessors/conversationCompactorModifier.js +374 -89
- package/dist/processor-pieces/preInferenceProcessors/chatCompressionModifier.d.ts +3 -0
- package/dist/processor-pieces/preInferenceProcessors/chatCompressionModifier.js +50 -27
- package/dist/unified/agent/agent.d.ts +10 -0
- package/dist/unified/agent/agent.js +198 -10
- package/dist/unified/agent/codeboltAgent.d.ts +19 -100
- package/dist/unified/agent/codeboltAgent.js +209 -109
- package/dist/unified/base/agentStep.js +17 -17
- package/dist/unified/base/initialPromptGenerator.js +13 -31
- package/dist/unified/base/promptContext.d.ts +13 -0
- package/dist/unified/base/promptContext.js +213 -0
- package/dist/unified/base/responseExecutor.d.ts +7 -19
- package/dist/unified/base/responseExecutor.js +351 -258
- package/dist/unified/index.d.ts +9 -0
- package/dist/unified/index.js +20 -13
- package/dist/unified/services/CompressionCoordinator.d.ts +67 -0
- package/dist/unified/services/CompressionCoordinator.js +214 -0
- package/dist/unified/services/compaction/autoCompact.d.ts +52 -0
- package/dist/unified/services/compaction/autoCompact.js +294 -0
- package/dist/unified/services/compaction/compactionOrchestrator.d.ts +78 -0
- package/dist/unified/services/compaction/compactionOrchestrator.js +230 -0
- package/dist/unified/services/compaction/contextCollapse.d.ts +63 -0
- package/dist/unified/services/compaction/contextCollapse.js +291 -0
- package/dist/unified/services/compaction/microCompact.d.ts +34 -0
- package/dist/unified/services/compaction/microCompact.js +195 -0
- package/dist/unified/services/compaction/postCompactCleanup.d.ts +15 -0
- package/dist/unified/services/compaction/postCompactCleanup.js +37 -0
- package/dist/unified/services/compaction/reactiveCompact.d.ts +65 -0
- package/dist/unified/services/compaction/reactiveCompact.js +301 -0
- package/dist/unified/services/compaction/snipCompact.d.ts +31 -0
- package/dist/unified/services/compaction/snipCompact.js +124 -0
- package/dist/unified/services/compaction/types.d.ts +66 -0
- package/dist/unified/services/compaction/types.js +39 -0
- package/package.json +22 -30
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.ResponseExecutor = void 0;
|
|
7
7
|
const codeboltjs_1 = __importDefault(require("@codebolt/codeboltjs"));
|
|
8
|
+
const promptContext_1 = require("./promptContext");
|
|
8
9
|
class ResponseExecutor {
|
|
9
10
|
constructor(options) {
|
|
10
11
|
this.preToolCallProcessors = [];
|
|
@@ -13,340 +14,373 @@ class ResponseExecutor {
|
|
|
13
14
|
this.finalMessage = undefined;
|
|
14
15
|
this.preToolCallProcessors = options.preToolCallProcessors;
|
|
15
16
|
this.postToolCallProcessors = options.postToolCallProcessors;
|
|
16
|
-
|
|
17
|
-
this.loopDetectionService = options.loopDetectionService;
|
|
18
|
-
}
|
|
17
|
+
this.loopDetectionService = options.loopDetectionService;
|
|
19
18
|
}
|
|
20
19
|
async executeResponse(input) {
|
|
21
|
-
var _a, _b;
|
|
22
|
-
|
|
20
|
+
var _a, _b, _c;
|
|
21
|
+
this.completed = false;
|
|
22
|
+
this.finalMessage = undefined;
|
|
23
|
+
let nextMessage = (0, promptContext_1.reconcileRuntimePromptContext)(input.nextMessage);
|
|
23
24
|
for (const preToolCallProcessor of this.preToolCallProcessors) {
|
|
24
25
|
try {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
const { nextPrompt, shouldExit } = await preToolCallProcessor.modify({
|
|
27
|
+
llmMessageSent: input.actualMessageSentToLLM,
|
|
28
|
+
rawLLMResponseMessage: input.rawLLMOutput,
|
|
29
|
+
nextPrompt: nextMessage,
|
|
30
|
+
});
|
|
31
|
+
nextMessage = (0, promptContext_1.reconcileRuntimePromptContext)(nextPrompt);
|
|
28
32
|
if (shouldExit) {
|
|
29
33
|
this.completed = true;
|
|
30
|
-
|
|
31
|
-
nextPrompt,
|
|
32
|
-
completed: this.completed
|
|
33
|
-
});
|
|
34
|
+
break;
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
catch (error) {
|
|
37
|
-
console.error(`[
|
|
38
|
-
// Continue with other modifiers
|
|
38
|
+
console.error(`[ResponseExecutor] Error in pre tool call processor:`, error);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
const toolExecution = await this.executeTools(input.rawLLMOutput);
|
|
42
|
+
this.completed = this.completed || toolExecution.completed;
|
|
43
|
+
this.finalMessage = (_a = toolExecution.finalMessage) !== null && _a !== void 0 ? _a : this.finalMessage;
|
|
44
|
+
this.injectDiscoveredTools(input.rawLLMOutput, toolExecution.toolResults, nextMessage);
|
|
45
|
+
if (toolExecution.toolResults.length > 0 || toolExecution.followUpMessages.length > 0) {
|
|
46
|
+
nextMessage = (0, promptContext_1.appendTranscriptMessages)(nextMessage, [
|
|
47
|
+
...toolExecution.toolResults.map((toolResult) => ({
|
|
47
48
|
role: toolResult.role,
|
|
48
|
-
content: typeof toolResult.content === 'string'
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// this.completed=true;
|
|
56
|
-
nextMessage.message.messages.push({
|
|
57
|
-
role: "user",
|
|
58
|
-
content: [{
|
|
59
|
-
type: "text",
|
|
60
|
-
text: "If you have completed the user's task, use the attempt_completion tool. if you have not completed the task and do not need additional information, then proceed with the next step of the task. (This is an automated message, so do not respond to it conversationally.)"
|
|
61
|
-
}]
|
|
62
|
-
});
|
|
49
|
+
content: typeof toolResult.content === 'string'
|
|
50
|
+
? toolResult.content
|
|
51
|
+
: JSON.stringify(toolResult.content),
|
|
52
|
+
tool_call_id: toolResult.tool_call_id,
|
|
53
|
+
})),
|
|
54
|
+
...toolExecution.followUpMessages,
|
|
55
|
+
]);
|
|
63
56
|
}
|
|
57
|
+
const transcriptLengthBeforePostToolProcessors = (0, promptContext_1.getTranscriptMessages)(nextMessage).length;
|
|
64
58
|
for (const postToolCallProcessor of this.postToolCallProcessors) {
|
|
65
59
|
try {
|
|
66
|
-
|
|
67
|
-
let { nextPrompt, shouldExit } = await postToolCallProcessor.modify({
|
|
60
|
+
const { nextPrompt, shouldExit } = await postToolCallProcessor.modify({
|
|
68
61
|
llmMessageSent: input.actualMessageSentToLLM,
|
|
69
62
|
rawLLMResponseMessage: input.rawLLMOutput,
|
|
70
63
|
nextPrompt: nextMessage,
|
|
71
|
-
toolResults: toolResults,
|
|
72
|
-
tokenLimit: (
|
|
73
|
-
maxOutputTokens: (
|
|
64
|
+
toolResults: toolExecution.toolResults,
|
|
65
|
+
tokenLimit: (_b = input.rawLLMOutput) === null || _b === void 0 ? void 0 : _b.tokenLimit,
|
|
66
|
+
maxOutputTokens: (_c = input.rawLLMOutput) === null || _c === void 0 ? void 0 : _c.maxOutputTokens
|
|
74
67
|
});
|
|
75
|
-
|
|
76
|
-
nextMessage = nextPrompt;
|
|
68
|
+
nextMessage = (0, promptContext_1.reconcileRuntimePromptContext)(nextPrompt);
|
|
77
69
|
if (shouldExit) {
|
|
78
70
|
this.completed = true;
|
|
79
|
-
|
|
80
|
-
nextPrompt,
|
|
81
|
-
completed: this.completed
|
|
82
|
-
});
|
|
71
|
+
break;
|
|
83
72
|
}
|
|
84
73
|
}
|
|
85
74
|
catch (error) {
|
|
86
75
|
console.error(`[ResponseExecutor] Error in post tool call processor:`, error);
|
|
87
|
-
// Continue with other processors
|
|
88
76
|
}
|
|
89
77
|
}
|
|
78
|
+
const transcriptLengthAfterPostToolProcessors = (0, promptContext_1.getTranscriptMessages)(nextMessage).length;
|
|
79
|
+
if (!toolExecution.hadToolCalls &&
|
|
80
|
+
transcriptLengthAfterPostToolProcessors > transcriptLengthBeforePostToolProcessors) {
|
|
81
|
+
this.completed = false;
|
|
82
|
+
this.finalMessage = undefined;
|
|
83
|
+
}
|
|
90
84
|
const output = {
|
|
91
85
|
completed: this.completed,
|
|
92
|
-
nextMessage
|
|
93
|
-
toolResults: toolResults
|
|
86
|
+
nextMessage,
|
|
87
|
+
toolResults: toolExecution.toolResults,
|
|
94
88
|
};
|
|
95
89
|
if (this.finalMessage !== undefined) {
|
|
96
90
|
output.finalMessage = this.finalMessage;
|
|
97
91
|
}
|
|
98
92
|
return output;
|
|
99
93
|
}
|
|
100
|
-
|
|
101
|
-
* Extract tool details from tool call
|
|
102
|
-
*/
|
|
103
|
-
getToolDetail(tool) {
|
|
94
|
+
parseToolCall(tool) {
|
|
104
95
|
let toolInput = {};
|
|
105
96
|
if (tool.function.arguments) {
|
|
106
97
|
try {
|
|
107
|
-
|
|
98
|
+
const parsedArguments = JSON.parse(tool.function.arguments);
|
|
99
|
+
if (parsedArguments && typeof parsedArguments === 'object' && !Array.isArray(parsedArguments)) {
|
|
100
|
+
toolInput = parsedArguments;
|
|
101
|
+
}
|
|
108
102
|
}
|
|
109
103
|
catch (parseError) {
|
|
110
104
|
throw new Error(`Failed to parse tool arguments: ${parseError}`);
|
|
111
105
|
}
|
|
112
106
|
}
|
|
113
107
|
return {
|
|
108
|
+
tool,
|
|
109
|
+
toolInput,
|
|
114
110
|
toolName: tool.function.name,
|
|
115
|
-
|
|
116
|
-
|
|
111
|
+
toolUseId: tool.id,
|
|
112
|
+
waitForPrevious: toolInput['waitForPreviousTools'] === true,
|
|
117
113
|
};
|
|
118
114
|
}
|
|
119
|
-
|
|
120
|
-
var _a, _b;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
for (const contentBlock of llmResponse.choices || []) {
|
|
125
|
-
if (contentBlock.message) {
|
|
126
|
-
if (contentBlock.message.content != null) {
|
|
127
|
-
lastMessageContent = contentBlock.message.content;
|
|
128
|
-
// await codebolt.chat.sendMessage(contentBlock.message.content, {});
|
|
129
|
-
}
|
|
130
|
-
if (contentBlock.message["reasoning_content"] != null && (!lastMessageContent || lastMessageContent.trim() === '')) {
|
|
131
|
-
lastMessageContent = contentBlock.message["reasoning_content"];
|
|
132
|
-
// await codebolt.chat.sendMessage((contentBlock.message as any)["reasoning_content"], {});
|
|
133
|
-
}
|
|
134
|
-
}
|
|
115
|
+
extractLastMessageContent(llmResponse) {
|
|
116
|
+
var _a, _b, _c;
|
|
117
|
+
for (const choice of (_a = llmResponse.choices) !== null && _a !== void 0 ? _a : []) {
|
|
118
|
+
if ((_b = choice.message) === null || _b === void 0 ? void 0 : _b.content) {
|
|
119
|
+
return choice.message.content;
|
|
135
120
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
toolUseId,
|
|
156
|
-
waitForPrevious: (toolInput === null || toolInput === void 0 ? void 0 : toolInput.waitForPreviousTools) === true
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
// Check for loops before execution
|
|
161
|
-
if (this.loopDetectionService) {
|
|
162
|
-
const toolCallsToCheck = toolsToExecute.map(t => ({ name: t.toolName, args: t.toolInput }));
|
|
163
|
-
for (const toolCall of toolCallsToCheck) {
|
|
164
|
-
const loopDetected = this.loopDetectionService.checkToolCallLoop(toolCall.name, toolCall.args);
|
|
165
|
-
if (loopDetected) {
|
|
166
|
-
this.completed = true;
|
|
167
|
-
this.finalMessage = `Loop Detected: The agent is stuck in a loop of identical tool calls (${toolCall.name}). Execution stopped to prevent infinite recurrence.`;
|
|
168
|
-
return [{
|
|
169
|
-
role: 'tool',
|
|
170
|
-
tool_call_id: 'system-loop-detection', // Virtual ID
|
|
171
|
-
content: JSON.stringify({ error: this.finalMessage })
|
|
172
|
-
}];
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
// Second pass: Execute tools sequentially (one by one)
|
|
177
|
-
for (const item of toolsToExecute) {
|
|
178
|
-
try {
|
|
179
|
-
if (!userRejectedToolUse) {
|
|
180
|
-
let [serverName] = item.toolName.replace('--', ':').split(':');
|
|
181
|
-
// codebolt.chat.sendMessage(`tool call ${serverName} ${item.toolName} ${item.toolInput}`, {});
|
|
182
|
-
if (serverName == 'subagent') {
|
|
183
|
-
await codeboltjs_1.default.agent.startAgent(item.toolName.replace("subagent--", ''), item.toolInput.task);
|
|
184
|
-
const [didUserReject, result] = [false, "tool result is successful"];
|
|
185
|
-
let toolResult = this.parseToolResult(item.toolUseId, result);
|
|
186
|
-
// Handle side effects (fallback messages)
|
|
187
|
-
if (toolResult.userMessage) {
|
|
188
|
-
fallBackMessages.push({
|
|
189
|
-
role: "user",
|
|
190
|
-
content: toolResult.userMessage.toString()
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
if (didUserReject) {
|
|
194
|
-
userRejectedToolUse = true;
|
|
195
|
-
}
|
|
196
|
-
toolResults.push({
|
|
197
|
-
role: "tool",
|
|
198
|
-
tool_call_id: toolResult.tool_call_id,
|
|
199
|
-
content: toolResult.content,
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
else if (item.toolName == "codebolt--thread_management") {
|
|
203
|
-
const response = await codeboltjs_1.default.thread.createThreadInBackground({
|
|
204
|
-
title: item.toolInput.title || item.toolInput.task || 'Background Thread',
|
|
205
|
-
description: item.toolInput.description || item.toolInput.task || '',
|
|
206
|
-
userMessage: item.toolInput.task || item.toolInput.userMessage || '',
|
|
207
|
-
selectedAgent: item.toolInput.selectedAgent,
|
|
208
|
-
isGrouped: item.toolInput.isGrouped,
|
|
209
|
-
groupId: item.toolInput.groupId,
|
|
210
|
-
});
|
|
211
|
-
toolResults.push({
|
|
212
|
-
role: "tool",
|
|
213
|
-
tool_call_id: item.toolUseId,
|
|
214
|
-
content: JSON.stringify(response),
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
const [didUserReject, result] = await this.executeTool(item.toolName, item.toolInput);
|
|
219
|
-
let toolResult = this.parseToolResult(item.toolUseId, result);
|
|
220
|
-
if (toolResult.userMessage) {
|
|
221
|
-
fallBackMessages.push({
|
|
222
|
-
role: "user",
|
|
223
|
-
content: toolResult.userMessage.toString()
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
if (didUserReject) {
|
|
227
|
-
userRejectedToolUse = true;
|
|
228
|
-
}
|
|
229
|
-
toolResults.push({
|
|
230
|
-
role: "tool",
|
|
231
|
-
tool_call_id: toolResult.tool_call_id,
|
|
232
|
-
content: toolResult.content,
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
else {
|
|
237
|
-
let toolResult = this.parseToolResult(item.toolUseId, "Skipping tool execution due to previous tool user rejection.");
|
|
238
|
-
if (toolResult.userMessage) {
|
|
239
|
-
fallBackMessages.push({
|
|
240
|
-
role: "user",
|
|
241
|
-
content: toolResult.userMessage.toString()
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
toolResults.push({
|
|
245
|
-
role: "tool",
|
|
246
|
-
tool_call_id: toolResult.tool_call_id,
|
|
247
|
-
content: toolResult.content,
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
catch (error) {
|
|
252
|
-
toolResults.push({
|
|
253
|
-
role: "tool",
|
|
254
|
-
tool_call_id: item.tool.id,
|
|
255
|
-
content: String(error),
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
}
|
|
121
|
+
const reasoningContent = (_c = choice.message) === null || _c === void 0 ? void 0 : _c.reasoning_content;
|
|
122
|
+
if (reasoningContent) {
|
|
123
|
+
return reasoningContent;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
getToolCalls(llmResponse) {
|
|
129
|
+
var _a, _b, _c, _d;
|
|
130
|
+
const toolCallsById = new Map();
|
|
131
|
+
for (const toolCall of (_a = llmResponse.tool_calls) !== null && _a !== void 0 ? _a : []) {
|
|
132
|
+
if (toolCall === null || toolCall === void 0 ? void 0 : toolCall.id) {
|
|
133
|
+
toolCallsById.set(toolCall.id, toolCall);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
for (const choice of (_b = llmResponse.choices) !== null && _b !== void 0 ? _b : []) {
|
|
137
|
+
for (const toolCall of (_d = (_c = choice.message) === null || _c === void 0 ? void 0 : _c.tool_calls) !== null && _d !== void 0 ? _d : []) {
|
|
138
|
+
if ((toolCall === null || toolCall === void 0 ? void 0 : toolCall.id) && !toolCallsById.has(toolCall.id)) {
|
|
139
|
+
toolCallsById.set(toolCall.id, toolCall);
|
|
259
140
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return Array.from(toolCallsById.values());
|
|
144
|
+
}
|
|
145
|
+
async executeTools(llmResponse) {
|
|
146
|
+
const lastMessageContent = this.extractLastMessageContent(llmResponse);
|
|
147
|
+
const toolCalls = this.getToolCalls(llmResponse);
|
|
148
|
+
if (toolCalls.length === 0) {
|
|
149
|
+
return {
|
|
150
|
+
toolResults: [],
|
|
151
|
+
followUpMessages: [],
|
|
152
|
+
completed: true,
|
|
153
|
+
finalMessage: lastMessageContent,
|
|
154
|
+
hadToolCalls: false,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const parsedToolCalls = toolCalls.map((tool) => this.parseToolCall(tool));
|
|
158
|
+
const completionToolCalls = parsedToolCalls.filter((toolCall) => toolCall.toolName.includes('attempt_completion'));
|
|
159
|
+
const executionToolCalls = parsedToolCalls.filter((toolCall) => !toolCall.toolName.includes('attempt_completion'));
|
|
160
|
+
if (this.loopDetectionService) {
|
|
161
|
+
for (const toolCall of executionToolCalls) {
|
|
162
|
+
const loopDetected = this.loopDetectionService.checkToolCallLoop(toolCall.toolName, toolCall.toolInput);
|
|
163
|
+
if (loopDetected) {
|
|
164
|
+
const loopMessage = `Loop detected while calling "${toolCall.toolName}". Execution stopped to prevent infinite recurrence.`;
|
|
165
|
+
return {
|
|
166
|
+
toolResults: [{
|
|
167
|
+
role: 'tool',
|
|
168
|
+
tool_call_id: 'system-loop-detection',
|
|
169
|
+
content: JSON.stringify({ error: loopMessage }),
|
|
170
|
+
}],
|
|
171
|
+
followUpMessages: [],
|
|
172
|
+
completed: true,
|
|
173
|
+
finalMessage: loopMessage,
|
|
174
|
+
hadToolCalls: true,
|
|
175
|
+
};
|
|
266
176
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const toolResults = [];
|
|
180
|
+
const followUpMessages = [];
|
|
181
|
+
let userRejectedToolUse = false;
|
|
182
|
+
let currentIndex = 0;
|
|
183
|
+
while (currentIndex < executionToolCalls.length) {
|
|
184
|
+
const currentToolCall = executionToolCalls[currentIndex];
|
|
185
|
+
if (!currentToolCall) {
|
|
186
|
+
currentIndex += 1;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (userRejectedToolUse) {
|
|
190
|
+
const skippedResult = this.parseToolResult(currentToolCall.toolUseId, 'Skipping tool execution due to previous tool user rejection.');
|
|
191
|
+
toolResults.push(skippedResult);
|
|
192
|
+
currentIndex += 1;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (!this.isConcurrencySafe(currentToolCall)) {
|
|
196
|
+
const executionResult = await this.executeSingleToolCall(currentToolCall);
|
|
197
|
+
toolResults.push(executionResult.toolResult);
|
|
198
|
+
followUpMessages.push(...executionResult.followUpMessages);
|
|
199
|
+
userRejectedToolUse = executionResult.didUserReject;
|
|
200
|
+
currentIndex += 1;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
const parallelBatch = [];
|
|
204
|
+
while (currentIndex < executionToolCalls.length) {
|
|
205
|
+
const candidateToolCall = executionToolCalls[currentIndex];
|
|
206
|
+
if (!candidateToolCall ||
|
|
207
|
+
candidateToolCall.waitForPrevious ||
|
|
208
|
+
!this.isConcurrencySafe(candidateToolCall)) {
|
|
209
|
+
break;
|
|
290
210
|
}
|
|
291
|
-
|
|
211
|
+
parallelBatch.push(candidateToolCall);
|
|
212
|
+
currentIndex += 1;
|
|
292
213
|
}
|
|
293
|
-
|
|
214
|
+
const batchResults = await Promise.all(parallelBatch.map((toolCall) => this.executeSingleToolCall(toolCall)));
|
|
215
|
+
for (const batchResult of batchResults) {
|
|
216
|
+
toolResults.push(batchResult.toolResult);
|
|
217
|
+
followUpMessages.push(...batchResult.followUpMessages);
|
|
218
|
+
userRejectedToolUse = userRejectedToolUse || batchResult.didUserReject;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (completionToolCalls.length > 0) {
|
|
222
|
+
const completionToolCall = completionToolCalls.at(-1);
|
|
223
|
+
if (completionToolCall) {
|
|
224
|
+
const completionArguments = completionToolCall.toolInput;
|
|
225
|
+
this.finalMessage = JSON.stringify(completionArguments);
|
|
226
|
+
const [, completionResult] = await this.executeTool(completionToolCall.toolName, completionArguments);
|
|
227
|
+
const parsedCompletionResult = this.parseToolResult(completionToolCall.toolUseId, completionResult === '' ? 'The user is satisfied with the result.' : completionResult);
|
|
228
|
+
toolResults.push(parsedCompletionResult);
|
|
294
229
|
}
|
|
295
230
|
}
|
|
231
|
+
return {
|
|
232
|
+
toolResults,
|
|
233
|
+
followUpMessages,
|
|
234
|
+
completed: completionToolCalls.length > 0,
|
|
235
|
+
finalMessage: this.finalMessage,
|
|
236
|
+
hadToolCalls: true,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
isConcurrencySafe(toolCall) {
|
|
240
|
+
var _a;
|
|
241
|
+
if (toolCall.waitForPrevious) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
const normalizedToolName = toolCall.toolName.toLowerCase();
|
|
245
|
+
if (normalizedToolName.startsWith('subagent--') ||
|
|
246
|
+
normalizedToolName.includes('thread_management')) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
const actualToolName = (_a = normalizedToolName.split('--').at(-1)) !== null && _a !== void 0 ? _a : normalizedToolName;
|
|
250
|
+
const toolNameTokens = actualToolName
|
|
251
|
+
.split(/[^a-z0-9]+/)
|
|
252
|
+
.filter((token) => token.length > 0);
|
|
253
|
+
const mutatingKeywords = new Set([
|
|
254
|
+
'write',
|
|
255
|
+
'edit',
|
|
256
|
+
'create',
|
|
257
|
+
'delete',
|
|
258
|
+
'remove',
|
|
259
|
+
'rename',
|
|
260
|
+
'move',
|
|
261
|
+
'copy',
|
|
262
|
+
'apply',
|
|
263
|
+
'shell',
|
|
264
|
+
'command',
|
|
265
|
+
'run',
|
|
266
|
+
'exec',
|
|
267
|
+
'thread_management',
|
|
268
|
+
'attempt_completion',
|
|
269
|
+
'completion',
|
|
270
|
+
'todo',
|
|
271
|
+
'spawn',
|
|
272
|
+
'start',
|
|
273
|
+
]);
|
|
274
|
+
if (toolNameTokens.some((token) => mutatingKeywords.has(token))) {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
const readOnlyKeywords = new Set([
|
|
278
|
+
'read',
|
|
279
|
+
'search',
|
|
280
|
+
'list',
|
|
281
|
+
'find',
|
|
282
|
+
'glob',
|
|
283
|
+
'grep',
|
|
284
|
+
'view',
|
|
285
|
+
'stat',
|
|
286
|
+
'inspect',
|
|
287
|
+
'get',
|
|
288
|
+
'show',
|
|
289
|
+
'query',
|
|
290
|
+
'ls',
|
|
291
|
+
'cat',
|
|
292
|
+
]);
|
|
293
|
+
return toolNameTokens.some((token) => readOnlyKeywords.has(token));
|
|
294
|
+
}
|
|
295
|
+
async executeSingleToolCall(toolCall) {
|
|
296
|
+
try {
|
|
297
|
+
let resultTuple;
|
|
298
|
+
if (toolCall.toolName === 'codebolt--thread_management') {
|
|
299
|
+
resultTuple = [
|
|
300
|
+
false,
|
|
301
|
+
await codeboltjs_1.default.thread.createThreadInBackground({
|
|
302
|
+
title: String(toolCall.toolInput['title'] || toolCall.toolInput['task'] || 'Background Thread'),
|
|
303
|
+
description: String(toolCall.toolInput['description'] || toolCall.toolInput['task'] || ''),
|
|
304
|
+
userMessage: String(toolCall.toolInput['task'] || toolCall.toolInput['userMessage'] || ''),
|
|
305
|
+
selectedAgent: toolCall.toolInput['selectedAgent'],
|
|
306
|
+
isGrouped: Boolean(toolCall.toolInput['isGrouped']),
|
|
307
|
+
...(typeof toolCall.toolInput['groupId'] === 'string'
|
|
308
|
+
? { groupId: toolCall.toolInput['groupId'] }
|
|
309
|
+
: {}),
|
|
310
|
+
})
|
|
311
|
+
];
|
|
312
|
+
}
|
|
313
|
+
else if (toolCall.toolName.startsWith('subagent--')) {
|
|
314
|
+
const task = toolCall.toolInput['task'];
|
|
315
|
+
await codeboltjs_1.default.agent.startAgent(toolCall.toolName.replace('subagent--', ''), typeof task === 'string' ? task : JSON.stringify(task));
|
|
316
|
+
resultTuple = [false, 'tool result is successful'];
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
resultTuple = await this.executeTool(toolCall.toolName, toolCall.toolInput);
|
|
320
|
+
}
|
|
321
|
+
const [didUserReject, result] = resultTuple;
|
|
322
|
+
const parsedResult = this.parseToolResult(toolCall.toolUseId, result);
|
|
323
|
+
return {
|
|
324
|
+
toolResult: parsedResult,
|
|
325
|
+
followUpMessages: parsedResult.userMessage ? [{
|
|
326
|
+
role: 'user',
|
|
327
|
+
content: parsedResult.userMessage.toString(),
|
|
328
|
+
}] : [],
|
|
329
|
+
didUserReject,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
296
332
|
catch (error) {
|
|
333
|
+
return {
|
|
334
|
+
toolResult: {
|
|
335
|
+
role: 'tool',
|
|
336
|
+
tool_call_id: toolCall.toolUseId,
|
|
337
|
+
content: String(error),
|
|
338
|
+
},
|
|
339
|
+
followUpMessages: [],
|
|
340
|
+
didUserReject: false,
|
|
341
|
+
};
|
|
297
342
|
}
|
|
298
|
-
return [];
|
|
299
343
|
}
|
|
300
|
-
/**
|
|
301
|
-
* Executes a tool with given name and input.
|
|
302
|
-
*
|
|
303
|
-
* @param toolName - The name of the tool to execute
|
|
304
|
-
* @param toolInput - The input parameters for the tool
|
|
305
|
-
* @returns Promise with tuple [userRejected, result]
|
|
306
|
-
*/
|
|
307
344
|
async executeTool(toolName, toolInput) {
|
|
308
345
|
var _a, _b, _c;
|
|
309
|
-
//codebolttools--readfile
|
|
310
|
-
// console.log("Executing tool: ", toolName, toolInput);
|
|
311
346
|
const parts = toolName.split('--');
|
|
312
347
|
const toolboxName = parts.length > 1 ? ((_a = parts[0]) !== null && _a !== void 0 ? _a : '') : 'codebolt';
|
|
313
348
|
const actualToolName = parts.length > 1 ? ((_b = parts[1]) !== null && _b !== void 0 ? _b : '') : ((_c = parts[0]) !== null && _c !== void 0 ? _c : '');
|
|
314
|
-
// console.log("Toolbox name: ", toolboxName, "Actual tool name: ", actualToolName);
|
|
315
349
|
const { data } = await codeboltjs_1.default.mcp.executeTool(toolboxName, actualToolName, toolInput);
|
|
316
|
-
// console.log("Tool result: ", data);
|
|
317
|
-
// Handle the case where data is an array [didUserReject, content]
|
|
318
350
|
if (Array.isArray(data) && data.length >= 2) {
|
|
319
351
|
const [didUserReject, content] = data;
|
|
320
352
|
return [Boolean(didUserReject), content];
|
|
321
353
|
}
|
|
322
|
-
// If data is not in the expected array format, return it as-is
|
|
323
354
|
return [false, data];
|
|
324
355
|
}
|
|
325
|
-
/**
|
|
326
|
-
* Creates a tool result object from the tool execution response.
|
|
327
|
-
*
|
|
328
|
-
* @param tool_call_id - The ID of the tool call
|
|
329
|
-
* @param content - The content returned by the tool
|
|
330
|
-
* @returns ToolResult object
|
|
331
|
-
*/
|
|
332
356
|
parseToolResult(tool_call_id, content) {
|
|
333
|
-
let
|
|
357
|
+
let serializedContent = typeof content === 'string'
|
|
358
|
+
? content
|
|
359
|
+
: JSON.stringify(content);
|
|
360
|
+
let userMessage;
|
|
334
361
|
try {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
362
|
+
const parsedContent = typeof serializedContent === 'string'
|
|
363
|
+
? JSON.parse(serializedContent)
|
|
364
|
+
: serializedContent;
|
|
365
|
+
if (parsedContent &&
|
|
366
|
+
typeof parsedContent === 'object' &&
|
|
367
|
+
'payload' in parsedContent &&
|
|
368
|
+
parsedContent.payload &&
|
|
369
|
+
typeof parsedContent.payload === 'object' &&
|
|
370
|
+
'content' in parsedContent.payload &&
|
|
371
|
+
typeof parsedContent.payload.content === 'string') {
|
|
372
|
+
serializedContent = 'The browser action has been executed. The screenshot has been captured for your analysis. The tool response is provided in the next user message.';
|
|
373
|
+
userMessage = parsedContent.payload.content;
|
|
341
374
|
}
|
|
342
375
|
}
|
|
343
|
-
catch
|
|
376
|
+
catch {
|
|
377
|
+
// Preserve the raw tool result when it is not JSON.
|
|
344
378
|
}
|
|
345
379
|
return {
|
|
346
|
-
role:
|
|
380
|
+
role: 'tool',
|
|
347
381
|
tool_call_id,
|
|
348
|
-
content,
|
|
349
|
-
userMessage
|
|
382
|
+
content: serializedContent,
|
|
383
|
+
userMessage,
|
|
350
384
|
};
|
|
351
385
|
}
|
|
352
386
|
setPreToolCallProcessors(processors) {
|
|
@@ -361,5 +395,64 @@ class ResponseExecutor {
|
|
|
361
395
|
getPostToolCallProcessors() {
|
|
362
396
|
return this.postToolCallProcessors;
|
|
363
397
|
}
|
|
398
|
+
injectDiscoveredTools(llmResponse, toolResults, nextMessage) {
|
|
399
|
+
var _a, _b;
|
|
400
|
+
try {
|
|
401
|
+
const toolCalls = this.getToolCalls(llmResponse);
|
|
402
|
+
if (!toolCalls || !((_a = nextMessage === null || nextMessage === void 0 ? void 0 : nextMessage.message) === null || _a === void 0 ? void 0 : _a.tools))
|
|
403
|
+
return;
|
|
404
|
+
for (const toolCall of toolCalls) {
|
|
405
|
+
if (!toolCall)
|
|
406
|
+
continue;
|
|
407
|
+
const toolName = ((_b = toolCall.function) === null || _b === void 0 ? void 0 : _b.name) || '';
|
|
408
|
+
const isToolSearch = toolName === 'tool_search' ||
|
|
409
|
+
toolName === 'codebolt--tool_search' ||
|
|
410
|
+
toolName.endsWith('--tool_search');
|
|
411
|
+
if (!isToolSearch)
|
|
412
|
+
continue;
|
|
413
|
+
const toolCallId = toolCall.id;
|
|
414
|
+
const toolResult = toolResults.find(r => r.tool_call_id === toolCallId);
|
|
415
|
+
if (!(toolResult === null || toolResult === void 0 ? void 0 : toolResult.content))
|
|
416
|
+
continue;
|
|
417
|
+
const content = typeof toolResult.content === 'string'
|
|
418
|
+
? toolResult.content
|
|
419
|
+
: JSON.stringify(toolResult.content);
|
|
420
|
+
const jsonMatch = content.match(/\[[\s\S]*\]/);
|
|
421
|
+
if (!jsonMatch)
|
|
422
|
+
continue;
|
|
423
|
+
let discoveredSchemas;
|
|
424
|
+
try {
|
|
425
|
+
discoveredSchemas = JSON.parse(jsonMatch[0]);
|
|
426
|
+
}
|
|
427
|
+
catch {
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
if (!Array.isArray(discoveredSchemas))
|
|
431
|
+
continue;
|
|
432
|
+
const existingToolNames = new Set(nextMessage.message.tools.map((tool) => { var _a; return (_a = tool.function) === null || _a === void 0 ? void 0 : _a.name; }));
|
|
433
|
+
for (const schema of discoveredSchemas) {
|
|
434
|
+
const schemaFunction = schema['function'];
|
|
435
|
+
const rawName = schemaFunction === null || schemaFunction === void 0 ? void 0 : schemaFunction.name;
|
|
436
|
+
if (!rawName)
|
|
437
|
+
continue;
|
|
438
|
+
const prefixedName = rawName.startsWith('codebolt--') ? rawName : `codebolt--${rawName}`;
|
|
439
|
+
if (existingToolNames.has(prefixedName))
|
|
440
|
+
continue;
|
|
441
|
+
const prefixedSchema = {
|
|
442
|
+
...schema,
|
|
443
|
+
function: {
|
|
444
|
+
...schemaFunction,
|
|
445
|
+
name: prefixedName
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
nextMessage.message.tools.push(prefixedSchema);
|
|
449
|
+
existingToolNames.add(prefixedName);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
catch (error) {
|
|
454
|
+
console.error('[ResponseExecutor] Error injecting discovered tools:', error);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
364
457
|
}
|
|
365
458
|
exports.ResponseExecutor = ResponseExecutor;
|