@posthog/agent 1.9.0 → 1.11.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 +8 -5
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/src/agent-registry.d.ts.map +1 -1
- package/dist/src/agent-registry.js +6 -0
- package/dist/src/agent-registry.js.map +1 -1
- package/dist/src/agent.d.ts +5 -0
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +370 -29
- package/dist/src/agent.js.map +1 -1
- package/dist/src/agents/research.d.ts +2 -0
- package/dist/src/agents/research.d.ts.map +1 -0
- package/dist/src/agents/research.js +105 -0
- package/dist/src/agents/research.js.map +1 -0
- package/dist/src/file-manager.d.ts +19 -0
- package/dist/src/file-manager.d.ts.map +1 -1
- package/dist/src/file-manager.js +39 -0
- package/dist/src/file-manager.js.map +1 -1
- package/dist/src/git-manager.d.ts +4 -0
- package/dist/src/git-manager.d.ts.map +1 -1
- package/dist/src/git-manager.js +41 -0
- package/dist/src/git-manager.js.map +1 -1
- package/dist/src/posthog-api.d.ts +16 -57
- package/dist/src/posthog-api.d.ts.map +1 -1
- package/dist/src/posthog-api.js +38 -38
- package/dist/src/posthog-api.js.map +1 -1
- package/dist/src/prompt-builder.d.ts +1 -0
- package/dist/src/prompt-builder.d.ts.map +1 -1
- package/dist/src/prompt-builder.js +40 -0
- package/dist/src/prompt-builder.js.map +1 -1
- package/dist/src/stage-executor.d.ts +1 -0
- package/dist/src/stage-executor.d.ts.map +1 -1
- package/dist/src/stage-executor.js +43 -0
- package/dist/src/stage-executor.js.map +1 -1
- package/dist/src/structured-extraction.d.ts +22 -0
- package/dist/src/structured-extraction.d.ts.map +1 -0
- package/dist/src/structured-extraction.js +136 -0
- package/dist/src/structured-extraction.js.map +1 -0
- package/dist/src/task-progress-reporter.d.ts +2 -5
- package/dist/src/task-progress-reporter.d.ts.map +1 -1
- package/dist/src/task-progress-reporter.js +37 -39
- package/dist/src/task-progress-reporter.js.map +1 -1
- package/dist/src/types.d.ts +31 -3
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/workflow-types.d.ts +1 -1
- package/dist/src/workflow-types.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/agent-registry.ts +6 -0
- package/src/agent.ts +409 -26
- package/src/agents/research.ts +103 -0
- package/src/file-manager.ts +64 -0
- package/src/git-manager.ts +52 -0
- package/src/posthog-api.ts +57 -92
- package/src/prompt-builder.ts +53 -0
- package/src/stage-executor.ts +50 -0
- package/src/structured-extraction.ts +167 -0
- package/src/task-progress-reporter.ts +38 -44
- package/src/types.ts +39 -3
- package/src/workflow-types.ts +1 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ 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
|
-
- **Progress Tracking**: Execution status stored in PostHog `
|
|
18
|
+
- **Progress Tracking**: Execution status stored in PostHog `TaskRun` records for easy polling
|
|
19
19
|
|
|
20
20
|
## Usage
|
|
21
21
|
|
|
@@ -96,7 +96,7 @@ your-repo/
|
|
|
96
96
|
|
|
97
97
|
## Progress Updates
|
|
98
98
|
|
|
99
|
-
Progress for each task execution is persisted to PostHog's `
|
|
99
|
+
Progress for each task execution is persisted to PostHog's `TaskRun` model, so UIs can poll for updates without relying on streaming hooks:
|
|
100
100
|
|
|
101
101
|
```typescript
|
|
102
102
|
const agent = new Agent({
|
|
@@ -106,9 +106,12 @@ const agent = new Agent({
|
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
const poller = setInterval(async () => {
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
const runs = await agent.getPostHogClient()?.listTaskRuns(taskId);
|
|
110
|
+
const latestRun = runs?.sort((a, b) =>
|
|
111
|
+
new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
|
112
|
+
)[0];
|
|
113
|
+
if (latestRun) {
|
|
114
|
+
renderProgress(latestRun.status, latestRun.log, latestRun.current_stage);
|
|
112
115
|
}
|
|
113
116
|
}, 3000);
|
|
114
117
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export { Agent, } from './src/agent.js';
|
|
2
2
|
export { PermissionMode, } from './src/types.js';
|
|
3
|
-
export type { Task, SupportingFile, ExecutionResult, AgentConfig, McpServerConfig, AgentEvent } from './src/types.js';
|
|
3
|
+
export type { Task, TaskRun, SupportingFile, ExecutionResult, AgentConfig, McpServerConfig, AgentEvent } 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';
|
|
7
|
+
export type { ExtractedQuestion, ExtractedQuestionWithAnswer, StructuredExtractor } from './src/structured-extraction.js';
|
|
8
|
+
export type { QuestionData, AnswerData, QuestionsFile } from './src/file-manager.js';
|
|
7
9
|
export type { ProviderAdapter } from './src/adapters/types.js';
|
|
8
10
|
export { ClaudeAdapter } from './src/adapters/claude/claude-adapter.js';
|
|
9
11
|
export type { Tool, ToolCategory, KnownTool, ReadTool, WriteTool, EditTool, GlobTool, NotebookEditTool, BashTool, BashOutputTool, KillShellTool, WebFetchTool, WebSearchTool, GrepTool, TaskTool, TodoWriteTool, ExitPlanModeTool, SlashCommandTool, } from './src/tools/types.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,EACX,eAAe,EACf,UAAU,EACb,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;AAG/B,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAGxE,YAAY,EACR,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,gBAAgB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC"}
|
|
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,OAAO,EACP,cAAc,EACd,eAAe,EACf,WAAW,EACX,eAAe,EACf,UAAU,EACb,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;AAG/B,YAAY,EACR,iBAAiB,EACjB,2BAA2B,EAC3B,mBAAmB,EACtB,MAAM,gCAAgC,CAAC;AAGxC,YAAY,EACR,YAAY,EACZ,UAAU,EACV,aAAa,EAChB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAGxE,YAAY,EACR,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,gBAAgB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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"}
|
|
@@ -12,6 +12,12 @@ class AgentRegistry {
|
|
|
12
12
|
}
|
|
13
13
|
static getDefaultAgents() {
|
|
14
14
|
return [
|
|
15
|
+
{
|
|
16
|
+
id: 'research',
|
|
17
|
+
name: 'research',
|
|
18
|
+
agent_type: 'research',
|
|
19
|
+
description: 'Explore codebase and generate clarifying questions',
|
|
20
|
+
},
|
|
15
21
|
{
|
|
16
22
|
id: 'planning',
|
|
17
23
|
name: 'planning',
|
|
@@ -1 +1 @@
|
|
|
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: '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,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;;;;"}
|
|
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;;;;"}
|
package/dist/src/agent.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Task, ExecutionResult, AgentConfig } from './types.js';
|
|
2
2
|
import type { WorkflowDefinition, WorkflowStage, WorkflowExecutionOptions } from './workflow-types.js';
|
|
3
3
|
import { PostHogAPIClient } from './posthog-api.js';
|
|
4
|
+
import { type ExtractedQuestion, type ExtractedQuestionWithAnswer } from './structured-extraction.js';
|
|
4
5
|
export declare class Agent {
|
|
5
6
|
private workingDirectory;
|
|
6
7
|
private onEvent?;
|
|
@@ -15,6 +16,8 @@ export declare class Agent {
|
|
|
15
16
|
private workflowRegistry;
|
|
16
17
|
private stageExecutor;
|
|
17
18
|
private progressReporter;
|
|
19
|
+
private promptBuilder;
|
|
20
|
+
private extractor?;
|
|
18
21
|
private mcpServers?;
|
|
19
22
|
debug: boolean;
|
|
20
23
|
constructor(config?: AgentConfig);
|
|
@@ -31,6 +34,7 @@ export declare class Agent {
|
|
|
31
34
|
workflow: WorkflowDefinition;
|
|
32
35
|
}>;
|
|
33
36
|
executeStage(task: Task, stage: WorkflowStage, options?: WorkflowExecutionOptions): Promise<void>;
|
|
37
|
+
runTask(taskOrId: Task | string, options?: import('./types.js').TaskExecutionOptions): Promise<void>;
|
|
34
38
|
progressToNextStage(taskId: string, currentStageKey?: string): Promise<void>;
|
|
35
39
|
run(prompt: string, options?: {
|
|
36
40
|
repositoryPath?: string;
|
|
@@ -51,6 +55,7 @@ export declare class Agent {
|
|
|
51
55
|
getTaskFiles(taskId: string): Promise<any[]>;
|
|
52
56
|
writePlan(taskId: string, plan: string): Promise<void>;
|
|
53
57
|
readPlan(taskId: string): Promise<string | null>;
|
|
58
|
+
extractQuestionsFromResearch(taskId: string, includeAnswers?: boolean): Promise<ExtractedQuestion[] | ExtractedQuestionWithAnswer[]>;
|
|
54
59
|
createPlanningBranch(taskId: string): Promise<string>;
|
|
55
60
|
commitPlan(taskId: string, taskTitle: string): Promise<string>;
|
|
56
61
|
createImplementationBranch(taskId: string, planningBranchName?: string): Promise<string>;
|
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;AAEvG,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,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
|
@@ -11,6 +11,7 @@ import { WorkflowRegistry } from './workflow-registry.js';
|
|
|
11
11
|
import { StageExecutor } from './stage-executor.js';
|
|
12
12
|
import { PromptBuilder } from './prompt-builder.js';
|
|
13
13
|
import { TaskProgressReporter } from './task-progress-reporter.js';
|
|
14
|
+
import { OpenAIExtractor } from './structured-extraction.js';
|
|
14
15
|
export { PermissionMode } from './types.js';
|
|
15
16
|
|
|
16
17
|
class Agent {
|
|
@@ -27,6 +28,8 @@ class Agent {
|
|
|
27
28
|
workflowRegistry;
|
|
28
29
|
stageExecutor;
|
|
29
30
|
progressReporter;
|
|
31
|
+
promptBuilder;
|
|
32
|
+
extractor;
|
|
30
33
|
mcpServers;
|
|
31
34
|
debug;
|
|
32
35
|
constructor(config = {}) {
|
|
@@ -73,16 +76,20 @@ class Agent {
|
|
|
73
76
|
});
|
|
74
77
|
}
|
|
75
78
|
this.workflowRegistry = new WorkflowRegistry(this.posthogAPI);
|
|
76
|
-
|
|
79
|
+
this.promptBuilder = new PromptBuilder({
|
|
77
80
|
getTaskFiles: (taskId) => this.getTaskFiles(taskId),
|
|
78
81
|
generatePlanTemplate: (vars) => this.templateManager.generatePlan(vars),
|
|
79
82
|
posthogClient: this.posthogAPI,
|
|
80
83
|
logger: this.logger.child('PromptBuilder')
|
|
81
84
|
});
|
|
82
|
-
this.stageExecutor = new StageExecutor(this.agentRegistry, this.logger, promptBuilder, undefined, // eventHandler set via setEventHandler below
|
|
85
|
+
this.stageExecutor = new StageExecutor(this.agentRegistry, this.logger, this.promptBuilder, undefined, // eventHandler set via setEventHandler below
|
|
83
86
|
this.mcpServers);
|
|
84
87
|
this.stageExecutor.setEventHandler((event) => this.emitEvent(event));
|
|
85
88
|
this.progressReporter = new TaskProgressReporter(this.posthogAPI, this.logger);
|
|
89
|
+
// Initialize OpenAI extractor if API key is available
|
|
90
|
+
if (process.env.OPENAI_API_KEY) {
|
|
91
|
+
this.extractor = new OpenAIExtractor(this.logger.child('OpenAIExtractor'));
|
|
92
|
+
}
|
|
86
93
|
}
|
|
87
94
|
/**
|
|
88
95
|
* Enable or disable debug logging
|
|
@@ -130,24 +137,29 @@ class Agent {
|
|
|
130
137
|
await this.posthogAPI.updateTask(task.id, { workflow: workflowId });
|
|
131
138
|
task.workflow = workflowId;
|
|
132
139
|
}
|
|
133
|
-
if (!task.current_stage && workflow.stages.length > 0) {
|
|
134
|
-
const firstStage = [...workflow.stages].sort((a, b) => a.position - b.position)[0];
|
|
135
|
-
await this.posthogAPI.updateTaskStage(task.id, firstStage.id);
|
|
136
|
-
task.current_stage = firstStage.id;
|
|
137
|
-
}
|
|
138
140
|
}
|
|
139
141
|
catch (e) {
|
|
140
|
-
this.logger.warn('Failed to sync task workflow
|
|
142
|
+
this.logger.warn('Failed to sync task workflow before execution', { error: e.message });
|
|
141
143
|
}
|
|
142
144
|
}
|
|
143
145
|
const executionId = this.taskManager.generateExecutionId();
|
|
144
146
|
this.logger.info('Starting workflow execution', { taskId: task.id, workflowId, executionId });
|
|
145
147
|
this.taskManager.startExecution(task.id, 'plan_and_build', executionId);
|
|
146
148
|
await this.progressReporter.start(task.id, {
|
|
147
|
-
workflowId,
|
|
148
|
-
workflowRunId: executionId,
|
|
149
149
|
totalSteps: orderedStages.length,
|
|
150
150
|
});
|
|
151
|
+
// Set initial stage on the newly created run
|
|
152
|
+
const firstStage = orderedStages[0];
|
|
153
|
+
if (this.posthogAPI && this.progressReporter.runId && firstStage) {
|
|
154
|
+
try {
|
|
155
|
+
await this.posthogAPI.updateTaskRun(task.id, this.progressReporter.runId, {
|
|
156
|
+
current_stage: firstStage.id
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch (e) {
|
|
160
|
+
this.logger.warn('Failed to set initial stage on run', { error: e.message });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
151
163
|
try {
|
|
152
164
|
let startIndex = 0;
|
|
153
165
|
const currentStageId = task.current_stage;
|
|
@@ -169,15 +181,18 @@ class Agent {
|
|
|
169
181
|
if (idx >= 0)
|
|
170
182
|
startIndex = idx;
|
|
171
183
|
}
|
|
172
|
-
// Align server-side stage when restarting from
|
|
173
|
-
if (this.posthogAPI) {
|
|
184
|
+
// Align server-side stage when restarting from a different stage
|
|
185
|
+
if (this.posthogAPI && this.progressReporter.runId) {
|
|
174
186
|
const targetStage = orderedStages[startIndex];
|
|
175
187
|
if (targetStage && targetStage.id !== currentStageId) {
|
|
176
188
|
try {
|
|
177
|
-
await this.posthogAPI.
|
|
178
|
-
|
|
189
|
+
await this.posthogAPI.updateTaskRun(task.id, this.progressReporter.runId, {
|
|
190
|
+
current_stage: targetStage.id
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
catch (e) {
|
|
194
|
+
this.logger.warn('Failed to update run stage', { error: e.message });
|
|
179
195
|
}
|
|
180
|
-
catch { }
|
|
181
196
|
}
|
|
182
197
|
}
|
|
183
198
|
for (let i = startIndex; i < orderedStages.length; i++) {
|
|
@@ -284,16 +299,320 @@ class Agent {
|
|
|
284
299
|
}
|
|
285
300
|
this.emitEvent(this.adapter.createStatusEvent('stage_complete', { stage: stage.key }));
|
|
286
301
|
}
|
|
302
|
+
// Adaptive task execution - 3-phase workflow (research → plan → build)
|
|
303
|
+
async runTask(taskOrId, options = {}) {
|
|
304
|
+
await this._configureLlmGateway();
|
|
305
|
+
const task = typeof taskOrId === 'string' ? await this.fetchTask(taskOrId) : taskOrId;
|
|
306
|
+
const cwd = options.repositoryPath || this.workingDirectory;
|
|
307
|
+
const isCloudMode = options.isCloudMode ?? false;
|
|
308
|
+
const taskSlug = task.slug || task.id;
|
|
309
|
+
this.logger.info('Starting adaptive task execution', { taskId: task.id, taskSlug, isCloudMode });
|
|
310
|
+
// Initialize progress reporter for task run tracking (needed for PR attachment)
|
|
311
|
+
await this.progressReporter.start(task.id, { totalSteps: 3 }); // 3 phases: research, plan, build
|
|
312
|
+
this.emitEvent(this.adapter.createStatusEvent('run_started', { runId: this.progressReporter.runId }));
|
|
313
|
+
// Phase 1: Branch check
|
|
314
|
+
const existingBranch = await this.gitManager.getTaskBranch(taskSlug);
|
|
315
|
+
if (!existingBranch) {
|
|
316
|
+
this.logger.info('Creating task branch', { taskSlug });
|
|
317
|
+
const branchName = `posthog/task-${taskSlug}`;
|
|
318
|
+
await this.gitManager.createOrSwitchToBranch(branchName);
|
|
319
|
+
this.emitEvent(this.adapter.createStatusEvent('branch_created', { branch: branchName }));
|
|
320
|
+
// Initial commit
|
|
321
|
+
await this.fileManager.ensureGitignore();
|
|
322
|
+
await this.gitManager.addAllPostHogFiles();
|
|
323
|
+
if (isCloudMode) {
|
|
324
|
+
await this.gitManager.commitAndPush(`Initialize task ${taskSlug}`, { allowEmpty: true });
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
await this.gitManager.commitChanges(`Initialize task ${taskSlug}`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
this.logger.info('Switching to existing task branch', { branch: existingBranch });
|
|
332
|
+
await this.gitManager.switchToBranch(existingBranch);
|
|
333
|
+
}
|
|
334
|
+
// Phase 2: Research
|
|
335
|
+
const researchExists = await this.fileManager.readResearch(task.id);
|
|
336
|
+
if (!researchExists) {
|
|
337
|
+
this.logger.info('Starting research phase', { taskId: task.id });
|
|
338
|
+
this.emitEvent(this.adapter.createStatusEvent('phase_start', { phase: 'research' }));
|
|
339
|
+
// Run research agent
|
|
340
|
+
const researchPrompt = await this.promptBuilder.buildResearchPrompt(task, cwd);
|
|
341
|
+
const { RESEARCH_SYSTEM_PROMPT } = await import('./agents/research.js');
|
|
342
|
+
const fullPrompt = RESEARCH_SYSTEM_PROMPT + '\n\n' + researchPrompt;
|
|
343
|
+
const baseOptions = {
|
|
344
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
345
|
+
cwd,
|
|
346
|
+
permissionMode: 'plan',
|
|
347
|
+
settingSources: ['local'],
|
|
348
|
+
mcpServers: this.mcpServers,
|
|
349
|
+
};
|
|
350
|
+
const response = query({
|
|
351
|
+
prompt: fullPrompt,
|
|
352
|
+
options: { ...baseOptions, ...(options.queryOverrides || {}) },
|
|
353
|
+
});
|
|
354
|
+
let researchContent = '';
|
|
355
|
+
for await (const message of response) {
|
|
356
|
+
this.emitEvent(this.adapter.createRawSDKEvent(message));
|
|
357
|
+
const transformed = this.adapter.transform(message);
|
|
358
|
+
if (transformed) {
|
|
359
|
+
this.emitEvent(transformed);
|
|
360
|
+
}
|
|
361
|
+
if (message.type === 'assistant' && message.message?.content) {
|
|
362
|
+
for (const c of message.message.content) {
|
|
363
|
+
if (c.type === 'text' && c.text)
|
|
364
|
+
researchContent += c.text + '\n';
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// Write research.md
|
|
369
|
+
if (researchContent.trim()) {
|
|
370
|
+
await this.fileManager.writeResearch(task.id, researchContent.trim());
|
|
371
|
+
this.logger.info('Research completed', { taskId: task.id });
|
|
372
|
+
}
|
|
373
|
+
// Commit research
|
|
374
|
+
await this.gitManager.addAllPostHogFiles();
|
|
375
|
+
// Extract questions using structured output and save to questions.json
|
|
376
|
+
if (this.extractor) {
|
|
377
|
+
try {
|
|
378
|
+
this.logger.info('Extracting questions from research.md', { taskId: task.id });
|
|
379
|
+
const questions = await this.extractQuestionsFromResearch(task.id, false);
|
|
380
|
+
this.logger.info('Questions extracted successfully', { taskId: task.id, count: questions.length });
|
|
381
|
+
// Save questions.json
|
|
382
|
+
await this.fileManager.writeQuestions(task.id, {
|
|
383
|
+
questions,
|
|
384
|
+
answered: false,
|
|
385
|
+
answers: null,
|
|
386
|
+
});
|
|
387
|
+
this.logger.info('Questions saved to questions.json', { taskId: task.id });
|
|
388
|
+
// Emit event for Array to pick up (local mode)
|
|
389
|
+
if (!isCloudMode) {
|
|
390
|
+
this.emitEvent({
|
|
391
|
+
type: 'artifact',
|
|
392
|
+
ts: Date.now(),
|
|
393
|
+
kind: 'research_questions',
|
|
394
|
+
content: questions,
|
|
395
|
+
});
|
|
396
|
+
this.logger.info('Emitted research_questions artifact event', { taskId: task.id });
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
catch (error) {
|
|
400
|
+
this.logger.error('Failed to extract questions', { error: error instanceof Error ? error.message : String(error) });
|
|
401
|
+
this.emitEvent({
|
|
402
|
+
type: 'error',
|
|
403
|
+
ts: Date.now(),
|
|
404
|
+
message: `Failed to extract questions: ${error instanceof Error ? error.message : String(error)}`,
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
this.logger.warn('OpenAI extractor not available (OPENAI_API_KEY not set), skipping question extraction');
|
|
410
|
+
this.emitEvent({
|
|
411
|
+
type: 'status',
|
|
412
|
+
ts: Date.now(),
|
|
413
|
+
phase: 'extraction_skipped',
|
|
414
|
+
message: 'Question extraction skipped - OPENAI_API_KEY not configured',
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
if (isCloudMode) {
|
|
418
|
+
await this.gitManager.commitAndPush(`Research phase for ${task.title}`);
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
await this.gitManager.commitChanges(`Research phase for ${task.title}`);
|
|
422
|
+
this.emitEvent(this.adapter.createStatusEvent('phase_complete', { phase: 'research' }));
|
|
423
|
+
return; // Local mode: return to user
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
// Phase 3: Auto-answer questions (cloud mode only)
|
|
427
|
+
if (isCloudMode) {
|
|
428
|
+
const questionsData = await this.fileManager.readQuestions(task.id);
|
|
429
|
+
if (questionsData && !questionsData.answered) {
|
|
430
|
+
this.logger.info('Auto-answering research questions', { taskId: task.id });
|
|
431
|
+
// Extract questions with recommended answers using structured output
|
|
432
|
+
if (this.extractor) {
|
|
433
|
+
const questionsWithAnswers = await this.extractQuestionsFromResearch(task.id, true);
|
|
434
|
+
// Save answers to questions.json
|
|
435
|
+
await this.fileManager.writeQuestions(task.id, {
|
|
436
|
+
questions: questionsWithAnswers.map(qa => ({
|
|
437
|
+
id: qa.id,
|
|
438
|
+
question: qa.question,
|
|
439
|
+
options: qa.options,
|
|
440
|
+
})),
|
|
441
|
+
answered: true,
|
|
442
|
+
answers: questionsWithAnswers.map(qa => ({
|
|
443
|
+
questionId: qa.id,
|
|
444
|
+
selectedOption: qa.recommendedAnswer,
|
|
445
|
+
customInput: qa.justification,
|
|
446
|
+
})),
|
|
447
|
+
});
|
|
448
|
+
this.logger.info('Auto-answers saved to questions.json', { taskId: task.id });
|
|
449
|
+
await this.gitManager.addAllPostHogFiles();
|
|
450
|
+
await this.gitManager.commitAndPush(`Answer research questions for ${task.title}`);
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
this.logger.warn('OpenAI extractor not available, skipping auto-answer');
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
// Phase 4: Plan
|
|
458
|
+
const planExists = await this.readPlan(task.id);
|
|
459
|
+
if (!planExists) {
|
|
460
|
+
// Check if questions have been answered
|
|
461
|
+
const questionsData = await this.fileManager.readQuestions(task.id);
|
|
462
|
+
if (!questionsData || !questionsData.answered) {
|
|
463
|
+
this.logger.info('Waiting for user answers to research questions');
|
|
464
|
+
this.emitEvent(this.adapter.createStatusEvent('phase_complete', { phase: 'research_questions' }));
|
|
465
|
+
return; // Wait for user to answer questions
|
|
466
|
+
}
|
|
467
|
+
this.logger.info('Starting planning phase', { taskId: task.id });
|
|
468
|
+
this.emitEvent(this.adapter.createStatusEvent('phase_start', { phase: 'planning' }));
|
|
469
|
+
// Build context with research + questions + answers
|
|
470
|
+
const research = await this.fileManager.readResearch(task.id);
|
|
471
|
+
let researchContext = '';
|
|
472
|
+
if (research) {
|
|
473
|
+
researchContext += `## Research Analysis\n\n${research}\n\n`;
|
|
474
|
+
}
|
|
475
|
+
// Add questions and answers
|
|
476
|
+
researchContext += `## Implementation Decisions\n\n`;
|
|
477
|
+
const answers = questionsData.answers || [];
|
|
478
|
+
for (const question of questionsData.questions) {
|
|
479
|
+
const answer = answers.find((a) => a.questionId === question.id);
|
|
480
|
+
researchContext += `### ${question.question}\n\n`;
|
|
481
|
+
if (answer) {
|
|
482
|
+
researchContext += `**Selected:** ${answer.selectedOption}\n`;
|
|
483
|
+
if (answer.customInput) {
|
|
484
|
+
researchContext += `**Details:** ${answer.customInput}\n`;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
this.logger.warn('No answer found for question', { questionId: question.id });
|
|
489
|
+
researchContext += `**Selected:** Not answered\n`;
|
|
490
|
+
}
|
|
491
|
+
researchContext += '\n';
|
|
492
|
+
}
|
|
493
|
+
// Run planning agent with full context
|
|
494
|
+
const planningPrompt = await this.promptBuilder.buildPlanningPrompt(task, cwd);
|
|
495
|
+
const { PLANNING_SYSTEM_PROMPT } = await import('./agents/planning.js');
|
|
496
|
+
const fullPrompt = PLANNING_SYSTEM_PROMPT + '\n\n' + planningPrompt + '\n\n' + researchContext;
|
|
497
|
+
const baseOptions = {
|
|
498
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
499
|
+
cwd,
|
|
500
|
+
permissionMode: 'plan',
|
|
501
|
+
settingSources: ['local'],
|
|
502
|
+
mcpServers: this.mcpServers,
|
|
503
|
+
};
|
|
504
|
+
const response = query({
|
|
505
|
+
prompt: fullPrompt,
|
|
506
|
+
options: { ...baseOptions, ...(options.queryOverrides || {}) },
|
|
507
|
+
});
|
|
508
|
+
let planContent = '';
|
|
509
|
+
for await (const message of response) {
|
|
510
|
+
this.emitEvent(this.adapter.createRawSDKEvent(message));
|
|
511
|
+
const transformed = this.adapter.transform(message);
|
|
512
|
+
if (transformed) {
|
|
513
|
+
this.emitEvent(transformed);
|
|
514
|
+
}
|
|
515
|
+
if (message.type === 'assistant' && message.message?.content) {
|
|
516
|
+
for (const c of message.message.content) {
|
|
517
|
+
if (c.type === 'text' && c.text)
|
|
518
|
+
planContent += c.text + '\n';
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
// Write plan.md
|
|
523
|
+
if (planContent.trim()) {
|
|
524
|
+
await this.writePlan(task.id, planContent.trim());
|
|
525
|
+
this.logger.info('Plan completed', { taskId: task.id });
|
|
526
|
+
}
|
|
527
|
+
// Commit plan
|
|
528
|
+
await this.gitManager.addAllPostHogFiles();
|
|
529
|
+
if (isCloudMode) {
|
|
530
|
+
await this.gitManager.commitAndPush(`Planning phase for ${task.title}`);
|
|
531
|
+
}
|
|
532
|
+
else {
|
|
533
|
+
await this.gitManager.commitChanges(`Planning phase for ${task.title}`);
|
|
534
|
+
this.emitEvent(this.adapter.createStatusEvent('phase_complete', { phase: 'planning' }));
|
|
535
|
+
return; // Local mode: return to user
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
// Phase 5: Build
|
|
539
|
+
const latestRun = task.latest_run;
|
|
540
|
+
const prExists = latestRun?.output && latestRun.output.pr_url;
|
|
541
|
+
if (!prExists) {
|
|
542
|
+
this.logger.info('Starting build phase', { taskId: task.id });
|
|
543
|
+
this.emitEvent(this.adapter.createStatusEvent('phase_start', { phase: 'build' }));
|
|
544
|
+
// Run execution agent
|
|
545
|
+
const executionPrompt = await this.promptBuilder.buildExecutionPrompt(task, cwd);
|
|
546
|
+
const { EXECUTION_SYSTEM_PROMPT } = await import('./agents/execution.js');
|
|
547
|
+
const fullPrompt = EXECUTION_SYSTEM_PROMPT + '\n\n' + executionPrompt;
|
|
548
|
+
const { PermissionMode } = await import('./types.js');
|
|
549
|
+
const permissionMode = options.permissionMode || PermissionMode.ACCEPT_EDITS;
|
|
550
|
+
const baseOptions = {
|
|
551
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
552
|
+
cwd,
|
|
553
|
+
permissionMode,
|
|
554
|
+
settingSources: ['local'],
|
|
555
|
+
mcpServers: this.mcpServers,
|
|
556
|
+
};
|
|
557
|
+
const response = query({
|
|
558
|
+
prompt: fullPrompt,
|
|
559
|
+
options: { ...baseOptions, ...(options.queryOverrides || {}) },
|
|
560
|
+
});
|
|
561
|
+
for await (const message of response) {
|
|
562
|
+
this.emitEvent(this.adapter.createRawSDKEvent(message));
|
|
563
|
+
const transformed = this.adapter.transform(message);
|
|
564
|
+
if (transformed) {
|
|
565
|
+
this.emitEvent(transformed);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
// Commit and push implementation
|
|
569
|
+
// Stage ALL changes (not just .posthog/)
|
|
570
|
+
const hasChanges = await this.gitManager.hasChanges();
|
|
571
|
+
if (hasChanges) {
|
|
572
|
+
await this.gitManager.addFiles(['.']); // Stage all changes
|
|
573
|
+
await this.gitManager.commitChanges(`Implementation for ${task.title}`);
|
|
574
|
+
// Push to origin
|
|
575
|
+
const branchName = await this.gitManager.getCurrentBranch();
|
|
576
|
+
await this.gitManager.pushBranch(branchName);
|
|
577
|
+
this.logger.info('Implementation committed and pushed', { taskId: task.id });
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
this.logger.warn('No changes to commit in build phase', { taskId: task.id });
|
|
581
|
+
}
|
|
582
|
+
// Create PR
|
|
583
|
+
const branchName = await this.gitManager.getCurrentBranch();
|
|
584
|
+
const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
|
|
585
|
+
this.logger.info('Pull request created', { taskId: task.id, prUrl });
|
|
586
|
+
this.emitEvent(this.adapter.createStatusEvent('pr_created', { prUrl }));
|
|
587
|
+
// Attach PR to task run
|
|
588
|
+
try {
|
|
589
|
+
await this.attachPullRequestToTask(task.id, prUrl, branchName);
|
|
590
|
+
this.logger.info('PR attached to task successfully', { taskId: task.id, prUrl });
|
|
591
|
+
}
|
|
592
|
+
catch (error) {
|
|
593
|
+
this.logger.warn('Could not attach PR to task', { error: error instanceof Error ? error.message : String(error) });
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
else {
|
|
597
|
+
this.logger.info('PR already exists, skipping build phase', { taskId: task.id });
|
|
598
|
+
}
|
|
599
|
+
// Phase 6: Complete
|
|
600
|
+
await this.progressReporter.complete();
|
|
601
|
+
this.logger.info('Task execution complete', { taskId: task.id });
|
|
602
|
+
this.emitEvent(this.adapter.createStatusEvent('task_complete', { taskId: task.id }));
|
|
603
|
+
}
|
|
287
604
|
async progressToNextStage(taskId, currentStageKey) {
|
|
288
|
-
if (!this.posthogAPI)
|
|
289
|
-
throw new Error('PostHog API not configured. Cannot progress stage.');
|
|
605
|
+
if (!this.posthogAPI || !this.progressReporter.runId) {
|
|
606
|
+
throw new Error('PostHog API not configured or no active run. Cannot progress stage.');
|
|
607
|
+
}
|
|
290
608
|
try {
|
|
291
|
-
await this.posthogAPI.
|
|
609
|
+
await this.posthogAPI.progressTaskRun(taskId, this.progressReporter.runId);
|
|
292
610
|
}
|
|
293
611
|
catch (error) {
|
|
294
612
|
if (error instanceof Error && error.message.includes('No next stage available')) {
|
|
295
|
-
this.logger.warn('No next stage available when attempting to progress
|
|
613
|
+
this.logger.warn('No next stage available when attempting to progress run', {
|
|
296
614
|
taskId,
|
|
615
|
+
runId: this.progressReporter.runId,
|
|
297
616
|
stage: currentStageKey,
|
|
298
617
|
error: error.message,
|
|
299
618
|
});
|
|
@@ -374,6 +693,22 @@ class Agent {
|
|
|
374
693
|
this.logger.debug('Reading plan', { taskId });
|
|
375
694
|
return await this.fileManager.readPlan(taskId);
|
|
376
695
|
}
|
|
696
|
+
async extractQuestionsFromResearch(taskId, includeAnswers = false) {
|
|
697
|
+
this.logger.info('Extracting questions from research.md', { taskId, includeAnswers });
|
|
698
|
+
if (!this.extractor) {
|
|
699
|
+
throw new Error('OpenAI extractor not initialized. Set OPENAI_API_KEY environment variable.');
|
|
700
|
+
}
|
|
701
|
+
const researchContent = await this.fileManager.readResearch(taskId);
|
|
702
|
+
if (!researchContent) {
|
|
703
|
+
throw new Error('research.md not found for task ' + taskId);
|
|
704
|
+
}
|
|
705
|
+
if (includeAnswers) {
|
|
706
|
+
return await this.extractor.extractQuestionsWithAnswers(researchContent);
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
return await this.extractor.extractQuestions(researchContent);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
377
712
|
// Git operations for task workflow
|
|
378
713
|
async createPlanningBranch(taskId) {
|
|
379
714
|
this.logger.info('Creating planning branch', { taskId });
|
|
@@ -417,24 +752,30 @@ Generated by PostHog Agent`;
|
|
|
417
752
|
return prUrl;
|
|
418
753
|
}
|
|
419
754
|
async attachPullRequestToTask(taskId, prUrl, branchName) {
|
|
420
|
-
this.logger.info('Attaching PR to task', { taskId, prUrl, branchName });
|
|
421
|
-
if (!this.posthogAPI) {
|
|
422
|
-
const error = new Error('PostHog API not configured. Cannot attach PR to task.');
|
|
755
|
+
this.logger.info('Attaching PR to task run', { taskId, prUrl, branchName });
|
|
756
|
+
if (!this.posthogAPI || !this.progressReporter.runId) {
|
|
757
|
+
const error = new Error('PostHog API not configured or no active run. Cannot attach PR to task.');
|
|
423
758
|
this.logger.error('PostHog API not configured', error);
|
|
424
759
|
throw error;
|
|
425
760
|
}
|
|
426
|
-
|
|
427
|
-
|
|
761
|
+
const updates = {
|
|
762
|
+
output: { pr_url: prUrl }
|
|
763
|
+
};
|
|
764
|
+
if (branchName) {
|
|
765
|
+
updates.branch = branchName;
|
|
766
|
+
}
|
|
767
|
+
await this.posthogAPI.updateTaskRun(taskId, this.progressReporter.runId, updates);
|
|
768
|
+
this.logger.debug('PR attached to task run', { taskId, runId: this.progressReporter.runId, prUrl });
|
|
428
769
|
}
|
|
429
770
|
async updateTaskBranch(taskId, branchName) {
|
|
430
|
-
this.logger.info('Updating task branch', { taskId, branchName });
|
|
431
|
-
if (!this.posthogAPI) {
|
|
432
|
-
const error = new Error('PostHog API not configured. Cannot update
|
|
771
|
+
this.logger.info('Updating task run branch', { taskId, branchName });
|
|
772
|
+
if (!this.posthogAPI || !this.progressReporter.runId) {
|
|
773
|
+
const error = new Error('PostHog API not configured or no active run. Cannot update branch.');
|
|
433
774
|
this.logger.error('PostHog API not configured', error);
|
|
434
775
|
throw error;
|
|
435
776
|
}
|
|
436
|
-
await this.posthogAPI.
|
|
437
|
-
this.logger.debug('Task branch updated', { taskId, branchName });
|
|
777
|
+
await this.posthogAPI.updateTaskRun(taskId, this.progressReporter.runId, { branch: branchName });
|
|
778
|
+
this.logger.debug('Task run branch updated', { taskId, runId: this.progressReporter.runId, branchName });
|
|
438
779
|
}
|
|
439
780
|
// Execution management
|
|
440
781
|
cancelTask(taskId) {
|