protoagent 0.0.2 ā 0.0.3
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/agentic-loop.js +262 -29
- package/dist/config/client.js +157 -18
- package/dist/config/commands.js +29 -28
- package/dist/config/setup.js +20 -19
- package/dist/config/system-prompt.js +62 -0
- package/dist/index.js +84 -17
- package/dist/tools/index.js +72 -16
- package/dist/tools/run-shell-command.js +15 -14
- package/dist/utils/conversation-compactor.js +7 -6
- package/dist/utils/cost-tracker.js +5 -4
- package/dist/utils/file-operations-approval.js +33 -45
- package/dist/utils/logger.js +176 -3
- package/package.json +1 -1
package/dist/agentic-loop.js
CHANGED
|
@@ -4,6 +4,7 @@ import { generateSystemPrompt } from './config/system-prompt.js';
|
|
|
4
4
|
import { getModelConfig } from './config/providers.js';
|
|
5
5
|
import { estimateTokens, createUsageInfo, logUsageInfo, getContextInfo } from './utils/cost-tracker.js';
|
|
6
6
|
import { checkAndCompactIfNeeded } from './utils/conversation-compactor.js';
|
|
7
|
+
import { logger } from './utils/logger.js';
|
|
7
8
|
// Create system message for ProtoAgent dynamically
|
|
8
9
|
async function createSystemMessage() {
|
|
9
10
|
const systemPrompt = await generateSystemPrompt();
|
|
@@ -27,8 +28,13 @@ export class AgenticLoop {
|
|
|
27
28
|
* Initialize the agentic loop with dynamic system message
|
|
28
29
|
*/
|
|
29
30
|
async initialize() {
|
|
31
|
+
logger.debug('š Initializing agentic loop', { component: 'AgenticLoop' });
|
|
30
32
|
this.systemMessage = await createSystemMessage();
|
|
31
33
|
this.messages = [this.systemMessage];
|
|
34
|
+
logger.debug('ā
Agentic loop initialized', {
|
|
35
|
+
component: 'AgenticLoop',
|
|
36
|
+
systemMessageLength: this.systemMessage.content?.toString().length || 0
|
|
37
|
+
});
|
|
32
38
|
}
|
|
33
39
|
/**
|
|
34
40
|
* Get the current conversation history
|
|
@@ -52,28 +58,67 @@ export class AgenticLoop {
|
|
|
52
58
|
* Process a user input and run the agentic loop
|
|
53
59
|
*/
|
|
54
60
|
async processUserInput(userInput) {
|
|
61
|
+
logger.debug('š„ Processing user input', {
|
|
62
|
+
component: 'AgenticLoop',
|
|
63
|
+
inputLength: userInput.length,
|
|
64
|
+
currentMessageCount: this.messages.length
|
|
65
|
+
});
|
|
55
66
|
try {
|
|
56
67
|
// Add user message to conversation history
|
|
68
|
+
logger.debug('ā Adding user message to conversation', { component: 'AgenticLoop' });
|
|
57
69
|
this.addMessage({
|
|
58
70
|
role: 'user',
|
|
59
71
|
content: userInput
|
|
60
72
|
});
|
|
61
|
-
|
|
73
|
+
logger.consoleLog('š¤ Thinking...');
|
|
74
|
+
logger.info('š¤ AI thinking process started');
|
|
75
|
+
logger.debug('š§ Starting thinking process', {
|
|
76
|
+
component: 'AgenticLoop',
|
|
77
|
+
totalMessages: this.messages.length,
|
|
78
|
+
maxIterations: this.options.maxIterations
|
|
79
|
+
});
|
|
62
80
|
// Start the agentic loop
|
|
63
81
|
let continueProcessing = true;
|
|
64
82
|
let iterationCount = 0;
|
|
65
83
|
while (continueProcessing && iterationCount < this.options.maxIterations) {
|
|
66
84
|
iterationCount++;
|
|
85
|
+
logger.trace(`š Starting agentic loop iteration ${iterationCount}/${this.options.maxIterations}`, {
|
|
86
|
+
component: 'AgenticLoop',
|
|
87
|
+
iteration: iterationCount,
|
|
88
|
+
messageCount: this.messages.length,
|
|
89
|
+
conversationTokensApprox: this.messages.reduce((sum, msg) => sum + (typeof msg.content === 'string' ? msg.content.length / 4 : 0), 0)
|
|
90
|
+
});
|
|
67
91
|
try {
|
|
68
92
|
// Check if conversation needs compaction before making API call
|
|
93
|
+
logger.debug('š Checking context window usage', { component: 'AgenticLoop', iteration: iterationCount });
|
|
69
94
|
const modelConfig = getModelConfig(this.config.provider, this.config.model);
|
|
70
95
|
if (modelConfig) {
|
|
71
96
|
const contextInfo = getContextInfo(this.messages, modelConfig);
|
|
97
|
+
logger.debug('š Context analysis complete', {
|
|
98
|
+
component: 'AgenticLoop',
|
|
99
|
+
currentTokens: contextInfo.currentTokens,
|
|
100
|
+
maxTokens: modelConfig.contextWindow,
|
|
101
|
+
needsCompaction: contextInfo.needsCompaction,
|
|
102
|
+
percentageUsed: ((contextInfo.currentTokens / modelConfig.contextWindow) * 100).toFixed(1)
|
|
103
|
+
});
|
|
72
104
|
if (contextInfo.needsCompaction) {
|
|
73
|
-
|
|
105
|
+
logger.consoleLog('\nšļø Context window approaching limit, compacting conversation...');
|
|
106
|
+
logger.info('šļø Context compaction message displayed to user');
|
|
107
|
+
logger.debug('šļø Starting conversation compaction', { component: 'AgenticLoop' });
|
|
74
108
|
this.messages = await checkAndCompactIfNeeded(this.openaiClient, this.config.model, this.messages, modelConfig.contextWindow, contextInfo.currentTokens);
|
|
109
|
+
logger.debug('ā
Conversation compaction complete', {
|
|
110
|
+
component: 'AgenticLoop',
|
|
111
|
+
newMessageCount: this.messages.length
|
|
112
|
+
});
|
|
75
113
|
}
|
|
76
114
|
}
|
|
115
|
+
logger.debug('š Creating chat completion request', {
|
|
116
|
+
component: 'AgenticLoop',
|
|
117
|
+
model: this.config.model,
|
|
118
|
+
messageCount: this.messages.length,
|
|
119
|
+
toolsCount: tools.length,
|
|
120
|
+
streaming: true
|
|
121
|
+
});
|
|
77
122
|
// Create completion using OpenAI with built-in retry logic and cost tracking
|
|
78
123
|
const { stream, estimatedInputTokens } = await createChatCompletion(this.openaiClient, {
|
|
79
124
|
model: this.config.model,
|
|
@@ -82,7 +127,13 @@ export class AgenticLoop {
|
|
|
82
127
|
tool_choice: 'auto',
|
|
83
128
|
stream: true
|
|
84
129
|
}, this.config, this.messages);
|
|
130
|
+
logger.debug('š” Chat completion stream created', {
|
|
131
|
+
component: 'AgenticLoop',
|
|
132
|
+
estimatedInputTokens,
|
|
133
|
+
iteration: iterationCount
|
|
134
|
+
});
|
|
85
135
|
// Collect the streamed response
|
|
136
|
+
logger.trace('šØ Starting to collect streamed response', { component: 'AgenticLoop' });
|
|
86
137
|
let assistantMessage = {
|
|
87
138
|
role: 'assistant',
|
|
88
139
|
content: '',
|
|
@@ -91,10 +142,25 @@ export class AgenticLoop {
|
|
|
91
142
|
let streamedContent = '';
|
|
92
143
|
let hasToolCalls = false;
|
|
93
144
|
let actualUsage = undefined;
|
|
145
|
+
let chunkCount = 0;
|
|
94
146
|
for await (const chunk of stream) {
|
|
147
|
+
chunkCount++;
|
|
95
148
|
const delta = chunk.choices[0]?.delta;
|
|
149
|
+
logger.trace('š¦ Processing chunk', {
|
|
150
|
+
component: 'AgenticLoop',
|
|
151
|
+
chunkNumber: chunkCount,
|
|
152
|
+
hasContent: !!delta?.content,
|
|
153
|
+
hasToolCalls: !!delta?.tool_calls,
|
|
154
|
+
finishReason: chunk.choices[0]?.finish_reason
|
|
155
|
+
});
|
|
96
156
|
if (chunk.usage) {
|
|
97
157
|
actualUsage = chunk.usage;
|
|
158
|
+
logger.trace('š Received usage data', {
|
|
159
|
+
component: 'AgenticLoop',
|
|
160
|
+
promptTokens: chunk.usage.prompt_tokens,
|
|
161
|
+
completionTokens: chunk.usage.completion_tokens,
|
|
162
|
+
totalTokens: chunk.usage.total_tokens
|
|
163
|
+
});
|
|
98
164
|
}
|
|
99
165
|
if (delta?.content) {
|
|
100
166
|
streamedContent += delta.content;
|
|
@@ -103,13 +169,17 @@ export class AgenticLoop {
|
|
|
103
169
|
if (this.options.streamOutput && !hasToolCalls && !delta.tool_calls) {
|
|
104
170
|
if (streamedContent === delta.content) {
|
|
105
171
|
// First content chunk
|
|
106
|
-
process.stdout.write('
|
|
172
|
+
process.stdout.write('\nš¤ ProtoAgent: ');
|
|
107
173
|
}
|
|
108
174
|
process.stdout.write(delta.content);
|
|
109
175
|
}
|
|
110
176
|
}
|
|
111
177
|
if (delta?.tool_calls) {
|
|
112
178
|
hasToolCalls = true;
|
|
179
|
+
logger.trace('š§ Tool calls detected in delta', {
|
|
180
|
+
component: 'AgenticLoop',
|
|
181
|
+
toolCallsCount: delta.tool_calls.length
|
|
182
|
+
});
|
|
113
183
|
// Initialize tool_calls array if not exists
|
|
114
184
|
if (!assistantMessage.tool_calls) {
|
|
115
185
|
assistantMessage.tool_calls = [];
|
|
@@ -117,6 +187,13 @@ export class AgenticLoop {
|
|
|
117
187
|
// Handle tool calls in streaming
|
|
118
188
|
for (const toolCallDelta of delta.tool_calls) {
|
|
119
189
|
const index = toolCallDelta.index || 0;
|
|
190
|
+
logger.trace('š ļø Processing tool call delta', {
|
|
191
|
+
component: 'AgenticLoop',
|
|
192
|
+
index,
|
|
193
|
+
hasId: !!toolCallDelta.id,
|
|
194
|
+
hasName: !!toolCallDelta.function?.name,
|
|
195
|
+
hasArgs: !!toolCallDelta.function?.arguments
|
|
196
|
+
});
|
|
120
197
|
// Ensure we have an entry at this index
|
|
121
198
|
if (!assistantMessage.tool_calls[index]) {
|
|
122
199
|
assistantMessage.tool_calls[index] = {
|
|
@@ -137,7 +214,63 @@ export class AgenticLoop {
|
|
|
137
214
|
}
|
|
138
215
|
}
|
|
139
216
|
}
|
|
217
|
+
logger.debug('ā
Stream processing complete', {
|
|
218
|
+
component: 'AgenticLoop',
|
|
219
|
+
totalChunks: chunkCount,
|
|
220
|
+
finalContentLength: streamedContent.length,
|
|
221
|
+
finalToolCallsCount: assistantMessage.tool_calls?.length || 0,
|
|
222
|
+
hasActualUsage: !!actualUsage
|
|
223
|
+
});
|
|
140
224
|
const message = assistantMessage;
|
|
225
|
+
// DEBUG: Log the complete AI response
|
|
226
|
+
logger.debug('š¤ AI Response received', {
|
|
227
|
+
component: 'AgenticLoop',
|
|
228
|
+
iteration: iterationCount,
|
|
229
|
+
responseType: message.tool_calls?.length > 0 ? 'TOOL_CALLS' : 'TEXT_RESPONSE',
|
|
230
|
+
contentLength: message.content?.length || 0,
|
|
231
|
+
contentPreview: message.content ? message.content.substring(0, 200) + (message.content.length > 200 ? '...' : '') : null,
|
|
232
|
+
rawMessage: JSON.stringify(message),
|
|
233
|
+
toolCallsCount: message.tool_calls?.length || 0,
|
|
234
|
+
toolNames: message.tool_calls?.map((tc) => tc.function.name) || [],
|
|
235
|
+
toolCallsDetails: message.tool_calls?.map((tc) => ({
|
|
236
|
+
id: tc.id,
|
|
237
|
+
name: tc.function.name,
|
|
238
|
+
argsLength: tc.function.arguments?.length || 0,
|
|
239
|
+
argsPreview: tc.function.arguments ? tc.function.arguments.substring(0, 100) + (tc.function.arguments.length > 100 ? '...' : '') : null
|
|
240
|
+
})) || []
|
|
241
|
+
});
|
|
242
|
+
// TRACE: Log the AI's decision after thinking
|
|
243
|
+
logger.trace('š§ AI thinking complete - analyzing response...', {
|
|
244
|
+
component: 'AgenticLoop',
|
|
245
|
+
iteration: iterationCount,
|
|
246
|
+
hasToolCalls: !!(message.tool_calls && message.tool_calls.length > 0),
|
|
247
|
+
hasContent: !!(message.content && message.content.trim().length > 0),
|
|
248
|
+
toolCount: message.tool_calls?.length || 0,
|
|
249
|
+
contentLength: message.content?.length || 0
|
|
250
|
+
});
|
|
251
|
+
if (message.tool_calls && message.tool_calls.length > 0) {
|
|
252
|
+
logger.trace('š§ AI decided to use tools', {
|
|
253
|
+
component: 'AgenticLoop',
|
|
254
|
+
decision: 'TOOL_CALLS',
|
|
255
|
+
tools: message.tool_calls.map((tc) => tc.function.name).join(', '),
|
|
256
|
+
reasoning: 'AI determined that tool usage is needed to complete the task'
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
else if (message.content && message.content.trim().length > 0) {
|
|
260
|
+
logger.trace('š¬ AI decided to provide direct response', {
|
|
261
|
+
component: 'AgenticLoop',
|
|
262
|
+
decision: 'DIRECT_RESPONSE',
|
|
263
|
+
responsePreview: message.content.slice(0, 100) + (message.content.length > 100 ? '...' : ''),
|
|
264
|
+
reasoning: 'AI determined that a direct text response is sufficient'
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
logger.trace('ā ļø AI provided empty response', {
|
|
269
|
+
component: 'AgenticLoop',
|
|
270
|
+
decision: 'EMPTY_RESPONSE',
|
|
271
|
+
reasoning: 'AI returned neither tool calls nor content - this may indicate an issue'
|
|
272
|
+
});
|
|
273
|
+
}
|
|
141
274
|
// Calculate and log cost information
|
|
142
275
|
if (modelConfig) {
|
|
143
276
|
const finalInputTokens = actualUsage?.prompt_tokens ?? estimatedInputTokens;
|
|
@@ -148,16 +281,50 @@ export class AgenticLoop {
|
|
|
148
281
|
}
|
|
149
282
|
// Check if AI wants to use tools
|
|
150
283
|
if (message.tool_calls && message.tool_calls.length > 0) {
|
|
284
|
+
logger.debug('š§ AI requested tool usage', {
|
|
285
|
+
component: 'AgenticLoop',
|
|
286
|
+
toolCount: message.tool_calls.length,
|
|
287
|
+
toolNames: message.tool_calls.map((tc) => tc.function.name)
|
|
288
|
+
});
|
|
151
289
|
// Add the AI's message (with tool calls) to conversation
|
|
152
290
|
this.addMessage(message);
|
|
153
|
-
|
|
291
|
+
logger.debug('ā AI message with tool calls added to conversation', {
|
|
292
|
+
component: 'AgenticLoop',
|
|
293
|
+
messageRole: 'assistant',
|
|
294
|
+
hasContent: !!message.content,
|
|
295
|
+
contentLength: message.content?.length || 0,
|
|
296
|
+
toolCallsCount: message.tool_calls?.length || 0,
|
|
297
|
+
conversationLength: this.messages.length
|
|
298
|
+
});
|
|
299
|
+
logger.consoleLog(`š§ Using ${message.tool_calls.length} tool(s)...`);
|
|
300
|
+
logger.info(`š§ Tool usage message displayed: ${message.tool_calls.length} tools`);
|
|
154
301
|
// Execute each tool call
|
|
155
302
|
for (const toolCall of message.tool_calls) {
|
|
156
303
|
const { name, arguments: args } = toolCall.function;
|
|
157
|
-
|
|
304
|
+
logger.debug('š ļø Executing tool', {
|
|
305
|
+
component: 'AgenticLoop',
|
|
306
|
+
toolName: name,
|
|
307
|
+
toolId: toolCall.id,
|
|
308
|
+
argsLength: args.length
|
|
309
|
+
});
|
|
310
|
+
logger.consoleLog(`š ļø ${name}`);
|
|
311
|
+
logger.info(`š ļø Tool execution message displayed: ${name}`);
|
|
158
312
|
try {
|
|
159
313
|
const toolArgs = JSON.parse(args);
|
|
314
|
+
logger.debug('š Tool arguments parsed', {
|
|
315
|
+
component: 'AgenticLoop',
|
|
316
|
+
toolName: name,
|
|
317
|
+
parsedArgs: Object.keys(toolArgs)
|
|
318
|
+
});
|
|
319
|
+
const startTime = Date.now();
|
|
160
320
|
const result = await handleToolCall(name, toolArgs);
|
|
321
|
+
const executionTime = Date.now() - startTime;
|
|
322
|
+
logger.debug('ā
Tool execution successful', {
|
|
323
|
+
component: 'AgenticLoop',
|
|
324
|
+
toolName: name,
|
|
325
|
+
executionTime,
|
|
326
|
+
resultLength: result.length
|
|
327
|
+
});
|
|
161
328
|
// Add tool result to conversation
|
|
162
329
|
this.addMessage({
|
|
163
330
|
role: 'tool',
|
|
@@ -165,17 +332,25 @@ export class AgenticLoop {
|
|
|
165
332
|
content: result
|
|
166
333
|
});
|
|
167
334
|
// Show abbreviated result to user
|
|
168
|
-
const lines = result.split('
|
|
335
|
+
const lines = result.split('\n');
|
|
169
336
|
if (lines.length > 10) {
|
|
170
|
-
|
|
337
|
+
logger.consoleLog(` ā
${lines.slice(0, 3).join('\n ')}\n ... (${lines.length - 6} more lines) ...\n ${lines.slice(-3).join('\n ')}`);
|
|
338
|
+
logger.info(` ā
Tool result displayed (abbreviated, ${lines.length} lines)`);
|
|
171
339
|
}
|
|
172
340
|
else {
|
|
173
|
-
|
|
341
|
+
logger.consoleLog(` ā
${result.slice(0, 200)}${result.length > 200 ? '...' : ''}`);
|
|
342
|
+
logger.info(` ā
Tool result displayed (full, ${result.length} chars)`);
|
|
174
343
|
}
|
|
175
344
|
}
|
|
176
345
|
catch (error) {
|
|
177
346
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
178
|
-
|
|
347
|
+
logger.error('ā Tool execution failed', {
|
|
348
|
+
component: 'AgenticLoop',
|
|
349
|
+
toolName: name,
|
|
350
|
+
error: errorMessage
|
|
351
|
+
});
|
|
352
|
+
logger.consoleLog(` ā Error: ${errorMessage}`);
|
|
353
|
+
logger.error(` ā Tool error message displayed: ${errorMessage}`);
|
|
179
354
|
// Add error result to conversation
|
|
180
355
|
this.addMessage({
|
|
181
356
|
role: 'tool',
|
|
@@ -185,6 +360,12 @@ export class AgenticLoop {
|
|
|
185
360
|
}
|
|
186
361
|
}
|
|
187
362
|
// Continue the loop to let AI process tool results
|
|
363
|
+
logger.trace('š Continuing agentic loop for AI to process tool results', {
|
|
364
|
+
component: 'AgenticLoop',
|
|
365
|
+
decision: 'CONTINUE_PROCESSING',
|
|
366
|
+
reasoning: 'Tools were executed, AI needs another thinking cycle to process results',
|
|
367
|
+
nextIteration: iterationCount + 1
|
|
368
|
+
});
|
|
188
369
|
continue;
|
|
189
370
|
}
|
|
190
371
|
else {
|
|
@@ -192,78 +373,130 @@ export class AgenticLoop {
|
|
|
192
373
|
if (message.content && !hasToolCalls) {
|
|
193
374
|
// Content was already streamed to user during the loop above
|
|
194
375
|
if (this.options.streamOutput) {
|
|
195
|
-
|
|
376
|
+
logger.consoleLog('\n'); // Add newline after streaming is complete
|
|
377
|
+
logger.debug('\\n AI response streaming completed');
|
|
196
378
|
}
|
|
197
379
|
else {
|
|
198
|
-
|
|
380
|
+
logger.consoleLog(`\nš¤ ProtoAgent: ${message.content}\n`);
|
|
381
|
+
logger.info('š¤ AI response displayed to user (non-streaming)');
|
|
199
382
|
}
|
|
200
383
|
// Add AI response to conversation history
|
|
201
384
|
this.addMessage({
|
|
202
385
|
role: 'assistant',
|
|
203
386
|
content: message.content
|
|
204
387
|
});
|
|
388
|
+
logger.debug('ā AI text response added to conversation', {
|
|
389
|
+
component: 'AgenticLoop',
|
|
390
|
+
messageRole: 'assistant',
|
|
391
|
+
contentLength: message.content?.length || 0,
|
|
392
|
+
conversationLength: this.messages.length
|
|
393
|
+
});
|
|
205
394
|
}
|
|
206
395
|
else if (message.content && hasToolCalls) {
|
|
207
396
|
// AI provided content along with tool calls (rare case)
|
|
208
397
|
if (this.options.streamOutput) {
|
|
209
|
-
process.stdout.write('
|
|
398
|
+
process.stdout.write('\nš¤ ProtoAgent: ');
|
|
210
399
|
process.stdout.write(message.content);
|
|
211
|
-
|
|
400
|
+
logger.consoleLog('\n');
|
|
401
|
+
logger.info('š¤ AI response with tool calls displayed (streaming)');
|
|
212
402
|
}
|
|
213
403
|
else {
|
|
214
|
-
|
|
404
|
+
logger.consoleLog(`\nš¤ ProtoAgent: ${message.content}\n`);
|
|
405
|
+
logger.info('š¤ AI response with tool calls displayed (non-streaming)');
|
|
215
406
|
}
|
|
216
407
|
// Add AI response to conversation history
|
|
217
408
|
this.addMessage({
|
|
218
409
|
role: 'assistant',
|
|
219
410
|
content: message.content
|
|
220
411
|
});
|
|
412
|
+
logger.debug('ā AI mixed response (content + tool calls) added to conversation', {
|
|
413
|
+
component: 'AgenticLoop',
|
|
414
|
+
messageRole: 'assistant',
|
|
415
|
+
contentLength: message.content?.length || 0,
|
|
416
|
+
conversationLength: this.messages.length
|
|
417
|
+
});
|
|
221
418
|
}
|
|
419
|
+
logger.trace('ā
Agentic loop complete - stopping processing', {
|
|
420
|
+
component: 'AgenticLoop',
|
|
421
|
+
decision: 'STOP_PROCESSING',
|
|
422
|
+
reasoning: 'AI provided final response without tool calls',
|
|
423
|
+
totalIterations: iterationCount
|
|
424
|
+
});
|
|
222
425
|
continueProcessing = false;
|
|
223
426
|
}
|
|
224
427
|
}
|
|
225
428
|
catch (apiError) {
|
|
226
429
|
// Handle API errors that weren't caught by the retry logic
|
|
227
|
-
|
|
430
|
+
logger.trace('ā API Error occurred - stopping agentic loop', {
|
|
431
|
+
component: 'AgenticLoop',
|
|
432
|
+
decision: 'STOP_ON_API_ERROR',
|
|
433
|
+
errorStatus: apiError?.status,
|
|
434
|
+
errorMessage: apiError?.message,
|
|
435
|
+
reasoning: 'Unrecoverable API error encountered'
|
|
436
|
+
});
|
|
437
|
+
console.error('\nā API Error:', apiError?.message || 'Unknown API error');
|
|
438
|
+
logger.error('\nā API Error message displayed to user', {
|
|
439
|
+
component: 'AgenticLoop',
|
|
440
|
+
error: apiError?.message || 'Unknown API error'
|
|
441
|
+
});
|
|
228
442
|
// Check for specific error types and provide helpful messages
|
|
229
443
|
if (apiError?.status === 401) {
|
|
230
|
-
|
|
231
|
-
|
|
444
|
+
logger.consoleLog('š” Authentication failed. Your API key may be invalid or expired.');
|
|
445
|
+
logger.consoleLog(' Run: protoagent config --update-key');
|
|
446
|
+
logger.info('š” Auth error help message displayed to user');
|
|
232
447
|
}
|
|
233
448
|
else if (apiError?.status === 403) {
|
|
234
|
-
|
|
449
|
+
logger.consoleLog('š” Access forbidden. Check your API key permissions or billing status.');
|
|
450
|
+
logger.info('š” Access forbidden help message displayed to user');
|
|
235
451
|
}
|
|
236
452
|
else if (apiError?.status === 400) {
|
|
237
|
-
|
|
238
|
-
|
|
453
|
+
logger.consoleLog('š” Bad request. There may be an issue with the request format.');
|
|
454
|
+
logger.consoleLog(' This could be a bug in ProtoAgent. Please check for updates.');
|
|
455
|
+
logger.info('š” Bad request help message displayed to user');
|
|
239
456
|
}
|
|
240
457
|
else {
|
|
241
|
-
|
|
458
|
+
logger.consoleLog('š” An unexpected API error occurred. Please try again.');
|
|
459
|
+
logger.info('š” Generic API error help message displayed to user');
|
|
242
460
|
}
|
|
243
461
|
// Exit the processing loop for API errors
|
|
244
462
|
break;
|
|
245
463
|
}
|
|
246
464
|
}
|
|
247
465
|
if (iterationCount >= this.options.maxIterations) {
|
|
248
|
-
|
|
466
|
+
logger.trace('ā ļø Maximum iteration limit reached - stopping agentic loop', {
|
|
467
|
+
component: 'AgenticLoop',
|
|
468
|
+
decision: 'STOP_ON_MAX_ITERATIONS',
|
|
469
|
+
maxIterations: this.options.maxIterations,
|
|
470
|
+
reasoning: 'Reached maximum allowed iterations to prevent infinite loops'
|
|
471
|
+
});
|
|
472
|
+
logger.consoleLog('\nā ļø Maximum iteration limit reached. Task may be incomplete.');
|
|
473
|
+
logger.warn('ā ļø Max iteration warning displayed to user');
|
|
249
474
|
}
|
|
250
475
|
}
|
|
251
476
|
catch (error) {
|
|
252
477
|
// Handle general processing errors
|
|
253
|
-
console.error('
|
|
478
|
+
console.error('\nā Error during processing:', error?.message || 'Unknown error');
|
|
479
|
+
logger.error('\nā General processing error displayed to user', {
|
|
480
|
+
component: 'AgenticLoop',
|
|
481
|
+
error: error?.message || 'Unknown error'
|
|
482
|
+
});
|
|
254
483
|
// Provide helpful error messages for common issues
|
|
255
484
|
if (error?.message?.includes('API key')) {
|
|
256
|
-
|
|
257
|
-
|
|
485
|
+
logger.consoleLog('š” There seems to be an issue with your API key configuration.');
|
|
486
|
+
logger.consoleLog(' Run: protoagent config --show');
|
|
487
|
+
logger.info('š” API key error help message displayed');
|
|
258
488
|
}
|
|
259
489
|
else if (error?.message?.includes('model')) {
|
|
260
|
-
|
|
261
|
-
|
|
490
|
+
logger.consoleLog('š” There seems to be an issue with the selected model.');
|
|
491
|
+
logger.consoleLog(' Run: protoagent config --update-model');
|
|
492
|
+
logger.info('š” Model error help message displayed');
|
|
262
493
|
}
|
|
263
494
|
else {
|
|
264
|
-
|
|
495
|
+
logger.consoleLog('š” An unexpected error occurred. Please check your configuration and try again.');
|
|
496
|
+
logger.info('š” Generic error help message displayed');
|
|
265
497
|
}
|
|
266
|
-
|
|
498
|
+
logger.consoleLog('\nš¤ ProtoAgent: I encountered an error and cannot continue processing this request.\n');
|
|
499
|
+
logger.info('š¤ Error termination message displayed to user');
|
|
267
500
|
}
|
|
268
501
|
}
|
|
269
502
|
}
|