crosscheck-mcp 0.2.27 → 0.2.29
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/README.md +4 -20
- package/dist/browser-ext.cjs +386 -360
- package/dist/browser-ext.cjs.map +1 -1
- package/dist/browser-ext.js +371 -345
- package/dist/browser-ext.js.map +1 -1
- package/dist/embed.cjs +635 -381
- package/dist/embed.cjs.map +1 -1
- package/dist/embed.d.cts +151 -2
- package/dist/embed.d.ts +151 -2
- package/dist/embed.js +612 -362
- package/dist/embed.js.map +1 -1
- package/dist/node-stdio.cjs +453 -473
- package/dist/node-stdio.cjs.map +1 -1
- package/dist/node-stdio.d.cts +12 -122
- package/dist/node-stdio.d.ts +12 -122
- package/dist/node-stdio.js +424 -444
- package/dist/node-stdio.js.map +1 -1
- package/dist/pricing.json +47 -9
- package/dist/self-check.cjs.map +1 -1
- package/dist/self-check.js.map +1 -1
- package/dist/types-BcprisDl.d.cts +76 -0
- package/dist/types-BcprisDl.d.ts +76 -0
- package/package.json +7 -2
package/dist/browser-ext.js
CHANGED
|
@@ -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:
|
|
20
|
-
completion_per_1k: 0.
|
|
21
|
-
cached_per_1k:
|
|
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:
|
|
25
|
-
completion_per_1k: 0.
|
|
26
|
-
cached_per_1k:
|
|
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:
|
|
30
|
-
completion_per_1k: 0.
|
|
31
|
-
cached_per_1k:
|
|
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
|
-
|
|
400
|
-
|
|
401
|
-
|
|
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 (!
|
|
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
|
-
|
|
492
|
-
|
|
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() {
|
|
@@ -764,6 +891,52 @@ function rejectsDisabledThinking(model) {
|
|
|
764
891
|
const m = model.toLowerCase();
|
|
765
892
|
return ADAPTIVE_THINKING_PREFIXES.some((p) => m.startsWith(p));
|
|
766
893
|
}
|
|
894
|
+
var NO_FORCED_TOOL_PREFIXES = [
|
|
895
|
+
"claude-fable-5-1",
|
|
896
|
+
"claude-mythos-5-1",
|
|
897
|
+
"claude-opus-5-5",
|
|
898
|
+
"claude-sonnet-5-5"
|
|
899
|
+
];
|
|
900
|
+
function rejectsForcedToolUse(model) {
|
|
901
|
+
const m = model.toLowerCase();
|
|
902
|
+
return NO_FORCED_TOOL_PREFIXES.some((p) => m.startsWith(p));
|
|
903
|
+
}
|
|
904
|
+
var UNSUPPORTED_SCHEMA_KEYS = /* @__PURE__ */ new Set([
|
|
905
|
+
"minimum",
|
|
906
|
+
"maximum",
|
|
907
|
+
"exclusiveMinimum",
|
|
908
|
+
"exclusiveMaximum",
|
|
909
|
+
"multipleOf",
|
|
910
|
+
"minLength",
|
|
911
|
+
"maxLength",
|
|
912
|
+
"pattern",
|
|
913
|
+
"minItems",
|
|
914
|
+
"maxItems",
|
|
915
|
+
"uniqueItems",
|
|
916
|
+
"minProperties",
|
|
917
|
+
"maxProperties",
|
|
918
|
+
"$schema"
|
|
919
|
+
]);
|
|
920
|
+
function toStructuredOutputSchema(schema) {
|
|
921
|
+
const walk = (node) => {
|
|
922
|
+
if (Array.isArray(node)) return node.map(walk);
|
|
923
|
+
if (!node || typeof node !== "object") return node;
|
|
924
|
+
const out = {};
|
|
925
|
+
for (const [k, v] of Object.entries(node)) {
|
|
926
|
+
if (UNSUPPORTED_SCHEMA_KEYS.has(k)) continue;
|
|
927
|
+
if (k === "properties" && v && typeof v === "object") {
|
|
928
|
+
out[k] = Object.fromEntries(Object.entries(v).map(([pk, pv]) => [pk, walk(pv)]));
|
|
929
|
+
} else if (["items", "anyOf", "allOf", "oneOf", "not", "$defs", "definitions"].includes(k)) {
|
|
930
|
+
out[k] = k === "$defs" || k === "definitions" ? Object.fromEntries(Object.entries(v ?? {}).map(([dk, dv]) => [dk, walk(dv)])) : walk(v);
|
|
931
|
+
} else {
|
|
932
|
+
out[k] = v;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
if (out["type"] === "object" || "properties" in out) out["additionalProperties"] = false;
|
|
936
|
+
return out;
|
|
937
|
+
};
|
|
938
|
+
return walk(schema);
|
|
939
|
+
}
|
|
767
940
|
var ANTHROPIC_STRUCTURED_TOOL_NAME = "structured_output";
|
|
768
941
|
function applyPromptCaching(body, env = process.env) {
|
|
769
942
|
const flag = (env["CROSSCHECK_ANTHROPIC_PROMPT_CACHE"] ?? "").trim();
|
|
@@ -815,7 +988,12 @@ function buildAnthropicRequest(opts) {
|
|
|
815
988
|
body.thinking = { type: "disabled" };
|
|
816
989
|
}
|
|
817
990
|
}
|
|
818
|
-
if (opts.jsonSchema) {
|
|
991
|
+
if (opts.jsonSchema && rejectsForcedToolUse(opts.model)) {
|
|
992
|
+
body.output_config = {
|
|
993
|
+
...body.output_config ?? {},
|
|
994
|
+
format: { type: "json_schema", schema: toStructuredOutputSchema(opts.jsonSchema) }
|
|
995
|
+
};
|
|
996
|
+
} else if (opts.jsonSchema) {
|
|
819
997
|
body.tools = [{
|
|
820
998
|
name: ANTHROPIC_STRUCTURED_TOOL_NAME,
|
|
821
999
|
description: "Emit a single JSON object matching the requested schema.",
|
|
@@ -934,7 +1112,11 @@ async function sendAnthropic(args) {
|
|
|
934
1112
|
try {
|
|
935
1113
|
respLike = await doFetch(url, init);
|
|
936
1114
|
} catch (e) {
|
|
937
|
-
|
|
1115
|
+
const d = diagnoseNetworkError(e);
|
|
1116
|
+
if (!looksLikeNetworkFailure(d)) throw e;
|
|
1117
|
+
throw new ProviderError(d.kind, networkErrorMessage("anthropic", d), {
|
|
1118
|
+
transient: d.transient
|
|
1119
|
+
});
|
|
938
1120
|
}
|
|
939
1121
|
const status = respLike.status;
|
|
940
1122
|
if (status >= 200 && status < 300) {
|
|
@@ -1007,6 +1189,11 @@ function jsonSchemaToGeminiSchema(schema) {
|
|
|
1007
1189
|
}
|
|
1008
1190
|
return out;
|
|
1009
1191
|
}
|
|
1192
|
+
var GEMINI_THINKING_HEADROOM_TOKENS = 16384;
|
|
1193
|
+
function thinkingHeadroom() {
|
|
1194
|
+
const raw = Number(process.env["CROSSCHECK_GEMINI_THINKING_HEADROOM_TOKENS"]);
|
|
1195
|
+
return Number.isFinite(raw) && raw >= 0 ? Math.trunc(raw) : GEMINI_THINKING_HEADROOM_TOKENS;
|
|
1196
|
+
}
|
|
1010
1197
|
function buildGeminiRequest(opts) {
|
|
1011
1198
|
const contents = [];
|
|
1012
1199
|
let systemText = null;
|
|
@@ -1025,8 +1212,9 @@ function buildGeminiRequest(opts) {
|
|
|
1025
1212
|
const body = {
|
|
1026
1213
|
contents,
|
|
1027
1214
|
generationConfig: {
|
|
1028
|
-
|
|
1029
|
-
|
|
1215
|
+
// Answer budget + thinking headroom. No temperature / topP / topK /
|
|
1216
|
+
// thinkingBudget, on any model — see the header note.
|
|
1217
|
+
maxOutputTokens: opts.maxTokens + thinkingHeadroom()
|
|
1030
1218
|
}
|
|
1031
1219
|
};
|
|
1032
1220
|
if (systemText !== null && systemText !== "") {
|
|
@@ -1036,8 +1224,8 @@ function buildGeminiRequest(opts) {
|
|
|
1036
1224
|
body.generationConfig.responseMimeType = "application/json";
|
|
1037
1225
|
body.generationConfig.responseSchema = jsonSchemaToGeminiSchema(opts.jsonSchema);
|
|
1038
1226
|
}
|
|
1039
|
-
const url = `${GEMINI_API_URL_BASE}/${encodeURIComponent(opts.model)}:generateContent
|
|
1040
|
-
return { url, headers: {}, body };
|
|
1227
|
+
const url = `${GEMINI_API_URL_BASE}/${encodeURIComponent(opts.model)}:generateContent`;
|
|
1228
|
+
return { url, headers: { "x-goog-api-key": opts.apiKey }, body };
|
|
1041
1229
|
}
|
|
1042
1230
|
function parseGeminiResponse(opts) {
|
|
1043
1231
|
const r = opts.resp ?? {};
|
|
@@ -1067,16 +1255,19 @@ function parseGeminiResponse(opts) {
|
|
|
1067
1255
|
}
|
|
1068
1256
|
try {
|
|
1069
1257
|
const first = cands[0];
|
|
1070
|
-
const
|
|
1071
|
-
const
|
|
1258
|
+
const finishReason = typeof first["finishReason"] === "string" ? first["finishReason"] : void 0;
|
|
1259
|
+
const content = first["content"] ?? {};
|
|
1260
|
+
const parts = Array.isArray(content["parts"]) ? content["parts"] : [];
|
|
1072
1261
|
let text = "";
|
|
1073
1262
|
for (const p of parts) {
|
|
1074
1263
|
if (p && typeof p === "object") {
|
|
1075
|
-
const
|
|
1264
|
+
const part = p;
|
|
1265
|
+
if (part["thought"] === true) continue;
|
|
1266
|
+
const t = part["text"];
|
|
1076
1267
|
if (typeof t === "string") text += t;
|
|
1077
1268
|
}
|
|
1078
1269
|
}
|
|
1079
|
-
return { text, usage };
|
|
1270
|
+
return { text, usage, ...finishReason ? { finishReason } : {} };
|
|
1080
1271
|
} catch (e) {
|
|
1081
1272
|
throw new ProviderError(
|
|
1082
1273
|
"parse",
|
|
@@ -1105,7 +1296,8 @@ async function sendGemini(args) {
|
|
|
1105
1296
|
apiKey: args.apiKey,
|
|
1106
1297
|
messages: args.messages,
|
|
1107
1298
|
maxTokens: args.maxTokens,
|
|
1108
|
-
|
|
1299
|
+
// args.temperature is deliberately NOT forwarded: Gemini ignores it and
|
|
1300
|
+
// upcoming models reject it. See the header note.
|
|
1109
1301
|
...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
|
|
1110
1302
|
});
|
|
1111
1303
|
const doFetch = args.fetchImpl ?? globalThis.fetch;
|
|
@@ -1120,7 +1312,11 @@ async function sendGemini(args) {
|
|
|
1120
1312
|
try {
|
|
1121
1313
|
respLike = await doFetch(url, init);
|
|
1122
1314
|
} catch (e) {
|
|
1123
|
-
|
|
1315
|
+
const d = diagnoseNetworkError(e);
|
|
1316
|
+
if (!looksLikeNetworkFailure(d)) throw e;
|
|
1317
|
+
throw new ProviderError(d.kind, networkErrorMessage("gemini", d), {
|
|
1318
|
+
transient: d.transient
|
|
1319
|
+
});
|
|
1124
1320
|
}
|
|
1125
1321
|
const status = respLike.status;
|
|
1126
1322
|
if (status >= 200 && status < 300) {
|
|
@@ -1130,11 +1326,18 @@ async function sendGemini(args) {
|
|
|
1130
1326
|
} catch (e) {
|
|
1131
1327
|
throw new ProviderError("parse", `gemini: response body not JSON: ${e.message}`);
|
|
1132
1328
|
}
|
|
1133
|
-
const { text, usage } = parseGeminiResponse({
|
|
1329
|
+
const { text, usage, finishReason } = parseGeminiResponse({
|
|
1134
1330
|
resp: parsed,
|
|
1135
1331
|
model: args.model,
|
|
1136
1332
|
purpose: args.purpose ?? "worker"
|
|
1137
1333
|
});
|
|
1334
|
+
if (text.trim() === "" && finishReason === "MAX_TOKENS") {
|
|
1335
|
+
throw new ProviderError(
|
|
1336
|
+
"parse",
|
|
1337
|
+
`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.`,
|
|
1338
|
+
{ transient: false }
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1138
1341
|
return { text, attempts: 1, usage: applyPricing2(usage, args.pricing) };
|
|
1139
1342
|
}
|
|
1140
1343
|
const bodyText = await respLike.text().catch(() => "");
|
|
@@ -1191,7 +1394,15 @@ function buildOpenAICompatibleRequest(opts) {
|
|
|
1191
1394
|
json_schema: {
|
|
1192
1395
|
name: "structured_output",
|
|
1193
1396
|
schema: opts.jsonSchema,
|
|
1194
|
-
strict:
|
|
1397
|
+
// NOT strict. Strict mode requires `additionalProperties: false` on
|
|
1398
|
+
// every object and every property listed in `required` — the
|
|
1399
|
+
// engine's schemas don't meet that, so every structured OpenAI call
|
|
1400
|
+
// (planner, judges, synthesis) was a 400, unnoticed until the canary
|
|
1401
|
+
// grew a structured check (2026-10-11). Non-strict still shapes the
|
|
1402
|
+
// reply to the schema, and structured.ts validates it against the
|
|
1403
|
+
// full schema regardless, so strictness added a failure mode and no
|
|
1404
|
+
// safety.
|
|
1405
|
+
strict: false
|
|
1195
1406
|
}
|
|
1196
1407
|
};
|
|
1197
1408
|
}
|
|
@@ -1301,7 +1512,11 @@ async function sendOpenAICompatible(args) {
|
|
|
1301
1512
|
try {
|
|
1302
1513
|
respLike = await doFetch(url, init);
|
|
1303
1514
|
} catch (e) {
|
|
1304
|
-
|
|
1515
|
+
const d = diagnoseNetworkError(e);
|
|
1516
|
+
if (!looksLikeNetworkFailure(d)) throw e;
|
|
1517
|
+
throw new ProviderError(d.kind, networkErrorMessage(args.provider, d), {
|
|
1518
|
+
transient: d.transient
|
|
1519
|
+
});
|
|
1305
1520
|
}
|
|
1306
1521
|
const status = respLike.status;
|
|
1307
1522
|
if (status >= 200 && status < 300) {
|
|
@@ -1475,7 +1690,7 @@ import { z } from "zod";
|
|
|
1475
1690
|
|
|
1476
1691
|
// src/server-meta.ts
|
|
1477
1692
|
var SERVER_NAME = "crosscheck-agent";
|
|
1478
|
-
var SERVER_VERSION = true ? "0.2.
|
|
1693
|
+
var SERVER_VERSION = true ? "0.2.29" : "0.0.0-dev";
|
|
1479
1694
|
|
|
1480
1695
|
// src/tools/audit.ts
|
|
1481
1696
|
import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
|
|
@@ -1698,6 +1913,31 @@ function pyReprType(t) {
|
|
|
1698
1913
|
return String(t);
|
|
1699
1914
|
}
|
|
1700
1915
|
|
|
1916
|
+
// src/core/session.ts
|
|
1917
|
+
import { randomUUID } from "crypto";
|
|
1918
|
+
var processSessionId = null;
|
|
1919
|
+
var startedAt = null;
|
|
1920
|
+
function engineSessionId() {
|
|
1921
|
+
if (processSessionId === null) {
|
|
1922
|
+
processSessionId = randomUUID();
|
|
1923
|
+
startedAt = Date.now();
|
|
1924
|
+
}
|
|
1925
|
+
return processSessionId;
|
|
1926
|
+
}
|
|
1927
|
+
function resolveSessionId(callerSupplied) {
|
|
1928
|
+
const trimmed = typeof callerSupplied === "string" ? callerSupplied.trim() : "";
|
|
1929
|
+
return trimmed.length > 0 ? trimmed : engineSessionId();
|
|
1930
|
+
}
|
|
1931
|
+
function localSessionRecordingEnabled(env = globalThis.process?.env ?? {}) {
|
|
1932
|
+
const v = (env["CROSSCHECK_RECORD_SESSIONS"] ?? "").trim().toLowerCase();
|
|
1933
|
+
return !["0", "false", "off", "no"].includes(v);
|
|
1934
|
+
}
|
|
1935
|
+
function recordingSessionId(callerSupplied) {
|
|
1936
|
+
if (localSessionRecordingEnabled()) return resolveSessionId(callerSupplied);
|
|
1937
|
+
const trimmed = typeof callerSupplied === "string" ? callerSupplied.trim() : "";
|
|
1938
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1701
1941
|
// src/core/usage.ts
|
|
1702
1942
|
function emptyUsage(provider, model, purpose = "worker") {
|
|
1703
1943
|
return {
|
|
@@ -1803,11 +2043,11 @@ function withCommas(n) {
|
|
|
1803
2043
|
function renderRunSummary(opts) {
|
|
1804
2044
|
const endedAt = opts.endedAtS ?? Math.trunc(Date.now() / 1e3);
|
|
1805
2045
|
let scope = "call";
|
|
1806
|
-
let
|
|
2046
|
+
let startedAt2 = null;
|
|
1807
2047
|
let rows = [];
|
|
1808
2048
|
if (opts.sessionScope && opts.sessionScope.rows.length > 0) {
|
|
1809
2049
|
scope = "session";
|
|
1810
|
-
|
|
2050
|
+
startedAt2 = opts.sessionScope.startedAt;
|
|
1811
2051
|
rows = opts.sessionScope.rows.map((r) => ({ ...r }));
|
|
1812
2052
|
} else {
|
|
1813
2053
|
const byPurpose = /* @__PURE__ */ new Map();
|
|
@@ -1838,6 +2078,7 @@ function renderRunSummary(opts) {
|
|
|
1838
2078
|
row.cpu_ms += a.cpu_ms ?? 0;
|
|
1839
2079
|
if (a.cache_hit) row.cache_hits += 1;
|
|
1840
2080
|
if (a.error) row.errors += 1;
|
|
2081
|
+
if (a.usage?.estimated) row.estimated = true;
|
|
1841
2082
|
}
|
|
1842
2083
|
rows = Array.from(byPurpose.values());
|
|
1843
2084
|
}
|
|
@@ -1850,16 +2091,18 @@ function renderRunSummary(opts) {
|
|
|
1850
2091
|
wall_ms: rows.reduce((s, r) => s + r.wall_ms, 0),
|
|
1851
2092
|
cpu_ms: rows.reduce((s, r) => s + r.cpu_ms, 0),
|
|
1852
2093
|
cache_hits: rows.reduce((s, r) => s + r.cache_hits, 0),
|
|
1853
|
-
errors: rows.reduce((s, r) => s + r.errors, 0)
|
|
2094
|
+
errors: rows.reduce((s, r) => s + r.errors, 0),
|
|
2095
|
+
...rows.some((r) => r.estimated) ? { estimated: true } : {}
|
|
1854
2096
|
};
|
|
1855
2097
|
const titleLeft = scope === "session" ? `session: ${opts.sessionId ?? ""}` : `call: ${opts.toolName}`;
|
|
1856
|
-
const
|
|
2098
|
+
const costText = totals.estimated ? `$${totals.cost_usd.toFixed(4)}+ (some calls unpriced)` : `$${totals.cost_usd.toFixed(4)}`;
|
|
2099
|
+
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
2100
|
const bodyLines = [];
|
|
1858
2101
|
for (let i = 0; i < rows.length; i++) {
|
|
1859
2102
|
const r = rows[i];
|
|
1860
2103
|
const glyph = i === rows.length - 1 ? "`-" : "|-";
|
|
1861
2104
|
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)`
|
|
2105
|
+
`${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
2106
|
);
|
|
1864
2107
|
}
|
|
1865
2108
|
const callByModel = rollupSpendByModel(
|
|
@@ -1907,7 +2150,7 @@ function renderRunSummary(opts) {
|
|
|
1907
2150
|
tool: opts.toolName,
|
|
1908
2151
|
scope,
|
|
1909
2152
|
currency: "USD",
|
|
1910
|
-
started_at:
|
|
2153
|
+
started_at: startedAt2,
|
|
1911
2154
|
ended_at: endedAt,
|
|
1912
2155
|
rows,
|
|
1913
2156
|
totals,
|
|
@@ -2032,14 +2275,15 @@ async function attachUsageBlock(result, answers, opts) {
|
|
|
2032
2275
|
delete result["_suppress_run_summary"];
|
|
2033
2276
|
}
|
|
2034
2277
|
async function appendUsageLog(storage, sessionId, toolName, answers, nowS) {
|
|
2035
|
-
|
|
2278
|
+
const sid = recordingSessionId(sessionId);
|
|
2279
|
+
if (!sid || answers.length === 0) return;
|
|
2036
2280
|
const now = nowS ?? Math.trunc(Date.now() / 1e3);
|
|
2037
2281
|
const rows = [];
|
|
2038
2282
|
for (const a of answers) {
|
|
2039
2283
|
const u = a.usage;
|
|
2040
2284
|
if (!u || typeof u.provider !== "string" || u.provider === "") continue;
|
|
2041
2285
|
rows.push({
|
|
2042
|
-
session_id:
|
|
2286
|
+
session_id: sid,
|
|
2043
2287
|
ts: now,
|
|
2044
2288
|
tool: toolName,
|
|
2045
2289
|
purpose: u.purpose ?? "worker",
|
|
@@ -2062,13 +2306,14 @@ async function appendUsageLog(storage, sessionId, toolName, answers, nowS) {
|
|
|
2062
2306
|
}
|
|
2063
2307
|
}
|
|
2064
2308
|
async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, nowS) {
|
|
2065
|
-
|
|
2309
|
+
const sid = recordingSessionId(sessionId);
|
|
2310
|
+
if (!sid) return;
|
|
2066
2311
|
const now = nowS ?? Math.trunc(Date.now() / 1e3);
|
|
2067
2312
|
try {
|
|
2068
|
-
let existing = await storage.getSession(
|
|
2313
|
+
let existing = await storage.getSession(sid);
|
|
2069
2314
|
if (!existing) {
|
|
2070
2315
|
await storage.upsertSession({
|
|
2071
|
-
session_id:
|
|
2316
|
+
session_id: sid,
|
|
2072
2317
|
started_at: now,
|
|
2073
2318
|
last_at: now,
|
|
2074
2319
|
calls: 0,
|
|
@@ -2081,7 +2326,7 @@ async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, now
|
|
|
2081
2326
|
total_cost_usd: 0,
|
|
2082
2327
|
total_cpu_ms: 0
|
|
2083
2328
|
});
|
|
2084
|
-
existing = await storage.getSession(
|
|
2329
|
+
existing = await storage.getSession(sid);
|
|
2085
2330
|
}
|
|
2086
2331
|
if (!existing) return;
|
|
2087
2332
|
let promptDelta = 0;
|
|
@@ -2101,7 +2346,7 @@ async function recordSessionCall(storage, sessionId, answers, wallMs, cpuMs, now
|
|
|
2101
2346
|
}
|
|
2102
2347
|
if (a.cache_hit) cacheHitDelta += 1;
|
|
2103
2348
|
}
|
|
2104
|
-
await storage.accumulateSessionTotals(
|
|
2349
|
+
await storage.accumulateSessionTotals(sid, {
|
|
2105
2350
|
calls: answers.length,
|
|
2106
2351
|
wall_ms: wallMs,
|
|
2107
2352
|
cache_hits: cacheHitDelta,
|
|
@@ -5033,10 +5278,6 @@ If you need supporting evidence, you may emit ONE \`<tool_call>...</tool_call>\`
|
|
|
5033
5278
|
}
|
|
5034
5279
|
|
|
5035
5280
|
// 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
5281
|
async function runConfer(args, opts) {
|
|
5041
5282
|
const callStartedWall = performance3.now();
|
|
5042
5283
|
const callStartedCpu = process.cpuUsage();
|
|
@@ -5052,16 +5293,11 @@ async function runConfer(args, opts) {
|
|
|
5052
5293
|
rejectedWorkerTools.push(t);
|
|
5053
5294
|
}
|
|
5054
5295
|
}
|
|
5055
|
-
|
|
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
|
-
}
|
|
5296
|
+
if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
|
|
5061
5297
|
return errorEnvelope2(
|
|
5062
5298
|
"CONFER_OPT_NOT_NATIVE",
|
|
5063
5299
|
"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
|
|
5300
|
+
"Native confer covers untrusted_input + early_stop + extract_claims + inject_session_memory + auto_panel. worker_tools needs innerCallers wired by the host."
|
|
5065
5301
|
);
|
|
5066
5302
|
}
|
|
5067
5303
|
const question = typeof args["question"] === "string" ? args["question"] : String(args["question"] ?? "");
|
|
@@ -5412,21 +5648,6 @@ function unknownProviderError(unknownNames, available) {
|
|
|
5412
5648
|
available_now: Object.keys(available).sort()
|
|
5413
5649
|
};
|
|
5414
5650
|
}
|
|
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
5651
|
function errorEnvelope2(code, message, hint) {
|
|
5431
5652
|
return {
|
|
5432
5653
|
tool: "confer",
|
|
@@ -5798,7 +6019,7 @@ function errorEnvelope3(code, message, hint) {
|
|
|
5798
6019
|
transient: false
|
|
5799
6020
|
};
|
|
5800
6021
|
}
|
|
5801
|
-
async function runVerify(args,
|
|
6022
|
+
async function runVerify(args, fetchConfig) {
|
|
5802
6023
|
const checks = args["checks"];
|
|
5803
6024
|
if (!Array.isArray(checks) || checks.length === 0) {
|
|
5804
6025
|
return {
|
|
@@ -5810,7 +6031,6 @@ async function runVerify(args, bridge, fetchConfig) {
|
|
|
5810
6031
|
)
|
|
5811
6032
|
};
|
|
5812
6033
|
}
|
|
5813
|
-
void bridge;
|
|
5814
6034
|
const allowShell = Boolean(args["allow_shell"] ?? false);
|
|
5815
6035
|
const wallStart = performance4.now();
|
|
5816
6036
|
const cpuStart = process.cpuUsage();
|
|
@@ -6112,7 +6332,6 @@ async function runBench(args, opts) {
|
|
|
6112
6332
|
const innerOpts = {
|
|
6113
6333
|
providers: opts.providers,
|
|
6114
6334
|
allowlist: opts.allowlist ?? null,
|
|
6115
|
-
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
6116
6335
|
...opts.moderator ? { moderator: opts.moderator } : {}
|
|
6117
6336
|
};
|
|
6118
6337
|
let inner;
|
|
@@ -6806,7 +7025,6 @@ var EST_TOKENS = {
|
|
|
6806
7025
|
med: [1500, 800],
|
|
6807
7026
|
high: [2500, 1500]
|
|
6808
7027
|
};
|
|
6809
|
-
var DEFERRED_OPTS2 = [];
|
|
6810
7028
|
var REACTIVE_SIGNAL_RE = /<signals>\s*(\{[\s\S]*?\})\s*<\/signals>/g;
|
|
6811
7029
|
function parseReactiveSignals(output) {
|
|
6812
7030
|
if (typeof output !== "string" || !output.includes("<signals>")) return [];
|
|
@@ -6846,17 +7064,6 @@ async function runOrchestrate(args, opts) {
|
|
|
6846
7064
|
);
|
|
6847
7065
|
if (breakerEnv) return breakerEnv;
|
|
6848
7066
|
}
|
|
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
7067
|
const goal = typeof args["goal"] === "string" ? args["goal"] : null;
|
|
6861
7068
|
const dagIn = isObj5(args["dag"]) ? args["dag"] : null;
|
|
6862
7069
|
if (goal === null === (dagIn === null)) {
|
|
@@ -7798,21 +8005,6 @@ function resolveProviders3(names, available, allowlist) {
|
|
|
7798
8005
|
}
|
|
7799
8006
|
return out;
|
|
7800
8007
|
}
|
|
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
8008
|
function errorEnvelope5(code, message, hint, kind = "client") {
|
|
7817
8009
|
return {
|
|
7818
8010
|
tool: "orchestrate",
|
|
@@ -8130,6 +8322,16 @@ function buildCallContext(args) {
|
|
|
8130
8322
|
var CREATE_DOC_MAX_BYTES = 32 * 1024;
|
|
8131
8323
|
var CREATE_AUDIT_THRESHOLD = 0.7;
|
|
8132
8324
|
async function runCreate(args, opts) {
|
|
8325
|
+
const subEnvelopes = [];
|
|
8326
|
+
const tracked = (fn) => async (...a) => {
|
|
8327
|
+
const out = await fn(...a);
|
|
8328
|
+
subEnvelopes.push(out);
|
|
8329
|
+
return out;
|
|
8330
|
+
};
|
|
8331
|
+
const confer = tracked(runConfer);
|
|
8332
|
+
const orchestrate = tracked(runOrchestrate);
|
|
8333
|
+
const review = tracked(runReview);
|
|
8334
|
+
const audit = tracked(runAudit);
|
|
8133
8335
|
const instruction = typeof args["instruction"] === "string" ? args["instruction"] : String(args["instruction"] ?? "");
|
|
8134
8336
|
if (!instruction) {
|
|
8135
8337
|
return errorEnvelope6(
|
|
@@ -8166,7 +8368,7 @@ ${constraints}
|
|
|
8166
8368
|
|
|
8167
8369
|
` : "") + `DOCUMENTS (${okCount} of ${descriptors.length} ingested):
|
|
8168
8370
|
${documentsPayload}`;
|
|
8169
|
-
const scope = await
|
|
8371
|
+
const scope = await confer({
|
|
8170
8372
|
question: "We are about to orchestrate a full plan->build->review->audit lifecycle for this instruction. List 3-6 concrete sub-tasks (each with a one-line description and a difficulty: low|med|high), any critical assumptions, and any missing-information risks. Be concise and decisive \u2014 your output will be used to build the orchestration DAG.\n\nINSTRUCTION:\n" + instruction,
|
|
8171
8373
|
context: contextBlock,
|
|
8172
8374
|
...providers !== void 0 ? { providers } : {},
|
|
@@ -8175,7 +8377,6 @@ ${documentsPayload}`;
|
|
|
8175
8377
|
}, {
|
|
8176
8378
|
providers: opts.providers,
|
|
8177
8379
|
allowlist: opts.allowlist ?? null,
|
|
8178
|
-
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
8179
8380
|
ctx
|
|
8180
8381
|
});
|
|
8181
8382
|
const scopeAnswer = Array.isArray(scope["answers"]) ? scope["answers"].filter((a) => typeof a["response"] === "string" && a["response"]).map((a) => `[${a["provider"]}]
|
|
@@ -8194,11 +8395,10 @@ ${scopeAnswer || "(none)"}
|
|
|
8194
8395
|
};
|
|
8195
8396
|
if (providers !== void 0) orchestrateArgs["providers"] = providers;
|
|
8196
8397
|
if (planOnly) orchestrateArgs["plan_only"] = true;
|
|
8197
|
-
let orchestration = await
|
|
8398
|
+
let orchestration = await orchestrate(orchestrateArgs, {
|
|
8198
8399
|
providers: opts.providers,
|
|
8199
8400
|
allowlist: opts.allowlist ?? null,
|
|
8200
8401
|
moderator,
|
|
8201
|
-
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
8202
8402
|
ctx
|
|
8203
8403
|
});
|
|
8204
8404
|
let attempts = 1;
|
|
@@ -8224,7 +8424,7 @@ ${scopeAnswer || "(none)"}
|
|
|
8224
8424
|
}
|
|
8225
8425
|
let reviewEnvelope = null;
|
|
8226
8426
|
if (!skipReview && typeof orchestration["final"] === "string" && orchestration["final"]) {
|
|
8227
|
-
reviewEnvelope = await
|
|
8427
|
+
reviewEnvelope = await review({
|
|
8228
8428
|
snippet: orchestration["final"],
|
|
8229
8429
|
intent: `final deliverable for: ${instruction}`,
|
|
8230
8430
|
...providers !== void 0 ? { providers } : {},
|
|
@@ -8233,7 +8433,6 @@ ${scopeAnswer || "(none)"}
|
|
|
8233
8433
|
}, {
|
|
8234
8434
|
providers: opts.providers,
|
|
8235
8435
|
allowlist: opts.allowlist ?? null,
|
|
8236
|
-
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
8237
8436
|
ctx
|
|
8238
8437
|
});
|
|
8239
8438
|
}
|
|
@@ -8245,7 +8444,7 @@ ${scopeAnswer || "(none)"}
|
|
|
8245
8444
|
const panelExhausted = producingPanel.length > 0 && producingPanel.every(
|
|
8246
8445
|
(p) => p in opts.providers || Object.keys(opts.providers).includes(p.toLowerCase())
|
|
8247
8446
|
) && producingPanel.length >= Object.keys(opts.providers).length;
|
|
8248
|
-
auditEnvelope = await
|
|
8447
|
+
auditEnvelope = await audit({
|
|
8249
8448
|
output_to_audit: orchestration["final"],
|
|
8250
8449
|
producing_panelists: producingPanel,
|
|
8251
8450
|
...auditRubric !== void 0 ? { rubric: auditRubric } : {},
|
|
@@ -8256,7 +8455,6 @@ ${scopeAnswer || "(none)"}
|
|
|
8256
8455
|
}, {
|
|
8257
8456
|
providers: opts.providers,
|
|
8258
8457
|
allowlist: opts.allowlist ?? null,
|
|
8259
|
-
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
8260
8458
|
ctx
|
|
8261
8459
|
});
|
|
8262
8460
|
let overallF = toNumberOrNull(auditEnvelope["overall_score"]);
|
|
@@ -8275,13 +8473,12 @@ ${retryConstraints}
|
|
|
8275
8473
|
DOCUMENTS:
|
|
8276
8474
|
${documentsPayload}`
|
|
8277
8475
|
};
|
|
8278
|
-
const retryOrchestration = await
|
|
8476
|
+
const retryOrchestration = await orchestrate(
|
|
8279
8477
|
retryOrchestrateArgs,
|
|
8280
8478
|
{
|
|
8281
8479
|
providers: opts.providers,
|
|
8282
8480
|
allowlist: opts.allowlist ?? null,
|
|
8283
8481
|
moderator,
|
|
8284
|
-
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
8285
8482
|
ctx
|
|
8286
8483
|
}
|
|
8287
8484
|
);
|
|
@@ -8290,7 +8487,7 @@ ${documentsPayload}`
|
|
|
8290
8487
|
if (typeof retryOrchestration["final"] === "string" && retryOrchestration["final"]) {
|
|
8291
8488
|
const retryPanel = computeProducingPanel(retryOrchestration);
|
|
8292
8489
|
const retryPanelExhausted = retryPanel.length > 0 && retryPanel.length >= Object.keys(opts.providers).length;
|
|
8293
|
-
auditEnvelope = await
|
|
8490
|
+
auditEnvelope = await audit({
|
|
8294
8491
|
output_to_audit: retryOrchestration["final"],
|
|
8295
8492
|
producing_panelists: retryPanel,
|
|
8296
8493
|
...auditRubric !== void 0 ? { rubric: auditRubric } : {},
|
|
@@ -8301,7 +8498,6 @@ ${documentsPayload}`
|
|
|
8301
8498
|
}, {
|
|
8302
8499
|
providers: opts.providers,
|
|
8303
8500
|
allowlist: opts.allowlist ?? null,
|
|
8304
|
-
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
8305
8501
|
ctx
|
|
8306
8502
|
});
|
|
8307
8503
|
overallF = toNumberOrNull(auditEnvelope["overall_score"]);
|
|
@@ -8366,9 +8562,28 @@ ${documentsPayload}`
|
|
|
8366
8562
|
["auditor", "items", "overall_score", "passed", "rubric"]
|
|
8367
8563
|
),
|
|
8368
8564
|
artifacts,
|
|
8369
|
-
warnings
|
|
8565
|
+
warnings,
|
|
8566
|
+
...combinedUsage(subEnvelopes)
|
|
8370
8567
|
};
|
|
8371
8568
|
}
|
|
8569
|
+
function combinedUsage(envelopes) {
|
|
8570
|
+
const usages = [];
|
|
8571
|
+
const byCallTiming = [];
|
|
8572
|
+
let wall = 0, cpu = 0;
|
|
8573
|
+
for (const env of envelopes) {
|
|
8574
|
+
const e = env ?? {};
|
|
8575
|
+
const calls = e["usage"]?.["by_call"] ?? [];
|
|
8576
|
+
const t = e["timing"] ?? {};
|
|
8577
|
+
const timing = Array.isArray(t["by_call"]) ? t["by_call"] : [];
|
|
8578
|
+
if (!Array.isArray(calls) || calls.length === 0) continue;
|
|
8579
|
+
usages.push(...calls);
|
|
8580
|
+
if (timing.length === calls.length) byCallTiming.push(...timing);
|
|
8581
|
+
else for (const c of calls) byCallTiming.push({ provider: c.provider, model: c.model, purpose: c.purpose ?? null, wall_ms: 0, cpu_ms: 0, cache_hit: false });
|
|
8582
|
+
wall += Number(t["wall_ms"] ?? 0) || 0;
|
|
8583
|
+
cpu += Number(t["cpu_ms"] ?? 0) || 0;
|
|
8584
|
+
}
|
|
8585
|
+
return { usage: aggregateUsage(usages), timing: { wall_ms: wall, cpu_ms: cpu, by_call: byCallTiming } };
|
|
8586
|
+
}
|
|
8372
8587
|
async function ingestDocuments(documents, sessionId, opts) {
|
|
8373
8588
|
if (documents.length === 0) return [];
|
|
8374
8589
|
const out = [];
|
|
@@ -8539,11 +8754,6 @@ function errorEnvelope6(toolName, code, message, hint) {
|
|
|
8539
8754
|
|
|
8540
8755
|
// src/tools/coordinate.ts
|
|
8541
8756
|
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
8757
|
var COORDINATE_DEFAULT_TEMP = 0.4;
|
|
8548
8758
|
var ROLE_TURN_SCHEMA = {
|
|
8549
8759
|
type: "object",
|
|
@@ -8598,23 +8808,18 @@ async function runCoordinate(args, opts) {
|
|
|
8598
8808
|
rejectedWorkerTools.push(t);
|
|
8599
8809
|
}
|
|
8600
8810
|
}
|
|
8601
|
-
|
|
8602
|
-
const needsBridge = DEFERRED_OPTS3.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
|
|
8603
|
-
if (needsBridge) {
|
|
8811
|
+
if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
|
|
8604
8812
|
if (superRequested) {
|
|
8605
8813
|
return errorEnvelope7(
|
|
8606
8814
|
"COORDINATE_SUPER_NOT_NATIVE",
|
|
8607
|
-
"super mode requested
|
|
8608
|
-
"worker_tools
|
|
8815
|
+
"super mode requested with worker_tools, but innerCallers are not wired",
|
|
8816
|
+
"worker_tools needs innerCallers wired by the host. Drop worker_tools, or wire innerCallers, to use super."
|
|
8609
8817
|
);
|
|
8610
8818
|
}
|
|
8611
|
-
if (opts.bridge && opts.bridge.toolNames.has("coordinate")) {
|
|
8612
|
-
return await deferCoordinate(args, opts.bridge);
|
|
8613
|
-
}
|
|
8614
8819
|
return errorEnvelope7(
|
|
8615
8820
|
"COORDINATE_OPT_NOT_NATIVE",
|
|
8616
8821
|
"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
|
|
8822
|
+
"Native coordinate covers the three-role flow + untrusted_input + inject_session_memory. worker_tools needs innerCallers wired by the host."
|
|
8618
8823
|
);
|
|
8619
8824
|
}
|
|
8620
8825
|
const untrusted = Boolean(args["untrusted_input"]);
|
|
@@ -9014,21 +9219,6 @@ function unknownProviderError3(unknownNames, available) {
|
|
|
9014
9219
|
available_now: Object.keys(available).sort()
|
|
9015
9220
|
};
|
|
9016
9221
|
}
|
|
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
9222
|
function errorEnvelope7(code, message, hint) {
|
|
9033
9223
|
return {
|
|
9034
9224
|
tool: "coordinate",
|
|
@@ -9356,10 +9546,6 @@ function buildModeratorTranscript(transcript) {
|
|
|
9356
9546
|
|
|
9357
9547
|
// src/tools/debate.ts
|
|
9358
9548
|
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
9549
|
async function runDebate(args, opts) {
|
|
9364
9550
|
const callStartedWall = performance10.now();
|
|
9365
9551
|
const callStartedCpu = process.cpuUsage();
|
|
@@ -9377,23 +9563,18 @@ async function runDebate(args, opts) {
|
|
|
9377
9563
|
rejectedWorkerTools.push(t);
|
|
9378
9564
|
}
|
|
9379
9565
|
}
|
|
9380
|
-
|
|
9381
|
-
const needsBridge = DEFERRED_OPTS4.some((k) => Boolean(args[k])) || workerToolsNeedsBridge;
|
|
9382
|
-
if (needsBridge) {
|
|
9566
|
+
if (acceptedWorkerTools.length > 0 && !opts.innerCallers) {
|
|
9383
9567
|
if (superRequested) {
|
|
9384
9568
|
return errorEnvelope9(
|
|
9385
9569
|
"DEBATE_SUPER_NOT_NATIVE",
|
|
9386
|
-
"super mode requested
|
|
9387
|
-
"worker_tools
|
|
9570
|
+
"super mode requested with worker_tools, but innerCallers are not wired",
|
|
9571
|
+
"worker_tools needs innerCallers wired by the host. Drop worker_tools, or wire innerCallers, to use super."
|
|
9388
9572
|
);
|
|
9389
9573
|
}
|
|
9390
|
-
if (opts.bridge && opts.bridge.toolNames.has("debate")) {
|
|
9391
|
-
return await deferDebate(args, opts.bridge);
|
|
9392
|
-
}
|
|
9393
9574
|
return errorEnvelope9(
|
|
9394
9575
|
"DEBATE_OPT_NOT_NATIVE",
|
|
9395
9576
|
"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
|
|
9577
|
+
"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
9578
|
);
|
|
9398
9579
|
}
|
|
9399
9580
|
const topic = typeof args["topic"] === "string" ? args["topic"] : String(args["topic"] ?? "");
|
|
@@ -9830,21 +10011,6 @@ function unknownProviderError5(unknownNames, available) {
|
|
|
9830
10011
|
available_now: Object.keys(available).sort()
|
|
9831
10012
|
};
|
|
9832
10013
|
}
|
|
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
10014
|
function errorEnvelope9(code, message, hint) {
|
|
9849
10015
|
return {
|
|
9850
10016
|
tool: "debate",
|
|
@@ -9864,9 +10030,6 @@ var DEFAULT_DELEGATION_LIMITS = {
|
|
|
9864
10030
|
};
|
|
9865
10031
|
async function runDelegate(args, opts) {
|
|
9866
10032
|
if (!opts.storage) {
|
|
9867
|
-
if (opts.bridge && opts.bridge.toolNames.has("delegate")) {
|
|
9868
|
-
return await deferDelegate(args, opts.bridge);
|
|
9869
|
-
}
|
|
9870
10033
|
return errorEnvelope10(
|
|
9871
10034
|
"DELEGATE_STORAGE_UNAVAILABLE",
|
|
9872
10035
|
"delegate needs the local database (for quota tracking), which isn't available",
|
|
@@ -9938,7 +10101,6 @@ async function runDelegate(args, opts) {
|
|
|
9938
10101
|
const innerOpts = {
|
|
9939
10102
|
providers: opts.providers,
|
|
9940
10103
|
allowlist: opts.allowlist ?? null,
|
|
9941
|
-
...opts.bridge ? { bridge: opts.bridge } : {},
|
|
9942
10104
|
...opts.moderator ? { moderator: opts.moderator } : {}
|
|
9943
10105
|
};
|
|
9944
10106
|
let result;
|
|
@@ -9977,21 +10139,6 @@ async function record(storage, sessionId, requester, toolCall, via, accepted, no
|
|
|
9977
10139
|
created_at: nowEpochSeconds
|
|
9978
10140
|
});
|
|
9979
10141
|
}
|
|
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
10142
|
function errorEnvelope10(code, message, hint) {
|
|
9996
10143
|
return {
|
|
9997
10144
|
tool: "delegate",
|
|
@@ -10034,9 +10181,6 @@ async function runExplain(args, opts) {
|
|
|
10034
10181
|
);
|
|
10035
10182
|
}
|
|
10036
10183
|
if (!opts.storage) {
|
|
10037
|
-
if (opts.bridge && opts.bridge.toolNames.has("explain")) {
|
|
10038
|
-
return await deferExplain(args, opts.bridge);
|
|
10039
|
-
}
|
|
10040
10184
|
return errorEnvelope11(
|
|
10041
10185
|
"EXPLAIN_STORAGE_UNAVAILABLE",
|
|
10042
10186
|
"explain needs the local transcript/stats database, which isn't available",
|
|
@@ -10318,21 +10462,6 @@ function pyRepr5(v) {
|
|
|
10318
10462
|
}
|
|
10319
10463
|
return String(v);
|
|
10320
10464
|
}
|
|
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
10465
|
function errorEnvelope11(code, message, hint, kind = "client", extra = {}) {
|
|
10337
10466
|
return {
|
|
10338
10467
|
tool: "explain",
|
|
@@ -10885,9 +11014,6 @@ async function runRecall(args, opts) {
|
|
|
10885
11014
|
if (k < 1) k = 1;
|
|
10886
11015
|
if (k > 50) k = 50;
|
|
10887
11016
|
if (!opts.storage) {
|
|
10888
|
-
if (opts.bridge && opts.bridge.toolNames.has("recall")) {
|
|
10889
|
-
return await deferRecall(args, opts.bridge);
|
|
10890
|
-
}
|
|
10891
11017
|
return errorEnvelope12(
|
|
10892
11018
|
"RECALL_STORAGE_UNAVAILABLE",
|
|
10893
11019
|
"recall needs the local database, which isn't available",
|
|
@@ -10940,21 +11066,6 @@ async function runRecall(args, opts) {
|
|
|
10940
11066
|
applied_filters: applied
|
|
10941
11067
|
};
|
|
10942
11068
|
}
|
|
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
11069
|
function errorEnvelope12(code, message, hint) {
|
|
10959
11070
|
return {
|
|
10960
11071
|
tool: "recall",
|
|
@@ -10977,9 +11088,6 @@ async function runRecommendPanel(args, opts) {
|
|
|
10977
11088
|
);
|
|
10978
11089
|
}
|
|
10979
11090
|
if (!opts.storage) {
|
|
10980
|
-
if (opts.bridge && opts.bridge.toolNames.has("recommend_panel")) {
|
|
10981
|
-
return await deferRecommendPanel(args, opts.bridge);
|
|
10982
|
-
}
|
|
10983
11091
|
return errorEnvelope13(
|
|
10984
11092
|
"RECOMMEND_PANEL_STORAGE_UNAVAILABLE",
|
|
10985
11093
|
"recommend_panel needs the local stats database, which isn't available",
|
|
@@ -11042,21 +11150,6 @@ async function runRecommendPanel(args, opts) {
|
|
|
11042
11150
|
meta: result.meta
|
|
11043
11151
|
};
|
|
11044
11152
|
}
|
|
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
11153
|
function errorEnvelope13(code, message, hint) {
|
|
11061
11154
|
return {
|
|
11062
11155
|
tool: "recommend_panel",
|
|
@@ -11086,9 +11179,6 @@ function toStringArray3(v) {
|
|
|
11086
11179
|
import { readFileSync as readFileSync10, existsSync as existsSync8 } from "fs";
|
|
11087
11180
|
async function runScoreboard(args, opts) {
|
|
11088
11181
|
if (!opts.storage) {
|
|
11089
|
-
if (opts.bridge && opts.bridge.toolNames.has("scoreboard")) {
|
|
11090
|
-
return await deferScoreboard(args, opts.bridge);
|
|
11091
|
-
}
|
|
11092
11182
|
return errorEnvelope14(
|
|
11093
11183
|
"SCOREBOARD_STORAGE_UNAVAILABLE",
|
|
11094
11184
|
"scoreboard needs the local stats database, which isn't available",
|
|
@@ -11211,21 +11301,6 @@ function clampInt3(raw, min, max, fallback) {
|
|
|
11211
11301
|
if (!Number.isFinite(n)) return fallback;
|
|
11212
11302
|
return Math.min(max, Math.max(min, Math.trunc(n)));
|
|
11213
11303
|
}
|
|
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
11304
|
function errorEnvelope14(code, message, hint) {
|
|
11230
11305
|
return {
|
|
11231
11306
|
tool: "scoreboard",
|
|
@@ -11262,9 +11337,6 @@ async function runSessionMemory(args, opts) {
|
|
|
11262
11337
|
);
|
|
11263
11338
|
}
|
|
11264
11339
|
if (!opts.storage) {
|
|
11265
|
-
if (opts.bridge && opts.bridge.toolNames.has("session_memory")) {
|
|
11266
|
-
return await deferSessionMemory(args, opts.bridge);
|
|
11267
|
-
}
|
|
11268
11340
|
return errorEnvelope15(
|
|
11269
11341
|
"SESSION_MEMORY_STORAGE_UNAVAILABLE",
|
|
11270
11342
|
"session_memory needs the local database, which isn't available",
|
|
@@ -11369,21 +11441,6 @@ function clampInt4(raw, min, max, fallback) {
|
|
|
11369
11441
|
if (!Number.isFinite(n)) return fallback;
|
|
11370
11442
|
return Math.min(max, Math.max(min, Math.trunc(n)));
|
|
11371
11443
|
}
|
|
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
11444
|
function errorEnvelope15(code, message, hint) {
|
|
11388
11445
|
return {
|
|
11389
11446
|
tool: "session_memory",
|
|
@@ -12003,7 +12060,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
|
|
|
12003
12060
|
var DEFAULT_PACKAGE = "crosscheck-cli";
|
|
12004
12061
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
12005
12062
|
function engineVersion() {
|
|
12006
|
-
return true ? "0.2.
|
|
12063
|
+
return true ? "0.2.29" : "0.0.0-dev";
|
|
12007
12064
|
}
|
|
12008
12065
|
function defaultUpdateCachePath() {
|
|
12009
12066
|
const base = process.env["CROSSCHECK_DATA_DIR"] || path9.join(os.homedir() || os.tmpdir(), ".crosscheck");
|
|
@@ -12775,12 +12832,11 @@ function helpTool() {
|
|
|
12775
12832
|
}
|
|
12776
12833
|
});
|
|
12777
12834
|
}
|
|
12778
|
-
function registerCoreTools(
|
|
12779
|
-
const o = opts && typeof opts === "object" && "toolNames" in opts ? { bridge: opts } : opts;
|
|
12835
|
+
function registerCoreTools(o = {}) {
|
|
12780
12836
|
const tools = /* @__PURE__ */ new Map();
|
|
12781
12837
|
const list = [
|
|
12782
12838
|
pingTool(),
|
|
12783
|
-
verifyTool(o.
|
|
12839
|
+
verifyTool(o.fetchConfig),
|
|
12784
12840
|
pickTool(
|
|
12785
12841
|
o.providers ?? {},
|
|
12786
12842
|
o.providerAllowlist ?? null,
|
|
@@ -12792,7 +12848,6 @@ function registerCoreTools(opts = {}) {
|
|
|
12792
12848
|
auditTool(
|
|
12793
12849
|
o.providers ?? {},
|
|
12794
12850
|
o.providerAllowlist ?? null,
|
|
12795
|
-
o.bridge,
|
|
12796
12851
|
o.transcriptsDir,
|
|
12797
12852
|
o.pricing,
|
|
12798
12853
|
o.storage,
|
|
@@ -12802,7 +12857,6 @@ function registerCoreTools(opts = {}) {
|
|
|
12802
12857
|
conferTool(
|
|
12803
12858
|
o.providers ?? {},
|
|
12804
12859
|
o.providerAllowlist ?? null,
|
|
12805
|
-
o.bridge,
|
|
12806
12860
|
o.moderatorDefault ?? "anthropic",
|
|
12807
12861
|
o.pricing,
|
|
12808
12862
|
o.storage,
|
|
@@ -12815,7 +12869,6 @@ function registerCoreTools(opts = {}) {
|
|
|
12815
12869
|
debateTool(
|
|
12816
12870
|
o.providers ?? {},
|
|
12817
12871
|
o.providerAllowlist ?? null,
|
|
12818
|
-
o.bridge,
|
|
12819
12872
|
buildInnerCallers(o),
|
|
12820
12873
|
o.storage,
|
|
12821
12874
|
o.pricing,
|
|
@@ -12827,7 +12880,6 @@ function registerCoreTools(opts = {}) {
|
|
|
12827
12880
|
coordinateTool(
|
|
12828
12881
|
o.providers ?? {},
|
|
12829
12882
|
o.providerAllowlist ?? null,
|
|
12830
|
-
o.bridge,
|
|
12831
12883
|
buildInnerCallers(o),
|
|
12832
12884
|
o.storage,
|
|
12833
12885
|
o.circuitBreakers,
|
|
@@ -12838,7 +12890,6 @@ function registerCoreTools(opts = {}) {
|
|
|
12838
12890
|
triangulateTool(
|
|
12839
12891
|
o.providers ?? {},
|
|
12840
12892
|
o.providerAllowlist ?? null,
|
|
12841
|
-
o.bridge,
|
|
12842
12893
|
o.storage,
|
|
12843
12894
|
o.circuitBreakers,
|
|
12844
12895
|
o.transcriptsDir,
|
|
@@ -12847,7 +12898,6 @@ function registerCoreTools(opts = {}) {
|
|
|
12847
12898
|
planTool(
|
|
12848
12899
|
o.providers ?? {},
|
|
12849
12900
|
o.providerAllowlist ?? null,
|
|
12850
|
-
o.bridge,
|
|
12851
12901
|
o.storage,
|
|
12852
12902
|
o.circuitBreakers,
|
|
12853
12903
|
o.transcriptsDir,
|
|
@@ -12856,7 +12906,6 @@ function registerCoreTools(opts = {}) {
|
|
|
12856
12906
|
critiqueTool(
|
|
12857
12907
|
o.providers ?? {},
|
|
12858
12908
|
o.providerAllowlist ?? null,
|
|
12859
|
-
o.bridge,
|
|
12860
12909
|
o.storage,
|
|
12861
12910
|
o.circuitBreakers,
|
|
12862
12911
|
o.transcriptsDir,
|
|
@@ -12865,7 +12914,6 @@ function registerCoreTools(opts = {}) {
|
|
|
12865
12914
|
reviewTool(
|
|
12866
12915
|
o.providers ?? {},
|
|
12867
12916
|
o.providerAllowlist ?? null,
|
|
12868
|
-
o.bridge,
|
|
12869
12917
|
o.storage,
|
|
12870
12918
|
o.circuitBreakers,
|
|
12871
12919
|
o.transcriptsDir,
|
|
@@ -12873,25 +12921,23 @@ function registerCoreTools(opts = {}) {
|
|
|
12873
12921
|
),
|
|
12874
12922
|
listProvidersTool(o.providers ?? {}, o.activeProviders ?? null, o.moderatorDefault ?? "anthropic"),
|
|
12875
12923
|
modelsTool(o.providers ?? {}, o.activeProviders ?? null),
|
|
12876
|
-
recallTool(o.storage
|
|
12877
|
-
sessionMemoryTool(o.storage
|
|
12878
|
-
scoreboardTool(o.storage, o.
|
|
12879
|
-
explainTool(o.storage, o.
|
|
12924
|
+
recallTool(o.storage),
|
|
12925
|
+
sessionMemoryTool(o.storage),
|
|
12926
|
+
scoreboardTool(o.storage, o.eventsPath),
|
|
12927
|
+
explainTool(o.storage, o.transcriptsDir),
|
|
12880
12928
|
delegateTool(
|
|
12881
12929
|
o.providers ?? {},
|
|
12882
12930
|
o.providerAllowlist ?? null,
|
|
12883
12931
|
o.storage,
|
|
12884
|
-
o.bridge,
|
|
12885
12932
|
o.moderatorDefault ?? "anthropic"
|
|
12886
12933
|
),
|
|
12887
12934
|
fetchTool(o.storage, o.fetchConfig, o.repoRoot),
|
|
12888
|
-
recommendPanelTool(o.providers ?? {}, o.storage
|
|
12935
|
+
recommendPanelTool(o.providers ?? {}, o.storage),
|
|
12889
12936
|
updateCrosscheckTool(o.repoRoot ?? null),
|
|
12890
12937
|
benchTool(
|
|
12891
12938
|
o.providers ?? {},
|
|
12892
12939
|
o.providerAllowlist ?? null,
|
|
12893
12940
|
o.storage,
|
|
12894
|
-
o.bridge,
|
|
12895
12941
|
o.moderatorDefault ?? "anthropic",
|
|
12896
12942
|
o.benchGoldensDir,
|
|
12897
12943
|
o.circuitBreakers,
|
|
@@ -12902,7 +12948,6 @@ function registerCoreTools(opts = {}) {
|
|
|
12902
12948
|
solveTool(
|
|
12903
12949
|
o.providers ?? {},
|
|
12904
12950
|
o.providerAllowlist ?? null,
|
|
12905
|
-
o.bridge,
|
|
12906
12951
|
o.storage,
|
|
12907
12952
|
o.circuitBreakers,
|
|
12908
12953
|
o.transcriptsDir,
|
|
@@ -12911,7 +12956,6 @@ function registerCoreTools(opts = {}) {
|
|
|
12911
12956
|
orchestrateTool(
|
|
12912
12957
|
o.providers ?? {},
|
|
12913
12958
|
o.providerAllowlist ?? null,
|
|
12914
|
-
o.bridge,
|
|
12915
12959
|
o.moderatorDefault ?? "anthropic",
|
|
12916
12960
|
o.storage,
|
|
12917
12961
|
o.pricing,
|
|
@@ -12958,7 +13002,6 @@ function createTool(o, toolName, cheapDefault) {
|
|
|
12958
13002
|
providers: o.providers ?? {},
|
|
12959
13003
|
allowlist: o.providerAllowlist ?? null,
|
|
12960
13004
|
...o.storage ? { storage: o.storage } : {},
|
|
12961
|
-
...o.bridge ? { bridge: o.bridge } : {},
|
|
12962
13005
|
...o.moderatorDefault ? { moderator: o.moderatorDefault } : {},
|
|
12963
13006
|
...o.fetchConfig ? { fetchConfig: o.fetchConfig } : {},
|
|
12964
13007
|
...o.repoRoot ? { repoRoot: o.repoRoot } : {},
|
|
@@ -12967,7 +13010,7 @@ function createTool(o, toolName, cheapDefault) {
|
|
|
12967
13010
|
})
|
|
12968
13011
|
};
|
|
12969
13012
|
}
|
|
12970
|
-
function orchestrateTool(providers, allowlist,
|
|
13013
|
+
function orchestrateTool(providers, allowlist, moderator, storage, pricing, breakers, transcriptsDir, repoRoot, nodeCache) {
|
|
12971
13014
|
return {
|
|
12972
13015
|
name: "orchestrate",
|
|
12973
13016
|
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 +13035,6 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
|
|
|
12992
13035
|
providers,
|
|
12993
13036
|
allowlist,
|
|
12994
13037
|
moderator,
|
|
12995
|
-
...bridge ? { bridge } : {},
|
|
12996
13038
|
...storage ? { storage } : {},
|
|
12997
13039
|
...pricing ? { pricing } : {},
|
|
12998
13040
|
...breakers ? { breakers } : {},
|
|
@@ -13002,7 +13044,7 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
|
|
|
13002
13044
|
})
|
|
13003
13045
|
};
|
|
13004
13046
|
}
|
|
13005
|
-
function solveTool(providers, allowlist,
|
|
13047
|
+
function solveTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
|
|
13006
13048
|
return {
|
|
13007
13049
|
name: "solve",
|
|
13008
13050
|
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 +13066,6 @@ function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsD
|
|
|
13024
13066
|
handler: (args) => runSolve(args, {
|
|
13025
13067
|
providers,
|
|
13026
13068
|
allowlist,
|
|
13027
|
-
...bridge ? { bridge } : {},
|
|
13028
13069
|
...storage ? { storage } : {},
|
|
13029
13070
|
...breakers ? { breakers } : {},
|
|
13030
13071
|
...transcriptsDir ? { transcriptsDir } : {},
|
|
@@ -13063,7 +13104,7 @@ function configPinTool(repoRoot, config, rejectDriftEnv) {
|
|
|
13063
13104
|
}
|
|
13064
13105
|
};
|
|
13065
13106
|
}
|
|
13066
|
-
function benchTool(providers, allowlist, storage,
|
|
13107
|
+
function benchTool(providers, allowlist, storage, moderator, defaultGoldensDir, breakers, transcriptsDir, repoRoot) {
|
|
13067
13108
|
return {
|
|
13068
13109
|
name: "bench",
|
|
13069
13110
|
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 +13123,6 @@ function benchTool(providers, allowlist, storage, bridge, moderator, defaultGold
|
|
|
13082
13123
|
allowlist,
|
|
13083
13124
|
moderator,
|
|
13084
13125
|
...storage ? { storage } : {},
|
|
13085
|
-
...bridge ? { bridge } : {},
|
|
13086
13126
|
...defaultGoldensDir ? { defaultGoldensDir } : {},
|
|
13087
13127
|
...breakers ? { breakers } : {},
|
|
13088
13128
|
...transcriptsDir ? { transcriptsDir } : {},
|
|
@@ -13109,7 +13149,7 @@ function updateCrosscheckTool(repoRoot) {
|
|
|
13109
13149
|
}
|
|
13110
13150
|
};
|
|
13111
13151
|
}
|
|
13112
|
-
function recommendPanelTool(providers, storage
|
|
13152
|
+
function recommendPanelTool(providers, storage) {
|
|
13113
13153
|
return {
|
|
13114
13154
|
name: "recommend_panel",
|
|
13115
13155
|
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 +13167,7 @@ function recommendPanelTool(providers, storage, bridge) {
|
|
|
13127
13167
|
},
|
|
13128
13168
|
handler: (args) => runRecommendPanel(args, {
|
|
13129
13169
|
providers,
|
|
13130
|
-
...storage ? { storage } : {}
|
|
13131
|
-
...bridge ? { bridge } : {}
|
|
13170
|
+
...storage ? { storage } : {}
|
|
13132
13171
|
})
|
|
13133
13172
|
};
|
|
13134
13173
|
}
|
|
@@ -13153,7 +13192,7 @@ function fetchTool(storage, fetchConfig, repoRoot) {
|
|
|
13153
13192
|
})
|
|
13154
13193
|
};
|
|
13155
13194
|
}
|
|
13156
|
-
function delegateTool(providers, allowlist, storage,
|
|
13195
|
+
function delegateTool(providers, allowlist, storage, moderator) {
|
|
13157
13196
|
return {
|
|
13158
13197
|
name: "delegate",
|
|
13159
13198
|
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 +13212,11 @@ function delegateTool(providers, allowlist, storage, bridge, moderator) {
|
|
|
13173
13212
|
providers,
|
|
13174
13213
|
allowlist,
|
|
13175
13214
|
moderator,
|
|
13176
|
-
...storage ? { storage } : {}
|
|
13177
|
-
...bridge ? { bridge } : {}
|
|
13215
|
+
...storage ? { storage } : {}
|
|
13178
13216
|
})
|
|
13179
13217
|
};
|
|
13180
13218
|
}
|
|
13181
|
-
function explainTool(storage,
|
|
13219
|
+
function explainTool(storage, transcriptsDir) {
|
|
13182
13220
|
return {
|
|
13183
13221
|
name: "explain",
|
|
13184
13222
|
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 +13234,11 @@ function explainTool(storage, bridge, transcriptsDir) {
|
|
|
13196
13234
|
},
|
|
13197
13235
|
handler: (args) => runExplain(args, {
|
|
13198
13236
|
...storage ? { storage } : {},
|
|
13199
|
-
...bridge ? { bridge } : {},
|
|
13200
13237
|
...transcriptsDir ? { transcriptsDir } : {}
|
|
13201
13238
|
})
|
|
13202
13239
|
};
|
|
13203
13240
|
}
|
|
13204
|
-
function scoreboardTool(storage,
|
|
13241
|
+
function scoreboardTool(storage, eventsPath) {
|
|
13205
13242
|
return {
|
|
13206
13243
|
name: "scoreboard",
|
|
13207
13244
|
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 +13252,11 @@ function scoreboardTool(storage, bridge, eventsPath) {
|
|
|
13215
13252
|
},
|
|
13216
13253
|
handler: (args) => runScoreboard(args, {
|
|
13217
13254
|
...storage ? { storage } : {},
|
|
13218
|
-
...bridge ? { bridge } : {},
|
|
13219
13255
|
...eventsPath ? { eventsPath } : {}
|
|
13220
13256
|
})
|
|
13221
13257
|
};
|
|
13222
13258
|
}
|
|
13223
|
-
function sessionMemoryTool(storage
|
|
13259
|
+
function sessionMemoryTool(storage) {
|
|
13224
13260
|
return {
|
|
13225
13261
|
name: "session_memory",
|
|
13226
13262
|
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 +13279,14 @@ function sessionMemoryTool(storage, bridge) {
|
|
|
13243
13279
|
required: ["action", "session_id"]
|
|
13244
13280
|
},
|
|
13245
13281
|
handler: (args) => runSessionMemory(args, {
|
|
13246
|
-
...storage ? { storage } : {}
|
|
13247
|
-
...bridge ? { bridge } : {}
|
|
13282
|
+
...storage ? { storage } : {}
|
|
13248
13283
|
})
|
|
13249
13284
|
};
|
|
13250
13285
|
}
|
|
13251
|
-
function recallTool(storage
|
|
13286
|
+
function recallTool(storage) {
|
|
13252
13287
|
return {
|
|
13253
13288
|
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
|
|
13289
|
+
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
13290
|
inputSchema: {
|
|
13256
13291
|
type: "object",
|
|
13257
13292
|
additionalProperties: true,
|
|
@@ -13265,8 +13300,7 @@ function recallTool(storage, bridge) {
|
|
|
13265
13300
|
required: ["query"]
|
|
13266
13301
|
},
|
|
13267
13302
|
handler: (args) => runRecall(args, {
|
|
13268
|
-
...storage ? { storage } : {}
|
|
13269
|
-
...bridge ? { bridge } : {}
|
|
13303
|
+
...storage ? { storage } : {}
|
|
13270
13304
|
})
|
|
13271
13305
|
};
|
|
13272
13306
|
}
|
|
@@ -13302,7 +13336,7 @@ function modelsTool(providers, activeProviders) {
|
|
|
13302
13336
|
handler: async (args) => runModels(args, { providers, activeProviders })
|
|
13303
13337
|
};
|
|
13304
13338
|
}
|
|
13305
|
-
function reviewTool(providers, allowlist,
|
|
13339
|
+
function reviewTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
|
|
13306
13340
|
return {
|
|
13307
13341
|
name: "review",
|
|
13308
13342
|
description: "Have an LLM panel peer-review a code or proposal snippet. Returns the confer envelope (one answer per provider).",
|
|
@@ -13321,7 +13355,6 @@ function reviewTool(providers, allowlist, bridge, storage, breakers, transcripts
|
|
|
13321
13355
|
handler: (args) => runReview(args, {
|
|
13322
13356
|
providers,
|
|
13323
13357
|
allowlist,
|
|
13324
|
-
...bridge ? { bridge } : {},
|
|
13325
13358
|
...storage ? { storage } : {},
|
|
13326
13359
|
...breakers ? { breakers } : {},
|
|
13327
13360
|
...transcriptsDir ? { transcriptsDir } : {},
|
|
@@ -13329,7 +13362,7 @@ function reviewTool(providers, allowlist, bridge, storage, breakers, transcripts
|
|
|
13329
13362
|
})
|
|
13330
13363
|
};
|
|
13331
13364
|
}
|
|
13332
|
-
function critiqueTool(providers, allowlist,
|
|
13365
|
+
function critiqueTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
|
|
13333
13366
|
return {
|
|
13334
13367
|
name: "critique",
|
|
13335
13368
|
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 +13382,6 @@ function critiqueTool(providers, allowlist, bridge, storage, breakers, transcrip
|
|
|
13349
13382
|
handler: (args) => runCritique(args, {
|
|
13350
13383
|
providers,
|
|
13351
13384
|
allowlist,
|
|
13352
|
-
...bridge ? { bridge } : {},
|
|
13353
13385
|
...storage ? { storage } : {},
|
|
13354
13386
|
...breakers ? { breakers } : {},
|
|
13355
13387
|
...transcriptsDir ? { transcriptsDir } : {},
|
|
@@ -13357,7 +13389,7 @@ function critiqueTool(providers, allowlist, bridge, storage, breakers, transcrip
|
|
|
13357
13389
|
})
|
|
13358
13390
|
};
|
|
13359
13391
|
}
|
|
13360
|
-
function planTool(providers, allowlist,
|
|
13392
|
+
function planTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
|
|
13361
13393
|
return {
|
|
13362
13394
|
name: "plan",
|
|
13363
13395
|
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 +13416,6 @@ function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDi
|
|
|
13384
13416
|
handler: (args) => runPlan(args, {
|
|
13385
13417
|
providers,
|
|
13386
13418
|
allowlist,
|
|
13387
|
-
...bridge ? { bridge } : {},
|
|
13388
13419
|
...storage ? { storage } : {},
|
|
13389
13420
|
...breakers ? { breakers } : {},
|
|
13390
13421
|
...transcriptsDir ? { transcriptsDir } : {},
|
|
@@ -13392,7 +13423,7 @@ function planTool(providers, allowlist, bridge, storage, breakers, transcriptsDi
|
|
|
13392
13423
|
})
|
|
13393
13424
|
};
|
|
13394
13425
|
}
|
|
13395
|
-
function triangulateTool(providers, allowlist,
|
|
13426
|
+
function triangulateTool(providers, allowlist, storage, breakers, transcriptsDir, repoRoot) {
|
|
13396
13427
|
return {
|
|
13397
13428
|
name: "triangulate",
|
|
13398
13429
|
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 +13444,6 @@ function triangulateTool(providers, allowlist, bridge, storage, breakers, transc
|
|
|
13413
13444
|
handler: (args) => runTriangulate(args, {
|
|
13414
13445
|
providers,
|
|
13415
13446
|
allowlist,
|
|
13416
|
-
...bridge ? { bridge } : {},
|
|
13417
13447
|
...storage ? { storage } : {},
|
|
13418
13448
|
...breakers ? { breakers } : {},
|
|
13419
13449
|
...transcriptsDir ? { transcriptsDir } : {},
|
|
@@ -13421,7 +13451,7 @@ function triangulateTool(providers, allowlist, bridge, storage, breakers, transc
|
|
|
13421
13451
|
})
|
|
13422
13452
|
};
|
|
13423
13453
|
}
|
|
13424
|
-
function coordinateTool(providers, allowlist,
|
|
13454
|
+
function coordinateTool(providers, allowlist, innerCallers, storage, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
|
|
13425
13455
|
return {
|
|
13426
13456
|
name: "coordinate",
|
|
13427
13457
|
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 +13476,6 @@ function coordinateTool(providers, allowlist, bridge, innerCallers, storage, bre
|
|
|
13446
13476
|
handler: (args) => runCoordinate(args, {
|
|
13447
13477
|
providers,
|
|
13448
13478
|
allowlist,
|
|
13449
|
-
...bridge ? { bridge } : {},
|
|
13450
13479
|
innerCallers,
|
|
13451
13480
|
...storage ? { storage } : {},
|
|
13452
13481
|
...breakers ? { breakers } : {},
|
|
@@ -13456,7 +13485,7 @@ function coordinateTool(providers, allowlist, bridge, innerCallers, storage, bre
|
|
|
13456
13485
|
})
|
|
13457
13486
|
};
|
|
13458
13487
|
}
|
|
13459
|
-
function debateTool(providers, allowlist,
|
|
13488
|
+
function debateTool(providers, allowlist, innerCallers, storage, pricing, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
|
|
13460
13489
|
return {
|
|
13461
13490
|
name: "debate",
|
|
13462
13491
|
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 +13515,6 @@ function debateTool(providers, allowlist, bridge, innerCallers, storage, pricing
|
|
|
13486
13515
|
handler: (args) => runDebate(args, {
|
|
13487
13516
|
providers,
|
|
13488
13517
|
allowlist,
|
|
13489
|
-
...bridge ? { bridge } : {},
|
|
13490
13518
|
innerCallers,
|
|
13491
13519
|
...storage ? { storage } : {},
|
|
13492
13520
|
...pricing ? { pricing } : {},
|
|
@@ -13506,10 +13534,10 @@ function buildInnerCallers(o) {
|
|
|
13506
13534
|
...o.repoRoot ? { repoRoot: o.repoRoot } : {}
|
|
13507
13535
|
});
|
|
13508
13536
|
}
|
|
13509
|
-
out.verify = (args) => runVerify(args, o.
|
|
13537
|
+
out.verify = (args) => runVerify(args, o.fetchConfig);
|
|
13510
13538
|
return out;
|
|
13511
13539
|
}
|
|
13512
|
-
function conferTool(providers, allowlist,
|
|
13540
|
+
function conferTool(providers, allowlist, moderator, pricing, storage, innerCallers, breakers, transcriptsDir, repoRoot, workerToolsCfg) {
|
|
13513
13541
|
return {
|
|
13514
13542
|
name: "confer",
|
|
13515
13543
|
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 +13564,6 @@ function conferTool(providers, allowlist, bridge, moderator, pricing, storage, i
|
|
|
13536
13564
|
handler: (args) => runConfer(args, {
|
|
13537
13565
|
providers,
|
|
13538
13566
|
allowlist,
|
|
13539
|
-
...bridge ? { bridge } : {},
|
|
13540
13567
|
moderator,
|
|
13541
13568
|
...pricing ? { pricing } : {},
|
|
13542
13569
|
...storage ? { storage } : {},
|
|
@@ -13548,7 +13575,7 @@ function conferTool(providers, allowlist, bridge, moderator, pricing, storage, i
|
|
|
13548
13575
|
})
|
|
13549
13576
|
};
|
|
13550
13577
|
}
|
|
13551
|
-
function auditTool(providers, allowlist,
|
|
13578
|
+
function auditTool(providers, allowlist, transcriptsDir, pricing, storage, breakers, repoRoot) {
|
|
13552
13579
|
return {
|
|
13553
13580
|
name: "audit",
|
|
13554
13581
|
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 +13601,6 @@ function auditTool(providers, allowlist, bridge, transcriptsDir, pricing, storag
|
|
|
13574
13601
|
handler: (args) => runAudit(args, {
|
|
13575
13602
|
providers,
|
|
13576
13603
|
allowlist,
|
|
13577
|
-
...bridge ? { bridge } : {},
|
|
13578
13604
|
...transcriptsDir ? { transcriptsDir } : {},
|
|
13579
13605
|
...pricing ? { pricing } : {},
|
|
13580
13606
|
...storage ? { storage } : {},
|
|
@@ -13638,7 +13664,7 @@ function pickTool(providers, allowlist, storage, breakers, transcriptsDir, repoR
|
|
|
13638
13664
|
})
|
|
13639
13665
|
};
|
|
13640
13666
|
}
|
|
13641
|
-
function verifyTool(
|
|
13667
|
+
function verifyTool(fetchConfig) {
|
|
13642
13668
|
return {
|
|
13643
13669
|
name: "verify",
|
|
13644
13670
|
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 +13682,7 @@ function verifyTool(bridge, fetchConfig) {
|
|
|
13656
13682
|
},
|
|
13657
13683
|
required: ["checks"]
|
|
13658
13684
|
},
|
|
13659
|
-
handler: (args) => runVerify(args,
|
|
13685
|
+
handler: (args) => runVerify(args, fetchConfig)
|
|
13660
13686
|
};
|
|
13661
13687
|
}
|
|
13662
13688
|
function pingTool() {
|
|
@@ -13706,7 +13732,7 @@ function createCrosscheck(opts) {
|
|
|
13706
13732
|
// Direct runConfer call with a streaming hook — bypasses the tool
|
|
13707
13733
|
// registry (whose handler signature can't carry a callback). Uses the
|
|
13708
13734
|
// same opts the registry wires for confer in a browser build: providers
|
|
13709
|
-
// + pricing + default moderator; storage/
|
|
13735
|
+
// + pricing + default moderator; storage/innerCallers aren't
|
|
13710
13736
|
// available here, matching the non-streaming path.
|
|
13711
13737
|
conferStream: (args, onAnswer) => runConfer(args, { providers, pricing: pricingDoc, moderator: "anthropic", onAnswer }),
|
|
13712
13738
|
debateStream: (args, { onTurn, onSynthesis } = {}) => runDebate(args, {
|