@codebolt/agent 5.0.7 → 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/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 +40 -18
- 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 +5 -5
|
@@ -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)
|
|
@@ -169,14 +196,6 @@ class ResponseExecutor {
|
|
|
169
196
|
});
|
|
170
197
|
}
|
|
171
198
|
else if (item.toolName == "codebolt--thread_management") {
|
|
172
|
-
codeboltjs_1.default.chat.sendMessage(JSON.stringify({
|
|
173
|
-
title: item.toolInput.title || item.toolInput.task || 'Background Thread',
|
|
174
|
-
description: item.toolInput.description || item.toolInput.task || '',
|
|
175
|
-
userMessage: item.toolInput.task || item.toolInput.userMessage || '',
|
|
176
|
-
selectedAgent: item.toolInput.selectedAgent,
|
|
177
|
-
isGrouped: item.toolInput.isGrouped,
|
|
178
|
-
groupId: item.toolInput.groupId,
|
|
179
|
-
}));
|
|
180
199
|
const response = await codeboltjs_1.default.thread.createThreadInBackground({
|
|
181
200
|
title: item.toolInput.title || item.toolInput.task || 'Background Thread',
|
|
182
201
|
description: item.toolInput.description || item.toolInput.task || '',
|
|
@@ -282,9 +301,12 @@ class ResponseExecutor {
|
|
|
282
301
|
* @returns Promise with tuple [userRejected, result]
|
|
283
302
|
*/
|
|
284
303
|
async executeTool(toolName, toolInput) {
|
|
304
|
+
var _a, _b;
|
|
285
305
|
//codebolttools--readfile
|
|
286
306
|
// console.log("Executing tool: ", toolName, toolInput);
|
|
287
|
-
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 : '';
|
|
288
310
|
// console.log("Toolbox name: ", toolboxName, "Actual tool name: ", actualToolName);
|
|
289
311
|
const { data } = await codeboltjs_1.default.mcp.executeTool(toolboxName, actualToolName, toolInput);
|
|
290
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
|
*/
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// Utility exports for the unified agent framework
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
exports.validateAgentConfig = validateAgentConfig;
|
|
4
5
|
exports.benchmarkAgent = benchmarkAgent;
|
|
@@ -201,13 +202,16 @@ async function benchmarkAgent(agent, testCases) {
|
|
|
201
202
|
}
|
|
202
203
|
const duration = Date.now() - startTime;
|
|
203
204
|
totalDuration += duration;
|
|
204
|
-
|
|
205
|
+
const resultEntry = {
|
|
205
206
|
name: testCase.name,
|
|
206
207
|
success,
|
|
207
208
|
duration,
|
|
208
|
-
output
|
|
209
|
-
|
|
210
|
-
|
|
209
|
+
output
|
|
210
|
+
};
|
|
211
|
+
if (error !== undefined) {
|
|
212
|
+
resultEntry.error = error;
|
|
213
|
+
}
|
|
214
|
+
results.push(resultEntry);
|
|
211
215
|
}
|
|
212
216
|
const summary = {
|
|
213
217
|
totalTests: testCases.length,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codebolt/agent",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.8",
|
|
4
4
|
"description": "CodeBolt Agent utilities for building and managing AI agents",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"js-yaml": "^4.1.0",
|
|
32
32
|
"zod": "^3.22.4",
|
|
33
|
-
"@codebolt/types": "5.0.
|
|
33
|
+
"@codebolt/types": "5.0.8"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@codebolt/codeboltjs": "5.0.
|
|
36
|
+
"@codebolt/codeboltjs": "5.0.8"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/js-yaml": "^4.0.9",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"typedoc": "0.28.16",
|
|
44
44
|
"typedoc-plugin-markdown": "4.9.0",
|
|
45
45
|
"typescript": "^5.4.5",
|
|
46
|
-
"@codebolt/
|
|
47
|
-
"@codebolt/
|
|
46
|
+
"@codebolt/codeboltjs": "5.0.8",
|
|
47
|
+
"@codebolt/types": "5.0.8"
|
|
48
48
|
},
|
|
49
49
|
"exports": {
|
|
50
50
|
"./builder": {
|