agent-nuvira 1.21.0 → 1.22.0
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/agents/edit-module.d.ts +121 -0
- package/dist/agents/edit-module.d.ts.map +1 -0
- package/dist/agents/edit-module.js +339 -0
- package/dist/agents/edit-module.js.map +1 -0
- package/dist/agents/pipeline-audit.d.ts +128 -0
- package/dist/agents/pipeline-audit.d.ts.map +1 -0
- package/dist/agents/pipeline-audit.js +162 -0
- package/dist/agents/pipeline-audit.js.map +1 -0
- package/dist/agents/plan-module.d.ts +84 -0
- package/dist/agents/plan-module.d.ts.map +1 -0
- package/dist/agents/plan-module.js +261 -0
- package/dist/agents/plan-module.js.map +1 -0
- package/dist/agents/task-execution-pipeline.d.ts +237 -0
- package/dist/agents/task-execution-pipeline.d.ts.map +1 -0
- package/dist/agents/task-execution-pipeline.js +816 -0
- package/dist/agents/task-execution-pipeline.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EditModule — Generates code changes from task descriptions and file context.
|
|
3
|
+
* Phase 7 of the architecture migration: extract from WriterAgent into
|
|
4
|
+
* a pluggable module with EventBus integration.
|
|
5
|
+
*
|
|
6
|
+
* The module reads relevant files, calls an LLM to generate modified versions,
|
|
7
|
+
* parses file changes from the response, validates syntax via AST analysis,
|
|
8
|
+
* and returns structured FileChange objects — without writing to disk.
|
|
9
|
+
*
|
|
10
|
+
* @see ARCHITECTURE.md §3.3 — Edit Module specification
|
|
11
|
+
*/
|
|
12
|
+
import type { EventBus } from '../observability/event-bus.js';
|
|
13
|
+
import type { LLMCallFn, FileChange, Artifact } from './agent.js';
|
|
14
|
+
/** Parameters for the EditModule.edit() method */
|
|
15
|
+
export interface EditParams {
|
|
16
|
+
/** The original user goal / task description */
|
|
17
|
+
goal: string;
|
|
18
|
+
/** Absolute path to the working directory */
|
|
19
|
+
workingDirectory: string;
|
|
20
|
+
/** File artifacts discovered during the inspection phase */
|
|
21
|
+
artifacts: Artifact[];
|
|
22
|
+
/** The LLM call function */
|
|
23
|
+
callLLM: LLMCallFn;
|
|
24
|
+
/** Optional structured context overrides */
|
|
25
|
+
taskDescription?: string;
|
|
26
|
+
/** Optional MCP tools description for the LLM */
|
|
27
|
+
mcpToolsFormatted?: string;
|
|
28
|
+
/** Optional rate limit callback */
|
|
29
|
+
onRateLimit?: (info: {
|
|
30
|
+
retryAfterMs: number;
|
|
31
|
+
modelName?: string;
|
|
32
|
+
agentName: string;
|
|
33
|
+
errorMessage: string;
|
|
34
|
+
}) => Promise<{
|
|
35
|
+
action: 'retry' | 'skip' | 'abort' | 'switch-model';
|
|
36
|
+
callLLM?: LLMCallFn;
|
|
37
|
+
}>;
|
|
38
|
+
/** Whether this is a retry attempt (stricter prompt) */
|
|
39
|
+
isRetry?: boolean;
|
|
40
|
+
}
|
|
41
|
+
/** Output of the edit phase */
|
|
42
|
+
export interface EditOutput {
|
|
43
|
+
/** File changes generated */
|
|
44
|
+
changes: FileChange[];
|
|
45
|
+
/** Human-readable summary */
|
|
46
|
+
summary: string;
|
|
47
|
+
/** How many files were changed */
|
|
48
|
+
changeCount: number;
|
|
49
|
+
/** Syntax warnings, if any */
|
|
50
|
+
warnings?: string[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* EditModule — Generate code changes from task descriptions and file context.
|
|
54
|
+
*
|
|
55
|
+
* The module reads files, calls the LLM to generate modified versions, parses
|
|
56
|
+
* the response, validates syntax, and returns structured FileChange objects.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* const module = new DefaultEditModule();
|
|
61
|
+
* const result = await module.edit({
|
|
62
|
+
* goal: 'Add JWT auth',
|
|
63
|
+
* workingDirectory: '/project',
|
|
64
|
+
* artifacts: inspectedFiles,
|
|
65
|
+
* callLLM,
|
|
66
|
+
* });
|
|
67
|
+
* console.log(`Changed ${result.changeCount} files`);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export interface EditModule {
|
|
71
|
+
/**
|
|
72
|
+
* Generate file changes from the given task and file context.
|
|
73
|
+
*/
|
|
74
|
+
edit(params: EditParams): Promise<EditOutput>;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* DefaultEditModule — Built-in edit module implementation.
|
|
78
|
+
*
|
|
79
|
+
* Builds a prompt from file artifacts and task description; calls the LLM;
|
|
80
|
+
* parses file changes from the response; validates syntax via AST analysis;
|
|
81
|
+
* and returns structured FileChange objects without writing to disk.
|
|
82
|
+
*/
|
|
83
|
+
export declare class DefaultEditModule implements EditModule {
|
|
84
|
+
/** The event bus for emitting observability events */
|
|
85
|
+
private eventBus;
|
|
86
|
+
constructor(eventBus?: EventBus);
|
|
87
|
+
/**
|
|
88
|
+
* Generate file changes from the given task and file context.
|
|
89
|
+
*/
|
|
90
|
+
edit(params: EditParams): Promise<EditOutput>;
|
|
91
|
+
/**
|
|
92
|
+
* Build the LLM prompt from file artifacts and task description.
|
|
93
|
+
*/
|
|
94
|
+
private buildPrompt;
|
|
95
|
+
/**
|
|
96
|
+
* Select files within the character budget, prioritizing smaller files.
|
|
97
|
+
*/
|
|
98
|
+
private selectFilesWithinBudget;
|
|
99
|
+
/**
|
|
100
|
+
* Parse the LLM response to extract file changes.
|
|
101
|
+
*/
|
|
102
|
+
private parseFileChanges;
|
|
103
|
+
/**
|
|
104
|
+
* Add a file change entry, comparing with existing content if the file exists.
|
|
105
|
+
*/
|
|
106
|
+
private addFileChange;
|
|
107
|
+
/**
|
|
108
|
+
* Validate file changes via AST syntax checking.
|
|
109
|
+
* Returns warning messages for any files with unbalanced syntax.
|
|
110
|
+
*/
|
|
111
|
+
private validateChanges;
|
|
112
|
+
/**
|
|
113
|
+
* Check if an error message indicates a rate-limit (429) error.
|
|
114
|
+
*/
|
|
115
|
+
private isRateLimitError;
|
|
116
|
+
/**
|
|
117
|
+
* Parse the "try again in Xs" hint from a rate-limit error response.
|
|
118
|
+
*/
|
|
119
|
+
private parseRetryAfterHint;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=edit-module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-module.d.ts","sourceRoot":"","sources":["../../src/agents/edit-module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AA+ClE,kDAAkD;AAClD,MAAM,WAAW,UAAU;IACzB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,gBAAgB,EAAE,MAAM,CAAC;IACzB,4DAA4D;IAC5D,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,4BAA4B;IAC5B,OAAO,EAAE,SAAS,CAAC;IACnB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iDAAiD;IACjD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mCAAmC;IACnC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,cAAc,CAAC;QAAC,OAAO,CAAC,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IACrM,wDAAwD;IACxD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,+BAA+B;AAC/B,MAAM,WAAW,UAAU;IACzB,6BAA6B;IAC7B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAID;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC/C;AAID;;;;;;GAMG;AACH,qBAAa,iBAAkB,YAAW,UAAU;IAClD,sDAAsD;IACtD,OAAO,CAAC,QAAQ,CAAW;gBAEf,QAAQ,CAAC,EAAE,QAAQ;IAI/B;;OAEG;IACG,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAuInD;;OAEG;IACH,OAAO,CAAC,WAAW;IA4CnB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAqC/B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAsBxB;;OAEG;IACH,OAAO,CAAC,aAAa;IA6BrB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAoBvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAIxB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAe5B"}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EditModule — Generates code changes from task descriptions and file context.
|
|
3
|
+
* Phase 7 of the architecture migration: extract from WriterAgent into
|
|
4
|
+
* a pluggable module with EventBus integration.
|
|
5
|
+
*
|
|
6
|
+
* The module reads relevant files, calls an LLM to generate modified versions,
|
|
7
|
+
* parses file changes from the response, validates syntax via AST analysis,
|
|
8
|
+
* and returns structured FileChange objects — without writing to disk.
|
|
9
|
+
*
|
|
10
|
+
* @see ARCHITECTURE.md §3.3 — Edit Module specification
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
13
|
+
import { isAbsolute, join } from 'node:path';
|
|
14
|
+
import { getEventBus, EventNames } from '../observability/event-bus.js';
|
|
15
|
+
import { detectLanguage } from '../editing/types.js';
|
|
16
|
+
import { validateSyntax } from '../editing/ast.js';
|
|
17
|
+
import { buildStructuralContext } from '../editing/edit.js';
|
|
18
|
+
// ─── Constants ──────────────────────────────────────────────────────────────
|
|
19
|
+
const EDIT_SYSTEM_PROMPT = `You are an expert software engineer implementing changes to a codebase.
|
|
20
|
+
|
|
21
|
+
Given file contents and an implementation task, you will:
|
|
22
|
+
1. Read the current file content carefully
|
|
23
|
+
2. Implement the requested changes
|
|
24
|
+
3. Return the COMPLETE updated file content for EACH modified file
|
|
25
|
+
|
|
26
|
+
## Output Format (MANDATORY)
|
|
27
|
+
|
|
28
|
+
Wrap EACH file you modify in its own code block. The file path MUST go right after the opening backticks with the prefix "filepath:".
|
|
29
|
+
|
|
30
|
+
CORRECT (use this format):
|
|
31
|
+
\`\`\`filepath:path/to/file.ts
|
|
32
|
+
// FULL updated file content here
|
|
33
|
+
\`\`\`
|
|
34
|
+
|
|
35
|
+
INCORRECT (do NOT use these):
|
|
36
|
+
- ❌ \`\`\`typescript\n...\n\`\`\` (missing filepath)
|
|
37
|
+
- ❌ \`\`\`\n...\n\`\`\` (missing language and filepath)
|
|
38
|
+
- ❌ Just describing the changes instead of returning the file
|
|
39
|
+
|
|
40
|
+
## Rules
|
|
41
|
+
- Return the FULL file content, not just the changed parts
|
|
42
|
+
- Preserve existing code style and conventions
|
|
43
|
+
- Add appropriate error handling
|
|
44
|
+
- Write clean, well-documented code
|
|
45
|
+
- If you modify multiple files, return ONE code block per file
|
|
46
|
+
`;
|
|
47
|
+
/** Maximum files to include in a single edit prompt */
|
|
48
|
+
const MAX_CONTEXT_FILES = 10;
|
|
49
|
+
/** Maximum total characters across all files sent to the LLM */
|
|
50
|
+
const MAX_CONTEXT_CHARS = 16_000;
|
|
51
|
+
/** Overhead per file in characters for formatting/path prefix */
|
|
52
|
+
const OVERHEAD_PER_FILE = 50;
|
|
53
|
+
// ─── Default EditModule ─────────────────────────────────────────────────────
|
|
54
|
+
/**
|
|
55
|
+
* DefaultEditModule — Built-in edit module implementation.
|
|
56
|
+
*
|
|
57
|
+
* Builds a prompt from file artifacts and task description; calls the LLM;
|
|
58
|
+
* parses file changes from the response; validates syntax via AST analysis;
|
|
59
|
+
* and returns structured FileChange objects without writing to disk.
|
|
60
|
+
*/
|
|
61
|
+
export class DefaultEditModule {
|
|
62
|
+
/** The event bus for emitting observability events */
|
|
63
|
+
eventBus;
|
|
64
|
+
constructor(eventBus) {
|
|
65
|
+
this.eventBus = eventBus ?? getEventBus();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Generate file changes from the given task and file context.
|
|
69
|
+
*/
|
|
70
|
+
async edit(params) {
|
|
71
|
+
const { goal, workingDirectory, artifacts, callLLM: initialCallLLM, taskDescription, mcpToolsFormatted, onRateLimit, isRetry } = params;
|
|
72
|
+
let currentCallLLM = initialCallLLM;
|
|
73
|
+
// ── Emit: edit generating ──────────────────────────────────────────
|
|
74
|
+
this.eventBus.emit(EventNames.EDIT_GENERATING, {
|
|
75
|
+
goal,
|
|
76
|
+
artifactCount: artifacts.length,
|
|
77
|
+
isRetry: isRetry ?? false,
|
|
78
|
+
}, 'edit-module');
|
|
79
|
+
// Try up to 2 API attempts
|
|
80
|
+
let lastError;
|
|
81
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
82
|
+
try {
|
|
83
|
+
const effectiveIsRetry = attempt > 0 ? true : (isRetry ?? false);
|
|
84
|
+
const prompt = this.buildPrompt(goal, workingDirectory, artifacts, taskDescription, mcpToolsFormatted, effectiveIsRetry);
|
|
85
|
+
const response = await currentCallLLM(prompt, {
|
|
86
|
+
temperature: effectiveIsRetry ? 0.1 : 0.3,
|
|
87
|
+
maxTokens: 4096,
|
|
88
|
+
});
|
|
89
|
+
const fileChanges = this.parseFileChanges(response, workingDirectory);
|
|
90
|
+
const warnings = this.validateChanges(fileChanges);
|
|
91
|
+
// Emit: per-file written events
|
|
92
|
+
for (const change of fileChanges) {
|
|
93
|
+
if (change.newContent) {
|
|
94
|
+
this.eventBus.emit(EventNames.EDIT_WRITTEN, {
|
|
95
|
+
path: change.path,
|
|
96
|
+
status: change.status,
|
|
97
|
+
bytes: change.newContent.length,
|
|
98
|
+
}, 'edit-module');
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
this.eventBus.emit(EventNames.EDIT_SKIPPED, {
|
|
102
|
+
path: change.path,
|
|
103
|
+
reason: 'no new content',
|
|
104
|
+
}, 'edit-module');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const count = fileChanges.length;
|
|
108
|
+
if (count === 0) {
|
|
109
|
+
// Emit empty result
|
|
110
|
+
const excerpt = response.slice(0, 300).replace(/\n/g, '\\n');
|
|
111
|
+
// If first attempt returned empty, retry with stricter prompt
|
|
112
|
+
if (attempt === 0) {
|
|
113
|
+
this.eventBus.emit(EventNames.EDIT_GENERATING, {
|
|
114
|
+
goal,
|
|
115
|
+
artifactCount: artifacts.length,
|
|
116
|
+
isRetry: true,
|
|
117
|
+
reason: 'empty-parse-retry',
|
|
118
|
+
}, 'edit-module');
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
changes: [],
|
|
123
|
+
summary: 'No files needed changes',
|
|
124
|
+
changeCount: 0,
|
|
125
|
+
warnings: ['LLM produced no parseable file changes'],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return { changes: fileChanges, summary: `Proposed changes to ${count} file${count !== 1 ? 's' : ''}`, changeCount: count, warnings: warnings.length > 0 ? warnings : undefined };
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
lastError = err instanceof Error ? err.message : String(err);
|
|
132
|
+
// Handle rate limit
|
|
133
|
+
if (onRateLimit && this.isRateLimitError(lastError)) {
|
|
134
|
+
const retryAfterMs = this.parseRetryAfterHint(lastError) || 5000;
|
|
135
|
+
const action = await onRateLimit({
|
|
136
|
+
retryAfterMs,
|
|
137
|
+
agentName: 'EditModule',
|
|
138
|
+
errorMessage: lastError.slice(0, 300),
|
|
139
|
+
});
|
|
140
|
+
if (action.action === 'abort') {
|
|
141
|
+
return {
|
|
142
|
+
changes: [],
|
|
143
|
+
summary: 'Edit aborted by user due to rate limit',
|
|
144
|
+
changeCount: 0,
|
|
145
|
+
warnings: [lastError],
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (action.action === 'skip') {
|
|
149
|
+
return {
|
|
150
|
+
changes: [],
|
|
151
|
+
summary: 'Skipped by user (rate limit)',
|
|
152
|
+
changeCount: 0,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (action.action === 'switch-model' && action.callLLM) {
|
|
156
|
+
// Retry with new callLLM
|
|
157
|
+
currentCallLLM = action.callLLM;
|
|
158
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
// 'retry': wait and retry
|
|
162
|
+
await new Promise((resolve) => setTimeout(resolve, retryAfterMs));
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (attempt === 0) {
|
|
166
|
+
// Transient error — retry once
|
|
167
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
// All attempts exhausted
|
|
171
|
+
return {
|
|
172
|
+
changes: [],
|
|
173
|
+
summary: 'Edit failed to generate changes',
|
|
174
|
+
changeCount: 0,
|
|
175
|
+
warnings: [lastError],
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
changes: [],
|
|
181
|
+
summary: 'Edit failed after retries',
|
|
182
|
+
changeCount: 0,
|
|
183
|
+
warnings: lastError ? [lastError] : undefined,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
// ─── Prompt Building ─────────────────────────────────────────────────
|
|
187
|
+
/**
|
|
188
|
+
* Build the LLM prompt from file artifacts and task description.
|
|
189
|
+
*/
|
|
190
|
+
buildPrompt(goal, workingDirectory, artifacts, taskDescription, mcpToolsFormatted, isRetry = false) {
|
|
191
|
+
const taskDesc = taskDescription || goal;
|
|
192
|
+
// Select files within the character budget
|
|
193
|
+
const filesToSend = this.selectFilesWithinBudget(artifacts, MAX_CONTEXT_CHARS);
|
|
194
|
+
const fileContext = filesToSend.length > 0
|
|
195
|
+
? filesToSend
|
|
196
|
+
.map(({ artifact, truncated }) => `--- ${artifact.path} ---${truncated ? ` (truncated, ${artifact.content.length}\u2192${truncated.length} chars)` : ''}\n${truncated || artifact.content}`)
|
|
197
|
+
.join('\n\n') +
|
|
198
|
+
(artifacts.length > filesToSend.length
|
|
199
|
+
? `\n\n... and ${artifacts.length - filesToSend.length} more files in the project (excluded to fit token budget)`
|
|
200
|
+
: '')
|
|
201
|
+
: '(No files found in context — you may need to create new files)';
|
|
202
|
+
// Build structural context for AST-aware editing
|
|
203
|
+
const structuralContexts = artifacts
|
|
204
|
+
.filter((a) => a.content)
|
|
205
|
+
.slice(0, 5)
|
|
206
|
+
.map((a) => buildStructuralContext(a.content, a.path))
|
|
207
|
+
.filter((s) => s.length > 0);
|
|
208
|
+
const structureSection = structuralContexts.length > 0
|
|
209
|
+
? `\n## File Structure Overview\n\nHere is the structural layout of the files you need to modify.\nUse these line ranges to understand where each function/class lives.\n\n${structuralContexts.join('\n\n')}\n`
|
|
210
|
+
: '';
|
|
211
|
+
const mcpSection = mcpToolsFormatted ? `\n${mcpToolsFormatted}\n` : '';
|
|
212
|
+
const instructions = isRetry
|
|
213
|
+
? `\n## CRITICAL — Read This Carefully\nThe previous response could not be parsed because the files were not wrapped in correctly formatted code blocks.\n\nYou MUST follow this format EXACTLY for EACH file you modify:\n\n\`\`\`filepath:src/example.ts\n// THE COMPLETE UPDATED FILE CONTENT GOES HERE (every line, full file)\n\`\`\`\n\nIMPORTANT:\n- The filepath: prefix is REQUIRED after the opening backticks\n- Return the FULL file, not a diff or snippet\n- If you modify 2 files, return 2 separate code blocks in this format`
|
|
214
|
+
: `\n## Instructions\nImplement the changes described in the task. Return the complete updated file content for each file you modify. Remember: each file must be wrapped in \`\`\`filepath:...\n\`\`\` format.`;
|
|
215
|
+
return `${EDIT_SYSTEM_PROMPT}\n\n## Task Description\n${taskDesc}\n\n## Working Directory\n${workingDirectory}\n\n## Current File Content\n${fileContext}${structureSection}${mcpSection}\n${instructions}`;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Select files within the character budget, prioritizing smaller files.
|
|
219
|
+
*/
|
|
220
|
+
selectFilesWithinBudget(artifacts, budget) {
|
|
221
|
+
const sorted = [...artifacts]
|
|
222
|
+
.map((a) => ({ artifact: a, size: a.content.length }))
|
|
223
|
+
.sort((a, b) => a.size - b.size);
|
|
224
|
+
const result = [];
|
|
225
|
+
let used = 0;
|
|
226
|
+
for (const { artifact, size } of sorted) {
|
|
227
|
+
if (result.length >= MAX_CONTEXT_FILES)
|
|
228
|
+
break;
|
|
229
|
+
const totalNeeded = size + OVERHEAD_PER_FILE;
|
|
230
|
+
if (used + totalNeeded <= budget) {
|
|
231
|
+
result.push({ artifact, truncated: null });
|
|
232
|
+
used += totalNeeded;
|
|
233
|
+
}
|
|
234
|
+
else if (used + OVERHEAD_PER_FILE < budget) {
|
|
235
|
+
const remaining = budget - used - OVERHEAD_PER_FILE;
|
|
236
|
+
if (remaining > 200) {
|
|
237
|
+
const truncated = artifact.content.slice(0, remaining);
|
|
238
|
+
result.push({ artifact, truncated });
|
|
239
|
+
used = budget;
|
|
240
|
+
}
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
// ─── File Change Parsing ─────────────────────────────────────────────
|
|
250
|
+
/**
|
|
251
|
+
* Parse the LLM response to extract file changes.
|
|
252
|
+
*/
|
|
253
|
+
parseFileChanges(response, workingDir) {
|
|
254
|
+
const changes = [];
|
|
255
|
+
// Match code blocks containing a real file path
|
|
256
|
+
const blockRegex = /```(?:[a-zA-Z0-9+#]*\s+)?(?:filepath:)?([^\n`]+(?:\.[a-zA-Z0-9]+|\/[^\n`]+))\n([\s\S]*?)```/g;
|
|
257
|
+
let match;
|
|
258
|
+
while ((match = blockRegex.exec(response)) !== null) {
|
|
259
|
+
let filePath = match[1].trim();
|
|
260
|
+
const content = match[2].trim();
|
|
261
|
+
// Clean up the file path
|
|
262
|
+
filePath = filePath.replace(/^['"]|['"]$/g, '').trim();
|
|
263
|
+
if (!filePath || !content)
|
|
264
|
+
continue;
|
|
265
|
+
this.addFileChange(changes, filePath, content, workingDir);
|
|
266
|
+
}
|
|
267
|
+
return changes;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Add a file change entry, comparing with existing content if the file exists.
|
|
271
|
+
*/
|
|
272
|
+
addFileChange(changes, filePath, content, workingDir) {
|
|
273
|
+
const absolutePath = isAbsolute(filePath) ? filePath : join(workingDir, filePath);
|
|
274
|
+
if (existsSync(absolutePath)) {
|
|
275
|
+
const originalContent = readFileSync(absolutePath, 'utf-8');
|
|
276
|
+
if (originalContent.trim() !== content.trim()) {
|
|
277
|
+
changes.push({
|
|
278
|
+
path: filePath,
|
|
279
|
+
originalContent,
|
|
280
|
+
newContent: content,
|
|
281
|
+
status: 'modified',
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
changes.push({
|
|
287
|
+
path: filePath,
|
|
288
|
+
newContent: content,
|
|
289
|
+
status: 'created',
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// ─── Validation ──────────────────────────────────────────────────────
|
|
294
|
+
/**
|
|
295
|
+
* Validate file changes via AST syntax checking.
|
|
296
|
+
* Returns warning messages for any files with unbalanced syntax.
|
|
297
|
+
*/
|
|
298
|
+
validateChanges(changes) {
|
|
299
|
+
const warnings = [];
|
|
300
|
+
for (const change of changes) {
|
|
301
|
+
if (change.newContent) {
|
|
302
|
+
const lang = detectLanguage(change.path);
|
|
303
|
+
if (lang !== 'unknown') {
|
|
304
|
+
const isValid = validateSyntax(change.newContent, lang);
|
|
305
|
+
if (!isValid) {
|
|
306
|
+
warnings.push(`Syntax warning: ${change.path} has unbalanced brackets`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return warnings;
|
|
312
|
+
}
|
|
313
|
+
// ─── Rate Limit Helpers ──────────────────────────────────────────────
|
|
314
|
+
/**
|
|
315
|
+
* Check if an error message indicates a rate-limit (429) error.
|
|
316
|
+
*/
|
|
317
|
+
isRateLimitError(errorMessage) {
|
|
318
|
+
return /rate\s*limit|429|too many requests|try again in/i.test(errorMessage);
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Parse the "try again in Xs" hint from a rate-limit error response.
|
|
322
|
+
*/
|
|
323
|
+
parseRetryAfterHint(errorMessage) {
|
|
324
|
+
const secondMatch = errorMessage.match(/try again in ([\d.]+)s/i);
|
|
325
|
+
if (secondMatch) {
|
|
326
|
+
const seconds = parseFloat(secondMatch[1]);
|
|
327
|
+
if (!isNaN(seconds) && seconds > 0)
|
|
328
|
+
return Math.ceil(seconds * 1000);
|
|
329
|
+
}
|
|
330
|
+
const msMatch = errorMessage.match(/try again in (\d+)ms/i);
|
|
331
|
+
if (msMatch) {
|
|
332
|
+
const ms = parseInt(msMatch[1], 10);
|
|
333
|
+
if (!isNaN(ms) && ms > 0)
|
|
334
|
+
return ms;
|
|
335
|
+
}
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
//# sourceMappingURL=edit-module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-module.js","sourceRoot":"","sources":["../../src/agents/edit-module.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PipelineAudit — Deterministic action audit trail for the task execution pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Records every action taken during pipeline execution so that:
|
|
5
|
+
* 1. The entire execution can be replayed for debugging
|
|
6
|
+
* 2. Each step has a complete before/after snapshot
|
|
7
|
+
* 3. Failed executions can be analyzed step-by-step
|
|
8
|
+
* 4. The audit log can be serialized to JSON for persistence
|
|
9
|
+
*
|
|
10
|
+
* @see ARCHITECTURE.md §4.3 — Safe Execution Layer
|
|
11
|
+
*/
|
|
12
|
+
/** Severity level for an audit entry */
|
|
13
|
+
export type AuditSeverity = 'info' | 'warning' | 'error' | 'success';
|
|
14
|
+
/** A single entry in the audit trail */
|
|
15
|
+
export interface AuditEntry {
|
|
16
|
+
/** Unique entry ID (monotonic counter) */
|
|
17
|
+
id: number;
|
|
18
|
+
/** Timestamp when the action occurred */
|
|
19
|
+
timestamp: string;
|
|
20
|
+
/** Which pipeline step produced this entry */
|
|
21
|
+
step: string;
|
|
22
|
+
/** Short action label (e.g. 'plan:started', 'edit:file-written') */
|
|
23
|
+
action: string;
|
|
24
|
+
/** Severity level */
|
|
25
|
+
severity: AuditSeverity;
|
|
26
|
+
/** Human-readable message */
|
|
27
|
+
message: string;
|
|
28
|
+
/** Optional structured metadata for replay */
|
|
29
|
+
metadata?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
/** Snapshot of state at a given point in the pipeline */
|
|
32
|
+
export interface PipelineSnapshot {
|
|
33
|
+
/** Step number (0-based) */
|
|
34
|
+
stepIndex: number;
|
|
35
|
+
/** Step name */
|
|
36
|
+
stepName: string;
|
|
37
|
+
/** When the snapshot was taken */
|
|
38
|
+
timestamp: string;
|
|
39
|
+
/** Number of file changes so far */
|
|
40
|
+
fileChangeCount: number;
|
|
41
|
+
/** Key metrics at this point */
|
|
42
|
+
metrics: {
|
|
43
|
+
artifactsCollected: number;
|
|
44
|
+
filesChanged: number;
|
|
45
|
+
testsPassed: number;
|
|
46
|
+
testsFailed: number;
|
|
47
|
+
durationMs: number;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Full audit trail for a single pipeline execution */
|
|
51
|
+
export interface AuditTrail {
|
|
52
|
+
/** Pipeline execution ID */
|
|
53
|
+
pipelineId: string;
|
|
54
|
+
/** The user's goal */
|
|
55
|
+
goal: string;
|
|
56
|
+
/** When the pipeline started */
|
|
57
|
+
startedAt: string;
|
|
58
|
+
/** All audit entries in chronological order */
|
|
59
|
+
entries: AuditEntry[];
|
|
60
|
+
/** State snapshots taken at each step boundary */
|
|
61
|
+
snapshots: PipelineSnapshot[];
|
|
62
|
+
/** Whether the pipeline completed successfully */
|
|
63
|
+
success: boolean;
|
|
64
|
+
/** When the pipeline ended */
|
|
65
|
+
endedAt?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* PipelineAudit — Records every action during task execution.
|
|
69
|
+
*
|
|
70
|
+
* Usage:
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const audit = new PipelineAudit('exec-001', 'Add JWT auth');
|
|
73
|
+
* audit.log('plan', 'plan:started', 'info', 'Decomposing goal...');
|
|
74
|
+
* // ... later
|
|
75
|
+
* const trail = audit.snapshot('plan', { artifactsCollected: 5, ... });
|
|
76
|
+
* audit.complete(true);
|
|
77
|
+
* const json = audit.serialize();
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare class PipelineAudit {
|
|
81
|
+
private entryId;
|
|
82
|
+
private startTime;
|
|
83
|
+
private trail;
|
|
84
|
+
constructor(pipelineId: string, goal: string);
|
|
85
|
+
/**
|
|
86
|
+
* Log an action to the audit trail.
|
|
87
|
+
*/
|
|
88
|
+
log(step: string, action: string, severity: AuditSeverity, message: string, metadata?: Record<string, unknown>): void;
|
|
89
|
+
/**
|
|
90
|
+
* Record a pipeline state snapshot at a step boundary.
|
|
91
|
+
*/
|
|
92
|
+
snapshot(stepIndex: number, stepName: string, metrics: {
|
|
93
|
+
artifactsCollected: number;
|
|
94
|
+
filesChanged: number;
|
|
95
|
+
testsPassed: number;
|
|
96
|
+
testsFailed: number;
|
|
97
|
+
}): PipelineSnapshot;
|
|
98
|
+
/**
|
|
99
|
+
* Mark the pipeline as completed (success or failure).
|
|
100
|
+
*/
|
|
101
|
+
complete(success: boolean): void;
|
|
102
|
+
/**
|
|
103
|
+
* Get the full audit trail.
|
|
104
|
+
*/
|
|
105
|
+
getTrail(): AuditTrail;
|
|
106
|
+
/**
|
|
107
|
+
* Get entries filtered by step name.
|
|
108
|
+
*/
|
|
109
|
+
getEntriesByStep(step: string): AuditEntry[];
|
|
110
|
+
/**
|
|
111
|
+
* Get entries with error severity.
|
|
112
|
+
*/
|
|
113
|
+
getErrors(): AuditEntry[];
|
|
114
|
+
/**
|
|
115
|
+
* Serialize the audit trail to a JSON string.
|
|
116
|
+
*/
|
|
117
|
+
serialize(): string;
|
|
118
|
+
/**
|
|
119
|
+
* Replay the audit entries as a human-readable log.
|
|
120
|
+
* Useful for debugging or post-mortem analysis.
|
|
121
|
+
*/
|
|
122
|
+
replay(): string;
|
|
123
|
+
/**
|
|
124
|
+
* Get the elapsed time as a human-readable string.
|
|
125
|
+
*/
|
|
126
|
+
private elapsed;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=pipeline-audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-audit.d.ts","sourceRoot":"","sources":["../../src/agents/pipeline-audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,wCAAwC;AACxC,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAErE,wCAAwC;AACxC,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,EAAE,EAAE,MAAM,CAAC;IACX,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,EAAE,aAAa,CAAC;IACxB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,yDAAyD;AACzD,MAAM,WAAW,gBAAgB;IAC/B,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,eAAe,EAAE,MAAM,CAAC;IACxB,gCAAgC;IAChC,OAAO,EAAE;QACP,kBAAkB,EAAE,MAAM,CAAC;QAC3B,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,uDAAuD;AACvD,MAAM,WAAW,UAAU;IACzB,4BAA4B;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,kDAAkD;IAClD,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,kDAAkD;IAClD,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID;;;;;;;;;;;;GAYG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAa;gBAEd,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAY5C;;OAEG;IACH,GAAG,CACD,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,IAAI;IAYP;;OAEG;IACH,QAAQ,CACN,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;QACP,kBAAkB,EAAE,MAAM,CAAC;QAC3B,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;KACrB,GACA,gBAAgB;IAenB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAchC;;OAEG;IACH,QAAQ,IAAI,UAAU;IAItB;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE;IAI5C;;OAEG;IACH,SAAS,IAAI,UAAU,EAAE;IAIzB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;;OAGG;IACH,MAAM,IAAI,MAAM;IAsChB;;OAEG;IACH,OAAO,CAAC,OAAO;CAGhB"}
|