pi-goal-list-loop-audit 0.31.1 → 0.31.3
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.
|
@@ -21,6 +21,10 @@ import type { SubagentModelStrategy } from "./goal-loop-subagents.js";
|
|
|
21
21
|
export interface Settings {
|
|
22
22
|
/** "provider/model-id" or bare "model-id". Unset → session model. */
|
|
23
23
|
auditorModel?: string;
|
|
24
|
+
/** v0.31.3: auto-swap target when the session model IS auditorModel —
|
|
25
|
+
* the verifier should differ from the executor. Unset = same model stands
|
|
26
|
+
* (with a loud one-line nudge). */
|
|
27
|
+
auditorModelFallback?: string;
|
|
24
28
|
auditorThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
25
29
|
/** Shell command run on goal complete / goal pause / loop stop; message passed as $1. */
|
|
26
30
|
notifyCmd?: string;
|
|
@@ -112,9 +116,10 @@ export interface Settings {
|
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
export const DEFAULT_SETTINGS: Settings = {
|
|
115
|
-
// Unset =
|
|
116
|
-
//
|
|
117
|
-
//
|
|
119
|
+
// Unset = "high" at the call site (v0.31.2). The auditor is the
|
|
120
|
+
// verification gate: its depth must NOT ride the session's coding-speed
|
|
121
|
+
// thinking dial (user 2026-07-31: "we should also select its thinking
|
|
122
|
+
// level — we don't keep switching it"). /glla thinking= overrides.
|
|
118
123
|
auditorThinkingLevel: undefined,
|
|
119
124
|
// v0.24.6: subagents inherit the session model by default — one quota
|
|
120
125
|
// pool, no surprise 403s from a pinned default agent's provider.
|
package/extensions/loops/goal.ts
CHANGED
|
@@ -1365,7 +1365,7 @@ async function retryStoredCompletionAudit(ctx: ExtensionContext, origin: "quota-
|
|
|
1365
1365
|
? "Manual /goal verify — running the isolated auditor now (no agent turn needed)."
|
|
1366
1366
|
: "Auditor quota window elapsed — retrying the audit with your stored completion claim (no agent turn needed).", "info");
|
|
1367
1367
|
const settings = loadSettings(liveCtx.cwd);
|
|
1368
|
-
const { model: auditorModel, error: modelError, via } = resolveAuditorModel(liveCtx, settings.auditorModel);
|
|
1368
|
+
const { model: auditorModel, error: modelError, via } = resolveAuditorModel(liveCtx, settings.auditorModel, settings.auditorModelFallback);
|
|
1369
1369
|
if (modelError) liveCtx.ui.notify(`Auditor model issue: ${modelError}`, "warning");
|
|
1370
1370
|
latestAuditProgress = { label: "quota-retry", lastEventAt: Date.now() };
|
|
1371
1371
|
completionAuditInFlight = true;
|
|
@@ -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 ??
|
|
1383
|
+
thinkingLevel: settings.auditorThinkingLevel ?? "high",
|
|
1384
1384
|
onProgress: (progress) => {
|
|
1385
1385
|
latestAuditProgress = { currentTool: progress.currentTool, label: progress.label, elapsedMs: progress.elapsedMs, lastEventAt: Date.now() };
|
|
1386
1386
|
refreshUI(liveCtx);
|
|
@@ -3173,7 +3173,7 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
3173
3173
|
}
|
|
3174
3174
|
updateGoal({ status: "auditing", pendingTasks: undefined }, ctx);
|
|
3175
3175
|
const settings = loadSettings(ctx.cwd);
|
|
3176
|
-
const { model: auditorModel, error: modelError, via } = resolveAuditorModel(ctx, settings.auditorModel);
|
|
3176
|
+
const { model: auditorModel, error: modelError, via } = resolveAuditorModel(ctx, settings.auditorModel, settings.auditorModelFallback);
|
|
3177
3177
|
if (modelError) {
|
|
3178
3178
|
ctx.ui.notify(`Auditor model issue: ${modelError}`, "warning");
|
|
3179
3179
|
}
|
|
@@ -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 ??
|
|
3191
|
+
thinkingLevel: settings.auditorThinkingLevel ?? "high",
|
|
3192
3192
|
signal: signal ?? undefined,
|
|
3193
3193
|
onProgress: (progress) => {
|
|
3194
3194
|
latestAuditProgress = {
|
|
@@ -4207,18 +4207,6 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
|
|
|
4207
4207
|
* the thinking level the user selected in pi; if none is set, audits run at
|
|
4208
4208
|
* "high" — the auditor is the verification gate, depth beats speed there.
|
|
4209
4209
|
*/
|
|
4210
|
-
function getSessionThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" {
|
|
4211
|
-
try {
|
|
4212
|
-
const level = extensionApi?.getThinkingLevel?.();
|
|
4213
|
-
if (level && ["off", "minimal", "low", "medium", "high", "xhigh"].includes(level)) {
|
|
4214
|
-
return level as "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
4215
|
-
}
|
|
4216
|
-
} catch {
|
|
4217
|
-
// fall through to the floor
|
|
4218
|
-
}
|
|
4219
|
-
return "high";
|
|
4220
|
-
}
|
|
4221
|
-
|
|
4222
4210
|
/**
|
|
4223
4211
|
* Resolve the auditor model (v0.6.2). The principle: **the user selects the
|
|
4224
4212
|
* model in pi; the auditor uses it.** The plugin never picks a model itself.
|
|
@@ -4232,39 +4220,67 @@ function getSessionThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high
|
|
|
4232
4220
|
* clear explanation (switch pi's model to a built-in provider, or set the
|
|
4233
4221
|
* override) — we do NOT silently substitute a different model.
|
|
4234
4222
|
*/
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
appendLedger(ctx.cwd, "auditor_model_fallback", { configured: trimmed, reason });
|
|
4248
|
-
ctx.ui.notify(`Auditor model "${trimmed}" is unavailable (${reason}) — falling back to the session model. Fix via /glla → Auditor model.`, "warning");
|
|
4249
|
-
return { model: sessionModel, via: "session-fallback" };
|
|
4250
|
-
}
|
|
4251
|
-
return { model: undefined, error: `${reason}: ${trimmed}` };
|
|
4252
|
-
};
|
|
4223
|
+
/** v0.31.3: the auditor model chain — pinned primary, pinned fallback,
|
|
4224
|
+
* session model LAST (user design 2026-07-31: "it can be the primary auditor
|
|
4225
|
+
* and the session model is always the last; we can have a fallback auditor
|
|
4226
|
+
* too" + "if the session model is the same as the auditor we auto fallback").
|
|
4227
|
+
* Two explicit pins and a cascade — no preference tables, no strategy
|
|
4228
|
+
* resolution (the v0.31.2 diverse-strategy machinery cost more complexity than it
|
|
4229
|
+
* bought; it lasted one version). Every hop is LOUD (ledger + notify): the
|
|
4230
|
+
* v0.9.12 no-SILENT-substitution law.
|
|
4231
|
+
*/
|
|
4232
|
+
function resolveAuditorModel(ctx: ExtensionContext, ref?: string, fallbackRef?: string): { model: any; error?: string; via?: string } {
|
|
4233
|
+
const sessionModel = ctx.model as any;
|
|
4234
|
+
const tryRef = (trimmed: string): { model?: any; reason?: string } => {
|
|
4253
4235
|
const slash = trimmed.indexOf("/");
|
|
4254
4236
|
if (slash > 0) {
|
|
4255
4237
|
const provider = trimmed.slice(0, slash);
|
|
4256
|
-
const
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4238
|
+
const model = ctx.modelRegistry.find(provider, trimmed.slice(slash + 1));
|
|
4239
|
+
if (!model) return { reason: "model not found" };
|
|
4240
|
+
// v0.29.17: an unkeyed provider counts as unavailable. (Quota-exhausted
|
|
4241
|
+
// keys stay on the quota-retry path — the model IS available there;
|
|
4242
|
+
// the key's window is the failure, not the model.)
|
|
4243
|
+
if (!ctx.modelRegistry.hasConfiguredAuth(model)) return { reason: `no configured auth for ${provider}` };
|
|
4244
|
+
return { model };
|
|
4261
4245
|
}
|
|
4262
4246
|
const matches = ctx.modelRegistry.getAvailable().filter((m: any) => m.id === trimmed || m.name === trimmed);
|
|
4263
|
-
|
|
4264
|
-
|
|
4247
|
+
return matches[0] ? { model: matches[0] } : { reason: "no available model matching" };
|
|
4248
|
+
};
|
|
4249
|
+
const isSession = (m: any) => sessionModel && m.provider === sessionModel.provider && m.id === sessionModel.id;
|
|
4250
|
+
const pins = [ref, fallbackRef].map((r) => r?.trim()).filter((r): r is string => !!r);
|
|
4251
|
+
for (let i = 0; i < pins.length; i++) {
|
|
4252
|
+
const pin = pins[i]!;
|
|
4253
|
+
const r = tryRef(pin);
|
|
4254
|
+
if (!r.model) {
|
|
4255
|
+
// Unavailable pin → cascade: next pin, then the session model (LOUD).
|
|
4256
|
+
appendLedger(ctx.cwd, "auditor_model_fallback", { configured: pin, reason: r.reason });
|
|
4257
|
+
ctx.ui.notify(`Auditor model "${pin}" is unavailable (${r.reason}) — ${i + 1 < pins.length ? "trying the fallback pin" : "falling back to the session model"}. Fix via /glla → Auditor model.`, "warning");
|
|
4258
|
+
continue;
|
|
4259
|
+
}
|
|
4260
|
+
if (isSession(r.model) && i + 1 < pins.length) {
|
|
4261
|
+
// The pin IS the session model — the verifier would be the executor's
|
|
4262
|
+
// own model; auto-swap down the chain (the user's move).
|
|
4263
|
+
appendLedger(ctx.cwd, "auditor_model_same_as_session", { model: `${r.model.provider}/${r.model.id}`, fallback: pins[i + 1] });
|
|
4264
|
+
ctx.ui.notify(`Session model IS the pinned auditor (${r.model.provider}/${r.model.id}) — auditor auto-swapped to ${pins[i + 1]} so the verifier differs.`, "info");
|
|
4265
|
+
continue;
|
|
4266
|
+
}
|
|
4267
|
+
if (isSession(r.model) && !fallbackRef?.trim()) {
|
|
4268
|
+
// Last resort reached and it IS the session model, with no fallback
|
|
4269
|
+
// ever pinned — the model stands (the session IS the last resort);
|
|
4270
|
+
// one loud nudge so the user can wire the swap.
|
|
4271
|
+
appendLedger(ctx.cwd, "auditor_model_same_as_session", { model: `${r.model.provider}/${r.model.id}`, fallback: null });
|
|
4272
|
+
ctx.ui.notify(`The session model IS the pinned auditor (${r.model.provider}/${r.model.id}) — pin a different /glla → Auditor fallback model so the verifier can differ.`, "warning");
|
|
4273
|
+
}
|
|
4274
|
+
return { model: r.model, via: i === 0 ? "setting" : "fallback-pin" };
|
|
4275
|
+
}
|
|
4276
|
+
if (sessionModel) {
|
|
4277
|
+
if (pins.length > 0) {
|
|
4278
|
+
appendLedger(ctx.cwd, "auditor_model_fallback", { configured: pins.join(" → "), reason: "all pins exhausted" });
|
|
4279
|
+
ctx.ui.notify("All pinned auditor models are unavailable — falling back to the session model. Fix via /glla → Auditor model.", "warning");
|
|
4280
|
+
return { model: sessionModel, via: "session-fallback" };
|
|
4281
|
+
}
|
|
4282
|
+
return { model: sessionModel, via: "session" };
|
|
4265
4283
|
}
|
|
4266
|
-
const sessionModel = ctx.model as any;
|
|
4267
|
-
if (sessionModel) return { model: sessionModel, via: "session" };
|
|
4268
4284
|
return { model: undefined, error: "no session model and no auditorModel configured — set one with /glla → Auditor model" };
|
|
4269
4285
|
}
|
|
4270
4286
|
|
|
@@ -4424,6 +4440,13 @@ export async function handleSettingChoice(id: string, ctx: ExtensionContext): Pr
|
|
|
4424
4440
|
if (pick.kind === "session") ctx.ui.notify("Auditor model override cleared — the auditor follows the pi session model.", "info");
|
|
4425
4441
|
return;
|
|
4426
4442
|
}
|
|
4443
|
+
case "auditorModelFallback": {
|
|
4444
|
+
const pick = await promptModelRef(ctx, "Auditor fallback model (used when the session model IS the auditor)", "provider/model-id — empty clears the fallback");
|
|
4445
|
+
if (pick === undefined) return;
|
|
4446
|
+
saveSettings("global", ctx.cwd, { auditorModelFallback: pick.kind === "session" ? undefined : pick.ref });
|
|
4447
|
+
if (pick.kind === "session") ctx.ui.notify("Auditor fallback cleared — a session on the pinned auditor model keeps that model.", "info");
|
|
4448
|
+
return;
|
|
4449
|
+
}
|
|
4427
4450
|
case "auditorThinkingLevel": {
|
|
4428
4451
|
const v = await ctx.ui.select("Auditor thinking level", ["off", "minimal", "low", "medium", "high", "xhigh"]);
|
|
4429
4452
|
if (v) saveSettings("global", ctx.cwd, { auditorThinkingLevel: v as Settings["auditorThinkingLevel"] });
|
|
@@ -169,13 +169,21 @@ export function buildSettingsRows(
|
|
|
169
169
|
sourceText: src("auditorModel"),
|
|
170
170
|
description: "provider/model override for the isolated auditor",
|
|
171
171
|
},
|
|
172
|
+
{
|
|
173
|
+
id: "auditorModelFallback",
|
|
174
|
+
section: "auditor",
|
|
175
|
+
label: "Auditor fallback model",
|
|
176
|
+
valueText: show("auditorModelFallback", "none — same-model sessions keep the pinned auditor"),
|
|
177
|
+
sourceText: src("auditorModelFallback"),
|
|
178
|
+
description: "auto-swap target when the session model IS the auditor model — the verifier should differ from the executor",
|
|
179
|
+
},
|
|
172
180
|
{
|
|
173
181
|
id: "auditorThinkingLevel",
|
|
174
182
|
section: "auditor",
|
|
175
183
|
label: "Auditor thinking",
|
|
176
|
-
valueText: show("auditorThinkingLevel", "session
|
|
184
|
+
valueText: show("auditorThinkingLevel", "high (fixed — never the session coding dial)"),
|
|
177
185
|
sourceText: src("auditorThinkingLevel"),
|
|
178
|
-
description: "thinking level for the auditor session",
|
|
186
|
+
description: "thinking level for the auditor session — unset = high (the verification gate does not ride the session thinking dial)",
|
|
179
187
|
},
|
|
180
188
|
{
|
|
181
189
|
id: "auditCap",
|
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.3",
|
|
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",
|