pi-goal-list-loop-audit 0.31.7 → 0.31.9
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/extensions/goal-loop-auditor.ts +1 -0
- package/extensions/goal-settings.ts +1 -1
- package/extensions/loops/goal.ts +38 -11
- package/package.json +1 -1
- package/prompts/goal-loop-continuation.md +1 -0
- package/prompts/goal-loop-forever-metricless.md +2 -0
- package/prompts/goal-loop-forever.md +2 -0
|
@@ -163,6 +163,7 @@ function buildGoalAuditorPrompt(goal: Goal, completionSummary: string | null | u
|
|
|
163
163
|
"6. When you disapprove, end the report body with a '## Required fixes' section: one line per blocking gap, each an actionable instruction the executor can complete (most critical first). This tail is what the executor sees first — make it self-sufficient.",
|
|
164
164
|
"7. Write the report in English, and never emit <think> blocks or fragments — your reasoning stays private; the report is the verdict plus evidence.",
|
|
165
165
|
"8. End with exactly <approved/> only if the objective is truly complete; <impossible>reason</impossible> if it can never be satisfied as stated; otherwise end with exactly <disapproved/>.",
|
|
166
|
+
"9. Reject-class pattern (v0.31.9, field-observed fork bomb): a test that invokes the project's whole test runner from INSIDE the suite (a test file spawning `bun test`/`npm test`/`pytest`/etc. on a path the runner itself collects) is unbounded recursion — 521 processes, load 28, a full system crash; a `timeout` wrapper kills processes, not recursion depth. Disapprove unless the recursion is provably depth-capped (e.g. an env sentinel checked before spawning).",
|
|
166
167
|
...(goal.verificationContract?.trim()
|
|
167
168
|
? [
|
|
168
169
|
"",
|
|
@@ -31,7 +31,7 @@ export interface Settings {
|
|
|
31
31
|
* the first-order defense either way; diversity is the second-order one
|
|
32
32
|
* the user may deliberately trade away. */
|
|
33
33
|
auditorSameSessionSwap?: boolean;
|
|
34
|
-
auditorThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
34
|
+
auditorThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
35
35
|
/** Shell command run on goal complete / goal pause / loop stop; message passed as $1. */
|
|
36
36
|
notifyCmd?: string;
|
|
37
37
|
/** Per-goal token budget; crossing it pauses the goal. Off by default
|
package/extensions/loops/goal.ts
CHANGED
|
@@ -1380,7 +1380,7 @@ async function retryStoredCompletionAudit(ctx: ExtensionContext, origin: "quota-
|
|
|
1380
1380
|
completionSummary: claim.completionSummary,
|
|
1381
1381
|
verificationSummary: claim.verificationSummary,
|
|
1382
1382
|
model: auditorModel,
|
|
1383
|
-
thinkingLevel: settings.auditorThinkingLevel ?? "high",
|
|
1383
|
+
thinkingLevel: (settings.auditorThinkingLevel ?? "high") as any, // may be "max" — pi ≥0.83 understands it; the dev-types predate it
|
|
1384
1384
|
onProgress: (progress) => {
|
|
1385
1385
|
latestAuditProgress = { currentTool: progress.currentTool, label: progress.label, elapsedMs: progress.elapsedMs, lastEventAt: Date.now() };
|
|
1386
1386
|
refreshUI(liveCtx);
|
|
@@ -3188,7 +3188,7 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
3188
3188
|
completionSummary: p.completionSummary,
|
|
3189
3189
|
verificationSummary: p.verificationSummary,
|
|
3190
3190
|
model: auditorModel,
|
|
3191
|
-
thinkingLevel: settings.auditorThinkingLevel ?? "high",
|
|
3191
|
+
thinkingLevel: (settings.auditorThinkingLevel ?? "high") as any, // may be "max" — pi ≥0.83 understands it; the dev-types predate it
|
|
3192
3192
|
signal: signal ?? undefined,
|
|
3193
3193
|
onProgress: (progress) => {
|
|
3194
3194
|
latestAuditProgress = {
|
|
@@ -4229,6 +4229,24 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
4229
4229
|
* bought; it lasted one version). Every hop is LOUD (ledger + notify): the
|
|
4230
4230
|
* v0.9.12 no-SILENT-substitution law.
|
|
4231
4231
|
*/
|
|
4232
|
+
/** v0.31.8: the auditor thinking options are derived from the PICKED
|
|
4233
|
+
* model, not a hardcoded list — same rule as pi's own thinking selector
|
|
4234
|
+
* (pi-ai getSupportedThinkingLevels): non-reasoning models expose only
|
|
4235
|
+
* "off"; xhigh/max exist only when the model maps them (thinkingLevelMap).
|
|
4236
|
+
* Replicated inline so the extension's older pi-ai dev-types don't matter —
|
|
4237
|
+
* the fields are read at runtime from the user's installed pi. */
|
|
4238
|
+
function auditorThinkingLevels(model: any): string[] {
|
|
4239
|
+
const ALL = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
4240
|
+
if (!model?.reasoning) return ["off"];
|
|
4241
|
+
const map = model.thinkingLevelMap as Record<string, string | null> | undefined;
|
|
4242
|
+
return ALL.filter((level) => {
|
|
4243
|
+
const mapped = map?.[level];
|
|
4244
|
+
if (mapped === null) return false;
|
|
4245
|
+
if (level === "xhigh" || level === "max") return mapped !== undefined;
|
|
4246
|
+
return true;
|
|
4247
|
+
});
|
|
4248
|
+
}
|
|
4249
|
+
|
|
4232
4250
|
function resolveAuditorModel(ctx: ExtensionContext, ref?: string, fallbackRef?: string, sameSessionSwap = true): { model: any; error?: string; via?: string } {
|
|
4233
4251
|
const sessionModel = ctx.model as any;
|
|
4234
4252
|
const tryRef = (trimmed: string): { model?: any; reason?: string } => {
|
|
@@ -4443,17 +4461,26 @@ export async function handleSettingChoice(id: string, ctx: ExtensionContext): Pr
|
|
|
4443
4461
|
// v0.31.7: the select must be UNMISTAKABLY the auditor's — the user
|
|
4444
4462
|
// Esc'd through it because it read like pi's own (general) thinking
|
|
4445
4463
|
// dialog, and nothing was ever saved.
|
|
4464
|
+
// v0.31.8: the options come from the PICKED MODEL's info (user: "we
|
|
4465
|
+
// are not using the model information cause it has no max") — a model
|
|
4466
|
+
// that maps xhigh/max offers them; a non-reasoning model is told, not asked.
|
|
4467
|
+
let pickedModel: any = pick.kind === "session" ? (ctx.model as any) : undefined;
|
|
4468
|
+
if (pick.kind === "ref" && pick.ref) {
|
|
4469
|
+
const parts = pick.ref.split("/");
|
|
4470
|
+
try {
|
|
4471
|
+
pickedModel = parts.length === 2 ? (ctx.modelRegistry?.find?.(parts[0]!, parts[1]!) as any) : (ctx.modelRegistry?.getAvailable?.().filter((m: any) => m.id === pick.ref)[0] as any);
|
|
4472
|
+
} catch { pickedModel = undefined; } // levels fall back to the full ladder below
|
|
4473
|
+
}
|
|
4446
4474
|
const curThinking = loadSettings(ctx.cwd).auditorThinkingLevel;
|
|
4475
|
+
const levels = auditorThinkingLevels(pickedModel);
|
|
4476
|
+
if (levels.length <= 1) {
|
|
4477
|
+
ctx.ui.notify(`Auditor model: ${pick.kind === "session" ? "session model (override cleared)" : pick.ref} — this model exposes no thinking levels (auditor runs with thinking off).`, "info");
|
|
4478
|
+
return;
|
|
4479
|
+
}
|
|
4480
|
+
const DESCR: Record<string, string> = { off: "no reasoning", minimal: "~1k tokens", low: "~2k tokens", medium: "~8k tokens", high: "the default; the gate must not ride the session's coding dial", xhigh: "~32k tokens", max: "maximum reasoning" };
|
|
4447
4481
|
const t = await ctx.ui.select(
|
|
4448
4482
|
"Auditor thinking — ISOLATED auditor session ONLY (your session model's thinking is untouched)",
|
|
4449
|
-
[
|
|
4450
|
-
`high — the default; the gate must not ride the session's coding dial${curThinking === undefined || curThinking === "high" ? " (current)" : ""}`,
|
|
4451
|
-
`medium${curThinking === "medium" ? " (current)" : ""}`,
|
|
4452
|
-
`low${curThinking === "low" ? " (current)" : ""}`,
|
|
4453
|
-
`minimal${curThinking === "minimal" ? " (current)" : ""}`,
|
|
4454
|
-
`xhigh${curThinking === "xhigh" ? " (current)" : ""}`,
|
|
4455
|
-
`off${curThinking === "off" ? " (current)" : ""}`,
|
|
4456
|
-
],
|
|
4483
|
+
levels.map((lv) => `${lv} — ${DESCR[lv] ?? ""}${lv === "high" && curThinking === undefined ? " (current)" : curThinking === lv ? " (current)" : ""}`),
|
|
4457
4484
|
);
|
|
4458
4485
|
if (t) saveSettings("global", ctx.cwd, { auditorThinkingLevel: t.split(" ")[0] as Settings["auditorThinkingLevel"] });
|
|
4459
4486
|
ctx.ui.notify(`Auditor model: ${pick.kind === "session" ? "session model (override cleared)" : pick.ref}${t ? ` · thinking ${t.split(" ")[0]}` : ""}`, "info");
|
|
@@ -5370,7 +5397,7 @@ async function cmdSettings(args: string, ctx: ExtensionContext): Promise<void> {
|
|
|
5370
5397
|
}
|
|
5371
5398
|
}
|
|
5372
5399
|
} else if (key === "thinking" || key === "auditorthinkinglevel") {
|
|
5373
|
-
if (["off", "minimal", "low", "medium", "high", "xhigh"].includes(value)) {
|
|
5400
|
+
if (["off", "minimal", "low", "medium", "high", "xhigh", "max"].includes(value)) {
|
|
5374
5401
|
patch.auditorThinkingLevel = value as Settings["auditorThinkingLevel"];
|
|
5375
5402
|
changed = true;
|
|
5376
5403
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-goal-list-loop-audit",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.9",
|
|
4
4
|
"description": "Goal. Loop. Audit. Done. \u2014 a pi-coding-agent extension that supervises long-running work, with isolated auditor on each completion. Beat bamboozling by design: the auditor runs in a fresh session with no extensions, no skills, no editor \u2014 only the read tools needed to verify your goal.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "dracon",
|
|
@@ -151,6 +151,7 @@ When the user must CHOOSE between paths, use `pause_goal` with `kind="decision"`
|
|
|
151
151
|
- **Do not modify the objective silently.** The objective is the user's; if it has drifted from what makes sense, use `complete_goal`'s `newObjective` at completion time, or `pause_goal` and propose a `/goal tweak` mid-flight — never just work on something else and claim the original.
|
|
152
152
|
- **Do not pretend completion.** If verification evidence is missing, call `pause_goal` instead of `complete_goal`.
|
|
153
153
|
- **Git discipline: never touch identity or branches.** Commit with the repo's configured identity exactly as-is — no `git config user.*`, no per-commit `git -c user.name=…` overrides, no invented identities like `<task>-agent <…@local>` (field-observed: a phase agent branded itself `phase-e-agent <phase-e@local>` and polluted the history). No creating or switching branches either — commit on the branch you found (usually `main`) and push to its upstream. If git refuses a commit for a missing identity, STOP and ask the user — never invent one.
|
|
154
|
+
- **Never run the suite from inside the suite.** A test must not spawn the project's whole test runner (`bun test`, `npm test`, `pytest`…) from a file the runner itself collects — unbounded recursion is a fork bomb (field-observed 2026-07-31: 521 processes, load 28, a full system crash). Count test files or parse manifests; never re-invoke the runner on its own suite.
|
|
154
155
|
- **Do not polish doorknobs.** If you are out of work and the goal is satisfied, call `complete_goal` instead of inventing a side-improvement.
|
|
155
156
|
- **Do not give up early.** If a task is hard, run it down properly. The auditor will catch doorknobs; the agent's job is to do the real work.
|
|
156
157
|
|
|
@@ -54,3 +54,5 @@ ${STRATEGY_NOTE}
|
|
|
54
54
|
- The spec is ALIVE: if the target needs sharpening, call
|
|
55
55
|
propose_loop_refine with your rationale — the user confirms or rejects.
|
|
56
56
|
${BOUNDS_NOTE}
|
|
57
|
+
|
|
58
|
+
- **Never run the suite from inside the suite.** A test must not spawn the project's whole test runner (`bun test`, `npm test`, `pytest`…) from a file the runner itself collects — unbounded recursion is a fork bomb (field-observed 2026-07-31: 521 processes, load 28, a full system crash). Count test files or parse manifests; never re-invoke the runner on its own suite.
|
|
@@ -57,3 +57,5 @@ ${STRATEGY_NOTE}
|
|
|
57
57
|
when the metric plateaus. Keep making real improvements.
|
|
58
58
|
- If the measure command itself is broken (errors, no number), fix whatever
|
|
59
59
|
your last change broke — that counts as a stall.
|
|
60
|
+
|
|
61
|
+
- **Never run the suite from inside the suite.** A test must not spawn the project's whole test runner (`bun test`, `npm test`, `pytest`…) from a file the runner itself collects — unbounded recursion is a fork bomb (field-observed 2026-07-31: 521 processes, load 28, a full system crash). Count test files or parse manifests; never re-invoke the runner on its own suite.
|