@posthog/agent 1.1.0 → 1.3.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 +68 -35
- package/README.md +55 -14
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/src/agent.d.ts +5 -1
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +65 -11
- package/dist/src/agent.js.map +1 -1
- package/dist/src/event-transformer.d.ts +2 -0
- package/dist/src/event-transformer.d.ts.map +1 -1
- package/dist/src/event-transformer.js +53 -5
- package/dist/src/event-transformer.js.map +1 -1
- package/dist/src/posthog-api.d.ts +34 -0
- package/dist/src/posthog-api.d.ts.map +1 -1
- package/dist/src/posthog-api.js +38 -0
- package/dist/src/posthog-api.js.map +1 -1
- package/dist/src/stage-executor.d.ts +5 -2
- package/dist/src/stage-executor.d.ts.map +1 -1
- package/dist/src/stage-executor.js +20 -12
- package/dist/src/stage-executor.js.map +1 -1
- package/dist/src/task-progress-reporter.d.ts +44 -0
- package/dist/src/task-progress-reporter.d.ts.map +1 -0
- package/dist/src/task-progress-reporter.js +234 -0
- package/dist/src/task-progress-reporter.js.map +1 -0
- package/dist/src/types.d.ts +20 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/package.json +2 -1
- package/src/agent.ts +77 -11
- package/src/event-transformer.ts +61 -7
- package/src/posthog-api.ts +79 -0
- package/src/stage-executor.ts +29 -15
- package/src/task-progress-reporter.ts +287 -0
- package/src/types.ts +30 -2
- package/dist/src/utils/mcp.d.ts +0 -10
- package/dist/src/utils/mcp.d.ts.map +0 -1
- package/dist/src/utils/mcp.js +0 -18
- package/dist/src/utils/mcp.js.map +0 -1
- package/src/utils/mcp.ts +0 -15
package/CLAUDE.md
CHANGED
|
@@ -114,16 +114,43 @@ const task = await agent.fetchTask("task_abc123");
|
|
|
114
114
|
const result = await agent.runTask(task, ExecutionMode.PLAN_AND_BUILD);
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
-
###
|
|
117
|
+
### Progress Updates
|
|
118
118
|
```typescript
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
119
|
+
const posthogClient = agent.getPostHogClient();
|
|
120
|
+
const poller = setInterval(async () => {
|
|
121
|
+
const progress = await posthogClient?.getTaskProgress(taskId);
|
|
122
|
+
if (progress?.has_progress) {
|
|
123
|
+
updateUI(progress.status, progress.current_step, progress.completed_steps, progress.total_steps);
|
|
124
|
+
}
|
|
125
|
+
}, 3000);
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
await agent.runWorkflow(taskId, workflowId, {
|
|
129
|
+
repositoryPath: selectedRepoPath,
|
|
130
|
+
permissionMode: PermissionMode.DEFAULT,
|
|
131
|
+
autoProgress: true,
|
|
132
|
+
});
|
|
133
|
+
} finally {
|
|
134
|
+
clearInterval(poller);
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
> The agent still emits transformed events via the `onEvent` callback, so UI layers can combine streaming updates with periodic polling if desired.
|
|
125
139
|
|
|
126
|
-
|
|
140
|
+
```typescript
|
|
141
|
+
// Handle the hook provided when constructing the Agent
|
|
142
|
+
import type { AgentEvent } from '@posthog/agent';
|
|
143
|
+
|
|
144
|
+
private handleLiveEvent(event: AgentEvent) {
|
|
145
|
+
switch (event.type) {
|
|
146
|
+
case 'status':
|
|
147
|
+
this.updateUI(event.phase, event.stage);
|
|
148
|
+
break;
|
|
149
|
+
case 'error':
|
|
150
|
+
this.showError(event.message);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
127
154
|
```
|
|
128
155
|
|
|
129
156
|
### Working with Task Files
|
|
@@ -212,10 +239,11 @@ await agent.writeTaskFile(task.id, "requirements.md",
|
|
|
212
239
|
"context"
|
|
213
240
|
);
|
|
214
241
|
|
|
215
|
-
// 4. Execute with PLAN_AND_BUILD mode
|
|
216
|
-
const result = await agent.
|
|
242
|
+
// 4. Execute with PLAN_AND_BUILD mode and rely on PostHog polling for progress
|
|
243
|
+
const result = await agent.runWorkflow(task.id, workflowId, {
|
|
244
|
+
repositoryPath: "/path/to/repo",
|
|
217
245
|
permissionMode: PermissionMode.DEFAULT,
|
|
218
|
-
|
|
246
|
+
autoProgress: true,
|
|
219
247
|
});
|
|
220
248
|
|
|
221
249
|
// 5. Review results
|
|
@@ -227,31 +255,36 @@ console.log("Plan location:", `.posthog/${task.id}/plan.md`);
|
|
|
227
255
|
### Array App Integration Pattern
|
|
228
256
|
|
|
229
257
|
```typescript
|
|
230
|
-
// How Array app uses the SDK
|
|
231
258
|
class ArrayTaskExecution {
|
|
232
|
-
async executeTask(taskId: string,
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
259
|
+
async executeTask(taskId: string, workflowId: string, repoPath: string) {
|
|
260
|
+
const poller = setInterval(() => this.pollProgress(taskId), 3000);
|
|
261
|
+
try {
|
|
262
|
+
await this.agent.runWorkflow(taskId, workflowId, {
|
|
263
|
+
repositoryPath: repoPath,
|
|
264
|
+
permissionMode: PermissionMode.DEFAULT,
|
|
265
|
+
autoProgress: true,
|
|
266
|
+
});
|
|
267
|
+
} finally {
|
|
268
|
+
clearInterval(poller);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
this.showBranchesForReview(taskId);
|
|
242
272
|
}
|
|
243
|
-
|
|
244
|
-
private
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
273
|
+
|
|
274
|
+
private async pollProgress(taskId: string) {
|
|
275
|
+
const client = this.agent.getPostHogClient();
|
|
276
|
+
if (!client) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const progress = await client.getTaskProgress(taskId);
|
|
281
|
+
if (progress.has_progress) {
|
|
282
|
+
this.updateProgressBar({
|
|
283
|
+
status: progress.status,
|
|
284
|
+
currentStep: progress.current_step,
|
|
285
|
+
completed: progress.completed_steps,
|
|
286
|
+
total: progress.total_steps,
|
|
287
|
+
});
|
|
255
288
|
}
|
|
256
289
|
}
|
|
257
290
|
}
|
|
@@ -293,4 +326,4 @@ try {
|
|
|
293
326
|
- **File I/O**: Efficient `.posthog/` folder management with minimal disk usage
|
|
294
327
|
- **API Calls**: Cached PostHog task data to minimize network requests
|
|
295
328
|
- **Event Streaming**: Real-time updates without blocking execution
|
|
296
|
-
- **Template Processing**: Lazy-loaded templates with variable substitution
|
|
329
|
+
- **Template Processing**: Lazy-loaded templates with variable substitution
|
package/README.md
CHANGED
|
@@ -15,17 +15,24 @@ bun run example
|
|
|
15
15
|
- **PostHog Integration**: Fetches existing tasks from PostHog API
|
|
16
16
|
- **Configurable Workflows**: Execute tasks via PostHog-defined or local workflows
|
|
17
17
|
- **Branch Management**: Automatic branch creation for planning and implementation
|
|
18
|
-
- **
|
|
18
|
+
- **Progress Tracking**: Execution status stored in PostHog `TaskProgress` records for easy polling
|
|
19
19
|
|
|
20
20
|
## Usage
|
|
21
21
|
|
|
22
22
|
```typescript
|
|
23
23
|
import { Agent, PermissionMode } from '@posthog/agent';
|
|
24
|
+
import type { AgentEvent } from '@posthog/agent';
|
|
24
25
|
|
|
25
26
|
const agent = new Agent({
|
|
26
27
|
workingDirectory: "/path/to/repo",
|
|
27
28
|
posthogApiUrl: "https://app.posthog.com",
|
|
28
|
-
posthogApiKey: process.env.POSTHOG_API_KEY
|
|
29
|
+
posthogApiKey: process.env.POSTHOG_API_KEY, // Used for both API and MCP
|
|
30
|
+
onEvent: (event) => {
|
|
31
|
+
// Streamed updates for responsive UIs
|
|
32
|
+
if (event.type !== 'token') {
|
|
33
|
+
handleLiveEvent(event);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
29
36
|
});
|
|
30
37
|
|
|
31
38
|
// Run by workflow
|
|
@@ -38,6 +45,15 @@ await agent.runWorkflow(taskId, workflowId, {
|
|
|
38
45
|
});
|
|
39
46
|
```
|
|
40
47
|
|
|
48
|
+
For local MCP development:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
const agent = new Agent({
|
|
52
|
+
workingDirectory: "/path/to/repo",
|
|
53
|
+
posthogMcpUrl: 'http://localhost:8787/mcp',
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
41
57
|
## Workflow
|
|
42
58
|
|
|
43
59
|
Each task execution creates Git branches:
|
|
@@ -78,22 +94,47 @@ your-repo/
|
|
|
78
94
|
└── (your code)
|
|
79
95
|
```
|
|
80
96
|
|
|
81
|
-
##
|
|
97
|
+
## Progress Updates
|
|
98
|
+
|
|
99
|
+
Progress for each task execution is persisted to PostHog's `TaskProgress` model, so UIs can poll for updates without relying on streaming hooks:
|
|
82
100
|
|
|
83
101
|
```typescript
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
switch (event.type) {
|
|
89
|
-
case 'status': updateProgress(event.data); break;
|
|
90
|
-
case 'file_write': showFileChange(event.data); break;
|
|
91
|
-
case 'done': showCompletion(); break;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
102
|
+
const agent = new Agent({
|
|
103
|
+
workingDirectory: repoPath,
|
|
104
|
+
posthogApiUrl: "https://app.posthog.com",
|
|
105
|
+
posthogApiKey: process.env.POSTHOG_KEY,
|
|
94
106
|
});
|
|
107
|
+
|
|
108
|
+
const poller = setInterval(async () => {
|
|
109
|
+
const progress = await agent.getPostHogClient()?.getTaskProgress(taskId);
|
|
110
|
+
if (progress?.has_progress) {
|
|
111
|
+
renderProgress(progress.status, progress.current_step, progress.completed_steps, progress.total_steps);
|
|
112
|
+
}
|
|
113
|
+
}, 3000);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
await agent.runWorkflow(taskId, workflowId, { repositoryPath: repoPath });
|
|
117
|
+
} finally {
|
|
118
|
+
clearInterval(poller);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Live stream still available through the onEvent hook
|
|
122
|
+
function handleLiveEvent(event: AgentEvent) {
|
|
123
|
+
switch (event.type) {
|
|
124
|
+
case 'status':
|
|
125
|
+
// optimistic UI update
|
|
126
|
+
break;
|
|
127
|
+
case 'error':
|
|
128
|
+
notifyError(event.message);
|
|
129
|
+
break;
|
|
130
|
+
default:
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
95
134
|
```
|
|
96
135
|
|
|
136
|
+
> Prefer streaming updates? Pass an `onEvent` handler when constructing the agent to keep receiving real-time events while progress is also written to PostHog.
|
|
137
|
+
|
|
97
138
|
## Requirements
|
|
98
139
|
|
|
99
140
|
- Bun runtime
|
|
@@ -139,4 +180,4 @@ await agent.runWorkflow(taskId, workflowId, {
|
|
|
139
180
|
});
|
|
140
181
|
```
|
|
141
182
|
|
|
142
|
-
Precedence for query options: base defaults in the SDK < global `queryOverrides` < per-stage `stageOverrides[stageKey].queryOverrides`.
|
|
183
|
+
Precedence for query options: base defaults in the SDK < global `queryOverrides` < per-stage `stageOverrides[stageKey].queryOverrides`.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { Agent, } from './src/agent.js';
|
|
2
2
|
export { PermissionMode, } from './src/types.js';
|
|
3
|
-
export type { Task, SupportingFile, ExecutionResult, AgentConfig } from './src/types.js';
|
|
3
|
+
export type { Task, SupportingFile, ExecutionResult, AgentConfig, McpServerConfig } from './src/types.js';
|
|
4
4
|
export type { WorkflowDefinition, WorkflowStage, WorkflowExecutionOptions, AgentDefinition } from './src/workflow-types.js';
|
|
5
5
|
export { Logger, LogLevel, } from './src/utils/logger.js';
|
|
6
6
|
export type { LoggerConfig } from './src/utils/logger.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EACH,KAAK,GACR,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACH,cAAc,GACjB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACR,IAAI,EACJ,cAAc,EACd,eAAe,EACf,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EACH,KAAK,GACR,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACH,cAAc,GACjB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACR,IAAI,EACJ,cAAc,EACd,eAAe,EACf,WAAW,EACX,eAAe,EAClB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACV,kBAAkB,EAClB,aAAa,EACb,wBAAwB,EACxB,eAAe,EAChB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACH,MAAM,EACN,QAAQ,GACX,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACR,YAAY,EACf,MAAM,uBAAuB,CAAC"}
|
package/dist/src/agent.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Task, ExecutionResult, AgentConfig } from './types.js';
|
|
2
2
|
import type { WorkflowDefinition, WorkflowStage, WorkflowExecutionOptions } from './workflow-types.js';
|
|
3
|
+
import { PostHogAPIClient } from './posthog-api.js';
|
|
3
4
|
export declare class Agent {
|
|
4
5
|
private workingDirectory;
|
|
5
6
|
private onEvent?;
|
|
@@ -13,6 +14,8 @@ export declare class Agent {
|
|
|
13
14
|
private agentRegistry;
|
|
14
15
|
private workflowRegistry;
|
|
15
16
|
private stageExecutor;
|
|
17
|
+
private progressReporter;
|
|
18
|
+
private mcpServers?;
|
|
16
19
|
debug: boolean;
|
|
17
20
|
constructor(config?: AgentConfig);
|
|
18
21
|
/**
|
|
@@ -31,6 +34,7 @@ export declare class Agent {
|
|
|
31
34
|
queryOverrides?: Record<string, any>;
|
|
32
35
|
}): Promise<ExecutionResult>;
|
|
33
36
|
fetchTask(taskId: string): Promise<Task>;
|
|
37
|
+
getPostHogClient(): PostHogAPIClient | undefined;
|
|
34
38
|
listTasks(filters?: {
|
|
35
39
|
repository?: string;
|
|
36
40
|
organization?: string;
|
|
@@ -48,7 +52,7 @@ export declare class Agent {
|
|
|
48
52
|
createImplementationBranch(taskId: string, planningBranchName?: string): Promise<string>;
|
|
49
53
|
commitImplementation(taskId: string, taskTitle: string, planSummary?: string): Promise<string>;
|
|
50
54
|
createPullRequest(taskId: string, branchName: string, taskTitle: string, taskDescription: string): Promise<string>;
|
|
51
|
-
attachPullRequestToTask(taskId: string, prUrl: string): Promise<void>;
|
|
55
|
+
attachPullRequestToTask(taskId: string, prUrl: string, branchName?: string): Promise<void>;
|
|
52
56
|
updateTaskBranch(taskId: string, branchName: string): Promise<void>;
|
|
53
57
|
cancelTask(taskId: string): void;
|
|
54
58
|
getTaskExecutionStatus(taskId: string): string | null;
|
package/dist/src/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/agent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAc,WAAW,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/agent.ts"],"names":[],"mappings":"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"}
|
package/dist/src/agent.js
CHANGED
|
@@ -10,6 +10,7 @@ import { AgentRegistry } from './agent-registry.js';
|
|
|
10
10
|
import { WorkflowRegistry } from './workflow-registry.js';
|
|
11
11
|
import { StageExecutor } from './stage-executor.js';
|
|
12
12
|
import { PromptBuilder } from './prompt-builder.js';
|
|
13
|
+
import { TaskProgressReporter } from './task-progress-reporter.js';
|
|
13
14
|
export { PermissionMode } from './types.js';
|
|
14
15
|
|
|
15
16
|
class Agent {
|
|
@@ -25,11 +26,34 @@ class Agent {
|
|
|
25
26
|
agentRegistry;
|
|
26
27
|
workflowRegistry;
|
|
27
28
|
stageExecutor;
|
|
29
|
+
progressReporter;
|
|
30
|
+
mcpServers;
|
|
28
31
|
debug;
|
|
29
32
|
constructor(config = {}) {
|
|
30
33
|
this.workingDirectory = config.workingDirectory || process.cwd();
|
|
31
34
|
this.onEvent = config.onEvent;
|
|
32
35
|
this.debug = config.debug || false;
|
|
36
|
+
// Build default PostHog MCP server configuration
|
|
37
|
+
const posthogMcpUrl = config.posthogMcpUrl
|
|
38
|
+
|| process.env.POSTHOG_MCP_URL
|
|
39
|
+
|| 'https://mcp.posthog.com/mcp';
|
|
40
|
+
// Add auth if API key provided
|
|
41
|
+
const headers = {};
|
|
42
|
+
if (config.posthogApiKey) {
|
|
43
|
+
headers['Authorization'] = `Bearer ${config.posthogApiKey}`;
|
|
44
|
+
}
|
|
45
|
+
const defaultMcpServers = {
|
|
46
|
+
posthog: {
|
|
47
|
+
type: 'http',
|
|
48
|
+
url: posthogMcpUrl,
|
|
49
|
+
...(Object.keys(headers).length > 0 ? { headers } : {}),
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
// Merge default PostHog MCP with user-provided servers (user config takes precedence)
|
|
53
|
+
this.mcpServers = {
|
|
54
|
+
...defaultMcpServers,
|
|
55
|
+
...config.mcpServers
|
|
56
|
+
};
|
|
33
57
|
this.logger = new Logger({ debug: this.debug, prefix: '[PostHog Agent]' });
|
|
34
58
|
this.taskManager = new TaskManager();
|
|
35
59
|
this.eventTransformer = new EventTransformer();
|
|
@@ -53,7 +77,10 @@ class Agent {
|
|
|
53
77
|
generatePlanTemplate: (vars) => this.templateManager.generatePlan(vars),
|
|
54
78
|
logger: this.logger.child('PromptBuilder')
|
|
55
79
|
});
|
|
56
|
-
this.stageExecutor = new StageExecutor(this.agentRegistry, this.logger, promptBuilder
|
|
80
|
+
this.stageExecutor = new StageExecutor(this.agentRegistry, this.logger, promptBuilder, undefined, // eventHandler set via setEventHandler below
|
|
81
|
+
this.mcpServers);
|
|
82
|
+
this.stageExecutor.setEventHandler((event) => this.emitEvent(event));
|
|
83
|
+
this.progressReporter = new TaskProgressReporter(this.posthogAPI, this.logger);
|
|
57
84
|
}
|
|
58
85
|
/**
|
|
59
86
|
* Enable or disable debug logging
|
|
@@ -70,6 +97,7 @@ class Agent {
|
|
|
70
97
|
if (!workflow) {
|
|
71
98
|
throw new Error(`Workflow ${workflowId} not found`);
|
|
72
99
|
}
|
|
100
|
+
const orderedStages = [...workflow.stages].sort((a, b) => a.position - b.position);
|
|
73
101
|
// Ensure task is assigned to workflow and positioned at first stage
|
|
74
102
|
if (this.posthogAPI) {
|
|
75
103
|
try {
|
|
@@ -90,8 +118,12 @@ class Agent {
|
|
|
90
118
|
const executionId = this.taskManager.generateExecutionId();
|
|
91
119
|
this.logger.info('Starting workflow execution', { taskId: task.id, workflowId, executionId });
|
|
92
120
|
this.taskManager.startExecution(task.id, 'plan_and_build', executionId);
|
|
121
|
+
await this.progressReporter.start(task.id, {
|
|
122
|
+
workflowId,
|
|
123
|
+
workflowRunId: executionId,
|
|
124
|
+
totalSteps: orderedStages.length,
|
|
125
|
+
});
|
|
93
126
|
try {
|
|
94
|
-
const orderedStages = [...workflow.stages].sort((a, b) => a.position - b.position);
|
|
95
127
|
let startIndex = 0;
|
|
96
128
|
const currentStageId = task.current_stage;
|
|
97
129
|
// If task is already at the last stage, fail gracefully without progressing
|
|
@@ -99,7 +131,10 @@ class Agent {
|
|
|
99
131
|
const currIdx = orderedStages.findIndex(s => s.id === currentStageId);
|
|
100
132
|
const atLastStage = currIdx >= 0 && currIdx === orderedStages.length - 1;
|
|
101
133
|
if (atLastStage) {
|
|
102
|
-
|
|
134
|
+
const finalStageKey = orderedStages[currIdx]?.key;
|
|
135
|
+
this.emitEvent(this.eventTransformer.createStatusEvent('no_next_stage', { stage: finalStageKey }));
|
|
136
|
+
await this.progressReporter.noNextStage(finalStageKey);
|
|
137
|
+
await this.progressReporter.complete();
|
|
103
138
|
this.taskManager.completeExecution(executionId, { task, workflow });
|
|
104
139
|
return { task, workflow };
|
|
105
140
|
}
|
|
@@ -122,7 +157,9 @@ class Agent {
|
|
|
122
157
|
}
|
|
123
158
|
for (let i = startIndex; i < orderedStages.length; i++) {
|
|
124
159
|
const stage = orderedStages[i];
|
|
160
|
+
await this.progressReporter.stageStarted(stage.key, i);
|
|
125
161
|
await this.executeStage(task, stage, options);
|
|
162
|
+
await this.progressReporter.stageCompleted(stage.key, i + 1);
|
|
126
163
|
if (options.autoProgress) {
|
|
127
164
|
const hasNext = i < orderedStages.length - 1;
|
|
128
165
|
if (hasNext) {
|
|
@@ -130,10 +167,12 @@ class Agent {
|
|
|
130
167
|
}
|
|
131
168
|
}
|
|
132
169
|
}
|
|
170
|
+
await this.progressReporter.complete();
|
|
133
171
|
this.taskManager.completeExecution(executionId, { task, workflow });
|
|
134
172
|
return { task, workflow };
|
|
135
173
|
}
|
|
136
174
|
catch (error) {
|
|
175
|
+
await this.progressReporter.fail(error);
|
|
137
176
|
this.taskManager.failExecution(executionId, error);
|
|
138
177
|
throw error;
|
|
139
178
|
}
|
|
@@ -153,17 +192,20 @@ class Agent {
|
|
|
153
192
|
const planningBranch = await this.createPlanningBranch(task.id);
|
|
154
193
|
await this.updateTaskBranch(task.id, planningBranch);
|
|
155
194
|
this.emitEvent(this.eventTransformer.createStatusEvent('branch_created', { stage: stage.key, branch: planningBranch }));
|
|
195
|
+
await this.progressReporter.branchCreated(stage.key, planningBranch);
|
|
156
196
|
}
|
|
157
197
|
else if (!isPlanning && !isManual && shouldCreateImplBranch) {
|
|
158
198
|
const implBranch = await this.createImplementationBranch(task.id);
|
|
159
199
|
await this.updateTaskBranch(task.id, implBranch);
|
|
160
200
|
this.emitEvent(this.eventTransformer.createStatusEvent('branch_created', { stage: stage.key, branch: implBranch }));
|
|
201
|
+
await this.progressReporter.branchCreated(stage.key, implBranch);
|
|
161
202
|
}
|
|
162
203
|
const result = await this.stageExecutor.execute(task, stage, options);
|
|
163
204
|
if (result.plan) {
|
|
164
205
|
await this.writePlan(task.id, result.plan);
|
|
165
206
|
await this.commitPlan(task.id, task.title);
|
|
166
207
|
this.emitEvent(this.eventTransformer.createStatusEvent('commit_made', { stage: stage.key, kind: 'plan' }));
|
|
208
|
+
await this.progressReporter.commitMade(stage.key, 'plan');
|
|
167
209
|
}
|
|
168
210
|
if (isManual) {
|
|
169
211
|
const defaultOpenPR = true; // manual stages default to PR for review
|
|
@@ -177,12 +219,14 @@ class Agent {
|
|
|
177
219
|
await this.updateTaskBranch(task.id, implBranch);
|
|
178
220
|
branchName = implBranch;
|
|
179
221
|
this.emitEvent(this.eventTransformer.createStatusEvent('branch_created', { stage: stage.key, branch: implBranch }));
|
|
222
|
+
await this.progressReporter.branchCreated(stage.key, implBranch);
|
|
180
223
|
}
|
|
181
224
|
try {
|
|
182
225
|
const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
|
|
183
226
|
await this.updateTaskBranch(task.id, branchName);
|
|
184
|
-
await this.attachPullRequestToTask(task.id, prUrl);
|
|
227
|
+
await this.attachPullRequestToTask(task.id, prUrl, branchName);
|
|
185
228
|
this.emitEvent(this.eventTransformer.createStatusEvent('pr_created', { stage: stage.key, prUrl }));
|
|
229
|
+
await this.progressReporter.pullRequestCreated(stage.key, prUrl);
|
|
186
230
|
}
|
|
187
231
|
catch { }
|
|
188
232
|
}
|
|
@@ -195,6 +239,7 @@ class Agent {
|
|
|
195
239
|
const planSummary = existingPlan ? existingPlan.split('\n')[0] : undefined;
|
|
196
240
|
await this.commitImplementation(task.id, task.title, planSummary);
|
|
197
241
|
this.emitEvent(this.eventTransformer.createStatusEvent('commit_made', { stage: stage.key, kind: 'implementation' }));
|
|
242
|
+
await this.progressReporter.commitMade(stage.key, 'implementation');
|
|
198
243
|
}
|
|
199
244
|
// PR creation on complete stage (or if explicitly requested), regardless of whether edits occurred
|
|
200
245
|
{
|
|
@@ -205,8 +250,9 @@ class Agent {
|
|
|
205
250
|
try {
|
|
206
251
|
const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
|
|
207
252
|
await this.updateTaskBranch(task.id, branchName);
|
|
208
|
-
await this.attachPullRequestToTask(task.id, prUrl);
|
|
253
|
+
await this.attachPullRequestToTask(task.id, prUrl, branchName);
|
|
209
254
|
this.emitEvent(this.eventTransformer.createStatusEvent('pr_created', { stage: stage.key, prUrl }));
|
|
255
|
+
await this.progressReporter.pullRequestCreated(stage.key, prUrl);
|
|
210
256
|
}
|
|
211
257
|
catch { }
|
|
212
258
|
}
|
|
@@ -221,10 +267,11 @@ class Agent {
|
|
|
221
267
|
// Direct prompt execution - still supported for low-level usage
|
|
222
268
|
async run(prompt, options = {}) {
|
|
223
269
|
const baseOptions = {
|
|
224
|
-
model: "claude-4-5-
|
|
270
|
+
model: "claude-sonnet-4-5-20250929",
|
|
225
271
|
cwd: options.repositoryPath || this.workingDirectory,
|
|
226
272
|
permissionMode: options.permissionMode || "default",
|
|
227
273
|
settingSources: ["local"],
|
|
274
|
+
mcpServers: this.mcpServers,
|
|
228
275
|
};
|
|
229
276
|
const response = query({
|
|
230
277
|
prompt,
|
|
@@ -232,7 +279,7 @@ class Agent {
|
|
|
232
279
|
});
|
|
233
280
|
const results = [];
|
|
234
281
|
for await (const message of response) {
|
|
235
|
-
this.logger.debug('Received message in direct run',
|
|
282
|
+
this.logger.debug('Received message in direct run', message);
|
|
236
283
|
const transformedEvent = this.eventTransformer.transform(message);
|
|
237
284
|
this.onEvent?.(transformedEvent);
|
|
238
285
|
results.push(message);
|
|
@@ -249,6 +296,9 @@ class Agent {
|
|
|
249
296
|
}
|
|
250
297
|
return this.posthogAPI.fetchTask(taskId);
|
|
251
298
|
}
|
|
299
|
+
getPostHogClient() {
|
|
300
|
+
return this.posthogAPI;
|
|
301
|
+
}
|
|
252
302
|
async listTasks(filters) {
|
|
253
303
|
if (!this.posthogAPI) {
|
|
254
304
|
throw new Error('PostHog API not configured. Provide posthogApiUrl and posthogApiKey in constructor.');
|
|
@@ -320,14 +370,14 @@ Generated by PostHog Agent`;
|
|
|
320
370
|
this.logger.info('Pull request created', { taskId, prUrl });
|
|
321
371
|
return prUrl;
|
|
322
372
|
}
|
|
323
|
-
async attachPullRequestToTask(taskId, prUrl) {
|
|
324
|
-
this.logger.info('Attaching PR to task', { taskId, prUrl });
|
|
373
|
+
async attachPullRequestToTask(taskId, prUrl, branchName) {
|
|
374
|
+
this.logger.info('Attaching PR to task', { taskId, prUrl, branchName });
|
|
325
375
|
if (!this.posthogAPI) {
|
|
326
376
|
const error = new Error('PostHog API not configured. Cannot attach PR to task.');
|
|
327
377
|
this.logger.error('PostHog API not configured', error);
|
|
328
378
|
throw error;
|
|
329
379
|
}
|
|
330
|
-
await this.posthogAPI.
|
|
380
|
+
await this.posthogAPI.attachTaskPullRequest(taskId, prUrl, branchName);
|
|
331
381
|
this.logger.debug('PR attached to task', { taskId, prUrl });
|
|
332
382
|
}
|
|
333
383
|
async updateTaskBranch(taskId, branchName) {
|
|
@@ -337,7 +387,7 @@ Generated by PostHog Agent`;
|
|
|
337
387
|
this.logger.error('PostHog API not configured', error);
|
|
338
388
|
throw error;
|
|
339
389
|
}
|
|
340
|
-
await this.posthogAPI.
|
|
390
|
+
await this.posthogAPI.setTaskBranch(taskId, branchName);
|
|
341
391
|
this.logger.debug('Task branch updated', { taskId, branchName });
|
|
342
392
|
}
|
|
343
393
|
// Execution management
|
|
@@ -364,6 +414,10 @@ Generated by PostHog Agent`;
|
|
|
364
414
|
// Log all events except tokens (too verbose)
|
|
365
415
|
this.logger.debug('Emitting event', { type: event.type, ts: event.ts });
|
|
366
416
|
}
|
|
417
|
+
const persistPromise = this.progressReporter.recordEvent(event);
|
|
418
|
+
if (persistPromise && typeof persistPromise.then === 'function') {
|
|
419
|
+
persistPromise.catch((error) => this.logger.debug('Failed to persist agent event', { message: error.message }));
|
|
420
|
+
}
|
|
367
421
|
this.onEvent?.(event);
|
|
368
422
|
}
|
|
369
423
|
}
|