codeep 1.2.59 → 1.2.61

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.
@@ -138,8 +138,12 @@ export async function executeAgentTask(task, dryRun, ctx) {
138
138
  const result = await runAgent(enrichedTask, context, {
139
139
  dryRun,
140
140
  chatHistory: app.getChatHistory(),
141
- onIteration: (iteration) => {
141
+ onIteration: (iteration, message) => {
142
142
  app.updateAgentProgress(iteration);
143
+ // Show special status messages (timeout retries, verification) but not generic iteration messages
144
+ if (message && !message.startsWith('Iteration ')) {
145
+ app.addMessage({ role: 'system', content: `_${message}_` });
146
+ }
143
147
  },
144
148
  onToolCall: (tool) => {
145
149
  const toolName = tool.tool.toLowerCase();
@@ -210,6 +214,31 @@ export async function executeAgentTask(task, dryRun, ctx) {
210
214
  const filePath = tool.parameters.path;
211
215
  app.addMessage({ role: 'system', content: `**Delete** \`${filePath}\`` });
212
216
  }
217
+ else if (actionType === 'read') {
218
+ const filePath = tool.parameters.path || shortTarget;
219
+ if (filePath)
220
+ app.addMessage({ role: 'system', content: `**Reading** \`${filePath}\`` });
221
+ }
222
+ else if (actionType === 'search') {
223
+ const pattern = tool.parameters.pattern || tool.parameters.query || shortTarget;
224
+ if (pattern)
225
+ app.addMessage({ role: 'system', content: `**Searching** for \`${pattern}\`` });
226
+ }
227
+ else if (actionType === 'list') {
228
+ const dirPath = tool.parameters.path || shortTarget;
229
+ if (dirPath)
230
+ app.addMessage({ role: 'system', content: `**Listing** \`${dirPath}\`` });
231
+ }
232
+ else if (actionType === 'fetch') {
233
+ const url = tool.parameters.url || shortTarget;
234
+ if (url)
235
+ app.addMessage({ role: 'system', content: `**Fetching** \`${url}\`` });
236
+ }
237
+ else if (actionType === 'command') {
238
+ const cmd = tool.parameters.command || shortTarget;
239
+ if (cmd)
240
+ app.addMessage({ role: 'system', content: `**Running** \`${cmd}\`` });
241
+ }
213
242
  },
214
243
  onToolResult: (result, toolCall) => {
215
244
  const toolName = toolCall.tool.toLowerCase();
@@ -235,7 +264,27 @@ export async function executeAgentTask(task, dryRun, ctx) {
235
264
  abortSignal: abortController.signal,
236
265
  });
237
266
  if (result.success) {
238
- const summary = result.finalResponse || `Completed ${result.actions.length} actions in ${result.iterations} steps.`;
267
+ const fileChanges = result.actions.filter(a => a.type === 'write' || a.type === 'edit' || a.type === 'delete');
268
+ const otherActions = result.actions.filter(a => a.type !== 'write' && a.type !== 'edit' && a.type !== 'delete');
269
+ const completionLines = [];
270
+ if (result.finalResponse) {
271
+ completionLines.push(result.finalResponse);
272
+ completionLines.push('');
273
+ }
274
+ completionLines.push(`**Agent completed** in ${result.iterations} step(s)`);
275
+ if (fileChanges.length > 0) {
276
+ completionLines.push('');
277
+ completionLines.push('**Files changed:**');
278
+ for (const a of fileChanges) {
279
+ const icon = a.type === 'delete' ? '✗' : '✓';
280
+ completionLines.push(` ${icon} ${a.type}: \`${a.target}\``);
281
+ }
282
+ }
283
+ if (otherActions.length > 0) {
284
+ completionLines.push('');
285
+ completionLines.push(`${otherActions.length} read/search operation(s) performed`);
286
+ }
287
+ const summary = completionLines.join('\n');
239
288
  app.addMessage({ role: 'assistant', content: summary });
240
289
  app.notify(`Agent completed: ${result.actions.length} actions`);
241
290
  // Auto-commit if enabled and there were file changes
@@ -236,6 +236,8 @@ export async function runAgent(prompt, projectContext, options = {}) {
236
236
  // Also remove Tool parameters/tool call artifacts that AI sometimes includes in text
237
237
  finalResponse = content
238
238
  .replace(/<think>[\s\S]*?<\/think>/gi, '')
239
+ .replace(/<tool_call>[\s\S]*?<\/tool_call>/gi, '')
240
+ .replace(/<arg_key>[\s\S]*?<\/arg_value>/gi, '')
239
241
  .replace(/Tool parameters:[\s\S]*?(?=\n\n|$)/gi, '')
240
242
  .replace(/\{'path'[\s\S]*?\}/g, '')
241
243
  .replace(/```[\s\S]*?```/g, '')
@@ -325,6 +327,7 @@ export async function runAgent(prompt, projectContext, options = {}) {
325
327
  const hasFileChanges = actions.some(a => a.type === 'write' || a.type === 'edit' || a.type === 'delete');
326
328
  if (hasFileChanges) {
327
329
  let fixAttempt = 0;
330
+ let previousErrorSignature = '';
328
331
  while (fixAttempt < maxFixAttempts) {
329
332
  // Check abort signal
330
333
  if (opts.abortSignal?.aborted) {
@@ -349,15 +352,32 @@ export async function runAgent(prompt, projectContext, options = {}) {
349
352
  // If we've exceeded attempts, report the errors
350
353
  if (fixAttempt >= maxFixAttempts) {
351
354
  const summary = getVerificationSummary(verifyResults);
352
- finalResponse += `\n\n✗ Verification failed after ${fixAttempt} fix attempts: ${summary.errors} errors remaining`;
355
+ const errorDetail = summary.errors > 0
356
+ ? `${summary.errors} error(s) remaining`
357
+ : `${summary.failed}/${summary.total} check(s) failing (exit code non-zero)`;
358
+ finalResponse += `\n\n✗ Verification failed after ${fixAttempt} fix attempt(s): ${errorDetail}`;
353
359
  break;
354
360
  }
355
- // Ask agent to fix the errors
361
+ // Detect if the same errors are repeating (previous fix attempt didn't help)
356
362
  const errorMessage = formatErrorsForAgent(verifyResults);
363
+ const currentErrorSignature = errorMessage.slice(0, 200);
364
+ const errorsRepeating = previousErrorSignature !== '' && currentErrorSignature === previousErrorSignature;
365
+ previousErrorSignature = currentErrorSignature;
366
+ // Escalate the fix strategy based on attempt number and whether errors are repeating
367
+ let fixPrompt;
368
+ if (errorsRepeating) {
369
+ fixPrompt = `${errorMessage}\n\nYour previous fix attempt did NOT resolve these errors — they are still the same. You MUST try a completely different approach:\n- Re-read the affected files to understand the current state\n- Consider whether the root cause is different from what you assumed\n- Try an alternative implementation strategy\n- If it's a missing dependency, install it with execute_command`;
370
+ }
371
+ else if (fixAttempt === 1) {
372
+ fixPrompt = `${errorMessage}\n\nFix these errors. Read the affected files first to understand the current state before making changes.`;
373
+ }
374
+ else {
375
+ fixPrompt = `${errorMessage}\n\nAttempt ${fixAttempt}/${maxFixAttempts}: Your previous fix was partially successful but errors remain. Re-read ALL affected files and take a fresh look — consider whether there are related issues you missed.`;
376
+ }
357
377
  messages.push({ role: 'assistant', content: finalResponse });
358
378
  messages.push({
359
379
  role: 'user',
360
- content: `${errorMessage}\n\nFix these errors. After fixing, I will re-run verification.`
380
+ content: fixPrompt,
361
381
  });
362
382
  iteration++;
363
383
  if (iteration >= opts.maxIterations) {
@@ -289,6 +289,24 @@ export function parseToolCalls(response) {
289
289
  }
290
290
  }
291
291
  }
292
+ // Format 3b: Tool <arg_key>param</arg_key><arg_value>value</arg_value> format
293
+ // Some models emit: Tool write_file<arg_key>path</arg_key><arg_value>...</arg_value>
294
+ if (toolCalls.length === 0) {
295
+ const argKeyValueRegex = /Tool\s+(\w+)((?:\s*<arg_key>[\s\S]*?<\/arg_key>\s*<arg_value>[\s\S]*?<\/arg_value>)+)/gi;
296
+ while ((match = argKeyValueRegex.exec(response)) !== null) {
297
+ const toolName = normalizeToolName(match[1]);
298
+ const argBlock = match[2];
299
+ const params = {};
300
+ const pairRegex = /<arg_key>([\s\S]*?)<\/arg_key>\s*<arg_value>([\s\S]*?)<\/arg_value>/gi;
301
+ let pairMatch;
302
+ while ((pairMatch = pairRegex.exec(argBlock)) !== null) {
303
+ params[pairMatch[1].trim()] = pairMatch[2].trim();
304
+ }
305
+ if (toolName && Object.keys(params).length > 0) {
306
+ toolCalls.push({ tool: toolName, parameters: params });
307
+ }
308
+ }
309
+ }
292
310
  // Format 4: Inline JSON with tool property (fallback)
293
311
  if (toolCalls.length === 0) {
294
312
  const jsonRegex = /\{[^{}]*"tool"\s*:\s*"[^"]+"\s*,\s*"parameters"\s*:\s*\{[^{}]*\}[^{}]*\}/g;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "1.2.59",
3
+ "version": "1.2.61",
4
4
  "description": "AI-powered coding assistant built for the terminal. Multiple LLM providers, project-aware context, and a seamless development workflow.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",