@codebolt/agent 5.0.6 → 5.0.8
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/processor-pieces/base/basePreToolCallProcessor.js +5 -2
- package/dist/processor-pieces/messageModifiers/argumentProcessorModifier.d.ts +1 -1
- package/dist/processor-pieces/messageModifiers/argumentProcessorModifier.js +2 -2
- package/dist/processor-pieces/messageModifiers/atFileProcessorModifier.js +24 -34
- package/dist/processor-pieces/messageModifiers/chatRecordingModifier.d.ts +1 -1
- package/dist/processor-pieces/messageModifiers/chatRecordingModifier.js +2 -2
- package/dist/processor-pieces/messageModifiers/coreSystemPromptModifier.d.ts +1 -1
- package/dist/processor-pieces/messageModifiers/coreSystemPromptModifier.js +2 -2
- package/dist/processor-pieces/messageModifiers/directoryContextModifier.d.ts +1 -1
- package/dist/processor-pieces/messageModifiers/directoryContextModifier.js +8 -3
- package/dist/processor-pieces/messageModifiers/environmentContextModifier.d.ts +1 -1
- package/dist/processor-pieces/messageModifiers/environmentContextModifier.js +1 -1
- package/dist/processor-pieces/messageModifiers/ideContextModifier.js +114 -17
- package/dist/processor-pieces/messageModifiers/memoryImportModifier.d.ts +1 -1
- package/dist/processor-pieces/messageModifiers/memoryImportModifier.js +13 -5
- package/dist/processor-pieces/messageModifiers/toolInjectionModifier.d.ts +5 -0
- package/dist/processor-pieces/messageModifiers/toolInjectionModifier.js +4 -0
- package/dist/processor-pieces/postInferenceProcessors/loopDetectionModifier.js +24 -8
- package/dist/processor-pieces/postToolCallProcessors/conversationCompactorModifier.d.ts +202 -5
- package/dist/processor-pieces/postToolCallProcessors/conversationCompactorModifier.js +826 -19
- package/dist/processor-pieces/postToolCallProcessors/index.d.ts +1 -1
- package/dist/processor-pieces/postToolCallProcessors/index.js +2 -1
- package/dist/processor-pieces/postToolCallProcessors/shellProcessorModifier.js +7 -4
- package/dist/processor-pieces/preInferenceProcessors/chatCompressionModifier.d.ts +1 -1
- package/dist/processor-pieces/preInferenceProcessors/chatCompressionModifier.js +12 -16
- package/dist/processor-pieces/pretoolCallProcessors/toolParameterModifier.d.ts +2 -3
- package/dist/processor-pieces/pretoolCallProcessors/toolParameterModifier.js +1 -2
- package/dist/processor-pieces/utils/messageModifierHelper.js +5 -2
- package/dist/types/InternalTypes.d.ts +8 -6
- package/dist/types/libFunctionTypes.d.ts +13 -19
- package/dist/types/libFunctionTypes.js +3 -0
- package/dist/types/processorTypes.d.ts +8 -8
- package/dist/types/processorTypes.js +6 -23
- package/dist/unified/agent/agent.js +1 -2
- package/dist/unified/agent/codeboltAgent.d.ts +23 -2
- package/dist/unified/agent/codeboltAgent.js +55 -12
- package/dist/unified/agent/tools.d.ts +7 -11
- package/dist/unified/agent/tools.js +12 -3
- package/dist/unified/agent/workflow.js +38 -20
- package/dist/unified/agent/workflowSteps.d.ts +1 -1
- package/dist/unified/agent/workflowSteps.js +58 -23
- package/dist/unified/base/agentStep.js +20 -1
- package/dist/unified/base/initialPromptGenerator.js +3 -1
- package/dist/unified/base/responseExecutor.d.ts +3 -0
- package/dist/unified/base/responseExecutor.js +41 -10
- package/dist/unified/index.d.ts +1 -0
- package/dist/unified/index.js +4 -1
- package/dist/unified/services/LoopDetectionService.d.ts +44 -0
- package/dist/unified/services/LoopDetectionService.js +79 -0
- package/dist/unified/utils/utils.d.ts +20 -1
- package/dist/unified/utils/utils.js +8 -4
- package/package.json +11 -6
|
@@ -28,26 +28,30 @@ class Workflow {
|
|
|
28
28
|
if (this.config.outputSchema && success) {
|
|
29
29
|
this.config.outputSchema.parse(this.context);
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
const result = {
|
|
32
32
|
executionId: this.executionId,
|
|
33
33
|
success,
|
|
34
34
|
data: this.context,
|
|
35
35
|
stepResults,
|
|
36
|
-
executionTime
|
|
37
|
-
error: success ? undefined : 'One or more steps failed'
|
|
36
|
+
executionTime
|
|
38
37
|
};
|
|
38
|
+
if (!success) {
|
|
39
|
+
result.error = 'One or more steps failed';
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
39
42
|
}
|
|
40
43
|
catch (error) {
|
|
41
44
|
const executionTime = Date.now() - this.startTime;
|
|
42
45
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
43
|
-
|
|
46
|
+
const result = {
|
|
44
47
|
executionId: this.executionId,
|
|
45
48
|
success: false,
|
|
46
49
|
data: this.context,
|
|
47
50
|
stepResults: this.stepResults,
|
|
48
|
-
executionTime
|
|
49
|
-
error: errorMessage
|
|
51
|
+
executionTime
|
|
50
52
|
};
|
|
53
|
+
result.error = errorMessage;
|
|
54
|
+
return result;
|
|
51
55
|
}
|
|
52
56
|
}
|
|
53
57
|
executeStep() {
|
|
@@ -55,6 +59,9 @@ class Workflow {
|
|
|
55
59
|
throw new Error('No more steps to execute');
|
|
56
60
|
}
|
|
57
61
|
const step = this.config.steps[this.currentStepIndex];
|
|
62
|
+
if (!step) {
|
|
63
|
+
throw new Error('Step not found at current index');
|
|
64
|
+
}
|
|
58
65
|
try {
|
|
59
66
|
// Note: Since BaseWorkflow expects sync methods, we can't properly handle async step execution
|
|
60
67
|
// This is a design limitation that would need to be addressed in the BaseWorkflow interface
|
|
@@ -74,9 +81,9 @@ class Workflow {
|
|
|
74
81
|
const errorResult = {
|
|
75
82
|
stepId: step.id,
|
|
76
83
|
success: false,
|
|
77
|
-
result: null
|
|
78
|
-
error: errorMessage
|
|
84
|
+
result: null
|
|
79
85
|
};
|
|
86
|
+
errorResult.error = errorMessage;
|
|
80
87
|
this.stepResults.push(errorResult);
|
|
81
88
|
return errorResult;
|
|
82
89
|
}
|
|
@@ -85,6 +92,8 @@ class Workflow {
|
|
|
85
92
|
const allResults = [];
|
|
86
93
|
for (let i = 0; i < this.config.steps.length; i++) {
|
|
87
94
|
const step = this.config.steps[i];
|
|
95
|
+
if (!step)
|
|
96
|
+
continue;
|
|
88
97
|
try {
|
|
89
98
|
// Note: This is a synchronous implementation due to BaseWorkflow interface constraints
|
|
90
99
|
// In a real async implementation, you would await step.execute(this.context)
|
|
@@ -108,9 +117,9 @@ class Workflow {
|
|
|
108
117
|
const errorResult = {
|
|
109
118
|
stepId: step.id,
|
|
110
119
|
success: false,
|
|
111
|
-
result: null
|
|
112
|
-
error: errorMessage
|
|
120
|
+
result: null
|
|
113
121
|
};
|
|
122
|
+
errorResult.error = errorMessage;
|
|
114
123
|
allResults.push(errorResult);
|
|
115
124
|
// Break on error (can be made configurable)
|
|
116
125
|
break;
|
|
@@ -166,26 +175,30 @@ class Workflow {
|
|
|
166
175
|
if (this.config.outputSchema && success) {
|
|
167
176
|
this.config.outputSchema.parse(this.context);
|
|
168
177
|
}
|
|
169
|
-
|
|
178
|
+
const result = {
|
|
170
179
|
executionId: this.executionId,
|
|
171
180
|
success,
|
|
172
181
|
data: this.context,
|
|
173
182
|
stepResults,
|
|
174
|
-
executionTime
|
|
175
|
-
error: success ? undefined : 'One or more steps failed'
|
|
183
|
+
executionTime
|
|
176
184
|
};
|
|
185
|
+
if (!success) {
|
|
186
|
+
result.error = 'One or more steps failed';
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
177
189
|
}
|
|
178
190
|
catch (error) {
|
|
179
191
|
const executionTime = Date.now() - this.startTime;
|
|
180
192
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
181
|
-
|
|
193
|
+
const result = {
|
|
182
194
|
executionId: this.executionId,
|
|
183
195
|
success: false,
|
|
184
196
|
data: this.context,
|
|
185
197
|
stepResults: this.stepResults,
|
|
186
|
-
executionTime
|
|
187
|
-
error: errorMessage
|
|
198
|
+
executionTime
|
|
188
199
|
};
|
|
200
|
+
result.error = errorMessage;
|
|
201
|
+
return result;
|
|
189
202
|
}
|
|
190
203
|
}
|
|
191
204
|
async executeStepAsync() {
|
|
@@ -193,6 +206,9 @@ class Workflow {
|
|
|
193
206
|
throw new Error('No more steps to execute');
|
|
194
207
|
}
|
|
195
208
|
const step = this.config.steps[this.currentStepIndex];
|
|
209
|
+
if (!step) {
|
|
210
|
+
throw new Error('Step not found at current index');
|
|
211
|
+
}
|
|
196
212
|
try {
|
|
197
213
|
const result = await step.execute(this.context);
|
|
198
214
|
// Handle different return types based on step type
|
|
@@ -216,9 +232,9 @@ class Workflow {
|
|
|
216
232
|
const errorResult = {
|
|
217
233
|
stepId: step.id,
|
|
218
234
|
success: false,
|
|
219
|
-
result: null
|
|
220
|
-
error: errorMessage
|
|
235
|
+
result: null
|
|
221
236
|
};
|
|
237
|
+
errorResult.error = errorMessage;
|
|
222
238
|
this.stepResults.push(errorResult);
|
|
223
239
|
return errorResult;
|
|
224
240
|
}
|
|
@@ -227,6 +243,8 @@ class Workflow {
|
|
|
227
243
|
const allResults = [];
|
|
228
244
|
for (let i = 0; i < this.config.steps.length; i++) {
|
|
229
245
|
const step = this.config.steps[i];
|
|
246
|
+
if (!step)
|
|
247
|
+
continue;
|
|
230
248
|
try {
|
|
231
249
|
const result = await step.execute(this.context);
|
|
232
250
|
// Handle different return types based on step type
|
|
@@ -260,9 +278,9 @@ class Workflow {
|
|
|
260
278
|
const errorResult = {
|
|
261
279
|
stepId: step.id,
|
|
262
280
|
success: false,
|
|
263
|
-
result: null
|
|
264
|
-
error: errorMessage
|
|
281
|
+
result: null
|
|
265
282
|
};
|
|
283
|
+
errorResult.error = errorMessage;
|
|
266
284
|
allResults.push(errorResult);
|
|
267
285
|
// Break on error (can be made configurable)
|
|
268
286
|
break;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AgentInterface, BaseWorkFlowStep, StepConfig, StepType, ToolInterface, workflowContext, workflowStepOutput } from "@codebolt/types/agent";
|
|
2
|
-
import { ZodType } from "zod";
|
|
2
|
+
import type { ZodType } from "zod";
|
|
3
3
|
export declare class ParallelStep implements BaseWorkFlowStep {
|
|
4
4
|
id: string;
|
|
5
5
|
description: string;
|
|
@@ -7,8 +7,12 @@ class ParallelStep {
|
|
|
7
7
|
this.id = config.id;
|
|
8
8
|
this.description = config.description;
|
|
9
9
|
this.type = config.type;
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
if (config.inputSchema !== undefined) {
|
|
11
|
+
this.inputSchema = config.inputSchema;
|
|
12
|
+
}
|
|
13
|
+
if (config.outputSchema !== undefined) {
|
|
14
|
+
this.outputSchema = config.outputSchema;
|
|
15
|
+
}
|
|
12
16
|
}
|
|
13
17
|
async execute(context) {
|
|
14
18
|
try {
|
|
@@ -41,8 +45,12 @@ class ConditionStep {
|
|
|
41
45
|
this.id = config.id;
|
|
42
46
|
this.description = config.description;
|
|
43
47
|
this.type = config.type;
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
if (config.inputSchema !== undefined) {
|
|
49
|
+
this.inputSchema = config.inputSchema;
|
|
50
|
+
}
|
|
51
|
+
if (config.outputSchema !== undefined) {
|
|
52
|
+
this.outputSchema = config.outputSchema;
|
|
53
|
+
}
|
|
46
54
|
}
|
|
47
55
|
async execute(context) {
|
|
48
56
|
try {
|
|
@@ -51,6 +59,8 @@ class ConditionStep {
|
|
|
51
59
|
const results = [];
|
|
52
60
|
for (let i = 0; i < this.steps.length; i++) {
|
|
53
61
|
const step = this.steps[i];
|
|
62
|
+
if (!step)
|
|
63
|
+
continue;
|
|
54
64
|
try {
|
|
55
65
|
const result = await step.execute(context);
|
|
56
66
|
results.push(result);
|
|
@@ -91,8 +101,12 @@ class LoopStep {
|
|
|
91
101
|
this.id = config.id;
|
|
92
102
|
this.description = config.description;
|
|
93
103
|
this.type = config.type;
|
|
94
|
-
|
|
95
|
-
|
|
104
|
+
if (config.inputSchema !== undefined) {
|
|
105
|
+
this.inputSchema = config.inputSchema;
|
|
106
|
+
}
|
|
107
|
+
if (config.outputSchema !== undefined) {
|
|
108
|
+
this.outputSchema = config.outputSchema;
|
|
109
|
+
}
|
|
96
110
|
this.maxIterations = maxIterations;
|
|
97
111
|
}
|
|
98
112
|
async execute(context) {
|
|
@@ -105,6 +119,8 @@ class LoopStep {
|
|
|
105
119
|
// Execute all steps in this iteration
|
|
106
120
|
for (let i = 0; i < this.steps.length; i++) {
|
|
107
121
|
const step = this.steps[i];
|
|
122
|
+
if (!step)
|
|
123
|
+
continue;
|
|
108
124
|
try {
|
|
109
125
|
const result = await step.execute(context);
|
|
110
126
|
result.stepId = `${result.stepId}_loop_${iteration}`;
|
|
@@ -153,8 +169,12 @@ class WorkFlowStep {
|
|
|
153
169
|
this.id = config.id;
|
|
154
170
|
this.description = config.description;
|
|
155
171
|
this.type = config.type;
|
|
156
|
-
|
|
157
|
-
|
|
172
|
+
if (config.inputSchema !== undefined) {
|
|
173
|
+
this.inputSchema = config.inputSchema;
|
|
174
|
+
}
|
|
175
|
+
if (config.outputSchema !== undefined) {
|
|
176
|
+
this.outputSchema = config.outputSchema;
|
|
177
|
+
}
|
|
158
178
|
}
|
|
159
179
|
async execute(context) {
|
|
160
180
|
try {
|
|
@@ -184,17 +204,24 @@ class AgentStep {
|
|
|
184
204
|
this.id = config.id;
|
|
185
205
|
this.description = config.description;
|
|
186
206
|
this.type = config.type;
|
|
187
|
-
|
|
188
|
-
|
|
207
|
+
if (config.inputSchema !== undefined) {
|
|
208
|
+
this.inputSchema = config.inputSchema;
|
|
209
|
+
}
|
|
210
|
+
if (config.outputSchema !== undefined) {
|
|
211
|
+
this.outputSchema = config.outputSchema;
|
|
212
|
+
}
|
|
189
213
|
}
|
|
190
214
|
async execute(context) {
|
|
191
|
-
|
|
192
|
-
|
|
215
|
+
const { result, success, error } = await this.agent.execute(context);
|
|
216
|
+
const output = {
|
|
193
217
|
stepId: this.id,
|
|
194
218
|
success: success,
|
|
195
|
-
result: result
|
|
196
|
-
error: error
|
|
219
|
+
result: result
|
|
197
220
|
};
|
|
221
|
+
if (error !== undefined) {
|
|
222
|
+
output.error = error;
|
|
223
|
+
}
|
|
224
|
+
return output;
|
|
198
225
|
}
|
|
199
226
|
}
|
|
200
227
|
exports.AgentStep = AgentStep;
|
|
@@ -203,28 +230,36 @@ class ToolStep {
|
|
|
203
230
|
this.id = config.id;
|
|
204
231
|
this.description = config.description;
|
|
205
232
|
this.type = config.type;
|
|
206
|
-
|
|
207
|
-
|
|
233
|
+
if (config.inputSchema !== undefined) {
|
|
234
|
+
this.inputSchema = config.inputSchema;
|
|
235
|
+
}
|
|
236
|
+
if (config.outputSchema !== undefined) {
|
|
237
|
+
this.outputSchema = config.outputSchema;
|
|
238
|
+
}
|
|
208
239
|
this.tool = tool;
|
|
209
240
|
}
|
|
210
241
|
async execute(context) {
|
|
211
242
|
try {
|
|
212
|
-
|
|
213
|
-
|
|
243
|
+
const { result, success, error } = await this.tool.execute({}, context);
|
|
244
|
+
const output = {
|
|
214
245
|
stepId: this.id,
|
|
215
246
|
success: success,
|
|
216
|
-
result: result
|
|
217
|
-
error: error
|
|
247
|
+
result: result
|
|
218
248
|
};
|
|
249
|
+
if (error !== undefined) {
|
|
250
|
+
output.error = error;
|
|
251
|
+
}
|
|
252
|
+
return output;
|
|
219
253
|
}
|
|
220
254
|
catch (error) {
|
|
221
255
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
222
|
-
|
|
256
|
+
const output = {
|
|
223
257
|
stepId: this.id,
|
|
224
258
|
success: false,
|
|
225
|
-
result: null
|
|
226
|
-
error: errorMessage
|
|
259
|
+
result: null
|
|
227
260
|
};
|
|
261
|
+
output.error = errorMessage;
|
|
262
|
+
return output;
|
|
228
263
|
}
|
|
229
264
|
}
|
|
230
265
|
}
|
|
@@ -63,8 +63,27 @@ class AgentStep {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
async generateResponse(messageForLLM) {
|
|
66
|
+
var _a, _b;
|
|
66
67
|
const response = await codeboltjs_1.default.llm.inference(messageForLLM);
|
|
67
|
-
|
|
68
|
+
const completion = response.completion;
|
|
69
|
+
// Add tokenLimit and maxOutputTokens to completion object if available in response
|
|
70
|
+
if (completion) {
|
|
71
|
+
// Check if tokenLimit exists at response level or in completion
|
|
72
|
+
if (response.tokenLimit !== undefined) {
|
|
73
|
+
completion.tokenLimit = response.tokenLimit;
|
|
74
|
+
}
|
|
75
|
+
if (response.maxOutputTokens !== undefined) {
|
|
76
|
+
completion.maxOutputTokens = response.maxOutputTokens;
|
|
77
|
+
}
|
|
78
|
+
// Also check inside completion object itself (from LLM provider response)
|
|
79
|
+
if (((_a = completion.completion) === null || _a === void 0 ? void 0 : _a.tokenLimit) !== undefined) {
|
|
80
|
+
completion.tokenLimit = completion.completion.tokenLimit;
|
|
81
|
+
}
|
|
82
|
+
if (((_b = completion.completion) === null || _b === void 0 ? void 0 : _b.maxOutputTokens) !== undefined) {
|
|
83
|
+
completion.maxOutputTokens = completion.completion.maxOutputTokens;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return completion;
|
|
68
87
|
}
|
|
69
88
|
/**
|
|
70
89
|
* Update LLM configuration
|
|
@@ -17,7 +17,9 @@ class InitialPromptGenerator {
|
|
|
17
17
|
this.processors = options.processors || [];
|
|
18
18
|
this.metaData = options.metaData || {};
|
|
19
19
|
this.enableLogging = options.enableLogging !== false;
|
|
20
|
-
|
|
20
|
+
if (options.baseSystemPrompt !== undefined) {
|
|
21
|
+
this.baseSystemPrompt = options.baseSystemPrompt;
|
|
22
|
+
}
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
23
25
|
* Process and modify input messages using the message modifier pattern
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AgentResponseExecutor, PostToolCallProcessor, PreToolCallProcessor, ResponseInput, ResponseOutput } from '@codebolt/types/agent';
|
|
2
|
+
import { LoopDetectionService } from '../services/LoopDetectionService';
|
|
2
3
|
export declare class ResponseExecutor implements AgentResponseExecutor {
|
|
3
4
|
private preToolCallProcessors;
|
|
4
5
|
private postToolCallProcessors;
|
|
@@ -7,7 +8,9 @@ export declare class ResponseExecutor implements AgentResponseExecutor {
|
|
|
7
8
|
constructor(options: {
|
|
8
9
|
preToolCallProcessors: PreToolCallProcessor[];
|
|
9
10
|
postToolCallProcessors: PostToolCallProcessor[];
|
|
11
|
+
loopDetectionService?: LoopDetectionService;
|
|
10
12
|
});
|
|
13
|
+
private loopDetectionService?;
|
|
11
14
|
executeResponse(input: ResponseInput): Promise<ResponseOutput>;
|
|
12
15
|
/**
|
|
13
16
|
* Extract tool details from tool call
|
|
@@ -13,8 +13,12 @@ class ResponseExecutor {
|
|
|
13
13
|
this.finalMessage = undefined;
|
|
14
14
|
this.preToolCallProcessors = options.preToolCallProcessors;
|
|
15
15
|
this.postToolCallProcessors = options.postToolCallProcessors;
|
|
16
|
+
if (options.loopDetectionService) {
|
|
17
|
+
this.loopDetectionService = options.loopDetectionService;
|
|
18
|
+
}
|
|
16
19
|
}
|
|
17
20
|
async executeResponse(input) {
|
|
21
|
+
var _a, _b;
|
|
18
22
|
let nextMessage = input.nextMessage;
|
|
19
23
|
for (const preToolCallProcessor of this.preToolCallProcessors) {
|
|
20
24
|
try {
|
|
@@ -59,13 +63,17 @@ class ResponseExecutor {
|
|
|
59
63
|
}
|
|
60
64
|
for (const postToolCallProcessor of this.postToolCallProcessors) {
|
|
61
65
|
try {
|
|
62
|
-
//
|
|
66
|
+
// Pass current nextMessage (with tool results) to the processor
|
|
63
67
|
let { nextPrompt, shouldExit } = await postToolCallProcessor.modify({
|
|
64
68
|
llmMessageSent: input.actualMessageSentToLLM,
|
|
65
69
|
rawLLMResponseMessage: input.rawLLMOutput,
|
|
66
|
-
nextPrompt:
|
|
67
|
-
toolResults:
|
|
70
|
+
nextPrompt: nextMessage,
|
|
71
|
+
toolResults: toolResults,
|
|
72
|
+
tokenLimit: (_a = input.rawLLMOutput) === null || _a === void 0 ? void 0 : _a.tokenLimit,
|
|
73
|
+
maxOutputTokens: (_b = input.rawLLMOutput) === null || _b === void 0 ? void 0 : _b.maxOutputTokens
|
|
68
74
|
});
|
|
75
|
+
// Update nextMessage with the (potentially compressed) result
|
|
76
|
+
nextMessage = nextPrompt;
|
|
69
77
|
if (shouldExit) {
|
|
70
78
|
this.completed = true;
|
|
71
79
|
Promise.resolve({
|
|
@@ -75,16 +83,19 @@ class ResponseExecutor {
|
|
|
75
83
|
}
|
|
76
84
|
}
|
|
77
85
|
catch (error) {
|
|
78
|
-
console.error(`[
|
|
79
|
-
// Continue with other
|
|
86
|
+
console.error(`[ResponseExecutor] Error in post tool call processor:`, error);
|
|
87
|
+
// Continue with other processors
|
|
80
88
|
}
|
|
81
89
|
}
|
|
82
|
-
|
|
90
|
+
const output = {
|
|
83
91
|
completed: this.completed,
|
|
84
92
|
nextMessage: nextMessage,
|
|
85
|
-
toolResults: toolResults
|
|
86
|
-
finalMessage: this.finalMessage
|
|
93
|
+
toolResults: toolResults
|
|
87
94
|
};
|
|
95
|
+
if (this.finalMessage !== undefined) {
|
|
96
|
+
output.finalMessage = this.finalMessage;
|
|
97
|
+
}
|
|
98
|
+
return output;
|
|
88
99
|
}
|
|
89
100
|
/**
|
|
90
101
|
* Extract tool details from tool call
|
|
@@ -142,6 +153,22 @@ class ResponseExecutor {
|
|
|
142
153
|
});
|
|
143
154
|
}
|
|
144
155
|
}
|
|
156
|
+
// Check for loops before execution
|
|
157
|
+
if (this.loopDetectionService) {
|
|
158
|
+
const toolCallsToCheck = toolsToExecute.map(t => ({ name: t.toolName, args: t.toolInput }));
|
|
159
|
+
for (const toolCall of toolCallsToCheck) {
|
|
160
|
+
const loopDetected = this.loopDetectionService.checkToolCallLoop(toolCall.name, toolCall.args);
|
|
161
|
+
if (loopDetected) {
|
|
162
|
+
this.completed = true;
|
|
163
|
+
this.finalMessage = `Loop Detected: The agent is stuck in a loop of identical tool calls (${toolCall.name}). Execution stopped to prevent infinite recurrence.`;
|
|
164
|
+
return [{
|
|
165
|
+
role: 'tool',
|
|
166
|
+
tool_call_id: 'system-loop-detection', // Virtual ID
|
|
167
|
+
content: JSON.stringify({ error: this.finalMessage })
|
|
168
|
+
}];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
145
172
|
// Second pass: Execute tools sequentially (one by one)
|
|
146
173
|
for (const item of toolsToExecute) {
|
|
147
174
|
try {
|
|
@@ -149,7 +176,7 @@ class ResponseExecutor {
|
|
|
149
176
|
let [serverName] = item.toolName.replace('--', ':').split(':');
|
|
150
177
|
// codebolt.chat.sendMessage(`tool call ${serverName} ${item.toolName} ${item.toolInput}`, {});
|
|
151
178
|
if (serverName == 'subagent') {
|
|
152
|
-
|
|
179
|
+
await codeboltjs_1.default.agent.startAgent(item.toolName.replace("subagent--", ''), item.toolInput.task);
|
|
153
180
|
const [didUserReject, result] = [false, "tool result is successful"];
|
|
154
181
|
let toolResult = this.parseToolResult(item.toolUseId, result);
|
|
155
182
|
// Handle side effects (fallback messages)
|
|
@@ -174,6 +201,7 @@ class ResponseExecutor {
|
|
|
174
201
|
description: item.toolInput.description || item.toolInput.task || '',
|
|
175
202
|
userMessage: item.toolInput.task || item.toolInput.userMessage || '',
|
|
176
203
|
selectedAgent: item.toolInput.selectedAgent,
|
|
204
|
+
isGrouped: item.toolInput.isGrouped,
|
|
177
205
|
groupId: item.toolInput.groupId,
|
|
178
206
|
});
|
|
179
207
|
toolResults.push({
|
|
@@ -273,9 +301,12 @@ class ResponseExecutor {
|
|
|
273
301
|
* @returns Promise with tuple [userRejected, result]
|
|
274
302
|
*/
|
|
275
303
|
async executeTool(toolName, toolInput) {
|
|
304
|
+
var _a, _b;
|
|
276
305
|
//codebolttools--readfile
|
|
277
306
|
// console.log("Executing tool: ", toolName, toolInput);
|
|
278
|
-
const
|
|
307
|
+
const parts = toolName.split('--');
|
|
308
|
+
const toolboxName = (_a = parts[0]) !== null && _a !== void 0 ? _a : '';
|
|
309
|
+
const actualToolName = (_b = parts[1]) !== null && _b !== void 0 ? _b : '';
|
|
279
310
|
// console.log("Toolbox name: ", toolboxName, "Actual tool name: ", actualToolName);
|
|
280
311
|
const { data } = await codeboltjs_1.default.mcp.executeTool(toolboxName, actualToolName, toolInput);
|
|
281
312
|
// console.log("Tool result: ", data);
|
package/dist/unified/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export { createDefaultMessageProcessor } from './base/create/createInitialPrompt
|
|
|
14
14
|
export { InitialPromptGenerator } from './base/initialPromptGenerator';
|
|
15
15
|
export { AgentStep } from './base/agentStep';
|
|
16
16
|
export { ResponseExecutor } from './base/responseExecutor';
|
|
17
|
+
export { LoopDetectionService, LoopType } from './services/LoopDetectionService';
|
|
17
18
|
export { Agent } from './agent/agent';
|
|
18
19
|
export { CodeboltAgent, createCodeboltAgent, type CodeboltAgentConfig } from './agent/codeboltAgent';
|
|
19
20
|
export { Tool, createTool } from './agent/tools';
|
package/dist/unified/index.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* The framework is designed to be modular, extensible, and easy to use.
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.Workflow = exports.createTool = exports.Tool = exports.createCodeboltAgent = exports.CodeboltAgent = exports.Agent = exports.ResponseExecutor = exports.AgentStep = exports.InitialPromptGenerator = exports.createDefaultMessageProcessor = exports.UnifiedToolExecutionError = exports.UnifiedResponseExecutionError = exports.UnifiedStepExecutionError = exports.UnifiedMessageProcessingError = exports.UnifiedAgentError = void 0;
|
|
13
|
+
exports.Workflow = exports.createTool = exports.Tool = exports.createCodeboltAgent = exports.CodeboltAgent = exports.Agent = exports.LoopType = exports.LoopDetectionService = exports.ResponseExecutor = exports.AgentStep = exports.InitialPromptGenerator = exports.createDefaultMessageProcessor = exports.UnifiedToolExecutionError = exports.UnifiedResponseExecutionError = exports.UnifiedStepExecutionError = exports.UnifiedMessageProcessingError = exports.UnifiedAgentError = void 0;
|
|
14
14
|
// Error types
|
|
15
15
|
var types_1 = require("./types/types");
|
|
16
16
|
Object.defineProperty(exports, "UnifiedAgentError", { enumerable: true, get: function () { return types_1.UnifiedAgentError; } });
|
|
@@ -27,6 +27,9 @@ var agentStep_1 = require("./base/agentStep");
|
|
|
27
27
|
Object.defineProperty(exports, "AgentStep", { enumerable: true, get: function () { return agentStep_1.AgentStep; } });
|
|
28
28
|
var responseExecutor_1 = require("./base/responseExecutor");
|
|
29
29
|
Object.defineProperty(exports, "ResponseExecutor", { enumerable: true, get: function () { return responseExecutor_1.ResponseExecutor; } });
|
|
30
|
+
var LoopDetectionService_1 = require("./services/LoopDetectionService");
|
|
31
|
+
Object.defineProperty(exports, "LoopDetectionService", { enumerable: true, get: function () { return LoopDetectionService_1.LoopDetectionService; } });
|
|
32
|
+
Object.defineProperty(exports, "LoopType", { enumerable: true, get: function () { return LoopDetectionService_1.LoopType; } });
|
|
30
33
|
// Agent framework components
|
|
31
34
|
var agent_1 = require("./agent/agent");
|
|
32
35
|
Object.defineProperty(exports, "Agent", { enumerable: true, get: function () { return agent_1.Agent; } });
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare enum LoopType {
|
|
2
|
+
CONSECUTIVE_IDENTICAL_TOOL_CALLS = "CONSECUTIVE_IDENTICAL_TOOL_CALLS",
|
|
3
|
+
CHANTING_IDENTICAL_SENTENCES = "CHANTING_IDENTICAL_SENTENCES"
|
|
4
|
+
}
|
|
5
|
+
export interface LoopDetectedEvent {
|
|
6
|
+
type: LoopType;
|
|
7
|
+
threshold: number;
|
|
8
|
+
count: number;
|
|
9
|
+
}
|
|
10
|
+
export interface LoopDetectionOptions {
|
|
11
|
+
toolCallLoopThreshold?: number;
|
|
12
|
+
contentLoopThreshold?: number;
|
|
13
|
+
debug?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Service for detecting and preventing infinite loops in AI responses.
|
|
17
|
+
* Monitors tool call repetitions and content sentence repetitions.
|
|
18
|
+
*
|
|
19
|
+
* Ported from gemini-cli/packages/core/src/services/loopDetectionService.ts
|
|
20
|
+
*/
|
|
21
|
+
export declare class LoopDetectionService {
|
|
22
|
+
private readonly toolCallLoopThreshold;
|
|
23
|
+
private readonly debug;
|
|
24
|
+
private lastToolCallKey;
|
|
25
|
+
private toolCallRepetitionCount;
|
|
26
|
+
private loopDetected;
|
|
27
|
+
constructor(options?: LoopDetectionOptions);
|
|
28
|
+
/**
|
|
29
|
+
* Resets the loop detection state. Call this when a "fresh" start is needed
|
|
30
|
+
* or a user explicitly interrupts.
|
|
31
|
+
*/
|
|
32
|
+
reset(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Generates a unique hash for a tool call based on name and arguments.
|
|
35
|
+
*/
|
|
36
|
+
private getToolCallKey;
|
|
37
|
+
/**
|
|
38
|
+
* Checks if the given tool call constitutes a loop.
|
|
39
|
+
* @param toolName Name of the tool
|
|
40
|
+
* @param toolArgs Arguments passed to the tool
|
|
41
|
+
* @returns LoopDetectedEvent if a loop is detected, null otherwise
|
|
42
|
+
*/
|
|
43
|
+
checkToolCallLoop(toolName: string, toolArgs: any): LoopDetectedEvent | null;
|
|
44
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LoopDetectionService = exports.LoopType = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
var LoopType;
|
|
6
|
+
(function (LoopType) {
|
|
7
|
+
LoopType["CONSECUTIVE_IDENTICAL_TOOL_CALLS"] = "CONSECUTIVE_IDENTICAL_TOOL_CALLS";
|
|
8
|
+
LoopType["CHANTING_IDENTICAL_SENTENCES"] = "CHANTING_IDENTICAL_SENTENCES";
|
|
9
|
+
})(LoopType || (exports.LoopType = LoopType = {}));
|
|
10
|
+
/**
|
|
11
|
+
* Service for detecting and preventing infinite loops in AI responses.
|
|
12
|
+
* Monitors tool call repetitions and content sentence repetitions.
|
|
13
|
+
*
|
|
14
|
+
* Ported from gemini-cli/packages/core/src/services/loopDetectionService.ts
|
|
15
|
+
*/
|
|
16
|
+
class LoopDetectionService {
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
// State
|
|
19
|
+
this.lastToolCallKey = null;
|
|
20
|
+
this.toolCallRepetitionCount = 0;
|
|
21
|
+
this.loopDetected = false;
|
|
22
|
+
this.toolCallLoopThreshold = options.toolCallLoopThreshold || 5;
|
|
23
|
+
this.debug = options.debug || false;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resets the loop detection state. Call this when a "fresh" start is needed
|
|
27
|
+
* or a user explicitly interrupts.
|
|
28
|
+
*/
|
|
29
|
+
reset() {
|
|
30
|
+
this.lastToolCallKey = null;
|
|
31
|
+
this.toolCallRepetitionCount = 0;
|
|
32
|
+
this.loopDetected = false;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Generates a unique hash for a tool call based on name and arguments.
|
|
36
|
+
*/
|
|
37
|
+
getToolCallKey(toolName, toolArgs) {
|
|
38
|
+
const argsString = typeof toolArgs === 'string' ? toolArgs : JSON.stringify(toolArgs);
|
|
39
|
+
const keyString = `${toolName}:${argsString}`;
|
|
40
|
+
return (0, node_crypto_1.createHash)('sha256').update(keyString).digest('hex');
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Checks if the given tool call constitutes a loop.
|
|
44
|
+
* @param toolName Name of the tool
|
|
45
|
+
* @param toolArgs Arguments passed to the tool
|
|
46
|
+
* @returns LoopDetectedEvent if a loop is detected, null otherwise
|
|
47
|
+
*/
|
|
48
|
+
checkToolCallLoop(toolName, toolArgs) {
|
|
49
|
+
if (this.loopDetected) {
|
|
50
|
+
// Already caught a loop, stick to it until reset
|
|
51
|
+
return {
|
|
52
|
+
type: LoopType.CONSECUTIVE_IDENTICAL_TOOL_CALLS,
|
|
53
|
+
threshold: this.toolCallLoopThreshold,
|
|
54
|
+
count: this.toolCallRepetitionCount
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const key = this.getToolCallKey(toolName, toolArgs);
|
|
58
|
+
if (this.lastToolCallKey === key) {
|
|
59
|
+
this.toolCallRepetitionCount++;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
this.lastToolCallKey = key;
|
|
63
|
+
this.toolCallRepetitionCount = 1;
|
|
64
|
+
}
|
|
65
|
+
if (this.toolCallRepetitionCount >= this.toolCallLoopThreshold) {
|
|
66
|
+
this.loopDetected = true;
|
|
67
|
+
if (this.debug) {
|
|
68
|
+
console.warn(`[LoopDetection] Detected consecutive identical tool calls: ${toolName} (${this.toolCallRepetitionCount})`);
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
type: LoopType.CONSECUTIVE_IDENTICAL_TOOL_CALLS,
|
|
72
|
+
threshold: this.toolCallLoopThreshold,
|
|
73
|
+
count: this.toolCallRepetitionCount
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.LoopDetectionService = LoopDetectionService;
|
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for unified agent - defined locally as it's not exported from types
|
|
3
|
+
*/
|
|
4
|
+
export interface UnifiedAgentConfig {
|
|
5
|
+
maxIterations?: number;
|
|
6
|
+
maxConversationLength?: number;
|
|
7
|
+
enableLogging?: boolean;
|
|
8
|
+
llmConfig?: {
|
|
9
|
+
llmname?: string;
|
|
10
|
+
model?: string;
|
|
11
|
+
temperature?: number;
|
|
12
|
+
maxTokens?: number;
|
|
13
|
+
apiKey?: string;
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
};
|
|
16
|
+
retryConfig?: {
|
|
17
|
+
maxRetries?: number;
|
|
18
|
+
retryDelay?: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
2
21
|
/**
|
|
3
22
|
* Advanced agent creation with full configuration
|
|
4
23
|
*/
|