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.
- package/dist/config/index.js +2 -2
- package/dist/utils/agent.js +32 -112
- package/dist/utils/tools.js +6 -2
- package/package.json +1 -1
package/dist/config/index.js
CHANGED
|
@@ -68,14 +68,14 @@ export const config = new Conf({
|
|
|
68
68
|
agentMaxFixAttempts: 3,
|
|
69
69
|
agentMaxIterations: 100,
|
|
70
70
|
agentMaxDuration: 20, // minutes
|
|
71
|
-
agentApiTimeout:
|
|
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:
|
|
78
|
+
maxTokens: 8192,
|
|
79
79
|
apiTimeout: 60000,
|
|
80
80
|
rateLimitApi: 30, // 30 requests per minute
|
|
81
81
|
rateLimitCommands: 100, // 100 commands per minute
|
package/dist/utils/agent.js
CHANGED
|
@@ -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
|
-
|
|
19
|
-
//
|
|
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
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
if (hasVeryComplexKeyword) {
|
|
39
|
-
multiplier = 3.0; // Triple timeout for very complex tasks
|
|
25
|
+
if (iteration > 8) {
|
|
26
|
+
multiplier = 1.5;
|
|
40
27
|
}
|
|
41
|
-
//
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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},
|
|
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
|
-
//
|
|
646
|
-
//
|
|
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
|
package/dist/utils/tools.js
CHANGED
|
@@ -459,7 +459,9 @@ function validatePath(path, projectRoot) {
|
|
|
459
459
|
* Execute a tool call
|
|
460
460
|
*/
|
|
461
461
|
export function executeTool(toolCall, projectRoot) {
|
|
462
|
-
|
|
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[
|
|
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.
|
|
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",
|