@posthog/agent 1.16.6 → 1.17.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/index.d.ts +1 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/src/agent.d.ts +0 -3
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +6 -27
- package/dist/src/agent.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 +84 -53
- package/dist/src/agents/research.js.map +1 -1
- package/dist/src/file-manager.d.ts +3 -21
- package/dist/src/file-manager.d.ts.map +1 -1
- package/dist/src/file-manager.js +15 -47
- package/dist/src/file-manager.js.map +1 -1
- package/dist/src/git-manager.d.ts.map +1 -1
- package/dist/src/git-manager.js +8 -1
- package/dist/src/git-manager.js.map +1 -1
- package/dist/src/types.d.ts +20 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/workflow/steps/plan.d.ts.map +1 -1
- package/dist/src/workflow/steps/plan.js +26 -18
- package/dist/src/workflow/steps/plan.js.map +1 -1
- package/dist/src/workflow/steps/research.d.ts.map +1 -1
- package/dist/src/workflow/steps/research.js +100 -66
- package/dist/src/workflow/steps/research.js.map +1 -1
- package/dist/src/workflow/types.d.ts +0 -2
- package/dist/src/workflow/types.d.ts.map +1 -1
- package/dist/templates/plan-template.md +1 -5
- package/package.json +2 -6
- package/src/agent.ts +7 -31
- package/src/agents/research.ts +84 -53
- package/src/file-manager.ts +18 -73
- package/src/git-manager.ts +7 -1
- package/src/templates/plan-template.md +1 -5
- package/src/types.ts +24 -1
- package/src/workflow/steps/plan.ts +28 -21
- package/src/workflow/steps/research.ts +109 -74
- package/src/workflow/types.ts +0 -2
- package/dist/_virtual/_commonjsHelpers.js +0 -6
- package/dist/_virtual/_commonjsHelpers.js.map +0 -1
- package/dist/_virtual/index.js +0 -4
- package/dist/_virtual/index.js.map +0 -1
- package/dist/node_modules/@ai-sdk/anthropic/dist/index.js +0 -1154
- package/dist/node_modules/@ai-sdk/anthropic/dist/index.js.map +0 -1
- package/dist/node_modules/@ai-sdk/provider/dist/index.js +0 -296
- package/dist/node_modules/@ai-sdk/provider/dist/index.js.map +0 -1
- package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js +0 -576
- package/dist/node_modules/@ai-sdk/provider-utils/dist/index.js.map +0 -1
- package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js +0 -741
- package/dist/node_modules/@ai-sdk/ui-utils/dist/index.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js +0 -112
- package/dist/node_modules/@opentelemetry/api/build/esm/api/context.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js +0 -123
- package/dist/node_modules/@opentelemetry/api/build/esm/api/diag.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js +0 -62
- package/dist/node_modules/@opentelemetry/api/build/esm/api/metrics.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js +0 -91
- package/dist/node_modules/@opentelemetry/api/build/esm/api/propagation.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js +0 -79
- package/dist/node_modules/@opentelemetry/api/build/esm/api/trace.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js +0 -59
- package/dist/node_modules/@opentelemetry/api/build/esm/baggage/context-helpers.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js +0 -99
- package/dist/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js +0 -31
- package/dist/node_modules/@opentelemetry/api/build/esm/baggage/utils.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js +0 -69
- package/dist/node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js +0 -54
- package/dist/node_modules/@opentelemetry/api/build/esm/context/context.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js +0 -22
- package/dist/node_modules/@opentelemetry/api/build/esm/context-api.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js +0 -104
- package/dist/node_modules/@opentelemetry/api/build/esm/diag/ComponentLogger.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js +0 -44
- package/dist/node_modules/@opentelemetry/api/build/esm/diag/internal/logLevelLogger.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js +0 -43
- package/dist/node_modules/@opentelemetry/api/build/esm/diag/types.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js +0 -27
- package/dist/node_modules/@opentelemetry/api/build/esm/diag-api.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js +0 -62
- package/dist/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js +0 -121
- package/dist/node_modules/@opentelemetry/api/build/esm/internal/semver.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js +0 -167
- package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeter.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js +0 -33
- package/dist/node_modules/@opentelemetry/api/build/esm/metrics/NoopMeterProvider.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js +0 -22
- package/dist/node_modules/@opentelemetry/api/build/esm/metrics-api.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js +0 -21
- package/dist/node_modules/@opentelemetry/api/build/esm/platform/node/globalThis.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js +0 -35
- package/dist/node_modules/@opentelemetry/api/build/esm/propagation/NoopTextMapPropagator.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js +0 -40
- package/dist/node_modules/@opentelemetry/api/build/esm/propagation/TextMapPropagator.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js +0 -22
- package/dist/node_modules/@opentelemetry/api/build/esm/propagation-api.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js +0 -70
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/NonRecordingSpan.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js +0 -78
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracer.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js +0 -34
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/NoopTracerProvider.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js +0 -55
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracer.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js +0 -56
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/ProxyTracerProvider.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js +0 -76
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/context-utils.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js +0 -27
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/invalid-span-constants.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js +0 -45
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/spancontext-utils.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js +0 -22
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/status.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js +0 -25
- package/dist/node_modules/@opentelemetry/api/build/esm/trace/trace_flags.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js +0 -24
- package/dist/node_modules/@opentelemetry/api/build/esm/trace-api.js.map +0 -1
- package/dist/node_modules/@opentelemetry/api/build/esm/version.js +0 -20
- package/dist/node_modules/@opentelemetry/api/build/esm/version.js.map +0 -1
- package/dist/node_modules/ai/dist/index.js +0 -2870
- package/dist/node_modules/ai/dist/index.js.map +0 -1
- package/dist/node_modules/nanoid/non-secure/index.js +0 -13
- package/dist/node_modules/nanoid/non-secure/index.js.map +0 -1
- package/dist/node_modules/secure-json-parse/index.js +0 -133
- package/dist/node_modules/secure-json-parse/index.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js +0 -37
- package/dist/node_modules/zod-to-json-schema/dist/esm/Options.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js +0 -26
- package/dist/node_modules/zod-to-json-schema/dist/esm/Refs.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js +0 -17
- package/dist/node_modules/zod-to-json-schema/dist/esm/errorMessages.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js +0 -11
- package/dist/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/index.js +0 -8
- package/dist/node_modules/zod-to-json-schema/dist/esm/index.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js +0 -66
- package/dist/node_modules/zod-to-json-schema/dist/esm/parseDef.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js +0 -21
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/any.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js +0 -30
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/array.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js +0 -53
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/bigint.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js +0 -8
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/boolean.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js +0 -8
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/branded.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js +0 -8
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js +0 -50
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/date.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js +0 -11
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/default.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js +0 -11
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/effects.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js +0 -9
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/enum.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js +0 -56
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js +0 -24
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/literal.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js +0 -30
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/map.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js +0 -19
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js +0 -15
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/never.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js +0 -13
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/null.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js +0 -37
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/nullable.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js +0 -56
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/number.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js +0 -76
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/object.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js +0 -25
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js +0 -24
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js +0 -8
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/promise.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js +0 -8
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js +0 -65
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/record.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js +0 -24
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/set.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js +0 -350
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/string.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js +0 -36
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/tuple.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js +0 -10
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/undefined.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js +0 -84
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/union.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js +0 -8
- package/dist/node_modules/zod-to-json-schema/dist/esm/parsers/unknown.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js +0 -110
- package/dist/node_modules/zod-to-json-schema/dist/esm/selectParser.js.map +0 -1
- package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js +0 -90
- package/dist/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js.map +0 -1
- package/dist/src/structured-extraction.d.ts +0 -28
- package/dist/src/structured-extraction.d.ts.map +0 -1
- package/dist/src/structured-extraction.js +0 -77
- package/dist/src/structured-extraction.js.map +0 -1
- package/dist/src/utils/ai-sdk.d.ts +0 -14
- package/dist/src/utils/ai-sdk.d.ts.map +0 -1
- package/dist/src/utils/ai-sdk.js +0 -38
- package/dist/src/utils/ai-sdk.js.map +0 -1
- package/src/structured-extraction.ts +0 -117
- package/src/utils/ai-sdk.ts +0 -47
|
@@ -3,11 +3,29 @@ import { RESEARCH_SYSTEM_PROMPT } from '../../agents/research.js';
|
|
|
3
3
|
import { finalizeStepGitActions } from '../utils.js';
|
|
4
4
|
|
|
5
5
|
const researchStep = async ({ step, context }) => {
|
|
6
|
-
const { task, cwd, isCloudMode, options, logger, fileManager, gitManager, promptBuilder, adapter, mcpServers,
|
|
6
|
+
const { task, cwd, isCloudMode, options, logger, fileManager, gitManager, promptBuilder, adapter, mcpServers, emitEvent, } = context;
|
|
7
7
|
const stepLogger = logger.child('ResearchStep');
|
|
8
8
|
const existingResearch = await fileManager.readResearch(task.id);
|
|
9
9
|
if (existingResearch) {
|
|
10
|
-
stepLogger.info('Research already exists
|
|
10
|
+
stepLogger.info('Research already exists', { taskId: task.id, hasQuestions: !!existingResearch.questions, answered: existingResearch.answered });
|
|
11
|
+
// If there are unanswered questions, re-emit them so UI can prompt user
|
|
12
|
+
if (existingResearch.questions && !existingResearch.answered) {
|
|
13
|
+
stepLogger.info('Re-emitting unanswered research questions', {
|
|
14
|
+
taskId: task.id,
|
|
15
|
+
questionCount: existingResearch.questions.length
|
|
16
|
+
});
|
|
17
|
+
emitEvent({
|
|
18
|
+
type: 'artifact',
|
|
19
|
+
ts: Date.now(),
|
|
20
|
+
kind: 'research_questions',
|
|
21
|
+
content: existingResearch.questions,
|
|
22
|
+
});
|
|
23
|
+
// In local mode, halt to allow user to answer
|
|
24
|
+
if (!isCloudMode) {
|
|
25
|
+
emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
|
|
26
|
+
return { status: 'skipped', halt: true };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
11
29
|
return { status: 'skipped' };
|
|
12
30
|
}
|
|
13
31
|
stepLogger.info('Starting research phase', { taskId: task.id });
|
|
@@ -37,7 +55,7 @@ const researchStep = async ({ step, context }) => {
|
|
|
37
55
|
prompt: fullPrompt,
|
|
38
56
|
options: { ...baseOptions, ...(options.queryOverrides || {}) },
|
|
39
57
|
});
|
|
40
|
-
let
|
|
58
|
+
let jsonContent = '';
|
|
41
59
|
for await (const message of response) {
|
|
42
60
|
emitEvent(adapter.createRawSDKEvent(message));
|
|
43
61
|
const transformed = adapter.transform(message);
|
|
@@ -47,87 +65,103 @@ const researchStep = async ({ step, context }) => {
|
|
|
47
65
|
if (message.type === 'assistant' && message.message?.content) {
|
|
48
66
|
for (const c of message.message.content) {
|
|
49
67
|
if (c.type === 'text' && c.text) {
|
|
50
|
-
|
|
68
|
+
jsonContent += c.text;
|
|
51
69
|
}
|
|
52
70
|
}
|
|
53
71
|
}
|
|
54
72
|
}
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
73
|
+
if (!jsonContent.trim()) {
|
|
74
|
+
stepLogger.error('No JSON output from research agent', { taskId: task.id });
|
|
75
|
+
emitEvent({
|
|
76
|
+
type: 'error',
|
|
77
|
+
ts: Date.now(),
|
|
78
|
+
message: 'Research agent returned no output',
|
|
79
|
+
});
|
|
80
|
+
return { status: 'completed', halt: true };
|
|
81
|
+
}
|
|
82
|
+
// Parse JSON response
|
|
83
|
+
let evaluation;
|
|
84
|
+
try {
|
|
85
|
+
// Extract JSON from potential markdown code blocks or other wrapping
|
|
86
|
+
const jsonMatch = jsonContent.match(/\{[\s\S]*\}/);
|
|
87
|
+
if (!jsonMatch) {
|
|
88
|
+
throw new Error('No JSON object found in response');
|
|
89
|
+
}
|
|
90
|
+
evaluation = JSON.parse(jsonMatch[0]);
|
|
91
|
+
stepLogger.info('Parsed research evaluation', {
|
|
92
|
+
taskId: task.id,
|
|
93
|
+
score: evaluation.actionabilityScore,
|
|
94
|
+
hasQuestions: !!evaluation.questions,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
stepLogger.error('Failed to parse research JSON', {
|
|
99
|
+
taskId: task.id,
|
|
100
|
+
error: error instanceof Error ? error.message : String(error),
|
|
101
|
+
content: jsonContent.substring(0, 500),
|
|
102
|
+
});
|
|
103
|
+
emitEvent({
|
|
104
|
+
type: 'error',
|
|
105
|
+
ts: Date.now(),
|
|
106
|
+
message: `Failed to parse research JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
107
|
+
});
|
|
108
|
+
return { status: 'completed', halt: true };
|
|
109
|
+
}
|
|
110
|
+
// Add answered/answers fields to evaluation
|
|
111
|
+
if (evaluation.questions && evaluation.questions.length > 0) {
|
|
112
|
+
evaluation.answered = false;
|
|
113
|
+
evaluation.answers = undefined;
|
|
58
114
|
}
|
|
115
|
+
// Always write research.json
|
|
116
|
+
await fileManager.writeResearch(task.id, evaluation);
|
|
117
|
+
stepLogger.info('Research evaluation written', {
|
|
118
|
+
taskId: task.id,
|
|
119
|
+
score: evaluation.actionabilityScore,
|
|
120
|
+
hasQuestions: !!evaluation.questions,
|
|
121
|
+
});
|
|
122
|
+
emitEvent({
|
|
123
|
+
type: 'artifact',
|
|
124
|
+
ts: Date.now(),
|
|
125
|
+
kind: 'research_evaluation',
|
|
126
|
+
content: evaluation,
|
|
127
|
+
});
|
|
59
128
|
await gitManager.addAllPostHogFiles();
|
|
60
129
|
await finalizeStepGitActions(context, step, {
|
|
61
130
|
commitMessage: `Research phase for ${task.title}`,
|
|
62
131
|
});
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
answers: null,
|
|
71
|
-
});
|
|
72
|
-
emitEvent({
|
|
73
|
-
type: 'artifact',
|
|
74
|
-
ts: Date.now(),
|
|
75
|
-
kind: 'research_questions',
|
|
76
|
-
content: parsedQuestions,
|
|
77
|
-
});
|
|
78
|
-
stepLogger.info('Questions extracted successfully', {
|
|
79
|
-
taskId: task.id,
|
|
80
|
-
count: parsedQuestions.length,
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
catch (error) {
|
|
84
|
-
stepLogger.error('Failed to extract questions', {
|
|
85
|
-
taskId: task.id,
|
|
86
|
-
error: error instanceof Error ? error.message : String(error),
|
|
87
|
-
});
|
|
88
|
-
emitEvent({
|
|
89
|
-
type: 'error',
|
|
90
|
-
ts: Date.now(),
|
|
91
|
-
message: `Failed to extract questions: ${error instanceof Error ? error.message : String(error)}`,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
else if (!extractor) {
|
|
96
|
-
stepLogger.warn('Question extractor not available, skipping question extraction. Ensure LLM gateway is configured.');
|
|
132
|
+
// Log whether questions need answering
|
|
133
|
+
if (evaluation.actionabilityScore < 0.7 && evaluation.questions && evaluation.questions.length > 0) {
|
|
134
|
+
stepLogger.info('Actionability score below threshold, questions needed', {
|
|
135
|
+
taskId: task.id,
|
|
136
|
+
score: evaluation.actionabilityScore,
|
|
137
|
+
questionCount: evaluation.questions.length,
|
|
138
|
+
});
|
|
97
139
|
emitEvent({
|
|
98
|
-
type: '
|
|
140
|
+
type: 'artifact',
|
|
99
141
|
ts: Date.now(),
|
|
100
|
-
|
|
101
|
-
|
|
142
|
+
kind: 'research_questions',
|
|
143
|
+
content: evaluation.questions,
|
|
102
144
|
});
|
|
103
145
|
}
|
|
146
|
+
else {
|
|
147
|
+
stepLogger.info('Actionability score acceptable, proceeding to planning', {
|
|
148
|
+
taskId: task.id,
|
|
149
|
+
score: evaluation.actionabilityScore,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
// In local mode, always halt after research for user review
|
|
104
153
|
if (!isCloudMode) {
|
|
105
154
|
emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
|
|
106
155
|
return { status: 'completed', halt: true };
|
|
107
156
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
customInput: qa.justification,
|
|
115
|
-
}));
|
|
116
|
-
await fileManager.writeQuestions(task.id, {
|
|
117
|
-
questions: researchQuestions.map((qa) => ({
|
|
118
|
-
id: qa.id,
|
|
119
|
-
question: qa.question,
|
|
120
|
-
options: qa.options,
|
|
121
|
-
})),
|
|
122
|
-
answered: true,
|
|
123
|
-
answers,
|
|
124
|
-
});
|
|
125
|
-
await gitManager.addAllPostHogFiles();
|
|
126
|
-
await finalizeStepGitActions(context, step, {
|
|
127
|
-
commitMessage: `Answer research questions for ${task.title}`,
|
|
128
|
-
});
|
|
129
|
-
stepLogger.info('Auto-answered research questions', { taskId: task.id });
|
|
157
|
+
// In cloud mode, check if questions need answering
|
|
158
|
+
const researchData = await fileManager.readResearch(task.id);
|
|
159
|
+
if (researchData?.questions && !researchData.answered) {
|
|
160
|
+
// Questions need answering - halt for user input in cloud mode too
|
|
161
|
+
emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
|
|
162
|
+
return { status: 'completed', halt: true };
|
|
130
163
|
}
|
|
164
|
+
// No questions or questions already answered - proceed to planning
|
|
131
165
|
emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
|
|
132
166
|
return { status: 'completed' };
|
|
133
167
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"research.js","sources":["../../../../src/workflow/steps/research.ts"],"sourcesContent":["import { query } from '@anthropic-ai/claude-agent-sdk';\nimport { RESEARCH_SYSTEM_PROMPT } from '../../agents/research.js';\nimport type { ExtractedQuestionWithAnswer } from '../../structured-extraction.js';\nimport type { WorkflowStepRunner } from '../types.js';\nimport { finalizeStepGitActions } from '../utils.js';\n\nexport const researchStep: WorkflowStepRunner = async ({ step, context }) => {\n const {\n task,\n cwd,\n isCloudMode,\n options,\n logger,\n fileManager,\n gitManager,\n promptBuilder,\n adapter,\n mcpServers,\n extractor,\n emitEvent,\n } = context;\n\n const stepLogger = logger.child('ResearchStep');\n\n const existingResearch = await fileManager.readResearch(task.id);\n if (existingResearch) {\n stepLogger.info('Research already exists, skipping step', { taskId: task.id });\n return { status: 'skipped' };\n }\n\n stepLogger.info('Starting research phase', { taskId: task.id });\n emitEvent(adapter.createStatusEvent('phase_start', { phase: 'research' }));\n\n const researchPrompt = await promptBuilder.buildResearchPrompt(task, cwd);\n const fullPrompt = `${RESEARCH_SYSTEM_PROMPT}\\n\\n${researchPrompt}`;\n\n const baseOptions: Record<string, any> = {\n model: step.model,\n cwd,\n permissionMode: 'plan',\n settingSources: ['local'],\n mcpServers,\n // Allow research tools: read-only operations, web search, and MCP resources\n allowedTools: [\n 'Read',\n 'Glob',\n 'Grep',\n 'WebFetch',\n 'WebSearch',\n 'ListMcpResources',\n 'ReadMcpResource',\n 'TodoWrite',\n 'BashOutput',\n ],\n };\n\n const response = query({\n prompt: fullPrompt,\n options: { ...baseOptions, ...(options.queryOverrides || {}) },\n });\n\n let researchContent = '';\n for await (const message of response) {\n emitEvent(adapter.createRawSDKEvent(message));\n const transformed = adapter.transform(message);\n if (transformed) {\n emitEvent(transformed);\n }\n if (message.type === 'assistant' && message.message?.content) {\n for (const c of message.message.content) {\n if (c.type === 'text' && c.text) {\n researchContent += `${c.text}\\n`;\n }\n }\n }\n }\n\n if (researchContent.trim()) {\n await fileManager.writeResearch(task.id, researchContent.trim());\n stepLogger.info('Research completed', { taskId: task.id });\n }\n\n await gitManager.addAllPostHogFiles();\n await finalizeStepGitActions(context, step, {\n commitMessage: `Research phase for ${task.title}`,\n });\n\n if (extractor && researchContent.trim()) {\n try {\n stepLogger.info('Extracting questions from research.md', { taskId: task.id });\n const parsedQuestions = await extractor.extractQuestions(researchContent);\n\n await fileManager.writeQuestions(task.id, {\n questions: parsedQuestions,\n answered: false,\n answers: null,\n });\n\n emitEvent({\n type: 'artifact',\n ts: Date.now(),\n kind: 'research_questions',\n content: parsedQuestions,\n });\n\n stepLogger.info('Questions extracted successfully', {\n taskId: task.id,\n count: parsedQuestions.length,\n });\n } catch (error) {\n stepLogger.error('Failed to extract questions', {\n taskId: task.id,\n error: error instanceof Error ? error.message : String(error),\n });\n emitEvent({\n type: 'error',\n ts: Date.now(),\n message: `Failed to extract questions: ${\n error instanceof Error ? error.message : String(error)\n }`,\n });\n }\n } else if (!extractor) {\n stepLogger.warn(\n 'Question extractor not available, skipping question extraction. Ensure LLM gateway is configured.'\n );\n emitEvent({\n type: 'status',\n ts: Date.now(),\n phase: 'extraction_skipped',\n message: 'Question extraction skipped - extractor not configured',\n });\n }\n\n if (!isCloudMode) {\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'completed', halt: true };\n }\n\n const questionsData = await fileManager.readQuestions(task.id);\n if (questionsData && !questionsData.answered && extractor && researchContent.trim()) {\n const researchQuestions = await extractor.extractQuestionsWithAnswers(researchContent);\n const answers = (researchQuestions as ExtractedQuestionWithAnswer[]).map((qa) => ({\n questionId: qa.id,\n selectedOption: qa.recommendedAnswer,\n customInput: qa.justification,\n }));\n\n await fileManager.writeQuestions(task.id, {\n questions: researchQuestions.map((qa) => ({\n id: qa.id,\n question: qa.question,\n options: qa.options,\n })),\n answered: true,\n answers,\n });\n\n await gitManager.addAllPostHogFiles();\n await finalizeStepGitActions(context, step, {\n commitMessage: `Answer research questions for ${task.title}`,\n });\n stepLogger.info('Auto-answered research questions', { taskId: task.id });\n }\n\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'completed' };\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"research.js","sources":["../../../../src/workflow/steps/research.ts"],"sourcesContent":["import { query } from '@anthropic-ai/claude-agent-sdk';\nimport { RESEARCH_SYSTEM_PROMPT } from '../../agents/research.js';\nimport type { WorkflowStepRunner } from '../types.js';\nimport type { ResearchEvaluation } from '../../types.js';\nimport { finalizeStepGitActions } from '../utils.js';\n\nexport const researchStep: WorkflowStepRunner = async ({ step, context }) => {\n const {\n task,\n cwd,\n isCloudMode,\n options,\n logger,\n fileManager,\n gitManager,\n promptBuilder,\n adapter,\n mcpServers,\n emitEvent,\n } = context;\n\n const stepLogger = logger.child('ResearchStep');\n\n const existingResearch = await fileManager.readResearch(task.id);\n if (existingResearch) {\n stepLogger.info('Research already exists', { taskId: task.id, hasQuestions: !!existingResearch.questions, answered: existingResearch.answered });\n \n // If there are unanswered questions, re-emit them so UI can prompt user\n if (existingResearch.questions && !existingResearch.answered) {\n stepLogger.info('Re-emitting unanswered research questions', { \n taskId: task.id,\n questionCount: existingResearch.questions.length \n });\n \n emitEvent({\n type: 'artifact',\n ts: Date.now(),\n kind: 'research_questions',\n content: existingResearch.questions,\n });\n \n // In local mode, halt to allow user to answer\n if (!isCloudMode) {\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'skipped', halt: true };\n }\n }\n \n return { status: 'skipped' };\n }\n\n stepLogger.info('Starting research phase', { taskId: task.id });\n emitEvent(adapter.createStatusEvent('phase_start', { phase: 'research' }));\n\n const researchPrompt = await promptBuilder.buildResearchPrompt(task, cwd);\n const fullPrompt = `${RESEARCH_SYSTEM_PROMPT}\\n\\n${researchPrompt}`;\n\n const baseOptions: Record<string, any> = {\n model: step.model,\n cwd,\n permissionMode: 'plan',\n settingSources: ['local'],\n mcpServers,\n // Allow research tools: read-only operations, web search, and MCP resources\n allowedTools: [\n 'Read',\n 'Glob',\n 'Grep',\n 'WebFetch',\n 'WebSearch',\n 'ListMcpResources',\n 'ReadMcpResource',\n 'TodoWrite',\n 'BashOutput',\n ],\n };\n\n const response = query({\n prompt: fullPrompt,\n options: { ...baseOptions, ...(options.queryOverrides || {}) },\n });\n\n let jsonContent = '';\n for await (const message of response) {\n emitEvent(adapter.createRawSDKEvent(message));\n const transformed = adapter.transform(message);\n if (transformed) {\n emitEvent(transformed);\n }\n if (message.type === 'assistant' && message.message?.content) {\n for (const c of message.message.content) {\n if (c.type === 'text' && c.text) {\n jsonContent += c.text;\n }\n }\n }\n }\n\n if (!jsonContent.trim()) {\n stepLogger.error('No JSON output from research agent', { taskId: task.id });\n emitEvent({\n type: 'error',\n ts: Date.now(),\n message: 'Research agent returned no output',\n });\n return { status: 'completed', halt: true };\n }\n\n // Parse JSON response\n let evaluation: ResearchEvaluation;\n try {\n // Extract JSON from potential markdown code blocks or other wrapping\n const jsonMatch = jsonContent.match(/\\{[\\s\\S]*\\}/);\n if (!jsonMatch) {\n throw new Error('No JSON object found in response');\n }\n evaluation = JSON.parse(jsonMatch[0]);\n stepLogger.info('Parsed research evaluation', {\n taskId: task.id,\n score: evaluation.actionabilityScore,\n hasQuestions: !!evaluation.questions,\n });\n } catch (error) {\n stepLogger.error('Failed to parse research JSON', {\n taskId: task.id,\n error: error instanceof Error ? error.message : String(error),\n content: jsonContent.substring(0, 500),\n });\n emitEvent({\n type: 'error',\n ts: Date.now(),\n message: `Failed to parse research JSON: ${\n error instanceof Error ? error.message : String(error)\n }`,\n });\n return { status: 'completed', halt: true };\n }\n\n // Add answered/answers fields to evaluation\n if (evaluation.questions && evaluation.questions.length > 0) {\n evaluation.answered = false;\n evaluation.answers = undefined;\n }\n\n // Always write research.json\n await fileManager.writeResearch(task.id, evaluation);\n stepLogger.info('Research evaluation written', {\n taskId: task.id,\n score: evaluation.actionabilityScore,\n hasQuestions: !!evaluation.questions,\n });\n\n emitEvent({\n type: 'artifact',\n ts: Date.now(),\n kind: 'research_evaluation',\n content: evaluation,\n });\n\n await gitManager.addAllPostHogFiles();\n await finalizeStepGitActions(context, step, {\n commitMessage: `Research phase for ${task.title}`,\n });\n\n // Log whether questions need answering\n if (evaluation.actionabilityScore < 0.7 && evaluation.questions && evaluation.questions.length > 0) {\n stepLogger.info('Actionability score below threshold, questions needed', {\n taskId: task.id,\n score: evaluation.actionabilityScore,\n questionCount: evaluation.questions.length,\n });\n \n emitEvent({\n type: 'artifact',\n ts: Date.now(),\n kind: 'research_questions',\n content: evaluation.questions,\n });\n } else {\n stepLogger.info('Actionability score acceptable, proceeding to planning', {\n taskId: task.id,\n score: evaluation.actionabilityScore,\n });\n }\n\n // In local mode, always halt after research for user review\n if (!isCloudMode) {\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'completed', halt: true };\n }\n\n // In cloud mode, check if questions need answering\n const researchData = await fileManager.readResearch(task.id);\n if (researchData?.questions && !researchData.answered) {\n // Questions need answering - halt for user input in cloud mode too\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'completed', halt: true };\n }\n\n // No questions or questions already answered - proceed to planning\n emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));\n return { status: 'completed' };\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,6 @@ import type { PromptBuilder } from '../prompt-builder.js';
|
|
|
6
6
|
import type { TaskProgressReporter } from '../task-progress-reporter.js';
|
|
7
7
|
import type { ProviderAdapter } from '../adapters/types.js';
|
|
8
8
|
import type { PostHogAPIClient } from '../posthog-api.js';
|
|
9
|
-
import type { StructuredExtractor } from '../structured-extraction.js';
|
|
10
9
|
export interface WorkflowRuntime {
|
|
11
10
|
task: Task;
|
|
12
11
|
taskSlug: string;
|
|
@@ -21,7 +20,6 @@ export interface WorkflowRuntime {
|
|
|
21
20
|
adapter: ProviderAdapter;
|
|
22
21
|
mcpServers?: Record<string, any>;
|
|
23
22
|
posthogAPI?: PostHogAPIClient;
|
|
24
|
-
extractor?: StructuredExtractor;
|
|
25
23
|
emitEvent: (event: any) => void;
|
|
26
24
|
stepResults: Record<string, any>;
|
|
27
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/workflow/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/workflow/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,kBAAkB,CAAC;IAChC,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,EAAE,oBAAoB,CAAC;IACvC,OAAO,EAAE,eAAe,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,SAAS,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,sBAAsB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,cAAc,GAAG,MAAM,CAAC;IACzC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,kBAAkB,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,OAAO,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAE/F,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posthog/agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.0",
|
|
4
4
|
"description": "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -49,12 +49,8 @@
|
|
|
49
49
|
"typescript": "^5.5.0"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@ai-sdk/anthropic": "^1.0.6",
|
|
53
|
-
"@ai-sdk/openai": "^1.0.10",
|
|
54
52
|
"@anthropic-ai/claude-agent-sdk": "^0.1.1",
|
|
55
|
-
"
|
|
56
|
-
"dotenv": "^17.2.3",
|
|
57
|
-
"zod": "^3.24.1"
|
|
53
|
+
"dotenv": "^17.2.3"
|
|
58
54
|
},
|
|
59
55
|
"files": [
|
|
60
56
|
"dist/**/*",
|
package/src/agent.ts
CHANGED
|
@@ -10,7 +10,6 @@ import type { ProviderAdapter } from './adapters/types.js';
|
|
|
10
10
|
import { Logger } from './utils/logger.js';
|
|
11
11
|
import { PromptBuilder } from './prompt-builder.js';
|
|
12
12
|
import { TaskProgressReporter } from './task-progress-reporter.js';
|
|
13
|
-
import { AISDKExtractor, type StructuredExtractor, type ExtractedQuestion, type ExtractedQuestionWithAnswer } from './structured-extraction.js';
|
|
14
13
|
import { TASK_WORKFLOW } from './workflow/config.js';
|
|
15
14
|
import type { WorkflowRuntime } from './workflow/types.js';
|
|
16
15
|
|
|
@@ -26,7 +25,6 @@ export class Agent {
|
|
|
26
25
|
private logger: Logger;
|
|
27
26
|
private progressReporter: TaskProgressReporter;
|
|
28
27
|
private promptBuilder: PromptBuilder;
|
|
29
|
-
private extractor?: StructuredExtractor;
|
|
30
28
|
private mcpServers?: Record<string, any>;
|
|
31
29
|
private canUseTool?: CanUseTool;
|
|
32
30
|
public debug: boolean;
|
|
@@ -92,7 +90,6 @@ export class Agent {
|
|
|
92
90
|
logger: this.logger.child('PromptBuilder')
|
|
93
91
|
});
|
|
94
92
|
this.progressReporter = new TaskProgressReporter(this.posthogAPI, this.logger);
|
|
95
|
-
this.extractor = new AISDKExtractor({apiKey: config.posthogApiKey, gatewayUrl: this.posthogAPI?.getLlmGatewayUrl() ?? '', logger: this.logger.child('AISDKExtractor')});
|
|
96
93
|
}
|
|
97
94
|
|
|
98
95
|
/**
|
|
@@ -159,7 +156,6 @@ export class Agent {
|
|
|
159
156
|
adapter: this.adapter,
|
|
160
157
|
mcpServers: this.mcpServers,
|
|
161
158
|
posthogAPI: this.posthogAPI,
|
|
162
|
-
extractor: this.extractor,
|
|
163
159
|
emitEvent: (event: any) => this.emitEvent(event),
|
|
164
160
|
stepResults: {},
|
|
165
161
|
};
|
|
@@ -283,32 +279,11 @@ export class Agent {
|
|
|
283
279
|
return await this.fileManager.readPlan(taskId);
|
|
284
280
|
}
|
|
285
281
|
|
|
286
|
-
async extractQuestionsFromResearch(taskId: string, includeAnswers: boolean = false): Promise<ExtractedQuestion[] | ExtractedQuestionWithAnswer[]> {
|
|
287
|
-
this.logger.info('Extracting questions from research.md', { taskId, includeAnswers });
|
|
288
|
-
|
|
289
|
-
if (!this.extractor) {
|
|
290
|
-
throw new Error('OpenAI extractor not initialized. Ensure the LLM gateway is configured.');
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const researchContent = await this.fileManager.readResearch(taskId);
|
|
294
|
-
if (!researchContent) {
|
|
295
|
-
throw new Error('research.md not found for task ' + taskId);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (includeAnswers) {
|
|
299
|
-
return await this.extractor.extractQuestionsWithAnswers(researchContent);
|
|
300
|
-
} else {
|
|
301
|
-
return await this.extractor.extractQuestions(researchContent);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
282
|
// Git operations for task execution
|
|
306
283
|
async createPlanningBranch(taskId: string): Promise<string> {
|
|
307
284
|
this.logger.info('Creating planning branch', { taskId });
|
|
308
285
|
const branchName = await this.gitManager.createTaskPlanningBranch(taskId);
|
|
309
286
|
this.logger.debug('Planning branch created', { taskId, branchName });
|
|
310
|
-
// Only create gitignore after we're on the new branch
|
|
311
|
-
await this.fileManager.ensureGitignore();
|
|
312
287
|
return branchName;
|
|
313
288
|
}
|
|
314
289
|
|
|
@@ -422,12 +397,17 @@ Generated by PostHog Agent`;
|
|
|
422
397
|
const branchName = await this.gitManager.createTaskBranch(taskSlug);
|
|
423
398
|
this.emitEvent(this.adapter.createStatusEvent('branch_created', { branch: branchName }));
|
|
424
399
|
|
|
425
|
-
await this.fileManager.ensureGitignore();
|
|
426
400
|
await this.gitManager.addAllPostHogFiles();
|
|
401
|
+
|
|
402
|
+
// Only commit if there are changes or we're in cloud mode
|
|
427
403
|
if (isCloudMode) {
|
|
428
404
|
await this.gitManager.commitAndPush(`Initialize task ${taskSlug}`, { allowEmpty: true });
|
|
429
405
|
} else {
|
|
430
|
-
|
|
406
|
+
// Check if there are any changes before committing
|
|
407
|
+
const hasChanges = await this.gitManager.hasStagedChanges();
|
|
408
|
+
if (hasChanges) {
|
|
409
|
+
await this.gitManager.commitChanges(`Initialize task ${taskSlug}`);
|
|
410
|
+
}
|
|
431
411
|
}
|
|
432
412
|
} else {
|
|
433
413
|
this.logger.info('Switching to existing task branch', { branch: existingBranch });
|
|
@@ -446,10 +426,6 @@ Generated by PostHog Agent`;
|
|
|
446
426
|
if (resolvedToken) {
|
|
447
427
|
process.env.OPENAI_API_KEY = resolvedToken;
|
|
448
428
|
}
|
|
449
|
-
|
|
450
|
-
if (!this.extractor) {
|
|
451
|
-
this.extractor = new AISDKExtractor({apiKey: resolvedToken || '', gatewayUrl: resolvedGatewayUrl || '', logger: this.logger.child('AISDKExtractor')});
|
|
452
|
-
}
|
|
453
429
|
}
|
|
454
430
|
|
|
455
431
|
private async ensurePullRequest(task: Task, stepResults: Record<string, any>): Promise<void> {
|
package/src/agents/research.ts
CHANGED
|
@@ -1,80 +1,111 @@
|
|
|
1
1
|
export const RESEARCH_SYSTEM_PROMPT = `<role>
|
|
2
|
-
PostHog AI Research Agent — analyze codebases to
|
|
2
|
+
PostHog AI Research Agent — analyze codebases to evaluate task actionability and identify missing information.
|
|
3
3
|
</role>
|
|
4
4
|
|
|
5
5
|
<constraints>
|
|
6
6
|
- Read-only: analyze files, search code, explore structure
|
|
7
7
|
- No modifications or code changes
|
|
8
|
+
- Output structured JSON only
|
|
8
9
|
</constraints>
|
|
9
10
|
|
|
10
11
|
<objective>
|
|
11
|
-
Your PRIMARY goal is to
|
|
12
|
+
Your PRIMARY goal is to evaluate whether a task is actionable and assign an actionability score.
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
14
|
+
Calculate an actionabilityScore (0-1) based on:
|
|
15
|
+
- **Task clarity** (0.4 weight): Is the task description specific and unambiguous?
|
|
16
|
+
- **Codebase context** (0.3 weight): Can you locate the relevant code and patterns?
|
|
17
|
+
- **Architectural decisions** (0.2 weight): Are the implementation approaches clear?
|
|
18
|
+
- **Dependencies** (0.1 weight): Are required dependencies and constraints understood?
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
If actionabilityScore < 0.7, generate specific clarifying questions to increase confidence.
|
|
21
|
+
|
|
22
|
+
DO NOT ask questions like "how should I fix this" — focus on missing information that prevents confident planning.
|
|
19
23
|
</objective>
|
|
20
24
|
|
|
21
25
|
<process>
|
|
22
26
|
1. Explore repository structure and identify relevant files/components
|
|
23
27
|
2. Understand existing patterns, conventions, and dependencies
|
|
24
|
-
3.
|
|
25
|
-
4. Identify
|
|
26
|
-
5.
|
|
27
|
-
6.
|
|
28
|
+
3. Calculate actionabilityScore based on clarity, context, architecture, and dependencies
|
|
29
|
+
4. Identify key files that will need modification
|
|
30
|
+
5. If score < 0.7: generate 2-4 specific questions to resolve blockers
|
|
31
|
+
6. Output JSON matching ResearchEvaluation schema
|
|
28
32
|
</process>
|
|
29
33
|
|
|
30
34
|
<output_format>
|
|
31
|
-
Output ONLY
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
[
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
- Always include "c) Something else (please specify)"
|
|
60
|
-
- Max 4 questions total
|
|
35
|
+
Output ONLY valid JSON with no markdown wrappers, no preamble, no explanation:
|
|
36
|
+
|
|
37
|
+
{
|
|
38
|
+
"actionabilityScore": 0.85,
|
|
39
|
+
"context": "Brief 2-3 sentence summary of the task and implementation approach",
|
|
40
|
+
"keyFiles": ["path/to/file1.ts", "path/to/file2.ts"],
|
|
41
|
+
"blockers": ["Optional: what's preventing full confidence"],
|
|
42
|
+
"questions": [
|
|
43
|
+
{
|
|
44
|
+
"id": "q1",
|
|
45
|
+
"question": "Specific architectural decision needed?",
|
|
46
|
+
"options": [
|
|
47
|
+
"First approach with concrete details",
|
|
48
|
+
"Alternative approach with concrete details",
|
|
49
|
+
"Third option if needed"
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
Rules:
|
|
56
|
+
- actionabilityScore: number between 0 and 1
|
|
57
|
+
- context: concise summary for planning phase
|
|
58
|
+
- keyFiles: array of file paths that need modification
|
|
59
|
+
- blockers: optional array explaining confidence gaps
|
|
60
|
+
- questions: ONLY include if actionabilityScore < 0.7
|
|
61
|
+
- Each question must have 2-3 options (maximum 3)
|
|
62
|
+
- Max 3 questions total
|
|
61
63
|
</output_format>
|
|
62
64
|
|
|
63
|
-
<
|
|
65
|
+
<scoring_examples>
|
|
66
|
+
<example score="0.9">
|
|
67
|
+
Task: "Fix typo in login button text"
|
|
68
|
+
Reasoning: Completely clear task, found exact component, no architectural decisions
|
|
69
|
+
</example>
|
|
70
|
+
|
|
71
|
+
<example score="0.75">
|
|
72
|
+
Task: "Add caching to API endpoints"
|
|
73
|
+
Reasoning: Clear goal, found endpoints, but multiple caching strategies possible
|
|
74
|
+
</example>
|
|
75
|
+
|
|
76
|
+
<example score="0.55">
|
|
77
|
+
Task: "Improve performance"
|
|
78
|
+
Reasoning: Vague task, unclear scope, needs questions about which areas to optimize
|
|
79
|
+
Questions needed: Which features are slow? What metrics define success?
|
|
80
|
+
</example>
|
|
81
|
+
|
|
82
|
+
<example score="0.3">
|
|
83
|
+
Task: "Add the new feature"
|
|
84
|
+
Reasoning: Extremely vague, no context, cannot locate relevant code
|
|
85
|
+
Questions needed: What feature? Which product area? What should it do?
|
|
86
|
+
</example>
|
|
87
|
+
</scoring_examples>
|
|
88
|
+
|
|
89
|
+
<question_examples>
|
|
64
90
|
<good_example>
|
|
65
|
-
|
|
66
|
-
|
|
91
|
+
{
|
|
92
|
+
"id": "q1",
|
|
93
|
+
"question": "Which caching layer should we use for API responses?",
|
|
94
|
+
"options": [
|
|
95
|
+
"Redis (existing infrastructure, requires setup)",
|
|
96
|
+
"In-memory cache (simpler, but not distributed)",
|
|
97
|
+
"Browser-side caching only (minimal backend changes)"
|
|
98
|
+
]
|
|
99
|
+
}
|
|
67
100
|
</good_example>
|
|
68
101
|
|
|
69
102
|
<bad_example>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
103
|
+
{
|
|
104
|
+
"id": "q1",
|
|
105
|
+
"question": "How should I implement this?",
|
|
106
|
+
"options": ["One way", "Another way"]
|
|
107
|
+
}
|
|
108
|
+
Reason: Too vague, doesn't explain the tradeoffs
|
|
73
109
|
</bad_example>
|
|
74
|
-
|
|
75
|
-
<good_example>
|
|
76
|
-
Task: "Add caching to API endpoints"
|
|
77
|
-
Output: Research showing existing cache implementations, question about cache backend choice IF multiple production systems are already in use
|
|
78
|
-
</good_example>
|
|
79
|
-
</examples>`;
|
|
110
|
+
</question_examples>`;
|
|
80
111
|
|