@posthog/agent 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_commonjsHelpers.js +6 -0
- package/dist/_virtual/_commonjsHelpers.js.map +1 -0
- package/dist/_virtual/index.js +4 -0
- package/dist/_virtual/index.js.map +1 -0
- package/dist/node_modules/@ai-sdk/anthropic/dist/index.js +1154 -0
- package/dist/node_modules/@ai-sdk/anthropic/dist/index.js.map +1 -0
- package/dist/node_modules/@ai-sdk/provider/dist/index.js +296 -0
- package/dist/node_modules/@ai-sdk/provider/dist/index.js.map +1 -0
- package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js +576 -0
- package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js.map +1 -0
- package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js +741 -0
- package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js +112 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js +123 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js +62 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js +91 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js +79 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js +59 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js +99 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js +31 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js +69 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js +54 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js +22 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js +104 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js +44 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js +43 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js +27 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js +62 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js +121 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js +167 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js +33 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js +22 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js +21 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js +35 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js +40 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js +22 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js +70 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js +78 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js +34 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js +55 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js +56 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js +76 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js +27 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js +45 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js +22 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js +25 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js +24 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js.map +1 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/version.js +20 -0
- package/dist/node_modules/@opentelemetry/api/build/esm/version.js.map +1 -0
- package/dist/node_modules/ai/dist/index.js +2870 -0
- package/dist/node_modules/ai/dist/index.js.map +1 -0
- package/dist/node_modules/nanoid/non-secure/index.js +13 -0
- package/dist/node_modules/nanoid/non-secure/index.js.map +1 -0
- package/dist/node_modules/secure-json-parse/index.js +133 -0
- package/dist/node_modules/secure-json-parse/index.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js +37 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js +26 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js +17 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js +11 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/index.js +8 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/index.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js +66 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js +21 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js +30 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js +53 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js +8 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js +8 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js +8 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js +50 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js +11 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js +11 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js +9 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js +56 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js +24 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js +30 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js +19 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js +15 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js +13 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js +37 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js +56 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js +76 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js +25 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js +24 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js +8 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js +8 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js +65 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js +24 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js +350 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js +36 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js +10 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js +84 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js +8 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js +110 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js.map +1 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js +90 -0
- package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js.map +1 -0
- package/dist/src/agent.d.ts +3 -0
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +93 -291
- package/dist/src/agent.js.map +1 -1
- package/dist/src/agents/planning.d.ts +1 -1
- package/dist/src/agents/planning.d.ts.map +1 -1
- package/dist/src/agents/planning.js +1 -2
- package/dist/src/agents/planning.js.map +1 -1
- package/dist/src/agents/research.d.ts +1 -1
- package/dist/src/agents/research.d.ts.map +1 -1
- package/dist/src/agents/research.js +3 -6
- package/dist/src/agents/research.js.map +1 -1
- package/dist/src/prompt-builder.d.ts.map +1 -1
- package/dist/src/prompt-builder.js +0 -1
- package/dist/src/prompt-builder.js.map +1 -1
- package/dist/src/structured-extraction.d.ts +2 -2
- package/dist/src/structured-extraction.d.ts.map +1 -1
- package/dist/src/structured-extraction.js +51 -110
- package/dist/src/structured-extraction.js.map +1 -1
- package/dist/src/workflow/config.d.ts +3 -0
- package/dist/src/workflow/config.d.ts.map +1 -0
- package/dist/src/workflow/config.js +43 -0
- package/dist/src/workflow/config.js.map +1 -0
- package/dist/src/workflow/steps/build.d.ts +3 -0
- package/dist/src/workflow/steps/build.d.ts.map +1 -0
- package/dist/src/workflow/steps/build.js +64 -0
- package/dist/src/workflow/steps/build.js.map +1 -0
- package/dist/src/workflow/steps/plan.d.ts +3 -0
- package/dist/src/workflow/steps/plan.d.ts.map +1 -0
- package/dist/src/workflow/steps/plan.js +86 -0
- package/dist/src/workflow/steps/plan.js.map +1 -0
- package/dist/src/workflow/steps/research.d.ts +3 -0
- package/dist/src/workflow/steps/research.d.ts.map +1 -0
- package/dist/src/workflow/steps/research.js +124 -0
- package/dist/src/workflow/steps/research.js.map +1 -0
- package/dist/src/workflow/types.d.ts +48 -0
- package/dist/src/workflow/types.d.ts.map +1 -0
- package/dist/src/workflow/utils.d.ts +12 -0
- package/dist/src/workflow/utils.d.ts.map +1 -0
- package/dist/src/workflow/utils.js +38 -0
- package/dist/src/workflow/utils.js.map +1 -0
- package/package.json +5 -2
- package/src/agent.ts +112 -321
- package/src/agents/planning.ts +1 -2
- package/src/agents/research.ts +3 -6
- package/src/prompt-builder.ts +0 -2
- package/src/structured-extraction.ts +58 -115
- package/src/workflow/config.ts +42 -0
- package/src/workflow/steps/build.ts +87 -0
- package/src/workflow/steps/plan.ts +112 -0
- package/src/workflow/steps/research.ts +156 -0
- package/src/workflow/types.ts +53 -0
- package/src/workflow/utils.ts +50 -0
package/dist/src/agent.js
CHANGED
|
@@ -8,7 +8,8 @@ import { ClaudeAdapter } from './adapters/claude/claude-adapter.js';
|
|
|
8
8
|
import { Logger } from './utils/logger.js';
|
|
9
9
|
import { PromptBuilder } from './prompt-builder.js';
|
|
10
10
|
import { TaskProgressReporter } from './task-progress-reporter.js';
|
|
11
|
-
import {
|
|
11
|
+
import { AISDKExtractor } from './structured-extraction.js';
|
|
12
|
+
import { TASK_WORKFLOW } from './workflow/config.js';
|
|
12
13
|
export { PermissionMode } from './types.js';
|
|
13
14
|
|
|
14
15
|
class Agent {
|
|
@@ -75,10 +76,7 @@ class Agent {
|
|
|
75
76
|
logger: this.logger.child('PromptBuilder')
|
|
76
77
|
});
|
|
77
78
|
this.progressReporter = new TaskProgressReporter(this.posthogAPI, this.logger);
|
|
78
|
-
|
|
79
|
-
if (process.env.OPENAI_API_KEY) {
|
|
80
|
-
this.extractor = new OpenAIExtractor(this.logger.child('OpenAIExtractor'));
|
|
81
|
-
}
|
|
79
|
+
this.extractor = new AISDKExtractor(this.logger.child('AISDKExtractor'));
|
|
82
80
|
}
|
|
83
81
|
/**
|
|
84
82
|
* Enable or disable debug logging
|
|
@@ -95,6 +93,7 @@ class Agent {
|
|
|
95
93
|
return;
|
|
96
94
|
}
|
|
97
95
|
if (process.env.ANTHROPIC_BASE_URL && process.env.ANTHROPIC_AUTH_TOKEN) {
|
|
96
|
+
this.ensureOpenAIGatewayEnv();
|
|
98
97
|
return;
|
|
99
98
|
}
|
|
100
99
|
try {
|
|
@@ -102,6 +101,7 @@ class Agent {
|
|
|
102
101
|
const apiKey = this.posthogAPI.getApiKey();
|
|
103
102
|
process.env.ANTHROPIC_BASE_URL = gatewayUrl;
|
|
104
103
|
process.env.ANTHROPIC_AUTH_TOKEN = apiKey;
|
|
104
|
+
this.ensureOpenAIGatewayEnv(gatewayUrl, apiKey);
|
|
105
105
|
this.logger.debug('Configured LLM gateway', { gatewayUrl });
|
|
106
106
|
}
|
|
107
107
|
catch (error) {
|
|
@@ -109,7 +109,7 @@ class Agent {
|
|
|
109
109
|
throw error;
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
-
// Adaptive task execution
|
|
112
|
+
// Adaptive task execution orchestrated via workflow steps
|
|
113
113
|
async runTask(taskOrId, options = {}) {
|
|
114
114
|
await this._configureLlmGateway();
|
|
115
115
|
const task = typeof taskOrId === 'string' ? await this.fetchTask(taskOrId) : taskOrId;
|
|
@@ -118,295 +118,36 @@ class Agent {
|
|
|
118
118
|
const taskSlug = task.slug || task.id;
|
|
119
119
|
this.logger.info('Starting adaptive task execution', { taskId: task.id, taskSlug, isCloudMode });
|
|
120
120
|
// Initialize progress reporter for task run tracking (needed for PR attachment)
|
|
121
|
-
await this.progressReporter.start(task.id, { totalSteps:
|
|
121
|
+
await this.progressReporter.start(task.id, { totalSteps: TASK_WORKFLOW.length });
|
|
122
122
|
this.emitEvent(this.adapter.createStatusEvent('run_started', { runId: this.progressReporter.runId }));
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (!researchExists) {
|
|
147
|
-
this.logger.info('Starting research phase', { taskId: task.id });
|
|
148
|
-
this.emitEvent(this.adapter.createStatusEvent('phase_start', { phase: 'research' }));
|
|
149
|
-
// Run research agent
|
|
150
|
-
const researchPrompt = await this.promptBuilder.buildResearchPrompt(task, cwd);
|
|
151
|
-
const { RESEARCH_SYSTEM_PROMPT } = await import('./agents/research.js');
|
|
152
|
-
const fullPrompt = RESEARCH_SYSTEM_PROMPT + '\n\n' + researchPrompt;
|
|
153
|
-
const baseOptions = {
|
|
154
|
-
model: 'claude-sonnet-4-5-20250929',
|
|
155
|
-
cwd,
|
|
156
|
-
permissionMode: 'plan',
|
|
157
|
-
settingSources: ['local'],
|
|
158
|
-
mcpServers: this.mcpServers,
|
|
159
|
-
};
|
|
160
|
-
const response = query({
|
|
161
|
-
prompt: fullPrompt,
|
|
162
|
-
options: { ...baseOptions, ...(options.queryOverrides || {}) },
|
|
163
|
-
});
|
|
164
|
-
let researchContent = '';
|
|
165
|
-
for await (const message of response) {
|
|
166
|
-
this.emitEvent(this.adapter.createRawSDKEvent(message));
|
|
167
|
-
const transformed = this.adapter.transform(message);
|
|
168
|
-
if (transformed) {
|
|
169
|
-
this.emitEvent(transformed);
|
|
170
|
-
}
|
|
171
|
-
if (message.type === 'assistant' && message.message?.content) {
|
|
172
|
-
for (const c of message.message.content) {
|
|
173
|
-
if (c.type === 'text' && c.text)
|
|
174
|
-
researchContent += c.text + '\n';
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
// Write research.md
|
|
179
|
-
if (researchContent.trim()) {
|
|
180
|
-
await this.fileManager.writeResearch(task.id, researchContent.trim());
|
|
181
|
-
this.logger.info('Research completed', { taskId: task.id });
|
|
182
|
-
}
|
|
183
|
-
// Commit research
|
|
184
|
-
await this.gitManager.addAllPostHogFiles();
|
|
185
|
-
// Extract questions using structured output and save to questions.json
|
|
186
|
-
if (this.extractor) {
|
|
187
|
-
try {
|
|
188
|
-
this.logger.info('Extracting questions from research.md', { taskId: task.id });
|
|
189
|
-
const questions = await this.extractQuestionsFromResearch(task.id, false);
|
|
190
|
-
this.logger.info('Questions extracted successfully', { taskId: task.id, count: questions.length });
|
|
191
|
-
// Save questions.json
|
|
192
|
-
await this.fileManager.writeQuestions(task.id, {
|
|
193
|
-
questions,
|
|
194
|
-
answered: false,
|
|
195
|
-
answers: null,
|
|
196
|
-
});
|
|
197
|
-
this.logger.info('Questions saved to questions.json', { taskId: task.id });
|
|
198
|
-
// Emit event for Array to pick up (local mode)
|
|
199
|
-
if (!isCloudMode) {
|
|
200
|
-
this.emitEvent({
|
|
201
|
-
type: 'artifact',
|
|
202
|
-
ts: Date.now(),
|
|
203
|
-
kind: 'research_questions',
|
|
204
|
-
content: questions,
|
|
205
|
-
});
|
|
206
|
-
this.logger.info('Emitted research_questions artifact event', { taskId: task.id });
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
catch (error) {
|
|
210
|
-
this.logger.error('Failed to extract questions', { error: error instanceof Error ? error.message : String(error) });
|
|
211
|
-
this.emitEvent({
|
|
212
|
-
type: 'error',
|
|
213
|
-
ts: Date.now(),
|
|
214
|
-
message: `Failed to extract questions: ${error instanceof Error ? error.message : String(error)}`,
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
this.logger.warn('OpenAI extractor not available (OPENAI_API_KEY not set), skipping question extraction');
|
|
220
|
-
this.emitEvent({
|
|
221
|
-
type: 'status',
|
|
222
|
-
ts: Date.now(),
|
|
223
|
-
phase: 'extraction_skipped',
|
|
224
|
-
message: 'Question extraction skipped - OPENAI_API_KEY not configured',
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
if (isCloudMode) {
|
|
228
|
-
await this.gitManager.commitAndPush(`Research phase for ${task.title}`);
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
231
|
-
await this.gitManager.commitChanges(`Research phase for ${task.title}`);
|
|
232
|
-
this.emitEvent(this.adapter.createStatusEvent('phase_complete', { phase: 'research' }));
|
|
233
|
-
return; // Local mode: return to user
|
|
123
|
+
await this.prepareTaskBranch(taskSlug, isCloudMode);
|
|
124
|
+
const workflowContext = {
|
|
125
|
+
task,
|
|
126
|
+
taskSlug,
|
|
127
|
+
cwd,
|
|
128
|
+
isCloudMode,
|
|
129
|
+
options,
|
|
130
|
+
logger: this.logger,
|
|
131
|
+
fileManager: this.fileManager,
|
|
132
|
+
gitManager: this.gitManager,
|
|
133
|
+
promptBuilder: this.promptBuilder,
|
|
134
|
+
progressReporter: this.progressReporter,
|
|
135
|
+
adapter: this.adapter,
|
|
136
|
+
mcpServers: this.mcpServers,
|
|
137
|
+
posthogAPI: this.posthogAPI,
|
|
138
|
+
extractor: this.extractor,
|
|
139
|
+
emitEvent: (event) => this.emitEvent(event),
|
|
140
|
+
stepResults: {},
|
|
141
|
+
};
|
|
142
|
+
for (const step of TASK_WORKFLOW) {
|
|
143
|
+
const result = await step.run({ step, context: workflowContext });
|
|
144
|
+
if (result.halt) {
|
|
145
|
+
return;
|
|
234
146
|
}
|
|
235
147
|
}
|
|
236
|
-
// Phase 3: Auto-answer questions (cloud mode only)
|
|
237
148
|
if (isCloudMode) {
|
|
238
|
-
|
|
239
|
-
if (questionsData && !questionsData.answered) {
|
|
240
|
-
this.logger.info('Auto-answering research questions', { taskId: task.id });
|
|
241
|
-
// Extract questions with recommended answers using structured output
|
|
242
|
-
if (this.extractor) {
|
|
243
|
-
const questionsWithAnswers = await this.extractQuestionsFromResearch(task.id, true);
|
|
244
|
-
// Save answers to questions.json
|
|
245
|
-
await this.fileManager.writeQuestions(task.id, {
|
|
246
|
-
questions: questionsWithAnswers.map(qa => ({
|
|
247
|
-
id: qa.id,
|
|
248
|
-
question: qa.question,
|
|
249
|
-
options: qa.options,
|
|
250
|
-
})),
|
|
251
|
-
answered: true,
|
|
252
|
-
answers: questionsWithAnswers.map(qa => ({
|
|
253
|
-
questionId: qa.id,
|
|
254
|
-
selectedOption: qa.recommendedAnswer,
|
|
255
|
-
customInput: qa.justification,
|
|
256
|
-
})),
|
|
257
|
-
});
|
|
258
|
-
this.logger.info('Auto-answers saved to questions.json', { taskId: task.id });
|
|
259
|
-
await this.gitManager.addAllPostHogFiles();
|
|
260
|
-
await this.gitManager.commitAndPush(`Answer research questions for ${task.title}`);
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
this.logger.warn('OpenAI extractor not available, skipping auto-answer');
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
// Phase 4: Plan
|
|
268
|
-
const planExists = await this.readPlan(task.id);
|
|
269
|
-
if (!planExists) {
|
|
270
|
-
// Check if questions have been answered
|
|
271
|
-
const questionsData = await this.fileManager.readQuestions(task.id);
|
|
272
|
-
if (!questionsData || !questionsData.answered) {
|
|
273
|
-
this.logger.info('Waiting for user answers to research questions');
|
|
274
|
-
this.emitEvent(this.adapter.createStatusEvent('phase_complete', { phase: 'research_questions' }));
|
|
275
|
-
return; // Wait for user to answer questions
|
|
276
|
-
}
|
|
277
|
-
this.logger.info('Starting planning phase', { taskId: task.id });
|
|
278
|
-
this.emitEvent(this.adapter.createStatusEvent('phase_start', { phase: 'planning' }));
|
|
279
|
-
// Build context with research + questions + answers
|
|
280
|
-
const research = await this.fileManager.readResearch(task.id);
|
|
281
|
-
let researchContext = '';
|
|
282
|
-
if (research) {
|
|
283
|
-
researchContext += `## Research Analysis\n\n${research}\n\n`;
|
|
284
|
-
}
|
|
285
|
-
// Add questions and answers
|
|
286
|
-
researchContext += `## Implementation Decisions\n\n`;
|
|
287
|
-
const answers = questionsData.answers || [];
|
|
288
|
-
for (const question of questionsData.questions) {
|
|
289
|
-
const answer = answers.find((a) => a.questionId === question.id);
|
|
290
|
-
researchContext += `### ${question.question}\n\n`;
|
|
291
|
-
if (answer) {
|
|
292
|
-
researchContext += `**Selected:** ${answer.selectedOption}\n`;
|
|
293
|
-
if (answer.customInput) {
|
|
294
|
-
researchContext += `**Details:** ${answer.customInput}\n`;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
else {
|
|
298
|
-
this.logger.warn('No answer found for question', { questionId: question.id });
|
|
299
|
-
researchContext += `**Selected:** Not answered\n`;
|
|
300
|
-
}
|
|
301
|
-
researchContext += '\n';
|
|
302
|
-
}
|
|
303
|
-
// Run planning agent with full context
|
|
304
|
-
const planningPrompt = await this.promptBuilder.buildPlanningPrompt(task, cwd);
|
|
305
|
-
const { PLANNING_SYSTEM_PROMPT } = await import('./agents/planning.js');
|
|
306
|
-
const fullPrompt = PLANNING_SYSTEM_PROMPT + '\n\n' + planningPrompt + '\n\n' + researchContext;
|
|
307
|
-
const baseOptions = {
|
|
308
|
-
model: 'claude-sonnet-4-5-20250929',
|
|
309
|
-
cwd,
|
|
310
|
-
permissionMode: 'plan',
|
|
311
|
-
settingSources: ['local'],
|
|
312
|
-
mcpServers: this.mcpServers,
|
|
313
|
-
};
|
|
314
|
-
const response = query({
|
|
315
|
-
prompt: fullPrompt,
|
|
316
|
-
options: { ...baseOptions, ...(options.queryOverrides || {}) },
|
|
317
|
-
});
|
|
318
|
-
let planContent = '';
|
|
319
|
-
for await (const message of response) {
|
|
320
|
-
this.emitEvent(this.adapter.createRawSDKEvent(message));
|
|
321
|
-
const transformed = this.adapter.transform(message);
|
|
322
|
-
if (transformed) {
|
|
323
|
-
this.emitEvent(transformed);
|
|
324
|
-
}
|
|
325
|
-
if (message.type === 'assistant' && message.message?.content) {
|
|
326
|
-
for (const c of message.message.content) {
|
|
327
|
-
if (c.type === 'text' && c.text)
|
|
328
|
-
planContent += c.text + '\n';
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
// Write plan.md
|
|
333
|
-
if (planContent.trim()) {
|
|
334
|
-
await this.writePlan(task.id, planContent.trim());
|
|
335
|
-
this.logger.info('Plan completed', { taskId: task.id });
|
|
336
|
-
}
|
|
337
|
-
// Commit plan
|
|
338
|
-
await this.gitManager.addAllPostHogFiles();
|
|
339
|
-
if (isCloudMode) {
|
|
340
|
-
await this.gitManager.commitAndPush(`Planning phase for ${task.title}`);
|
|
341
|
-
}
|
|
342
|
-
else {
|
|
343
|
-
await this.gitManager.commitChanges(`Planning phase for ${task.title}`);
|
|
344
|
-
this.emitEvent(this.adapter.createStatusEvent('phase_complete', { phase: 'planning' }));
|
|
345
|
-
return; // Local mode: return to user
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
// Phase 5: Build
|
|
349
|
-
const latestRun = task.latest_run;
|
|
350
|
-
const prExists = latestRun?.output && latestRun.output.pr_url;
|
|
351
|
-
if (!prExists) {
|
|
352
|
-
this.logger.info('Starting build phase', { taskId: task.id });
|
|
353
|
-
this.emitEvent(this.adapter.createStatusEvent('phase_start', { phase: 'build' }));
|
|
354
|
-
// Run execution agent
|
|
355
|
-
const executionPrompt = await this.promptBuilder.buildExecutionPrompt(task, cwd);
|
|
356
|
-
const { EXECUTION_SYSTEM_PROMPT } = await import('./agents/execution.js');
|
|
357
|
-
const fullPrompt = EXECUTION_SYSTEM_PROMPT + '\n\n' + executionPrompt;
|
|
358
|
-
const { PermissionMode } = await import('./types.js');
|
|
359
|
-
const permissionMode = options.permissionMode || PermissionMode.ACCEPT_EDITS;
|
|
360
|
-
const baseOptions = {
|
|
361
|
-
model: 'claude-sonnet-4-5-20250929',
|
|
362
|
-
cwd,
|
|
363
|
-
permissionMode,
|
|
364
|
-
settingSources: ['local'],
|
|
365
|
-
mcpServers: this.mcpServers,
|
|
366
|
-
};
|
|
367
|
-
const response = query({
|
|
368
|
-
prompt: fullPrompt,
|
|
369
|
-
options: { ...baseOptions, ...(options.queryOverrides || {}) },
|
|
370
|
-
});
|
|
371
|
-
for await (const message of response) {
|
|
372
|
-
this.emitEvent(this.adapter.createRawSDKEvent(message));
|
|
373
|
-
const transformed = this.adapter.transform(message);
|
|
374
|
-
if (transformed) {
|
|
375
|
-
this.emitEvent(transformed);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
// Commit and push implementation
|
|
379
|
-
// Stage ALL changes (not just .posthog/)
|
|
380
|
-
const hasChanges = await this.gitManager.hasChanges();
|
|
381
|
-
if (hasChanges) {
|
|
382
|
-
await this.gitManager.addFiles(['.']); // Stage all changes
|
|
383
|
-
await this.gitManager.commitChanges(`Implementation for ${task.title}`);
|
|
384
|
-
// Push to origin
|
|
385
|
-
const branchName = await this.gitManager.getCurrentBranch();
|
|
386
|
-
await this.gitManager.pushBranch(branchName);
|
|
387
|
-
this.logger.info('Implementation committed and pushed', { taskId: task.id });
|
|
388
|
-
}
|
|
389
|
-
else {
|
|
390
|
-
this.logger.warn('No changes to commit in build phase', { taskId: task.id });
|
|
391
|
-
}
|
|
392
|
-
// Create PR
|
|
393
|
-
const branchName = await this.gitManager.getCurrentBranch();
|
|
394
|
-
const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description);
|
|
395
|
-
this.logger.info('Pull request created', { taskId: task.id, prUrl });
|
|
396
|
-
this.emitEvent(this.adapter.createStatusEvent('pr_created', { prUrl }));
|
|
397
|
-
// Attach PR to task run
|
|
398
|
-
try {
|
|
399
|
-
await this.attachPullRequestToTask(task.id, prUrl, branchName);
|
|
400
|
-
this.logger.info('PR attached to task successfully', { taskId: task.id, prUrl });
|
|
401
|
-
}
|
|
402
|
-
catch (error) {
|
|
403
|
-
this.logger.warn('Could not attach PR to task', { error: error instanceof Error ? error.message : String(error) });
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
else {
|
|
407
|
-
this.logger.info('PR already exists, skipping build phase', { taskId: task.id });
|
|
149
|
+
await this.ensurePullRequest(task, workflowContext.stepResults);
|
|
408
150
|
}
|
|
409
|
-
// Phase 6: Complete
|
|
410
151
|
await this.progressReporter.complete();
|
|
411
152
|
this.logger.info('Task execution complete', { taskId: task.id });
|
|
412
153
|
this.emitEvent(this.adapter.createStatusEvent('task_complete', { taskId: task.id }));
|
|
@@ -484,7 +225,7 @@ class Agent {
|
|
|
484
225
|
async extractQuestionsFromResearch(taskId, includeAnswers = false) {
|
|
485
226
|
this.logger.info('Extracting questions from research.md', { taskId, includeAnswers });
|
|
486
227
|
if (!this.extractor) {
|
|
487
|
-
throw new Error('OpenAI extractor not initialized.
|
|
228
|
+
throw new Error('OpenAI extractor not initialized. Ensure the LLM gateway is configured.');
|
|
488
229
|
}
|
|
489
230
|
const researchContent = await this.fileManager.readResearch(taskId);
|
|
490
231
|
if (!researchContent) {
|
|
@@ -584,6 +325,67 @@ Generated by PostHog Agent`;
|
|
|
584
325
|
}
|
|
585
326
|
return null;
|
|
586
327
|
}
|
|
328
|
+
async prepareTaskBranch(taskSlug, isCloudMode) {
|
|
329
|
+
const existingBranch = await this.gitManager.getTaskBranch(taskSlug);
|
|
330
|
+
if (!existingBranch) {
|
|
331
|
+
this.logger.info('Creating task branch', { taskSlug });
|
|
332
|
+
const branchName = `posthog/task-${taskSlug}`;
|
|
333
|
+
await this.gitManager.createOrSwitchToBranch(branchName);
|
|
334
|
+
this.emitEvent(this.adapter.createStatusEvent('branch_created', { branch: branchName }));
|
|
335
|
+
await this.fileManager.ensureGitignore();
|
|
336
|
+
await this.gitManager.addAllPostHogFiles();
|
|
337
|
+
if (isCloudMode) {
|
|
338
|
+
await this.gitManager.commitAndPush(`Initialize task ${taskSlug}`, { allowEmpty: true });
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
await this.gitManager.commitChanges(`Initialize task ${taskSlug}`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
this.logger.info('Switching to existing task branch', { branch: existingBranch });
|
|
346
|
+
await this.gitManager.switchToBranch(existingBranch);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
ensureOpenAIGatewayEnv(baseUrl, token) {
|
|
350
|
+
const resolvedBaseUrl = baseUrl || process.env.ANTHROPIC_BASE_URL;
|
|
351
|
+
const resolvedToken = token || process.env.ANTHROPIC_AUTH_TOKEN;
|
|
352
|
+
if (resolvedBaseUrl) {
|
|
353
|
+
process.env.OPENAI_BASE_URL = resolvedBaseUrl;
|
|
354
|
+
}
|
|
355
|
+
if (resolvedToken) {
|
|
356
|
+
process.env.OPENAI_API_KEY = resolvedToken;
|
|
357
|
+
}
|
|
358
|
+
if (!this.extractor) {
|
|
359
|
+
this.extractor = new AISDKExtractor(this.logger.child('AISDKExtractor'));
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
async ensurePullRequest(task, stepResults) {
|
|
363
|
+
const latestRun = task.latest_run;
|
|
364
|
+
const existingPr = latestRun?.output && typeof latestRun.output === 'object'
|
|
365
|
+
? latestRun.output.pr_url
|
|
366
|
+
: null;
|
|
367
|
+
if (existingPr) {
|
|
368
|
+
this.logger.info('PR already exists, skipping creation', { taskId: task.id, prUrl: existingPr });
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const buildResult = stepResults['build'];
|
|
372
|
+
if (!buildResult?.commitCreated) {
|
|
373
|
+
this.logger.warn('Build step did not produce a commit; skipping PR creation', { taskId: task.id });
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
const branchName = await this.gitManager.getCurrentBranch();
|
|
377
|
+
const prUrl = await this.createPullRequest(task.id, branchName, task.title, task.description ?? '');
|
|
378
|
+
this.emitEvent(this.adapter.createStatusEvent('pr_created', { prUrl }));
|
|
379
|
+
try {
|
|
380
|
+
await this.attachPullRequestToTask(task.id, prUrl, branchName);
|
|
381
|
+
this.logger.info('PR attached to task successfully', { taskId: task.id, prUrl });
|
|
382
|
+
}
|
|
383
|
+
catch (error) {
|
|
384
|
+
this.logger.warn('Could not attach PR to task', {
|
|
385
|
+
error: error instanceof Error ? error.message : String(error),
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
587
389
|
emitEvent(event) {
|
|
588
390
|
if (this.debug && event.type !== 'token') {
|
|
589
391
|
// Log all events except tokens (too verbose)
|