crosscheck-mcp 0.2.30 → 0.2.31

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/embed.js CHANGED
@@ -6,11 +6,35 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
6
6
  throw Error('Dynamic require of "' + x + '" is not supported');
7
7
  });
8
8
 
9
- // src/entrypoints/embed.ts
10
- import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
11
- import { existsSync as existsSync11 } from "fs";
12
- import path12 from "path";
13
- import { fileURLToPath as fileURLToPath2 } from "url";
9
+ // src/core/retarget.ts
10
+ function retargetProvider(p, newModel, fallbackModels) {
11
+ const chain = fallbackModels && fallbackModels.length > 0 ? fallbackModels : void 0;
12
+ if (p.model === newModel && chain === void 0) return p;
13
+ return {
14
+ name: p.name,
15
+ model: newModel,
16
+ ...chain ? { fallbackModels: chain } : {},
17
+ send: (args) => p.send({ ...args, modelOverride: newModel })
18
+ };
19
+ }
20
+ async function loadProviderWeights(storage, names) {
21
+ const out = {};
22
+ for (const raw of names) {
23
+ const name = raw.toLowerCase();
24
+ if (name in out) continue;
25
+ const row = await storage.getProviderStats(name);
26
+ if (!row) {
27
+ out[name] = 0.5;
28
+ continue;
29
+ }
30
+ const total = row.wins + row.losses + row.abstains;
31
+ out[name] = total <= 0 ? 0.5 : (row.wins + 0.5 * row.abstains) / total;
32
+ }
33
+ return out;
34
+ }
35
+
36
+ // src/core/super-mode.ts
37
+ import { AsyncLocalStorage } from "async_hooks";
14
38
 
15
39
  // src/core/pricing.ts
16
40
  import { readFileSync } from "fs";
@@ -1300,12 +1324,238 @@ function makeGeminiProvider(model, apiKey, opts, fallbackModels = []) {
1300
1324
  };
1301
1325
  }
1302
1326
 
1327
+ // src/core/reasoning-upgrade.ts
1328
+ var UPGRADE_MODEL = "claude-fable-5";
1329
+ var UPGRADE_LABEL = "Fable 5";
1330
+ function isUpgradeRequested(args) {
1331
+ if (args["upgrade"] === true) return true;
1332
+ const reasoning = args["reasoning"];
1333
+ if (typeof reasoning === "string" && reasoning.trim().toLowerCase() === "max") {
1334
+ return true;
1335
+ }
1336
+ const model = args["model"];
1337
+ if (typeof model === "string") {
1338
+ const m = model.trim().toLowerCase();
1339
+ if (m === "fable5" || m === "fable-5" || m === "fable" || m === UPGRADE_MODEL) {
1340
+ return true;
1341
+ }
1342
+ }
1343
+ return false;
1344
+ }
1345
+ var HEAVY_TERMS = [
1346
+ /\bprov(e|ing|en)\b|\bproof\b|\btheorem\b|\bderiv(e|ation)\b/i,
1347
+ /\barchitect(ure|ing)?\b|\bdesign\s+(a|the|an)\b|\bhigh[-\s]?level\s+design\b/i,
1348
+ /\btrade[-\s]?offs?\b|\bpros?\s+and\s+cons?\b|\bweigh\b/i,
1349
+ /\boptimi[sz]e\b|\bcomplexity\b|\bO\(|\balgorithm(ic)?\b/i,
1350
+ /\brace\s+condition\b|\bconcurren(t|cy)\b|\bdeadlock\b|\bdistributed\b|\bconsensus\b/i,
1351
+ /\broot[-\s]?cause\b|\bdebug(ging)?\b|\bwhy\s+(does|is|would|might)\b/i,
1352
+ /\bsecurity\b|\bthreat\s+model\b|\bexploit\b|\bvulnerabilit(y|ies)\b/i,
1353
+ /\bmigrat(e|ion)\b|\brefactor\b|\bre[-\s]?architect\b/i,
1354
+ /\binvariant\b|\bcorrectness\b|\bedge\s+cases?\b|\bformal(ly)?\b/i,
1355
+ /\bstrateg(y|ic|ies)\b|\bplan\s+(the|a|an|out)\b|\broadmap\b/i,
1356
+ /\breason\s+(through|about)\b|\bstep[-\s]?by[-\s]?step\b|\bthink\s+deeply\b/i,
1357
+ /\bnp[-\s]?(hard|complete)\b|\bgraph\b|\bstate\s+machine\b|\bconstraint\b/i
1358
+ ];
1359
+ var DIFFICULTY_TERMS = /\b(hard|tricky|subtle|complex|complicated|non[-\s]?trivial|thorny|gnarly|difficult|deep)\b/i;
1360
+ function assessReasoning(text) {
1361
+ const s = typeof text === "string" ? text : "";
1362
+ const signals = [];
1363
+ let score = 0;
1364
+ let termHits = 0;
1365
+ for (const re of HEAVY_TERMS) {
1366
+ if (re.test(s)) termHits += 1;
1367
+ }
1368
+ if (termHits > 0) {
1369
+ const add = Math.min(termHits, 4);
1370
+ score += add;
1371
+ signals.push(`${termHits} reasoning cue${termHits === 1 ? "" : "s"}`);
1372
+ }
1373
+ if (DIFFICULTY_TERMS.test(s)) {
1374
+ score += 1;
1375
+ signals.push("explicit difficulty marker");
1376
+ }
1377
+ const words = s.split(/\s+/).filter(Boolean).length;
1378
+ if (words >= 120) {
1379
+ score += 2;
1380
+ signals.push("long, detailed prompt");
1381
+ } else if (words >= 50) {
1382
+ score += 1;
1383
+ signals.push("substantial prompt");
1384
+ }
1385
+ const constraints = (s.match(/\b(must|should|need to|ensure|require[ds]?|constraint)\b/gi) ?? []).length + (s.match(/(^|\n)\s*(?:[-*]|\d+[.)])\s+/g) ?? []).length;
1386
+ if (constraints >= 3) {
1387
+ score += 1;
1388
+ signals.push(`${constraints} constraints/steps`);
1389
+ }
1390
+ const heavy = score >= 3;
1391
+ const reason = heavy ? `Task looks reasoning-heavy (${signals.join(", ") || "score " + score}).` : `Task looks routine (score ${score}).`;
1392
+ return { heavy, score, reason, signals };
1393
+ }
1394
+ function buildSuggestedUpgrade(toolName, assessment) {
1395
+ return {
1396
+ model: UPGRADE_MODEL,
1397
+ label: UPGRADE_LABEL,
1398
+ reason: assessment.reason,
1399
+ how: `re-run \`${toolName}\` with reasoning:"max" (or upgrade:true) to route the lead reasoning seat to ${UPGRADE_LABEL}, and \u2014 when an OpenAI key is configured \u2014 add an OpenAI second-opinion pass that ${UPGRADE_LABEL} weighs before finalizing (the result names which model ran). Other panel seats stay on their normal models.`
1400
+ };
1401
+ }
1402
+
1403
+ // src/core/super-mode.ts
1404
+ var SUPER_MODELS = {
1405
+ // Fable 5.1 verified present on the account; 5 as the fallback for accounts
1406
+ // that haven't been granted 5.1 yet.
1407
+ anthropic: ["claude-fable-5-1", UPGRADE_MODEL],
1408
+ // Astra is live (verified against the account's model list 2026-09-23).
1409
+ // The fallback is named explicitly rather than reusing CO_REASON_MODEL:
1410
+ // that constant means "OpenAI's top reasoning model" for the max-reasoning
1411
+ // co-reasoner, which is a different question from "what should super fall
1412
+ // back to". Sharing the symbol silently coupled two unrelated decisions.
1413
+ openai: ["gpt-6-astra", "gpt-6-sol"],
1414
+ // Explicitly left as-is per product decision. Note grok-4-latest is not in
1415
+ // xAI's published model list, but it resolves in practice — real panel calls
1416
+ // on it succeeded as recently as 2026-08-30 — so it is an unlisted alias
1417
+ // rather than a dead id.
1418
+ xai: [DEFAULT_MODELS["xai"]],
1419
+ // 3.8 Flash is now BOTH the everyday default and the super pick for Gemini,
1420
+ // so this can no longer borrow DEFAULT_MODELS as its fallback — that would
1421
+ // repeat the same model and retry one that just failed. Named explicitly.
1422
+ gemini: ["gemini-3.8-flash", "gemini-3.1-pro-preview"],
1423
+ kimi: [DEFAULT_MODELS["kimi"]],
1424
+ qwen: [DEFAULT_MODELS["qwen"]]
1425
+ };
1426
+ var SUPER_ENV_VARS = {
1427
+ anthropic: "ANTHROPIC_SUPER_MODEL",
1428
+ openai: "OPENAI_SUPER_MODEL",
1429
+ xai: "XAI_SUPER_MODEL",
1430
+ gemini: "GEMINI_SUPER_MODEL",
1431
+ kimi: "KIMI_SUPER_MODEL",
1432
+ qwen: "QWEN_SUPER_MODEL",
1433
+ mistral: "MISTRAL_SUPER_MODEL",
1434
+ groq: "GROQ_SUPER_MODEL",
1435
+ deepseek: "DEEPSEEK_SUPER_MODEL"
1436
+ };
1437
+ function parseChain(v) {
1438
+ if (!v) return [];
1439
+ const out = [];
1440
+ for (const raw of v.split(",")) {
1441
+ const m = raw.trim();
1442
+ if (m && !out.includes(m)) out.push(m);
1443
+ }
1444
+ return out;
1445
+ }
1446
+ var superEnvStore = new AsyncLocalStorage();
1447
+ function withSuperEnv(env, fn) {
1448
+ return superEnvStore.run(env, fn);
1449
+ }
1450
+ var currentEnv = () => superEnvStore.getStore() ?? process.env;
1451
+ function superChainFor(provider, env = currentEnv()) {
1452
+ const varName = SUPER_ENV_VARS[provider];
1453
+ const user = varName ? parseChain(env[varName]) : [];
1454
+ if (user.length > 0) {
1455
+ const fallbacks = varName ? parseChain(env[`${varName}_FALLBACKS`]) : [];
1456
+ return [...user, ...fallbacks.filter((m) => !user.includes(m))];
1457
+ }
1458
+ return SUPER_MODELS[provider] ?? [];
1459
+ }
1460
+ function superPrimary(provider, env = currentEnv()) {
1461
+ return superChainFor(provider, env)[0];
1462
+ }
1463
+ var SUPER_PROVIDER_NAMES = Object.keys(SUPER_MODELS);
1464
+ function isSuperRequested(args) {
1465
+ return args["super"] === true;
1466
+ }
1467
+ function retargetForSuper(p, env = currentEnv()) {
1468
+ const chain = superChainFor(p.name, env);
1469
+ if (chain.length === 0) return p;
1470
+ const [primary, ...fallbacks] = chain;
1471
+ return retargetProvider(p, primary, fallbacks);
1472
+ }
1473
+ var SUPER_BUDGET_MULTIPLIER = 3;
1474
+ var SUPER_BUDGET_CEILING = 16e3;
1475
+ function superBudget(base) {
1476
+ return Math.min(base * SUPER_BUDGET_MULTIPLIER, SUPER_BUDGET_CEILING);
1477
+ }
1478
+
1479
+ // src/core/moderator.ts
1480
+ var DEFAULT_MODERATOR = "anthropic";
1481
+ var PROVIDER_ALIASES = {
1482
+ grok: "xai",
1483
+ claude: "anthropic",
1484
+ google: "gemini",
1485
+ chatgpt: "openai",
1486
+ gpt: "openai",
1487
+ moonshot: "kimi"
1488
+ };
1489
+ function parseModeratorSpec(raw) {
1490
+ if (typeof raw !== "string") return null;
1491
+ const s = raw.trim();
1492
+ if (!s) return null;
1493
+ const i = s.indexOf(":");
1494
+ const providerPart = (i < 0 ? s : s.slice(0, i)).trim().toLowerCase();
1495
+ const modelPart = i < 0 ? "" : s.slice(i + 1).trim();
1496
+ if (!providerPart) return null;
1497
+ return {
1498
+ provider: PROVIDER_ALIASES[providerPart] ?? providerPart,
1499
+ model: modelPart || null
1500
+ };
1501
+ }
1502
+ function moderatorProviderName(raw, fallback = DEFAULT_MODERATOR) {
1503
+ return (parseModeratorSpec(raw) ?? parseModeratorSpec(fallback))?.provider ?? DEFAULT_MODERATOR;
1504
+ }
1505
+ function pickModeratorSpec(...candidates) {
1506
+ for (const c of candidates) {
1507
+ const s = parseModeratorSpec(c);
1508
+ if (s) return s;
1509
+ }
1510
+ return { provider: DEFAULT_MODERATOR, model: null };
1511
+ }
1512
+ function resolveModerator(providers, ...candidates) {
1513
+ const spec = pickModeratorSpec(...candidates);
1514
+ const base = providers[spec.provider];
1515
+ if (!base) return { provider: void 0, spec, pinned: false };
1516
+ if (!spec.model) return { provider: base, spec, pinned: false };
1517
+ return { provider: retargetProvider(base, spec.model), spec, pinned: true };
1518
+ }
1519
+ function synthesisSeat(o) {
1520
+ const { moderator, pinned, superRequested, upgradeRequested } = o;
1521
+ const wantsMore = superRequested || upgradeRequested;
1522
+ if (!wantsMore) return { provider: moderator, upgraded: false, label: null, skipReason: null };
1523
+ if (pinned) {
1524
+ return {
1525
+ provider: moderator,
1526
+ upgraded: false,
1527
+ label: null,
1528
+ skipReason: `the moderator is pinned to ${moderator.name}:${moderator.model}; a pinned model is used as-is.`
1529
+ };
1530
+ }
1531
+ if (moderator.name === "anthropic" && !superRequested) {
1532
+ return { provider: retargetProvider(moderator, UPGRADE_MODEL), upgraded: true, label: UPGRADE_LABEL, skipReason: null };
1533
+ }
1534
+ if (superChainFor(moderator.name).length === 0) {
1535
+ return {
1536
+ provider: moderator,
1537
+ upgraded: false,
1538
+ label: null,
1539
+ skipReason: `no flagship model is known for ${moderator.name}; the moderator ran at ${moderator.model}.`
1540
+ };
1541
+ }
1542
+ const seat = retargetForSuper(moderator);
1543
+ const label = moderator.name === "anthropic" ? UPGRADE_LABEL : seat.model;
1544
+ return { provider: seat, upgraded: true, label, skipReason: null };
1545
+ }
1546
+
1547
+ // src/entrypoints/embed.ts
1548
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
1549
+ import { existsSync as existsSync11 } from "fs";
1550
+ import path12 from "path";
1551
+ import { fileURLToPath as fileURLToPath2 } from "url";
1552
+
1303
1553
  // src/tools/index.ts
1304
1554
  import { z } from "zod";
1305
1555
 
1306
1556
  // src/server-meta.ts
1307
1557
  var SERVER_NAME = "crosscheck-agent";
1308
- var SERVER_VERSION = true ? "0.2.30" : "0.0.0-dev";
1558
+ var SERVER_VERSION = true ? "0.2.31" : "0.0.0-dev";
1309
1559
 
1310
1560
  // src/tools/audit.ts
1311
1561
  import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
@@ -1988,33 +2238,6 @@ function operatorCeiling(purpose, provider) {
1988
2238
  return null;
1989
2239
  }
1990
2240
 
1991
- // src/core/retarget.ts
1992
- function retargetProvider(p, newModel, fallbackModels) {
1993
- const chain = fallbackModels && fallbackModels.length > 0 ? fallbackModels : void 0;
1994
- if (p.model === newModel && chain === void 0) return p;
1995
- return {
1996
- name: p.name,
1997
- model: newModel,
1998
- ...chain ? { fallbackModels: chain } : {},
1999
- send: (args) => p.send({ ...args, modelOverride: newModel })
2000
- };
2001
- }
2002
- async function loadProviderWeights(storage, names) {
2003
- const out = {};
2004
- for (const raw of names) {
2005
- const name = raw.toLowerCase();
2006
- if (name in out) continue;
2007
- const row = await storage.getProviderStats(name);
2008
- if (!row) {
2009
- out[name] = 0.5;
2010
- continue;
2011
- }
2012
- const total = row.wins + row.losses + row.abstains;
2013
- out[name] = total <= 0 ? 0.5 : (row.wins + 0.5 * row.abstains) / total;
2014
- }
2015
- return out;
2016
- }
2017
-
2018
2241
  // src/core/model-fallback.ts
2019
2242
  async function sendWithModelFallback(provider, args) {
2020
2243
  const chain = [provider.model, ...provider.fallbackModels ?? []];
@@ -3081,82 +3304,6 @@ function selectForDifficulty(args) {
3081
3304
  };
3082
3305
  }
3083
3306
 
3084
- // src/core/reasoning-upgrade.ts
3085
- var UPGRADE_MODEL = "claude-fable-5";
3086
- var UPGRADE_LABEL = "Fable 5";
3087
- function isUpgradeRequested(args) {
3088
- if (args["upgrade"] === true) return true;
3089
- const reasoning = args["reasoning"];
3090
- if (typeof reasoning === "string" && reasoning.trim().toLowerCase() === "max") {
3091
- return true;
3092
- }
3093
- const model = args["model"];
3094
- if (typeof model === "string") {
3095
- const m = model.trim().toLowerCase();
3096
- if (m === "fable5" || m === "fable-5" || m === "fable" || m === UPGRADE_MODEL) {
3097
- return true;
3098
- }
3099
- }
3100
- return false;
3101
- }
3102
- var HEAVY_TERMS = [
3103
- /\bprov(e|ing|en)\b|\bproof\b|\btheorem\b|\bderiv(e|ation)\b/i,
3104
- /\barchitect(ure|ing)?\b|\bdesign\s+(a|the|an)\b|\bhigh[-\s]?level\s+design\b/i,
3105
- /\btrade[-\s]?offs?\b|\bpros?\s+and\s+cons?\b|\bweigh\b/i,
3106
- /\boptimi[sz]e\b|\bcomplexity\b|\bO\(|\balgorithm(ic)?\b/i,
3107
- /\brace\s+condition\b|\bconcurren(t|cy)\b|\bdeadlock\b|\bdistributed\b|\bconsensus\b/i,
3108
- /\broot[-\s]?cause\b|\bdebug(ging)?\b|\bwhy\s+(does|is|would|might)\b/i,
3109
- /\bsecurity\b|\bthreat\s+model\b|\bexploit\b|\bvulnerabilit(y|ies)\b/i,
3110
- /\bmigrat(e|ion)\b|\brefactor\b|\bre[-\s]?architect\b/i,
3111
- /\binvariant\b|\bcorrectness\b|\bedge\s+cases?\b|\bformal(ly)?\b/i,
3112
- /\bstrateg(y|ic|ies)\b|\bplan\s+(the|a|an|out)\b|\broadmap\b/i,
3113
- /\breason\s+(through|about)\b|\bstep[-\s]?by[-\s]?step\b|\bthink\s+deeply\b/i,
3114
- /\bnp[-\s]?(hard|complete)\b|\bgraph\b|\bstate\s+machine\b|\bconstraint\b/i
3115
- ];
3116
- var DIFFICULTY_TERMS = /\b(hard|tricky|subtle|complex|complicated|non[-\s]?trivial|thorny|gnarly|difficult|deep)\b/i;
3117
- function assessReasoning(text) {
3118
- const s = typeof text === "string" ? text : "";
3119
- const signals = [];
3120
- let score = 0;
3121
- let termHits = 0;
3122
- for (const re of HEAVY_TERMS) {
3123
- if (re.test(s)) termHits += 1;
3124
- }
3125
- if (termHits > 0) {
3126
- const add = Math.min(termHits, 4);
3127
- score += add;
3128
- signals.push(`${termHits} reasoning cue${termHits === 1 ? "" : "s"}`);
3129
- }
3130
- if (DIFFICULTY_TERMS.test(s)) {
3131
- score += 1;
3132
- signals.push("explicit difficulty marker");
3133
- }
3134
- const words = s.split(/\s+/).filter(Boolean).length;
3135
- if (words >= 120) {
3136
- score += 2;
3137
- signals.push("long, detailed prompt");
3138
- } else if (words >= 50) {
3139
- score += 1;
3140
- signals.push("substantial prompt");
3141
- }
3142
- const constraints = (s.match(/\b(must|should|need to|ensure|require[ds]?|constraint)\b/gi) ?? []).length + (s.match(/(^|\n)\s*(?:[-*]|\d+[.)])\s+/g) ?? []).length;
3143
- if (constraints >= 3) {
3144
- score += 1;
3145
- signals.push(`${constraints} constraints/steps`);
3146
- }
3147
- const heavy = score >= 3;
3148
- const reason = heavy ? `Task looks reasoning-heavy (${signals.join(", ") || "score " + score}).` : `Task looks routine (score ${score}).`;
3149
- return { heavy, score, reason, signals };
3150
- }
3151
- function buildSuggestedUpgrade(toolName, assessment) {
3152
- return {
3153
- model: UPGRADE_MODEL,
3154
- label: UPGRADE_LABEL,
3155
- reason: assessment.reason,
3156
- how: `re-run \`${toolName}\` with reasoning:"max" (or upgrade:true) to route the lead reasoning seat to ${UPGRADE_LABEL}, and \u2014 when an OpenAI key is configured \u2014 add an OpenAI second-opinion pass that ${UPGRADE_LABEL} weighs before finalizing (the result names which model ran). Other panel seats stay on their normal models.`
3157
- };
3158
- }
3159
-
3160
3307
  // src/tools/audit.ts
3161
3308
  var AUDIT_OBVIOUS_FAILURE_HIGH = 0.3;
3162
3309
  var AUDIT_OBVIOUS_FAILURE_MED = 0.2;
@@ -3454,9 +3601,14 @@ ${rubricText}`;
3454
3601
  );
3455
3602
  }
3456
3603
  const upgradeRequested = isUpgradeRequested(args);
3457
- const upgraded = upgradeRequested && opts.providers["anthropic"] !== void 0;
3458
- const auditorForCall = upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : auditor;
3459
- const coProvider = pickCoReasoner(opts.providers, upgradeRequested);
3604
+ const seat = synthesisSeat({ moderator: auditor, pinned: false, superRequested: false, upgradeRequested });
3605
+ const upgraded = seat.upgraded;
3606
+ const auditorForCall = seat.provider;
3607
+ const coProvider = pickCoReasoner(
3608
+ opts.providers,
3609
+ upgradeRequested,
3610
+ auditorForCall.name === "openai" ? auditorForCall.model : void 0
3611
+ );
3460
3612
  const coReason = await coReasonThenInject({
3461
3613
  provider: coProvider,
3462
3614
  messages: msgs,
@@ -3539,15 +3691,16 @@ ${rubricText}`;
3539
3691
  if (upgraded) {
3540
3692
  result["reasoning_upgrade"] = {
3541
3693
  applied: true,
3542
- model: UPGRADE_MODEL,
3543
- label: UPGRADE_LABEL,
3694
+ provider: auditorForCall.name,
3695
+ model: auditorForCall.model,
3696
+ label: seat.label ?? auditorForCall.model,
3544
3697
  seat: "auditor",
3545
3698
  ...coReasoned ? { co_reasoner: { model: coProvider.model, label: coReasonLabel(coProvider.model) } } : {}
3546
3699
  };
3547
3700
  } else if (upgradeRequested) {
3548
3701
  result["reasoning_upgrade"] = {
3549
3702
  applied: false,
3550
- reason: `no Anthropic key available \u2014 the ${UPGRADE_LABEL} upgrade needs it.`
3703
+ reason: seat.skipReason ?? "the auditor couldn't be upgraded."
3551
3704
  };
3552
3705
  } else {
3553
3706
  const assessment = assessReasoning(
@@ -3630,7 +3783,7 @@ function pickAuditor(providers, exclude, explicit, moderatorName, allowlist, che
3630
3783
  }
3631
3784
  }
3632
3785
  }
3633
- const mod = providers[moderatorName.toLowerCase()];
3786
+ const mod = resolveModerator(providers, moderatorName).provider;
3634
3787
  if (mod !== void 0 && !exclude.has(mod.name) && (allowlist === null || allowlist.includes(mod.name))) {
3635
3788
  return { auditor: mod, reason: null };
3636
3789
  }
@@ -3949,9 +4102,7 @@ function pickPanelJudge(providers, moderatorName, pricing) {
3949
4102
  return entry.model && entry.model !== base.model ? retargetProvider(base, entry.model) : base;
3950
4103
  }
3951
4104
  }
3952
- const mod = providers[moderatorName.toLowerCase()];
3953
- if (mod !== void 0) return mod;
3954
- return null;
4105
+ return resolveModerator(providers, moderatorName).provider ?? null;
3955
4106
  }
3956
4107
  var AGREEMENT_CHECK_SCHEMA = {
3957
4108
  type: "object",
@@ -4268,83 +4419,6 @@ async function pickAutoPanel(storage, purpose, n, providers, allowlist) {
4268
4419
  return { providers: ranked.slice(0, Math.max(1, n)), coldStart: true };
4269
4420
  }
4270
4421
 
4271
- // src/core/super-mode.ts
4272
- import { AsyncLocalStorage } from "async_hooks";
4273
- var SUPER_MODELS = {
4274
- // Fable 5.1 verified present on the account; 5 as the fallback for accounts
4275
- // that haven't been granted 5.1 yet.
4276
- anthropic: ["claude-fable-5-1", UPGRADE_MODEL],
4277
- // Astra is live (verified against the account's model list 2026-09-23).
4278
- // The fallback is named explicitly rather than reusing CO_REASON_MODEL:
4279
- // that constant means "OpenAI's top reasoning model" for the max-reasoning
4280
- // co-reasoner, which is a different question from "what should super fall
4281
- // back to". Sharing the symbol silently coupled two unrelated decisions.
4282
- openai: ["gpt-6-astra", "gpt-6-sol"],
4283
- // Explicitly left as-is per product decision. Note grok-4-latest is not in
4284
- // xAI's published model list, but it resolves in practice — real panel calls
4285
- // on it succeeded as recently as 2026-08-30 — so it is an unlisted alias
4286
- // rather than a dead id.
4287
- xai: [DEFAULT_MODELS["xai"]],
4288
- // 3.8 Flash is now BOTH the everyday default and the super pick for Gemini,
4289
- // so this can no longer borrow DEFAULT_MODELS as its fallback — that would
4290
- // repeat the same model and retry one that just failed. Named explicitly.
4291
- gemini: ["gemini-3.8-flash", "gemini-3.1-pro-preview"],
4292
- kimi: [DEFAULT_MODELS["kimi"]],
4293
- qwen: [DEFAULT_MODELS["qwen"]]
4294
- };
4295
- var SUPER_ENV_VARS = {
4296
- anthropic: "ANTHROPIC_SUPER_MODEL",
4297
- openai: "OPENAI_SUPER_MODEL",
4298
- xai: "XAI_SUPER_MODEL",
4299
- gemini: "GEMINI_SUPER_MODEL",
4300
- kimi: "KIMI_SUPER_MODEL",
4301
- qwen: "QWEN_SUPER_MODEL",
4302
- mistral: "MISTRAL_SUPER_MODEL",
4303
- groq: "GROQ_SUPER_MODEL",
4304
- deepseek: "DEEPSEEK_SUPER_MODEL"
4305
- };
4306
- function parseChain(v) {
4307
- if (!v) return [];
4308
- const out = [];
4309
- for (const raw of v.split(",")) {
4310
- const m = raw.trim();
4311
- if (m && !out.includes(m)) out.push(m);
4312
- }
4313
- return out;
4314
- }
4315
- var superEnvStore = new AsyncLocalStorage();
4316
- function withSuperEnv(env, fn) {
4317
- return superEnvStore.run(env, fn);
4318
- }
4319
- var currentEnv = () => superEnvStore.getStore() ?? process.env;
4320
- function superChainFor(provider, env = currentEnv()) {
4321
- const varName = SUPER_ENV_VARS[provider];
4322
- const user = varName ? parseChain(env[varName]) : [];
4323
- if (user.length > 0) {
4324
- const fallbacks = varName ? parseChain(env[`${varName}_FALLBACKS`]) : [];
4325
- return [...user, ...fallbacks.filter((m) => !user.includes(m))];
4326
- }
4327
- return SUPER_MODELS[provider] ?? [];
4328
- }
4329
- function superPrimary(provider, env = currentEnv()) {
4330
- return superChainFor(provider, env)[0];
4331
- }
4332
- var SUPER_PROVIDER_NAMES = Object.keys(SUPER_MODELS);
4333
- function isSuperRequested(args) {
4334
- return args["super"] === true;
4335
- }
4336
- function retargetForSuper(p, env = currentEnv()) {
4337
- const chain = superChainFor(p.name, env);
4338
- if (chain.length === 0) return p;
4339
- const [primary, ...fallbacks] = chain;
4340
- return retargetProvider(p, primary, fallbacks);
4341
- }
4342
- var SUPER_BUDGET_MULTIPLIER = 3;
4343
- var SUPER_BUDGET_CEILING = 16e3;
4344
- function superBudget(base) {
4345
- return Math.min(base * SUPER_BUDGET_MULTIPLIER, SUPER_BUDGET_CEILING);
4346
- }
4347
-
4348
4422
  // src/core/session-memory.ts
4349
4423
  var SESSION_MEMORY_DEFAULT_LIMIT = 50;
4350
4424
  var SESSION_MEMORY_INJECT_BUDGET_CHARS = 4e3;
@@ -6725,8 +6799,9 @@ async function runOrchestrate(args, opts) {
6725
6799
  blocked
6726
6800
  };
6727
6801
  }
6728
- const moderatorName = typeof args["moderator"] === "string" && args["moderator"] ? args["moderator"] : opts.moderator ?? "anthropic";
6729
- const moderator = opts.providers[moderatorName.toLowerCase()] ?? selected[0];
6802
+ const resolvedModerator = resolveModerator(opts.providers, args["moderator"], opts.moderator);
6803
+ const moderator = resolvedModerator.provider ?? selected[0];
6804
+ const moderatorChosen = resolvedModerator.provider !== void 0 && (resolvedModerator.pinned || parseModeratorSpec(args["moderator"]) !== null);
6730
6805
  const failFast = boolArg2(args["fail_fast"], false);
6731
6806
  const planOnly = boolArg2(args["plan_only"], false);
6732
6807
  const cheapMode = boolArg2(args["cheap_mode"], opts.ctx?.cheap_mode ?? false);
@@ -7210,11 +7285,17 @@ ${recombineSys}` : recombineSys },
7210
7285
  let synthProvider = moderator;
7211
7286
  let synthModel = null;
7212
7287
  const upgradeRequested = isUpgradeRequested(args);
7213
- const upgraded = upgradeRequested && opts.providers["anthropic"] !== void 0;
7288
+ const seat = synthesisSeat({
7289
+ moderator,
7290
+ pinned: resolvedModerator.provider !== void 0 && resolvedModerator.pinned,
7291
+ superRequested: false,
7292
+ upgradeRequested
7293
+ });
7294
+ const upgraded = seat.upgraded;
7214
7295
  if (upgraded) {
7215
- synthProvider = retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL);
7216
- synthModel = `anthropic/${UPGRADE_MODEL}`;
7217
- } else if (cheapMode && opts.pricing) {
7296
+ synthProvider = seat.provider;
7297
+ synthModel = `${seat.provider.name}/${seat.provider.model}`;
7298
+ } else if (cheapMode && opts.pricing && !moderatorChosen) {
7218
7299
  const pick = selectForDifficulty({
7219
7300
  pricing: opts.pricing,
7220
7301
  tier: "med",
@@ -7240,7 +7321,11 @@ ${recombineSys}` : recombineSys },
7240
7321
  provider: synthProvider.name
7241
7322
  } }
7242
7323
  );
7243
- const coProvider = pickCoReasoner(opts.providers, upgradeRequested);
7324
+ const coProvider = pickCoReasoner(
7325
+ opts.providers,
7326
+ upgradeRequested,
7327
+ synthProvider.name === "openai" ? synthProvider.model : void 0
7328
+ );
7244
7329
  const coReason = await coReasonThenInject({
7245
7330
  provider: coProvider,
7246
7331
  messages: recMsgs,
@@ -7290,7 +7375,8 @@ ${recombineSys}` : recombineSys },
7290
7375
  missing,
7291
7376
  partial,
7292
7377
  fail_fast: failFast,
7293
- cheap_mode: cheapMode
7378
+ cheap_mode: cheapMode,
7379
+ moderator: { provider: moderator.name, model: moderator.model }
7294
7380
  };
7295
7381
  if (personaMeta.used !== null) result["persona"] = personaMeta;
7296
7382
  if (synthModel) result["synth_model"] = synthModel;
@@ -7298,15 +7384,16 @@ ${recombineSys}` : recombineSys },
7298
7384
  if (upgraded) {
7299
7385
  result["reasoning_upgrade"] = {
7300
7386
  applied: true,
7301
- model: UPGRADE_MODEL,
7302
- label: UPGRADE_LABEL,
7387
+ provider: seat.provider.name,
7388
+ model: seat.provider.model,
7389
+ label: seat.label ?? seat.provider.model,
7303
7390
  seat: "recombine/synthesis",
7304
7391
  ...coReasoned ? { co_reasoner: { model: coProvider.model, label: coReasonLabel(coProvider.model) } } : {}
7305
7392
  };
7306
7393
  } else if (upgradeRequested) {
7307
7394
  result["reasoning_upgrade"] = {
7308
7395
  applied: false,
7309
- reason: `no Anthropic key available \u2014 the ${UPGRADE_LABEL} upgrade needs it.`
7396
+ reason: seat.skipReason ?? "the moderator couldn't be upgraded."
7310
7397
  };
7311
7398
  } else if (goal) {
7312
7399
  const assessment = assessReasoning(goal);
@@ -8488,13 +8575,24 @@ async function runCoordinate(args, opts) {
8488
8575
  };
8489
8576
  }
8490
8577
  const proposerName = typeof args["proposer"] === "string" && args["proposer"] ? args["proposer"] : selected[0].name;
8491
- const synthName = typeof args["synthesizer"] === "string" && args["synthesizer"] ? args["synthesizer"] : typeof args["moderator"] === "string" && args["moderator"] ? args["moderator"] : opts.moderator ?? "anthropic";
8578
+ const resolvedSynth = resolveModerator(
8579
+ opts.providers,
8580
+ args["synthesizer"],
8581
+ args["moderator"],
8582
+ opts.moderator
8583
+ );
8492
8584
  const proposer = opts.providers[proposerName.toLowerCase()] ?? selected[0];
8493
- const synth = opts.providers[synthName.toLowerCase()] ?? proposer;
8585
+ const synth = resolvedSynth.provider ?? proposer;
8494
8586
  const proposerForCall = superRequested ? retargetForSuper(proposer) : proposer;
8495
8587
  const upgradeRequested = isUpgradeRequested(args) || superRequested;
8496
- const upgraded = upgradeRequested && opts.providers["anthropic"] !== void 0;
8497
- const synthForCall = superRequested && opts.providers["anthropic"] ? retargetForSuper(opts.providers["anthropic"]) : upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : synth;
8588
+ const seat = synthesisSeat({
8589
+ moderator: synth,
8590
+ pinned: resolvedSynth.provider !== void 0 && resolvedSynth.pinned,
8591
+ superRequested,
8592
+ upgradeRequested
8593
+ });
8594
+ const upgraded = seat.upgraded;
8595
+ const synthForCall = seat.provider;
8498
8596
  let critics = [];
8499
8597
  if (Array.isArray(args["critics"])) {
8500
8598
  for (const n of args["critics"]) {
@@ -8645,7 +8743,11 @@ CRITIQUES:
8645
8743
  ${critiqueBlock}`
8646
8744
  }
8647
8745
  ];
8648
- const coProvider = pickCoReasoner(opts.providers, upgradeRequested);
8746
+ const coProvider = pickCoReasoner(
8747
+ opts.providers,
8748
+ upgradeRequested,
8749
+ synthForCall.name === "openai" ? synthForCall.model : void 0
8750
+ );
8649
8751
  const coReason = await coReasonThenInject({
8650
8752
  provider: coProvider,
8651
8753
  messages: synthMessages,
@@ -8690,7 +8792,8 @@ ${critiqueBlock}`
8690
8792
  critique_answers: scannedCritiques,
8691
8793
  critique_structured: critiqueStructured,
8692
8794
  synthesis_answer: synthAns,
8693
- synthesis_structured: synthObj
8795
+ synthesis_structured: synthObj,
8796
+ moderator: { provider: synthForCall.name, model: synthForCall.model }
8694
8797
  };
8695
8798
  if (synthErrs.length > 0) result["synthesis_errors"] = synthErrs;
8696
8799
  if (canaryLeaks.length > 0) result["canary_leaks"] = canaryLeaks;
@@ -8708,15 +8811,16 @@ ${critiqueBlock}`
8708
8811
  result["reasoning_upgrade"] = {
8709
8812
  applied: true,
8710
8813
  // The model that actually ran the seat, not the one we'd have picked.
8711
- model: superRequested ? superPrimary("anthropic") ?? UPGRADE_MODEL : UPGRADE_MODEL,
8712
- label: UPGRADE_LABEL,
8814
+ provider: synthForCall.name,
8815
+ model: synthForCall.model,
8816
+ label: seat.label ?? synthForCall.model,
8713
8817
  seat: "synthesizer",
8714
8818
  ...coReasonAns ? { co_reasoner: { model: coProvider.model, label: coReasonLabel(coProvider.model) } } : {}
8715
8819
  };
8716
8820
  } else if (upgradeRequested) {
8717
8821
  result["reasoning_upgrade"] = {
8718
8822
  applied: false,
8719
- reason: `no Anthropic key available \u2014 the ${UPGRADE_LABEL} upgrade needs it.`
8823
+ reason: seat.skipReason ?? "the synthesizer couldn't be upgraded."
8720
8824
  };
8721
8825
  } else {
8722
8826
  const assessment = assessReasoning(topic);
@@ -9322,10 +9426,12 @@ async function runDebate(args, opts) {
9322
9426
  const earlyStopThreshold = Number.isFinite(earlyStopThresholdRaw) ? earlyStopThresholdRaw : 0.7;
9323
9427
  let earlyStoppedRound = null;
9324
9428
  let agreementBlock = null;
9325
- const moderatorName = typeof args["moderator"] === "string" && args["moderator"] ? args["moderator"] : opts.moderator ?? "anthropic";
9326
- const moderator = opts.providers[moderatorName.toLowerCase()] ?? selected[0];
9429
+ const resolvedModerator = resolveModerator(opts.providers, args["moderator"], opts.moderator);
9430
+ const moderatorName = resolvedModerator.spec.provider;
9431
+ const moderator = resolvedModerator.provider ?? selected[0];
9327
9432
  const upgradeRequested = isUpgradeRequested(args) || superRequested;
9328
- const upgraded = upgradeRequested && opts.providers["anthropic"] !== void 0;
9433
+ const seat = moderator ? synthesisSeat({ moderator, pinned: resolvedModerator.pinned, superRequested, upgradeRequested }) : null;
9434
+ const upgraded = seat?.upgraded ?? false;
9329
9435
  for (let rnd = 1; rnd <= maxRounds; rnd++) {
9330
9436
  const roundMessages = [
9331
9437
  {
@@ -9410,8 +9516,10 @@ ${prior.body}` });
9410
9516
  let personaMeta = null;
9411
9517
  let coReasoned = false;
9412
9518
  let coReasonerModel = null;
9519
+ let moderatorUsed = null;
9413
9520
  if (moderator) {
9414
- const synthProvider = superRequested && opts.providers["anthropic"] ? retargetForSuper(opts.providers["anthropic"]) : upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : moderator;
9521
+ const synthProvider = seat?.provider ?? moderator;
9522
+ moderatorUsed = { provider: synthProvider.name, model: synthProvider.model };
9415
9523
  const condensed = buildModeratorTranscript(transcript);
9416
9524
  const persona = buildPersonaInjection({
9417
9525
  toolName: "debate",
@@ -9437,7 +9545,7 @@ TRANSCRIPT:
9437
9545
  ${condensed}`
9438
9546
  }
9439
9547
  ];
9440
- const openAiSeat = selected.find((p) => p.name === "openai")?.model;
9548
+ const openAiSeat = synthProvider.name === "openai" ? synthProvider.model : selected.find((p) => p.name === "openai")?.model;
9441
9549
  const coProvider = pickCoReasoner(opts.providers, upgradeRequested, openAiSeat);
9442
9550
  const coReason = await coReasonThenInject({
9443
9551
  provider: coProvider,
@@ -9497,20 +9605,22 @@ ${condensed}`
9497
9605
  transcript,
9498
9606
  synthesis
9499
9607
  };
9608
+ if (moderatorUsed) result["moderator"] = moderatorUsed;
9500
9609
  if (personaMeta && personaMeta.used !== null) result["persona"] = personaMeta;
9501
9610
  if (compactionMeta) result["round_compaction"] = compactionMeta;
9502
9611
  if (upgraded) {
9503
9612
  result["reasoning_upgrade"] = {
9504
9613
  applied: true,
9505
- model: superRequested ? superPrimary("anthropic") ?? UPGRADE_MODEL : UPGRADE_MODEL,
9506
- label: UPGRADE_LABEL,
9614
+ provider: seat.provider.name,
9615
+ model: seat.provider.model,
9616
+ label: seat.label ?? seat.provider.model,
9507
9617
  seat: "moderator synthesis",
9508
9618
  ...coReasoned && coReasonerModel ? { co_reasoner: { model: coReasonerModel, label: coReasonLabel(coReasonerModel) } } : {}
9509
9619
  };
9510
9620
  } else if (upgradeRequested) {
9511
9621
  result["reasoning_upgrade"] = {
9512
9622
  applied: false,
9513
- reason: `no Anthropic key available \u2014 the ${UPGRADE_LABEL} upgrade needs it.`
9623
+ reason: seat?.skipReason ?? "no moderator was available for the upgrade."
9514
9624
  };
9515
9625
  } else {
9516
9626
  const assessment = assessReasoning(topic);
@@ -10139,12 +10249,25 @@ function runListProviders(args, opts) {
10139
10249
  }
10140
10250
  const result = {
10141
10251
  providers,
10142
- moderator_default: opts.moderatorDefault ?? "anthropic",
10252
+ moderator_default: opts.moderatorDefault ?? DEFAULT_MODERATOR,
10253
+ // Who will actually moderate right now: the configured spec if that
10254
+ // provider has a key, else the first available (what the tools fall to).
10255
+ moderator: describeModerator(opts.providers ?? {}, opts.moderatorDefault),
10143
10256
  usage_hint: USAGE_HINT
10144
10257
  };
10145
10258
  if (superRequested) result["super_mode"] = true;
10146
10259
  return result;
10147
10260
  }
10261
+ function describeModerator(providers, spec) {
10262
+ const r = resolveModerator(providers, spec);
10263
+ const p = r.provider ?? Object.values(providers)[0];
10264
+ return {
10265
+ spec: spec ?? DEFAULT_MODERATOR,
10266
+ provider: p?.name ?? null,
10267
+ model: p?.model ?? null,
10268
+ available: r.provider !== void 0
10269
+ };
10270
+ }
10148
10271
 
10149
10272
  // src/tools/models.ts
10150
10273
  var KNOWN_PROVIDERS7 = [
@@ -11694,7 +11817,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
11694
11817
  var DEFAULT_PACKAGE = "crosscheck-cli";
11695
11818
  var FETCH_TIMEOUT_MS = 3e3;
11696
11819
  function engineVersion() {
11697
- return true ? "0.2.30" : "0.0.0-dev";
11820
+ return true ? "0.2.31" : "0.0.0-dev";
11698
11821
  }
11699
11822
  function defaultUpdateCachePath() {
11700
11823
  const base = process.env["CROSSCHECK_DATA_DIR"] || path9.join(os.homedir() || os.tmpdir(), ".crosscheck");
@@ -12139,7 +12262,7 @@ var HELP_CATALOG = [
12139
12262
  primaryArg: "topic",
12140
12263
  summary: "Bounded multi-round debate between models, ending in a synthesized recommendation.",
12141
12264
  example: "xc debate should we adopt a monorepo?",
12142
- detail: `The panel argues across a few rounds \u2014 each model sees the others' prior turns, concedes or pushes back \u2014 then a moderator synthesizes a single grounded recommendation. Supports reasoning:"max" to bump the moderator synthesis seat to Fable 5. Great for contentious or trade-off-heavy calls.`
12265
+ detail: `The panel argues across a few rounds \u2014 each model sees the others' prior turns, concedes or pushes back \u2014 then a moderator synthesizes a single grounded recommendation. Any model can moderate \u2014 pass moderator:"openai" or an exact model (moderator:"openai:gpt-6-sol"), or set a default with \`crosscheck moderator set\`. reasoning:"max" bumps the moderator's synthesis to its provider's flagship (Fable 5 for Anthropic). Great for contentious or trade-off-heavy calls.`
12143
12266
  },
12144
12267
  {
12145
12268
  name: "coordinate",
@@ -12382,6 +12505,10 @@ function renderHelpCommand(entry) {
12382
12505
  }
12383
12506
 
12384
12507
  // src/tools/index.ts
12508
+ var MODERATOR_PARAM = {
12509
+ type: "string",
12510
+ description: 'Who moderates (synthesises) this run: a provider ("openai") or an exact model ("openai:gpt-6-sol"). Any configured provider works. Defaults to the configured moderator (CROSSCHECK_MODERATOR / config `moderator`).'
12511
+ };
12385
12512
  function defineTool(opts) {
12386
12513
  return {
12387
12514
  name: opts.name,
@@ -12616,7 +12743,7 @@ function createTool(o, toolName, cheapDefault) {
12616
12743
  instruction: { type: "string" },
12617
12744
  documents: { type: "array", items: { type: "string" } },
12618
12745
  providers: { type: "array", items: { type: "string" } },
12619
- moderator: { type: "string" },
12746
+ moderator: MODERATOR_PARAM,
12620
12747
  constraints: { type: "string" },
12621
12748
  target_path: { type: "string" },
12622
12749
  session_id: { type: "string" },
@@ -12657,7 +12784,7 @@ function orchestrateTool(providers, allowlist, moderator, storage, pricing, brea
12657
12784
  dag: { type: "object", additionalProperties: true },
12658
12785
  context: { type: "string" },
12659
12786
  providers: { type: "array", items: { type: "string" } },
12660
- moderator: { type: "string" },
12787
+ moderator: MODERATOR_PARAM,
12661
12788
  fail_fast: { type: "boolean" },
12662
12789
  plan_only: { type: "boolean" },
12663
12790
  cheap_mode: { type: "boolean" },
@@ -13036,7 +13163,7 @@ function planTool(providers, allowlist, storage, breakers, transcriptsDir, repoR
13036
13163
  constraints: { type: "string" },
13037
13164
  context: { type: "string" },
13038
13165
  providers: { type: "array", items: { type: "string" } },
13039
- moderator: { type: "string" },
13166
+ moderator: MODERATOR_PARAM,
13040
13167
  session_id: { type: "string" },
13041
13168
  structured: { type: "boolean" },
13042
13169
  mode: { type: "string", enum: ["fast", "thorough"] },
@@ -13098,7 +13225,7 @@ function coordinateTool(providers, allowlist, innerCallers, storage, breakers, t
13098
13225
  providers: { type: "array", items: { type: "string" } },
13099
13226
  proposer: { type: "string" },
13100
13227
  synthesizer: { type: "string" },
13101
- moderator: { type: "string" },
13228
+ moderator: MODERATOR_PARAM,
13102
13229
  critics: { type: "array", items: { type: "string" } },
13103
13230
  session_id: { type: "string" },
13104
13231
  untrusted_input: { type: "boolean" },
@@ -13131,7 +13258,7 @@ function debateTool(providers, allowlist, innerCallers, storage, pricing, breake
13131
13258
  context: { type: "string" },
13132
13259
  max_rounds: { type: "integer", minimum: 1 },
13133
13260
  providers: { type: "array", items: { type: "string" } },
13134
- moderator: { type: "string" },
13261
+ moderator: MODERATOR_PARAM,
13135
13262
  session_id: { type: "string" },
13136
13263
  reasoning: { type: "string", enum: ["default", "max"], description: '"max" bumps the moderator-synthesis seat to Fable 5 (premium thinking model); the debaters stay on their normal models. Omit for the Opus 4.8 default.' },
13137
13264
  structured: { type: "boolean" },
@@ -13676,8 +13803,8 @@ function createEmbeddedEngine(opts) {
13676
13803
  const built = Object.fromEntries(
13677
13804
  Object.entries(buildProviders({ env, pricing })).map(([name, p]) => [name, withActivity(p)])
13678
13805
  );
13679
- const moderator = opts.moderator ?? "anthropic";
13680
- const tools = registerCoreTools({ providers: built, pricing });
13806
+ const moderator = opts.moderator ?? DEFAULT_MODERATOR;
13807
+ const tools = registerCoreTools({ providers: built, pricing, moderatorDefault: moderator });
13681
13808
  const providerIds = Object.keys(built).map(vaultId).sort();
13682
13809
  const models = {};
13683
13810
  for (const [name, p] of Object.entries(built)) models[vaultId(name)] = p.model;
@@ -13708,7 +13835,8 @@ function createEmbeddedEngine(opts) {
13708
13835
  nextCallId,
13709
13836
  skipped: /* @__PURE__ */ new Set(),
13710
13837
  inflight: /* @__PURE__ */ new Map(),
13711
- moderator: vaultId(moderator),
13838
+ // The provider half of a `provider:model` spec, as the vault spells it.
13839
+ moderator: vaultId(moderatorProviderName(moderator)),
13712
13840
  ...runOpts.callTimeoutMs && runOpts.callTimeoutMs > 0 ? { callTimeoutMs: runOpts.callTimeoutMs } : {},
13713
13841
  ...runOpts.images?.length ? { images: runOpts.images.filter((i) => IMAGE_MEDIA_TYPES.includes(i.mediaType) && typeof i.data === "string" && i.data.length > 0).slice(0, MAX_RUN_IMAGES) } : {}
13714
13842
  };