crosscheck-mcp 0.2.27 → 0.2.28

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.
@@ -15,20 +15,24 @@ var pricing_default = {
15
15
  notes: "Prices reflect public list pricing per provider. cached_per_1k applies to prompt tokens served from prompt-cache (Anthropic) or input-cache (OpenAI) when supported. Update when providers change rates. Missing models fall back to cost=0 with estimated=true. 2026-06-07: removed decommissioned gemini-2.0-flash / gemini-2.0-flash-lite (Google returns 404) and replaced the low-tier lite model with gemini-2.5-flash-lite. 2026-06-08: bumped the default Anthropic model to claude-opus-4-8. Kept gemini-2.5-pro as the Gemini default (gemini-3.1-pro-preview measured ~2.2x the cost at $2/$12 per M \u2014 output-token dominated by ~1.5k thinking tokens \u2014 so not worth it for a 1-of-4 panel voice). 2026-06-09: corrected rates verified against live provider pricing pages \u2014 gemini-2.5-pro output $5->$10/M; gemini-2.5-flash $0.15/$0.60 -> $0.30/$2.50; gpt-5 $5/$15 -> $1.25/$10 (cached $0.125); grok-4-latest input $5->$3/M (legacy grok-4 tier). Anthropic opus/sonnet/haiku rates confirmed unchanged. Older/unused models (gpt-4o, o1, o3, grok-3) not all re-verified. 2026-07-02: added claude-fable-5 as the optional reasoning-upgrade model (used only for the lead reasoning seat when the operator bumps a heavy task). 2026-07-04: set claude-fable-5 to its real pay-as-you-go API price effective 2026-07-07 \u2014 $10/M input ($0.01/1k), $50/M output ($0.05/1k), cached at 10% of input ($0.001/1k). Dropped the estimated flag. Note: Fable 5 is cheaper than opus-4-8 on both input and output. 2026-07-09: Google retired gemini-2.5-pro AND gemini-3-pro-preview (both now 404 'no longer available'). Moved the Gemini default to gemini-3.1-pro-preview ($2/M in, $12/M out, cache $0.20/M \u2014 the newest working pro; note it's a preview and may need another bump) and added gemini-3.5-flash ($1.50/M in, $9/M out, cache $0.15/M \u2014 GA) to the low/cheap tier. Removed the dead gemini-2.5-pro rate. IMPORTANT: gemini-3.x are heavy thinking models \u2014 thoughtsTokenCount (billed as output) is now folded into completion_tokens in the adapter, so cost reflects reasoning tokens. 2026-07-13: bumped the default OpenAI model to gpt-5.5 ($5/M in, $30/M out, cached $0.50/M \u2014 verified live). Note gpt-5.5 is markedly pricier than gpt-5 ($1.25/$10): ~4x input, 3x output. Kept gpt-5 in the table for cost lookups on pinned installs. 2026-07-16: added gpt-5.6 at the Sol (flagship) tier \u2014 $5/M in, $30/M out, cached $0.50/M (cache-write $6.25/M not modeled). gpt-5.6 is the second premium voice for the max-reasoning co-reasoner (runs alongside claude-fable-5 when an OpenAI key is set). Terra/Luna tiers not added (unused). 2026-07-17: added Moonshot AI (Kimi) provider with kimi-k3, base URL https://api.moonshot.ai/v1. Confirmed real rates \u2014 $3.00/M input (cache miss, $0.003/1k), $15.00/M output ($0.015/1k), $0.30/M cache-hit input ($0.0003/1k); 1M-token context. Kimi K3 is reasoning-class (temperature must be 1; uses max_completion_tokens). 2026-07-24: added claude-opus-5 ($5/M in, $25/M out, cached $0.50/M -- 10% of input, matching this table's existing cache-discount ratio) and made it the default anthropic model (was claude-opus-4-8). Fable 5 remains the reasoning-upgrade/super-mode target, unchanged. 2026-08-04: added Alibaba Cloud Qwen provider (OpenAI-compatible, DashScope international endpoint https://dashscope-intl.aliyuncs.com/compatible-mode/v1) with default model qwen3.8-max -- confirmed business pricing $2.00/M input ($0.002/1k), $6.00/M output ($0.006/1k), cache estimated at 10% of input ($0.0002/1k, not independently confirmed). Also added qwen3.7-max as a fallback tier at $1.25/M in ($0.00125/1k) / $3.75/M out ($0.00375/1k). Note: the model string initially configured (qwen-v3.8 / qwen-v3.7) does not exist on DashScope and 404s -- live-probed the real key against qwen3.8-max, qwen3.7-max, qwen3-max, qwen-max, and qwen-plus, all of which work; corrected the default and pricing keys to qwen3.8-max/qwen3.7-max and fixed QWEN_MODEL in both .env files to match. Qwen's Max tier is a standard instruct model, not reasoning-class -- normal temperature/max_tokens handling. 2026-09-06: added gpt-6-astra at published list rates ($10/$50 per Mtok, $1/Mtok cache read; the $12.50/Mtok cache-WRITE rate has no field in this schema and is not modelled). gemini-3.8-flash now carries Google's published paid-tier rates ($0.75/$3.75/$0.075 per Mtok). THESE DOUBLE ON 2027-01-01 ($1.50/$7.50/$0.15) and this schema has no effective-date support, so they must be updated by hand on that date or every Gemini cost will read half of actual. claude-fable-5-1 now carries published rates ($10/$50/$0.25 per Mtok). Note its cache-read rate is 4x cheaper than claude-fable-5's, so the two must not be assumed to track each other. No inferred rows remain. All three were previously absent, which silently recorded their cost as $0."
16
16
  },
17
17
  anthropic: {
18
+ _source: {
19
+ url: "https://platform.claude.com/docs/en/about-claude/pricing",
20
+ verified_at: "2026-09-27"
21
+ },
18
22
  "claude-opus-4-5": {
19
- prompt_per_1k: 0.015,
20
- completion_per_1k: 0.075,
21
- cached_per_1k: 15e-4
23
+ prompt_per_1k: 5e-3,
24
+ completion_per_1k: 0.025,
25
+ cached_per_1k: 5e-4
22
26
  },
23
27
  "claude-opus-4-7": {
24
- prompt_per_1k: 0.015,
25
- completion_per_1k: 0.075,
26
- cached_per_1k: 15e-4
28
+ prompt_per_1k: 5e-3,
29
+ completion_per_1k: 0.025,
30
+ cached_per_1k: 5e-4
27
31
  },
28
32
  "claude-opus-4-8": {
29
- prompt_per_1k: 0.015,
30
- completion_per_1k: 0.075,
31
- cached_per_1k: 15e-4
33
+ prompt_per_1k: 5e-3,
34
+ completion_per_1k: 0.025,
35
+ cached_per_1k: 5e-4
32
36
  },
33
37
  "claude-opus-5-5": {
34
38
  prompt_per_1k: 4e-3,
@@ -77,6 +81,10 @@ var pricing_default = {
77
81
  }
78
82
  },
79
83
  openai: {
84
+ _source: {
85
+ url: "https://developers.openai.com/api/docs/pricing",
86
+ verified_at: "2026-09-27"
87
+ },
80
88
  "gpt-6-astra": {
81
89
  prompt_per_1k: 0.01,
82
90
  completion_per_1k: 0.05,
@@ -161,6 +169,36 @@ var pricing_default = {
161
169
  prompt_per_1k: 11e-4,
162
170
  completion_per_1k: 44e-4,
163
171
  cached_per_1k: 55e-5
172
+ },
173
+ "gpt-5-pro": {
174
+ prompt_per_1k: 0.015,
175
+ completion_per_1k: 0.12,
176
+ cached_per_1k: 0
177
+ },
178
+ "gpt-5.2-pro": {
179
+ prompt_per_1k: 0.021,
180
+ completion_per_1k: 0.168,
181
+ cached_per_1k: 0
182
+ },
183
+ "gpt-5.4-pro": {
184
+ prompt_per_1k: 0.03,
185
+ completion_per_1k: 0.18,
186
+ cached_per_1k: 0
187
+ },
188
+ "gpt-5.5-pro": {
189
+ prompt_per_1k: 0.03,
190
+ completion_per_1k: 0.18,
191
+ cached_per_1k: 0
192
+ },
193
+ "o1-pro": {
194
+ prompt_per_1k: 0.15,
195
+ completion_per_1k: 0.6,
196
+ cached_per_1k: 0
197
+ },
198
+ "o3-pro": {
199
+ prompt_per_1k: 0.02,
200
+ completion_per_1k: 0.08,
201
+ cached_per_1k: 0
164
202
  }
165
203
  },
166
204
  xai: {
@@ -395,20 +433,30 @@ function modelPricing(pricing, provider, model) {
395
433
  const block = pricing[provider];
396
434
  if (!block || typeof block !== "object" || Array.isArray(block)) return null;
397
435
  const table = block;
436
+ if (model.startsWith("_")) return null;
398
437
  let entry = table[model];
399
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
400
- const best = Object.keys(table).filter((k) => model.startsWith(k)).sort((a, b) => b.length - a.length)[0];
401
- entry = best !== void 0 ? table[best] : void 0;
438
+ let match = "exact";
439
+ if (!isRates(entry)) {
440
+ const best = Object.keys(table).filter((k) => !k.startsWith("_")).filter((k) => model.startsWith(k) && DATE_STAMP.test(model.slice(k.length))).sort((a, b) => b.length - a.length)[0];
441
+ if (best !== void 0) {
442
+ entry = table[best];
443
+ match = "stamp";
444
+ }
402
445
  }
403
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) return null;
446
+ if (!isRates(entry)) return null;
404
447
  const e = entry;
405
448
  return {
406
449
  prompt_per_1k: numberOrZero(e["prompt_per_1k"]),
407
450
  completion_per_1k: numberOrZero(e["completion_per_1k"]),
408
451
  cached_per_1k: numberOrZero(e["cached_per_1k"]),
409
- ...e["estimated"] === true ? { estimated: true } : {}
452
+ ...e["estimated"] === true ? { estimated: true } : {},
453
+ match
410
454
  };
411
455
  }
456
+ var DATE_STAMP = /^-\d{8}$/;
457
+ function isRates(v) {
458
+ return Boolean(v) && typeof v === "object" && !Array.isArray(v);
459
+ }
412
460
  function numberOrZero(v) {
413
461
  if (typeof v === "number" && Number.isFinite(v)) return v;
414
462
  if (typeof v === "string") {
@@ -488,8 +536,20 @@ var PROVIDER_CAPS = {
488
536
  gemini: {
489
537
  family: "gemini",
490
538
  system_role: "separate",
491
- supports_temperature: true,
492
- reasoning_prefixes: ["gemini-3.1-pro", "gemini-3.5-flash", "gemini-2.5-pro"]
539
+ // No sampling, on any Gemini model. Ignored since 3.6 Flash and rejected
540
+ // by upcoming models (Google, 2026-10). "model" means "omit for reasoning
541
+ // models", and every Gemini model is reasoning-class (below) — so this
542
+ // resolves to never, through the same rule the other providers use. The
543
+ // adapter also never sends it; this keeps the record honest for anything
544
+ // else that reads it.
545
+ supports_temperature: "model",
546
+ // EVERY Gemini model is reasoning-class. The old list named three
547
+ // families and missed gemini-3.8-flash — the DEFAULT — so the default
548
+ // model got the small non-reasoning budgets (768 tokens for an audit)
549
+ // while spending up to ~480 tokens of each call thinking. Google's docs
550
+ // say thinking cannot be switched off on current models, so a list of
551
+ // which ones think is a list that can only ever be incomplete.
552
+ reasoning_prefixes: ["gemini-"]
493
553
  },
494
554
  // Qwen's "Max" tier (qwen-v3.8, qwen-v3.7) is a standard instruct/chat
495
555
  // model, not a visible-reasoning model like QwQ — normal temperature and
@@ -612,6 +672,73 @@ function httpFailureToProviderError(provider, status, bodyText, retryAfterS, mod
612
672
  );
613
673
  }
614
674
 
675
+ // src/providers/network-errors.ts
676
+ function codeOf(e) {
677
+ if (!e || typeof e !== "object") return null;
678
+ const c = e.code;
679
+ return typeof c === "string" && c.length > 0 ? c : null;
680
+ }
681
+ function rootCause(e, depth = 0) {
682
+ if (depth > 5 || !e || typeof e !== "object") return e;
683
+ const o = e;
684
+ if (Array.isArray(o.errors) && o.errors.length > 0) {
685
+ const coded = o.errors.find((x) => codeOf(x) !== null);
686
+ return rootCause(coded ?? o.errors[0], depth + 1);
687
+ }
688
+ if (o.cause !== void 0 && o.cause !== null) return rootCause(o.cause, depth + 1);
689
+ return e;
690
+ }
691
+ var BY_CODE = {
692
+ ENOTFOUND: { cause: "dns", detail: "the provider's hostname did not resolve \u2014 DNS, or a typo'd base URL", transient: false, kind: "network" },
693
+ EAI_AGAIN: { cause: "dns", detail: "DNS lookup failed temporarily \u2014 resolver or network is flapping", transient: true, kind: "network" },
694
+ ECONNREFUSED: { cause: "refused", detail: "the connection was refused \u2014 nothing is listening, or a proxy blocked it", transient: false, kind: "network" },
695
+ ECONNRESET: { cause: "reset", detail: "the peer closed the connection mid-request \u2014 flaky path, or an upstream error behind a proxy", transient: true, kind: "network" },
696
+ EPIPE: { cause: "reset", detail: "the connection closed while we were still writing", transient: true, kind: "network" },
697
+ ETIMEDOUT: { cause: "connect_timeout", detail: "the connection timed out before it was established", transient: true, kind: "timeout" },
698
+ EHOSTUNREACH: { cause: "unreachable", detail: "no route to the provider \u2014 VPN, or offline", transient: true, kind: "network" },
699
+ ENETUNREACH: { cause: "unreachable", detail: "the network is unreachable \u2014 offline, or a routing change", transient: true, kind: "network" },
700
+ ENETDOWN: { cause: "unreachable", detail: "the local network is down", transient: true, kind: "network" },
701
+ EPROTO: { cause: "tls", detail: "the TLS handshake failed \u2014 an intercepting proxy, or a protocol mismatch", transient: false, kind: "network" },
702
+ ERR_TLS_CERT_ALTNAME_INVALID: { cause: "tls", detail: "the certificate did not match the hostname \u2014 traffic is being intercepted", transient: false, kind: "network" },
703
+ CERT_HAS_EXPIRED: { cause: "tls", detail: "the server certificate has expired, or this machine's clock is wrong", transient: false, kind: "network" },
704
+ UNABLE_TO_VERIFY_LEAF_SIGNATURE: { cause: "tls", detail: "the certificate chain could not be verified \u2014 a corporate proxy's root is probably not trusted here", transient: false, kind: "network" },
705
+ UND_ERR_CONNECT_TIMEOUT: { cause: "connect_timeout", detail: "could not open a connection within the timeout \u2014 firewall, or the host is down", transient: true, kind: "timeout" },
706
+ UND_ERR_HEADERS_TIMEOUT: { cause: "read_timeout", detail: "connected, but the provider sent no response headers in time \u2014 it is overloaded or thinking too long", transient: true, kind: "timeout" },
707
+ UND_ERR_BODY_TIMEOUT: { cause: "read_timeout", detail: "the response body stalled mid-stream", transient: true, kind: "timeout" },
708
+ UND_ERR_SOCKET: { cause: "reset", detail: "the socket closed unexpectedly", transient: true, kind: "network" },
709
+ UND_ERR_ABORTED: { cause: "aborted", detail: "the request was cancelled", transient: false, kind: "network" },
710
+ ABORT_ERR: { cause: "aborted", detail: "the request was cancelled", transient: false, kind: "network" }
711
+ };
712
+ function diagnoseNetworkError(e) {
713
+ const root = rootCause(e);
714
+ const code = codeOf(root) ?? codeOf(e);
715
+ if (code && BY_CODE[code]) return { ...BY_CODE[code], code };
716
+ const name = root && typeof root === "object" ? root.name : void 0;
717
+ if (name === "AbortError" || name === "TimeoutError") {
718
+ return {
719
+ cause: name === "TimeoutError" ? "read_timeout" : "aborted",
720
+ code: code ?? String(name),
721
+ detail: name === "TimeoutError" ? "the request exceeded its timeout" : "the request was cancelled",
722
+ transient: name === "TimeoutError",
723
+ kind: name === "TimeoutError" ? "timeout" : "network"
724
+ };
725
+ }
726
+ return {
727
+ cause: "unknown",
728
+ code,
729
+ detail: code ? `the connection failed with ${code}` : "the connection failed and the underlying error carried no code",
730
+ transient: true,
731
+ kind: "network"
732
+ };
733
+ }
734
+ function looksLikeNetworkFailure(d) {
735
+ return d.code !== null || d.cause !== "unknown";
736
+ }
737
+ function networkErrorMessage(provider, d) {
738
+ const code = d.code ? ` [${d.code}]` : "";
739
+ return `${provider}: ${d.detail}${code}`;
740
+ }
741
+
615
742
  // src/providers/retry.ts
616
743
  var override = null;
617
744
  function resolveRetryConfig() {
@@ -934,7 +1061,11 @@ async function sendAnthropic(args) {
934
1061
  try {
935
1062
  respLike = await doFetch(url, init);
936
1063
  } catch (e) {
937
- throw new ProviderError("network", `anthropic: fetch failed: ${e.message}`);
1064
+ const d = diagnoseNetworkError(e);
1065
+ if (!looksLikeNetworkFailure(d)) throw e;
1066
+ throw new ProviderError(d.kind, networkErrorMessage("anthropic", d), {
1067
+ transient: d.transient
1068
+ });
938
1069
  }
939
1070
  const status = respLike.status;
940
1071
  if (status >= 200 && status < 300) {
@@ -1007,6 +1138,11 @@ function jsonSchemaToGeminiSchema(schema) {
1007
1138
  }
1008
1139
  return out;
1009
1140
  }
1141
+ var GEMINI_THINKING_HEADROOM_TOKENS = 16384;
1142
+ function thinkingHeadroom() {
1143
+ const raw = Number(process.env["CROSSCHECK_GEMINI_THINKING_HEADROOM_TOKENS"]);
1144
+ return Number.isFinite(raw) && raw >= 0 ? Math.trunc(raw) : GEMINI_THINKING_HEADROOM_TOKENS;
1145
+ }
1010
1146
  function buildGeminiRequest(opts) {
1011
1147
  const contents = [];
1012
1148
  let systemText = null;
@@ -1025,8 +1161,9 @@ function buildGeminiRequest(opts) {
1025
1161
  const body = {
1026
1162
  contents,
1027
1163
  generationConfig: {
1028
- maxOutputTokens: opts.maxTokens,
1029
- temperature: opts.temperature
1164
+ // Answer budget + thinking headroom. No temperature / topP / topK /
1165
+ // thinkingBudget, on any model — see the header note.
1166
+ maxOutputTokens: opts.maxTokens + thinkingHeadroom()
1030
1167
  }
1031
1168
  };
1032
1169
  if (systemText !== null && systemText !== "") {
@@ -1036,8 +1173,8 @@ function buildGeminiRequest(opts) {
1036
1173
  body.generationConfig.responseMimeType = "application/json";
1037
1174
  body.generationConfig.responseSchema = jsonSchemaToGeminiSchema(opts.jsonSchema);
1038
1175
  }
1039
- const url = `${GEMINI_API_URL_BASE}/${encodeURIComponent(opts.model)}:generateContent?key=${encodeURIComponent(opts.apiKey)}`;
1040
- return { url, headers: {}, body };
1176
+ const url = `${GEMINI_API_URL_BASE}/${encodeURIComponent(opts.model)}:generateContent`;
1177
+ return { url, headers: { "x-goog-api-key": opts.apiKey }, body };
1041
1178
  }
1042
1179
  function parseGeminiResponse(opts) {
1043
1180
  const r = opts.resp ?? {};
@@ -1067,16 +1204,19 @@ function parseGeminiResponse(opts) {
1067
1204
  }
1068
1205
  try {
1069
1206
  const first = cands[0];
1070
- const content = first["content"];
1071
- const parts = content["parts"];
1207
+ const finishReason = typeof first["finishReason"] === "string" ? first["finishReason"] : void 0;
1208
+ const content = first["content"] ?? {};
1209
+ const parts = Array.isArray(content["parts"]) ? content["parts"] : [];
1072
1210
  let text = "";
1073
1211
  for (const p of parts) {
1074
1212
  if (p && typeof p === "object") {
1075
- const t = p["text"];
1213
+ const part = p;
1214
+ if (part["thought"] === true) continue;
1215
+ const t = part["text"];
1076
1216
  if (typeof t === "string") text += t;
1077
1217
  }
1078
1218
  }
1079
- return { text, usage };
1219
+ return { text, usage, ...finishReason ? { finishReason } : {} };
1080
1220
  } catch (e) {
1081
1221
  throw new ProviderError(
1082
1222
  "parse",
@@ -1105,7 +1245,8 @@ async function sendGemini(args) {
1105
1245
  apiKey: args.apiKey,
1106
1246
  messages: args.messages,
1107
1247
  maxTokens: args.maxTokens,
1108
- temperature: args.temperature,
1248
+ // args.temperature is deliberately NOT forwarded: Gemini ignores it and
1249
+ // upcoming models reject it. See the header note.
1109
1250
  ...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
1110
1251
  });
1111
1252
  const doFetch = args.fetchImpl ?? globalThis.fetch;
@@ -1120,7 +1261,11 @@ async function sendGemini(args) {
1120
1261
  try {
1121
1262
  respLike = await doFetch(url, init);
1122
1263
  } catch (e) {
1123
- throw new ProviderError("network", `gemini: fetch failed: ${e.message}`);
1264
+ const d = diagnoseNetworkError(e);
1265
+ if (!looksLikeNetworkFailure(d)) throw e;
1266
+ throw new ProviderError(d.kind, networkErrorMessage("gemini", d), {
1267
+ transient: d.transient
1268
+ });
1124
1269
  }
1125
1270
  const status = respLike.status;
1126
1271
  if (status >= 200 && status < 300) {
@@ -1130,11 +1275,18 @@ async function sendGemini(args) {
1130
1275
  } catch (e) {
1131
1276
  throw new ProviderError("parse", `gemini: response body not JSON: ${e.message}`);
1132
1277
  }
1133
- const { text, usage } = parseGeminiResponse({
1278
+ const { text, usage, finishReason } = parseGeminiResponse({
1134
1279
  resp: parsed,
1135
1280
  model: args.model,
1136
1281
  purpose: args.purpose ?? "worker"
1137
1282
  });
1283
+ if (text.trim() === "" && finishReason === "MAX_TOKENS") {
1284
+ throw new ProviderError(
1285
+ "parse",
1286
+ `gemini: the answer was cut off before any visible text \u2014 thinking used the whole output budget (${usage.completion_tokens} tokens). Raise CROSSCHECK_GEMINI_THINKING_HEADROOM_TOKENS or the purpose's budget.`,
1287
+ { transient: false }
1288
+ );
1289
+ }
1138
1290
  return { text, attempts: 1, usage: applyPricing2(usage, args.pricing) };
1139
1291
  }
1140
1292
  const bodyText = await respLike.text().catch(() => "");
@@ -1301,7 +1453,11 @@ async function sendOpenAICompatible(args) {
1301
1453
  try {
1302
1454
  respLike = await doFetch(url, init);
1303
1455
  } catch (e) {
1304
- throw new ProviderError("network", `${args.provider}: fetch failed: ${e.message}`);
1456
+ const d = diagnoseNetworkError(e);
1457
+ if (!looksLikeNetworkFailure(d)) throw e;
1458
+ throw new ProviderError(d.kind, networkErrorMessage(args.provider, d), {
1459
+ transient: d.transient
1460
+ });
1305
1461
  }
1306
1462
  const status = respLike.status;
1307
1463
  if (status >= 200 && status < 300) {
@@ -1475,7 +1631,7 @@ import { z } from "zod";
1475
1631
 
1476
1632
  // src/server-meta.ts
1477
1633
  var SERVER_NAME = "crosscheck-agent";
1478
- var SERVER_VERSION = true ? "0.2.27" : "0.0.0-dev";
1634
+ var SERVER_VERSION = true ? "0.2.28" : "0.0.0-dev";
1479
1635
 
1480
1636
  // src/tools/audit.ts
1481
1637
  import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
@@ -1698,6 +1854,31 @@ function pyReprType(t) {
1698
1854
  return String(t);
1699
1855
  }
1700
1856
 
1857
+ // src/core/session.ts
1858
+ import { randomUUID } from "crypto";
1859
+ var processSessionId = null;
1860
+ var startedAt = null;
1861
+ function engineSessionId() {
1862
+ if (processSessionId === null) {
1863
+ processSessionId = randomUUID();
1864
+ startedAt = Date.now();
1865
+ }
1866
+ return processSessionId;
1867
+ }
1868
+ function resolveSessionId(callerSupplied) {
1869
+ const trimmed = typeof callerSupplied === "string" ? callerSupplied.trim() : "";
1870
+ return trimmed.length > 0 ? trimmed : engineSessionId();
1871
+ }
1872
+ function localSessionRecordingEnabled(env = globalThis.process?.env ?? {}) {
1873
+ const v = (env["CROSSCHECK_RECORD_SESSIONS"] ?? "").trim().toLowerCase();
1874
+ return !["0", "false", "off", "no"].includes(v);
1875
+ }
1876
+ function recordingSessionId(callerSupplied) {
1877
+ if (localSessionRecordingEnabled()) return resolveSessionId(callerSupplied);
1878
+ const trimmed = typeof callerSupplied === "string" ? callerSupplied.trim() : "";
1879
+ return trimmed.length > 0 ? trimmed : null;
1880
+ }
1881
+
1701
1882
  // src/core/usage.ts
1702
1883
  function emptyUsage(provider, model, purpose = "worker") {
1703
1884
  return {
@@ -1803,11 +1984,11 @@ function withCommas(n) {
1803
1984
  function renderRunSummary(opts) {
1804
1985
  const endedAt = opts.endedAtS ?? Math.trunc(Date.now() / 1e3);
1805
1986
  let scope = "call";
1806
- let startedAt = null;
1987
+ let startedAt2 = null;
1807
1988
  let rows = [];
1808
1989
  if (opts.sessionScope && opts.sessionScope.rows.length > 0) {
1809
1990
  scope = "session";
1810
- startedAt = opts.sessionScope.startedAt;
1991
+ startedAt2 = opts.sessionScope.startedAt;
1811
1992
  rows = opts.sessionScope.rows.map((r) => ({ ...r }));
1812
1993
  } else {
1813
1994
  const byPurpose = /* @__PURE__ */ new Map();
@@ -1838,6 +2019,7 @@ function renderRunSummary(opts) {
1838
2019
  row.cpu_ms += a.cpu_ms ?? 0;
1839
2020
  if (a.cache_hit) row.cache_hits += 1;
1840
2021
  if (a.error) row.errors += 1;
2022
+ if (a.usage?.estimated) row.estimated = true;
1841
2023
  }
1842
2024
  rows = Array.from(byPurpose.values());
1843
2025
  }
@@ -1850,16 +2032,18 @@ function renderRunSummary(opts) {
1850
2032
  wall_ms: rows.reduce((s, r) => s + r.wall_ms, 0),
1851
2033
  cpu_ms: rows.reduce((s, r) => s + r.cpu_ms, 0),
1852
2034
  cache_hits: rows.reduce((s, r) => s + r.cache_hits, 0),
1853
- errors: rows.reduce((s, r) => s + r.errors, 0)
2035
+ errors: rows.reduce((s, r) => s + r.errors, 0),
2036
+ ...rows.some((r) => r.estimated) ? { estimated: true } : {}
1854
2037
  };
1855
2038
  const titleLeft = scope === "session" ? `session: ${opts.sessionId ?? ""}` : `call: ${opts.toolName}`;
1856
- const header = `${titleLeft} (${totals.calls} calls, ${withCommas(totals.total_tokens)} tokens, $${totals.cost_usd.toFixed(4)}, ${(totals.wall_ms / 1e3).toFixed(1)}s wall, ${(totals.cpu_ms / 1e3).toFixed(3)}s cpu)`;
2039
+ const costText = totals.estimated ? `$${totals.cost_usd.toFixed(4)}+ (some calls unpriced)` : `$${totals.cost_usd.toFixed(4)}`;
2040
+ const header = `${titleLeft} (${totals.calls} calls, ${withCommas(totals.total_tokens)} tokens, ${costText}, ${(totals.wall_ms / 1e3).toFixed(1)}s wall, ${(totals.cpu_ms / 1e3).toFixed(3)}s cpu)`;
1857
2041
  const bodyLines = [];
1858
2042
  for (let i = 0; i < rows.length; i++) {
1859
2043
  const r = rows[i];
1860
2044
  const glyph = i === rows.length - 1 ? "`-" : "|-";
1861
2045
  bodyLines.push(
1862
- `${glyph} purpose: ${r.purpose} (calls=${r.calls} tokens=${withCommas(r.total_tokens)} cost=$${r.cost_usd.toFixed(4)} wall=${(r.wall_ms / 1e3).toFixed(1)}s cpu=${(r.cpu_ms / 1e3).toFixed(3)}s)`
2046
+ `${glyph} purpose: ${r.purpose} (calls=${r.calls} tokens=${withCommas(r.total_tokens)} cost=$${r.cost_usd.toFixed(4)}${r.estimated ? "+" : ""} wall=${(r.wall_ms / 1e3).toFixed(1)}s cpu=${(r.cpu_ms / 1e3).toFixed(3)}s)`
1863
2047
  );
1864
2048
  }
1865
2049
  const callByModel = rollupSpendByModel(
@@ -1907,7 +2091,7 @@ function renderRunSummary(opts) {
1907
2091
  tool: opts.toolName,
1908
2092
  scope,
1909
2093
  currency: "USD",
1910
- started_at: startedAt,
2094
+ started_at: startedAt2,
1911
2095
  ended_at: endedAt,
1912
2096
  rows,
1913
2097
  totals,
@@ -2032,14 +2216,15 @@ async function attachUsageBlock(result, answers, opts) {
2032
2216
  delete result["_suppress_run_summary"];
2033
2217
  }
2034
2218
  async function appendUsageLog(storage, sessionId, toolName, answers, nowS) {
2035
- if (!sessionId || answers.length === 0) return;
2219
+ const sid = recordingSessionId(sessionId);
2220
+ if (!sid || answers.length === 0) return;
2036
2221
  const now = nowS ?? Math.trunc(Date.now() / 1e3);
2037
2222
  const rows = [];
2038
2223
  for (const a of answers) {
2039
2224
  const u = a.usage;
2040
2225
  if (!u || typeof u.provider !== "string" || u.provider === "") continue;
2041
2226
  rows.push({
2042
- session_id: sessionId,
2227
+ session_id: sid,
2043
2228
  ts: now,
2044
2229
  tool: toolName,
2045
2230
  purpose: u.purpose ?? "worker",
@@ -2062,13 +2247,14 @@ async function appendUsageLog(storage, sessionId, toolName, answers, nowS) {
2062
2247
  }
2063
2248
  }
2064
2249
  async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, nowS) {
2065
- if (!sessionId) return;
2250
+ const sid = recordingSessionId(sessionId);
2251
+ if (!sid) return;
2066
2252
  const now = nowS ?? Math.trunc(Date.now() / 1e3);
2067
2253
  try {
2068
- let existing = await storage.getSession(sessionId);
2254
+ let existing = await storage.getSession(sid);
2069
2255
  if (!existing) {
2070
2256
  await storage.upsertSession({
2071
- session_id: sessionId,
2257
+ session_id: sid,
2072
2258
  started_at: now,
2073
2259
  last_at: now,
2074
2260
  calls: 0,
@@ -2081,7 +2267,7 @@ async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, now
2081
2267
  total_cost_usd: 0,
2082
2268
  total_cpu_ms: 0
2083
2269
  });
2084
- existing = await storage.getSession(sessionId);
2270
+ existing = await storage.getSession(sid);
2085
2271
  }
2086
2272
  if (!existing) return;
2087
2273
  let promptDelta = 0;
@@ -2101,7 +2287,7 @@ async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, now
2101
2287
  }
2102
2288
  if (a.cache_hit) cacheHitDelta += 1;
2103
2289
  }
2104
- await storage.accumulateSessionTotals(sessionId, {
2290
+ await storage.accumulateSessionTotals(sid, {
2105
2291
  calls: answers.length,
2106
2292
  wall_ms: wallMs,
2107
2293
  cache_hits: cacheHitDelta,
@@ -5033,10 +5219,6 @@ If you need supporting evidence, you may emit ONE \`<tool_call>...</tool_call>\`
5033
5219
  }
5034
5220
 
5035
5221
  // src/tools/confer.ts
5036
- var DEFERRED_OPTS = [
5037
- // empty — every confer opt runs natively except worker_tools, which
5038
- // is gated below (non-empty list → defer).
5039
- ];
5040
5222
  async function runConfer(args, opts) {
5041
5223
  const callStartedWall = performance3.now();
5042
5224
  const callStartedCpu = process.cpuUsage();
@@ -5052,16 +5234,11 @@ async function runConfer(args, opts) {
5052
5234
  rejectedWorkerTools.push(t);
5053
5235
  }
5054
5236
  }
5055
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
5056
- const needsBridge = DEFERRED_OPTS.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
5057
- if (needsBridge) {
5058
- if (opts.bridge && opts.bridge.toolNames.has("confer")) {
5059
- return await deferConfer(args, opts.bridge);
5060
- }
5237
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
5061
5238
  return errorEnvelope2(
5062
5239
  "CONFER_OPT_NOT_NATIVE",
5063
5240
  "worker_tools requested but innerCallers are not wired",
5064
- "Native confer covers untrusted_input + early_stop + extract_claims + inject_session_memory + auto_panel. worker_tools needs innerCallers wired by the host (or CROSSCHECK_BRIDGE_PYTHON=1 as a backstop)."
5241
+ "Native confer covers untrusted_input + early_stop + extract_claims + inject_session_memory + auto_panel. worker_tools needs innerCallers wired by the host."
5065
5242
  );
5066
5243
  }
5067
5244
  const question = typeof args["question"] === "string" ? args["question"] : String(args["question"] ?? "");
@@ -5412,21 +5589,6 @@ function unknownProviderError(unknownNames, available) {
5412
5589
  available_now: Object.keys(available).sort()
5413
5590
  };
5414
5591
  }
5415
- async function deferConfer(args, bridge) {
5416
- const r = await bridge.callTool("confer", args);
5417
- const text = r.content[0]?.text;
5418
- if (typeof text === "string") {
5419
- try {
5420
- return JSON.parse(text);
5421
- } catch {
5422
- }
5423
- }
5424
- return errorEnvelope2(
5425
- "CONFER_BRIDGE_BAD_ENVELOPE",
5426
- "bridge returned an unparseable envelope for confer",
5427
- "Check that the Python child is healthy."
5428
- );
5429
- }
5430
5592
  function errorEnvelope2(code, message, hint) {
5431
5593
  return {
5432
5594
  tool: "confer",
@@ -5798,7 +5960,7 @@ function errorEnvelope3(code, message, hint) {
5798
5960
  transient: false
5799
5961
  };
5800
5962
  }
5801
- async function runVerify(args, bridge, fetchConfig) {
5963
+ async function runVerify(args, fetchConfig) {
5802
5964
  const checks = args["checks"];
5803
5965
  if (!Array.isArray(checks) || checks.length === 0) {
5804
5966
  return {
@@ -5810,7 +5972,6 @@ async function runVerify(args, bridge, fetchConfig) {
5810
5972
  )
5811
5973
  };
5812
5974
  }
5813
- void bridge;
5814
5975
  const allowShell = Boolean(args["allow_shell"] ?? false);
5815
5976
  const wallStart = performance4.now();
5816
5977
  const cpuStart = process.cpuUsage();
@@ -6112,7 +6273,6 @@ async function runBench(args, opts) {
6112
6273
  const innerOpts = {
6113
6274
  providers: opts.providers,
6114
6275
  allowlist: opts.allowlist ?? null,
6115
- ...opts.bridge ? { bridge: opts.bridge } : {},
6116
6276
  ...opts.moderator ? { moderator: opts.moderator } : {}
6117
6277
  };
6118
6278
  let inner;
@@ -6806,7 +6966,6 @@ var EST_TOKENS = {
6806
6966
  med: [1500, 800],
6807
6967
  high: [2500, 1500]
6808
6968
  };
6809
- var DEFERRED_OPTS2 = [];
6810
6969
  var REACTIVE_SIGNAL_RE = /<signals>\s*(\{[\s\S]*?\})\s*<\/signals>/g;
6811
6970
  function parseReactiveSignals(output) {
6812
6971
  if (typeof output !== "string" || !output.includes("<signals>")) return [];
@@ -6846,17 +7005,6 @@ async function runOrchestrate(args, opts) {
6846
7005
  );
6847
7006
  if (breakerEnv) return breakerEnv;
6848
7007
  }
6849
- const needsBridge = DEFERRED_OPTS2.some((k) => Boolean(args[k]));
6850
- if (needsBridge) {
6851
- if (opts.bridge && opts.bridge.toolNames.has("orchestrate")) {
6852
- return await deferOrchestrate(args, opts.bridge);
6853
- }
6854
- return errorEnvelope5(
6855
- "ORCHESTRATE_OPT_NOT_NATIVE",
6856
- "this orchestrate opt-in requires the Python bridge in v1",
6857
- "v1 native covers the plain DAG flow + cheap_mode. reactive (mid-flight DAG updates) still defers. Set CROSSCHECK_BRIDGE_PYTHON=1 to enable."
6858
- );
6859
- }
6860
7008
  const goal = typeof args["goal"] === "string" ? args["goal"] : null;
6861
7009
  const dagIn = isObj5(args["dag"]) ? args["dag"] : null;
6862
7010
  if (goal === null === (dagIn === null)) {
@@ -7798,21 +7946,6 @@ function resolveProviders3(names, available, allowlist) {
7798
7946
  }
7799
7947
  return out;
7800
7948
  }
7801
- async function deferOrchestrate(args, bridge) {
7802
- const r = await bridge.callTool("orchestrate", args);
7803
- const text = r.content[0]?.text;
7804
- if (typeof text === "string") {
7805
- try {
7806
- return JSON.parse(text);
7807
- } catch {
7808
- }
7809
- }
7810
- return errorEnvelope5(
7811
- "ORCHESTRATE_BRIDGE_BAD_ENVELOPE",
7812
- "bridge returned an unparseable envelope for orchestrate",
7813
- "Check that the Python child is healthy."
7814
- );
7815
- }
7816
7949
  function errorEnvelope5(code, message, hint, kind = "client") {
7817
7950
  return {
7818
7951
  tool: "orchestrate",
@@ -8175,7 +8308,6 @@ ${documentsPayload}`;
8175
8308
  }, {
8176
8309
  providers: opts.providers,
8177
8310
  allowlist: opts.allowlist ?? null,
8178
- ...opts.bridge ? { bridge: opts.bridge } : {},
8179
8311
  ctx
8180
8312
  });
8181
8313
  const scopeAnswer = Array.isArray(scope["answers"]) ? scope["answers"].filter((a) => typeof a["response"] === "string" && a["response"]).map((a) => `[${a["provider"]}]
@@ -8198,7 +8330,6 @@ ${scopeAnswer || "(none)"}
8198
8330
  providers: opts.providers,
8199
8331
  allowlist: opts.allowlist ?? null,
8200
8332
  moderator,
8201
- ...opts.bridge ? { bridge: opts.bridge } : {},
8202
8333
  ctx
8203
8334
  });
8204
8335
  let attempts = 1;
@@ -8233,7 +8364,6 @@ ${scopeAnswer || "(none)"}
8233
8364
  }, {
8234
8365
  providers: opts.providers,
8235
8366
  allowlist: opts.allowlist ?? null,
8236
- ...opts.bridge ? { bridge: opts.bridge } : {},
8237
8367
  ctx
8238
8368
  });
8239
8369
  }
@@ -8256,7 +8386,6 @@ ${scopeAnswer || "(none)"}
8256
8386
  }, {
8257
8387
  providers: opts.providers,
8258
8388
  allowlist: opts.allowlist ?? null,
8259
- ...opts.bridge ? { bridge: opts.bridge } : {},
8260
8389
  ctx
8261
8390
  });
8262
8391
  let overallF = toNumberOrNull(auditEnvelope["overall_score"]);
@@ -8281,7 +8410,6 @@ ${documentsPayload}`
8281
8410
  providers: opts.providers,
8282
8411
  allowlist: opts.allowlist ?? null,
8283
8412
  moderator,
8284
- ...opts.bridge ? { bridge: opts.bridge } : {},
8285
8413
  ctx
8286
8414
  }
8287
8415
  );
@@ -8301,7 +8429,6 @@ ${documentsPayload}`
8301
8429
  }, {
8302
8430
  providers: opts.providers,
8303
8431
  allowlist: opts.allowlist ?? null,
8304
- ...opts.bridge ? { bridge: opts.bridge } : {},
8305
8432
  ctx
8306
8433
  });
8307
8434
  overallF = toNumberOrNull(auditEnvelope["overall_score"]);
@@ -8539,11 +8666,6 @@ function errorEnvelope6(toolName, code, message, hint) {
8539
8666
 
8540
8667
  // src/tools/coordinate.ts
8541
8668
  import { performance as performance8 } from "perf_hooks";
8542
- var DEFERRED_OPTS3 = [
8543
- // empty — every coordinate opt runs natively when its deps
8544
- // (storage / innerCallers) are wired. Without them the
8545
- // worker_tools gate still triggers a bridge defer.
8546
- ];
8547
8669
  var COORDINATE_DEFAULT_TEMP = 0.4;
8548
8670
  var ROLE_TURN_SCHEMA = {
8549
8671
  type: "object",
@@ -8598,23 +8720,18 @@ async function runCoordinate(args, opts) {
8598
8720
  rejectedWorkerTools.push(t);
8599
8721
  }
8600
8722
  }
8601
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
8602
- const needsBridge = DEFERRED_OPTS3.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
8603
- if (needsBridge) {
8723
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
8604
8724
  if (superRequested) {
8605
8725
  return errorEnvelope7(
8606
8726
  "COORDINATE_SUPER_NOT_NATIVE",
8607
- "super mode requested but worker_tools needs the Python bridge",
8608
- "worker_tools without innerCallers wired defers to the Python bridge, which doesn't support super mode. Drop worker_tools, or wire innerCallers, to use super."
8727
+ "super mode requested with worker_tools, but innerCallers are not wired",
8728
+ "worker_tools needs innerCallers wired by the host. Drop worker_tools, or wire innerCallers, to use super."
8609
8729
  );
8610
8730
  }
8611
- if (opts.bridge && opts.bridge.toolNames.has("coordinate")) {
8612
- return await deferCoordinate(args, opts.bridge);
8613
- }
8614
8731
  return errorEnvelope7(
8615
8732
  "COORDINATE_OPT_NOT_NATIVE",
8616
8733
  "worker_tools requested but innerCallers are not wired",
8617
- "Native coordinate covers the three-role flow + untrusted_input + inject_session_memory. worker_tools needs innerCallers wired by the host (or CROSSCHECK_BRIDGE_PYTHON=1 as a backstop)."
8734
+ "Native coordinate covers the three-role flow + untrusted_input + inject_session_memory. worker_tools needs innerCallers wired by the host."
8618
8735
  );
8619
8736
  }
8620
8737
  const untrusted = Boolean(args["untrusted_input"]);
@@ -9014,21 +9131,6 @@ function unknownProviderError3(unknownNames, available) {
9014
9131
  available_now: Object.keys(available).sort()
9015
9132
  };
9016
9133
  }
9017
- async function deferCoordinate(args, bridge) {
9018
- const r = await bridge.callTool("coordinate", args);
9019
- const text = r.content[0]?.text;
9020
- if (typeof text === "string") {
9021
- try {
9022
- return JSON.parse(text);
9023
- } catch {
9024
- }
9025
- }
9026
- return errorEnvelope7(
9027
- "COORDINATE_BRIDGE_BAD_ENVELOPE",
9028
- "bridge returned an unparseable envelope for coordinate",
9029
- "Check that the Python child is healthy."
9030
- );
9031
- }
9032
9134
  function errorEnvelope7(code, message, hint) {
9033
9135
  return {
9034
9136
  tool: "coordinate",
@@ -9356,10 +9458,6 @@ function buildModeratorTranscript(transcript) {
9356
9458
 
9357
9459
  // src/tools/debate.ts
9358
9460
  import { performance as performance10 } from "perf_hooks";
9359
- var DEFERRED_OPTS4 = [
9360
- // empty — every debate opt runs natively when its deps
9361
- // (storage / innerCallers) are wired.
9362
- ];
9363
9461
  async function runDebate(args, opts) {
9364
9462
  const callStartedWall = performance10.now();
9365
9463
  const callStartedCpu = process.cpuUsage();
@@ -9377,23 +9475,18 @@ async function runDebate(args, opts) {
9377
9475
  rejectedWorkerTools.push(t);
9378
9476
  }
9379
9477
  }
9380
- const workerToolsNeedsBridge = acceptedWorkerTools.length > 0 && !opts.innerCallers;
9381
- const needsBridge = DEFERRED_OPTS4.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
9382
- if (needsBridge) {
9478
+ if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
9383
9479
  if (superRequested) {
9384
9480
  return errorEnvelope9(
9385
9481
  "DEBATE_SUPER_NOT_NATIVE",
9386
- "super mode requested but worker_tools needs the Python bridge",
9387
- "worker_tools without innerCallers wired defers to the Python bridge, which doesn't support super mode. Drop worker_tools, or wire innerCallers, to use super."
9482
+ "super mode requested with worker_tools, but innerCallers are not wired",
9483
+ "worker_tools needs innerCallers wired by the host. Drop worker_tools, or wire innerCallers, to use super."
9388
9484
  );
9389
9485
  }
9390
- if (opts.bridge && opts.bridge.toolNames.has("debate")) {
9391
- return await deferDebate(args, opts.bridge);
9392
- }
9393
9486
  return errorEnvelope9(
9394
9487
  "DEBATE_OPT_NOT_NATIVE",
9395
9488
  "worker_tools requested but innerCallers are not wired",
9396
- "Native debate covers N-round + plain/structured moderator synthesis + inject_session_memory + auto_panel + extract_claims + early_stop. worker_tools needs innerCallers wired by the host (or CROSSCHECK_BRIDGE_PYTHON=1 as a backstop)."
9489
+ "Native debate covers N-round + plain/structured moderator synthesis + inject_session_memory + auto_panel + extract_claims + early_stop. worker_tools needs innerCallers wired by the host."
9397
9490
  );
9398
9491
  }
9399
9492
  const topic = typeof args["topic"] === "string" ? args["topic"] : String(args["topic"] ?? "");
@@ -9830,21 +9923,6 @@ function unknownProviderError5(unknownNames, available) {
9830
9923
  available_now: Object.keys(available).sort()
9831
9924
  };
9832
9925
  }
9833
- async function deferDebate(args, bridge) {
9834
- const r = await bridge.callTool("debate", args);
9835
- const text = r.content[0]?.text;
9836
- if (typeof text === "string") {
9837
- try {
9838
- return JSON.parse(text);
9839
- } catch {
9840
- }
9841
- }
9842
- return errorEnvelope9(
9843
- "DEBATE_BRIDGE_BAD_ENVELOPE",
9844
- "bridge returned an unparseable envelope for debate",
9845
- "Check that the Python child is healthy."
9846
- );
9847
- }
9848
9926
  function errorEnvelope9(code, message, hint) {
9849
9927
  return {
9850
9928
  tool: "debate",
@@ -9864,9 +9942,6 @@ var DEFAULT_DELEGATION_LIMITS = {
9864
9942
  };
9865
9943
  async function runDelegate(args, opts) {
9866
9944
  if (!opts.storage) {
9867
- if (opts.bridge && opts.bridge.toolNames.has("delegate")) {
9868
- return await deferDelegate(args, opts.bridge);
9869
- }
9870
9945
  return errorEnvelope10(
9871
9946
  "DELEGATE_STORAGE_UNAVAILABLE",
9872
9947
  "delegate needs the local database (for quota tracking), which isn't available",
@@ -9938,7 +10013,6 @@ async function runDelegate(args, opts) {
9938
10013
  const innerOpts = {
9939
10014
  providers: opts.providers,
9940
10015
  allowlist: opts.allowlist ?? null,
9941
- ...opts.bridge ? { bridge: opts.bridge } : {},
9942
10016
  ...opts.moderator ? { moderator: opts.moderator } : {}
9943
10017
  };
9944
10018
  let result;
@@ -9977,21 +10051,6 @@ async function record(storage, sessionId, requester, toolCall, via, accepted, no
9977
10051
  created_at: nowEpochSeconds
9978
10052
  });
9979
10053
  }
9980
- async function deferDelegate(args, bridge) {
9981
- const r = await bridge.callTool("delegate", args);
9982
- const text = r.content[0]?.text;
9983
- if (typeof text === "string") {
9984
- try {
9985
- return JSON.parse(text);
9986
- } catch {
9987
- }
9988
- }
9989
- return errorEnvelope10(
9990
- "DELEGATE_BRIDGE_BAD_ENVELOPE",
9991
- "bridge returned an unparseable envelope for delegate",
9992
- "Check that the Python child is healthy."
9993
- );
9994
- }
9995
10054
  function errorEnvelope10(code, message, hint) {
9996
10055
  return {
9997
10056
  tool: "delegate",
@@ -10034,9 +10093,6 @@ async function runExplain(args, opts) {
10034
10093
  );
10035
10094
  }
10036
10095
  if (!opts.storage) {
10037
- if (opts.bridge && opts.bridge.toolNames.has("explain")) {
10038
- return await deferExplain(args, opts.bridge);
10039
- }
10040
10096
  return errorEnvelope11(
10041
10097
  "EXPLAIN_STORAGE_UNAVAILABLE",
10042
10098
  "explain needs the local transcript/stats database, which isn't available",
@@ -10318,21 +10374,6 @@ function pyRepr5(v) {
10318
10374
  }
10319
10375
  return String(v);
10320
10376
  }
10321
- async function deferExplain(args, bridge) {
10322
- const r = await bridge.callTool("explain", args);
10323
- const text = r.content[0]?.text;
10324
- if (typeof text === "string") {
10325
- try {
10326
- return JSON.parse(text);
10327
- } catch {
10328
- }
10329
- }
10330
- return errorEnvelope11(
10331
- "EXPLAIN_BRIDGE_BAD_ENVELOPE",
10332
- "bridge returned an unparseable envelope for explain",
10333
- "Check that the Python child is healthy."
10334
- );
10335
- }
10336
10377
  function errorEnvelope11(code, message, hint, kind = "client", extra = {}) {
10337
10378
  return {
10338
10379
  tool: "explain",
@@ -10885,9 +10926,6 @@ async function runRecall(args, opts) {
10885
10926
  if (k < 1) k = 1;
10886
10927
  if (k > 50) k = 50;
10887
10928
  if (!opts.storage) {
10888
- if (opts.bridge && opts.bridge.toolNames.has("recall")) {
10889
- return await deferRecall(args, opts.bridge);
10890
- }
10891
10929
  return errorEnvelope12(
10892
10930
  "RECALL_STORAGE_UNAVAILABLE",
10893
10931
  "recall needs the local database, which isn't available",
@@ -10940,21 +10978,6 @@ async function runRecall(args, opts) {
10940
10978
  applied_filters: applied
10941
10979
  };
10942
10980
  }
10943
- async function deferRecall(args, bridge) {
10944
- const r = await bridge.callTool("recall", args);
10945
- const text = r.content[0]?.text;
10946
- if (typeof text === "string") {
10947
- try {
10948
- return JSON.parse(text);
10949
- } catch {
10950
- }
10951
- }
10952
- return errorEnvelope12(
10953
- "RECALL_BRIDGE_BAD_ENVELOPE",
10954
- "bridge returned an unparseable envelope for recall",
10955
- "Check that the Python child is healthy."
10956
- );
10957
- }
10958
10981
  function errorEnvelope12(code, message, hint) {
10959
10982
  return {
10960
10983
  tool: "recall",
@@ -10977,9 +11000,6 @@ async function runRecommendPanel(args, opts) {
10977
11000
  );
10978
11001
  }
10979
11002
  if (!opts.storage) {
10980
- if (opts.bridge && opts.bridge.toolNames.has("recommend_panel")) {
10981
- return await deferRecommendPanel(args, opts.bridge);
10982
- }
10983
11003
  return errorEnvelope13(
10984
11004
  "RECOMMEND_PANEL_STORAGE_UNAVAILABLE",
10985
11005
  "recommend_panel needs the local stats database, which isn't available",
@@ -11042,21 +11062,6 @@ async function runRecommendPanel(args, opts) {
11042
11062
  meta: result.meta
11043
11063
  };
11044
11064
  }
11045
- async function deferRecommendPanel(args, bridge) {
11046
- const r = await bridge.callTool("recommend_panel", args);
11047
- const text = r.content[0]?.text;
11048
- if (typeof text === "string") {
11049
- try {
11050
- return JSON.parse(text);
11051
- } catch {
11052
- }
11053
- }
11054
- return errorEnvelope13(
11055
- "RECOMMEND_PANEL_BRIDGE_BAD_ENVELOPE",
11056
- "bridge returned an unparseable envelope for recommend_panel",
11057
- "Check that the Python child is healthy."
11058
- );
11059
- }
11060
11065
  function errorEnvelope13(code, message, hint) {
11061
11066
  return {
11062
11067
  tool: "recommend_panel",
@@ -11086,9 +11091,6 @@ function toStringArray3(v) {
11086
11091
  import { readFileSync as readFileSync10, existsSync as existsSync8 } from "fs";
11087
11092
  async function runScoreboard(args, opts) {
11088
11093
  if (!opts.storage) {
11089
- if (opts.bridge && opts.bridge.toolNames.has("scoreboard")) {
11090
- return await deferScoreboard(args, opts.bridge);
11091
- }
11092
11094
  return errorEnvelope14(
11093
11095
  "SCOREBOARD_STORAGE_UNAVAILABLE",
11094
11096
  "scoreboard needs the local stats database, which isn't available",
@@ -11211,21 +11213,6 @@ function clampInt3(raw, min, max, fallback) {
11211
11213
  if (!Number.isFinite(n)) return fallback;
11212
11214
  return Math.min(max, Math.max(min, Math.trunc(n)));
11213
11215
  }
11214
- async function deferScoreboard(args, bridge) {
11215
- const r = await bridge.callTool("scoreboard", args);
11216
- const text = r.content[0]?.text;
11217
- if (typeof text === "string") {
11218
- try {
11219
- return JSON.parse(text);
11220
- } catch {
11221
- }
11222
- }
11223
- return errorEnvelope14(
11224
- "SCOREBOARD_BRIDGE_BAD_ENVELOPE",
11225
- "bridge returned an unparseable envelope for scoreboard",
11226
- "Check that the Python child is healthy."
11227
- );
11228
- }
11229
11216
  function errorEnvelope14(code, message, hint) {
11230
11217
  return {
11231
11218
  tool: "scoreboard",
@@ -11262,9 +11249,6 @@ async function runSessionMemory(args, opts) {
11262
11249
  );
11263
11250
  }
11264
11251
  if (!opts.storage) {
11265
- if (opts.bridge && opts.bridge.toolNames.has("session_memory")) {
11266
- return await deferSessionMemory(args, opts.bridge);
11267
- }
11268
11252
  return errorEnvelope15(
11269
11253
  "SESSION_MEMORY_STORAGE_UNAVAILABLE",
11270
11254
  "session_memory needs the local database, which isn't available",
@@ -11369,21 +11353,6 @@ function clampInt4(raw, min, max, fallback) {
11369
11353
  if (!Number.isFinite(n)) return fallback;
11370
11354
  return Math.min(max, Math.max(min, Math.trunc(n)));
11371
11355
  }
11372
- async function deferSessionMemory(args, bridge) {
11373
- const r = await bridge.callTool("session_memory", args);
11374
- const text = r.content[0]?.text;
11375
- if (typeof text === "string") {
11376
- try {
11377
- return JSON.parse(text);
11378
- } catch {
11379
- }
11380
- }
11381
- return errorEnvelope15(
11382
- "SESSION_MEMORY_BRIDGE_BAD_ENVELOPE",
11383
- "bridge returned an unparseable envelope for session_memory",
11384
- "Check that the Python child is healthy."
11385
- );
11386
- }
11387
11356
  function errorEnvelope15(code, message, hint) {
11388
11357
  return {
11389
11358
  tool: "session_memory",
@@ -12003,7 +11972,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
12003
11972
  var DEFAULT_PACKAGE = "crosscheck-cli";
12004
11973
  var FETCH_TIMEOUT_MS = 3e3;
12005
11974
  function engineVersion() {
12006
- return true ? "0.2.27" : "0.0.0-dev";
11975
+ return true ? "0.2.28" : "0.0.0-dev";
12007
11976
  }
12008
11977
  function defaultUpdateCachePath() {
12009
11978
  const base = process.env["CROSSCHECK_DATA_DIR"] || path9.join(os.homedir() || os.tmpdir(), ".crosscheck");
@@ -12775,12 +12744,11 @@ function helpTool() {
12775
12744
  }
12776
12745
  });
12777
12746
  }
12778
- function registerCoreTools(opts = {}) {
12779
- const o = opts && typeof opts === "object" && "toolNames" in opts ? { bridge: opts } : opts;
12747
+ function registerCoreTools(o = {}) {
12780
12748
  const tools = /* @__PURE__ */ new Map();
12781
12749
  const list = [
12782
12750
  pingTool(),
12783
- verifyTool(o.bridge, o.fetchConfig),
12751
+ verifyTool(o.fetchConfig),
12784
12752
  pickTool(
12785
12753
  o.providers ?? {},
12786
12754
  o.providerAllowlist ?? null,
@@ -12792,7 +12760,6 @@ function registerCoreTools(opts = {}) {
12792
12760
  auditTool(
12793
12761
  o.providers ?? {},
12794
12762
  o.providerAllowlist ?? null,
12795
- o.bridge,
12796
12763
  o.transcriptsDir,
12797
12764
  o.pricing,
12798
12765
  o.storage,
@@ -12802,7 +12769,6 @@ function registerCoreTools(opts = {}) {
12802
12769
  conferTool(
12803
12770
  o.providers ?? {},
12804
12771
  o.providerAllowlist ?? null,
12805
- o.bridge,
12806
12772
  o.moderatorDefault ?? "anthropic",
12807
12773
  o.pricing,
12808
12774
  o.storage,
@@ -12815,7 +12781,6 @@ function registerCoreTools(opts = {}) {
12815
12781
  debateTool(
12816
12782
  o.providers ?? {},
12817
12783
  o.providerAllowlist ?? null,
12818
- o.bridge,
12819
12784
  buildInnerCallers(o),
12820
12785
  o.storage,
12821
12786
  o.pricing,
@@ -12827,7 +12792,6 @@ function registerCoreTools(opts = {}) {
12827
12792
  coordinateTool(
12828
12793
  o.providers ?? {},
12829
12794
  o.providerAllowlist ?? null,
12830
- o.bridge,
12831
12795
  buildInnerCallers(o),
12832
12796
  o.storage,
12833
12797
  o.circuitBreakers,
@@ -12838,7 +12802,6 @@ function registerCoreTools(opts = {}) {
12838
12802
  triangulateTool(
12839
12803
  o.providers ?? {},
12840
12804
  o.providerAllowlist ?? null,
12841
- o.bridge,
12842
12805
  o.storage,
12843
12806
  o.circuitBreakers,
12844
12807
  o.transcriptsDir,
@@ -12847,7 +12810,6 @@ function registerCoreTools(opts = {}) {
12847
12810
  planTool(
12848
12811
  o.providers ?? {},
12849
12812
  o.providerAllowlist ?? null,
12850
- o.bridge,
12851
12813
  o.storage,
12852
12814
  o.circuitBreakers,
12853
12815
  o.transcriptsDir,
@@ -12856,7 +12818,6 @@ function registerCoreTools(opts = {}) {
12856
12818
  critiqueTool(
12857
12819
  o.providers ?? {},
12858
12820
  o.providerAllowlist ?? null,
12859
- o.bridge,
12860
12821
  o.storage,
12861
12822
  o.circuitBreakers,
12862
12823
  o.transcriptsDir,
@@ -12865,7 +12826,6 @@ function registerCoreTools(opts = {}) {
12865
12826
  reviewTool(
12866
12827
  o.providers ?? {},
12867
12828
  o.providerAllowlist ?? null,
12868
- o.bridge,
12869
12829
  o.storage,
12870
12830
  o.circuitBreakers,
12871
12831
  o.transcriptsDir,
@@ -12873,25 +12833,23 @@ function registerCoreTools(opts = {}) {
12873
12833
  ),
12874
12834
  listProvidersTool(o.providers ?? {}, o.activeProviders ?? null, o.moderatorDefault ?? "anthropic"),
12875
12835
  modelsTool(o.providers ?? {}, o.activeProviders ?? null),
12876
- recallTool(o.storage, o.bridge),
12877
- sessionMemoryTool(o.storage, o.bridge),
12878
- scoreboardTool(o.storage, o.bridge, o.eventsPath),
12879
- explainTool(o.storage, o.bridge, o.transcriptsDir),
12836
+ recallTool(o.storage),
12837
+ sessionMemoryTool(o.storage),
12838
+ scoreboardTool(o.storage, o.eventsPath),
12839
+ explainTool(o.storage, o.transcriptsDir),
12880
12840
  delegateTool(
12881
12841
  o.providers ?? {},
12882
12842
  o.providerAllowlist ?? null,
12883
12843
  o.storage,
12884
- o.bridge,
12885
12844
  o.moderatorDefault ?? "anthropic"
12886
12845
  ),
12887
12846
  fetchTool(o.storage, o.fetchConfig, o.repoRoot),
12888
- recommendPanelTool(o.providers ?? {}, o.storage, o.bridge),
12847
+ recommendPanelTool(o.providers ?? {}, o.storage),
12889
12848
  updateCrosscheckTool(o.repoRoot ?? null),
12890
12849
  benchTool(
12891
12850
  o.providers ?? {},
12892
12851
  o.providerAllowlist ?? null,
12893
12852
  o.storage,
12894
- o.bridge,
12895
12853
  o.moderatorDefault ?? "anthropic",
12896
12854
  o.benchGoldensDir,
12897
12855
  o.circuitBreakers,
@@ -12902,7 +12860,6 @@ function registerCoreTools(opts = {}) {
12902
12860
  solveTool(
12903
12861
  o.providers ?? {},
12904
12862
  o.providerAllowlist ?? null,
12905
- o.bridge,
12906
12863
  o.storage,
12907
12864
  o.circuitBreakers,
12908
12865
  o.transcriptsDir,
@@ -12911,7 +12868,6 @@ function registerCoreTools(opts = {}) {
12911
12868
  orchestrateTool(
12912
12869
  o.providers ?? {},
12913
12870
  o.providerAllowlist ?? null,
12914
- o.bridge,
12915
12871
  o.moderatorDefault ?? "anthropic",
12916
12872
  o.storage,
12917
12873
  o.pricing,
@@ -12958,7 +12914,6 @@ function createTool(o, toolName, cheapDefault) {
12958
12914
  providers: o.providers ?? {},
12959
12915
  allowlist: o.providerAllowlist ?? null,
12960
12916
  ...o.storage ? { storage: o.storage } : {},
12961
- ...o.bridge ? { bridge: o.bridge } : {},
12962
12917
  ...o.moderatorDefault ? { moderator: o.moderatorDefault } : {},
12963
12918
  ...o.fetchConfig ? { fetchConfig: o.fetchConfig } : {},
12964
12919
  ...o.repoRoot ? { repoRoot: o.repoRoot } : {},
@@ -12967,7 +12922,7 @@ function createTool(o, toolName, cheapDefault) {
12967
12922
  })
12968
12923
  };
12969
12924
  }
12970
- function orchestrateTool(providers, allowlist, bridge, moderator, storage, pricing, breakers, transcriptsDir, repoRoot, nodeCache) {
12925
+ function orchestrateTool(providers, allowlist, moderator, storage, pricing, breakers, transcriptsDir, repoRoot, nodeCache) {
12971
12926
  return {
12972
12927
  name: "orchestrate",
12973
12928
  description: "Plan and execute a DAG of LLM subtasks. Either supply a `goal` (planner will draft the DAG) OR a hand-authored `dag`. Workers run topologically; recombine produces a single `final`. Covers the sequential flow, cheap_mode (per-node tier picking), and reactive (mid-flight DAG updates) \u2014 all native.",
@@ -12992,7 +12947,6 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
12992
12947
  providers,
12993
12948
  allowlist,
12994
12949
  moderator,
12995
- ...bridge ? { bridge } : {},
12996
12950
  ...storage ? { storage } : {},
12997
12951
  ...pricing ? { pricing } : {},
12998
12952
  ...breakers ? { breakers } : {},
@@ -13002,7 +12956,7 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
13002
12956
  })
13003
12957
  };
13004
12958
  }
13005
- function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
12959
+ function solveTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
13006
12960
  return {
13007
12961
  name: "solve",
13008
12962
  description: "Iterative LLM solver. Generates a proposal, verifies it against the supplied verifier, and retries with feedback up to max_attempts. Verifier kinds: regex_response and shell (run in a native sandbox with wall-clock + optional memory/CPU limits). With target_path, returns a unified-diff patch.",
@@ -13024,7 +12978,6 @@ function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsD
13024
12978
  handler: (args) => runSolve(args, {
13025
12979
  providers,
13026
12980
  allowlist,
13027
- ...bridge ? { bridge } : {},
13028
12981
  ...storage ? { storage } : {},
13029
12982
  ...breakers ? { breakers } : {},
13030
12983
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13063,7 +13016,7 @@ function configPinTool(repoRoot, config, rejectDriftEnv) {
13063
13016
  }
13064
13017
  };
13065
13018
  }
13066
- function benchTool(providers, allowlist, storage, bridge, moderator, defaultGoldensDir, breakers, transcriptsDir, repoRoot) {
13019
+ function benchTool(providers, allowlist, storage, moderator, defaultGoldensDir, breakers, transcriptsDir, repoRoot) {
13067
13020
  return {
13068
13021
  name: "bench",
13069
13022
  description: "Run benchmark goldens against each provider's confer/review output. Each golden: {name, tool_call: confer|review, args, verifiers[]}. Returns per-provider pass/fail/error + a ranking sorted by score. Records ballots into provider_stats when storage is wired (used by triangulate's win-rate weights).",
@@ -13082,7 +13035,6 @@ function benchTool(providers, allowlist, storage, bridge, moderator, defaultGold
13082
13035
  allowlist,
13083
13036
  moderator,
13084
13037
  ...storage ? { storage } : {},
13085
- ...bridge ? { bridge } : {},
13086
13038
  ...defaultGoldensDir ? { defaultGoldensDir } : {},
13087
13039
  ...breakers ? { breakers } : {},
13088
13040
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13109,7 +13061,7 @@ function updateCrosscheckTool(repoRoot) {
13109
13061
  }
13110
13062
  };
13111
13063
  }
13112
- function recommendPanelTool(providers, storage, bridge) {
13064
+ function recommendPanelTool(providers, storage) {
13113
13065
  return {
13114
13066
  name: "recommend_panel",
13115
13067
  description: "Recommend a minimal effective panel for a given purpose, based on historical usage_log + provider_stats. Cold-start falls back to the configured panel ordered by win-rate.",
@@ -13127,8 +13079,7 @@ function recommendPanelTool(providers, storage, bridge) {
13127
13079
  },
13128
13080
  handler: (args) => runRecommendPanel(args, {
13129
13081
  providers,
13130
- ...storage ? { storage } : {},
13131
- ...bridge ? { bridge } : {}
13082
+ ...storage ? { storage } : {}
13132
13083
  })
13133
13084
  };
13134
13085
  }
@@ -13153,7 +13104,7 @@ function fetchTool(storage, fetchConfig, repoRoot) {
13153
13104
  })
13154
13105
  };
13155
13106
  }
13156
- function delegateTool(providers, allowlist, storage, bridge, moderator) {
13107
+ function delegateTool(providers, allowlist, storage, moderator) {
13157
13108
  return {
13158
13109
  name: "delegate",
13159
13110
  description: "Run a delegable tool (confer | review) restricted to a single named provider, with explicit quota check. Records every attempt (accepted or refused) to the delegations table; quota in the response reflects counts AFTER the current call.",
@@ -13173,12 +13124,11 @@ function delegateTool(providers, allowlist, storage, bridge, moderator) {
13173
13124
  providers,
13174
13125
  allowlist,
13175
13126
  moderator,
13176
- ...storage ? { storage } : {},
13177
- ...bridge ? { bridge } : {}
13127
+ ...storage ? { storage } : {}
13178
13128
  })
13179
13129
  };
13180
13130
  }
13181
- function explainTool(storage, bridge, transcriptsDir) {
13131
+ function explainTool(storage, transcriptsDir) {
13182
13132
  return {
13183
13133
  name: "explain",
13184
13134
  description: "Replay a session as a navigable tree with cost/latency annotations. Reads usage_log + optionally walks the transcripts directory for per-tool summaries.",
@@ -13196,12 +13146,11 @@ function explainTool(storage, bridge, transcriptsDir) {
13196
13146
  },
13197
13147
  handler: (args) => runExplain(args, {
13198
13148
  ...storage ? { storage } : {},
13199
- ...bridge ? { bridge } : {},
13200
13149
  ...transcriptsDir ? { transcriptsDir } : {}
13201
13150
  })
13202
13151
  };
13203
13152
  }
13204
- function scoreboardTool(storage, bridge, eventsPath) {
13153
+ function scoreboardTool(storage, eventsPath) {
13205
13154
  return {
13206
13155
  name: "scoreboard",
13207
13156
  description: "Aggregate provider ballot stats + delegation counts + table totals. Supports top_k (rank limit) and recent_limit (tail of events.jsonl when configured). Reads the engine's local stats database (auto-created at <data dir>/db.sqlite).",
@@ -13215,12 +13164,11 @@ function scoreboardTool(storage, bridge, eventsPath) {
13215
13164
  },
13216
13165
  handler: (args) => runScoreboard(args, {
13217
13166
  ...storage ? { storage } : {},
13218
- ...bridge ? { bridge } : {},
13219
13167
  ...eventsPath ? { eventsPath } : {}
13220
13168
  })
13221
13169
  };
13222
13170
  }
13223
- function sessionMemoryTool(storage, bridge) {
13171
+ function sessionMemoryTool(storage) {
13224
13172
  return {
13225
13173
  name: "session_memory",
13226
13174
  description: "CRUD over the per-session working memory ledger. Actions: list, add, mark_stale, clear. Uses the engine's local database (auto-created at <data dir>/db.sqlite).",
@@ -13243,15 +13191,14 @@ function sessionMemoryTool(storage, bridge) {
13243
13191
  required: ["action", "session_id"]
13244
13192
  },
13245
13193
  handler: (args) => runSessionMemory(args, {
13246
- ...storage ? { storage } : {},
13247
- ...bridge ? { bridge } : {}
13194
+ ...storage ? { storage } : {}
13248
13195
  })
13249
13196
  };
13250
13197
  }
13251
- function recallTool(storage, bridge) {
13198
+ function recallTool(storage) {
13252
13199
  return {
13253
13200
  name: "recall",
13254
- description: "Full-text search across persisted transcripts via SQLite FTS5. Returns rows ordered by relevance with a windowed snippet. Requires a wired Storage adapter; falls back to the Python bridge when not available.",
13201
+ description: "Full-text search across persisted transcripts via SQLite FTS5. Returns rows ordered by relevance with a windowed snippet. Requires a wired Storage adapter.",
13255
13202
  inputSchema: {
13256
13203
  type: "object",
13257
13204
  additionalProperties: true,
@@ -13265,8 +13212,7 @@ function recallTool(storage, bridge) {
13265
13212
  required: ["query"]
13266
13213
  },
13267
13214
  handler: (args) => runRecall(args, {
13268
- ...storage ? { storage } : {},
13269
- ...bridge ? { bridge } : {}
13215
+ ...storage ? { storage } : {}
13270
13216
  })
13271
13217
  };
13272
13218
  }
@@ -13302,7 +13248,7 @@ function modelsTool(providers, activeProviders) {
13302
13248
  handler: async (args) => runModels(args, { providers, activeProviders })
13303
13249
  };
13304
13250
  }
13305
- function reviewTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
13251
+ function reviewTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
13306
13252
  return {
13307
13253
  name: "review",
13308
13254
  description: "Have an LLM panel peer-review a code or proposal snippet. Returns the confer envelope (one answer per provider).",
@@ -13321,7 +13267,6 @@ function reviewTool(providers, allowlist, bridge, storage, breakers, transcripts
13321
13267
  handler: (args) => runReview(args, {
13322
13268
  providers,
13323
13269
  allowlist,
13324
- ...bridge ? { bridge } : {},
13325
13270
  ...storage ? { storage } : {},
13326
13271
  ...breakers ? { breakers } : {},
13327
13272
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13329,7 +13274,7 @@ function reviewTool(providers, allowlist, bridge, storage, breakers, transcripts
13329
13274
  })
13330
13275
  };
13331
13276
  }
13332
- function critiqueTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
13277
+ function critiqueTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
13333
13278
  return {
13334
13279
  name: "critique",
13335
13280
  description: "Have each LLM panelist list the top weaknesses of a proposed answer or approach (severity-rated). Returns per-provider weakness lists + a merged list ordered by severity.",
@@ -13349,7 +13294,6 @@ function critiqueTool(providers, allowlist, bridge, storage, breakers, transcrip
13349
13294
  handler: (args) => runCritique(args, {
13350
13295
  providers,
13351
13296
  allowlist,
13352
- ...bridge ? { bridge } : {},
13353
13297
  ...storage ? { storage } : {},
13354
13298
  ...breakers ? { breakers } : {},
13355
13299
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13357,7 +13301,7 @@ function critiqueTool(providers, allowlist, bridge, storage, breakers, transcrip
13357
13301
  })
13358
13302
  };
13359
13303
  }
13360
- function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
13304
+ function planTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
13361
13305
  return {
13362
13306
  name: "plan",
13363
13307
  description: 'Have an LLM panel debate a step-by-step plan for the stated goal under the given constraints. Returns the debate envelope with a moderator-synthesised plan. Defaults to `mode: "fast"` (2 rounds + early_stop) \u2014 set `mode: "thorough"` for 5 rounds without early_stop. Explicit `max_rounds` / `early_stop` / `early_stop_threshold` always override the mode preset. Use `structured: true` for schema-validated synthesis.',
@@ -13384,7 +13328,6 @@ function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDi
13384
13328
  handler: (args) => runPlan(args, {
13385
13329
  providers,
13386
13330
  allowlist,
13387
- ...bridge ? { bridge } : {},
13388
13331
  ...storage ? { storage } : {},
13389
13332
  ...breakers ? { breakers } : {},
13390
13333
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13392,7 +13335,7 @@ function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDi
13392
13335
  })
13393
13336
  };
13394
13337
  }
13395
- function triangulateTool(providers, allowlist, bridge, storage, breakers, transcriptsDir, repoRoot) {
13338
+ function triangulateTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
13396
13339
  return {
13397
13340
  name: "triangulate",
13398
13341
  description: "Run a coordinate flow and reshape the output as a consensus + minority report with per-provider weights. v1 uses 1.0 weights (matches a fresh provider_stats DB); future versions thread real win-rate weights when the DB layer ports.",
@@ -13413,7 +13356,6 @@ function triangulateTool(providers, allowlist, bridge, storage, breakers, transc
13413
13356
  handler: (args) => runTriangulate(args, {
13414
13357
  providers,
13415
13358
  allowlist,
13416
- ...bridge ? { bridge } : {},
13417
13359
  ...storage ? { storage } : {},
13418
13360
  ...breakers ? { breakers } : {},
13419
13361
  ...transcriptsDir ? { transcriptsDir } : {},
@@ -13421,7 +13363,7 @@ function triangulateTool(providers, allowlist, bridge, storage, breakers, transc
13421
13363
  })
13422
13364
  };
13423
13365
  }
13424
- function coordinateTool(providers, allowlist, bridge, innerCallers, storage, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13366
+ function coordinateTool(providers, allowlist, innerCallers, storage, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13425
13367
  return {
13426
13368
  name: "coordinate",
13427
13369
  description: "Run a three-role coordination flow (proposer \u2192 critics \u2192 synthesizer) with structured output at every step. Native opts: untrusted_input (canary + neutralize), worker_tools (bounded ReAct on proposer + critic roles; synth never sees inner tools), inject_session_memory (storage-backed working-memory block prepended to the topic).",
@@ -13446,7 +13388,6 @@ function coordinateTool(providers, allowlist, bridge, innerCallers, storage, bre
13446
13388
  handler: (args) => runCoordinate(args, {
13447
13389
  providers,
13448
13390
  allowlist,
13449
- ...bridge ? { bridge } : {},
13450
13391
  innerCallers,
13451
13392
  ...storage ? { storage } : {},
13452
13393
  ...breakers ? { breakers } : {},
@@ -13456,7 +13397,7 @@ function coordinateTool(providers, allowlist, bridge, innerCallers, storage, bre
13456
13397
  })
13457
13398
  };
13458
13399
  }
13459
- function debateTool(providers, allowlist, bridge, innerCallers, storage, pricing, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13400
+ function debateTool(providers, allowlist, innerCallers, storage, pricing, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13460
13401
  return {
13461
13402
  name: "debate",
13462
13403
  description: "Run a multi-round debate between LLM providers and synthesise the result via a moderator. Native opts: inject_session_memory, auto_panel, worker_tools, structured synthesis (schema-validated), extract_claims (final-round distillation), early_stop (post-round agreement check).",
@@ -13486,7 +13427,6 @@ function debateTool(providers, allowlist, bridge, innerCallers, storage, pricing
13486
13427
  handler: (args) => runDebate(args, {
13487
13428
  providers,
13488
13429
  allowlist,
13489
- ...bridge ? { bridge } : {},
13490
13430
  innerCallers,
13491
13431
  ...storage ? { storage } : {},
13492
13432
  ...pricing ? { pricing } : {},
@@ -13506,10 +13446,10 @@ function buildInnerCallers(o) {
13506
13446
  ...o.repoRoot ? { repoRoot: o.repoRoot } : {}
13507
13447
  });
13508
13448
  }
13509
- out.verify = (args) => runVerify(args, o.bridge, o.fetchConfig);
13449
+ out.verify = (args) => runVerify(args, o.fetchConfig);
13510
13450
  return out;
13511
13451
  }
13512
- function conferTool(providers, allowlist, bridge, moderator, pricing, storage, innerCallers, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13452
+ function conferTool(providers, allowlist, moderator, pricing, storage, innerCallers, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
13513
13453
  return {
13514
13454
  name: "confer",
13515
13455
  description: "Ask a panel of LLM providers the same question; return one answer per provider. Native opts: untrusted_input (canary + neutralization), early_stop (cheap-tier agreement check after first 2 panelists when N>=3), extract_claims (cheap-tier extractor with per-provider support maps), inject_session_memory (storage-backed working-memory block prepended to the first user message), auto_panel (router-driven top-N panel pick), worker_tools (bounded ReAct loop per panelist when innerCallers are wired by the host).",
@@ -13536,7 +13476,6 @@ function conferTool(providers, allowlist, bridge, moderator, pricing, storage, i
13536
13476
  handler: (args) => runConfer(args, {
13537
13477
  providers,
13538
13478
  allowlist,
13539
- ...bridge ? { bridge } : {},
13540
13479
  moderator,
13541
13480
  ...pricing ? { pricing } : {},
13542
13481
  ...storage ? { storage } : {},
@@ -13548,7 +13487,7 @@ function conferTool(providers, allowlist, bridge, moderator, pricing, storage, i
13548
13487
  })
13549
13488
  };
13550
13489
  }
13551
- function auditTool(providers, allowlist, bridge, transcriptsDir, pricing, storage, breakers, repoRoot) {
13490
+ function auditTool(providers, allowlist, transcriptsDir, pricing, storage, breakers, repoRoot) {
13552
13491
  return {
13553
13492
  name: "audit",
13554
13493
  description: "Score a piece of output against an audit rubric. Single-judge by default; coalesce-mode (multi-judge consensus) and panel-exhausted self-audit run natively. cheap_mode picks the cheapest 'med'-tier model as auditor when a pricing.json is wired. session_id-only inputs load the latest transcript automatically when a transcripts directory is wired.",
@@ -13574,7 +13513,6 @@ function auditTool(providers, allowlist, bridge, transcriptsDir, pricing, storag
13574
13513
  handler: (args) => runAudit(args, {
13575
13514
  providers,
13576
13515
  allowlist,
13577
- ...bridge ? { bridge } : {},
13578
13516
  ...transcriptsDir ? { transcriptsDir } : {},
13579
13517
  ...pricing ? { pricing } : {},
13580
13518
  ...storage ? { storage } : {},
@@ -13638,7 +13576,7 @@ function pickTool(providers, allowlist, storage, breakers, transcriptsDir, repoR
13638
13576
  })
13639
13577
  };
13640
13578
  }
13641
- function verifyTool(bridge, fetchConfig) {
13579
+ function verifyTool(fetchConfig) {
13642
13580
  return {
13643
13581
  name: "verify",
13644
13582
  description: "Run a list of deterministic property checks against caller-supplied data. No LLM calls; everything is local. Returns per-check {passed, reason} plus all_passed / summary / timing fields. Supports the text kinds (contains, not_contains, regex_match, contains_any, contains_all, min_length), shell (sandboxed subprocess with timeout + Unix pgid isolation), and url_head (HEAD request gated by fetch.url_allowlist). All kinds run natively.",
@@ -13656,7 +13594,7 @@ function verifyTool(bridge, fetchConfig) {
13656
13594
  },
13657
13595
  required: ["checks"]
13658
13596
  },
13659
- handler: (args) => runVerify(args, bridge, fetchConfig)
13597
+ handler: (args) => runVerify(args, fetchConfig)
13660
13598
  };
13661
13599
  }
13662
13600
  function pingTool() {
@@ -13706,7 +13644,7 @@ function createCrosscheck(opts) {
13706
13644
  // Direct runConfer call with a streaming hook — bypasses the tool
13707
13645
  // registry (whose handler signature can't carry a callback). Uses the
13708
13646
  // same opts the registry wires for confer in a browser build: providers
13709
- // + pricing + default moderator; storage/bridge/innerCallers aren't
13647
+ // + pricing + default moderator; storage/innerCallers aren't
13710
13648
  // available here, matching the non-streaming path.
13711
13649
  conferStream: (args, onAnswer) => runConfer(args, { providers, pricing: pricingDoc, moderator: "anthropic", onAnswer }),
13712
13650
  debateStream: (args, { onTurn, onSynthesis } = {}) => runDebate(args, {