codeep 1.0.5 → 1.0.7
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.d.ts +2 -0
- package/dist/config/index.js +2 -0
- package/dist/utils/agent.d.ts +4 -0
- package/dist/utils/agent.js +41 -5
- package/dist/utils/taskPlanner.d.ts +34 -0
- package/dist/utils/taskPlanner.js +160 -0
- package/package.json +1 -1
package/dist/config/index.d.ts
CHANGED
|
@@ -35,6 +35,8 @@ interface ConfigSchema {
|
|
|
35
35
|
agentAutoCommitBranch: boolean;
|
|
36
36
|
agentAutoVerify: boolean;
|
|
37
37
|
agentMaxFixAttempts: number;
|
|
38
|
+
agentMaxIterations: number;
|
|
39
|
+
agentMaxDuration: number;
|
|
38
40
|
projectPermissions: ProjectPermission[];
|
|
39
41
|
providerApiKeys: ProviderApiKey[];
|
|
40
42
|
}
|
package/dist/config/index.js
CHANGED
|
@@ -66,6 +66,8 @@ export const config = new Conf({
|
|
|
66
66
|
agentAutoCommitBranch: false,
|
|
67
67
|
agentAutoVerify: true, // Auto-verify by default
|
|
68
68
|
agentMaxFixAttempts: 3,
|
|
69
|
+
agentMaxIterations: 100,
|
|
70
|
+
agentMaxDuration: 20, // minutes
|
|
69
71
|
protocol: 'openai',
|
|
70
72
|
plan: 'lite',
|
|
71
73
|
language: 'en',
|
package/dist/utils/agent.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { ProjectContext } from './project';
|
|
|
5
5
|
import { ToolCall, ToolResult, ActionLog } from './tools';
|
|
6
6
|
import { undoLastAction, undoAllActions, getCurrentSession, getRecentSessions, formatSession, ActionSession } from './history';
|
|
7
7
|
import { VerifyResult } from './verify';
|
|
8
|
+
import { TaskPlan, SubTask } from './taskPlanner';
|
|
8
9
|
export interface AgentOptions {
|
|
9
10
|
maxIterations: number;
|
|
10
11
|
maxDuration: number;
|
|
@@ -13,10 +14,13 @@ export interface AgentOptions {
|
|
|
13
14
|
onIteration?: (iteration: number, message: string) => void;
|
|
14
15
|
onThinking?: (text: string) => void;
|
|
15
16
|
onVerification?: (results: VerifyResult[]) => void;
|
|
17
|
+
onTaskPlan?: (plan: TaskPlan) => void;
|
|
18
|
+
onTaskUpdate?: (task: SubTask) => void;
|
|
16
19
|
abortSignal?: AbortSignal;
|
|
17
20
|
dryRun?: boolean;
|
|
18
21
|
autoVerify?: boolean;
|
|
19
22
|
maxFixAttempts?: number;
|
|
23
|
+
usePlanning?: boolean;
|
|
20
24
|
}
|
|
21
25
|
export interface AgentResult {
|
|
22
26
|
success: boolean;
|
package/dist/utils/agent.js
CHANGED
|
@@ -7,9 +7,11 @@ import { getProviderBaseUrl, getProviderAuthHeader, supportsNativeTools } from '
|
|
|
7
7
|
import { startSession, endSession, undoLastAction, undoAllActions, getCurrentSession, getRecentSessions, formatSession } from './history.js';
|
|
8
8
|
import { runAllVerifications, formatErrorsForAgent, hasVerificationErrors, getVerificationSummary } from './verify.js';
|
|
9
9
|
import { gatherSmartContext, formatSmartContext, extractTargetFile } from './smartContext.js';
|
|
10
|
+
import { planTasks, formatTaskPlan } from './taskPlanner.js';
|
|
10
11
|
const DEFAULT_OPTIONS = {
|
|
11
|
-
maxIterations:
|
|
12
|
-
maxDuration:
|
|
12
|
+
maxIterations: 100, // Increased for large tasks
|
|
13
|
+
maxDuration: 20 * 60 * 1000, // 20 minutes
|
|
14
|
+
usePlanning: true, // Enable task planning by default
|
|
13
15
|
};
|
|
14
16
|
/**
|
|
15
17
|
* Generate system prompt for agent mode (used with native tool calling)
|
|
@@ -358,12 +360,42 @@ async function handleStream(body, protocol, onChunk) {
|
|
|
358
360
|
* Run the agent loop
|
|
359
361
|
*/
|
|
360
362
|
export async function runAgent(prompt, projectContext, options = {}) {
|
|
361
|
-
|
|
363
|
+
// Load limits from config
|
|
364
|
+
const configMaxIterations = config.get('agentMaxIterations');
|
|
365
|
+
const configMaxDuration = config.get('agentMaxDuration') * 60 * 1000; // convert minutes to ms
|
|
366
|
+
const opts = {
|
|
367
|
+
...DEFAULT_OPTIONS,
|
|
368
|
+
maxIterations: configMaxIterations,
|
|
369
|
+
maxDuration: configMaxDuration,
|
|
370
|
+
...options
|
|
371
|
+
};
|
|
362
372
|
const startTime = Date.now();
|
|
363
373
|
const actions = [];
|
|
364
374
|
const messages = [];
|
|
365
375
|
// Start history session for undo support
|
|
366
376
|
const sessionId = startSession(prompt, projectContext.root || process.cwd());
|
|
377
|
+
// Task planning phase (if enabled and prompt is complex enough)
|
|
378
|
+
let taskPlan = null;
|
|
379
|
+
if (opts.usePlanning && prompt.split(' ').length > 5) {
|
|
380
|
+
try {
|
|
381
|
+
opts.onIteration?.(0, 'Planning tasks...');
|
|
382
|
+
taskPlan = await planTasks(prompt, {
|
|
383
|
+
name: projectContext.name,
|
|
384
|
+
type: projectContext.type,
|
|
385
|
+
structure: projectContext.structure,
|
|
386
|
+
});
|
|
387
|
+
if (taskPlan.tasks.length > 1) {
|
|
388
|
+
opts.onTaskPlan?.(taskPlan);
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
taskPlan = null; // Single task, no need for planning
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
catch (error) {
|
|
395
|
+
// Planning failed, continue without it
|
|
396
|
+
taskPlan = null;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
367
399
|
// Gather smart context based on the task
|
|
368
400
|
const targetFile = extractTargetFile(prompt);
|
|
369
401
|
const smartContext = gatherSmartContext(targetFile, projectContext, prompt);
|
|
@@ -379,8 +411,12 @@ export async function runAgent(prompt, projectContext, options = {}) {
|
|
|
379
411
|
if (smartContextStr) {
|
|
380
412
|
systemPrompt += '\n\n' + smartContextStr;
|
|
381
413
|
}
|
|
382
|
-
// Initial user message
|
|
383
|
-
|
|
414
|
+
// Initial user message with optional task plan
|
|
415
|
+
let initialPrompt = prompt;
|
|
416
|
+
if (taskPlan) {
|
|
417
|
+
initialPrompt = `${prompt}\n\n## Task Breakdown\nI've broken this down into subtasks. Complete them in order:\n\n${formatTaskPlan(taskPlan)}\n\nStart with task 1.`;
|
|
418
|
+
}
|
|
419
|
+
messages.push({ role: 'user', content: initialPrompt });
|
|
384
420
|
let iteration = 0;
|
|
385
421
|
let finalResponse = '';
|
|
386
422
|
let result;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Planning - breaks down complex tasks into subtasks
|
|
3
|
+
*/
|
|
4
|
+
export interface SubTask {
|
|
5
|
+
id: number;
|
|
6
|
+
description: string;
|
|
7
|
+
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
8
|
+
dependencies?: number[];
|
|
9
|
+
}
|
|
10
|
+
export interface TaskPlan {
|
|
11
|
+
originalPrompt: string;
|
|
12
|
+
tasks: SubTask[];
|
|
13
|
+
estimatedIterations: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Ask AI to break down a complex task into subtasks
|
|
17
|
+
*/
|
|
18
|
+
export declare function planTasks(userPrompt: string, projectContext: {
|
|
19
|
+
name: string;
|
|
20
|
+
type: string;
|
|
21
|
+
structure: string;
|
|
22
|
+
}): Promise<TaskPlan>;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a task's dependencies are completed
|
|
25
|
+
*/
|
|
26
|
+
export declare function canStartTask(task: SubTask, allTasks: SubTask[]): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Get next task to execute
|
|
29
|
+
*/
|
|
30
|
+
export declare function getNextTask(tasks: SubTask[]): SubTask | null;
|
|
31
|
+
/**
|
|
32
|
+
* Format task plan for display
|
|
33
|
+
*/
|
|
34
|
+
export declare function formatTaskPlan(plan: TaskPlan): string;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Planning - breaks down complex tasks into subtasks
|
|
3
|
+
*/
|
|
4
|
+
import { config, getApiKey } from '../config/index.js';
|
|
5
|
+
import { getProviderBaseUrl, getProviderAuthHeader } from '../config/providers.js';
|
|
6
|
+
/**
|
|
7
|
+
* Ask AI to break down a complex task into subtasks
|
|
8
|
+
*/
|
|
9
|
+
export async function planTasks(userPrompt, projectContext) {
|
|
10
|
+
const systemPrompt = `You are a task planning expert. Break down user requests into clear, sequential subtasks.
|
|
11
|
+
|
|
12
|
+
RULES:
|
|
13
|
+
1. Create 3-15 subtasks maximum
|
|
14
|
+
2. Each subtask should be specific and actionable
|
|
15
|
+
3. Order tasks logically (dependencies first)
|
|
16
|
+
4. Use simple, clear descriptions
|
|
17
|
+
5. Respond ONLY with a JSON object, no other text
|
|
18
|
+
|
|
19
|
+
Example response format:
|
|
20
|
+
{
|
|
21
|
+
"tasks": [
|
|
22
|
+
{"id": 1, "description": "Create project directory structure", "dependencies": []},
|
|
23
|
+
{"id": 2, "description": "Create index.html with basic structure", "dependencies": [1]},
|
|
24
|
+
{"id": 3, "description": "Create styles.css with base styles", "dependencies": [1]},
|
|
25
|
+
{"id": 4, "description": "Add navigation to all pages", "dependencies": [2, 3]}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Project Context:
|
|
30
|
+
- Name: ${projectContext.name}
|
|
31
|
+
- Type: ${projectContext.type}
|
|
32
|
+
|
|
33
|
+
User Request: ${userPrompt}
|
|
34
|
+
|
|
35
|
+
Break this down into subtasks. Respond with JSON only.`;
|
|
36
|
+
try {
|
|
37
|
+
const apiKey = await getApiKey();
|
|
38
|
+
if (!apiKey) {
|
|
39
|
+
throw new Error('No API key configured');
|
|
40
|
+
}
|
|
41
|
+
const protocol = config.get('protocol');
|
|
42
|
+
const provider = config.get('provider');
|
|
43
|
+
const model = config.get('model');
|
|
44
|
+
const baseUrl = getProviderBaseUrl(provider, protocol);
|
|
45
|
+
const authHeaderType = getProviderAuthHeader(provider, protocol);
|
|
46
|
+
const messages = [
|
|
47
|
+
{ role: 'user', content: systemPrompt }
|
|
48
|
+
];
|
|
49
|
+
const requestBody = protocol === 'anthropic'
|
|
50
|
+
? {
|
|
51
|
+
model,
|
|
52
|
+
max_tokens: 2048,
|
|
53
|
+
messages,
|
|
54
|
+
system: 'You are a task planning assistant. Respond with JSON only.',
|
|
55
|
+
}
|
|
56
|
+
: {
|
|
57
|
+
model,
|
|
58
|
+
messages: [
|
|
59
|
+
{ role: 'system', content: 'You are a task planning assistant. Respond with JSON only.' },
|
|
60
|
+
...messages
|
|
61
|
+
],
|
|
62
|
+
temperature: 0.3,
|
|
63
|
+
max_tokens: 2048,
|
|
64
|
+
};
|
|
65
|
+
const headers = {
|
|
66
|
+
'Content-Type': 'application/json',
|
|
67
|
+
};
|
|
68
|
+
if (authHeaderType === 'x-api-key') {
|
|
69
|
+
headers['x-api-key'] = apiKey;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
73
|
+
}
|
|
74
|
+
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
75
|
+
method: 'POST',
|
|
76
|
+
headers,
|
|
77
|
+
body: JSON.stringify(requestBody),
|
|
78
|
+
});
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
throw new Error(`API request failed: ${response.statusText}`);
|
|
81
|
+
}
|
|
82
|
+
const data = await response.json();
|
|
83
|
+
const content = protocol === 'anthropic'
|
|
84
|
+
? data.content?.[0]?.text || ''
|
|
85
|
+
: data.choices?.[0]?.message?.content || '';
|
|
86
|
+
// Extract JSON from response (handle markdown code blocks)
|
|
87
|
+
let jsonStr = content.trim();
|
|
88
|
+
if (jsonStr.startsWith('```json')) {
|
|
89
|
+
jsonStr = jsonStr.replace(/```json\n?/g, '').replace(/```\n?/g, '');
|
|
90
|
+
}
|
|
91
|
+
else if (jsonStr.startsWith('```')) {
|
|
92
|
+
jsonStr = jsonStr.replace(/```\n?/g, '');
|
|
93
|
+
}
|
|
94
|
+
const parsed = JSON.parse(jsonStr);
|
|
95
|
+
// Validate and convert to TaskPlan
|
|
96
|
+
const tasks = parsed.tasks.map((t, index) => ({
|
|
97
|
+
id: t.id || index + 1,
|
|
98
|
+
description: t.description,
|
|
99
|
+
status: 'pending',
|
|
100
|
+
dependencies: t.dependencies || [],
|
|
101
|
+
}));
|
|
102
|
+
return {
|
|
103
|
+
originalPrompt: userPrompt,
|
|
104
|
+
tasks,
|
|
105
|
+
estimatedIterations: tasks.length * 3, // Rough estimate
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
// Fallback: create a single task
|
|
110
|
+
return {
|
|
111
|
+
originalPrompt: userPrompt,
|
|
112
|
+
tasks: [
|
|
113
|
+
{
|
|
114
|
+
id: 1,
|
|
115
|
+
description: userPrompt,
|
|
116
|
+
status: 'pending',
|
|
117
|
+
dependencies: [],
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
estimatedIterations: 10,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Check if a task's dependencies are completed
|
|
126
|
+
*/
|
|
127
|
+
export function canStartTask(task, allTasks) {
|
|
128
|
+
if (!task.dependencies || task.dependencies.length === 0) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
return task.dependencies.every(depId => {
|
|
132
|
+
const depTask = allTasks.find(t => t.id === depId);
|
|
133
|
+
return depTask?.status === 'completed';
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get next task to execute
|
|
138
|
+
*/
|
|
139
|
+
export function getNextTask(tasks) {
|
|
140
|
+
return tasks.find(t => t.status === 'pending' && canStartTask(t, tasks)) || null;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Format task plan for display
|
|
144
|
+
*/
|
|
145
|
+
export function formatTaskPlan(plan) {
|
|
146
|
+
const lines = ['Task Plan:', ''];
|
|
147
|
+
plan.tasks.forEach(task => {
|
|
148
|
+
const icon = task.status === 'completed' ? '✓'
|
|
149
|
+
: task.status === 'in_progress' ? '⏳'
|
|
150
|
+
: task.status === 'failed' ? '✗'
|
|
151
|
+
: '⏸';
|
|
152
|
+
const deps = task.dependencies && task.dependencies.length > 0
|
|
153
|
+
? ` (after: ${task.dependencies.join(', ')})`
|
|
154
|
+
: '';
|
|
155
|
+
lines.push(`${icon} ${task.id}. ${task.description}${deps}`);
|
|
156
|
+
});
|
|
157
|
+
lines.push('');
|
|
158
|
+
lines.push(`Estimated iterations: ~${plan.estimatedIterations}`);
|
|
159
|
+
return lines.join('\n');
|
|
160
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeep",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
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",
|