@posthog/agent 1.11.0 → 1.12.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/README.md +26 -65
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/src/adapters/types.d.ts +1 -1
- package/dist/src/agent.d.ts +0 -13
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +2 -214
- package/dist/src/agent.js.map +1 -1
- package/dist/src/agents/execution.d.ts +1 -1
- package/dist/src/agents/execution.js +2 -2
- package/dist/src/agents/execution.js.map +1 -1
- package/dist/src/git-manager.js +1 -1
- package/dist/src/git-manager.js.map +1 -1
- package/dist/src/posthog-api.d.ts +0 -8
- package/dist/src/posthog-api.d.ts.map +1 -1
- package/dist/src/posthog-api.js +0 -32
- package/dist/src/posthog-api.js.map +1 -1
- package/dist/src/task-progress-reporter.d.ts +0 -6
- package/dist/src/task-progress-reporter.d.ts.map +1 -1
- package/dist/src/task-progress-reporter.js +2 -26
- package/dist/src/task-progress-reporter.js.map +1 -1
- package/dist/src/template-manager.d.ts.map +1 -1
- package/dist/src/template-manager.js +26 -4
- package/dist/src/template-manager.js.map +1 -1
- package/dist/src/types.d.ts +0 -4
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +0 -1
- package/dist/src/types.js.map +1 -1
- package/package.json +2 -3
- package/src/adapters/types.ts +1 -1
- package/src/agent.ts +3 -234
- package/src/agents/execution.ts +2 -2
- package/src/git-manager.ts +1 -1
- package/src/posthog-api.ts +0 -40
- package/src/task-progress-reporter.ts +2 -34
- package/src/template-manager.ts +35 -5
- package/src/types.ts +0 -7
- package/dist/src/agent-registry.d.ts +0 -16
- package/dist/src/agent-registry.d.ts.map +0 -1
- package/dist/src/agent-registry.js +0 -62
- package/dist/src/agent-registry.js.map +0 -1
- package/dist/src/stage-executor.d.ts +0 -20
- package/dist/src/stage-executor.d.ts.map +0 -1
- package/dist/src/stage-executor.js +0 -178
- package/dist/src/stage-executor.js.map +0 -1
- package/dist/src/workflow-registry.d.ts +0 -11
- package/dist/src/workflow-registry.d.ts.map +0 -1
- package/dist/src/workflow-registry.js +0 -27
- package/dist/src/workflow-registry.js.map +0 -1
- package/dist/src/workflow-types.d.ts +0 -45
- package/dist/src/workflow-types.d.ts.map +0 -1
- package/src/agent-registry.ts +0 -65
- package/src/stage-executor.ts +0 -210
- package/src/workflow-registry.ts +0 -30
- package/src/workflow-types.ts +0 -52
package/src/agent.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
2
2
|
import type { Task, ExecutionResult, PlanResult, AgentConfig } from './types.js';
|
|
3
|
-
import type { WorkflowDefinition, WorkflowStage, WorkflowExecutionOptions } from './workflow-types.js';
|
|
4
3
|
import { TaskManager } from './task-manager.js';
|
|
5
4
|
import { PostHogAPIClient } from './posthog-api.js';
|
|
6
5
|
import { PostHogFileManager } from './file-manager.js';
|
|
@@ -11,9 +10,6 @@ import type { ProviderAdapter } from './adapters/types.js';
|
|
|
11
10
|
import { PLANNING_SYSTEM_PROMPT } from './agents/planning.js';
|
|
12
11
|
import { EXECUTION_SYSTEM_PROMPT } from './agents/execution.js';
|
|
13
12
|
import { Logger } from './utils/logger.js';
|
|
14
|
-
import { AgentRegistry } from './agent-registry.js';
|
|
15
|
-
import { WorkflowRegistry } from './workflow-registry.js';
|
|
16
|
-
import { StageExecutor } from './stage-executor.js';
|
|
17
13
|
import { PromptBuilder } from './prompt-builder.js';
|
|
18
14
|
import { TaskProgressReporter } from './task-progress-reporter.js';
|
|
19
15
|
import { OpenAIExtractor, type ExtractedQuestion, type ExtractedQuestionWithAnswer } from './structured-extraction.js';
|
|
@@ -28,9 +24,6 @@ export class Agent {
|
|
|
28
24
|
private templateManager: TemplateManager;
|
|
29
25
|
private adapter: ProviderAdapter;
|
|
30
26
|
private logger: Logger;
|
|
31
|
-
private agentRegistry: AgentRegistry;
|
|
32
|
-
private workflowRegistry: WorkflowRegistry;
|
|
33
|
-
private stageExecutor: StageExecutor;
|
|
34
27
|
private progressReporter: TaskProgressReporter;
|
|
35
28
|
private promptBuilder: PromptBuilder;
|
|
36
29
|
private extractor?: OpenAIExtractor;
|
|
@@ -81,7 +74,6 @@ export class Agent {
|
|
|
81
74
|
// TODO: Add author config from environment or config
|
|
82
75
|
});
|
|
83
76
|
this.templateManager = new TemplateManager();
|
|
84
|
-
this.agentRegistry = new AgentRegistry();
|
|
85
77
|
|
|
86
78
|
if (config.posthogApiUrl && config.posthogApiKey) {
|
|
87
79
|
this.posthogAPI = new PostHogAPIClient({
|
|
@@ -90,21 +82,12 @@ export class Agent {
|
|
|
90
82
|
});
|
|
91
83
|
}
|
|
92
84
|
|
|
93
|
-
this.workflowRegistry = new WorkflowRegistry(this.posthogAPI);
|
|
94
85
|
this.promptBuilder = new PromptBuilder({
|
|
95
86
|
getTaskFiles: (taskId: string) => this.getTaskFiles(taskId),
|
|
96
87
|
generatePlanTemplate: (vars) => this.templateManager.generatePlan(vars),
|
|
97
88
|
posthogClient: this.posthogAPI,
|
|
98
89
|
logger: this.logger.child('PromptBuilder')
|
|
99
90
|
});
|
|
100
|
-
this.stageExecutor = new StageExecutor(
|
|
101
|
-
this.agentRegistry,
|
|
102
|
-
this.logger,
|
|
103
|
-
this.promptBuilder,
|
|
104
|
-
undefined, // eventHandler set via setEventHandler below
|
|
105
|
-
this.mcpServers
|
|
106
|
-
);
|
|
107
|
-
this.stageExecutor.setEventHandler((event) => this.emitEvent(event));
|
|
108
91
|
this.progressReporter = new TaskProgressReporter(this.posthogAPI, this.logger);
|
|
109
92
|
|
|
110
93
|
// Initialize OpenAI extractor if API key is available
|
|
@@ -147,196 +130,7 @@ export class Agent {
|
|
|
147
130
|
}
|
|
148
131
|
}
|
|
149
132
|
|
|
150
|
-
//
|
|
151
|
-
async runWorkflow(taskOrId: Task | string, workflowId: string, options: WorkflowExecutionOptions = {}): Promise<{ task: Task; workflow: WorkflowDefinition }> {
|
|
152
|
-
await this._configureLlmGateway();
|
|
153
|
-
|
|
154
|
-
const task = typeof taskOrId === 'string' ? await this.fetchTask(taskOrId) : taskOrId;
|
|
155
|
-
await this.workflowRegistry.loadWorkflows();
|
|
156
|
-
const workflow = this.workflowRegistry.getWorkflow(workflowId);
|
|
157
|
-
if (!workflow) {
|
|
158
|
-
throw new Error(`Workflow ${workflowId} not found`);
|
|
159
|
-
}
|
|
160
|
-
const orderedStages = [...workflow.stages].sort((a, b) => a.position - b.position);
|
|
161
|
-
|
|
162
|
-
// Ensure task is assigned to workflow and positioned at first stage
|
|
163
|
-
if (this.posthogAPI) {
|
|
164
|
-
try {
|
|
165
|
-
if ((task.workflow as any) !== workflowId) {
|
|
166
|
-
await this.posthogAPI.updateTask(task.id, { workflow: workflowId } as any);
|
|
167
|
-
(task as any).workflow = workflowId;
|
|
168
|
-
}
|
|
169
|
-
} catch (e) {
|
|
170
|
-
this.logger.warn('Failed to sync task workflow before execution', { error: (e as Error).message });
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const executionId = this.taskManager.generateExecutionId();
|
|
175
|
-
this.logger.info('Starting workflow execution', { taskId: task.id, workflowId, executionId });
|
|
176
|
-
this.taskManager.startExecution(task.id, 'plan_and_build', executionId);
|
|
177
|
-
await this.progressReporter.start(task.id, {
|
|
178
|
-
totalSteps: orderedStages.length,
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
// Set initial stage on the newly created run
|
|
182
|
-
const firstStage = orderedStages[0];
|
|
183
|
-
if (this.posthogAPI && this.progressReporter.runId && firstStage) {
|
|
184
|
-
try {
|
|
185
|
-
await this.posthogAPI.updateTaskRun(task.id, this.progressReporter.runId, {
|
|
186
|
-
current_stage: firstStage.id
|
|
187
|
-
});
|
|
188
|
-
} catch (e) {
|
|
189
|
-
this.logger.warn('Failed to set initial stage on run', { error: (e as Error).message });
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
try {
|
|
194
|
-
let startIndex = 0;
|
|
195
|
-
const currentStageId = (task as any).current_stage as string | undefined;
|
|
196
|
-
|
|
197
|
-
// If task is already at the last stage, fail gracefully without progressing
|
|
198
|
-
if (currentStageId) {
|
|
199
|
-
const currIdx = orderedStages.findIndex(s => s.id === currentStageId);
|
|
200
|
-
const atLastStage = currIdx >= 0 && currIdx === orderedStages.length - 1;
|
|
201
|
-
if (atLastStage) {
|
|
202
|
-
const finalStageKey = orderedStages[currIdx]?.key;
|
|
203
|
-
this.emitEvent(this.adapter.createStatusEvent('no_next_stage', { stage: finalStageKey }));
|
|
204
|
-
await this.progressReporter.noNextStage(finalStageKey);
|
|
205
|
-
await this.progressReporter.complete();
|
|
206
|
-
this.taskManager.completeExecution(executionId, { task, workflow });
|
|
207
|
-
return { task, workflow };
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (options.resumeFromCurrentStage && currentStageId) {
|
|
212
|
-
const idx = orderedStages.findIndex(s => s.id === currentStageId);
|
|
213
|
-
if (idx >= 0) startIndex = idx;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Align server-side stage when restarting from a different stage
|
|
217
|
-
if (this.posthogAPI && this.progressReporter.runId) {
|
|
218
|
-
const targetStage = orderedStages[startIndex];
|
|
219
|
-
if (targetStage && targetStage.id !== currentStageId) {
|
|
220
|
-
try {
|
|
221
|
-
await this.posthogAPI.updateTaskRun(task.id, this.progressReporter.runId, {
|
|
222
|
-
current_stage: targetStage.id
|
|
223
|
-
});
|
|
224
|
-
} catch (e) {
|
|
225
|
-
this.logger.warn('Failed to update run stage', { error: (e as Error).message });
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
for (let i = startIndex; i < orderedStages.length; i++) {
|
|
231
|
-
const stage = orderedStages[i];
|
|
232
|
-
await this.progressReporter.stageStarted(stage.key, i);
|
|
233
|
-
await this.executeStage(task, stage, options);
|
|
234
|
-
await this.progressReporter.stageCompleted(stage.key, i + 1);
|
|
235
|
-
if (options.autoProgress) {
|
|
236
|
-
const hasNext = i < orderedStages.length - 1;
|
|
237
|
-
if (hasNext) {
|
|
238
|
-
await this.progressToNextStage(task.id, stage.key);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
await this.progressReporter.complete();
|
|
243
|
-
this.taskManager.completeExecution(executionId, { task, workflow });
|
|
244
|
-
return { task, workflow };
|
|
245
|
-
} catch (error) {
|
|
246
|
-
await this.progressReporter.fail(error as Error);
|
|
247
|
-
this.taskManager.failExecution(executionId, error as Error);
|
|
248
|
-
throw error;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
async executeStage(task: Task, stage: WorkflowStage, options: WorkflowExecutionOptions = {}): Promise<void> {
|
|
253
|
-
this.emitEvent(this.adapter.createStatusEvent('stage_start', { stage: stage.key }));
|
|
254
|
-
const overrides = options.stageOverrides?.[stage.key];
|
|
255
|
-
const agentName = stage.agent_name || 'code_generation';
|
|
256
|
-
const agentDef = this.agentRegistry.getAgent(agentName);
|
|
257
|
-
const isManual = stage.is_manual_only === true;
|
|
258
|
-
const stageKeyLower = (stage.key || '').toLowerCase().trim();
|
|
259
|
-
const isPlanningByKey = stageKeyLower === 'plan' || stageKeyLower.includes('plan');
|
|
260
|
-
const isPlanning = !isManual && ((agentDef?.agent_type === 'planning') || isPlanningByKey);
|
|
261
|
-
const shouldCreatePlanningBranch = overrides?.createPlanningBranch !== false; // default true
|
|
262
|
-
const shouldCreateImplBranch = overrides?.createImplementationBranch !== false; // default true
|
|
263
|
-
|
|
264
|
-
if (isPlanning && shouldCreatePlanningBranch) {
|
|
265
|
-
const planningBranch = await this.createPlanningBranch(task.id);
|
|
266
|
-
await this.updateTaskBranch(task.id, planningBranch);
|
|
267
|
-
this.emitEvent(this.adapter.createStatusEvent('branch_created', { stage: stage.key, branch: planningBranch }));
|
|
268
|
-
await this.progressReporter.branchCreated(stage.key, planningBranch);
|
|
269
|
-
} else if (!isPlanning && !isManual && shouldCreateImplBranch) {
|
|
270
|
-
const implBranch = await this.createImplementationBranch(task.id);
|
|
271
|
-
await this.updateTaskBranch(task.id, implBranch);
|
|
272
|
-
this.emitEvent(this.adapter.createStatusEvent('branch_created', { stage: stage.key, branch: implBranch }));
|
|
273
|
-
await this.progressReporter.branchCreated(stage.key, implBranch);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const result = await this.stageExecutor.execute(task, stage, options);
|
|
277
|
-
|
|
278
|
-
if (result.plan) {
|
|
279
|
-
await this.writePlan(task.id, result.plan);
|
|
280
|
-
await this.commitPlan(task.id, task.title);
|
|
281
|
-
this.emitEvent(this.adapter.createStatusEvent('commit_made', { stage: stage.key, kind: 'plan' }));
|
|
282
|
-
await this.progressReporter.commitMade(stage.key, 'plan');
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (isManual) {
|
|
286
|
-
const defaultOpenPR = true; // manual stages default to PR for review
|
|
287
|
-
const openPR = overrides?.openPullRequest ?? defaultOpenPR;
|
|
288
|
-
if (openPR) {
|
|
289
|
-
// Ensure we're on an implementation branch for PRs
|
|
290
|
-
let branchName = await this.gitManager.getCurrentBranch();
|
|
291
|
-
const onTaskBranch = branchName.includes(`posthog/task-${task.id}`);
|
|
292
|
-
if (!onTaskBranch && (overrides?.createImplementationBranch !== false)) {
|
|
293
|
-
const implBranch = await this.createImplementationBranch(task.id);
|
|
294
|
-
await this.updateTaskBranch(task.id, implBranch);
|
|
295
|
-
branchName = implBranch;
|
|
296
|
-
this.emitEvent(this.adapter.createStatusEvent('branch_created', { stage: stage.key, branch: implBranch }));
|
|
297
|
-
await this.progressReporter.branchCreated(stage.key, implBranch);
|
|
298
|
-
}
|
|
299
|
-
try {
|
|
300
|
-
const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
|
|
301
|
-
await this.updateTaskBranch(task.id, branchName);
|
|
302
|
-
await this.attachPullRequestToTask(task.id, prUrl, branchName);
|
|
303
|
-
this.emitEvent(this.adapter.createStatusEvent('pr_created', { stage: stage.key, prUrl }));
|
|
304
|
-
await this.progressReporter.pullRequestCreated(stage.key, prUrl);
|
|
305
|
-
} catch {}
|
|
306
|
-
}
|
|
307
|
-
// Do not auto-progress on manual stages
|
|
308
|
-
this.emitEvent(this.adapter.createStatusEvent('stage_complete', { stage: stage.key }));
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if (result.results) {
|
|
313
|
-
const existingPlan = await this.readPlan(task.id);
|
|
314
|
-
const planSummary = existingPlan ? existingPlan.split('\n')[0] : undefined;
|
|
315
|
-
await this.commitImplementation(task.id, task.title, planSummary);
|
|
316
|
-
this.emitEvent(this.adapter.createStatusEvent('commit_made', { stage: stage.key, kind: 'implementation' }));
|
|
317
|
-
await this.progressReporter.commitMade(stage.key, 'implementation');
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// PR creation on complete stage (or if explicitly requested), regardless of whether edits occurred
|
|
321
|
-
{
|
|
322
|
-
const defaultOpenPR = stage.key.toLowerCase().includes('complete');
|
|
323
|
-
const openPR = overrides?.openPullRequest ?? defaultOpenPR;
|
|
324
|
-
if (openPR) {
|
|
325
|
-
const branchName = await this.gitManager.getCurrentBranch();
|
|
326
|
-
try {
|
|
327
|
-
const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
|
|
328
|
-
await this.updateTaskBranch(task.id, branchName);
|
|
329
|
-
await this.attachPullRequestToTask(task.id, prUrl, branchName);
|
|
330
|
-
this.emitEvent(this.adapter.createStatusEvent('pr_created', { stage: stage.key, prUrl }));
|
|
331
|
-
await this.progressReporter.pullRequestCreated(stage.key, prUrl);
|
|
332
|
-
} catch {}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
this.emitEvent(this.adapter.createStatusEvent('stage_complete', { stage: stage.key }));
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// Adaptive task execution - 3-phase workflow (research → plan → build)
|
|
133
|
+
// Adaptive task execution - 3 phases (research → plan → build)
|
|
340
134
|
async runTask(taskOrId: Task | string, options: import('./types.js').TaskExecutionOptions = {}): Promise<void> {
|
|
341
135
|
await this._configureLlmGateway();
|
|
342
136
|
|
|
@@ -671,28 +465,6 @@ export class Agent {
|
|
|
671
465
|
this.emitEvent(this.adapter.createStatusEvent('task_complete', { taskId: task.id }));
|
|
672
466
|
}
|
|
673
467
|
|
|
674
|
-
async progressToNextStage(taskId: string, currentStageKey?: string): Promise<void> {
|
|
675
|
-
if (!this.posthogAPI || !this.progressReporter.runId) {
|
|
676
|
-
throw new Error('PostHog API not configured or no active run. Cannot progress stage.');
|
|
677
|
-
}
|
|
678
|
-
try {
|
|
679
|
-
await this.posthogAPI.progressTaskRun(taskId, this.progressReporter.runId);
|
|
680
|
-
} catch (error) {
|
|
681
|
-
if (error instanceof Error && error.message.includes('No next stage available')) {
|
|
682
|
-
this.logger.warn('No next stage available when attempting to progress run', {
|
|
683
|
-
taskId,
|
|
684
|
-
runId: this.progressReporter.runId,
|
|
685
|
-
stage: currentStageKey,
|
|
686
|
-
error: error.message,
|
|
687
|
-
});
|
|
688
|
-
this.emitEvent(this.adapter.createStatusEvent('no_next_stage', { stage: currentStageKey }));
|
|
689
|
-
await this.progressReporter.noNextStage(currentStageKey);
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
throw error;
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
|
|
696
468
|
// Direct prompt execution - still supported for low-level usage
|
|
697
469
|
async run(prompt: string, options: { repositoryPath?: string; permissionMode?: import('./types.js').PermissionMode; queryOverrides?: Record<string, any> } = {}): Promise<ExecutionResult> {
|
|
698
470
|
await this._configureLlmGateway();
|
|
@@ -744,8 +516,6 @@ export class Agent {
|
|
|
744
516
|
repository?: string;
|
|
745
517
|
organization?: string;
|
|
746
518
|
origin_product?: string;
|
|
747
|
-
workflow?: string;
|
|
748
|
-
current_stage?: string;
|
|
749
519
|
}): Promise<Task[]> {
|
|
750
520
|
if (!this.posthogAPI) {
|
|
751
521
|
throw new Error('PostHog API not configured. Provide posthogApiUrl and posthogApiKey in constructor.');
|
|
@@ -799,8 +569,8 @@ export class Agent {
|
|
|
799
569
|
return await this.extractor.extractQuestions(researchContent);
|
|
800
570
|
}
|
|
801
571
|
}
|
|
802
|
-
|
|
803
|
-
// Git operations for task
|
|
572
|
+
|
|
573
|
+
// Git operations for task execution
|
|
804
574
|
async createPlanningBranch(taskId: string): Promise<string> {
|
|
805
575
|
this.logger.info('Creating planning branch', { taskId });
|
|
806
576
|
const branchName = await this.gitManager.createTaskPlanningBranch(taskId);
|
|
@@ -925,4 +695,3 @@ Generated by PostHog Agent`;
|
|
|
925
695
|
|
|
926
696
|
export { PermissionMode } from './types.js';
|
|
927
697
|
export type { Task, SupportingFile, ExecutionResult, AgentConfig } from './types.js';
|
|
928
|
-
export type { WorkflowDefinition, WorkflowStage, WorkflowExecutionOptions } from './workflow-types.js';
|
package/src/agents/execution.ts
CHANGED
|
@@ -34,11 +34,11 @@ export const EXECUTION_SYSTEM_PROMPT = `<context>
|
|
|
34
34
|
- Verified no build artifacts or dependencies are being committed
|
|
35
35
|
</checklist>
|
|
36
36
|
|
|
37
|
-
<
|
|
37
|
+
<approach>
|
|
38
38
|
- first make a plan and create a todo list
|
|
39
39
|
- execute the todo list one by one
|
|
40
40
|
- test the changes
|
|
41
|
-
</
|
|
41
|
+
</approach>
|
|
42
42
|
|
|
43
43
|
<output_format>
|
|
44
44
|
Once finished respond with a summary of changes made
|
package/src/git-manager.ts
CHANGED
|
@@ -161,7 +161,7 @@ export class GitManager {
|
|
|
161
161
|
await this.runGitCommand(`push ${forceFlag} -u origin ${branchName}`);
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
// Utility methods for PostHog task
|
|
164
|
+
// Utility methods for PostHog task execution
|
|
165
165
|
async createTaskPlanningBranch(taskId: string, baseBranch?: string): Promise<string> {
|
|
166
166
|
let branchName = `posthog/task-${taskId}-planning`;
|
|
167
167
|
let counter = 1;
|
package/src/posthog-api.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Task, TaskRun, LogEntry, SupportingFile, PostHogAPIConfig, PostHogResource, ResourceType, UrlMention } from './types.js';
|
|
2
|
-
import type { WorkflowDefinition, AgentDefinition } from './workflow-types.js';
|
|
3
2
|
|
|
4
3
|
interface PostHogApiResponse<T> {
|
|
5
4
|
results?: T[];
|
|
@@ -107,8 +106,6 @@ export class PostHogAPIClient {
|
|
|
107
106
|
repository?: string;
|
|
108
107
|
organization?: string;
|
|
109
108
|
origin_product?: string;
|
|
110
|
-
workflow?: string;
|
|
111
|
-
current_stage?: string;
|
|
112
109
|
}): Promise<Task[]> {
|
|
113
110
|
const teamId = await this.getTeamId();
|
|
114
111
|
const url = new URL(`${this.baseUrl}/api/projects/${teamId}/tasks/`);
|
|
@@ -171,26 +168,6 @@ export class PostHogAPIClient {
|
|
|
171
168
|
});
|
|
172
169
|
}
|
|
173
170
|
|
|
174
|
-
async updateTaskRunStage(taskId: string, runId: string, stageId: string): Promise<TaskRun> {
|
|
175
|
-
const teamId = await this.getTeamId();
|
|
176
|
-
return this.apiRequest<TaskRun>(`/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/update_stage/`, {
|
|
177
|
-
method: 'PATCH',
|
|
178
|
-
body: JSON.stringify({ current_stage: stageId }),
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
async progressTaskRun(taskId: string, runId: string, nextStageId?: string): Promise<TaskRun> {
|
|
183
|
-
const teamId = await this.getTeamId();
|
|
184
|
-
const payload: Record<string, string> = {};
|
|
185
|
-
if (nextStageId) {
|
|
186
|
-
payload.next_stage_id = nextStageId;
|
|
187
|
-
}
|
|
188
|
-
return this.apiRequest<TaskRun>(`/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/progress_run/`, {
|
|
189
|
-
method: 'POST',
|
|
190
|
-
body: JSON.stringify(payload),
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
|
|
194
171
|
async setTaskRunOutput(taskId: string, runId: string, output: Record<string, unknown>): Promise<TaskRun> {
|
|
195
172
|
const teamId = await this.getTeamId();
|
|
196
173
|
return this.apiRequest<TaskRun>(`/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/set_output/`, {
|
|
@@ -207,23 +184,6 @@ export class PostHogAPIClient {
|
|
|
207
184
|
});
|
|
208
185
|
}
|
|
209
186
|
|
|
210
|
-
// Workflow endpoints
|
|
211
|
-
async fetchWorkflow(workflowId: string): Promise<WorkflowDefinition> {
|
|
212
|
-
const teamId = await this.getTeamId();
|
|
213
|
-
return this.apiRequest<WorkflowDefinition>(`/api/projects/${teamId}/workflows/${workflowId}/`);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
async listWorkflows(): Promise<WorkflowDefinition[]> {
|
|
217
|
-
const teamId = await this.getTeamId();
|
|
218
|
-
const response = await this.apiRequest<PostHogApiResponse<WorkflowDefinition>>(`/api/projects/${teamId}/workflows/`);
|
|
219
|
-
return response.results || [];
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Agent catalog exposure
|
|
223
|
-
async listAgents(): Promise<AgentDefinition[]> {
|
|
224
|
-
return this.apiRequest<AgentDefinition[]>(`/api/agents/`);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
187
|
/**
|
|
228
188
|
* Fetch error details from PostHog error tracking
|
|
229
189
|
*/
|
|
@@ -51,45 +51,13 @@ export class TaskProgressReporter {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
async stageStarted(stageKey: string, stageIndex: number): Promise<void> {
|
|
55
|
-
await this.update({
|
|
56
|
-
status: 'in_progress',
|
|
57
|
-
}, `Stage started: ${stageKey}`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async stageCompleted(stageKey: string, completedStages: number): Promise<void> {
|
|
61
|
-
await this.update({
|
|
62
|
-
status: 'in_progress',
|
|
63
|
-
}, `Stage completed: ${stageKey}`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async branchCreated(stageKey: string, branchName: string): Promise<void> {
|
|
67
|
-
await this.appendLog(`Branch created (${stageKey}): ${branchName}`);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async commitMade(stageKey: string, kind: 'plan' | 'implementation'): Promise<void> {
|
|
71
|
-
await this.appendLog(`Commit made (${stageKey}, ${kind})`);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async pullRequestCreated(stageKey: string, prUrl: string): Promise<void> {
|
|
75
|
-
await this.appendLog(`Pull request created (${stageKey}): ${prUrl}`);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async noNextStage(stageKey?: string): Promise<void> {
|
|
79
|
-
await this.appendLog(
|
|
80
|
-
stageKey
|
|
81
|
-
? `No next stage available after '${stageKey}'. Execution halted.`
|
|
82
|
-
: 'No next stage available. Execution halted.'
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
54
|
async complete(): Promise<void> {
|
|
87
|
-
await this.update({ status: 'completed' }, '
|
|
55
|
+
await this.update({ status: 'completed' }, 'Task execution completed');
|
|
88
56
|
}
|
|
89
57
|
|
|
90
58
|
async fail(error: Error | string): Promise<void> {
|
|
91
59
|
const message = typeof error === 'string' ? error : error.message;
|
|
92
|
-
await this.update({ status: 'failed', error_message: message }, `
|
|
60
|
+
await this.update({ status: 'failed', error_message: message }, `Task execution failed: ${message}`);
|
|
93
61
|
}
|
|
94
62
|
|
|
95
63
|
async appendLog(line: string): Promise<void> {
|
package/src/template-manager.ts
CHANGED
|
@@ -17,14 +17,45 @@ export class TemplateManager {
|
|
|
17
17
|
constructor() {
|
|
18
18
|
const __filename = fileURLToPath(import.meta.url);
|
|
19
19
|
const __dirname = dirname(__filename);
|
|
20
|
+
|
|
21
|
+
// Exhaustive list of possible template locations
|
|
20
22
|
const candidateDirs = [
|
|
21
|
-
|
|
23
|
+
// Standard build output (dist/src/template-manager.js -> dist/templates)
|
|
22
24
|
join(__dirname, '..', 'templates'),
|
|
25
|
+
|
|
26
|
+
// If preserveModules creates nested structure (dist/src/template-manager.js -> dist/src/templates)
|
|
27
|
+
join(__dirname, 'templates'),
|
|
28
|
+
|
|
29
|
+
// Development scenarios (src/template-manager.ts -> src/templates)
|
|
30
|
+
join(__dirname, '..', '..', 'src', 'templates'),
|
|
31
|
+
|
|
32
|
+
// Package root templates directory
|
|
23
33
|
join(__dirname, '..', '..', 'templates'),
|
|
24
|
-
|
|
34
|
+
|
|
35
|
+
// When node_modules symlink or installed (node_modules/@posthog/agent/dist/src/... -> node_modules/@posthog/agent/dist/templates)
|
|
36
|
+
join(__dirname, '..', '..', 'dist', 'templates'),
|
|
37
|
+
|
|
38
|
+
// When consumed from node_modules deep in tree
|
|
39
|
+
join(__dirname, '..', '..', '..', 'templates'),
|
|
40
|
+
join(__dirname, '..', '..', '..', 'dist', 'templates'),
|
|
41
|
+
join(__dirname, '..', '..', '..', 'src', 'templates'),
|
|
42
|
+
|
|
43
|
+
// When bundled by Vite/Webpack (e.g., .vite/build/index.js -> node_modules/@posthog/agent/dist/templates)
|
|
44
|
+
// Try to find node_modules from current location
|
|
45
|
+
join(__dirname, '..', 'node_modules', '@posthog', 'agent', 'dist', 'templates'),
|
|
46
|
+
join(__dirname, '..', '..', 'node_modules', '@posthog', 'agent', 'dist', 'templates'),
|
|
47
|
+
join(__dirname, '..', '..', '..', 'node_modules', '@posthog', 'agent', 'dist', 'templates'),
|
|
25
48
|
];
|
|
26
49
|
|
|
27
50
|
const resolvedDir = candidateDirs.find((dir) => existsSync(dir));
|
|
51
|
+
|
|
52
|
+
if (!resolvedDir) {
|
|
53
|
+
console.error('[TemplateManager] Could not find templates directory.');
|
|
54
|
+
console.error('[TemplateManager] Current file:', __filename);
|
|
55
|
+
console.error('[TemplateManager] Current dir:', __dirname);
|
|
56
|
+
console.error('[TemplateManager] Tried:', candidateDirs.map(d => `\n - ${d} (exists: ${existsSync(d)})`).join(''));
|
|
57
|
+
}
|
|
58
|
+
|
|
28
59
|
this.templatesDir = resolvedDir ?? candidateDirs[0];
|
|
29
60
|
}
|
|
30
61
|
|
|
@@ -33,7 +64,7 @@ export class TemplateManager {
|
|
|
33
64
|
const templatePath = join(this.templatesDir, templateName);
|
|
34
65
|
return await fs.readFile(templatePath, 'utf8');
|
|
35
66
|
} catch (error) {
|
|
36
|
-
throw new Error(`Failed to load template ${templateName}: ${error}`);
|
|
67
|
+
throw new Error(`Failed to load template ${templateName} from ${this.templatesDir}: ${error}`);
|
|
37
68
|
}
|
|
38
69
|
}
|
|
39
70
|
|
|
@@ -60,7 +91,6 @@ export class TemplateManager {
|
|
|
60
91
|
});
|
|
61
92
|
}
|
|
62
93
|
|
|
63
|
-
|
|
64
94
|
async generateCustomFile(templateName: string, variables: TemplateVariables): Promise<string> {
|
|
65
95
|
const template = await this.loadTemplate(templateName);
|
|
66
96
|
return this.substituteVariables(template, {
|
|
@@ -147,7 +177,7 @@ These files are:
|
|
|
147
177
|
Customize \`.posthog/.gitignore\` to control which files are committed:
|
|
148
178
|
- Include plans and documentation by default
|
|
149
179
|
- Exclude temporary files and sensitive data
|
|
150
|
-
- Customize based on your team's
|
|
180
|
+
- Customize based on your team's needs
|
|
151
181
|
|
|
152
182
|
---
|
|
153
183
|
|
package/src/types.ts
CHANGED
|
@@ -5,7 +5,6 @@ export interface Task {
|
|
|
5
5
|
description: string;
|
|
6
6
|
origin_product: 'error_tracking' | 'eval_clusters' | 'user_created' | 'support_queue' | 'session_summaries';
|
|
7
7
|
position?: number;
|
|
8
|
-
workflow?: string | null;
|
|
9
8
|
github_integration?: number | null;
|
|
10
9
|
repository_config?: unknown; // JSONField
|
|
11
10
|
repository_list: string;
|
|
@@ -34,7 +33,6 @@ export interface TaskRun {
|
|
|
34
33
|
task: string; // Task ID
|
|
35
34
|
team: number;
|
|
36
35
|
branch: string | null;
|
|
37
|
-
current_stage: string | null; // WorkflowStage ID
|
|
38
36
|
status: 'started' | 'in_progress' | 'completed' | 'failed';
|
|
39
37
|
log: LogEntry[]; // Array of log entry objects
|
|
40
38
|
error_message: string | null;
|
|
@@ -52,8 +50,6 @@ export interface SupportingFile {
|
|
|
52
50
|
created_at: string;
|
|
53
51
|
}
|
|
54
52
|
|
|
55
|
-
// Removed legacy ExecutionMode in favor of configurable workflows
|
|
56
|
-
|
|
57
53
|
export enum PermissionMode {
|
|
58
54
|
PLAN = "plan",
|
|
59
55
|
DEFAULT = "default",
|
|
@@ -155,11 +151,9 @@ export interface StatusEvent extends BaseEvent {
|
|
|
155
151
|
type: 'status';
|
|
156
152
|
phase: string;
|
|
157
153
|
// Common optional fields (varies by phase):
|
|
158
|
-
stage?: string; // Workflow stage (plan, code, complete)
|
|
159
154
|
kind?: string; // Kind of status (plan, implementation)
|
|
160
155
|
branch?: string; // Git branch name
|
|
161
156
|
prUrl?: string; // Pull request URL
|
|
162
|
-
workflowId?: string; // Workflow identifier
|
|
163
157
|
taskId?: string; // Task identifier
|
|
164
158
|
messageId?: string; // Claude message ID
|
|
165
159
|
model?: string; // Model name
|
|
@@ -271,7 +265,6 @@ export interface TaskExecutionResult {
|
|
|
271
265
|
task: Task;
|
|
272
266
|
plan?: string;
|
|
273
267
|
executionResult?: ExecutionResult;
|
|
274
|
-
// Deprecated: mode removed in workflow-based execution
|
|
275
268
|
}
|
|
276
269
|
|
|
277
270
|
// MCP Server configuration types (re-exported from Claude SDK for convenience)
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { AgentDefinition, AgentType } from './workflow-types.js';
|
|
2
|
-
export declare class AgentRegistry {
|
|
3
|
-
private agentsByName;
|
|
4
|
-
constructor(definitions?: AgentDefinition[]);
|
|
5
|
-
static getDefaultAgents(): AgentDefinition[];
|
|
6
|
-
register(def: AgentDefinition): void;
|
|
7
|
-
getAgent(name: string): AgentDefinition | undefined;
|
|
8
|
-
listAgents(): AgentDefinition[];
|
|
9
|
-
exportForPostHog(): {
|
|
10
|
-
id: string;
|
|
11
|
-
name: string;
|
|
12
|
-
agent_type: AgentType;
|
|
13
|
-
description?: string;
|
|
14
|
-
}[];
|
|
15
|
-
}
|
|
16
|
-
//# sourceMappingURL=agent-registry.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"agent-registry.d.ts","sourceRoot":"","sources":["../../src/agent-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEtE,qBAAa,aAAa;IACxB,OAAO,CAAC,YAAY,CAA2C;gBAEnD,WAAW,CAAC,EAAE,eAAe,EAAE;IAQ3C,MAAM,CAAC,gBAAgB,IAAI,eAAe,EAAE;IAmC5C,QAAQ,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;IAIpC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAInD,UAAU,IAAI,eAAe,EAAE;IAI/B,gBAAgB,IAAI;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,SAAS,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE;CAGhG"}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
class AgentRegistry {
|
|
2
|
-
agentsByName = new Map();
|
|
3
|
-
constructor(definitions) {
|
|
4
|
-
if (definitions) {
|
|
5
|
-
for (const def of definitions)
|
|
6
|
-
this.register(def);
|
|
7
|
-
}
|
|
8
|
-
else {
|
|
9
|
-
for (const def of AgentRegistry.getDefaultAgents())
|
|
10
|
-
this.register(def);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
static getDefaultAgents() {
|
|
14
|
-
return [
|
|
15
|
-
{
|
|
16
|
-
id: 'research',
|
|
17
|
-
name: 'research',
|
|
18
|
-
agent_type: 'research',
|
|
19
|
-
description: 'Explore codebase and generate clarifying questions',
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
id: 'planning',
|
|
23
|
-
name: 'planning',
|
|
24
|
-
agent_type: 'planning',
|
|
25
|
-
description: 'Analyze repo and produce implementation plan',
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
id: 'code_generation',
|
|
29
|
-
name: 'code_generation',
|
|
30
|
-
agent_type: 'execution',
|
|
31
|
-
description: 'Implements code changes using Claude SDK',
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
id: 'review',
|
|
35
|
-
name: 'review',
|
|
36
|
-
agent_type: 'review',
|
|
37
|
-
description: 'Reviews changes and suggests fixes',
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
id: 'testing',
|
|
41
|
-
name: 'testing',
|
|
42
|
-
agent_type: 'testing',
|
|
43
|
-
description: 'Runs tests and reports results',
|
|
44
|
-
},
|
|
45
|
-
];
|
|
46
|
-
}
|
|
47
|
-
register(def) {
|
|
48
|
-
this.agentsByName.set(def.name, def);
|
|
49
|
-
}
|
|
50
|
-
getAgent(name) {
|
|
51
|
-
return this.agentsByName.get(name);
|
|
52
|
-
}
|
|
53
|
-
listAgents() {
|
|
54
|
-
return Array.from(this.agentsByName.values());
|
|
55
|
-
}
|
|
56
|
-
exportForPostHog() {
|
|
57
|
-
return this.listAgents().map(({ id, name, agent_type, description }) => ({ id, name, agent_type, description }));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export { AgentRegistry };
|
|
62
|
-
//# sourceMappingURL=agent-registry.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"agent-registry.js","sources":["../../src/agent-registry.ts"],"sourcesContent":["import type { AgentDefinition, AgentType } from './workflow-types.js';\n\nexport class AgentRegistry {\n private agentsByName: Map<string, AgentDefinition> = new Map();\n\n constructor(definitions?: AgentDefinition[]) {\n if (definitions) {\n for (const def of definitions) this.register(def);\n } else {\n for (const def of AgentRegistry.getDefaultAgents()) this.register(def);\n }\n }\n\n static getDefaultAgents(): AgentDefinition[] {\n return [\n {\n id: 'research',\n name: 'research',\n agent_type: 'research',\n description: 'Explore codebase and generate clarifying questions',\n },\n {\n id: 'planning',\n name: 'planning',\n agent_type: 'planning',\n description: 'Analyze repo and produce implementation plan',\n },\n {\n id: 'code_generation',\n name: 'code_generation',\n agent_type: 'execution',\n description: 'Implements code changes using Claude SDK',\n },\n {\n id: 'review',\n name: 'review',\n agent_type: 'review',\n description: 'Reviews changes and suggests fixes',\n },\n {\n id: 'testing',\n name: 'testing',\n agent_type: 'testing',\n description: 'Runs tests and reports results',\n },\n ];\n }\n\n register(def: AgentDefinition): void {\n this.agentsByName.set(def.name, def);\n }\n\n getAgent(name: string): AgentDefinition | undefined {\n return this.agentsByName.get(name);\n }\n\n listAgents(): AgentDefinition[] {\n return Array.from(this.agentsByName.values());\n }\n\n exportForPostHog(): { id: string; name: string; agent_type: AgentType; description?: string }[] {\n return this.listAgents().map(({ id, name, agent_type, description }) => ({ id, name, agent_type, description }));\n }\n}\n\n"],"names":[],"mappings":"MAEa,aAAa,CAAA;AAChB,IAAA,YAAY,GAAiC,IAAI,GAAG,EAAE;AAE9D,IAAA,WAAA,CAAY,WAA+B,EAAA;QACzC,IAAI,WAAW,EAAE;YACf,KAAK,MAAM,GAAG,IAAI,WAAW;AAAE,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QACnD;aAAO;AACL,YAAA,KAAK,MAAM,GAAG,IAAI,aAAa,CAAC,gBAAgB,EAAE;AAAE,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QACxE;IACF;AAEA,IAAA,OAAO,gBAAgB,GAAA;QACrB,OAAO;AACL,YAAA;AACE,gBAAA,EAAE,EAAE,UAAU;AACd,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,UAAU,EAAE,UAAU;AACtB,gBAAA,WAAW,EAAE,oDAAoD;AAClE,aAAA;AACD,YAAA;AACE,gBAAA,EAAE,EAAE,UAAU;AACd,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,UAAU,EAAE,UAAU;AACtB,gBAAA,WAAW,EAAE,8CAA8C;AAC5D,aAAA;AACD,YAAA;AACE,gBAAA,EAAE,EAAE,iBAAiB;AACrB,gBAAA,IAAI,EAAE,iBAAiB;AACvB,gBAAA,UAAU,EAAE,WAAW;AACvB,gBAAA,WAAW,EAAE,0CAA0C;AACxD,aAAA;AACD,YAAA;AACE,gBAAA,EAAE,EAAE,QAAQ;AACZ,gBAAA,IAAI,EAAE,QAAQ;AACd,gBAAA,UAAU,EAAE,QAAQ;AACpB,gBAAA,WAAW,EAAE,oCAAoC;AAClD,aAAA;AACD,YAAA;AACE,gBAAA,EAAE,EAAE,SAAS;AACb,gBAAA,IAAI,EAAE,SAAS;AACf,gBAAA,UAAU,EAAE,SAAS;AACrB,gBAAA,WAAW,EAAE,gCAAgC;AAC9C,aAAA;SACF;IACH;AAEA,IAAA,QAAQ,CAAC,GAAoB,EAAA;QAC3B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC;IACtC;AAEA,IAAA,QAAQ,CAAC,IAAY,EAAA;QACnB,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;IACpC;IAEA,UAAU,GAAA;QACR,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;IAC/C;IAEA,gBAAgB,GAAA;AACd,QAAA,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;IAClH;AACD;;;;"}
|