@posthog/agent 1.5.0 → 1.6.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/src/prompt-builder.d.ts +16 -2
- package/dist/src/prompt-builder.d.ts.map +1 -1
- package/dist/src/prompt-builder.js +77 -5
- package/dist/src/prompt-builder.js.map +1 -1
- package/dist/src/stage-executor.js +2 -2
- package/dist/src/stage-executor.js.map +1 -1
- package/package.json +1 -1
- package/src/prompt-builder.ts +101 -5
- package/src/stage-executor.ts +2 -2
|
@@ -11,7 +11,21 @@ export declare class PromptBuilder {
|
|
|
11
11
|
private generatePlanTemplate;
|
|
12
12
|
private logger;
|
|
13
13
|
constructor(deps: PromptBuilderDeps);
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Extract file paths from XML tags in description
|
|
16
|
+
* Format: <file path="relative/path.ts" />
|
|
17
|
+
*/
|
|
18
|
+
private extractFilePaths;
|
|
19
|
+
/**
|
|
20
|
+
* Read file contents from repository
|
|
21
|
+
*/
|
|
22
|
+
private readFileContent;
|
|
23
|
+
/**
|
|
24
|
+
* Process description to extract file tags and read contents
|
|
25
|
+
* Returns processed description and referenced file contents
|
|
26
|
+
*/
|
|
27
|
+
private processFileReferences;
|
|
28
|
+
buildPlanningPrompt(task: Task, repositoryPath?: string): Promise<string>;
|
|
29
|
+
buildExecutionPrompt(task: Task, repositoryPath?: string): Promise<string>;
|
|
16
30
|
}
|
|
17
31
|
//# sourceMappingURL=prompt-builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../../src/prompt-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../../src/prompt-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAI3C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACjD,oBAAoB,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,oBAAoB,CAA4C;IACxE,OAAO,CAAC,MAAM,CAAS;gBAEX,IAAI,EAAE,iBAAiB;IAMnC;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAYxB;;OAEG;YACW,eAAe;IAW7B;;;OAGG;YACW,qBAAqB;IAgC7B,mBAAmB,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkDzE,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CA8CjF"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Logger } from './utils/logger.js';
|
|
2
|
+
import { promises } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
2
4
|
|
|
3
5
|
class PromptBuilder {
|
|
4
6
|
getTaskFiles;
|
|
@@ -9,12 +11,73 @@ class PromptBuilder {
|
|
|
9
11
|
this.generatePlanTemplate = deps.generatePlanTemplate;
|
|
10
12
|
this.logger = deps.logger || new Logger({ debug: false, prefix: '[PromptBuilder]' });
|
|
11
13
|
}
|
|
12
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Extract file paths from XML tags in description
|
|
16
|
+
* Format: <file path="relative/path.ts" />
|
|
17
|
+
*/
|
|
18
|
+
extractFilePaths(description) {
|
|
19
|
+
const fileTagRegex = /<file\s+path="([^"]+)"\s*\/>/g;
|
|
20
|
+
const paths = [];
|
|
21
|
+
let match;
|
|
22
|
+
while ((match = fileTagRegex.exec(description)) !== null) {
|
|
23
|
+
paths.push(match[1]);
|
|
24
|
+
}
|
|
25
|
+
return paths;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Read file contents from repository
|
|
29
|
+
*/
|
|
30
|
+
async readFileContent(repositoryPath, filePath) {
|
|
31
|
+
try {
|
|
32
|
+
const fullPath = join(repositoryPath, filePath);
|
|
33
|
+
const content = await promises.readFile(fullPath, 'utf8');
|
|
34
|
+
return content;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
this.logger.warn(`Failed to read referenced file: ${filePath}`, { error });
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Process description to extract file tags and read contents
|
|
43
|
+
* Returns processed description and referenced file contents
|
|
44
|
+
*/
|
|
45
|
+
async processFileReferences(description, repositoryPath) {
|
|
46
|
+
const filePaths = this.extractFilePaths(description);
|
|
47
|
+
const referencedFiles = [];
|
|
48
|
+
if (filePaths.length === 0 || !repositoryPath) {
|
|
49
|
+
return { description, referencedFiles };
|
|
50
|
+
}
|
|
51
|
+
// Read all referenced files
|
|
52
|
+
for (const filePath of filePaths) {
|
|
53
|
+
const content = await this.readFileContent(repositoryPath, filePath);
|
|
54
|
+
if (content !== null) {
|
|
55
|
+
referencedFiles.push({ path: filePath, content });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Replace file tags with just the filename for readability
|
|
59
|
+
let processedDescription = description;
|
|
60
|
+
for (const filePath of filePaths) {
|
|
61
|
+
const fileName = filePath.split('/').pop() || filePath;
|
|
62
|
+
processedDescription = processedDescription.replace(new RegExp(`<file\\s+path="${filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}"\\s*/>`, 'g'), `@${fileName}`);
|
|
63
|
+
}
|
|
64
|
+
return { description: processedDescription, referencedFiles };
|
|
65
|
+
}
|
|
66
|
+
async buildPlanningPrompt(task, repositoryPath) {
|
|
67
|
+
// Process file references in description
|
|
68
|
+
const { description: processedDescription, referencedFiles } = await this.processFileReferences(task.description, repositoryPath);
|
|
13
69
|
let prompt = '';
|
|
14
|
-
prompt += `## Current Task\n\n**Task**: ${task.title}\n**Description**: ${
|
|
70
|
+
prompt += `## Current Task\n\n**Task**: ${task.title}\n**Description**: ${processedDescription}`;
|
|
15
71
|
if (task.primary_repository) {
|
|
16
72
|
prompt += `\n**Repository**: ${task.primary_repository}`;
|
|
17
73
|
}
|
|
74
|
+
// Add referenced files from @ mentions
|
|
75
|
+
if (referencedFiles.length > 0) {
|
|
76
|
+
prompt += `\n\n## Referenced Files\n\n`;
|
|
77
|
+
for (const file of referencedFiles) {
|
|
78
|
+
prompt += `### ${file.path}\n\`\`\`\n${file.content}\n\`\`\`\n\n`;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
18
81
|
try {
|
|
19
82
|
const taskFiles = await this.getTaskFiles(task.id);
|
|
20
83
|
const contextFiles = taskFiles.filter((f) => f.type === 'context' || f.type === 'reference');
|
|
@@ -31,7 +94,7 @@ class PromptBuilder {
|
|
|
31
94
|
const templateVariables = {
|
|
32
95
|
task_id: task.id,
|
|
33
96
|
task_title: task.title,
|
|
34
|
-
task_description:
|
|
97
|
+
task_description: processedDescription,
|
|
35
98
|
date: new Date().toISOString().split('T')[0],
|
|
36
99
|
repository: (task.primary_repository || ''),
|
|
37
100
|
};
|
|
@@ -39,12 +102,21 @@ class PromptBuilder {
|
|
|
39
102
|
prompt += `\n\nPlease analyze the codebase and create a detailed implementation plan for this task. Use the following template structure for your plan:\n\n${planTemplate}\n\nFill in each section with specific, actionable information based on your analysis. Replace all placeholder content with actual details about this task.`;
|
|
40
103
|
return prompt;
|
|
41
104
|
}
|
|
42
|
-
async buildExecutionPrompt(task) {
|
|
105
|
+
async buildExecutionPrompt(task, repositoryPath) {
|
|
106
|
+
// Process file references in description
|
|
107
|
+
const { description: processedDescription, referencedFiles } = await this.processFileReferences(task.description, repositoryPath);
|
|
43
108
|
let prompt = '';
|
|
44
|
-
prompt += `## Current Task\n\n**Task**: ${task.title}\n**Description**: ${
|
|
109
|
+
prompt += `## Current Task\n\n**Task**: ${task.title}\n**Description**: ${processedDescription}`;
|
|
45
110
|
if (task.primary_repository) {
|
|
46
111
|
prompt += `\n**Repository**: ${task.primary_repository}`;
|
|
47
112
|
}
|
|
113
|
+
// Add referenced files from @ mentions
|
|
114
|
+
if (referencedFiles.length > 0) {
|
|
115
|
+
prompt += `\n\n## Referenced Files\n\n`;
|
|
116
|
+
for (const file of referencedFiles) {
|
|
117
|
+
prompt += `### ${file.path}\n\`\`\`\n${file.content}\n\`\`\`\n\n`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
48
120
|
try {
|
|
49
121
|
const taskFiles = await this.getTaskFiles(task.id);
|
|
50
122
|
const hasPlan = taskFiles.some((f) => f.type === 'plan');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-builder.js","sources":["../../src/prompt-builder.ts"],"sourcesContent":["import type { Task } from './types.js';\nimport type { TemplateVariables } from './template-manager.js';\nimport { Logger } from './utils/logger.js';\n\nexport interface PromptBuilderDeps {\n getTaskFiles: (taskId: string) => Promise<any[]>;\n generatePlanTemplate: (vars: TemplateVariables) => Promise<string>;\n logger?: Logger;\n}\n\nexport class PromptBuilder {\n private getTaskFiles: PromptBuilderDeps['getTaskFiles'];\n private generatePlanTemplate: PromptBuilderDeps['generatePlanTemplate'];\n private logger: Logger;\n\n constructor(deps: PromptBuilderDeps) {\n this.getTaskFiles = deps.getTaskFiles;\n this.generatePlanTemplate = deps.generatePlanTemplate;\n this.logger = deps.logger || new Logger({ debug: false, prefix: '[PromptBuilder]' });\n }\n\n async buildPlanningPrompt(task: Task): Promise<string> {\n let prompt = '';\n prompt += `## Current Task\\n\\n**Task**: ${task.title}\\n**Description**: ${task.description}`;\n\n if ((task as any).primary_repository) {\n prompt += `\\n**Repository**: ${(task as any).primary_repository}`;\n }\n\n try {\n const taskFiles = await this.getTaskFiles(task.id);\n const contextFiles = taskFiles.filter((f: any) => f.type === 'context' || f.type === 'reference');\n if (contextFiles.length > 0) {\n prompt += `\\n\\n## Supporting Files`;\n for (const file of contextFiles) {\n prompt += `\\n\\n### ${file.name} (${file.type})\\n${file.content}`;\n }\n }\n } catch (error) {\n this.logger.debug('No existing task files found for planning', { taskId: task.id });\n }\n\n const templateVariables = {\n task_id: task.id,\n task_title: task.title,\n task_description: task.description,\n date: new Date().toISOString().split('T')[0],\n repository: ((task as any).primary_repository || '') as string,\n };\n\n const planTemplate = await this.generatePlanTemplate(templateVariables);\n\n prompt += `\\n\\nPlease analyze the codebase and create a detailed implementation plan for this task. Use the following template structure for your plan:\\n\\n${planTemplate}\\n\\nFill in each section with specific, actionable information based on your analysis. Replace all placeholder content with actual details about this task.`;\n\n return prompt;\n }\n\n async buildExecutionPrompt(task: Task): Promise<string> {\n let prompt = '';\n prompt += `## Current Task\\n\\n**Task**: ${task.title}\\n**Description**: ${task.description}`;\n\n if ((task as any).primary_repository) {\n prompt += `\\n**Repository**: ${(task as any).primary_repository}`;\n }\n\n try {\n const taskFiles = await this.getTaskFiles(task.id);\n const hasPlan = taskFiles.some((f: any) => f.type === 'plan');\n if (taskFiles.length > 0) {\n prompt += `\\n\\n## Context and Supporting Information`;\n for (const file of taskFiles) {\n if (file.type === 'plan') {\n prompt += `\\n\\n### Execution Plan\\n${file.content}`;\n } else {\n prompt += `\\n\\n### ${file.name} (${file.type})\\n${file.content}`;\n }\n }\n }\n if (hasPlan) {\n prompt += `\\n\\nPlease implement the changes described in the execution plan above. Follow the plan step-by-step and make the necessary file modifications. You must actually edit files and make changes - do not just analyze or review.`;\n } else {\n prompt += `\\n\\nPlease implement the changes described in the task above. You must actually edit files and make changes - do not just analyze or review.`;\n }\n } catch (error) {\n this.logger.debug('No supporting files found for execution', { taskId: task.id });\n prompt += `\\n\\nPlease implement the changes described in the task above.`;\n }\n return prompt;\n }\n}\n\n\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"prompt-builder.js","sources":["../../src/prompt-builder.ts"],"sourcesContent":["import type { Task } from './types.js';\nimport type { TemplateVariables } from './template-manager.js';\nimport { Logger } from './utils/logger.js';\nimport { promises as fs } from 'fs';\nimport { join } from 'path';\n\nexport interface PromptBuilderDeps {\n getTaskFiles: (taskId: string) => Promise<any[]>;\n generatePlanTemplate: (vars: TemplateVariables) => Promise<string>;\n logger?: Logger;\n}\n\nexport class PromptBuilder {\n private getTaskFiles: PromptBuilderDeps['getTaskFiles'];\n private generatePlanTemplate: PromptBuilderDeps['generatePlanTemplate'];\n private logger: Logger;\n\n constructor(deps: PromptBuilderDeps) {\n this.getTaskFiles = deps.getTaskFiles;\n this.generatePlanTemplate = deps.generatePlanTemplate;\n this.logger = deps.logger || new Logger({ debug: false, prefix: '[PromptBuilder]' });\n }\n\n /**\n * Extract file paths from XML tags in description\n * Format: <file path=\"relative/path.ts\" />\n */\n private extractFilePaths(description: string): string[] {\n const fileTagRegex = /<file\\s+path=\"([^\"]+)\"\\s*\\/>/g;\n const paths: string[] = [];\n let match: RegExpExecArray | null;\n\n while ((match = fileTagRegex.exec(description)) !== null) {\n paths.push(match[1]);\n }\n\n return paths;\n }\n\n /**\n * Read file contents from repository\n */\n private async readFileContent(repositoryPath: string, filePath: string): Promise<string | null> {\n try {\n const fullPath = join(repositoryPath, filePath);\n const content = await fs.readFile(fullPath, 'utf8');\n return content;\n } catch (error) {\n this.logger.warn(`Failed to read referenced file: ${filePath}`, { error });\n return null;\n }\n }\n\n /**\n * Process description to extract file tags and read contents\n * Returns processed description and referenced file contents\n */\n private async processFileReferences(\n description: string,\n repositoryPath?: string\n ): Promise<{ description: string; referencedFiles: Array<{ path: string; content: string }> }> {\n const filePaths = this.extractFilePaths(description);\n const referencedFiles: Array<{ path: string; content: string }> = [];\n\n if (filePaths.length === 0 || !repositoryPath) {\n return { description, referencedFiles };\n }\n\n // Read all referenced files\n for (const filePath of filePaths) {\n const content = await this.readFileContent(repositoryPath, filePath);\n if (content !== null) {\n referencedFiles.push({ path: filePath, content });\n }\n }\n\n // Replace file tags with just the filename for readability\n let processedDescription = description;\n for (const filePath of filePaths) {\n const fileName = filePath.split('/').pop() || filePath;\n processedDescription = processedDescription.replace(\n new RegExp(`<file\\\\s+path=\"${filePath.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\"\\\\s*/>`, 'g'),\n `@${fileName}`\n );\n }\n\n return { description: processedDescription, referencedFiles };\n }\n\n async buildPlanningPrompt(task: Task, repositoryPath?: string): Promise<string> {\n // Process file references in description\n const { description: processedDescription, referencedFiles } = await this.processFileReferences(\n task.description,\n repositoryPath\n );\n\n let prompt = '';\n prompt += `## Current Task\\n\\n**Task**: ${task.title}\\n**Description**: ${processedDescription}`;\n\n if ((task as any).primary_repository) {\n prompt += `\\n**Repository**: ${(task as any).primary_repository}`;\n }\n\n // Add referenced files from @ mentions\n if (referencedFiles.length > 0) {\n prompt += `\\n\\n## Referenced Files\\n\\n`;\n for (const file of referencedFiles) {\n prompt += `### ${file.path}\\n\\`\\`\\`\\n${file.content}\\n\\`\\`\\`\\n\\n`;\n }\n }\n\n try {\n const taskFiles = await this.getTaskFiles(task.id);\n const contextFiles = taskFiles.filter((f: any) => f.type === 'context' || f.type === 'reference');\n if (contextFiles.length > 0) {\n prompt += `\\n\\n## Supporting Files`;\n for (const file of contextFiles) {\n prompt += `\\n\\n### ${file.name} (${file.type})\\n${file.content}`;\n }\n }\n } catch (error) {\n this.logger.debug('No existing task files found for planning', { taskId: task.id });\n }\n\n const templateVariables = {\n task_id: task.id,\n task_title: task.title,\n task_description: processedDescription,\n date: new Date().toISOString().split('T')[0],\n repository: ((task as any).primary_repository || '') as string,\n };\n\n const planTemplate = await this.generatePlanTemplate(templateVariables);\n\n prompt += `\\n\\nPlease analyze the codebase and create a detailed implementation plan for this task. Use the following template structure for your plan:\\n\\n${planTemplate}\\n\\nFill in each section with specific, actionable information based on your analysis. Replace all placeholder content with actual details about this task.`;\n\n return prompt;\n }\n\n async buildExecutionPrompt(task: Task, repositoryPath?: string): Promise<string> {\n // Process file references in description\n const { description: processedDescription, referencedFiles } = await this.processFileReferences(\n task.description,\n repositoryPath\n );\n\n let prompt = '';\n prompt += `## Current Task\\n\\n**Task**: ${task.title}\\n**Description**: ${processedDescription}`;\n\n if ((task as any).primary_repository) {\n prompt += `\\n**Repository**: ${(task as any).primary_repository}`;\n }\n\n // Add referenced files from @ mentions\n if (referencedFiles.length > 0) {\n prompt += `\\n\\n## Referenced Files\\n\\n`;\n for (const file of referencedFiles) {\n prompt += `### ${file.path}\\n\\`\\`\\`\\n${file.content}\\n\\`\\`\\`\\n\\n`;\n }\n }\n\n try {\n const taskFiles = await this.getTaskFiles(task.id);\n const hasPlan = taskFiles.some((f: any) => f.type === 'plan');\n if (taskFiles.length > 0) {\n prompt += `\\n\\n## Context and Supporting Information`;\n for (const file of taskFiles) {\n if (file.type === 'plan') {\n prompt += `\\n\\n### Execution Plan\\n${file.content}`;\n } else {\n prompt += `\\n\\n### ${file.name} (${file.type})\\n${file.content}`;\n }\n }\n }\n if (hasPlan) {\n prompt += `\\n\\nPlease implement the changes described in the execution plan above. Follow the plan step-by-step and make the necessary file modifications. You must actually edit files and make changes - do not just analyze or review.`;\n } else {\n prompt += `\\n\\nPlease implement the changes described in the task above. You must actually edit files and make changes - do not just analyze or review.`;\n }\n } catch (error) {\n this.logger.debug('No supporting files found for execution', { taskId: task.id });\n prompt += `\\n\\nPlease implement the changes described in the task above.`;\n }\n return prompt;\n }\n}\n\n\n"],"names":["fs"],"mappings":"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"}
|
|
@@ -55,7 +55,7 @@ class StageExecutor {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
async runPlanning(task, cwd, options, stageKey) {
|
|
58
|
-
const contextPrompt = await this.promptBuilder.buildPlanningPrompt(task);
|
|
58
|
+
const contextPrompt = await this.promptBuilder.buildPlanningPrompt(task, cwd);
|
|
59
59
|
let prompt = PLANNING_SYSTEM_PROMPT + '\n\n' + contextPrompt;
|
|
60
60
|
const stageOverrides = options.stageOverrides?.[stageKey] || options.stageOverrides?.['plan'];
|
|
61
61
|
const mergedOverrides = {
|
|
@@ -95,7 +95,7 @@ class StageExecutor {
|
|
|
95
95
|
return { plan: plan.trim() };
|
|
96
96
|
}
|
|
97
97
|
async runExecution(task, cwd, permissionMode, options, stageKey) {
|
|
98
|
-
const contextPrompt = await this.promptBuilder.buildExecutionPrompt(task);
|
|
98
|
+
const contextPrompt = await this.promptBuilder.buildExecutionPrompt(task, cwd);
|
|
99
99
|
let prompt = EXECUTION_SYSTEM_PROMPT + '\n\n' + contextPrompt;
|
|
100
100
|
const stageOverrides = options.stageOverrides?.[stageKey];
|
|
101
101
|
const mergedOverrides = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage-executor.js","sources":["../../src/stage-executor.ts"],"sourcesContent":["import { query } from '@anthropic-ai/claude-agent-sdk';\nimport { Logger } from './utils/logger.js';\nimport { EventTransformer } from './event-transformer.js';\nimport { AgentRegistry } from './agent-registry.js';\nimport type { AgentEvent, Task, McpServerConfig } from './types.js';\nimport type { WorkflowStage, WorkflowStageExecutionResult, WorkflowExecutionOptions } from './workflow-types.js';\nimport { PLANNING_SYSTEM_PROMPT } from './agents/planning.js';\nimport { EXECUTION_SYSTEM_PROMPT } from './agents/execution.js';\nimport { PromptBuilder } from './prompt-builder.js';\n\nexport class StageExecutor {\n private registry: AgentRegistry;\n private logger: Logger;\n private eventTransformer: EventTransformer;\n private promptBuilder: PromptBuilder;\n private eventHandler?: (event: AgentEvent) => void;\n private mcpServers?: Record<string, McpServerConfig>;\n\n constructor(\n registry: AgentRegistry,\n logger: Logger,\n promptBuilder?: PromptBuilder,\n eventHandler?: (event: AgentEvent) => void,\n mcpServers?: Record<string, McpServerConfig>,\n ) {\n this.registry = registry;\n this.logger = logger.child('StageExecutor');\n this.eventTransformer = new EventTransformer();\n this.promptBuilder = promptBuilder || new PromptBuilder({\n getTaskFiles: async () => [],\n generatePlanTemplate: async () => '',\n logger,\n });\n this.eventHandler = eventHandler;\n this.mcpServers = mcpServers;\n }\n\n setEventHandler(handler?: (event: AgentEvent) => void): void {\n this.eventHandler = handler;\n }\n\n async execute(task: Task, stage: WorkflowStage, options: WorkflowExecutionOptions): Promise<WorkflowStageExecutionResult> {\n const isManual = stage.is_manual_only === true;\n if (isManual) {\n this.logger.info('Manual stage detected; skipping agent execution', { stage: stage.key });\n return { results: [] };\n }\n\n const inferredAgent = stage.key.toLowerCase().includes('plan') ? 'planning_basic' : 'code_generation';\n const agentName = stage.agent_name || inferredAgent;\n const agent = this.registry.getAgent(agentName);\n if (!agent) {\n throw new Error(`Unknown agent '${agentName}' for stage '${stage.key}'`);\n }\n\n const permissionMode = (options.permissionMode as any) || 'acceptEdits';\n const cwd = options.repositoryPath || process.cwd();\n\n switch (agent.agent_type) {\n case 'planning':\n return this.runPlanning(task, cwd, options, stage.key);\n case 'execution':\n return this.runExecution(task, cwd, permissionMode, options, stage.key);\n case 'review': // TODO: Implement review\n case 'testing': // TODO: Implement testing\n default:\n // throw new Error(`Unsupported agent type: ${agent.agent_type}`);\n console.warn(`Unsupported agent type: ${agent.agent_type}`);\n return { results: [] };\n }\n }\n\n private async runPlanning(task: Task, cwd: string, options: WorkflowExecutionOptions, stageKey: string): Promise<WorkflowStageExecutionResult> {\n const contextPrompt = await this.promptBuilder.buildPlanningPrompt(task);\n let prompt = PLANNING_SYSTEM_PROMPT + '\\n\\n' + contextPrompt;\n\n const stageOverrides = options.stageOverrides?.[stageKey] || options.stageOverrides?.['plan'];\n const mergedOverrides = {\n ...(options.queryOverrides || {}),\n ...(stageOverrides?.queryOverrides || {}),\n } as Record<string, any>;\n\n const baseOptions: Record<string, any> = {\n model: 'claude-sonnet-4-5-20250929',\n cwd,\n permissionMode: 'plan',\n settingSources: ['local'],\n mcpServers: this.mcpServers\n };\n\n const response = query({\n prompt,\n options: { ...baseOptions, ...mergedOverrides },\n });\n\n let plan = '';\n for await (const message of response) {\n // Emit raw SDK event first\n this.eventHandler?.(this.eventTransformer.createRawSDKEvent(message));\n \n // Then emit transformed event\n const transformed = this.eventTransformer.transform(message);\n if (transformed) {\n if (transformed.type !== 'token') {\n this.logger.debug('Planning event', { type: transformed.type });\n }\n this.eventHandler?.(transformed);\n }\n \n if (message.type === 'assistant' && message.message?.content) {\n for (const c of message.message.content) {\n if (c.type === 'text' && c.text) plan += c.text + '\\n';\n }\n }\n }\n\n return { plan: plan.trim() };\n }\n\n private async runExecution(task: Task, cwd: string, permissionMode: WorkflowExecutionOptions['permissionMode'], options: WorkflowExecutionOptions, stageKey: string): Promise<WorkflowStageExecutionResult> {\n const contextPrompt = await this.promptBuilder.buildExecutionPrompt(task);\n let prompt = EXECUTION_SYSTEM_PROMPT + '\\n\\n' + contextPrompt;\n\n const stageOverrides = options.stageOverrides?.[stageKey];\n const mergedOverrides = {\n ...(options.queryOverrides || {}),\n ...(stageOverrides?.queryOverrides || {}),\n } as Record<string, any>;\n\n const baseOptions: Record<string, any> = {\n model: 'claude-sonnet-4-5-20250929',\n cwd,\n permissionMode,\n settingSources: ['local'],\n mcpServers: this.mcpServers\n };\n\n const response = query({\n prompt,\n options: { ...baseOptions, ...mergedOverrides },\n });\n const results: any[] = [];\n for await (const message of response) {\n // Emit raw SDK event first\n this.eventHandler?.(this.eventTransformer.createRawSDKEvent(message));\n \n // Then emit transformed event\n const transformed = this.eventTransformer.transform(message);\n if (transformed) {\n if (transformed.type !== 'token') {\n this.logger.debug('Execution event', { type: transformed.type });\n }\n this.eventHandler?.(transformed);\n }\n \n results.push(message);\n }\n return { results };\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stage-executor.js","sources":["../../src/stage-executor.ts"],"sourcesContent":["import { query } from '@anthropic-ai/claude-agent-sdk';\nimport { Logger } from './utils/logger.js';\nimport { EventTransformer } from './event-transformer.js';\nimport { AgentRegistry } from './agent-registry.js';\nimport type { AgentEvent, Task, McpServerConfig } from './types.js';\nimport type { WorkflowStage, WorkflowStageExecutionResult, WorkflowExecutionOptions } from './workflow-types.js';\nimport { PLANNING_SYSTEM_PROMPT } from './agents/planning.js';\nimport { EXECUTION_SYSTEM_PROMPT } from './agents/execution.js';\nimport { PromptBuilder } from './prompt-builder.js';\n\nexport class StageExecutor {\n private registry: AgentRegistry;\n private logger: Logger;\n private eventTransformer: EventTransformer;\n private promptBuilder: PromptBuilder;\n private eventHandler?: (event: AgentEvent) => void;\n private mcpServers?: Record<string, McpServerConfig>;\n\n constructor(\n registry: AgentRegistry,\n logger: Logger,\n promptBuilder?: PromptBuilder,\n eventHandler?: (event: AgentEvent) => void,\n mcpServers?: Record<string, McpServerConfig>,\n ) {\n this.registry = registry;\n this.logger = logger.child('StageExecutor');\n this.eventTransformer = new EventTransformer();\n this.promptBuilder = promptBuilder || new PromptBuilder({\n getTaskFiles: async () => [],\n generatePlanTemplate: async () => '',\n logger,\n });\n this.eventHandler = eventHandler;\n this.mcpServers = mcpServers;\n }\n\n setEventHandler(handler?: (event: AgentEvent) => void): void {\n this.eventHandler = handler;\n }\n\n async execute(task: Task, stage: WorkflowStage, options: WorkflowExecutionOptions): Promise<WorkflowStageExecutionResult> {\n const isManual = stage.is_manual_only === true;\n if (isManual) {\n this.logger.info('Manual stage detected; skipping agent execution', { stage: stage.key });\n return { results: [] };\n }\n\n const inferredAgent = stage.key.toLowerCase().includes('plan') ? 'planning_basic' : 'code_generation';\n const agentName = stage.agent_name || inferredAgent;\n const agent = this.registry.getAgent(agentName);\n if (!agent) {\n throw new Error(`Unknown agent '${agentName}' for stage '${stage.key}'`);\n }\n\n const permissionMode = (options.permissionMode as any) || 'acceptEdits';\n const cwd = options.repositoryPath || process.cwd();\n\n switch (agent.agent_type) {\n case 'planning':\n return this.runPlanning(task, cwd, options, stage.key);\n case 'execution':\n return this.runExecution(task, cwd, permissionMode, options, stage.key);\n case 'review': // TODO: Implement review\n case 'testing': // TODO: Implement testing\n default:\n // throw new Error(`Unsupported agent type: ${agent.agent_type}`);\n console.warn(`Unsupported agent type: ${agent.agent_type}`);\n return { results: [] };\n }\n }\n\n private async runPlanning(task: Task, cwd: string, options: WorkflowExecutionOptions, stageKey: string): Promise<WorkflowStageExecutionResult> {\n const contextPrompt = await this.promptBuilder.buildPlanningPrompt(task, cwd);\n let prompt = PLANNING_SYSTEM_PROMPT + '\\n\\n' + contextPrompt;\n\n const stageOverrides = options.stageOverrides?.[stageKey] || options.stageOverrides?.['plan'];\n const mergedOverrides = {\n ...(options.queryOverrides || {}),\n ...(stageOverrides?.queryOverrides || {}),\n } as Record<string, any>;\n\n const baseOptions: Record<string, any> = {\n model: 'claude-sonnet-4-5-20250929',\n cwd,\n permissionMode: 'plan',\n settingSources: ['local'],\n mcpServers: this.mcpServers\n };\n\n const response = query({\n prompt,\n options: { ...baseOptions, ...mergedOverrides },\n });\n\n let plan = '';\n for await (const message of response) {\n // Emit raw SDK event first\n this.eventHandler?.(this.eventTransformer.createRawSDKEvent(message));\n \n // Then emit transformed event\n const transformed = this.eventTransformer.transform(message);\n if (transformed) {\n if (transformed.type !== 'token') {\n this.logger.debug('Planning event', { type: transformed.type });\n }\n this.eventHandler?.(transformed);\n }\n \n if (message.type === 'assistant' && message.message?.content) {\n for (const c of message.message.content) {\n if (c.type === 'text' && c.text) plan += c.text + '\\n';\n }\n }\n }\n\n return { plan: plan.trim() };\n }\n\n private async runExecution(task: Task, cwd: string, permissionMode: WorkflowExecutionOptions['permissionMode'], options: WorkflowExecutionOptions, stageKey: string): Promise<WorkflowStageExecutionResult> {\n const contextPrompt = await this.promptBuilder.buildExecutionPrompt(task, cwd);\n let prompt = EXECUTION_SYSTEM_PROMPT + '\\n\\n' + contextPrompt;\n\n const stageOverrides = options.stageOverrides?.[stageKey];\n const mergedOverrides = {\n ...(options.queryOverrides || {}),\n ...(stageOverrides?.queryOverrides || {}),\n } as Record<string, any>;\n\n const baseOptions: Record<string, any> = {\n model: 'claude-sonnet-4-5-20250929',\n cwd,\n permissionMode,\n settingSources: ['local'],\n mcpServers: this.mcpServers\n };\n\n const response = query({\n prompt,\n options: { ...baseOptions, ...mergedOverrides },\n });\n const results: any[] = [];\n for await (const message of response) {\n // Emit raw SDK event first\n this.eventHandler?.(this.eventTransformer.createRawSDKEvent(message));\n \n // Then emit transformed event\n const transformed = this.eventTransformer.transform(message);\n if (transformed) {\n if (transformed.type !== 'token') {\n this.logger.debug('Execution event', { type: transformed.type });\n }\n this.eventHandler?.(transformed);\n }\n \n results.push(message);\n }\n return { results };\n }\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/prompt-builder.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Task } from './types.js';
|
|
2
2
|
import type { TemplateVariables } from './template-manager.js';
|
|
3
3
|
import { Logger } from './utils/logger.js';
|
|
4
|
+
import { promises as fs } from 'fs';
|
|
5
|
+
import { join } from 'path';
|
|
4
6
|
|
|
5
7
|
export interface PromptBuilderDeps {
|
|
6
8
|
getTaskFiles: (taskId: string) => Promise<any[]>;
|
|
@@ -19,14 +21,94 @@ export class PromptBuilder {
|
|
|
19
21
|
this.logger = deps.logger || new Logger({ debug: false, prefix: '[PromptBuilder]' });
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Extract file paths from XML tags in description
|
|
26
|
+
* Format: <file path="relative/path.ts" />
|
|
27
|
+
*/
|
|
28
|
+
private extractFilePaths(description: string): string[] {
|
|
29
|
+
const fileTagRegex = /<file\s+path="([^"]+)"\s*\/>/g;
|
|
30
|
+
const paths: string[] = [];
|
|
31
|
+
let match: RegExpExecArray | null;
|
|
32
|
+
|
|
33
|
+
while ((match = fileTagRegex.exec(description)) !== null) {
|
|
34
|
+
paths.push(match[1]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return paths;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Read file contents from repository
|
|
42
|
+
*/
|
|
43
|
+
private async readFileContent(repositoryPath: string, filePath: string): Promise<string | null> {
|
|
44
|
+
try {
|
|
45
|
+
const fullPath = join(repositoryPath, filePath);
|
|
46
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
47
|
+
return content;
|
|
48
|
+
} catch (error) {
|
|
49
|
+
this.logger.warn(`Failed to read referenced file: ${filePath}`, { error });
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Process description to extract file tags and read contents
|
|
56
|
+
* Returns processed description and referenced file contents
|
|
57
|
+
*/
|
|
58
|
+
private async processFileReferences(
|
|
59
|
+
description: string,
|
|
60
|
+
repositoryPath?: string
|
|
61
|
+
): Promise<{ description: string; referencedFiles: Array<{ path: string; content: string }> }> {
|
|
62
|
+
const filePaths = this.extractFilePaths(description);
|
|
63
|
+
const referencedFiles: Array<{ path: string; content: string }> = [];
|
|
64
|
+
|
|
65
|
+
if (filePaths.length === 0 || !repositoryPath) {
|
|
66
|
+
return { description, referencedFiles };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Read all referenced files
|
|
70
|
+
for (const filePath of filePaths) {
|
|
71
|
+
const content = await this.readFileContent(repositoryPath, filePath);
|
|
72
|
+
if (content !== null) {
|
|
73
|
+
referencedFiles.push({ path: filePath, content });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Replace file tags with just the filename for readability
|
|
78
|
+
let processedDescription = description;
|
|
79
|
+
for (const filePath of filePaths) {
|
|
80
|
+
const fileName = filePath.split('/').pop() || filePath;
|
|
81
|
+
processedDescription = processedDescription.replace(
|
|
82
|
+
new RegExp(`<file\\s+path="${filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}"\\s*/>`, 'g'),
|
|
83
|
+
`@${fileName}`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { description: processedDescription, referencedFiles };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async buildPlanningPrompt(task: Task, repositoryPath?: string): Promise<string> {
|
|
91
|
+
// Process file references in description
|
|
92
|
+
const { description: processedDescription, referencedFiles } = await this.processFileReferences(
|
|
93
|
+
task.description,
|
|
94
|
+
repositoryPath
|
|
95
|
+
);
|
|
96
|
+
|
|
23
97
|
let prompt = '';
|
|
24
|
-
prompt += `## Current Task\n\n**Task**: ${task.title}\n**Description**: ${
|
|
98
|
+
prompt += `## Current Task\n\n**Task**: ${task.title}\n**Description**: ${processedDescription}`;
|
|
25
99
|
|
|
26
100
|
if ((task as any).primary_repository) {
|
|
27
101
|
prompt += `\n**Repository**: ${(task as any).primary_repository}`;
|
|
28
102
|
}
|
|
29
103
|
|
|
104
|
+
// Add referenced files from @ mentions
|
|
105
|
+
if (referencedFiles.length > 0) {
|
|
106
|
+
prompt += `\n\n## Referenced Files\n\n`;
|
|
107
|
+
for (const file of referencedFiles) {
|
|
108
|
+
prompt += `### ${file.path}\n\`\`\`\n${file.content}\n\`\`\`\n\n`;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
30
112
|
try {
|
|
31
113
|
const taskFiles = await this.getTaskFiles(task.id);
|
|
32
114
|
const contextFiles = taskFiles.filter((f: any) => f.type === 'context' || f.type === 'reference');
|
|
@@ -43,7 +125,7 @@ export class PromptBuilder {
|
|
|
43
125
|
const templateVariables = {
|
|
44
126
|
task_id: task.id,
|
|
45
127
|
task_title: task.title,
|
|
46
|
-
task_description:
|
|
128
|
+
task_description: processedDescription,
|
|
47
129
|
date: new Date().toISOString().split('T')[0],
|
|
48
130
|
repository: ((task as any).primary_repository || '') as string,
|
|
49
131
|
};
|
|
@@ -55,14 +137,28 @@ export class PromptBuilder {
|
|
|
55
137
|
return prompt;
|
|
56
138
|
}
|
|
57
139
|
|
|
58
|
-
async buildExecutionPrompt(task: Task): Promise<string> {
|
|
140
|
+
async buildExecutionPrompt(task: Task, repositoryPath?: string): Promise<string> {
|
|
141
|
+
// Process file references in description
|
|
142
|
+
const { description: processedDescription, referencedFiles } = await this.processFileReferences(
|
|
143
|
+
task.description,
|
|
144
|
+
repositoryPath
|
|
145
|
+
);
|
|
146
|
+
|
|
59
147
|
let prompt = '';
|
|
60
|
-
prompt += `## Current Task\n\n**Task**: ${task.title}\n**Description**: ${
|
|
148
|
+
prompt += `## Current Task\n\n**Task**: ${task.title}\n**Description**: ${processedDescription}`;
|
|
61
149
|
|
|
62
150
|
if ((task as any).primary_repository) {
|
|
63
151
|
prompt += `\n**Repository**: ${(task as any).primary_repository}`;
|
|
64
152
|
}
|
|
65
153
|
|
|
154
|
+
// Add referenced files from @ mentions
|
|
155
|
+
if (referencedFiles.length > 0) {
|
|
156
|
+
prompt += `\n\n## Referenced Files\n\n`;
|
|
157
|
+
for (const file of referencedFiles) {
|
|
158
|
+
prompt += `### ${file.path}\n\`\`\`\n${file.content}\n\`\`\`\n\n`;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
66
162
|
try {
|
|
67
163
|
const taskFiles = await this.getTaskFiles(task.id);
|
|
68
164
|
const hasPlan = taskFiles.some((f: any) => f.type === 'plan');
|
package/src/stage-executor.ts
CHANGED
|
@@ -71,7 +71,7 @@ export class StageExecutor {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
private async runPlanning(task: Task, cwd: string, options: WorkflowExecutionOptions, stageKey: string): Promise<WorkflowStageExecutionResult> {
|
|
74
|
-
const contextPrompt = await this.promptBuilder.buildPlanningPrompt(task);
|
|
74
|
+
const contextPrompt = await this.promptBuilder.buildPlanningPrompt(task, cwd);
|
|
75
75
|
let prompt = PLANNING_SYSTEM_PROMPT + '\n\n' + contextPrompt;
|
|
76
76
|
|
|
77
77
|
const stageOverrides = options.stageOverrides?.[stageKey] || options.stageOverrides?.['plan'];
|
|
@@ -118,7 +118,7 @@ export class StageExecutor {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
private async runExecution(task: Task, cwd: string, permissionMode: WorkflowExecutionOptions['permissionMode'], options: WorkflowExecutionOptions, stageKey: string): Promise<WorkflowStageExecutionResult> {
|
|
121
|
-
const contextPrompt = await this.promptBuilder.buildExecutionPrompt(task);
|
|
121
|
+
const contextPrompt = await this.promptBuilder.buildExecutionPrompt(task, cwd);
|
|
122
122
|
let prompt = EXECUTION_SYSTEM_PROMPT + '\n\n' + contextPrompt;
|
|
123
123
|
|
|
124
124
|
const stageOverrides = options.stageOverrides?.[stageKey];
|