@posthog/agent 1.24.0 → 1.24.2
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/LICENSE +33 -0
- package/dist/index.d.ts +11 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/src/adapters/claude/claude-adapter.d.ts +3 -3
- package/dist/src/adapters/claude/claude-adapter.d.ts.map +1 -1
- package/dist/src/adapters/claude/claude-adapter.js +111 -156
- package/dist/src/adapters/claude/claude-adapter.js.map +1 -1
- package/dist/src/adapters/claude/tool-mapper.d.ts +1 -1
- package/dist/src/adapters/claude/tool-mapper.d.ts.map +1 -1
- package/dist/src/adapters/claude/tool-mapper.js.map +1 -1
- package/dist/src/adapters/types.d.ts +1 -1
- package/dist/src/adapters/types.d.ts.map +1 -1
- package/dist/src/agent.d.ts +7 -7
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +85 -143
- package/dist/src/agent.js.map +1 -1
- package/dist/src/agents/execution.js.map +1 -1
- package/dist/src/agents/planning.js.map +1 -1
- package/dist/src/agents/research.js.map +1 -1
- package/dist/src/file-manager.d.ts +4 -4
- package/dist/src/file-manager.d.ts.map +1 -1
- package/dist/src/file-manager.js +58 -59
- package/dist/src/file-manager.js.map +1 -1
- package/dist/src/git-manager.d.ts +1 -1
- package/dist/src/git-manager.d.ts.map +1 -1
- package/dist/src/git-manager.js +70 -87
- package/dist/src/git-manager.js.map +1 -1
- package/dist/src/posthog-api.d.ts +3 -2
- package/dist/src/posthog-api.d.ts.map +1 -1
- package/dist/src/posthog-api.js +22 -22
- package/dist/src/posthog-api.js.map +1 -1
- package/dist/src/prompt-builder.d.ts +3 -3
- package/dist/src/prompt-builder.d.ts.map +1 -1
- package/dist/src/prompt-builder.js +93 -123
- package/dist/src/prompt-builder.js.map +1 -1
- package/dist/src/task-manager.d.ts +4 -4
- package/dist/src/task-manager.d.ts.map +1 -1
- package/dist/src/task-manager.js +18 -19
- package/dist/src/task-manager.js.map +1 -1
- package/dist/src/task-progress-reporter.d.ts +4 -3
- package/dist/src/task-progress-reporter.d.ts.map +1 -1
- package/dist/src/task-progress-reporter.js +54 -59
- package/dist/src/task-progress-reporter.js.map +1 -1
- package/dist/src/template-manager.d.ts +1 -1
- package/dist/src/template-manager.d.ts.map +1 -1
- package/dist/src/template-manager.js +28 -30
- package/dist/src/template-manager.js.map +1 -1
- package/dist/src/todo-manager.d.ts +3 -3
- package/dist/src/todo-manager.d.ts.map +1 -1
- package/dist/src/todo-manager.js +24 -29
- package/dist/src/todo-manager.js.map +1 -1
- package/dist/src/tools/registry.d.ts +1 -1
- package/dist/src/tools/registry.js +60 -60
- package/dist/src/tools/registry.js.map +1 -1
- package/dist/src/tools/types.d.ts +31 -31
- package/dist/src/types.d.ts +33 -33
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/utils/logger.d.ts +4 -4
- package/dist/src/utils/logger.d.ts.map +1 -1
- package/dist/src/utils/logger.js +8 -8
- package/dist/src/utils/logger.js.map +1 -1
- package/dist/src/workflow/config.d.ts +1 -1
- package/dist/src/workflow/config.d.ts.map +1 -1
- package/dist/src/workflow/config.js +18 -18
- package/dist/src/workflow/config.js.map +1 -1
- package/dist/src/workflow/steps/build.d.ts +1 -1
- package/dist/src/workflow/steps/build.d.ts.map +1 -1
- package/dist/src/workflow/steps/build.js +38 -46
- package/dist/src/workflow/steps/build.js.map +1 -1
- package/dist/src/workflow/steps/finalize.d.ts +1 -1
- package/dist/src/workflow/steps/finalize.d.ts.map +1 -1
- package/dist/src/workflow/steps/finalize.js +48 -54
- package/dist/src/workflow/steps/finalize.js.map +1 -1
- package/dist/src/workflow/steps/plan.d.ts +1 -1
- package/dist/src/workflow/steps/plan.d.ts.map +1 -1
- package/dist/src/workflow/steps/plan.js +46 -58
- package/dist/src/workflow/steps/plan.js.map +1 -1
- package/dist/src/workflow/steps/research.d.ts +1 -1
- package/dist/src/workflow/steps/research.d.ts.map +1 -1
- package/dist/src/workflow/steps/research.js +56 -68
- package/dist/src/workflow/steps/research.js.map +1 -1
- package/dist/src/workflow/types.d.ts +12 -12
- package/dist/src/workflow/types.d.ts.map +1 -1
- package/dist/src/workflow/utils.d.ts +1 -1
- package/dist/src/workflow/utils.d.ts.map +1 -1
- package/dist/src/workflow/utils.js +4 -7
- package/dist/src/workflow/utils.js.map +1 -1
- package/package.json +6 -6
- package/src/adapters/claude/claude-adapter.ts +168 -220
- package/src/adapters/claude/tool-mapper.ts +2 -2
- package/src/adapters/types.ts +1 -1
- package/src/agent.ts +444 -579
- package/src/agents/execution.ts +1 -1
- package/src/agents/planning.ts +1 -1
- package/src/agents/research.ts +1 -0
- package/src/file-manager.ts +63 -64
- package/src/git-manager.ts +88 -144
- package/src/posthog-api.ts +82 -122
- package/src/prompt-builder.ts +135 -180
- package/src/task-manager.ts +30 -38
- package/src/task-progress-reporter.ts +59 -70
- package/src/template-manager.ts +45 -98
- package/src/todo-manager.ts +30 -35
- package/src/tools/registry.ts +62 -62
- package/src/tools/types.ts +36 -36
- package/src/types.ts +71 -93
- package/src/utils/logger.ts +56 -62
- package/src/workflow/config.ts +48 -48
- package/src/workflow/steps/build.ts +113 -122
- package/src/workflow/steps/finalize.ts +182 -214
- package/src/workflow/steps/plan.ts +131 -151
- package/src/workflow/steps/research.ts +186 -205
- package/src/workflow/types.ts +36 -38
- package/src/workflow/utils.ts +34 -37
|
@@ -1,222 +1,203 @@
|
|
|
1
|
-
import { query } from
|
|
2
|
-
import { RESEARCH_SYSTEM_PROMPT } from
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import { finalizeStepGitActions } from
|
|
1
|
+
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
2
|
+
import { RESEARCH_SYSTEM_PROMPT } from '../../agents/research.js';
|
|
3
|
+
import type { WorkflowStepRunner } from '../types.js';
|
|
4
|
+
import type { ResearchEvaluation } from '../../types.js';
|
|
5
|
+
import { finalizeStepGitActions } from '../utils.js';
|
|
6
6
|
|
|
7
7
|
export const researchStep: WorkflowStepRunner = async ({ step, context }) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
8
|
+
const {
|
|
9
|
+
task,
|
|
10
|
+
cwd,
|
|
11
|
+
isCloudMode,
|
|
12
|
+
options,
|
|
13
|
+
logger,
|
|
14
|
+
fileManager,
|
|
15
|
+
gitManager,
|
|
16
|
+
promptBuilder,
|
|
17
|
+
adapter,
|
|
18
|
+
mcpServers,
|
|
19
|
+
emitEvent,
|
|
20
|
+
} = context;
|
|
21
|
+
|
|
22
|
+
const stepLogger = logger.child('ResearchStep');
|
|
23
|
+
|
|
24
|
+
const existingResearch = await fileManager.readResearch(task.id);
|
|
25
|
+
if (existingResearch) {
|
|
26
|
+
stepLogger.info('Research already exists', { taskId: task.id, hasQuestions: !!existingResearch.questions, answered: existingResearch.answered });
|
|
27
|
+
|
|
28
|
+
// If there are unanswered questions, re-emit them so UI can prompt user
|
|
29
|
+
if (existingResearch.questions && !existingResearch.answered) {
|
|
30
|
+
stepLogger.info('Re-emitting unanswered research questions', {
|
|
31
|
+
taskId: task.id,
|
|
32
|
+
questionCount: existingResearch.questions.length
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
emitEvent({
|
|
36
|
+
type: 'artifact',
|
|
37
|
+
ts: Date.now(),
|
|
38
|
+
kind: 'research_questions',
|
|
39
|
+
content: existingResearch.questions,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// In local mode, halt to allow user to answer
|
|
43
|
+
if (!isCloudMode) {
|
|
44
|
+
emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
|
|
45
|
+
return { status: 'skipped', halt: true };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { status: 'skipped' };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
stepLogger.info('Starting research phase', { taskId: task.id });
|
|
53
|
+
emitEvent(adapter.createStatusEvent('phase_start', { phase: 'research' }));
|
|
54
|
+
|
|
55
|
+
const researchPrompt = await promptBuilder.buildResearchPrompt(task, cwd);
|
|
56
|
+
const fullPrompt = `${RESEARCH_SYSTEM_PROMPT}\n\n${researchPrompt}`;
|
|
57
|
+
|
|
58
|
+
const baseOptions: Record<string, any> = {
|
|
59
|
+
model: step.model,
|
|
60
|
+
cwd,
|
|
61
|
+
permissionMode: 'plan',
|
|
62
|
+
settingSources: ['local'],
|
|
63
|
+
mcpServers,
|
|
64
|
+
// Allow research tools: read-only operations, web search, and MCP resources
|
|
65
|
+
allowedTools: [
|
|
66
|
+
'Read',
|
|
67
|
+
'Glob',
|
|
68
|
+
'Grep',
|
|
69
|
+
'WebFetch',
|
|
70
|
+
'WebSearch',
|
|
71
|
+
'ListMcpResources',
|
|
72
|
+
'ReadMcpResource',
|
|
73
|
+
'TodoWrite',
|
|
74
|
+
'BashOutput',
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const response = query({
|
|
79
|
+
prompt: fullPrompt,
|
|
80
|
+
options: { ...baseOptions, ...(options.queryOverrides || {}) },
|
|
30
81
|
});
|
|
31
82
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
83
|
+
let jsonContent = '';
|
|
84
|
+
for await (const message of response) {
|
|
85
|
+
emitEvent(adapter.createRawSDKEvent(message));
|
|
86
|
+
const transformedEvents = adapter.transform(message);
|
|
87
|
+
for (const event of transformedEvents) {
|
|
88
|
+
emitEvent(event);
|
|
89
|
+
}
|
|
90
|
+
if (message.type === 'assistant' && message.message?.content) {
|
|
91
|
+
for (const c of message.message.content) {
|
|
92
|
+
if (c.type === 'text' && c.text) {
|
|
93
|
+
jsonContent += c.text;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
38
98
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (!isCloudMode) {
|
|
48
|
-
emitEvent(
|
|
49
|
-
adapter.createStatusEvent("phase_complete", { phase: "research" }),
|
|
50
|
-
);
|
|
51
|
-
return { status: "skipped", halt: true };
|
|
52
|
-
}
|
|
99
|
+
if (!jsonContent.trim()) {
|
|
100
|
+
stepLogger.error('No JSON output from research agent', { taskId: task.id });
|
|
101
|
+
emitEvent({
|
|
102
|
+
type: 'error',
|
|
103
|
+
ts: Date.now(),
|
|
104
|
+
message: 'Research agent returned no output',
|
|
105
|
+
});
|
|
106
|
+
return { status: 'completed', halt: true };
|
|
53
107
|
}
|
|
54
108
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const fullPrompt = `${RESEARCH_SYSTEM_PROMPT}\n\n${researchPrompt}`;
|
|
63
|
-
|
|
64
|
-
const baseOptions: Record<string, unknown> = {
|
|
65
|
-
model: step.model,
|
|
66
|
-
cwd,
|
|
67
|
-
permissionMode: "plan",
|
|
68
|
-
settingSources: ["local"],
|
|
69
|
-
mcpServers,
|
|
70
|
-
// Allow research tools: read-only operations, web search, and MCP resources
|
|
71
|
-
allowedTools: [
|
|
72
|
-
"Read",
|
|
73
|
-
"Glob",
|
|
74
|
-
"Grep",
|
|
75
|
-
"WebFetch",
|
|
76
|
-
"WebSearch",
|
|
77
|
-
"ListMcpResources",
|
|
78
|
-
"ReadMcpResource",
|
|
79
|
-
"TodoWrite",
|
|
80
|
-
"BashOutput",
|
|
81
|
-
],
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const response = query({
|
|
85
|
-
prompt: fullPrompt,
|
|
86
|
-
options: { ...baseOptions, ...(options.queryOverrides || {}) },
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
let jsonContent = "";
|
|
90
|
-
try {
|
|
91
|
-
for await (const message of response) {
|
|
92
|
-
emitEvent(adapter.createRawSDKEvent(message));
|
|
93
|
-
const transformedEvents = adapter.transform(message);
|
|
94
|
-
for (const event of transformedEvents) {
|
|
95
|
-
emitEvent(event);
|
|
96
|
-
}
|
|
97
|
-
if (message.type === "assistant" && message.message?.content) {
|
|
98
|
-
for (const c of message.message.content) {
|
|
99
|
-
if (c.type === "text" && c.text) {
|
|
100
|
-
jsonContent += c.text;
|
|
101
|
-
}
|
|
109
|
+
// Parse JSON response
|
|
110
|
+
let evaluation: ResearchEvaluation;
|
|
111
|
+
try {
|
|
112
|
+
// Extract JSON from potential markdown code blocks or other wrapping
|
|
113
|
+
const jsonMatch = jsonContent.match(/\{[\s\S]*\}/);
|
|
114
|
+
if (!jsonMatch) {
|
|
115
|
+
throw new Error('No JSON object found in response');
|
|
102
116
|
}
|
|
103
|
-
|
|
117
|
+
evaluation = JSON.parse(jsonMatch[0]);
|
|
118
|
+
stepLogger.info('Parsed research evaluation', {
|
|
119
|
+
taskId: task.id,
|
|
120
|
+
score: evaluation.actionabilityScore,
|
|
121
|
+
hasQuestions: !!evaluation.questions,
|
|
122
|
+
});
|
|
123
|
+
} catch (error) {
|
|
124
|
+
stepLogger.error('Failed to parse research JSON', {
|
|
125
|
+
taskId: task.id,
|
|
126
|
+
error: error instanceof Error ? error.message : String(error),
|
|
127
|
+
content: jsonContent.substring(0, 500),
|
|
128
|
+
});
|
|
129
|
+
emitEvent({
|
|
130
|
+
type: 'error',
|
|
131
|
+
ts: Date.now(),
|
|
132
|
+
message: `Failed to parse research JSON: ${
|
|
133
|
+
error instanceof Error ? error.message : String(error)
|
|
134
|
+
}`,
|
|
135
|
+
});
|
|
136
|
+
return { status: 'completed', halt: true };
|
|
104
137
|
}
|
|
105
|
-
} catch (error) {
|
|
106
|
-
stepLogger.error("Error during research step query", error);
|
|
107
|
-
throw error;
|
|
108
|
-
}
|
|
109
138
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
ts: Date.now(),
|
|
115
|
-
message: "Research agent returned no output",
|
|
116
|
-
});
|
|
117
|
-
return { status: "completed", halt: true };
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Parse JSON response
|
|
121
|
-
let evaluation: ResearchEvaluation;
|
|
122
|
-
try {
|
|
123
|
-
// Extract JSON from potential markdown code blocks or other wrapping
|
|
124
|
-
const jsonMatch = jsonContent.match(/\{[\s\S]*\}/);
|
|
125
|
-
if (!jsonMatch) {
|
|
126
|
-
throw new Error("No JSON object found in response");
|
|
139
|
+
// Add answered/answers fields to evaluation
|
|
140
|
+
if (evaluation.questions && evaluation.questions.length > 0) {
|
|
141
|
+
evaluation.answered = false;
|
|
142
|
+
evaluation.answers = undefined;
|
|
127
143
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
stepLogger.error("Failed to parse research JSON", {
|
|
136
|
-
taskId: task.id,
|
|
137
|
-
error: error instanceof Error ? error.message : String(error),
|
|
138
|
-
content: jsonContent.substring(0, 500),
|
|
139
|
-
});
|
|
140
|
-
emitEvent({
|
|
141
|
-
type: "error",
|
|
142
|
-
ts: Date.now(),
|
|
143
|
-
message: `Failed to parse research JSON: ${
|
|
144
|
-
error instanceof Error ? error.message : String(error)
|
|
145
|
-
}`,
|
|
146
|
-
});
|
|
147
|
-
return { status: "completed", halt: true };
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Add answered/answers fields to evaluation
|
|
151
|
-
if (evaluation.questions && evaluation.questions.length > 0) {
|
|
152
|
-
evaluation.answered = false;
|
|
153
|
-
evaluation.answers = undefined;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Always write research.json
|
|
157
|
-
await fileManager.writeResearch(task.id, evaluation);
|
|
158
|
-
stepLogger.info("Research evaluation written", {
|
|
159
|
-
taskId: task.id,
|
|
160
|
-
score: evaluation.actionabilityScore,
|
|
161
|
-
hasQuestions: !!evaluation.questions,
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
emitEvent({
|
|
165
|
-
type: "artifact",
|
|
166
|
-
ts: Date.now(),
|
|
167
|
-
kind: "research_evaluation",
|
|
168
|
-
content: evaluation,
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
await gitManager.addAllPostHogFiles();
|
|
172
|
-
await finalizeStepGitActions(context, step, {
|
|
173
|
-
commitMessage: `Research phase for ${task.title}`,
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
// Log whether questions need answering
|
|
177
|
-
if (
|
|
178
|
-
evaluation.actionabilityScore < 0.7 &&
|
|
179
|
-
evaluation.questions &&
|
|
180
|
-
evaluation.questions.length > 0
|
|
181
|
-
) {
|
|
182
|
-
stepLogger.info("Actionability score below threshold, questions needed", {
|
|
183
|
-
taskId: task.id,
|
|
184
|
-
score: evaluation.actionabilityScore,
|
|
185
|
-
questionCount: evaluation.questions.length,
|
|
144
|
+
|
|
145
|
+
// Always write research.json
|
|
146
|
+
await fileManager.writeResearch(task.id, evaluation);
|
|
147
|
+
stepLogger.info('Research evaluation written', {
|
|
148
|
+
taskId: task.id,
|
|
149
|
+
score: evaluation.actionabilityScore,
|
|
150
|
+
hasQuestions: !!evaluation.questions,
|
|
186
151
|
});
|
|
187
152
|
|
|
188
153
|
emitEvent({
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
154
|
+
type: 'artifact',
|
|
155
|
+
ts: Date.now(),
|
|
156
|
+
kind: 'research_evaluation',
|
|
157
|
+
content: evaluation,
|
|
193
158
|
});
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
159
|
+
|
|
160
|
+
await gitManager.addAllPostHogFiles();
|
|
161
|
+
await finalizeStepGitActions(context, step, {
|
|
162
|
+
commitMessage: `Research phase for ${task.title}`,
|
|
198
163
|
});
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
164
|
+
|
|
165
|
+
// Log whether questions need answering
|
|
166
|
+
if (evaluation.actionabilityScore < 0.7 && evaluation.questions && evaluation.questions.length > 0) {
|
|
167
|
+
stepLogger.info('Actionability score below threshold, questions needed', {
|
|
168
|
+
taskId: task.id,
|
|
169
|
+
score: evaluation.actionabilityScore,
|
|
170
|
+
questionCount: evaluation.questions.length,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
emitEvent({
|
|
174
|
+
type: 'artifact',
|
|
175
|
+
ts: Date.now(),
|
|
176
|
+
kind: 'research_questions',
|
|
177
|
+
content: evaluation.questions,
|
|
178
|
+
});
|
|
179
|
+
} else {
|
|
180
|
+
stepLogger.info('Actionability score acceptable, proceeding to planning', {
|
|
181
|
+
taskId: task.id,
|
|
182
|
+
score: evaluation.actionabilityScore,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// In local mode, always halt after research for user review
|
|
187
|
+
if (!isCloudMode) {
|
|
188
|
+
emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
|
|
189
|
+
return { status: 'completed', halt: true };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// In cloud mode, check if questions need answering
|
|
193
|
+
const researchData = await fileManager.readResearch(task.id);
|
|
194
|
+
if (researchData?.questions && !researchData.answered) {
|
|
195
|
+
// Questions need answering - halt for user input in cloud mode too
|
|
196
|
+
emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
|
|
197
|
+
return { status: 'completed', halt: true };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// No questions or questions already answered - proceed to planning
|
|
201
|
+
emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
|
|
202
|
+
return { status: 'completed' };
|
|
222
203
|
};
|
package/src/workflow/types.ts
CHANGED
|
@@ -1,53 +1,51 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
5
|
-
import type { PromptBuilder } from
|
|
6
|
-
import type { TaskProgressReporter } from
|
|
7
|
-
import type {
|
|
8
|
-
import type {
|
|
1
|
+
import type { Task, TaskExecutionOptions, PermissionMode } from '../types.js';
|
|
2
|
+
import type { Logger } from '../utils/logger.js';
|
|
3
|
+
import type { PostHogFileManager } from '../file-manager.js';
|
|
4
|
+
import type { GitManager } from '../git-manager.js';
|
|
5
|
+
import type { PromptBuilder } from '../prompt-builder.js';
|
|
6
|
+
import type { TaskProgressReporter } from '../task-progress-reporter.js';
|
|
7
|
+
import type { ProviderAdapter } from '../adapters/types.js';
|
|
8
|
+
import type { PostHogAPIClient } from '../posthog-api.js';
|
|
9
9
|
|
|
10
10
|
export interface WorkflowRuntime {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
11
|
+
task: Task;
|
|
12
|
+
taskSlug: string;
|
|
13
|
+
cwd: string;
|
|
14
|
+
isCloudMode: boolean;
|
|
15
|
+
options: TaskExecutionOptions;
|
|
16
|
+
logger: Logger;
|
|
17
|
+
fileManager: PostHogFileManager;
|
|
18
|
+
gitManager: GitManager;
|
|
19
|
+
promptBuilder: PromptBuilder;
|
|
20
|
+
progressReporter: TaskProgressReporter;
|
|
21
|
+
adapter: ProviderAdapter;
|
|
22
|
+
mcpServers?: Record<string, any>;
|
|
23
|
+
posthogAPI?: PostHogAPIClient;
|
|
24
|
+
emitEvent: (event: any) => void;
|
|
25
|
+
stepResults: Record<string, any>;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export interface WorkflowStepDefinition {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
agent: string;
|
|
32
|
+
model: string;
|
|
33
|
+
permissionMode?: PermissionMode | string;
|
|
34
|
+
commit?: boolean;
|
|
35
|
+
push?: boolean;
|
|
36
|
+
run: WorkflowStepRunner;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export interface WorkflowStepRuntime {
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
step: WorkflowStepDefinition;
|
|
41
|
+
context: WorkflowRuntime;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
export interface WorkflowStepResult {
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
status: 'completed' | 'skipped';
|
|
46
|
+
halt?: boolean;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export type WorkflowStepRunner = (
|
|
50
|
-
runtime: WorkflowStepRuntime,
|
|
51
|
-
) => Promise<WorkflowStepResult>;
|
|
49
|
+
export type WorkflowStepRunner = (runtime: WorkflowStepRuntime) => Promise<WorkflowStepResult>;
|
|
52
50
|
|
|
53
51
|
export type WorkflowDefinition = WorkflowStepDefinition[];
|
package/src/workflow/utils.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { WorkflowRuntime, WorkflowStepDefinition } from
|
|
1
|
+
import type { WorkflowRuntime, WorkflowStepDefinition } from './types.js';
|
|
2
2
|
|
|
3
3
|
interface FinalizeGitOptions {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
commitMessage: string;
|
|
5
|
+
allowEmptyCommit?: boolean;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -10,44 +10,41 @@ interface FinalizeGitOptions {
|
|
|
10
10
|
* Returns true if a commit was created.
|
|
11
11
|
*/
|
|
12
12
|
export async function finalizeStepGitActions(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
context: WorkflowRuntime,
|
|
14
|
+
step: WorkflowStepDefinition,
|
|
15
|
+
options: FinalizeGitOptions
|
|
16
16
|
): Promise<boolean> {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
if (!step.commit) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const { gitManager, logger } = context;
|
|
22
|
+
const hasStagedChanges = await gitManager.hasStagedChanges();
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
if (!hasStagedChanges && !options.allowEmptyCommit) {
|
|
25
|
+
logger.debug('No staged changes to commit for step', { stepId: step.id });
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
29
|
+
try {
|
|
30
|
+
await gitManager.commitChanges(options.commitMessage);
|
|
31
|
+
logger.info('Committed changes for step', {
|
|
32
|
+
stepId: step.id,
|
|
33
|
+
message: options.commitMessage,
|
|
34
|
+
});
|
|
35
|
+
} catch (error) {
|
|
36
|
+
logger.error('Failed to commit changes for step', {
|
|
37
|
+
stepId: step.id,
|
|
38
|
+
error: error instanceof Error ? error.message : String(error),
|
|
39
|
+
});
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
branch: branchName,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
43
|
+
if (step.push) {
|
|
44
|
+
const branchName = await gitManager.getCurrentBranch();
|
|
45
|
+
await gitManager.pushBranch(branchName);
|
|
46
|
+
logger.info('Pushed branch after step', { stepId: step.id, branch: branchName });
|
|
47
|
+
}
|
|
51
48
|
|
|
52
|
-
|
|
49
|
+
return true;
|
|
53
50
|
}
|