@posthog/agent 1.22.0 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +3 -3
- package/README.md +3 -3
- 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 +156 -111
- 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 +143 -85
- 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 +59 -58
- 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 +93 -69
- package/dist/src/git-manager.js.map +1 -1
- package/dist/src/posthog-api.d.ts +2 -3
- 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 +123 -93
- 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 +19 -18
- package/dist/src/task-manager.js.map +1 -1
- package/dist/src/task-progress-reporter.d.ts +3 -4
- package/dist/src/task-progress-reporter.d.ts.map +1 -1
- package/dist/src/task-progress-reporter.js +59 -54
- 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 +30 -28
- 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 +29 -24
- 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 +46 -38
- 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 +54 -48
- 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 +58 -46
- 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 +68 -56
- 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 +7 -4
- package/dist/src/workflow/utils.js.map +1 -1
- package/package.json +8 -8
- package/src/adapters/claude/claude-adapter.ts +220 -168
- package/src/adapters/claude/tool-mapper.ts +2 -2
- package/src/adapters/types.ts +1 -1
- package/src/agent.ts +579 -444
- package/src/agents/execution.ts +1 -1
- package/src/agents/planning.ts +1 -1
- package/src/agents/research.ts +0 -1
- package/src/file-manager.ts +64 -63
- package/src/git-manager.ts +152 -87
- package/src/posthog-api.ts +122 -82
- package/src/prompt-builder.ts +180 -135
- package/src/task-manager.ts +38 -30
- package/src/task-progress-reporter.ts +70 -59
- package/src/template-manager.ts +98 -45
- package/src/todo-manager.ts +35 -30
- package/src/tools/registry.ts +62 -62
- package/src/tools/types.ts +36 -36
- package/src/types.ts +93 -71
- package/src/utils/logger.ts +62 -56
- package/src/workflow/config.ts +48 -48
- package/src/workflow/steps/build.ts +122 -113
- package/src/workflow/steps/finalize.ts +214 -182
- package/src/workflow/steps/plan.ts +151 -131
- package/src/workflow/steps/research.ts +205 -186
- package/src/workflow/types.ts +38 -36
- package/src/workflow/utils.ts +37 -34
- package/LICENSE +0 -33
|
@@ -1,203 +1,222 @@
|
|
|
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 { ResearchEvaluation } from "../../types.js";
|
|
4
|
+
import type { WorkflowStepRunner } 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
|
-
|
|
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 || {}) },
|
|
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", {
|
|
27
|
+
taskId: task.id,
|
|
28
|
+
hasQuestions: !!existingResearch.questions,
|
|
29
|
+
answered: existingResearch.answered,
|
|
81
30
|
});
|
|
82
31
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
}
|
|
32
|
+
// If there are unanswered questions, re-emit them so UI can prompt user
|
|
33
|
+
if (existingResearch.questions && !existingResearch.answered) {
|
|
34
|
+
stepLogger.info("Re-emitting unanswered research questions", {
|
|
35
|
+
taskId: task.id,
|
|
36
|
+
questionCount: existingResearch.questions.length,
|
|
37
|
+
});
|
|
98
38
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
39
|
+
emitEvent({
|
|
40
|
+
type: "artifact",
|
|
41
|
+
ts: Date.now(),
|
|
42
|
+
kind: "research_questions",
|
|
43
|
+
content: existingResearch.questions,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// In local mode, halt to allow user to answer
|
|
47
|
+
if (!isCloudMode) {
|
|
48
|
+
emitEvent(
|
|
49
|
+
adapter.createStatusEvent("phase_complete", { phase: "research" }),
|
|
50
|
+
);
|
|
51
|
+
return { status: "skipped", halt: true };
|
|
52
|
+
}
|
|
107
53
|
}
|
|
108
54
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
55
|
+
return { status: "skipped" };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
stepLogger.info("Starting research phase", { taskId: task.id });
|
|
59
|
+
emitEvent(adapter.createStatusEvent("phase_start", { phase: "research" }));
|
|
60
|
+
|
|
61
|
+
const researchPrompt = await promptBuilder.buildResearchPrompt(task, cwd);
|
|
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
|
+
}
|
|
116
102
|
}
|
|
117
|
-
|
|
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 };
|
|
103
|
+
}
|
|
137
104
|
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
stepLogger.error("Error during research step query", error);
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
138
109
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
110
|
+
if (!jsonContent.trim()) {
|
|
111
|
+
stepLogger.error("No JSON output from research agent", { taskId: task.id });
|
|
112
|
+
emitEvent({
|
|
113
|
+
type: "error",
|
|
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");
|
|
143
127
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
128
|
+
evaluation = JSON.parse(jsonMatch[0]);
|
|
129
|
+
stepLogger.info("Parsed research evaluation", {
|
|
130
|
+
taskId: task.id,
|
|
131
|
+
score: evaluation.actionabilityScore,
|
|
132
|
+
hasQuestions: !!evaluation.questions,
|
|
133
|
+
});
|
|
134
|
+
} catch (error) {
|
|
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),
|
|
151
139
|
});
|
|
152
|
-
|
|
153
140
|
emitEvent({
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
141
|
+
type: "error",
|
|
142
|
+
ts: Date.now(),
|
|
143
|
+
message: `Failed to parse research JSON: ${
|
|
144
|
+
error instanceof Error ? error.message : String(error)
|
|
145
|
+
}`,
|
|
158
146
|
});
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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,
|
|
163
186
|
});
|
|
164
187
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
// No questions or questions already answered - proceed to planning
|
|
201
|
-
emitEvent(adapter.createStatusEvent('phase_complete', { phase: 'research' }));
|
|
202
|
-
return { status: 'completed' };
|
|
188
|
+
emitEvent({
|
|
189
|
+
type: "artifact",
|
|
190
|
+
ts: Date.now(),
|
|
191
|
+
kind: "research_questions",
|
|
192
|
+
content: evaluation.questions,
|
|
193
|
+
});
|
|
194
|
+
} else {
|
|
195
|
+
stepLogger.info("Actionability score acceptable, proceeding to planning", {
|
|
196
|
+
taskId: task.id,
|
|
197
|
+
score: evaluation.actionabilityScore,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// In local mode, always halt after research for user review
|
|
202
|
+
if (!isCloudMode) {
|
|
203
|
+
emitEvent(
|
|
204
|
+
adapter.createStatusEvent("phase_complete", { phase: "research" }),
|
|
205
|
+
);
|
|
206
|
+
return { status: "completed", halt: true };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// In cloud mode, check if questions need answering
|
|
210
|
+
const researchData = await fileManager.readResearch(task.id);
|
|
211
|
+
if (researchData?.questions && !researchData.answered) {
|
|
212
|
+
// Questions need answering - halt for user input in cloud mode too
|
|
213
|
+
emitEvent(
|
|
214
|
+
adapter.createStatusEvent("phase_complete", { phase: "research" }),
|
|
215
|
+
);
|
|
216
|
+
return { status: "completed", halt: true };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// No questions or questions already answered - proceed to planning
|
|
220
|
+
emitEvent(adapter.createStatusEvent("phase_complete", { phase: "research" }));
|
|
221
|
+
return { status: "completed" };
|
|
203
222
|
};
|
package/src/workflow/types.ts
CHANGED
|
@@ -1,51 +1,53 @@
|
|
|
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 { ProviderAdapter } from "../adapters/types.js";
|
|
2
|
+
import type { PostHogFileManager } from "../file-manager.js";
|
|
3
|
+
import type { GitManager } from "../git-manager.js";
|
|
4
|
+
import type { PostHogAPIClient } from "../posthog-api.js";
|
|
5
|
+
import type { PromptBuilder } from "../prompt-builder.js";
|
|
6
|
+
import type { TaskProgressReporter } from "../task-progress-reporter.js";
|
|
7
|
+
import type { PermissionMode, Task, TaskExecutionOptions } from "../types.js";
|
|
8
|
+
import type { Logger } from "../utils/logger.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, unknown>;
|
|
23
|
+
posthogAPI?: PostHogAPIClient;
|
|
24
|
+
emitEvent: (event: unknown) => void;
|
|
25
|
+
stepResults: Record<string, unknown>;
|
|
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 = (
|
|
49
|
+
export type WorkflowStepRunner = (
|
|
50
|
+
runtime: WorkflowStepRuntime,
|
|
51
|
+
) => Promise<WorkflowStepResult>;
|
|
50
52
|
|
|
51
53
|
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,41 +10,44 @@ 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
|
-
|
|
43
|
+
if (step.push) {
|
|
44
|
+
const branchName = await gitManager.getCurrentBranch();
|
|
45
|
+
await gitManager.pushBranch(branchName);
|
|
46
|
+
logger.info("Pushed branch after step", {
|
|
47
|
+
stepId: step.id,
|
|
48
|
+
branch: branchName,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
return true;
|
|
50
53
|
}
|
package/LICENSE
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
Business Source License 1.1
|
|
2
|
-
|
|
3
|
-
Parameters
|
|
4
|
-
|
|
5
|
-
Licensor: PostHog Inc.
|
|
6
|
-
Licensed Work: Array & Posthog Agent package
|
|
7
|
-
The Licensed Work is © 2025 PostHog Inc.
|
|
8
|
-
|
|
9
|
-
Change Date: None (the Licensed Work will remain under this License indefinitely unless Licensor specifies otherwise)
|
|
10
|
-
Change License: At Licensor's discretion
|
|
11
|
-
|
|
12
|
-
Additional Use Grant:
|
|
13
|
-
You may use, modify, and self-host this software for personal purposes.
|
|
14
|
-
You may also submit contributions (e.g., pull requests) to the Licensed Work under this License.
|
|
15
|
-
Commercial redistribution, resale, or offering as a managed/hosted service requires a separate commercial agreement with the Licensor.
|
|
16
|
-
Using the Licensed Work to build or offer a competing product or service is prohibited without explicit written permission from the Licensor.
|
|
17
|
-
|
|
18
|
-
Terms
|
|
19
|
-
|
|
20
|
-
The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make use of the Licensed Work for personal purposes. The Licensor may make an Additional Use Grant, above, permitting limited production use.
|
|
21
|
-
|
|
22
|
-
Effective on the Change Date (if one is ever designated by the Licensor), the Change License will apply to the Licensed Work.
|
|
23
|
-
|
|
24
|
-
Any use of the Licensed Work not explicitly permitted by this License is prohibited.
|
|
25
|
-
This License applies separately to each version of the Licensed Work released by the Licensor.
|
|
26
|
-
|
|
27
|
-
THE LICENSED WORK IS PROVIDED "AS IS". THE LICENSOR MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
28
|
-
|
|
29
|
-
This License does not grant trademark rights, and no license is granted for use of the Licensor's trademarks, trade names, or logos.
|
|
30
|
-
|
|
31
|
-
License text copyright (c) 2020 MariaDB Corporation Ab, All Rights Reserved.
|
|
32
|
-
|
|
33
|
-
"Business Source License" is a trademark of MariaDB Corporation Ab.
|