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