ultimate-pi 0.22.1 → 0.22.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/.pi/extensions/agt-kill-switch.ts +7 -1
- package/.pi/extensions/harness-plan-approval.ts +9 -1
- package/.pi/extensions/harness-run-context.ts +529 -84
- package/.pi/extensions/policy-gate.ts +15 -2
- package/.pi/harness/agents.manifest.json +3 -3
- package/.pi/harness/agents.policy.yaml +82 -3
- package/.pi/harness/specs/plan-task-clarification.schema.json +10 -1
- package/.pi/lib/agents-policy.mjs +42 -1
- package/.pi/lib/agt/build-evaluation-context.ts +3 -1
- package/.pi/lib/agt/kill-switch-state.ts +14 -0
- package/.pi/lib/agt/legacy-evaluate.ts +3 -1
- package/.pi/lib/ask-user/index.ts +2 -0
- package/.pi/lib/ask-user/merge-task-clarification.ts +5 -0
- package/.pi/lib/ask-user/policy.ts +23 -0
- package/.pi/lib/ask-user/presenters/glimpse.ts +8 -1
- package/.pi/lib/ask-user/presenters/headless.ts +15 -0
- package/.pi/lib/ask-user/presenters/select.ts +11 -2
- package/.pi/lib/ask-user/validate-core.mjs +16 -0
- package/.pi/lib/harness-artifact-gate.ts +75 -5
- package/.pi/lib/harness-repair-brief.ts +30 -4
- package/.pi/lib/harness-run-context.ts +804 -17
- package/.pi/lib/harness-schema-validate.ts +147 -38
- package/.pi/lib/harness-spawn-policy.ts +9 -0
- package/.pi/lib/harness-spawn-topology.ts +109 -7
- package/.pi/lib/harness-subagent-precheck.ts +21 -0
- package/.pi/lib/harness-subagent-submit-pipeline.ts +95 -21
- package/.pi/lib/harness-subagent-submit-register.ts +6 -1
- package/.pi/lib/harness-subagents-bridge.ts +3 -0
- package/.pi/lib/harness-yaml.ts +11 -3
- package/.pi/lib/plan-approval/create-plan.ts +2 -6
- package/.pi/lib/plan-debate-gate.ts +87 -0
- package/.pi/lib/plan-debate-lane.ts +8 -2
- package/.pi/lib/plan-human-gates.ts +322 -0
- package/.pi/prompts/harness-clear.md +25 -0
- package/.pi/prompts/harness-plan.md +4 -0
- package/.pi/scripts/generate-agents-policy-yaml.mjs +73 -7
- package/.pi/scripts/harness-reconcile-run-context.mjs +62 -0
- package/.pi/scripts/harness-schema-compile-verify.mjs +29 -0
- package/.pi/scripts/harness-verify.mjs +27 -0
- package/CHANGELOG.md +6 -0
- package/README.md +4 -0
- package/package.json +1 -1
|
@@ -7,11 +7,19 @@ import { access, readFile, stat } from "node:fs/promises";
|
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { parse as parseYaml } from "yaml";
|
|
9
9
|
import { validateAgainstHarnessSchema } from "./harness-schema-validate.js";
|
|
10
|
+
import { validateTaskClarificationHumanGate } from "./plan-human-gates.js";
|
|
10
11
|
import {
|
|
11
12
|
TASK_CLARIFICATION_ARTIFACT,
|
|
12
13
|
validateTaskClarificationDoc,
|
|
13
14
|
} from "./plan-task-clarification.js";
|
|
14
15
|
|
|
16
|
+
export interface ArtifactGateContext {
|
|
17
|
+
entries?: unknown[];
|
|
18
|
+
quick?: boolean;
|
|
19
|
+
taskSummary?: string;
|
|
20
|
+
lastOutcome?: string | null;
|
|
21
|
+
}
|
|
22
|
+
|
|
15
23
|
export interface ArtifactGateResult {
|
|
16
24
|
ok: boolean;
|
|
17
25
|
errors: string[];
|
|
@@ -25,11 +33,50 @@ const ARTIFACT_SCHEMA: Record<string, string> = {
|
|
|
25
33
|
"artifacts/stack.yaml": "plan-stack-brief.schema.json",
|
|
26
34
|
"artifacts/task-clarification.yaml": "plan-task-clarification.schema.json",
|
|
27
35
|
"artifacts/planning-context.yaml": "plan-planning-context.schema.json",
|
|
36
|
+
"artifacts/execution-plan-draft.yaml":
|
|
37
|
+
"plan-execution-plan-brief.schema.json",
|
|
28
38
|
"artifacts/eval-verdict.yaml": "eval-verdict.schema.json",
|
|
29
39
|
"artifacts/adversary-report.yaml": "adversary-report.schema.json",
|
|
30
40
|
"artifacts/sentrux-repair-plan.yaml": "sentrux-repair-plan.schema.json",
|
|
41
|
+
"artifacts/review-round-consolidated.yaml":
|
|
42
|
+
"plan-review-round-draft.schema.json",
|
|
31
43
|
};
|
|
32
44
|
|
|
45
|
+
/** Round-indexed debate artifacts (submit_* output). */
|
|
46
|
+
const ROUND_ARTIFACT_SCHEMA: Array<{ pattern: RegExp; schemaFile: string }> = [
|
|
47
|
+
{
|
|
48
|
+
pattern: /^artifacts\/hypothesis-validation-r\d+\.yaml$/,
|
|
49
|
+
schemaFile: "plan-hypothesis-eval.schema.json",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
pattern: /^artifacts\/validation-turn-r\d+\.yaml$/,
|
|
53
|
+
schemaFile: "plan-validation-turn.schema.json",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
pattern: /^artifacts\/adversary-brief-r\d+\.yaml$/,
|
|
57
|
+
schemaFile: "plan-adversary-brief.schema.json",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
pattern: /^artifacts\/sprint-audit-r\d+\.yaml$/,
|
|
61
|
+
schemaFile: "plan-sprint-audit-turn.schema.json",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
pattern: /^artifacts\/review-round-r\d+\.yaml$/,
|
|
65
|
+
schemaFile: "plan-review-round-draft.schema.json",
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
export function resolveArtifactSchemaFile(
|
|
70
|
+
normalizedPath: string,
|
|
71
|
+
): string | undefined {
|
|
72
|
+
const exact = ARTIFACT_SCHEMA[normalizedPath];
|
|
73
|
+
if (exact) return exact;
|
|
74
|
+
for (const entry of ROUND_ARTIFACT_SCHEMA) {
|
|
75
|
+
if (entry.pattern.test(normalizedPath)) return entry.schemaFile;
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
33
80
|
const PREREQUISITE_ORDER: Record<string, string[]> = {
|
|
34
81
|
"artifacts/planning-context.yaml": [TASK_CLARIFICATION_ARTIFACT],
|
|
35
82
|
"artifacts/hypothesis.yaml": ["artifacts/decomposition.yaml"],
|
|
@@ -41,6 +88,12 @@ const PREREQUISITE_ORDER: Record<string, string[]> = {
|
|
|
41
88
|
"artifacts/decomposition.yaml",
|
|
42
89
|
"artifacts/hypothesis.yaml",
|
|
43
90
|
],
|
|
91
|
+
"artifacts/execution-plan-draft.yaml": [
|
|
92
|
+
"artifacts/decomposition.yaml",
|
|
93
|
+
"artifacts/hypothesis.yaml",
|
|
94
|
+
"artifacts/implementation-research.yaml",
|
|
95
|
+
"artifacts/stack.yaml",
|
|
96
|
+
],
|
|
44
97
|
};
|
|
45
98
|
|
|
46
99
|
async function fileExists(path: string): Promise<boolean> {
|
|
@@ -121,6 +174,7 @@ export async function validateHarnessArtifactFile(
|
|
|
121
174
|
runRoot: string,
|
|
122
175
|
relPath: string,
|
|
123
176
|
specsDir: string,
|
|
177
|
+
gateCtx?: ArtifactGateContext & { skipPrerequisites?: boolean },
|
|
124
178
|
): Promise<ArtifactGateResult> {
|
|
125
179
|
const normalized = relPath.replace(/\\/g, "/");
|
|
126
180
|
const abs = join(runRoot, normalized);
|
|
@@ -152,7 +206,7 @@ export async function validateHarnessArtifactFile(
|
|
|
152
206
|
);
|
|
153
207
|
}
|
|
154
208
|
|
|
155
|
-
const schemaFile =
|
|
209
|
+
const schemaFile = resolveArtifactSchemaFile(normalized);
|
|
156
210
|
if (doc && schemaFile) {
|
|
157
211
|
const validation = await validateAgainstHarnessSchema(
|
|
158
212
|
specsDir,
|
|
@@ -171,16 +225,30 @@ export async function validateHarnessArtifactFile(
|
|
|
171
225
|
if (!clar.ok) {
|
|
172
226
|
errors.push(...clar.errors.map((e) => `${normalized}: ${e}`));
|
|
173
227
|
}
|
|
228
|
+
const human = validateTaskClarificationHumanGate(
|
|
229
|
+
gateCtx?.entries ?? [],
|
|
230
|
+
doc,
|
|
231
|
+
{
|
|
232
|
+
quick: gateCtx?.quick,
|
|
233
|
+
taskSummary: gateCtx?.taskSummary,
|
|
234
|
+
allowFollowUpMessage: gateCtx?.lastOutcome === "needs_clarification",
|
|
235
|
+
},
|
|
236
|
+
);
|
|
237
|
+
if (!human.ok) {
|
|
238
|
+
errors.push(...human.errors.map((e) => `${normalized}: ${e}`));
|
|
239
|
+
}
|
|
174
240
|
}
|
|
175
241
|
|
|
176
242
|
if (doc) {
|
|
177
243
|
errors.push(...(await validatePlanningContextArtifact(normalized, doc)));
|
|
178
244
|
}
|
|
179
245
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
246
|
+
if (!gateCtx?.skipPrerequisites) {
|
|
247
|
+
const prereqs = PREREQUISITE_ORDER[normalized] ?? [];
|
|
248
|
+
errors.push(
|
|
249
|
+
...(await validateArtifactPrerequisites(runRoot, normalized, prereqs)),
|
|
250
|
+
);
|
|
251
|
+
}
|
|
184
252
|
|
|
185
253
|
return { ok: errors.length === 0, errors };
|
|
186
254
|
}
|
|
@@ -189,6 +257,7 @@ export async function validateHarnessArtifactPaths(
|
|
|
189
257
|
runRoot: string,
|
|
190
258
|
paths: string[],
|
|
191
259
|
specsDir: string,
|
|
260
|
+
gateCtx?: ArtifactGateContext,
|
|
192
261
|
): Promise<{
|
|
193
262
|
ok: boolean;
|
|
194
263
|
present: string[];
|
|
@@ -205,6 +274,7 @@ export async function validateHarnessArtifactPaths(
|
|
|
205
274
|
runRoot,
|
|
206
275
|
normalized,
|
|
207
276
|
specsDir,
|
|
277
|
+
gateCtx,
|
|
208
278
|
);
|
|
209
279
|
if (gate.errors.some((e) => e.startsWith("missing file"))) {
|
|
210
280
|
missing.push(normalized);
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import {
|
|
7
|
+
harnessRunsRoot,
|
|
8
|
+
type RemediationClass,
|
|
9
|
+
remediationClassFromEvalVerdict,
|
|
10
|
+
} from "./harness-run-context.js";
|
|
11
|
+
import { readYamlFile, writeYamlFile } from "./harness-yaml.js";
|
|
8
12
|
|
|
9
13
|
const REPAIR_BRIEF_SCHEMA = "1.0.0";
|
|
10
14
|
|
|
@@ -72,8 +76,15 @@ export async function synthesizeRepairBrief(
|
|
|
72
76
|
|
|
73
77
|
const remediation =
|
|
74
78
|
(typeof review?.remediation_class === "string" &&
|
|
75
|
-
review.remediation_class) ||
|
|
76
|
-
|
|
79
|
+
(review.remediation_class as RemediationClass)) ||
|
|
80
|
+
remediationClassFromEvalVerdict(
|
|
81
|
+
evalDoc as {
|
|
82
|
+
status?: string;
|
|
83
|
+
recommended_action?: string;
|
|
84
|
+
failed_checks?: string[];
|
|
85
|
+
},
|
|
86
|
+
) ||
|
|
87
|
+
"inconclusive";
|
|
77
88
|
|
|
78
89
|
const sourceArtifacts = buildSourceArtifacts(input, planRel, {
|
|
79
90
|
evalDoc,
|
|
@@ -132,6 +143,21 @@ export async function synthesizeRepairBrief(
|
|
|
132
143
|
return brief;
|
|
133
144
|
}
|
|
134
145
|
|
|
146
|
+
export async function ensureRepairBriefOnDisk(
|
|
147
|
+
input: SynthesizeRepairBriefInput,
|
|
148
|
+
): Promise<boolean> {
|
|
149
|
+
const runRoot = join(harnessRunsRoot(input.projectRoot), input.runId);
|
|
150
|
+
const rel = "artifacts/repair-brief.yaml";
|
|
151
|
+
try {
|
|
152
|
+
await readYamlFile(join(runRoot, rel), "repair-brief");
|
|
153
|
+
return false;
|
|
154
|
+
} catch {
|
|
155
|
+
const brief = await synthesizeRepairBrief(input);
|
|
156
|
+
await writeYamlFile(join(runRoot, rel), brief);
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
135
161
|
function buildSourceArtifacts(
|
|
136
162
|
input: SynthesizeRepairBriefInput,
|
|
137
163
|
planRel: string,
|