codeep 1.0.21 → 1.0.23
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/utils/agent.js +5 -75
- package/dist/utils/tools.d.ts +0 -3
- package/dist/utils/tools.js +38 -7
- package/package.json +1 -1
package/dist/utils/agent.js
CHANGED
|
@@ -62,7 +62,7 @@ import { getProviderBaseUrl, getProviderAuthHeader, supportsNativeTools } from '
|
|
|
62
62
|
import { startSession, endSession, undoLastAction, undoAllActions, getCurrentSession, getRecentSessions, formatSession } from './history.js';
|
|
63
63
|
import { runAllVerifications, formatErrorsForAgent, hasVerificationErrors, getVerificationSummary } from './verify.js';
|
|
64
64
|
import { gatherSmartContext, formatSmartContext, extractTargetFile } from './smartContext.js';
|
|
65
|
-
import { planTasks,
|
|
65
|
+
import { planTasks, formatTaskPlan } from './taskPlanner.js';
|
|
66
66
|
const DEFAULT_OPTIONS = {
|
|
67
67
|
maxIterations: 100, // Increased for large tasks
|
|
68
68
|
maxDuration: 20 * 60 * 1000, // 20 minutes
|
|
@@ -636,83 +636,13 @@ export async function runAgent(prompt, projectContext, options = {}) {
|
|
|
636
636
|
toolCalls = textToolCalls;
|
|
637
637
|
}
|
|
638
638
|
}
|
|
639
|
-
// If no tool calls,
|
|
639
|
+
// If no tool calls, agent is done - simple and clean like Claude Code/Aider
|
|
640
640
|
if (toolCalls.length === 0) {
|
|
641
|
-
console.error(`[DEBUG] No tool calls at iteration ${iteration},
|
|
642
|
-
console.error(`[DEBUG] Response preview:`, content.substring(0, 200));
|
|
641
|
+
console.error(`[DEBUG] No tool calls at iteration ${iteration}, agent finished`);
|
|
643
642
|
// Remove <think>...</think> tags from response (some models include thinking)
|
|
644
643
|
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
|
-
}
|
|
644
|
+
// Trust the model - if it says it's done, it's done
|
|
645
|
+
// No forcing, no blocking, no artificial requirements
|
|
716
646
|
break;
|
|
717
647
|
}
|
|
718
648
|
// Add assistant response to history
|
package/dist/utils/tools.d.ts
CHANGED
|
@@ -196,9 +196,6 @@ export declare function getOpenAITools(): OpenAITool[];
|
|
|
196
196
|
* Get tools in Anthropic Tool Use format
|
|
197
197
|
*/
|
|
198
198
|
export declare function getAnthropicTools(): AnthropicTool[];
|
|
199
|
-
/**
|
|
200
|
-
* Parse tool calls from OpenAI response
|
|
201
|
-
*/
|
|
202
199
|
export declare function parseOpenAIToolCalls(toolCalls: any[]): ToolCall[];
|
|
203
200
|
/**
|
|
204
201
|
* Parse tool calls from Anthropic response
|
package/dist/utils/tools.js
CHANGED
|
@@ -174,6 +174,33 @@ export function getAnthropicTools() {
|
|
|
174
174
|
/**
|
|
175
175
|
* Parse tool calls from OpenAI response
|
|
176
176
|
*/
|
|
177
|
+
/**
|
|
178
|
+
* Normalize tool name to lowercase with underscores
|
|
179
|
+
*/
|
|
180
|
+
function normalizeToolName(name) {
|
|
181
|
+
const toolNameMap = {
|
|
182
|
+
'executecommand': 'execute_command',
|
|
183
|
+
'execute_command': 'execute_command',
|
|
184
|
+
'readfile': 'read_file',
|
|
185
|
+
'read_file': 'read_file',
|
|
186
|
+
'writefile': 'write_file',
|
|
187
|
+
'write_file': 'write_file',
|
|
188
|
+
'editfile': 'edit_file',
|
|
189
|
+
'edit_file': 'edit_file',
|
|
190
|
+
'deletefile': 'delete_file',
|
|
191
|
+
'delete_file': 'delete_file',
|
|
192
|
+
'listfiles': 'list_files',
|
|
193
|
+
'list_files': 'list_files',
|
|
194
|
+
'searchcode': 'search_code',
|
|
195
|
+
'search_code': 'search_code',
|
|
196
|
+
'createdirectory': 'create_directory',
|
|
197
|
+
'create_directory': 'create_directory',
|
|
198
|
+
'fetchurl': 'fetch_url',
|
|
199
|
+
'fetch_url': 'fetch_url',
|
|
200
|
+
};
|
|
201
|
+
const lower = name.toLowerCase().replace(/-/g, '_');
|
|
202
|
+
return toolNameMap[lower] || lower;
|
|
203
|
+
}
|
|
177
204
|
export function parseOpenAIToolCalls(toolCalls) {
|
|
178
205
|
if (!toolCalls || !Array.isArray(toolCalls))
|
|
179
206
|
return [];
|
|
@@ -186,7 +213,7 @@ export function parseOpenAIToolCalls(toolCalls) {
|
|
|
186
213
|
parameters = {};
|
|
187
214
|
}
|
|
188
215
|
return {
|
|
189
|
-
tool: tc.function?.name || '',
|
|
216
|
+
tool: normalizeToolName(tc.function?.name || ''),
|
|
190
217
|
parameters,
|
|
191
218
|
id: tc.id,
|
|
192
219
|
};
|
|
@@ -201,7 +228,7 @@ export function parseAnthropicToolCalls(content) {
|
|
|
201
228
|
return content
|
|
202
229
|
.filter(block => block.type === 'tool_use')
|
|
203
230
|
.map(block => ({
|
|
204
|
-
tool: block.name || '',
|
|
231
|
+
tool: normalizeToolName(block.name || ''),
|
|
205
232
|
parameters: block.input || {},
|
|
206
233
|
id: block.id,
|
|
207
234
|
}))
|
|
@@ -386,7 +413,7 @@ function tryParseToolCall(str) {
|
|
|
386
413
|
const parsed = JSON.parse(cleaned);
|
|
387
414
|
if (parsed.tool && typeof parsed.tool === 'string') {
|
|
388
415
|
return {
|
|
389
|
-
tool: parsed.tool,
|
|
416
|
+
tool: normalizeToolName(parsed.tool),
|
|
390
417
|
parameters: parsed.parameters || {},
|
|
391
418
|
id: parsed.id,
|
|
392
419
|
};
|
|
@@ -394,9 +421,9 @@ function tryParseToolCall(str) {
|
|
|
394
421
|
}
|
|
395
422
|
catch {
|
|
396
423
|
// Try to extract tool name and parameters manually for malformed JSON
|
|
397
|
-
const toolMatch = str.match(/"tool"\s*:\s*"([^"]+)"/);
|
|
424
|
+
const toolMatch = str.match(/"tool"\s*:\s*"([^"]+)"/i);
|
|
398
425
|
if (toolMatch) {
|
|
399
|
-
const tool = toolMatch[1];
|
|
426
|
+
const tool = normalizeToolName(toolMatch[1]);
|
|
400
427
|
const params = {};
|
|
401
428
|
// Extract simple string parameters
|
|
402
429
|
const paramMatches = str.matchAll(/"(\w+)"\s*:\s*"([^"]*)"/g);
|
|
@@ -432,7 +459,9 @@ function validatePath(path, projectRoot) {
|
|
|
432
459
|
* Execute a tool call
|
|
433
460
|
*/
|
|
434
461
|
export function executeTool(toolCall, projectRoot) {
|
|
435
|
-
|
|
462
|
+
// Normalize tool name to handle case variations (WRITE_FILE -> write_file)
|
|
463
|
+
const tool = normalizeToolName(toolCall.tool);
|
|
464
|
+
const parameters = toolCall.parameters;
|
|
436
465
|
try {
|
|
437
466
|
switch (tool) {
|
|
438
467
|
case 'read_file': {
|
|
@@ -705,6 +734,8 @@ function listDirectory(dir, projectRoot, recursive, prefix = '') {
|
|
|
705
734
|
* Create action log from tool result
|
|
706
735
|
*/
|
|
707
736
|
export function createActionLog(toolCall, result) {
|
|
737
|
+
// Normalize tool name to handle case variations
|
|
738
|
+
const normalizedTool = normalizeToolName(toolCall.tool);
|
|
708
739
|
const typeMap = {
|
|
709
740
|
read_file: 'read',
|
|
710
741
|
write_file: 'write',
|
|
@@ -722,7 +753,7 @@ export function createActionLog(toolCall, result) {
|
|
|
722
753
|
toolCall.parameters.url ||
|
|
723
754
|
'unknown';
|
|
724
755
|
return {
|
|
725
|
-
type: typeMap[
|
|
756
|
+
type: typeMap[normalizedTool] || 'command',
|
|
726
757
|
target,
|
|
727
758
|
result: result.success ? 'success' : 'error',
|
|
728
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.23",
|
|
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",
|