@almightygpt/core 0.9.2 → 0.10.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/adapters/factory.d.ts +12 -0
- package/dist/adapters/factory.d.ts.map +1 -0
- package/dist/adapters/factory.js +40 -0
- package/dist/adapters/factory.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/plan/run-plan-review.d.ts +40 -0
- package/dist/plan/run-plan-review.d.ts.map +1 -0
- package/dist/plan/run-plan-review.js +224 -0
- package/dist/plan/run-plan-review.js.map +1 -0
- package/dist/plan/run-plan.d.ts +42 -0
- package/dist/plan/run-plan.d.ts.map +1 -0
- package/dist/plan/run-plan.js +193 -0
- package/dist/plan/run-plan.js.map +1 -0
- package/dist/runs/types.d.ts +1 -1
- package/dist/runs/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/adapters/factory.ts +45 -0
- package/src/index.ts +13 -1
- package/src/plan/run-plan-review.ts +302 -0
- package/src/plan/run-plan.ts +247 -0
- package/src/runs/types.ts +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-plan.js","sourceRoot":"","sources":["../../src/plan/run-plan.ts"],"names":[],"mappings":"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"}
|
package/dist/runs/types.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - audit what was sent to which provider,
|
|
10
10
|
* - drive the future VS Code / dashboard / CLI history views.
|
|
11
11
|
*/
|
|
12
|
-
export type RunType = "review-diff" | "review-path" | "review-requirement" | "review-worker-reviewer";
|
|
12
|
+
export type RunType = "review-diff" | "review-path" | "review-requirement" | "review-worker-reviewer" | "plan" | "review-plan";
|
|
13
13
|
export type RunStatus = "running" | "completed" | "failed" | "aborted_budget";
|
|
14
14
|
export interface AgentMetrics {
|
|
15
15
|
agent: string;
|
package/dist/runs/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runs/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,OAAO,GACf,aAAa,GACb,aAAa,GACb,oBAAoB,GACpB,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runs/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter factory — single place to map (name, provider) → concrete
|
|
3
|
+
* Adapter instance.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from review/run-diff-review.ts during v0.10.0 (plan
|
|
6
|
+
* module) so the plan + review pipelines share the same factory and
|
|
7
|
+
* a new adapter only needs to be wired in one place.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { type Adapter } from "./types.js";
|
|
11
|
+
import { MockAdapter } from "./mock.js";
|
|
12
|
+
import { OpenAIAdapter } from "./openai.js";
|
|
13
|
+
import { ClaudeAdapter } from "./claude.js";
|
|
14
|
+
import { GeminiAdapter } from "./gemini.js";
|
|
15
|
+
|
|
16
|
+
export function makeAdapter(name: string, provider: string): Adapter {
|
|
17
|
+
switch (provider) {
|
|
18
|
+
case "openai":
|
|
19
|
+
return new OpenAIAdapter(name);
|
|
20
|
+
case "anthropic":
|
|
21
|
+
return new ClaudeAdapter(name);
|
|
22
|
+
case "google":
|
|
23
|
+
return new GeminiAdapter(name);
|
|
24
|
+
case "mock":
|
|
25
|
+
return new MockAdapter();
|
|
26
|
+
default:
|
|
27
|
+
throw new Error(
|
|
28
|
+
`Provider "${provider}" not supported. ` +
|
|
29
|
+
`Use "openai", "anthropic", "google", or "mock".`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function envHintForProvider(provider: string): string {
|
|
35
|
+
switch (provider) {
|
|
36
|
+
case "openai":
|
|
37
|
+
return "Export OPENAI_API_KEY in your environment.";
|
|
38
|
+
case "anthropic":
|
|
39
|
+
return "Export ANTHROPIC_API_KEY in your environment.";
|
|
40
|
+
case "google":
|
|
41
|
+
return "Export GOOGLE_API_KEY (or GEMINI_API_KEY) in your environment.";
|
|
42
|
+
default:
|
|
43
|
+
return "";
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* - budget/ ✅ task #14 BudgetTracker + BudgetExceededError
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
export const VERSION = "0.
|
|
16
|
+
export const VERSION = "0.10.0";
|
|
17
17
|
|
|
18
18
|
// MCP server (v0.9.0+) — exposes AlmightyGPT's review surface as MCP tools.
|
|
19
19
|
export { startMcpServer } from "./mcp/server.js";
|
|
@@ -143,6 +143,18 @@ export {
|
|
|
143
143
|
type KeychainAdapter,
|
|
144
144
|
} from "./auth/keychain.js";
|
|
145
145
|
export { validateKey, type ValidationResult } from "./auth/validator.js";
|
|
146
|
+
// Plan subsystem (v0.10.0+) — Worker plan + Reviewer plan-review
|
|
147
|
+
export {
|
|
148
|
+
runWorkerPlan,
|
|
149
|
+
type PlanOptions,
|
|
150
|
+
type PlanResult,
|
|
151
|
+
} from "./plan/run-plan.js";
|
|
152
|
+
export {
|
|
153
|
+
runPlanReview,
|
|
154
|
+
type PlanReviewOptions,
|
|
155
|
+
type PlanReviewResult,
|
|
156
|
+
} from "./plan/run-plan-review.js";
|
|
157
|
+
|
|
146
158
|
export {
|
|
147
159
|
AuthMissingError,
|
|
148
160
|
PROVIDER_ENV_VARS,
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `almightygpt review --plan <file>` — Reviewer AI critiques a PLAN
|
|
3
|
+
* doc (not a git diff). Same review primitives as runDiffReview but
|
|
4
|
+
* the input is the plan markdown and the framing tells the Reviewer
|
|
5
|
+
* to critique the plan's structure, completeness, and risks rather
|
|
6
|
+
* than line-by-line code.
|
|
7
|
+
*
|
|
8
|
+
* Output lands at `<reviewsDir>/plan-<topic>.md` (prefix distinguishes
|
|
9
|
+
* plan reviews from diff reviews when they share the same topic name).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { readFile } from "node:fs/promises";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { loadConfig } from "../config/load.js";
|
|
15
|
+
import { makeAdapter } from "../adapters/factory.js";
|
|
16
|
+
import { AdapterError } from "../adapters/types.js";
|
|
17
|
+
import { assembleMemory } from "../review/memory.js";
|
|
18
|
+
import {
|
|
19
|
+
createRunFolder,
|
|
20
|
+
writeRunMetadata,
|
|
21
|
+
writeRunInput,
|
|
22
|
+
writeAgentOutput,
|
|
23
|
+
collectGitContext,
|
|
24
|
+
} from "../runs/folder.js";
|
|
25
|
+
import {
|
|
26
|
+
writeHumanReviewFile,
|
|
27
|
+
preflightReviewFileCollision,
|
|
28
|
+
} from "../review/write.js";
|
|
29
|
+
|
|
30
|
+
export interface PlanReviewOptions {
|
|
31
|
+
repoRoot: string;
|
|
32
|
+
topic: string;
|
|
33
|
+
/** Path (relative to repoRoot) to the plan markdown to review. */
|
|
34
|
+
planPath: string;
|
|
35
|
+
reviewer?: string;
|
|
36
|
+
force?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface PlanReviewResult {
|
|
40
|
+
reviewPath: string;
|
|
41
|
+
reviewBytes: number;
|
|
42
|
+
reviewer: string;
|
|
43
|
+
provider: string;
|
|
44
|
+
modelUsed: string;
|
|
45
|
+
tokensIn: number;
|
|
46
|
+
cachedTokensIn: number;
|
|
47
|
+
tokensOut: number;
|
|
48
|
+
costUsd: number;
|
|
49
|
+
latencyMs: number;
|
|
50
|
+
memorySources: { path: string; bytes: number }[];
|
|
51
|
+
memoryMissing: string[];
|
|
52
|
+
runId: string;
|
|
53
|
+
runFolder: string;
|
|
54
|
+
shallowWarning?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const PLAN_REVIEW_SYSTEM_FRAMING = [
|
|
58
|
+
"You are the Reviewer AI in an AlmightyGPT Plan-review stage.",
|
|
59
|
+
"",
|
|
60
|
+
"WHAT YOU ARE REVIEWING: the PLAN markdown supplied below. NOT a git",
|
|
61
|
+
"diff and NOT code — a plan that a Worker AI drafted in response to a",
|
|
62
|
+
"human's requirement. The plan has not been implemented yet. Your job",
|
|
63
|
+
"is to find what's WRONG with the plan: missing steps, hidden",
|
|
64
|
+
"dependencies, risks the Worker didn't surface, ambiguous decisions,",
|
|
65
|
+
"things that will break in production, edge cases the test plan misses.",
|
|
66
|
+
"",
|
|
67
|
+
"WHAT THE ORCHESTRATOR OWNS (do NOT include these in your response):",
|
|
68
|
+
" - The H1 title (orchestrator prepends `# Plan Review: <topic>`).",
|
|
69
|
+
" - The header block with model / tokens / cost.",
|
|
70
|
+
" - The `## Cost and Latency` and `## Appendix: Raw Outputs` sections.",
|
|
71
|
+
"",
|
|
72
|
+
"WHAT YOU MUST PRODUCE — start with `## Decision Required` and emit",
|
|
73
|
+
"ONLY these sections in this order:",
|
|
74
|
+
" ## Decision Required",
|
|
75
|
+
" ## Highest-Risk Findings",
|
|
76
|
+
" ## Concrete Weaknesses",
|
|
77
|
+
" ## Worker Plan Summary",
|
|
78
|
+
" ## Test Plan",
|
|
79
|
+
" ## Human Decision",
|
|
80
|
+
"",
|
|
81
|
+
"ANTI-SYCOPHANCY (non-negotiable):",
|
|
82
|
+
" - Find at least 3 concrete weaknesses with specific file / step / line",
|
|
83
|
+
" references from the plan.",
|
|
84
|
+
" - A finding without a specific anchor is too vague.",
|
|
85
|
+
" - 'Looks good, minor suggestions' is a FAILED review — recalibrate.",
|
|
86
|
+
"",
|
|
87
|
+
"REVIEW LENS — focus on what plans commonly get wrong:",
|
|
88
|
+
" - Steps assume capabilities that don't exist yet",
|
|
89
|
+
" - Risks section underweights production blast radius",
|
|
90
|
+
" - Test plan is generic ('add tests') instead of named cases",
|
|
91
|
+
" - Open questions are missing things the human will actually need to",
|
|
92
|
+
" decide before implementation",
|
|
93
|
+
" - Affected modules list is incomplete (the plan touches more surfaces",
|
|
94
|
+
" than it admits)",
|
|
95
|
+
" - Migration / rollback story is missing or hand-wavy",
|
|
96
|
+
].join("\n");
|
|
97
|
+
|
|
98
|
+
function buildPlanReviewUserMessage(
|
|
99
|
+
topic: string,
|
|
100
|
+
planContent: string,
|
|
101
|
+
): string {
|
|
102
|
+
return [
|
|
103
|
+
`# Plan-review request — topic: \`${topic}\``,
|
|
104
|
+
"",
|
|
105
|
+
"## The plan to review",
|
|
106
|
+
"",
|
|
107
|
+
"```markdown",
|
|
108
|
+
planContent.trim(),
|
|
109
|
+
"```",
|
|
110
|
+
"",
|
|
111
|
+
"## Your task",
|
|
112
|
+
"",
|
|
113
|
+
"Critique the plan above using the structure in your system prompt.",
|
|
114
|
+
"Start your response with `## Decision Required` (no H1, no preamble).",
|
|
115
|
+
].join("\n");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export async function runPlanReview(
|
|
119
|
+
opts: PlanReviewOptions,
|
|
120
|
+
): Promise<PlanReviewResult> {
|
|
121
|
+
const config = await loadConfig(opts.repoRoot);
|
|
122
|
+
|
|
123
|
+
const reviewerName = opts.reviewer ?? config.defaults.reviewer;
|
|
124
|
+
if (!reviewerName) {
|
|
125
|
+
throw new Error(
|
|
126
|
+
"No reviewer specified. Pass --reviewer <name> or set defaults.reviewer in .almightygpt/config.yaml.",
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
const agentConfig = config.agents[reviewerName];
|
|
130
|
+
if (!agentConfig) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`Reviewer "${reviewerName}" not found in .almightygpt/config.yaml agents map.`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
if (!agentConfig.enabled) {
|
|
136
|
+
throw new Error(`Reviewer "${reviewerName}" is disabled in .almightygpt/config.yaml.`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const adapter = makeAdapter(reviewerName, agentConfig.provider);
|
|
140
|
+
if (!(await adapter.isAvailable())) {
|
|
141
|
+
throw new AdapterError(
|
|
142
|
+
`Adapter "${reviewerName}" (${agentConfig.provider}) is not available. Set the provider's API key.`,
|
|
143
|
+
reviewerName,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Plan reviews land at <reviewsDir>/plan-<topic>.md so they don't
|
|
148
|
+
// collide with diff reviews on the same topic.
|
|
149
|
+
const planReviewTopic = `plan-${opts.topic}`;
|
|
150
|
+
await preflightReviewFileCollision(
|
|
151
|
+
opts.repoRoot,
|
|
152
|
+
config.reviewsDir,
|
|
153
|
+
planReviewTopic,
|
|
154
|
+
opts.force ?? false,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Load the plan to review.
|
|
158
|
+
let planContent: string;
|
|
159
|
+
try {
|
|
160
|
+
planContent = await readFile(join(opts.repoRoot, opts.planPath), "utf8");
|
|
161
|
+
} catch (err) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`Could not read plan file at ${opts.planPath}: ${err instanceof Error ? err.message : String(err)}`,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const runFolder = await createRunFolder({
|
|
168
|
+
repoRoot: opts.repoRoot,
|
|
169
|
+
runsDir: config.runsDir,
|
|
170
|
+
topic: planReviewTopic,
|
|
171
|
+
type: "review-plan",
|
|
172
|
+
});
|
|
173
|
+
const createdAt = new Date().toISOString();
|
|
174
|
+
|
|
175
|
+
const memory = await assembleMemory(opts.repoRoot, agentConfig.memoryFile);
|
|
176
|
+
const systemPrompt = PLAN_REVIEW_SYSTEM_FRAMING + "\n\n" + memory.text;
|
|
177
|
+
const userMessage = buildPlanReviewUserMessage(opts.topic, planContent);
|
|
178
|
+
|
|
179
|
+
await writeRunInput(runFolder.absPath, userMessage);
|
|
180
|
+
|
|
181
|
+
const adapterOut = await adapter.execute({
|
|
182
|
+
role: "reviewer",
|
|
183
|
+
systemPrompt,
|
|
184
|
+
userMessage,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
await writeAgentOutput(runFolder.absPath, "reviewer", adapterOut.content);
|
|
188
|
+
|
|
189
|
+
// Shallow detection: same rule as diff reviews — need N concrete
|
|
190
|
+
// weaknesses with anchors.
|
|
191
|
+
const shallowWarning = detectShallowPlanReview(
|
|
192
|
+
adapterOut.content,
|
|
193
|
+
config.review.requireConcreteWeaknesses,
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const writeOpts: Parameters<typeof writeHumanReviewFile>[0] = {
|
|
197
|
+
repoRoot: opts.repoRoot,
|
|
198
|
+
reviewsDir: config.reviewsDir,
|
|
199
|
+
topic: planReviewTopic,
|
|
200
|
+
reviewerName,
|
|
201
|
+
reviewerProvider: adapter.provider,
|
|
202
|
+
modelUsed: adapterOut.modelUsed,
|
|
203
|
+
body: adapterOut.content,
|
|
204
|
+
metrics: {
|
|
205
|
+
tokensIn: adapterOut.tokensIn,
|
|
206
|
+
tokensOut: adapterOut.tokensOut,
|
|
207
|
+
costUsd: adapterOut.costUsd,
|
|
208
|
+
latencyMs: adapterOut.latencyMs,
|
|
209
|
+
},
|
|
210
|
+
runFolder: runFolder.relPath,
|
|
211
|
+
};
|
|
212
|
+
if (shallowWarning) writeOpts.shallowWarning = shallowWarning;
|
|
213
|
+
if (opts.force) writeOpts.force = opts.force;
|
|
214
|
+
const written = await writeHumanReviewFile(writeOpts);
|
|
215
|
+
|
|
216
|
+
const git = await collectGitContext(opts.repoRoot);
|
|
217
|
+
await writeRunMetadata(runFolder.absPath, {
|
|
218
|
+
id: runFolder.id,
|
|
219
|
+
type: "review-plan",
|
|
220
|
+
createdAt,
|
|
221
|
+
finishedAt: new Date().toISOString(),
|
|
222
|
+
workspacePath: opts.repoRoot,
|
|
223
|
+
topic: planReviewTopic,
|
|
224
|
+
git,
|
|
225
|
+
input: { source: "requirement-file", path: opts.planPath },
|
|
226
|
+
agents: [
|
|
227
|
+
{
|
|
228
|
+
name: reviewerName,
|
|
229
|
+
role: "reviewer",
|
|
230
|
+
provider: agentConfig.provider,
|
|
231
|
+
enabled: true,
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
adapterVersions: [],
|
|
235
|
+
status: "completed",
|
|
236
|
+
metrics: [
|
|
237
|
+
{
|
|
238
|
+
agent: reviewerName,
|
|
239
|
+
role: "reviewer",
|
|
240
|
+
provider: adapter.provider,
|
|
241
|
+
model: adapterOut.modelUsed,
|
|
242
|
+
tokensIn: adapterOut.tokensIn,
|
|
243
|
+
cachedTokensIn: adapterOut.cachedTokensIn ?? 0,
|
|
244
|
+
tokensOut: adapterOut.tokensOut,
|
|
245
|
+
costUsd: adapterOut.costUsd,
|
|
246
|
+
latencyMs: adapterOut.latencyMs,
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
totals: {
|
|
250
|
+
tokensIn: adapterOut.tokensIn,
|
|
251
|
+
tokensOut: adapterOut.tokensOut,
|
|
252
|
+
costUsd: adapterOut.costUsd,
|
|
253
|
+
latencyMs: adapterOut.latencyMs,
|
|
254
|
+
},
|
|
255
|
+
reviewPath: written.path,
|
|
256
|
+
budget: {
|
|
257
|
+
maxCostPerRunUsd: config.budget.maxCostPerRunUsd,
|
|
258
|
+
maxTokensPerRun: config.budget.maxTokensPerRun,
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
const result: PlanReviewResult = {
|
|
263
|
+
reviewPath: written.path,
|
|
264
|
+
reviewBytes: written.bytes,
|
|
265
|
+
reviewer: reviewerName,
|
|
266
|
+
provider: adapter.provider,
|
|
267
|
+
modelUsed: adapterOut.modelUsed,
|
|
268
|
+
tokensIn: adapterOut.tokensIn,
|
|
269
|
+
cachedTokensIn: adapterOut.cachedTokensIn ?? 0,
|
|
270
|
+
tokensOut: adapterOut.tokensOut,
|
|
271
|
+
costUsd: adapterOut.costUsd,
|
|
272
|
+
latencyMs: adapterOut.latencyMs,
|
|
273
|
+
memorySources: memory.sources,
|
|
274
|
+
memoryMissing: memory.missing,
|
|
275
|
+
runId: runFolder.id,
|
|
276
|
+
runFolder: runFolder.relPath,
|
|
277
|
+
};
|
|
278
|
+
if (shallowWarning) result.shallowWarning = shallowWarning;
|
|
279
|
+
return result;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** Same shallow heuristic as diff reviews — count file/step/line anchors. */
|
|
283
|
+
function detectShallowPlanReview(
|
|
284
|
+
content: string,
|
|
285
|
+
requireConcreteWeaknesses: number,
|
|
286
|
+
): string | undefined {
|
|
287
|
+
const anchorPattern = /\b(?:file|step|line|section)[:\s][\w\-./]+/gi;
|
|
288
|
+
const anchors = content.match(anchorPattern) ?? [];
|
|
289
|
+
const weaknessesSection = content.match(
|
|
290
|
+
/## Concrete Weaknesses([\s\S]*?)(?=##|$)/i,
|
|
291
|
+
);
|
|
292
|
+
const weaknessBullets =
|
|
293
|
+
weaknessesSection?.[1]?.match(/^\s*[-*\d.]/gm)?.length ?? 0;
|
|
294
|
+
|
|
295
|
+
if (anchors.length === 0) {
|
|
296
|
+
return "Plan review has zero anchored references (file / step / line). The Reviewer may not have engaged with specifics — consider re-running.";
|
|
297
|
+
}
|
|
298
|
+
if (weaknessBullets < requireConcreteWeaknesses) {
|
|
299
|
+
return `Plan review listed ${weaknessBullets} concrete weaknesses, fewer than the configured minimum of ${requireConcreteWeaknesses}. Output may be shallow — consider re-running with a more rigorous Reviewer.`;
|
|
300
|
+
}
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `almightygpt plan` — Worker AI reads a free-text requirement +
|
|
3
|
+
* project memory, produces a structured plan markdown.
|
|
4
|
+
*
|
|
5
|
+
* Distinct from the review pipeline because the INPUT is a
|
|
6
|
+
* requirement (a sentence or paragraph from the user describing
|
|
7
|
+
* what they want), not a git diff. Output is a plan doc with
|
|
8
|
+
* required sections — same shape on every run so the Reviewer
|
|
9
|
+
* downstream knows what to expect.
|
|
10
|
+
*
|
|
11
|
+
* Plans land at `docs/<worker>-plans/<topic>.md`. The Reviewer step
|
|
12
|
+
* then runs against this plan via the `review --plan <file>` mode
|
|
13
|
+
* (see run-plan-review.ts).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
17
|
+
import { dirname, join } from "node:path";
|
|
18
|
+
import { loadConfig } from "../config/load.js";
|
|
19
|
+
import { makeAdapter } from "../adapters/factory.js";
|
|
20
|
+
import { AdapterError } from "../adapters/types.js";
|
|
21
|
+
import { assembleMemory } from "../review/memory.js";
|
|
22
|
+
import {
|
|
23
|
+
createRunFolder,
|
|
24
|
+
writeRunMetadata,
|
|
25
|
+
writeRunInput,
|
|
26
|
+
writeAgentOutput,
|
|
27
|
+
collectGitContext,
|
|
28
|
+
} from "../runs/folder.js";
|
|
29
|
+
import { assertSafeToWrite } from "../git/status.js";
|
|
30
|
+
|
|
31
|
+
export interface PlanOptions {
|
|
32
|
+
repoRoot: string;
|
|
33
|
+
topic: string;
|
|
34
|
+
requirement: string;
|
|
35
|
+
worker?: string;
|
|
36
|
+
force?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface PlanResult {
|
|
40
|
+
planPath: string;
|
|
41
|
+
planBytes: number;
|
|
42
|
+
worker: string;
|
|
43
|
+
provider: string;
|
|
44
|
+
modelUsed: string;
|
|
45
|
+
tokensIn: number;
|
|
46
|
+
cachedTokensIn: number;
|
|
47
|
+
tokensOut: number;
|
|
48
|
+
costUsd: number;
|
|
49
|
+
latencyMs: number;
|
|
50
|
+
memorySources: { path: string; bytes: number }[];
|
|
51
|
+
memoryMissing: string[];
|
|
52
|
+
runId: string;
|
|
53
|
+
runFolder: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const PLAN_SYSTEM_FRAMING = [
|
|
57
|
+
"You are the Worker AI in an AlmightyGPT Plan stage.",
|
|
58
|
+
"",
|
|
59
|
+
"WHAT YOU ARE DOING: turning a free-text requirement (the user message",
|
|
60
|
+
"below) into a structured plan markdown that a Reviewer AI will then",
|
|
61
|
+
"critique. You are NOT writing code — only the plan. The human will",
|
|
62
|
+
"approve / reject / refine the plan, and only then will implementation",
|
|
63
|
+
"happen (in a separate tool).",
|
|
64
|
+
"",
|
|
65
|
+
"WHAT THE ORCHESTRATOR OWNS (do NOT include these in your response):",
|
|
66
|
+
" - The H1 title (the orchestrator prepends `# Plan: <topic>`).",
|
|
67
|
+
" - The header block with model / tokens / cost.",
|
|
68
|
+
"",
|
|
69
|
+
"WHAT YOU MUST PRODUCE — emit exactly these sections in this order:",
|
|
70
|
+
" ## Goal",
|
|
71
|
+
" ## Affected modules / surfaces",
|
|
72
|
+
" ## Step-by-step approach",
|
|
73
|
+
" ## Risks",
|
|
74
|
+
" ## Test plan",
|
|
75
|
+
" ## Open questions",
|
|
76
|
+
"",
|
|
77
|
+
"STYLE:",
|
|
78
|
+
" - Be concrete. Name specific files, classes, functions, env vars.",
|
|
79
|
+
" - Write so the Reviewer can find concrete things to critique.",
|
|
80
|
+
" - Open questions are not a weakness; they're the things you'd ask",
|
|
81
|
+
" the human if you could. Surface them.",
|
|
82
|
+
].join("\n");
|
|
83
|
+
|
|
84
|
+
function buildPlanUserMessage(topic: string, requirement: string): string {
|
|
85
|
+
return [
|
|
86
|
+
`# Plan request — topic: \`${topic}\``,
|
|
87
|
+
"",
|
|
88
|
+
"## Requirement (from human)",
|
|
89
|
+
"",
|
|
90
|
+
requirement.trim(),
|
|
91
|
+
"",
|
|
92
|
+
"## Your task",
|
|
93
|
+
"",
|
|
94
|
+
"Produce the plan markdown using the structure in your system prompt.",
|
|
95
|
+
"Start your response with `## Goal` (no H1, no preamble).",
|
|
96
|
+
].join("\n");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function runWorkerPlan(opts: PlanOptions): Promise<PlanResult> {
|
|
100
|
+
const config = await loadConfig(opts.repoRoot);
|
|
101
|
+
|
|
102
|
+
const workerName = opts.worker ?? config.defaults.worker;
|
|
103
|
+
if (!workerName) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
"No worker specified. Pass --worker <name> or set defaults.worker in .almightygpt/config.yaml.",
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
const agentConfig = config.agents[workerName];
|
|
109
|
+
if (!agentConfig) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
`Worker "${workerName}" not found in .almightygpt/config.yaml agents map.`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
if (!agentConfig.enabled) {
|
|
115
|
+
throw new Error(`Worker "${workerName}" is disabled in .almightygpt/config.yaml.`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const adapter = makeAdapter(workerName, agentConfig.provider);
|
|
119
|
+
if (!(await adapter.isAvailable())) {
|
|
120
|
+
throw new AdapterError(
|
|
121
|
+
`Adapter "${workerName}" (${agentConfig.provider}) is not available. Set the provider's API key.`,
|
|
122
|
+
workerName,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Plans land at docs/<worker>-plans/<topic>.md — symmetric with reviews.
|
|
127
|
+
const plansDir = `docs/${workerName}-plans`;
|
|
128
|
+
const planRel = `${plansDir}/${opts.topic}.md`;
|
|
129
|
+
await assertSafeToWrite(opts.repoRoot, planRel, opts.force ?? false);
|
|
130
|
+
|
|
131
|
+
const runFolder = await createRunFolder({
|
|
132
|
+
repoRoot: opts.repoRoot,
|
|
133
|
+
runsDir: config.runsDir,
|
|
134
|
+
topic: opts.topic,
|
|
135
|
+
type: "plan",
|
|
136
|
+
});
|
|
137
|
+
const createdAt = new Date().toISOString();
|
|
138
|
+
|
|
139
|
+
const memory = await assembleMemory(opts.repoRoot, agentConfig.memoryFile);
|
|
140
|
+
const systemPrompt = PLAN_SYSTEM_FRAMING + "\n\n" + memory.text;
|
|
141
|
+
const userMessage = buildPlanUserMessage(opts.topic, opts.requirement);
|
|
142
|
+
|
|
143
|
+
await writeRunInput(runFolder.absPath, userMessage);
|
|
144
|
+
|
|
145
|
+
const adapterOut = await adapter.execute({
|
|
146
|
+
role: "worker",
|
|
147
|
+
systemPrompt,
|
|
148
|
+
userMessage,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
await writeAgentOutput(runFolder.absPath, "worker", adapterOut.content);
|
|
152
|
+
|
|
153
|
+
// Compose the final plan file: orchestrator-owned header + worker body.
|
|
154
|
+
const header = [
|
|
155
|
+
`# Plan: ${opts.topic}`,
|
|
156
|
+
"",
|
|
157
|
+
`> Worker: \`${workerName}\` (${adapter.provider}, ${adapterOut.modelUsed})`,
|
|
158
|
+
`> Generated: ${new Date().toISOString()}`,
|
|
159
|
+
`> Tokens: ${adapterOut.tokensIn} in / ${adapterOut.tokensOut} out`,
|
|
160
|
+
`> Cost: $${adapterOut.costUsd.toFixed(4)} USD`,
|
|
161
|
+
`> Run folder: \`${runFolder.relPath}\``,
|
|
162
|
+
"",
|
|
163
|
+
].join("\n");
|
|
164
|
+
|
|
165
|
+
const footer = [
|
|
166
|
+
"",
|
|
167
|
+
"---",
|
|
168
|
+
"",
|
|
169
|
+
"## How this plan was produced",
|
|
170
|
+
"",
|
|
171
|
+
`The AlmightyGPT Plan stage produced this. Worker (\`${workerName}\`)`,
|
|
172
|
+
`read the requirement above + the project's memory files.`,
|
|
173
|
+
"",
|
|
174
|
+
"**Next stage:** cross-AI review with `almightygpt review --plan",
|
|
175
|
+
`${planRel} --reviewer codex --topic ${opts.topic}\` (Reviewer critiques`,
|
|
176
|
+
"this plan), then human approval, then implementation in your",
|
|
177
|
+
"preferred coding tool.",
|
|
178
|
+
].join("\n");
|
|
179
|
+
|
|
180
|
+
const planContent = header + adapterOut.content.trim() + footer;
|
|
181
|
+
const planAbs = join(opts.repoRoot, planRel);
|
|
182
|
+
await mkdir(dirname(planAbs), { recursive: true });
|
|
183
|
+
await writeFile(planAbs, planContent, "utf8");
|
|
184
|
+
|
|
185
|
+
const gitContext = await collectGitContext(opts.repoRoot);
|
|
186
|
+
await writeRunMetadata(runFolder.absPath, {
|
|
187
|
+
id: runFolder.id,
|
|
188
|
+
type: "plan",
|
|
189
|
+
createdAt,
|
|
190
|
+
finishedAt: new Date().toISOString(),
|
|
191
|
+
workspacePath: opts.repoRoot,
|
|
192
|
+
topic: opts.topic,
|
|
193
|
+
git: gitContext,
|
|
194
|
+
input: { source: "requirement-file" },
|
|
195
|
+
agents: [
|
|
196
|
+
{
|
|
197
|
+
name: workerName,
|
|
198
|
+
role: "worker",
|
|
199
|
+
provider: agentConfig.provider,
|
|
200
|
+
enabled: true,
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
adapterVersions: [],
|
|
204
|
+
status: "completed",
|
|
205
|
+
metrics: [
|
|
206
|
+
{
|
|
207
|
+
agent: workerName,
|
|
208
|
+
role: "worker",
|
|
209
|
+
provider: adapter.provider,
|
|
210
|
+
model: adapterOut.modelUsed,
|
|
211
|
+
tokensIn: adapterOut.tokensIn,
|
|
212
|
+
cachedTokensIn: adapterOut.cachedTokensIn ?? 0,
|
|
213
|
+
tokensOut: adapterOut.tokensOut,
|
|
214
|
+
costUsd: adapterOut.costUsd,
|
|
215
|
+
latencyMs: adapterOut.latencyMs,
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
totals: {
|
|
219
|
+
tokensIn: adapterOut.tokensIn,
|
|
220
|
+
tokensOut: adapterOut.tokensOut,
|
|
221
|
+
costUsd: adapterOut.costUsd,
|
|
222
|
+
latencyMs: adapterOut.latencyMs,
|
|
223
|
+
},
|
|
224
|
+
reviewPath: planRel,
|
|
225
|
+
budget: {
|
|
226
|
+
maxCostPerRunUsd: config.budget.maxCostPerRunUsd,
|
|
227
|
+
maxTokensPerRun: config.budget.maxTokensPerRun,
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
planPath: planRel,
|
|
233
|
+
planBytes: planContent.length,
|
|
234
|
+
worker: workerName,
|
|
235
|
+
provider: adapter.provider,
|
|
236
|
+
modelUsed: adapterOut.modelUsed,
|
|
237
|
+
tokensIn: adapterOut.tokensIn,
|
|
238
|
+
cachedTokensIn: adapterOut.cachedTokensIn ?? 0,
|
|
239
|
+
tokensOut: adapterOut.tokensOut,
|
|
240
|
+
costUsd: adapterOut.costUsd,
|
|
241
|
+
latencyMs: adapterOut.latencyMs,
|
|
242
|
+
memorySources: memory.sources,
|
|
243
|
+
memoryMissing: memory.missing,
|
|
244
|
+
runId: runFolder.id,
|
|
245
|
+
runFolder: runFolder.relPath,
|
|
246
|
+
};
|
|
247
|
+
}
|
package/src/runs/types.ts
CHANGED
|
@@ -14,7 +14,9 @@ export type RunType =
|
|
|
14
14
|
| "review-diff"
|
|
15
15
|
| "review-path"
|
|
16
16
|
| "review-requirement"
|
|
17
|
-
| "review-worker-reviewer"
|
|
17
|
+
| "review-worker-reviewer"
|
|
18
|
+
| "plan"
|
|
19
|
+
| "review-plan";
|
|
18
20
|
|
|
19
21
|
export type RunStatus = "running" | "completed" | "failed" | "aborted_budget";
|
|
20
22
|
|