codeep 1.0.22 → 1.0.24

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.
@@ -68,14 +68,14 @@ export const config = new Conf({
68
68
  agentMaxFixAttempts: 3,
69
69
  agentMaxIterations: 100,
70
70
  agentMaxDuration: 20, // minutes
71
- agentApiTimeout: 90000, // 90 seconds base timeout for agent (dynamically adjusted)
71
+ agentApiTimeout: 120000, // 120 seconds base timeout for agent (dynamically adjusted)
72
72
  protocol: 'openai',
73
73
  plan: 'lite',
74
74
  language: 'en',
75
75
  autoSave: true,
76
76
  currentSessionId: '',
77
77
  temperature: 0.7,
78
- maxTokens: 4096,
78
+ maxTokens: 8192,
79
79
  apiTimeout: 60000,
80
80
  rateLimitApi: 30, // 30 requests per minute
81
81
  rateLimitCommands: 100, // 100 commands per minute
@@ -15,46 +15,19 @@ class TimeoutError extends Error {
15
15
  * Complex tasks (creating pages, multiple files) need more time
16
16
  */
17
17
  function calculateDynamicTimeout(prompt, iteration, baseTimeout) {
18
- const promptLower = prompt.toLowerCase();
19
- // Keywords that indicate complex tasks requiring more time
20
- const complexKeywords = [
21
- 'create', 'build', 'implement', 'generate', 'make', 'develop', 'setup',
22
- 'website', 'app', 'application', 'page', 'component', 'feature',
23
- 'kreiraj', 'napravi', 'izgradi', 'generiraj', 'razvij', 'stranica', 'aplikacija'
24
- ];
25
- // Keywords indicating very large tasks
26
- const veryComplexKeywords = [
27
- 'full', 'complete', 'entire', 'whole', 'multiple', 'all',
28
- 'cijeli', 'kompletni', 'sve', 'višestruki'
29
- ];
18
+ // Simple approach: just use base timeout with small multiplier for later iterations
19
+ // Complex calculations were causing more problems than they solved
30
20
  let multiplier = 1.0;
31
- // Check for complex keywords
32
- const hasComplexKeyword = complexKeywords.some(kw => promptLower.includes(kw));
33
- if (hasComplexKeyword) {
34
- multiplier = 2.0; // Double timeout for complex tasks
21
+ // Later iterations have larger context, may need slightly more time
22
+ if (iteration > 3) {
23
+ multiplier = 1.2;
35
24
  }
36
- // Check for very complex keywords
37
- const hasVeryComplexKeyword = veryComplexKeywords.some(kw => promptLower.includes(kw));
38
- if (hasVeryComplexKeyword) {
39
- multiplier = 3.0; // Triple timeout for very complex tasks
25
+ if (iteration > 8) {
26
+ multiplier = 1.5;
40
27
  }
41
- // Long prompts usually mean complex tasks
42
- if (prompt.length > 200) {
43
- multiplier = Math.max(multiplier, 2.0);
44
- }
45
- if (prompt.length > 500) {
46
- multiplier = Math.max(multiplier, 3.0);
47
- }
48
- // Later iterations might need more time (context is larger)
49
- if (iteration > 5) {
50
- multiplier *= 1.2;
51
- }
52
- if (iteration > 10) {
53
- multiplier *= 1.3;
54
- }
55
- // Minimum 60 seconds, maximum 5 minutes for a single API call
28
+ // Minimum 120 seconds, maximum 5 minutes for a single API call
56
29
  const calculatedTimeout = baseTimeout * multiplier;
57
- return Math.min(Math.max(calculatedTimeout, 60000), 300000);
30
+ return Math.min(Math.max(calculatedTimeout, 120000), 300000);
58
31
  }
59
32
  import { parseToolCalls, executeTool, createActionLog, formatToolDefinitions, getOpenAITools, getAnthropicTools, parseOpenAIToolCalls, parseAnthropicToolCalls } from './tools.js';
60
33
  import { config, getApiKey } from '../config/index.js';
@@ -62,7 +35,7 @@ import { getProviderBaseUrl, getProviderAuthHeader, supportsNativeTools } from '
62
35
  import { startSession, endSession, undoLastAction, undoAllActions, getCurrentSession, getRecentSessions, formatSession } from './history.js';
63
36
  import { runAllVerifications, formatErrorsForAgent, hasVerificationErrors, getVerificationSummary } from './verify.js';
64
37
  import { gatherSmartContext, formatSmartContext, extractTargetFile } from './smartContext.js';
65
- import { planTasks, getNextTask, formatTaskPlan } from './taskPlanner.js';
38
+ import { planTasks, formatTaskPlan } from './taskPlanner.js';
66
39
  const DEFAULT_OPTIONS = {
67
40
  maxIterations: 100, // Increased for large tasks
68
41
  maxDuration: 20 * 60 * 1000, // 20 minutes
@@ -261,10 +234,27 @@ async function agentChat(messages, systemPrompt, onChunk, abortSignal, dynamicTi
261
234
  throw new Error(`API error: ${response.status} - ${errorText}`);
262
235
  }
263
236
  const data = await response.json();
237
+ // Debug: log raw API response
238
+ console.error(`[DEBUG] Raw API response:`, JSON.stringify(data, null, 2).substring(0, 1000));
264
239
  if (protocol === 'openai') {
265
240
  const message = data.choices?.[0]?.message;
266
241
  const content = message?.content || '';
267
- const toolCalls = parseOpenAIToolCalls(message?.tool_calls || []);
242
+ const rawToolCalls = message?.tool_calls || [];
243
+ // Debug: log raw tool calls from API
244
+ console.error(`[DEBUG] Raw tool_calls from API:`, JSON.stringify(rawToolCalls, null, 2));
245
+ const toolCalls = parseOpenAIToolCalls(rawToolCalls);
246
+ // Debug: log parsed tool calls
247
+ console.error(`[DEBUG] Parsed tool calls:`, JSON.stringify(toolCalls, null, 2));
248
+ // If no native tool calls, try parsing from content (some models return text-based)
249
+ if (toolCalls.length === 0 && content) {
250
+ console.error(`[DEBUG] No native tool calls, checking content for text-based calls...`);
251
+ console.error(`[DEBUG] Content preview:`, content.substring(0, 500));
252
+ const textToolCalls = parseToolCalls(content);
253
+ if (textToolCalls.length > 0) {
254
+ console.error(`[DEBUG] Found ${textToolCalls.length} text-based tool calls`);
255
+ return { content, toolCalls: textToolCalls, usedNativeTools: false };
256
+ }
257
+ }
268
258
  if (onChunk && content) {
269
259
  onChunk(content);
270
260
  }
@@ -636,83 +626,13 @@ export async function runAgent(prompt, projectContext, options = {}) {
636
626
  toolCalls = textToolCalls;
637
627
  }
638
628
  }
639
- // If no tool calls, check if agent is really done
629
+ // If no tool calls, agent is done - simple and clean like Claude Code/Aider
640
630
  if (toolCalls.length === 0) {
641
- console.error(`[DEBUG] No tool calls at iteration ${iteration}, content length: ${content.length}, actions so far: ${actions.length}`);
642
- console.error(`[DEBUG] Response preview:`, content.substring(0, 200));
631
+ console.error(`[DEBUG] No tool calls at iteration ${iteration}, agent finished`);
643
632
  // Remove <think>...</think> tags from response (some models include thinking)
644
633
  finalResponse = content.replace(/<think>[\s\S]*?<\/think>/gi, '').trim();
645
- // CRITICAL: Don't stop prematurely if we haven't done much work yet
646
- // Check if prompt contains "create", "build", "make", "implement", "add" etc.
647
- const taskKeywords = ['create', 'build', 'make', 'implement', 'add', 'generate', 'write', 'setup', 'develop', 'kreiraj', 'napravi', 'dodaj', 'website', 'app', 'feature'];
648
- const promptLowerCase = prompt.toLowerCase();
649
- const isCreationTask = taskKeywords.some(kw => promptLowerCase.includes(kw));
650
- // Only count actual FILE writes, not directories
651
- const hasCreatedFiles = actions.some(a => a.type === 'write');
652
- const writeFileCount = actions.filter(a => a.type === 'write').length;
653
- const hasMkdir = actions.some(a => a.type === 'mkdir');
654
- const isVeryEarlyIteration = iteration <= 5; // Extended to 5 iterations
655
- console.error(`[DEBUG] Task check: isCreationTask=${isCreationTask}, hasCreatedFiles=${hasCreatedFiles}, writeFileCount=${writeFileCount}, hasMkdir=${hasMkdir}, iteration=${iteration}`);
656
- console.error(`[DEBUG] Actions breakdown:`, actions.map(a => `${a.type}:${a.target}`).join(', '));
657
- // STRICT RULE: If it's a creation task, agent MUST create FILES (not just directories)
658
- // Creating a directory is not enough - we need actual file content
659
- if (isCreationTask && !hasCreatedFiles && iteration <= 10) {
660
- console.error(`[DEBUG] BLOCKING early stop - creation task detected but NO files created yet (iteration ${iteration}, ${actions.length} actions)`);
661
- // Force agent to create files
662
- messages.push({ role: 'assistant', content: finalResponse });
663
- messages.push({
664
- role: 'user',
665
- content: `❌ STOP. You have NOT created any files yet!\n\nYou MUST use write_file and create_directory tools to create the actual files I asked for.\n\nDo NOT respond with explanations. Execute the tools NOW:\n1. Use create_directory if needed\n2. Use write_file to create EACH file\n3. Only after creating ALL files, respond with a summary.`
666
- });
667
- finalResponse = ''; // Reset
668
- continue;
669
- }
670
- // If creation task but not enough files created, keep pushing
671
- if (isCreationTask && writeFileCount < 2 && iteration <= 10) {
672
- console.error(`[DEBUG] BLOCKING early stop - only ${writeFileCount} files created, need more (iteration ${iteration})`);
673
- messages.push({ role: 'assistant', content: finalResponse });
674
- messages.push({
675
- role: 'user',
676
- content: `You've only created ${writeFileCount} file(s). The task requires creating multiple files. Continue creating the remaining files now.`
677
- });
678
- finalResponse = ''; // Reset
679
- continue;
680
- }
681
- // General safety: very few actions in early iterations
682
- if (isVeryEarlyIteration && actions.length < 2) {
683
- console.error(`[DEBUG] BLOCKING early stop - very few actions (iteration ${iteration}, only ${actions.length} actions)`);
684
- messages.push({ role: 'assistant', content: finalResponse });
685
- messages.push({
686
- role: 'user',
687
- content: `Continue working on the task. Use the available tools to complete what I asked for.`
688
- });
689
- finalResponse = ''; // Reset
690
- continue;
691
- }
692
- // Check if we're using task planning and there are more tasks
693
- if (taskPlan && taskPlan.tasks.some(t => t.status === 'pending')) {
694
- const nextTask = getNextTask(taskPlan.tasks);
695
- if (nextTask) {
696
- // Mark previous task as completed
697
- const prevTask = taskPlan.tasks.find(t => t.status === 'in_progress' && t.id !== nextTask.id);
698
- if (prevTask) {
699
- prevTask.status = 'completed';
700
- }
701
- // Move to next task
702
- nextTask.status = 'in_progress';
703
- opts.onTaskUpdate?.(nextTask);
704
- // Build progress summary
705
- const completedTasks = taskPlan.tasks.filter(t => t.status === 'completed');
706
- const progressSummary = completedTasks.map(t => `✓ ${t.id}. ${t.description}`).join('\n');
707
- messages.push({ role: 'assistant', content: finalResponse });
708
- messages.push({
709
- role: 'user',
710
- content: `Good! Task ${prevTask?.id} done.\n\nCompleted:\n${progressSummary}\n\nNEXT TASK (do it now):\n${nextTask.id}. ${nextTask.description}\n\nUse your tools immediately to complete this task. Do NOT ask for permission or confirmation.`
711
- });
712
- finalResponse = ''; // Reset for next task
713
- continue;
714
- }
715
- }
634
+ // Trust the model - if it says it's done, it's done
635
+ // No forcing, no blocking, no artificial requirements
716
636
  break;
717
637
  }
718
638
  // Add assistant response to history
@@ -459,7 +459,9 @@ function validatePath(path, projectRoot) {
459
459
  * Execute a tool call
460
460
  */
461
461
  export function executeTool(toolCall, projectRoot) {
462
- const { tool, parameters } = toolCall;
462
+ // Normalize tool name to handle case variations (WRITE_FILE -> write_file)
463
+ const tool = normalizeToolName(toolCall.tool);
464
+ const parameters = toolCall.parameters;
463
465
  try {
464
466
  switch (tool) {
465
467
  case 'read_file': {
@@ -732,6 +734,8 @@ function listDirectory(dir, projectRoot, recursive, prefix = '') {
732
734
  * Create action log from tool result
733
735
  */
734
736
  export function createActionLog(toolCall, result) {
737
+ // Normalize tool name to handle case variations
738
+ const normalizedTool = normalizeToolName(toolCall.tool);
735
739
  const typeMap = {
736
740
  read_file: 'read',
737
741
  write_file: 'write',
@@ -749,7 +753,7 @@ export function createActionLog(toolCall, result) {
749
753
  toolCall.parameters.url ||
750
754
  'unknown';
751
755
  return {
752
- type: typeMap[toolCall.tool] || 'command',
756
+ type: typeMap[normalizedTool] || 'command',
753
757
  target,
754
758
  result: result.success ? 'success' : 'error',
755
759
  details: result.success ? result.output.slice(0, 200) : result.error,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
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",