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