@posthog/agent 1.24.0 → 1.24.2
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/LICENSE +33 -0
- package/dist/index.d.ts +11 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/src/adapters/claude/claude-adapter.d.ts +3 -3
- package/dist/src/adapters/claude/claude-adapter.d.ts.map +1 -1
- package/dist/src/adapters/claude/claude-adapter.js +111 -156
- package/dist/src/adapters/claude/claude-adapter.js.map +1 -1
- package/dist/src/adapters/claude/tool-mapper.d.ts +1 -1
- package/dist/src/adapters/claude/tool-mapper.d.ts.map +1 -1
- package/dist/src/adapters/claude/tool-mapper.js.map +1 -1
- package/dist/src/adapters/types.d.ts +1 -1
- package/dist/src/adapters/types.d.ts.map +1 -1
- package/dist/src/agent.d.ts +7 -7
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +85 -143
- package/dist/src/agent.js.map +1 -1
- package/dist/src/agents/execution.js.map +1 -1
- package/dist/src/agents/planning.js.map +1 -1
- package/dist/src/agents/research.js.map +1 -1
- package/dist/src/file-manager.d.ts +4 -4
- package/dist/src/file-manager.d.ts.map +1 -1
- package/dist/src/file-manager.js +58 -59
- package/dist/src/file-manager.js.map +1 -1
- package/dist/src/git-manager.d.ts +1 -1
- package/dist/src/git-manager.d.ts.map +1 -1
- package/dist/src/git-manager.js +70 -87
- package/dist/src/git-manager.js.map +1 -1
- package/dist/src/posthog-api.d.ts +3 -2
- package/dist/src/posthog-api.d.ts.map +1 -1
- package/dist/src/posthog-api.js +22 -22
- package/dist/src/posthog-api.js.map +1 -1
- package/dist/src/prompt-builder.d.ts +3 -3
- package/dist/src/prompt-builder.d.ts.map +1 -1
- package/dist/src/prompt-builder.js +93 -123
- package/dist/src/prompt-builder.js.map +1 -1
- package/dist/src/task-manager.d.ts +4 -4
- package/dist/src/task-manager.d.ts.map +1 -1
- package/dist/src/task-manager.js +18 -19
- package/dist/src/task-manager.js.map +1 -1
- package/dist/src/task-progress-reporter.d.ts +4 -3
- package/dist/src/task-progress-reporter.d.ts.map +1 -1
- package/dist/src/task-progress-reporter.js +54 -59
- package/dist/src/task-progress-reporter.js.map +1 -1
- package/dist/src/template-manager.d.ts +1 -1
- package/dist/src/template-manager.d.ts.map +1 -1
- package/dist/src/template-manager.js +28 -30
- package/dist/src/template-manager.js.map +1 -1
- package/dist/src/todo-manager.d.ts +3 -3
- package/dist/src/todo-manager.d.ts.map +1 -1
- package/dist/src/todo-manager.js +24 -29
- package/dist/src/todo-manager.js.map +1 -1
- package/dist/src/tools/registry.d.ts +1 -1
- package/dist/src/tools/registry.js +60 -60
- package/dist/src/tools/registry.js.map +1 -1
- package/dist/src/tools/types.d.ts +31 -31
- package/dist/src/types.d.ts +33 -33
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/utils/logger.d.ts +4 -4
- package/dist/src/utils/logger.d.ts.map +1 -1
- package/dist/src/utils/logger.js +8 -8
- package/dist/src/utils/logger.js.map +1 -1
- package/dist/src/workflow/config.d.ts +1 -1
- package/dist/src/workflow/config.d.ts.map +1 -1
- package/dist/src/workflow/config.js +18 -18
- package/dist/src/workflow/config.js.map +1 -1
- package/dist/src/workflow/steps/build.d.ts +1 -1
- package/dist/src/workflow/steps/build.d.ts.map +1 -1
- package/dist/src/workflow/steps/build.js +38 -46
- package/dist/src/workflow/steps/build.js.map +1 -1
- package/dist/src/workflow/steps/finalize.d.ts +1 -1
- package/dist/src/workflow/steps/finalize.d.ts.map +1 -1
- package/dist/src/workflow/steps/finalize.js +48 -54
- package/dist/src/workflow/steps/finalize.js.map +1 -1
- package/dist/src/workflow/steps/plan.d.ts +1 -1
- package/dist/src/workflow/steps/plan.d.ts.map +1 -1
- package/dist/src/workflow/steps/plan.js +46 -58
- package/dist/src/workflow/steps/plan.js.map +1 -1
- package/dist/src/workflow/steps/research.d.ts +1 -1
- package/dist/src/workflow/steps/research.d.ts.map +1 -1
- package/dist/src/workflow/steps/research.js +56 -68
- package/dist/src/workflow/steps/research.js.map +1 -1
- package/dist/src/workflow/types.d.ts +12 -12
- package/dist/src/workflow/types.d.ts.map +1 -1
- package/dist/src/workflow/utils.d.ts +1 -1
- package/dist/src/workflow/utils.d.ts.map +1 -1
- package/dist/src/workflow/utils.js +4 -7
- package/dist/src/workflow/utils.js.map +1 -1
- package/package.json +6 -6
- package/src/adapters/claude/claude-adapter.ts +168 -220
- package/src/adapters/claude/tool-mapper.ts +2 -2
- package/src/adapters/types.ts +1 -1
- package/src/agent.ts +444 -579
- package/src/agents/execution.ts +1 -1
- package/src/agents/planning.ts +1 -1
- package/src/agents/research.ts +1 -0
- package/src/file-manager.ts +63 -64
- package/src/git-manager.ts +88 -144
- package/src/posthog-api.ts +82 -122
- package/src/prompt-builder.ts +135 -180
- package/src/task-manager.ts +30 -38
- package/src/task-progress-reporter.ts +59 -70
- package/src/template-manager.ts +45 -98
- package/src/todo-manager.ts +30 -35
- package/src/tools/registry.ts +62 -62
- package/src/tools/types.ts +36 -36
- package/src/types.ts +71 -93
- package/src/utils/logger.ts +56 -62
- package/src/workflow/config.ts +48 -48
- package/src/workflow/steps/build.ts +113 -122
- package/src/workflow/steps/finalize.ts +182 -214
- package/src/workflow/steps/plan.ts +131 -151
- package/src/workflow/steps/research.ts +186 -205
- package/src/workflow/types.ts +36 -38
- package/src/workflow/utils.ts +34 -37
package/src/prompt-builder.ts
CHANGED
|
@@ -1,30 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
1
|
+
import type { Task, UrlMention, PostHogResource } from './types.js';
|
|
2
|
+
import type { TemplateVariables } from './template-manager.js';
|
|
3
|
+
import { Logger } from './utils/logger.js';
|
|
4
|
+
import { promises as fs } from 'fs';
|
|
5
|
+
import { join } from 'path';
|
|
6
6
|
|
|
7
7
|
export interface PromptBuilderDeps {
|
|
8
8
|
getTaskFiles: (taskId: string) => Promise<any[]>;
|
|
9
9
|
generatePlanTemplate: (vars: TemplateVariables) => Promise<string>;
|
|
10
|
-
posthogClient?: {
|
|
11
|
-
fetchResourceByUrl: (mention: UrlMention) => Promise<PostHogResource>;
|
|
12
|
-
};
|
|
10
|
+
posthogClient?: { fetchResourceByUrl: (mention: UrlMention) => Promise<PostHogResource> };
|
|
13
11
|
logger?: Logger;
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
export class PromptBuilder {
|
|
17
|
-
private getTaskFiles: PromptBuilderDeps[
|
|
18
|
-
private generatePlanTemplate: PromptBuilderDeps[
|
|
19
|
-
private posthogClient?: PromptBuilderDeps[
|
|
15
|
+
private getTaskFiles: PromptBuilderDeps['getTaskFiles'];
|
|
16
|
+
private generatePlanTemplate: PromptBuilderDeps['generatePlanTemplate'];
|
|
17
|
+
private posthogClient?: PromptBuilderDeps['posthogClient'];
|
|
20
18
|
private logger: Logger;
|
|
21
19
|
|
|
22
20
|
constructor(deps: PromptBuilderDeps) {
|
|
23
21
|
this.getTaskFiles = deps.getTaskFiles;
|
|
24
22
|
this.generatePlanTemplate = deps.generatePlanTemplate;
|
|
25
23
|
this.posthogClient = deps.posthogClient;
|
|
26
|
-
this.logger =
|
|
27
|
-
deps.logger || new Logger({ debug: false, prefix: "[PromptBuilder]" });
|
|
24
|
+
this.logger = deps.logger || new Logger({ debug: false, prefix: '[PromptBuilder]' });
|
|
28
25
|
}
|
|
29
26
|
|
|
30
27
|
/**
|
|
@@ -36,10 +33,8 @@ export class PromptBuilder {
|
|
|
36
33
|
const paths: string[] = [];
|
|
37
34
|
let match: RegExpExecArray | null;
|
|
38
35
|
|
|
39
|
-
match = fileTagRegex.exec(description)
|
|
40
|
-
while (match !== null) {
|
|
36
|
+
while ((match = fileTagRegex.exec(description)) !== null) {
|
|
41
37
|
paths.push(match[1]);
|
|
42
|
-
match = fileTagRegex.exec(description);
|
|
43
38
|
}
|
|
44
39
|
|
|
45
40
|
return paths;
|
|
@@ -48,18 +43,13 @@ export class PromptBuilder {
|
|
|
48
43
|
/**
|
|
49
44
|
* Read file contents from repository
|
|
50
45
|
*/
|
|
51
|
-
private async readFileContent(
|
|
52
|
-
repositoryPath: string,
|
|
53
|
-
filePath: string,
|
|
54
|
-
): Promise<string | null> {
|
|
46
|
+
private async readFileContent(repositoryPath: string, filePath: string): Promise<string | null> {
|
|
55
47
|
try {
|
|
56
48
|
const fullPath = join(repositoryPath, filePath);
|
|
57
|
-
const content = await fs.readFile(fullPath,
|
|
49
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
58
50
|
return content;
|
|
59
51
|
} catch (error) {
|
|
60
|
-
this.logger.warn(`Failed to read referenced file: ${filePath}`, {
|
|
61
|
-
error,
|
|
62
|
-
});
|
|
52
|
+
this.logger.warn(`Failed to read referenced file: ${filePath}`, { error });
|
|
63
53
|
return null;
|
|
64
54
|
}
|
|
65
55
|
}
|
|
@@ -70,35 +60,30 @@ export class PromptBuilder {
|
|
|
70
60
|
*/
|
|
71
61
|
private extractUrlMentions(description: string): UrlMention[] {
|
|
72
62
|
const mentions: UrlMention[] = [];
|
|
73
|
-
|
|
63
|
+
|
|
74
64
|
// PostHog resource mentions: <error id="..." />, <experiment id="..." />, etc.
|
|
75
|
-
const resourceRegex =
|
|
76
|
-
/<(error|experiment|insight|feature_flag)\s+id="([^"]+)"\s*\/>/g;
|
|
65
|
+
const resourceRegex = /<(error|experiment|insight|feature_flag)\s+id="([^"]+)"\s*\/>/g;
|
|
77
66
|
let match: RegExpExecArray | null;
|
|
78
67
|
|
|
79
|
-
match = resourceRegex.exec(description)
|
|
80
|
-
while (match !== null) {
|
|
68
|
+
while ((match = resourceRegex.exec(description)) !== null) {
|
|
81
69
|
const [, type, id] = match;
|
|
82
70
|
mentions.push({
|
|
83
|
-
url:
|
|
71
|
+
url: '', // Will be reconstructed if needed
|
|
84
72
|
type: type as any,
|
|
85
73
|
id,
|
|
86
|
-
label: this.generateUrlLabel(
|
|
74
|
+
label: this.generateUrlLabel('', type as any),
|
|
87
75
|
});
|
|
88
|
-
match = resourceRegex.exec(description);
|
|
89
76
|
}
|
|
90
77
|
|
|
91
78
|
// Generic URL mentions: <url href="..." />
|
|
92
79
|
const urlRegex = /<url\s+href="([^"]+)"\s*\/>/g;
|
|
93
|
-
match = urlRegex.exec(description)
|
|
94
|
-
while (match !== null) {
|
|
80
|
+
while ((match = urlRegex.exec(description)) !== null) {
|
|
95
81
|
const [, url] = match;
|
|
96
82
|
mentions.push({
|
|
97
83
|
url,
|
|
98
|
-
type:
|
|
99
|
-
label: this.generateUrlLabel(url,
|
|
84
|
+
type: 'generic',
|
|
85
|
+
label: this.generateUrlLabel(url, 'generic'),
|
|
100
86
|
});
|
|
101
|
-
match = urlRegex.exec(description);
|
|
102
87
|
}
|
|
103
88
|
|
|
104
89
|
return mentions;
|
|
@@ -111,23 +96,21 @@ export class PromptBuilder {
|
|
|
111
96
|
try {
|
|
112
97
|
const urlObj = new URL(url);
|
|
113
98
|
switch (type) {
|
|
114
|
-
case
|
|
99
|
+
case 'error':
|
|
115
100
|
const errorMatch = url.match(/error_tracking\/([a-f0-9-]+)/);
|
|
116
|
-
return errorMatch ? `Error ${errorMatch[1].slice(0, 8)}...` :
|
|
117
|
-
|
|
118
|
-
case "experiment": {
|
|
101
|
+
return errorMatch ? `Error ${errorMatch[1].slice(0, 8)}...` : 'Error';
|
|
102
|
+
case 'experiment':
|
|
119
103
|
const expMatch = url.match(/experiments\/(\d+)/);
|
|
120
|
-
return expMatch ? `Experiment #${expMatch[1]}` :
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return "Feature Flag";
|
|
104
|
+
return expMatch ? `Experiment #${expMatch[1]}` : 'Experiment';
|
|
105
|
+
case 'insight':
|
|
106
|
+
return 'Insight';
|
|
107
|
+
case 'feature_flag':
|
|
108
|
+
return 'Feature Flag';
|
|
126
109
|
default:
|
|
127
110
|
return urlObj.hostname;
|
|
128
111
|
}
|
|
129
112
|
} catch {
|
|
130
|
-
return
|
|
113
|
+
return 'URL';
|
|
131
114
|
}
|
|
132
115
|
}
|
|
133
116
|
|
|
@@ -135,7 +118,7 @@ export class PromptBuilder {
|
|
|
135
118
|
* Process URL references and fetch their content
|
|
136
119
|
*/
|
|
137
120
|
private async processUrlReferences(
|
|
138
|
-
description: string
|
|
121
|
+
description: string
|
|
139
122
|
): Promise<{ description: string; referencedResources: PostHogResource[] }> {
|
|
140
123
|
const urlMentions = this.extractUrlMentions(description);
|
|
141
124
|
const referencedResources: PostHogResource[] = [];
|
|
@@ -150,15 +133,13 @@ export class PromptBuilder {
|
|
|
150
133
|
const resource = await this.posthogClient.fetchResourceByUrl(mention);
|
|
151
134
|
referencedResources.push(resource);
|
|
152
135
|
} catch (error) {
|
|
153
|
-
this.logger.warn(`Failed to fetch resource from URL: ${mention.url}`, {
|
|
154
|
-
error,
|
|
155
|
-
});
|
|
136
|
+
this.logger.warn(`Failed to fetch resource from URL: ${mention.url}`, { error });
|
|
156
137
|
// Add a placeholder resource for failed fetches
|
|
157
138
|
referencedResources.push({
|
|
158
139
|
type: mention.type,
|
|
159
|
-
id: mention.id ||
|
|
140
|
+
id: mention.id || '',
|
|
160
141
|
url: mention.url,
|
|
161
|
-
title: mention.label ||
|
|
142
|
+
title: mention.label || 'Unknown Resource',
|
|
162
143
|
content: `Failed to fetch resource from ${mention.url}: ${error}`,
|
|
163
144
|
metadata: {},
|
|
164
145
|
});
|
|
@@ -168,22 +149,20 @@ export class PromptBuilder {
|
|
|
168
149
|
// Replace URL tags with just the label for readability
|
|
169
150
|
let processedDescription = description;
|
|
170
151
|
for (const mention of urlMentions) {
|
|
171
|
-
if (mention.type ===
|
|
152
|
+
if (mention.type === 'generic') {
|
|
172
153
|
// Generic URLs: <url href="..." />
|
|
173
|
-
const escapedUrl = mention.url.replace(/[.*+?^${}()|[\]\\]/g,
|
|
154
|
+
const escapedUrl = mention.url.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
174
155
|
processedDescription = processedDescription.replace(
|
|
175
|
-
new RegExp(`<url\\s+href="${escapedUrl}"\\s*/>`,
|
|
176
|
-
`@${mention.label}
|
|
156
|
+
new RegExp(`<url\\s+href="${escapedUrl}"\\s*/>`, 'g'),
|
|
157
|
+
`@${mention.label}`
|
|
177
158
|
);
|
|
178
159
|
} else {
|
|
179
160
|
// PostHog resources: <error id="..." />, <experiment id="..." />, etc.
|
|
180
|
-
const escapedType = mention.type.replace(/[.*+?^${}()|[\]\\]/g,
|
|
181
|
-
const escapedId = mention.id
|
|
182
|
-
? mention.id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
183
|
-
: "";
|
|
161
|
+
const escapedType = mention.type.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
162
|
+
const escapedId = mention.id ? mention.id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') : '';
|
|
184
163
|
processedDescription = processedDescription.replace(
|
|
185
|
-
new RegExp(`<${escapedType}\\s+id="${escapedId}"\\s*/>`,
|
|
186
|
-
`@${mention.label}
|
|
164
|
+
new RegExp(`<${escapedType}\\s+id="${escapedId}"\\s*/>`, 'g'),
|
|
165
|
+
`@${mention.label}`
|
|
187
166
|
);
|
|
188
167
|
}
|
|
189
168
|
}
|
|
@@ -197,11 +176,8 @@ export class PromptBuilder {
|
|
|
197
176
|
*/
|
|
198
177
|
private async processFileReferences(
|
|
199
178
|
description: string,
|
|
200
|
-
repositoryPath?: string
|
|
201
|
-
): Promise<{
|
|
202
|
-
description: string;
|
|
203
|
-
referencedFiles: Array<{ path: string; content: string }>;
|
|
204
|
-
}> {
|
|
179
|
+
repositoryPath?: string
|
|
180
|
+
): Promise<{ description: string; referencedFiles: Array<{ path: string; content: string }> }> {
|
|
205
181
|
const filePaths = this.extractFilePaths(description);
|
|
206
182
|
const referencedFiles: Array<{ path: string; content: string }> = [];
|
|
207
183
|
|
|
@@ -220,221 +196,211 @@ export class PromptBuilder {
|
|
|
220
196
|
// Replace file tags with just the filename for readability
|
|
221
197
|
let processedDescription = description;
|
|
222
198
|
for (const filePath of filePaths) {
|
|
223
|
-
const fileName = filePath.split(
|
|
199
|
+
const fileName = filePath.split('/').pop() || filePath;
|
|
224
200
|
processedDescription = processedDescription.replace(
|
|
225
|
-
new RegExp(
|
|
226
|
-
|
|
227
|
-
"g",
|
|
228
|
-
),
|
|
229
|
-
`@${fileName}`,
|
|
201
|
+
new RegExp(`<file\\s+path="${filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}"\\s*/>`, 'g'),
|
|
202
|
+
`@${fileName}`
|
|
230
203
|
);
|
|
231
204
|
}
|
|
232
205
|
|
|
233
206
|
return { description: processedDescription, referencedFiles };
|
|
234
207
|
}
|
|
235
208
|
|
|
236
|
-
async buildResearchPrompt(
|
|
237
|
-
task: Task,
|
|
238
|
-
repositoryPath?: string,
|
|
239
|
-
): Promise<string> {
|
|
209
|
+
async buildResearchPrompt(task: Task, repositoryPath?: string): Promise<string> {
|
|
240
210
|
// Process file references in description
|
|
241
|
-
const { description: descriptionAfterFiles, referencedFiles } =
|
|
242
|
-
|
|
211
|
+
const { description: descriptionAfterFiles, referencedFiles } = await this.processFileReferences(
|
|
212
|
+
task.description,
|
|
213
|
+
repositoryPath
|
|
214
|
+
);
|
|
243
215
|
|
|
244
216
|
// Process URL references in description
|
|
245
|
-
const { description: processedDescription, referencedResources } =
|
|
246
|
-
|
|
217
|
+
const { description: processedDescription, referencedResources } = await this.processUrlReferences(
|
|
218
|
+
descriptionAfterFiles
|
|
219
|
+
);
|
|
247
220
|
|
|
248
|
-
let prompt =
|
|
221
|
+
let prompt = '<task>\n';
|
|
249
222
|
prompt += `<title>${task.title}</title>\n`;
|
|
250
223
|
prompt += `<description>${processedDescription}</description>\n`;
|
|
251
224
|
|
|
252
225
|
if ((task as any).primary_repository) {
|
|
253
226
|
prompt += `<repository>${(task as any).primary_repository}</repository>\n`;
|
|
254
227
|
}
|
|
255
|
-
prompt +=
|
|
228
|
+
prompt += '</task>\n';
|
|
256
229
|
|
|
257
230
|
// Add referenced files from @ mentions
|
|
258
231
|
if (referencedFiles.length > 0) {
|
|
259
|
-
prompt +=
|
|
232
|
+
prompt += '\n<referenced_files>\n';
|
|
260
233
|
for (const file of referencedFiles) {
|
|
261
234
|
prompt += `<file path="${file.path}">\n\`\`\`\n${file.content}\n\`\`\`\n</file>\n`;
|
|
262
235
|
}
|
|
263
|
-
prompt +=
|
|
236
|
+
prompt += '</referenced_files>\n';
|
|
264
237
|
}
|
|
265
238
|
|
|
266
239
|
// Add referenced resources from URL mentions
|
|
267
240
|
if (referencedResources.length > 0) {
|
|
268
|
-
prompt +=
|
|
241
|
+
prompt += '\n<referenced_resources>\n';
|
|
269
242
|
for (const resource of referencedResources) {
|
|
270
243
|
prompt += `<resource type="${resource.type}" url="${resource.url}">\n`;
|
|
271
244
|
prompt += `<title>${resource.title}</title>\n`;
|
|
272
245
|
prompt += `<content>${resource.content}</content>\n`;
|
|
273
|
-
prompt +=
|
|
246
|
+
prompt += '</resource>\n';
|
|
274
247
|
}
|
|
275
|
-
prompt +=
|
|
248
|
+
prompt += '</referenced_resources>\n';
|
|
276
249
|
}
|
|
277
250
|
|
|
278
251
|
try {
|
|
279
252
|
const taskFiles = await this.getTaskFiles(task.id);
|
|
280
|
-
const contextFiles = taskFiles.filter(
|
|
281
|
-
(f: any) => f.type === "context" || f.type === "reference",
|
|
282
|
-
);
|
|
253
|
+
const contextFiles = taskFiles.filter((f: any) => f.type === 'context' || f.type === 'reference');
|
|
283
254
|
if (contextFiles.length > 0) {
|
|
284
|
-
prompt +=
|
|
255
|
+
prompt += '\n<supporting_files>\n';
|
|
285
256
|
for (const file of contextFiles) {
|
|
286
257
|
prompt += `<file name="${file.name}" type="${file.type}">\n${file.content}\n</file>\n`;
|
|
287
258
|
}
|
|
288
|
-
prompt +=
|
|
259
|
+
prompt += '</supporting_files>\n';
|
|
289
260
|
}
|
|
290
|
-
} catch (
|
|
291
|
-
this.logger.debug(
|
|
292
|
-
taskId: task.id,
|
|
293
|
-
});
|
|
261
|
+
} catch (error) {
|
|
262
|
+
this.logger.debug('No existing task files found for research', { taskId: task.id });
|
|
294
263
|
}
|
|
295
264
|
|
|
296
265
|
return prompt;
|
|
297
266
|
}
|
|
298
267
|
|
|
299
|
-
async buildPlanningPrompt(
|
|
300
|
-
task: Task,
|
|
301
|
-
repositoryPath?: string,
|
|
302
|
-
): Promise<string> {
|
|
268
|
+
async buildPlanningPrompt(task: Task, repositoryPath?: string): Promise<string> {
|
|
303
269
|
// Process file references in description
|
|
304
|
-
const { description: descriptionAfterFiles, referencedFiles } =
|
|
305
|
-
|
|
270
|
+
const { description: descriptionAfterFiles, referencedFiles } = await this.processFileReferences(
|
|
271
|
+
task.description,
|
|
272
|
+
repositoryPath
|
|
273
|
+
);
|
|
306
274
|
|
|
307
275
|
// Process URL references in description
|
|
308
|
-
const { description: processedDescription, referencedResources } =
|
|
309
|
-
|
|
276
|
+
const { description: processedDescription, referencedResources } = await this.processUrlReferences(
|
|
277
|
+
descriptionAfterFiles
|
|
278
|
+
);
|
|
310
279
|
|
|
311
|
-
let prompt =
|
|
280
|
+
let prompt = '<task>\n';
|
|
312
281
|
prompt += `<title>${task.title}</title>\n`;
|
|
313
282
|
prompt += `<description>${processedDescription}</description>\n`;
|
|
314
283
|
|
|
315
284
|
if ((task as any).primary_repository) {
|
|
316
285
|
prompt += `<repository>${(task as any).primary_repository}</repository>\n`;
|
|
317
286
|
}
|
|
318
|
-
prompt +=
|
|
287
|
+
prompt += '</task>\n';
|
|
319
288
|
|
|
320
289
|
// Add referenced files from @ mentions
|
|
321
290
|
if (referencedFiles.length > 0) {
|
|
322
|
-
prompt +=
|
|
291
|
+
prompt += '\n<referenced_files>\n';
|
|
323
292
|
for (const file of referencedFiles) {
|
|
324
293
|
prompt += `<file path="${file.path}">\n\`\`\`\n${file.content}\n\`\`\`\n</file>\n`;
|
|
325
294
|
}
|
|
326
|
-
prompt +=
|
|
295
|
+
prompt += '</referenced_files>\n';
|
|
327
296
|
}
|
|
328
297
|
|
|
329
298
|
// Add referenced resources from URL mentions
|
|
330
299
|
if (referencedResources.length > 0) {
|
|
331
|
-
prompt +=
|
|
300
|
+
prompt += '\n<referenced_resources>\n';
|
|
332
301
|
for (const resource of referencedResources) {
|
|
333
302
|
prompt += `<resource type="${resource.type}" url="${resource.url}">\n`;
|
|
334
303
|
prompt += `<title>${resource.title}</title>\n`;
|
|
335
304
|
prompt += `<content>${resource.content}</content>\n`;
|
|
336
|
-
prompt +=
|
|
305
|
+
prompt += '</resource>\n';
|
|
337
306
|
}
|
|
338
|
-
prompt +=
|
|
307
|
+
prompt += '</referenced_resources>\n';
|
|
339
308
|
}
|
|
340
309
|
|
|
341
310
|
try {
|
|
342
311
|
const taskFiles = await this.getTaskFiles(task.id);
|
|
343
|
-
const contextFiles = taskFiles.filter(
|
|
344
|
-
(f: any) => f.type === "context" || f.type === "reference",
|
|
345
|
-
);
|
|
312
|
+
const contextFiles = taskFiles.filter((f: any) => f.type === 'context' || f.type === 'reference');
|
|
346
313
|
if (contextFiles.length > 0) {
|
|
347
|
-
prompt +=
|
|
314
|
+
prompt += '\n<supporting_files>\n';
|
|
348
315
|
for (const file of contextFiles) {
|
|
349
316
|
prompt += `<file name="${file.name}" type="${file.type}">\n${file.content}\n</file>\n`;
|
|
350
317
|
}
|
|
351
|
-
prompt +=
|
|
318
|
+
prompt += '</supporting_files>\n';
|
|
352
319
|
}
|
|
353
|
-
} catch (
|
|
354
|
-
this.logger.debug(
|
|
355
|
-
taskId: task.id,
|
|
356
|
-
});
|
|
320
|
+
} catch (error) {
|
|
321
|
+
this.logger.debug('No existing task files found for planning', { taskId: task.id });
|
|
357
322
|
}
|
|
358
323
|
|
|
359
324
|
const templateVariables = {
|
|
360
325
|
task_id: task.id,
|
|
361
326
|
task_title: task.title,
|
|
362
327
|
task_description: processedDescription,
|
|
363
|
-
date: new Date().toISOString().split(
|
|
364
|
-
repository: ((task as any).primary_repository ||
|
|
328
|
+
date: new Date().toISOString().split('T')[0],
|
|
329
|
+
repository: ((task as any).primary_repository || '') as string,
|
|
365
330
|
};
|
|
366
331
|
|
|
367
332
|
const planTemplate = await this.generatePlanTemplate(templateVariables);
|
|
368
333
|
|
|
369
|
-
prompt +=
|
|
370
|
-
prompt +=
|
|
371
|
-
|
|
372
|
-
prompt +=
|
|
373
|
-
prompt += "<plan_template>\n";
|
|
334
|
+
prompt += '\n<instructions>\n';
|
|
335
|
+
prompt += 'Analyze the codebase and create a detailed implementation plan. Use the template structure below, filling each section with specific, actionable information.\n';
|
|
336
|
+
prompt += '</instructions>\n\n';
|
|
337
|
+
prompt += '<plan_template>\n';
|
|
374
338
|
prompt += planTemplate;
|
|
375
|
-
prompt +=
|
|
339
|
+
prompt += '\n</plan_template>';
|
|
376
340
|
|
|
377
341
|
return prompt;
|
|
378
342
|
}
|
|
379
343
|
|
|
380
|
-
async buildExecutionPrompt(
|
|
381
|
-
task: Task,
|
|
382
|
-
repositoryPath?: string,
|
|
383
|
-
): Promise<string> {
|
|
344
|
+
async buildExecutionPrompt(task: Task, repositoryPath?: string): Promise<string> {
|
|
384
345
|
// Process file references in description
|
|
385
|
-
const { description: descriptionAfterFiles, referencedFiles } =
|
|
386
|
-
|
|
346
|
+
const { description: descriptionAfterFiles, referencedFiles } = await this.processFileReferences(
|
|
347
|
+
task.description,
|
|
348
|
+
repositoryPath
|
|
349
|
+
);
|
|
387
350
|
|
|
388
351
|
// Process URL references in description
|
|
389
|
-
const { description: processedDescription, referencedResources } =
|
|
390
|
-
|
|
352
|
+
const { description: processedDescription, referencedResources } = await this.processUrlReferences(
|
|
353
|
+
descriptionAfterFiles
|
|
354
|
+
);
|
|
391
355
|
|
|
392
|
-
let prompt =
|
|
356
|
+
let prompt = '<task>\n';
|
|
393
357
|
prompt += `<title>${task.title}</title>\n`;
|
|
394
358
|
prompt += `<description>${processedDescription}</description>\n`;
|
|
395
359
|
|
|
396
360
|
if ((task as any).primary_repository) {
|
|
397
361
|
prompt += `<repository>${(task as any).primary_repository}</repository>\n`;
|
|
398
362
|
}
|
|
399
|
-
prompt +=
|
|
363
|
+
prompt += '</task>\n';
|
|
400
364
|
|
|
401
365
|
// Add referenced files from @ mentions
|
|
402
366
|
if (referencedFiles.length > 0) {
|
|
403
|
-
prompt +=
|
|
367
|
+
prompt += '\n<referenced_files>\n';
|
|
404
368
|
for (const file of referencedFiles) {
|
|
405
369
|
prompt += `<file path="${file.path}">\n\`\`\`\n${file.content}\n\`\`\`\n</file>\n`;
|
|
406
370
|
}
|
|
407
|
-
prompt +=
|
|
371
|
+
prompt += '</referenced_files>\n';
|
|
408
372
|
}
|
|
409
373
|
|
|
410
374
|
// Add referenced resources from URL mentions
|
|
411
375
|
if (referencedResources.length > 0) {
|
|
412
|
-
prompt +=
|
|
376
|
+
prompt += '\n<referenced_resources>\n';
|
|
413
377
|
for (const resource of referencedResources) {
|
|
414
378
|
prompt += `<resource type="${resource.type}" url="${resource.url}">\n`;
|
|
415
379
|
prompt += `<title>${resource.title}</title>\n`;
|
|
416
380
|
prompt += `<content>${resource.content}</content>\n`;
|
|
417
|
-
prompt +=
|
|
381
|
+
prompt += '</resource>\n';
|
|
418
382
|
}
|
|
419
|
-
prompt +=
|
|
383
|
+
prompt += '</referenced_resources>\n';
|
|
420
384
|
}
|
|
421
385
|
|
|
422
386
|
try {
|
|
423
387
|
const taskFiles = await this.getTaskFiles(task.id);
|
|
424
|
-
const hasPlan = taskFiles.some((f: any) => f.type ===
|
|
425
|
-
const todosFile = taskFiles.find((f: any) => f.name ===
|
|
388
|
+
const hasPlan = taskFiles.some((f: any) => f.type === 'plan');
|
|
389
|
+
const todosFile = taskFiles.find((f: any) => f.name === 'todos.json');
|
|
426
390
|
|
|
427
391
|
if (taskFiles.length > 0) {
|
|
428
|
-
prompt +=
|
|
392
|
+
prompt += '\n<context>\n';
|
|
429
393
|
for (const file of taskFiles) {
|
|
430
|
-
if (file.type ===
|
|
394
|
+
if (file.type === 'plan') {
|
|
431
395
|
prompt += `<plan>\n${file.content}\n</plan>\n`;
|
|
432
|
-
} else if (file.name ===
|
|
396
|
+
} else if (file.name === 'todos.json') {
|
|
397
|
+
// skip - we do this below
|
|
398
|
+
continue;
|
|
433
399
|
} else {
|
|
434
400
|
prompt += `<file name="${file.name}" type="${file.type}">\n${file.content}\n</file>\n`;
|
|
435
401
|
}
|
|
436
402
|
}
|
|
437
|
-
prompt +=
|
|
403
|
+
prompt += '</context>\n';
|
|
438
404
|
}
|
|
439
405
|
|
|
440
406
|
// Add todos context if resuming work
|
|
@@ -442,48 +408,37 @@ export class PromptBuilder {
|
|
|
442
408
|
try {
|
|
443
409
|
const todos = JSON.parse(todosFile.content);
|
|
444
410
|
if (todos.items && todos.items.length > 0) {
|
|
445
|
-
prompt +=
|
|
446
|
-
prompt +=
|
|
447
|
-
"You previously created the following todo list for this task:\n\n";
|
|
411
|
+
prompt += '\n<previous_todos>\n';
|
|
412
|
+
prompt += 'You previously created the following todo list for this task:\n\n';
|
|
448
413
|
for (const item of todos.items) {
|
|
449
|
-
const statusIcon =
|
|
450
|
-
item.status === "completed"
|
|
451
|
-
? "✓"
|
|
452
|
-
: item.status === "in_progress"
|
|
453
|
-
? "▶"
|
|
454
|
-
: "○";
|
|
414
|
+
const statusIcon = item.status === 'completed' ? '✓' : item.status === 'in_progress' ? '▶' : '○';
|
|
455
415
|
prompt += `${statusIcon} [${item.status}] ${item.content}\n`;
|
|
456
416
|
}
|
|
457
417
|
prompt += `\nProgress: ${todos.metadata.completed}/${todos.metadata.total} completed\n`;
|
|
458
|
-
prompt +=
|
|
459
|
-
|
|
460
|
-
prompt += "</previous_todos>\n";
|
|
418
|
+
prompt += '\nYou can reference this list when resuming work or create an updated list as needed.\n';
|
|
419
|
+
prompt += '</previous_todos>\n';
|
|
461
420
|
}
|
|
462
421
|
} catch (error) {
|
|
463
|
-
this.logger.debug(
|
|
464
|
-
error,
|
|
465
|
-
});
|
|
422
|
+
this.logger.debug('Failed to parse todos.json for context', { error });
|
|
466
423
|
}
|
|
467
424
|
}
|
|
468
425
|
|
|
469
|
-
prompt +=
|
|
426
|
+
prompt += '\n<instructions>\n';
|
|
470
427
|
if (hasPlan) {
|
|
471
|
-
prompt +=
|
|
472
|
-
"Implement the changes described in the execution plan. Follow the plan step-by-step and make the necessary file modifications.\n";
|
|
428
|
+
prompt += 'Implement the changes described in the execution plan. Follow the plan step-by-step and make the necessary file modifications.\n';
|
|
473
429
|
} else {
|
|
474
|
-
prompt +=
|
|
475
|
-
"Implement the changes described in the task. Make the necessary file modifications to complete the task.\n";
|
|
430
|
+
prompt += 'Implement the changes described in the task. Make the necessary file modifications to complete the task.\n';
|
|
476
431
|
}
|
|
477
|
-
prompt +=
|
|
478
|
-
} catch (
|
|
479
|
-
this.logger.debug(
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
prompt +=
|
|
483
|
-
prompt += "Implement the changes described in the task.\n";
|
|
484
|
-
prompt += "</instructions>";
|
|
432
|
+
prompt += '</instructions>';
|
|
433
|
+
} catch (error) {
|
|
434
|
+
this.logger.debug('No supporting files found for execution', { taskId: task.id });
|
|
435
|
+
prompt += '\n<instructions>\n';
|
|
436
|
+
prompt += 'Implement the changes described in the task.\n';
|
|
437
|
+
prompt += '</instructions>';
|
|
485
438
|
}
|
|
486
439
|
|
|
487
440
|
return prompt;
|
|
488
441
|
}
|
|
489
442
|
}
|
|
443
|
+
|
|
444
|
+
|