pi-goal-list-loop-audit 0.31.1 → 0.31.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.
@@ -112,9 +112,10 @@ export interface Settings {
112
112
  }
113
113
 
114
114
  export const DEFAULT_SETTINGS: Settings = {
115
- // Unset = follow the pi session thinking level (user selects thinking in
116
- // pi, auditor follows), floor "high" the auditor is the verification
117
- // gate, depth is worth more there than speed. /glla thinking= overrides.
115
+ // Unset = "high" at the call site (v0.31.2). The auditor is the
116
+ // verification gate: its depth must NOT ride the session's coding-speed
117
+ // thinking dial (user 2026-07-31: "we should also select its thinking
118
+ // level — we don't keep switching it"). /glla thinking= overrides.
118
119
  auditorThinkingLevel: undefined,
119
120
  // v0.24.6: subagents inherit the session model by default — one quota
120
121
  // pool, no surprise 403s from a pinned default agent's provider.
@@ -154,6 +154,7 @@ import {
154
154
  } from "../settings-menu.js";
155
155
  import {
156
156
  buildModelPickItems,
157
+ pickDiverseAuditorModel,
157
158
  ModelPickerComponent,
158
159
  type ModelPickItem,
159
160
  } from "../model-picker.js";
@@ -1380,7 +1381,7 @@ async function retryStoredCompletionAudit(ctx: ExtensionContext, origin: "quota-
1380
1381
  completionSummary: claim.completionSummary,
1381
1382
  verificationSummary: claim.verificationSummary,
1382
1383
  model: auditorModel,
1383
- thinkingLevel: settings.auditorThinkingLevel ?? getSessionThinkingLevel(),
1384
+ thinkingLevel: settings.auditorThinkingLevel ?? "high",
1384
1385
  onProgress: (progress) => {
1385
1386
  latestAuditProgress = { currentTool: progress.currentTool, label: progress.label, elapsedMs: progress.elapsedMs, lastEventAt: Date.now() };
1386
1387
  refreshUI(liveCtx);
@@ -3188,7 +3189,7 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
3188
3189
  completionSummary: p.completionSummary,
3189
3190
  verificationSummary: p.verificationSummary,
3190
3191
  model: auditorModel,
3191
- thinkingLevel: settings.auditorThinkingLevel ?? getSessionThinkingLevel(),
3192
+ thinkingLevel: settings.auditorThinkingLevel ?? "high",
3192
3193
  signal: signal ?? undefined,
3193
3194
  onProgress: (progress) => {
3194
3195
  latestAuditProgress = {
@@ -4207,18 +4208,6 @@ function registerAgentTools(pi: any, ctx: ExtensionContext): void {
4207
4208
  * the thinking level the user selected in pi; if none is set, audits run at
4208
4209
  * "high" — the auditor is the verification gate, depth beats speed there.
4209
4210
  */
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
4211
  /**
4223
4212
  * Resolve the auditor model (v0.6.2). The principle: **the user selects the
4224
4213
  * model in pi; the auditor uses it.** The plugin never picks a model itself.
@@ -4235,6 +4224,24 @@ function getSessionThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high
4235
4224
  function resolveAuditorModel(ctx: ExtensionContext, ref?: string): { model: any; error?: string; via?: string } {
4236
4225
  if (ref && ref.trim()) {
4237
4226
  const trimmed = ref.trim();
4227
+ // v0.31.2: "diverse" — the cross-vendor auditor (user design 2026-07-31:
4228
+ // "there is benefit to have a different auditor"). Independent blind
4229
+ // spots + a separate quota pool; the fresh auditor session shares no
4230
+ // prompt cache anyway, so cross-vendor costs nothing extra.
4231
+ if (trimmed.toLowerCase() === "diverse") {
4232
+ const sessionModel = ctx.model as any;
4233
+ const available = ctx.modelRegistry
4234
+ .getAvailable()
4235
+ .filter((m: any) => ctx.modelRegistry.hasConfiguredAuth(m));
4236
+ const pick = pickDiverseAuditorModel(available, sessionModel?.provider);
4237
+ if (pick) return { model: pick, via: "diverse" };
4238
+ if (sessionModel) {
4239
+ appendLedger(ctx.cwd, "auditor_model_fallback", { configured: "diverse", reason: "no configured-auth model outside the session's provider" });
4240
+ ctx.ui.notify("Auditor model \"diverse\" found no model outside the session's provider — falling back to the session model (LOUD fallback; pin one via /glla → Auditor model).", "warning");
4241
+ return { model: sessionModel, via: "session-fallback" };
4242
+ }
4243
+ return { model: undefined, error: "auditorModel \"diverse\": no configured-auth model at all" };
4244
+ }
4238
4245
  // v0.29.17: an unavailable configured model (unknown id, or a provider
4239
4246
  // with no configured auth) falls back LOUDLY to the session model —
4240
4247
  // user request: "fall back to the session if unavailable". The v0.9.12
@@ -4355,6 +4362,7 @@ async function promptModelRef(
4355
4362
  ctx: ExtensionContext,
4356
4363
  title: string,
4357
4364
  emptyLabel: string,
4365
+ extraTop: ModelPickItem[] = [],
4358
4366
  ): Promise<{ kind: "session" } | { kind: "ref"; ref: string } | undefined> {
4359
4367
  if (typeof (ctx.ui as { custom?: unknown }).custom !== "function" || !ctx.modelRegistry) {
4360
4368
  const v = await ctx.ui.input(title, "provider/model-id — empty keeps the default");
@@ -4366,7 +4374,7 @@ async function promptModelRef(
4366
4374
  const models = ctx.modelRegistry
4367
4375
  .getAvailable()
4368
4376
  .filter((m: any) => ctx.modelRegistry.hasConfiguredAuth(m));
4369
- const items = buildModelPickItems(models, sessionLabel);
4377
+ const items = buildModelPickItems(models, sessionLabel, extraTop);
4370
4378
  const pick = await ctx.ui.custom<ModelPickItem | undefined>((tui, theme, keybindings, done) => {
4371
4379
  return new ModelPickerComponent({ title, items }, () => tui.requestRender(), theme, keybindings, done);
4372
4380
  });
@@ -4418,10 +4426,21 @@ export async function handleSettingChoice(id: string, ctx: ExtensionContext): Pr
4418
4426
  return;
4419
4427
  }
4420
4428
  case "auditorModel": {
4421
- const pick = await promptModelRef(ctx, "Auditor model override", "provider/model-id empty keeps the pi session model");
4429
+ // v0.31.2: "diverse" sits at the top — the cross-vendor auditor
4430
+ // (independent blind spots + a separate quota pool from the coding
4431
+ // session). Picked like a model; resolution happens per-audit so
4432
+ // provider availability is re-checked every time.
4433
+ const diverseItem: ModelPickItem = {
4434
+ kind: "model",
4435
+ ref: "diverse",
4436
+ label: "diverse — cross-vendor auditor: a different provider than the session, picked fresh per audit (Recommended)",
4437
+ searchText: "diverse cross vendor independent different provider quota strategy recommended",
4438
+ };
4439
+ const pick = await promptModelRef(ctx, "Auditor model override", "provider/model-id — empty keeps the pi session model", [diverseItem]);
4422
4440
  if (pick === undefined) return;
4423
4441
  saveSettings("global", ctx.cwd, { auditorModel: pick.kind === "session" ? undefined : pick.ref });
4424
4442
  if (pick.kind === "session") ctx.ui.notify("Auditor model override cleared — the auditor follows the pi session model.", "info");
4443
+ if (pick.kind === "ref" && pick.ref === "diverse") ctx.ui.notify("Auditor model: DIVERSE — each audit picks a configured model outside the session's provider (deepseek ↔ MiniMax first).", "info");
4425
4444
  return;
4426
4445
  }
4427
4446
  case "auditorThinkingLevel": {
@@ -41,7 +41,7 @@ export interface RegistryModelLike {
41
41
  /** Build the picker's static item list from registry models (already
42
42
  * filtered to configured-auth providers by the caller). Session row first,
43
43
  * manual-entry row last; models sorted by provider then id. */
44
- export function buildModelPickItems(models: RegistryModelLike[], sessionLabel: string): ModelPickItem[] {
44
+ export function buildModelPickItems(models: RegistryModelLike[], sessionLabel: string, extraTop: ModelPickItem[] = []): ModelPickItem[] {
45
45
  const sorted = [...models].sort((a, b) =>
46
46
  a.provider === b.provider ? a.id.localeCompare(b.id) : a.provider.localeCompare(b.provider),
47
47
  );
@@ -51,6 +51,7 @@ export function buildModelPickItems(models: RegistryModelLike[], sessionLabel: s
51
51
  label: `session model (${sessionLabel}) — clear the override`,
52
52
  searchText: "session model default clear override follow",
53
53
  },
54
+ ...extraTop,
54
55
  ...sorted.map((m) => {
55
56
  const ref = `${m.provider}/${m.id}`;
56
57
  return {
@@ -206,3 +207,47 @@ export class ModelPickerComponent {
206
207
 
207
208
  // Re-export for callers that only need the width helper's type signature.
208
209
  export { visibleWidth };
210
+
211
+ /** v0.31.2: provider preference for the "diverse" auditor strategy (user
212
+ * design 2026-07-31: "there is benefit to have a different auditor — M3's
213
+ * auditor could be deepseek and vice versa"). A cross-vendor auditor reads
214
+ * the executor's claims with INDEPENDENT blind spots (same-family models
215
+ * share failure modes), and it spends a DIFFERENT provider's quota pool —
216
+ * audits stop eating the coding session's MiniMax window. The auditor is
217
+ * already a fresh session (no prompt-cache sharing), so cross-vendor costs
218
+ * nothing in cache terms.
219
+ *
220
+ * Order: deepseek-via-openrouter first, MiniMax second, then the other
221
+ * providers seen on this rig. The session's own provider is EXCLUDED
222
+ * entirely (openrouter hosts everything — family-level reasoning about its
223
+ * catalogue isn't reliable, so exclusion is at provider granularity).
224
+ */
225
+ export const DIVERSE_AUDITOR_PREFERENCE: Array<{ provider: string; match?: string }> = [
226
+ { provider: "openrouter", match: "deepseek/deepseek-chat" },
227
+ { provider: "openrouter", match: "deepseek" },
228
+ { provider: "minimax", match: "MiniMax-M3" },
229
+ { provider: "minimax" },
230
+ { provider: "kimi-coding" },
231
+ { provider: "kimi" },
232
+ { provider: "xai-auth" },
233
+ { provider: "opencode" },
234
+ { provider: "zenmux" },
235
+ ];
236
+
237
+ /** Pure selection: the first preference entry (outside the session's
238
+ * provider) with at least one available model wins; within an entry the
239
+ * models arrive pre-filtered (auth checked by the caller) and sorted.
240
+ * Returns undefined when nothing outside the session provider is available
241
+ * — the caller falls back LOUDLY to the session model.
242
+ */
243
+ export function pickDiverseAuditorModel(
244
+ models: RegistryModelLike[],
245
+ sessionProvider: string | undefined,
246
+ ): RegistryModelLike | undefined {
247
+ for (const pref of DIVERSE_AUDITOR_PREFERENCE) {
248
+ if (pref.provider === sessionProvider) continue;
249
+ const hit = models.find((m) => m.provider === pref.provider && (!pref.match || m.id.includes(pref.match)));
250
+ if (hit) return hit;
251
+ }
252
+ return undefined;
253
+ }
@@ -173,9 +173,9 @@ export function buildSettingsRows(
173
173
  id: "auditorThinkingLevel",
174
174
  section: "auditor",
175
175
  label: "Auditor thinking",
176
- valueText: show("auditorThinkingLevel", "session, floor high"),
176
+ valueText: show("auditorThinkingLevel", "high (fixed — never the session coding dial)"),
177
177
  sourceText: src("auditorThinkingLevel"),
178
- description: "thinking level for the auditor session",
178
+ description: "thinking level for the auditor session — unset = high (the verification gate does not ride the session thinking dial)",
179
179
  },
180
180
  {
181
181
  id: "auditCap",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goal-list-loop-audit",
3
- "version": "0.31.1",
3
+ "version": "0.31.2",
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",