crosscheck-mcp 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/node-stdio.cjs +361 -16
- package/dist/node-stdio.cjs.map +1 -1
- package/dist/node-stdio.d.cts +14 -0
- package/dist/node-stdio.d.ts +14 -0
- package/dist/node-stdio.js +361 -16
- package/dist/node-stdio.js.map +1 -1
- package/dist/pricing.json +3 -1
- package/package.json +4 -8
package/dist/node-stdio.js
CHANGED
|
@@ -545,6 +545,22 @@ var init_better_sqlite3 = __esm({
|
|
|
545
545
|
ORDER BY purpose`
|
|
546
546
|
).all(sessionId);
|
|
547
547
|
}
|
|
548
|
+
async listUsageGroupedByModel(sessionId) {
|
|
549
|
+
return this.cached(
|
|
550
|
+
"usage-grp-model",
|
|
551
|
+
`SELECT provider,
|
|
552
|
+
model,
|
|
553
|
+
COUNT(*) AS calls,
|
|
554
|
+
COALESCE(SUM(prompt_tokens), 0) AS prompt_tokens,
|
|
555
|
+
COALESCE(SUM(completion_tokens), 0) AS completion_tokens,
|
|
556
|
+
COALESCE(SUM(total_tokens), 0) AS total_tokens,
|
|
557
|
+
COALESCE(SUM(cost_usd), 0) AS cost_usd
|
|
558
|
+
FROM usage_log
|
|
559
|
+
WHERE session_id = ?
|
|
560
|
+
GROUP BY provider, model
|
|
561
|
+
ORDER BY cost_usd DESC, provider, model`
|
|
562
|
+
).all(sessionId);
|
|
563
|
+
}
|
|
548
564
|
async listUsageGroupedByProvider(purpose) {
|
|
549
565
|
if (purpose !== void 0) {
|
|
550
566
|
return this.cached(
|
|
@@ -1052,7 +1068,8 @@ function modelPricing(pricing, provider, model) {
|
|
|
1052
1068
|
return {
|
|
1053
1069
|
prompt_per_1k: numberOrZero(e["prompt_per_1k"]),
|
|
1054
1070
|
completion_per_1k: numberOrZero(e["completion_per_1k"]),
|
|
1055
|
-
cached_per_1k: numberOrZero(e["cached_per_1k"])
|
|
1071
|
+
cached_per_1k: numberOrZero(e["cached_per_1k"]),
|
|
1072
|
+
...e["estimated"] === true ? { estimated: true } : {}
|
|
1056
1073
|
};
|
|
1057
1074
|
}
|
|
1058
1075
|
function numberOrZero(v) {
|
|
@@ -1072,7 +1089,7 @@ function calculateCost(pricing, provider, model, promptTokens, completionTokens,
|
|
|
1072
1089
|
const prompt = Math.max(0, Math.trunc(promptTokens) - cached);
|
|
1073
1090
|
const completion = Math.max(0, Math.trunc(completionTokens));
|
|
1074
1091
|
const raw = prompt / 1e3 * rates.prompt_per_1k + completion / 1e3 * rates.completion_per_1k + cached / 1e3 * rates.cached_per_1k;
|
|
1075
|
-
return { cost_usd: roundTo(raw, 8), estimated:
|
|
1092
|
+
return { cost_usd: roundTo(raw, 8), estimated: rates.estimated === true };
|
|
1076
1093
|
}
|
|
1077
1094
|
function roundTo(x, n) {
|
|
1078
1095
|
if (!Number.isFinite(x)) return 0;
|
|
@@ -1092,7 +1109,7 @@ var PROVIDER_CAPS = {
|
|
|
1092
1109
|
family: "anthropic",
|
|
1093
1110
|
system_role: "separate",
|
|
1094
1111
|
supports_temperature: "model",
|
|
1095
|
-
reasoning_prefixes: ["claude-opus-4-7", "claude-opus-4-8"]
|
|
1112
|
+
reasoning_prefixes: ["claude-opus-4-7", "claude-opus-4-8", "claude-fable-5"]
|
|
1096
1113
|
},
|
|
1097
1114
|
openai: {
|
|
1098
1115
|
family: "openai_chat",
|
|
@@ -2044,7 +2061,17 @@ Examples:
|
|
|
2044
2061
|
- \`xc what's the right caching strategy here?\` \u2192 \`mcp__crosscheck__${DEFAULT_TOOL}({ question: "what's the right caching strategy here?" })\` (no tool name match \u2192 default to ${DEFAULT_TOOL})
|
|
2045
2062
|
- \`XC how risky is this refactor?\` \u2192 same default-to-${DEFAULT_TOOL} behavior
|
|
2046
2063
|
|
|
2047
|
-
This convention is opt-in: a user message without the \`xc\`/\`XC\` prefix should NOT be auto-routed here. Pick tools normally based on the conversation
|
|
2064
|
+
This convention is opt-in: a user message without the \`xc\`/\`XC\` prefix should NOT be auto-routed here. Pick tools normally based on the conversation.
|
|
2065
|
+
|
|
2066
|
+
Reasoning upgrade (Fable 5):
|
|
2067
|
+
- The reasoning tools (plan, solve, debate, orchestrate, audit, triangulate) can bump their lead reasoning seat to Fable 5 \u2014 Anthropic's newest thinking model \u2014 instead of the default Opus 4.8. Only that one seat is upgraded; other panel seats stay on their normal models, so premium tokens are not wasted.
|
|
2068
|
+
- When a tool result includes a "suggested_upgrade" block, the engine judged the task reasoning-heavy. Surface it: ask the user something like "This looks reasoning-heavy \u2014 bump the lead seat to Fable 5 (higher quality, higher cost)?" If they say yes, re-run the SAME tool with reasoning:"max" added. Do NOT upgrade silently.
|
|
2069
|
+
- If the user explicitly asks for the best/deepest reasoning up front, pass reasoning:"max" directly. A result with reasoning_upgrade.applied = true confirms Fable 5 was used.
|
|
2070
|
+
|
|
2071
|
+
Spend visibility:
|
|
2072
|
+
- Every reasoning-tool result carries a "run_summary" whose pre-rendered "text" block already includes a "spend by model (this call)" breakdown. Show that block \u2014 do not bury the cost.
|
|
2073
|
+
- "run_summary" also carries "session_by_model" + "session_cost_usd" (per-model spend for the whole session). At the END of a multi-turn task, present the session spend per model plus the aggregate total, so the user knows what the task cost without scrolling back.
|
|
2074
|
+
- Fable 5's price is a provisional placeholder; rows from it are flagged "(est)"/estimated \u2014 say so when reporting those dollar figures.`;
|
|
2048
2075
|
}
|
|
2049
2076
|
|
|
2050
2077
|
// src/tools/index.ts
|
|
@@ -2300,6 +2327,7 @@ function roundCost(x) {
|
|
|
2300
2327
|
function aggregateUsage(usages) {
|
|
2301
2328
|
const byCall = usages.map((u) => ({ ...u }));
|
|
2302
2329
|
const byProvider = /* @__PURE__ */ new Map();
|
|
2330
|
+
const byModel = /* @__PURE__ */ new Map();
|
|
2303
2331
|
let totalPrompt = 0;
|
|
2304
2332
|
let totalCompletion = 0;
|
|
2305
2333
|
let totalCached = 0;
|
|
@@ -2327,6 +2355,29 @@ function aggregateUsage(usages) {
|
|
|
2327
2355
|
bp.cost_usd = roundCost(bp.cost_usd + u.cost_usd);
|
|
2328
2356
|
bp.calls += 1;
|
|
2329
2357
|
bp.estimated = bp.estimated || u.estimated;
|
|
2358
|
+
const modelKey = `${u.provider}/${u.model}`;
|
|
2359
|
+
let bm = byModel.get(modelKey);
|
|
2360
|
+
if (!bm) {
|
|
2361
|
+
bm = {
|
|
2362
|
+
provider: u.provider,
|
|
2363
|
+
model: u.model,
|
|
2364
|
+
prompt_tokens: 0,
|
|
2365
|
+
completion_tokens: 0,
|
|
2366
|
+
cached_tokens: 0,
|
|
2367
|
+
total_tokens: 0,
|
|
2368
|
+
cost_usd: 0,
|
|
2369
|
+
calls: 0,
|
|
2370
|
+
estimated: false
|
|
2371
|
+
};
|
|
2372
|
+
byModel.set(modelKey, bm);
|
|
2373
|
+
}
|
|
2374
|
+
bm.prompt_tokens += u.prompt_tokens;
|
|
2375
|
+
bm.completion_tokens += u.completion_tokens;
|
|
2376
|
+
bm.cached_tokens += u.cached_tokens;
|
|
2377
|
+
bm.total_tokens += u.total_tokens;
|
|
2378
|
+
bm.cost_usd = roundCost(bm.cost_usd + u.cost_usd);
|
|
2379
|
+
bm.calls += 1;
|
|
2380
|
+
bm.estimated = bm.estimated || u.estimated;
|
|
2330
2381
|
totalPrompt += u.prompt_tokens;
|
|
2331
2382
|
totalCompletion += u.completion_tokens;
|
|
2332
2383
|
totalCached += u.cached_tokens;
|
|
@@ -2336,6 +2387,7 @@ function aggregateUsage(usages) {
|
|
|
2336
2387
|
return {
|
|
2337
2388
|
by_call: byCall,
|
|
2338
2389
|
by_provider: Array.from(byProvider.values()),
|
|
2390
|
+
by_model: Array.from(byModel.values()),
|
|
2339
2391
|
totals: {
|
|
2340
2392
|
prompt_tokens: totalPrompt,
|
|
2341
2393
|
completion_tokens: totalCompletion,
|
|
@@ -2418,7 +2470,46 @@ function renderRunSummary(opts) {
|
|
|
2418
2470
|
`${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)`
|
|
2419
2471
|
);
|
|
2420
2472
|
}
|
|
2421
|
-
const
|
|
2473
|
+
const callByModel = rollupSpendByModel(
|
|
2474
|
+
opts.answers.map((a) => ({
|
|
2475
|
+
provider: a.usage?.provider ?? "",
|
|
2476
|
+
model: a.usage?.model ?? "",
|
|
2477
|
+
calls: 1,
|
|
2478
|
+
total_tokens: a.usage?.total_tokens ?? 0,
|
|
2479
|
+
cost_usd: a.usage?.cost_usd ?? 0,
|
|
2480
|
+
estimated: a.usage?.estimated ?? false
|
|
2481
|
+
})).filter((r) => r.provider !== "")
|
|
2482
|
+
);
|
|
2483
|
+
let sessionByModel;
|
|
2484
|
+
let sessionCost;
|
|
2485
|
+
if (opts.sessionModelRows && opts.sessionModelRows.length > 0) {
|
|
2486
|
+
sessionByModel = rollupSpendByModel(
|
|
2487
|
+
opts.sessionModelRows.map((r) => ({
|
|
2488
|
+
provider: r.provider,
|
|
2489
|
+
model: r.model,
|
|
2490
|
+
calls: r.calls,
|
|
2491
|
+
total_tokens: r.total_tokens,
|
|
2492
|
+
cost_usd: r.cost_usd,
|
|
2493
|
+
// Derive estimated from the pricing doc (SQL rows don't carry it).
|
|
2494
|
+
estimated: opts.pricing ? modelPricing(opts.pricing, r.provider, r.model)?.estimated === true : false
|
|
2495
|
+
}))
|
|
2496
|
+
);
|
|
2497
|
+
sessionCost = round8(sessionByModel.reduce((s, r) => s + r.cost_usd, 0));
|
|
2498
|
+
}
|
|
2499
|
+
const lines = [header, ...bodyLines];
|
|
2500
|
+
if (callByModel.length > 0) {
|
|
2501
|
+
lines.push("spend by model (this call):");
|
|
2502
|
+
lines.push(...renderSpendByModelLines(callByModel));
|
|
2503
|
+
}
|
|
2504
|
+
if (sessionByModel && sessionByModel.length > 0 && sessionCost !== void 0) {
|
|
2505
|
+
lines.push(
|
|
2506
|
+
`session so far \u2014 spend by model (${withCommas(
|
|
2507
|
+
sessionByModel.reduce((s, r) => s + r.total_tokens, 0)
|
|
2508
|
+
)} tokens, $${sessionCost.toFixed(4)}${sessionByModel.some((r) => r.estimated) ? " \xB7 includes estimated rates" : ""}):`
|
|
2509
|
+
);
|
|
2510
|
+
lines.push(...renderSpendByModelLines(sessionByModel));
|
|
2511
|
+
}
|
|
2512
|
+
const text = lines.join("\n");
|
|
2422
2513
|
return {
|
|
2423
2514
|
session_id: opts.sessionId,
|
|
2424
2515
|
tool: opts.toolName,
|
|
@@ -2428,9 +2519,47 @@ function renderRunSummary(opts) {
|
|
|
2428
2519
|
ended_at: endedAt,
|
|
2429
2520
|
rows,
|
|
2430
2521
|
totals,
|
|
2522
|
+
call_by_model: callByModel,
|
|
2523
|
+
...sessionByModel ? { session_by_model: sessionByModel } : {},
|
|
2524
|
+
...sessionCost !== void 0 ? { session_cost_usd: sessionCost } : {},
|
|
2431
2525
|
text
|
|
2432
2526
|
};
|
|
2433
2527
|
}
|
|
2528
|
+
function rollupSpendByModel(frags) {
|
|
2529
|
+
const m = /* @__PURE__ */ new Map();
|
|
2530
|
+
for (const f of frags) {
|
|
2531
|
+
const key = `${f.provider}/${f.model}`;
|
|
2532
|
+
let row = m.get(key);
|
|
2533
|
+
if (!row) {
|
|
2534
|
+
row = {
|
|
2535
|
+
provider: f.provider,
|
|
2536
|
+
model: f.model,
|
|
2537
|
+
calls: 0,
|
|
2538
|
+
total_tokens: 0,
|
|
2539
|
+
cost_usd: 0,
|
|
2540
|
+
estimated: false
|
|
2541
|
+
};
|
|
2542
|
+
m.set(key, row);
|
|
2543
|
+
}
|
|
2544
|
+
row.calls += f.calls;
|
|
2545
|
+
row.total_tokens += f.total_tokens;
|
|
2546
|
+
row.cost_usd = round8(row.cost_usd + f.cost_usd);
|
|
2547
|
+
row.estimated = row.estimated || f.estimated;
|
|
2548
|
+
}
|
|
2549
|
+
return Array.from(m.values()).sort(
|
|
2550
|
+
(a, b) => b.cost_usd - a.cost_usd || a.provider.localeCompare(b.provider)
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
function renderSpendByModelLines(rows) {
|
|
2554
|
+
const nameW = Math.max(...rows.map((r) => `${r.provider}/${r.model}`.length), 0);
|
|
2555
|
+
return rows.map((r) => {
|
|
2556
|
+
const name = `${r.provider}/${r.model}`.padEnd(nameW);
|
|
2557
|
+
const calls = `${r.calls} call${r.calls === 1 ? "" : "s"}`.padStart(8);
|
|
2558
|
+
const toks = `${withCommas(r.total_tokens)} tok`.padStart(13);
|
|
2559
|
+
const cost = `$${r.cost_usd.toFixed(4)}`.padStart(10);
|
|
2560
|
+
return ` ${name} ${calls} ${toks} ${cost}${r.estimated ? " (est)" : ""}`;
|
|
2561
|
+
});
|
|
2562
|
+
}
|
|
2434
2563
|
async function attachUsageBlock(result, answers, opts) {
|
|
2435
2564
|
const allCalls = [...answers, ...opts?.extras ?? []];
|
|
2436
2565
|
const usages = [];
|
|
@@ -2466,7 +2595,12 @@ async function attachUsageBlock(result, answers, opts) {
|
|
|
2466
2595
|
result["timing"] = timing;
|
|
2467
2596
|
if (opts?.toolName && !result["_suppress_run_summary"]) {
|
|
2468
2597
|
let sessionScope;
|
|
2598
|
+
let sessionModelRows;
|
|
2469
2599
|
if (opts.storage && opts.sessionId) {
|
|
2600
|
+
try {
|
|
2601
|
+
sessionModelRows = await opts.storage.listUsageGroupedByModel(opts.sessionId);
|
|
2602
|
+
} catch {
|
|
2603
|
+
}
|
|
2470
2604
|
try {
|
|
2471
2605
|
const rows = await opts.storage.listUsageGroupedByPurpose(opts.sessionId);
|
|
2472
2606
|
if (rows.length > 0) {
|
|
@@ -2496,6 +2630,8 @@ async function attachUsageBlock(result, answers, opts) {
|
|
|
2496
2630
|
toolName: opts.toolName,
|
|
2497
2631
|
answers: allCalls,
|
|
2498
2632
|
...sessionScope ? { sessionScope } : {},
|
|
2633
|
+
...sessionModelRows && sessionModelRows.length > 0 ? { sessionModelRows } : {},
|
|
2634
|
+
...opts.pricing ? { pricing: opts.pricing } : {},
|
|
2499
2635
|
...opts.endedAtS !== void 0 ? { endedAtS: opts.endedAtS } : {}
|
|
2500
2636
|
});
|
|
2501
2637
|
}
|
|
@@ -3561,6 +3697,83 @@ function selectForDifficulty(args) {
|
|
|
3561
3697
|
};
|
|
3562
3698
|
}
|
|
3563
3699
|
|
|
3700
|
+
// src/core/reasoning-upgrade.ts
|
|
3701
|
+
init_esm_shims();
|
|
3702
|
+
var UPGRADE_MODEL = "claude-fable-5";
|
|
3703
|
+
var UPGRADE_LABEL = "Fable 5";
|
|
3704
|
+
function isUpgradeRequested(args) {
|
|
3705
|
+
if (args["upgrade"] === true) return true;
|
|
3706
|
+
const reasoning = args["reasoning"];
|
|
3707
|
+
if (typeof reasoning === "string" && reasoning.trim().toLowerCase() === "max") {
|
|
3708
|
+
return true;
|
|
3709
|
+
}
|
|
3710
|
+
const model = args["model"];
|
|
3711
|
+
if (typeof model === "string") {
|
|
3712
|
+
const m = model.trim().toLowerCase();
|
|
3713
|
+
if (m === "fable5" || m === "fable-5" || m === "fable" || m === UPGRADE_MODEL) {
|
|
3714
|
+
return true;
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
return false;
|
|
3718
|
+
}
|
|
3719
|
+
var HEAVY_TERMS = [
|
|
3720
|
+
/\bprov(e|ing|en)\b|\bproof\b|\btheorem\b|\bderiv(e|ation)\b/i,
|
|
3721
|
+
/\barchitect(ure|ing)?\b|\bdesign\s+(a|the|an)\b|\bhigh[-\s]?level\s+design\b/i,
|
|
3722
|
+
/\btrade[-\s]?offs?\b|\bpros?\s+and\s+cons?\b|\bweigh\b/i,
|
|
3723
|
+
/\boptimi[sz]e\b|\bcomplexity\b|\bO\(|\balgorithm(ic)?\b/i,
|
|
3724
|
+
/\brace\s+condition\b|\bconcurren(t|cy)\b|\bdeadlock\b|\bdistributed\b|\bconsensus\b/i,
|
|
3725
|
+
/\broot[-\s]?cause\b|\bdebug(ging)?\b|\bwhy\s+(does|is|would|might)\b/i,
|
|
3726
|
+
/\bsecurity\b|\bthreat\s+model\b|\bexploit\b|\bvulnerabilit(y|ies)\b/i,
|
|
3727
|
+
/\bmigrat(e|ion)\b|\brefactor\b|\bre[-\s]?architect\b/i,
|
|
3728
|
+
/\binvariant\b|\bcorrectness\b|\bedge\s+cases?\b|\bformal(ly)?\b/i,
|
|
3729
|
+
/\bstrateg(y|ic|ies)\b|\bplan\s+(the|a|an|out)\b|\broadmap\b/i,
|
|
3730
|
+
/\breason\s+(through|about)\b|\bstep[-\s]?by[-\s]?step\b|\bthink\s+deeply\b/i,
|
|
3731
|
+
/\bnp[-\s]?(hard|complete)\b|\bgraph\b|\bstate\s+machine\b|\bconstraint\b/i
|
|
3732
|
+
];
|
|
3733
|
+
var DIFFICULTY_TERMS = /\b(hard|tricky|subtle|complex|complicated|non[-\s]?trivial|thorny|gnarly|difficult|deep)\b/i;
|
|
3734
|
+
function assessReasoning(text) {
|
|
3735
|
+
const s = typeof text === "string" ? text : "";
|
|
3736
|
+
const signals = [];
|
|
3737
|
+
let score = 0;
|
|
3738
|
+
let termHits = 0;
|
|
3739
|
+
for (const re of HEAVY_TERMS) {
|
|
3740
|
+
if (re.test(s)) termHits += 1;
|
|
3741
|
+
}
|
|
3742
|
+
if (termHits > 0) {
|
|
3743
|
+
const add = Math.min(termHits, 4);
|
|
3744
|
+
score += add;
|
|
3745
|
+
signals.push(`${termHits} reasoning cue${termHits === 1 ? "" : "s"}`);
|
|
3746
|
+
}
|
|
3747
|
+
if (DIFFICULTY_TERMS.test(s)) {
|
|
3748
|
+
score += 1;
|
|
3749
|
+
signals.push("explicit difficulty marker");
|
|
3750
|
+
}
|
|
3751
|
+
const words = s.split(/\s+/).filter(Boolean).length;
|
|
3752
|
+
if (words >= 120) {
|
|
3753
|
+
score += 2;
|
|
3754
|
+
signals.push("long, detailed prompt");
|
|
3755
|
+
} else if (words >= 50) {
|
|
3756
|
+
score += 1;
|
|
3757
|
+
signals.push("substantial prompt");
|
|
3758
|
+
}
|
|
3759
|
+
const constraints = (s.match(/\b(must|should|need to|ensure|require[ds]?|constraint)\b/gi) ?? []).length + (s.match(/(^|\n)\s*(?:[-*]|\d+[.)])\s+/g) ?? []).length;
|
|
3760
|
+
if (constraints >= 3) {
|
|
3761
|
+
score += 1;
|
|
3762
|
+
signals.push(`${constraints} constraints/steps`);
|
|
3763
|
+
}
|
|
3764
|
+
const heavy = score >= 3;
|
|
3765
|
+
const reason = heavy ? `Task looks reasoning-heavy (${signals.join(", ") || "score " + score}).` : `Task looks routine (score ${score}).`;
|
|
3766
|
+
return { heavy, score, reason, signals };
|
|
3767
|
+
}
|
|
3768
|
+
function buildSuggestedUpgrade(toolName, assessment) {
|
|
3769
|
+
return {
|
|
3770
|
+
model: UPGRADE_MODEL,
|
|
3771
|
+
label: UPGRADE_LABEL,
|
|
3772
|
+
reason: assessment.reason,
|
|
3773
|
+
how: `re-run \`${toolName}\` with reasoning:"max" (or upgrade:true) to route the lead reasoning seat to ${UPGRADE_LABEL}. Other panel seats stay on their normal models, so only the high-level reasoning uses the premium model.`
|
|
3774
|
+
};
|
|
3775
|
+
}
|
|
3776
|
+
|
|
3564
3777
|
// src/tools/audit.ts
|
|
3565
3778
|
var AUDIT_OBVIOUS_FAILURE_HIGH = 0.3;
|
|
3566
3779
|
var AUDIT_OBVIOUS_FAILURE_MED = 0.2;
|
|
@@ -3827,7 +4040,10 @@ ${rubricText}`;
|
|
|
3827
4040
|
"Set ANTHROPIC_API_KEY or another provider in .env, or set `allow_self_audit=true` to permit the producing panel to self-grade."
|
|
3828
4041
|
);
|
|
3829
4042
|
}
|
|
3830
|
-
const
|
|
4043
|
+
const upgradeRequested = isUpgradeRequested(args);
|
|
4044
|
+
const upgraded = upgradeRequested && opts.providers["anthropic"] !== void 0;
|
|
4045
|
+
const auditorForCall = upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : auditor;
|
|
4046
|
+
const r = await requestStructured(auditorForCall, msgs, AUDIT_RUBRIC_SCHEMA, {
|
|
3831
4047
|
maxTokens: 2048,
|
|
3832
4048
|
maxRetries: 1,
|
|
3833
4049
|
purpose: "audit"
|
|
@@ -3869,7 +4085,7 @@ ${rubricText}`;
|
|
|
3869
4085
|
tool: "audit",
|
|
3870
4086
|
mode: "single",
|
|
3871
4087
|
strict_mode: strictMode,
|
|
3872
|
-
auditor: { provider:
|
|
4088
|
+
auditor: { provider: auditorForCall.name, model: auditorForCall.model },
|
|
3873
4089
|
rubric: rubricItems,
|
|
3874
4090
|
items: itemsWithMeta,
|
|
3875
4091
|
overall_score: overall,
|
|
@@ -3877,6 +4093,26 @@ ${rubricText}`;
|
|
|
3877
4093
|
};
|
|
3878
4094
|
if (persona.meta.used !== null) result["persona"] = persona.meta;
|
|
3879
4095
|
if (errs.length > 0) result["validation_errors"] = errs;
|
|
4096
|
+
if (upgraded) {
|
|
4097
|
+
result["reasoning_upgrade"] = {
|
|
4098
|
+
applied: true,
|
|
4099
|
+
model: UPGRADE_MODEL,
|
|
4100
|
+
label: UPGRADE_LABEL,
|
|
4101
|
+
seat: "auditor"
|
|
4102
|
+
};
|
|
4103
|
+
} else if (upgradeRequested) {
|
|
4104
|
+
result["reasoning_upgrade"] = {
|
|
4105
|
+
applied: false,
|
|
4106
|
+
reason: `no Anthropic key available \u2014 the ${UPGRADE_LABEL} upgrade needs it.`
|
|
4107
|
+
};
|
|
4108
|
+
} else {
|
|
4109
|
+
const assessment = assessReasoning(
|
|
4110
|
+
typeof outputToAudit === "string" ? outputToAudit : String(outputToAudit ?? "")
|
|
4111
|
+
);
|
|
4112
|
+
if (assessment.heavy && opts.providers["anthropic"]) {
|
|
4113
|
+
result["suggested_upgrade"] = buildSuggestedUpgrade("audit", assessment);
|
|
4114
|
+
}
|
|
4115
|
+
}
|
|
3880
4116
|
if (!allPass && opts.storage && typeof sessionId === "string" && sessionId) {
|
|
3881
4117
|
const marked = await markStaleOnAuditFailure(
|
|
3882
4118
|
opts.storage,
|
|
@@ -7546,7 +7782,12 @@ ${recombineSys}` : recombineSys },
|
|
|
7546
7782
|
];
|
|
7547
7783
|
let synthProvider = moderator;
|
|
7548
7784
|
let synthModel = null;
|
|
7549
|
-
|
|
7785
|
+
const upgradeRequested = isUpgradeRequested(args);
|
|
7786
|
+
const upgraded = upgradeRequested && opts.providers["anthropic"] !== void 0;
|
|
7787
|
+
if (upgraded) {
|
|
7788
|
+
synthProvider = retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL);
|
|
7789
|
+
synthModel = `anthropic/${UPGRADE_MODEL}`;
|
|
7790
|
+
} else if (cheapMode && opts.pricing) {
|
|
7550
7791
|
const pick = selectForDifficulty({
|
|
7551
7792
|
pricing: opts.pricing,
|
|
7552
7793
|
tier: "med",
|
|
@@ -7617,6 +7858,24 @@ ${recombineSys}` : recombineSys },
|
|
|
7617
7858
|
if (personaMeta.used !== null) result["persona"] = personaMeta;
|
|
7618
7859
|
if (synthModel) result["synth_model"] = synthModel;
|
|
7619
7860
|
if (synthErr) result["synth_error"] = synthErr;
|
|
7861
|
+
if (upgraded) {
|
|
7862
|
+
result["reasoning_upgrade"] = {
|
|
7863
|
+
applied: true,
|
|
7864
|
+
model: UPGRADE_MODEL,
|
|
7865
|
+
label: UPGRADE_LABEL,
|
|
7866
|
+
seat: "recombine/synthesis"
|
|
7867
|
+
};
|
|
7868
|
+
} else if (upgradeRequested) {
|
|
7869
|
+
result["reasoning_upgrade"] = {
|
|
7870
|
+
applied: false,
|
|
7871
|
+
reason: `no Anthropic key available \u2014 the ${UPGRADE_LABEL} upgrade needs it.`
|
|
7872
|
+
};
|
|
7873
|
+
} else if (goal) {
|
|
7874
|
+
const assessment = assessReasoning(goal);
|
|
7875
|
+
if (assessment.heavy && opts.providers["anthropic"]) {
|
|
7876
|
+
result["suggested_upgrade"] = buildSuggestedUpgrade("orchestrate", assessment);
|
|
7877
|
+
}
|
|
7878
|
+
}
|
|
7620
7879
|
if (plannerErrors.length > 0) result["planner_errors"] = plannerErrors;
|
|
7621
7880
|
if (unknownNames.length > 0) result["skipped_unknown_providers"] = unknownNames;
|
|
7622
7881
|
if (blocked.length > 0) result["blocked_by_allowlist"] = blocked;
|
|
@@ -8788,6 +9047,9 @@ async function runCoordinate(args, opts) {
|
|
|
8788
9047
|
const synthName = typeof args["synthesizer"] === "string" && args["synthesizer"] ? args["synthesizer"] : typeof args["moderator"] === "string" && args["moderator"] ? args["moderator"] : opts.moderator ?? "anthropic";
|
|
8789
9048
|
const proposer = opts.providers[proposerName.toLowerCase()] ?? selected[0];
|
|
8790
9049
|
const synth = opts.providers[synthName.toLowerCase()] ?? proposer;
|
|
9050
|
+
const upgradeRequested = isUpgradeRequested(args);
|
|
9051
|
+
const upgraded = upgradeRequested && opts.providers["anthropic"] !== void 0;
|
|
9052
|
+
const synthForCall = upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : synth;
|
|
8791
9053
|
let critics = [];
|
|
8792
9054
|
if (Array.isArray(args["critics"])) {
|
|
8793
9055
|
for (const n of args["critics"]) {
|
|
@@ -8936,7 +9198,7 @@ ${critiqueBlock}`
|
|
|
8936
9198
|
}
|
|
8937
9199
|
];
|
|
8938
9200
|
const synthResult = await requestStructured(
|
|
8939
|
-
|
|
9201
|
+
synthForCall,
|
|
8940
9202
|
synthMessages,
|
|
8941
9203
|
STRUCTURED_SYNTHESIS_SCHEMA,
|
|
8942
9204
|
{ maxTokens, maxRetries: 1, purpose: "synth" }
|
|
@@ -8985,6 +9247,24 @@ ${critiqueBlock}`
|
|
|
8985
9247
|
}
|
|
8986
9248
|
if (unknownNames.length > 0) result["skipped_unknown_providers"] = unknownNames;
|
|
8987
9249
|
if (blocked.length > 0) result["blocked_by_allowlist"] = blocked;
|
|
9250
|
+
if (upgraded) {
|
|
9251
|
+
result["reasoning_upgrade"] = {
|
|
9252
|
+
applied: true,
|
|
9253
|
+
model: UPGRADE_MODEL,
|
|
9254
|
+
label: UPGRADE_LABEL,
|
|
9255
|
+
seat: "synthesizer"
|
|
9256
|
+
};
|
|
9257
|
+
} else if (upgradeRequested) {
|
|
9258
|
+
result["reasoning_upgrade"] = {
|
|
9259
|
+
applied: false,
|
|
9260
|
+
reason: `no Anthropic key available \u2014 the ${UPGRADE_LABEL} upgrade needs it.`
|
|
9261
|
+
};
|
|
9262
|
+
} else {
|
|
9263
|
+
const assessment = assessReasoning(topic);
|
|
9264
|
+
if (assessment.heavy && opts.providers["anthropic"]) {
|
|
9265
|
+
result["suggested_upgrade"] = buildSuggestedUpgrade("coordinate", assessment);
|
|
9266
|
+
}
|
|
9267
|
+
}
|
|
8988
9268
|
const allCallEnvelopes = [
|
|
8989
9269
|
scannedProposal,
|
|
8990
9270
|
...scannedCritiques,
|
|
@@ -9525,6 +9805,8 @@ async function runDebate(args, opts) {
|
|
|
9525
9805
|
let agreementBlock = null;
|
|
9526
9806
|
const moderatorName = typeof args["moderator"] === "string" && args["moderator"] ? args["moderator"] : opts.moderator ?? "anthropic";
|
|
9527
9807
|
const moderator = opts.providers[moderatorName.toLowerCase()] ?? selected[0];
|
|
9808
|
+
const upgradeRequested = isUpgradeRequested(args);
|
|
9809
|
+
const upgraded = upgradeRequested && opts.providers["anthropic"] !== void 0;
|
|
9528
9810
|
for (let rnd = 1; rnd <= maxRounds; rnd++) {
|
|
9529
9811
|
const roundMessages = [
|
|
9530
9812
|
{
|
|
@@ -9586,6 +9868,7 @@ ${prior}` });
|
|
|
9586
9868
|
let synthesisErrors = [];
|
|
9587
9869
|
let personaMeta = null;
|
|
9588
9870
|
if (moderator) {
|
|
9871
|
+
const synthProvider = upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : moderator;
|
|
9589
9872
|
const condensed = transcript.map(
|
|
9590
9873
|
(e) => `[${e.provider} \u2014 round ${e.round}]
|
|
9591
9874
|
${e.response ?? "(error)"}`
|
|
@@ -9616,7 +9899,7 @@ ${condensed}`
|
|
|
9616
9899
|
];
|
|
9617
9900
|
if (structuredOpt) {
|
|
9618
9901
|
const r = await requestStructured(
|
|
9619
|
-
|
|
9902
|
+
synthProvider,
|
|
9620
9903
|
synthMessages,
|
|
9621
9904
|
STRUCTURED_SYNTHESIS_SCHEMA,
|
|
9622
9905
|
{ maxTokens, maxRetries: 1, purpose: "synth" }
|
|
@@ -9625,7 +9908,7 @@ ${condensed}`
|
|
|
9625
9908
|
synthesisStructured = r.obj;
|
|
9626
9909
|
synthesisErrors = r.errors;
|
|
9627
9910
|
} else {
|
|
9628
|
-
synthesis = await askOne(
|
|
9911
|
+
synthesis = await askOne(synthProvider, synthMessages, {
|
|
9629
9912
|
maxTokens,
|
|
9630
9913
|
temperature: 0.4,
|
|
9631
9914
|
purpose: "synth"
|
|
@@ -9657,6 +9940,24 @@ ${condensed}`
|
|
|
9657
9940
|
synthesis
|
|
9658
9941
|
};
|
|
9659
9942
|
if (personaMeta && personaMeta.used !== null) result["persona"] = personaMeta;
|
|
9943
|
+
if (upgraded) {
|
|
9944
|
+
result["reasoning_upgrade"] = {
|
|
9945
|
+
applied: true,
|
|
9946
|
+
model: UPGRADE_MODEL,
|
|
9947
|
+
label: UPGRADE_LABEL,
|
|
9948
|
+
seat: "moderator synthesis"
|
|
9949
|
+
};
|
|
9950
|
+
} else if (upgradeRequested) {
|
|
9951
|
+
result["reasoning_upgrade"] = {
|
|
9952
|
+
applied: false,
|
|
9953
|
+
reason: `no Anthropic key available \u2014 the ${UPGRADE_LABEL} upgrade needs it.`
|
|
9954
|
+
};
|
|
9955
|
+
} else {
|
|
9956
|
+
const assessment = assessReasoning(topic);
|
|
9957
|
+
if (assessment.heavy && opts.providers["anthropic"]) {
|
|
9958
|
+
result["suggested_upgrade"] = buildSuggestedUpgrade("debate", assessment);
|
|
9959
|
+
}
|
|
9960
|
+
}
|
|
9660
9961
|
if (synthesisStructured !== null) {
|
|
9661
9962
|
result["synthesis_structured"] = synthesisStructured;
|
|
9662
9963
|
}
|
|
@@ -10728,7 +11029,15 @@ Return: (1) the plan as numbered steps, (2) risks, (3) alternatives considered.`
|
|
|
10728
11029
|
if (args["providers"] !== void 0) debateArgs["providers"] = args["providers"];
|
|
10729
11030
|
if (args["moderator"] !== void 0) debateArgs["moderator"] = args["moderator"];
|
|
10730
11031
|
if (args["session_id"] !== void 0) debateArgs["session_id"] = args["session_id"];
|
|
10731
|
-
|
|
11032
|
+
if (args["reasoning"] !== void 0) debateArgs["reasoning"] = args["reasoning"];
|
|
11033
|
+
if (args["upgrade"] !== void 0) debateArgs["upgrade"] = args["upgrade"];
|
|
11034
|
+
if (args["model"] !== void 0) debateArgs["model"] = args["model"];
|
|
11035
|
+
const result = await runDebate(debateArgs, opts);
|
|
11036
|
+
if (result["suggested_upgrade"] && typeof result["suggested_upgrade"] === "object") {
|
|
11037
|
+
const su = result["suggested_upgrade"];
|
|
11038
|
+
su["how"] = `re-run \`plan\` with reasoning:"max" (or upgrade:true) to route the plan-synthesis seat to Fable 5. The debaters stay on their normal models.`;
|
|
11039
|
+
}
|
|
11040
|
+
return result;
|
|
10732
11041
|
}
|
|
10733
11042
|
|
|
10734
11043
|
// src/tools/recall.ts
|
|
@@ -11461,8 +11770,11 @@ ${problem}` : problem;
|
|
|
11461
11770
|
let winningProvider = null;
|
|
11462
11771
|
let lastVerification = null;
|
|
11463
11772
|
const maxTokens = opts.maxTokens ?? 4096;
|
|
11773
|
+
const upgradeRequested = isUpgradeRequested(args);
|
|
11774
|
+
const fableProvider = upgradeRequested && opts.providers["anthropic"] ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : null;
|
|
11775
|
+
const upgraded = fableProvider !== null;
|
|
11464
11776
|
for (let i = 1; i <= maxAttempts; i++) {
|
|
11465
|
-
const provider = selected[(i - 1) % selected.length];
|
|
11777
|
+
const provider = fableProvider ?? selected[(i - 1) % selected.length];
|
|
11466
11778
|
const msgs = [
|
|
11467
11779
|
{ role: "system", content: systemMsg },
|
|
11468
11780
|
{ role: "user", content: userBlock }
|
|
@@ -11559,6 +11871,24 @@ Re-emit the FULL solution. No commentary.`
|
|
|
11559
11871
|
}
|
|
11560
11872
|
if (unknownNames.length > 0) result["skipped_unknown_providers"] = unknownNames;
|
|
11561
11873
|
if (blocked.length > 0) result["blocked_by_allowlist"] = blocked;
|
|
11874
|
+
if (upgraded) {
|
|
11875
|
+
result["reasoning_upgrade"] = {
|
|
11876
|
+
applied: true,
|
|
11877
|
+
model: UPGRADE_MODEL,
|
|
11878
|
+
label: UPGRADE_LABEL,
|
|
11879
|
+
seat: "solver"
|
|
11880
|
+
};
|
|
11881
|
+
} else if (upgradeRequested) {
|
|
11882
|
+
result["reasoning_upgrade"] = {
|
|
11883
|
+
applied: false,
|
|
11884
|
+
reason: `no Anthropic key available \u2014 the ${UPGRADE_LABEL} upgrade needs it.`
|
|
11885
|
+
};
|
|
11886
|
+
} else {
|
|
11887
|
+
const assessment = assessReasoning(problem);
|
|
11888
|
+
if (assessment.heavy && opts.providers["anthropic"]) {
|
|
11889
|
+
result["suggested_upgrade"] = buildSuggestedUpgrade("solve", assessment);
|
|
11890
|
+
}
|
|
11891
|
+
}
|
|
11562
11892
|
const sessionId = typeof args["session_id"] === "string" ? args["session_id"] : null;
|
|
11563
11893
|
const allCallEnvelopes = solveAnswers;
|
|
11564
11894
|
const wallMs = Math.trunc(performance12.now() - callStartedWall);
|
|
@@ -11837,7 +12167,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
|
|
|
11837
12167
|
var DEFAULT_PACKAGE = "crosscheck-cli";
|
|
11838
12168
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
11839
12169
|
function engineVersion() {
|
|
11840
|
-
return true ? "0.1.
|
|
12170
|
+
return true ? "0.1.15" : "0.0.0-dev";
|
|
11841
12171
|
}
|
|
11842
12172
|
function defaultUpdateCachePath() {
|
|
11843
12173
|
const base = process.env["CROSSCHECK_DATA_DIR"] || path10.join(os.homedir() || os.tmpdir(), ".crosscheck");
|
|
@@ -12191,6 +12521,9 @@ async function runTriangulate(args, opts) {
|
|
|
12191
12521
|
};
|
|
12192
12522
|
if (args["providers"] !== void 0) coordArgs["providers"] = args["providers"];
|
|
12193
12523
|
if (args["session_id"] !== void 0) coordArgs["session_id"] = args["session_id"];
|
|
12524
|
+
if (args["reasoning"] !== void 0) coordArgs["reasoning"] = args["reasoning"];
|
|
12525
|
+
if (args["upgrade"] !== void 0) coordArgs["upgrade"] = args["upgrade"];
|
|
12526
|
+
if (args["model"] !== void 0) coordArgs["model"] = args["model"];
|
|
12194
12527
|
const coord = await runCoordinate(coordArgs, opts);
|
|
12195
12528
|
if (typeof coord["error"] === "string") return coord;
|
|
12196
12529
|
const synth = coord["synthesis_structured"] ?? {};
|
|
@@ -12239,10 +12572,16 @@ async function runTriangulate(args, opts) {
|
|
|
12239
12572
|
"session",
|
|
12240
12573
|
"transcript_path",
|
|
12241
12574
|
"blocked_by_allowlist",
|
|
12242
|
-
"skipped_unknown_providers"
|
|
12575
|
+
"skipped_unknown_providers",
|
|
12576
|
+
"reasoning_upgrade",
|
|
12577
|
+
"suggested_upgrade"
|
|
12243
12578
|
]) {
|
|
12244
12579
|
if (k in coord) result[k] = coord[k];
|
|
12245
12580
|
}
|
|
12581
|
+
if (result["suggested_upgrade"] && typeof result["suggested_upgrade"] === "object") {
|
|
12582
|
+
const su = result["suggested_upgrade"];
|
|
12583
|
+
su["how"] = `re-run \`triangulate\` with reasoning:"max" (or upgrade:true) to route the synthesizer seat to Fable 5. The proposer + critics stay on their normal models.`;
|
|
12584
|
+
}
|
|
12246
12585
|
return result;
|
|
12247
12586
|
}
|
|
12248
12587
|
|
|
@@ -12463,6 +12802,7 @@ function orchestrateTool(providers, allowlist, bridge, moderator, storage, prici
|
|
|
12463
12802
|
additionalProperties: true,
|
|
12464
12803
|
properties: {
|
|
12465
12804
|
goal: { type: "string" },
|
|
12805
|
+
reasoning: { type: "string", enum: ["default", "max"], description: '"max" bumps the recombine/synthesis seat to Fable 5 (premium thinking model); worker nodes stay on their normal (incl. cheap-mode) models. Omit for the default.' },
|
|
12466
12806
|
dag: { type: "object", additionalProperties: true },
|
|
12467
12807
|
context: { type: "string" },
|
|
12468
12808
|
providers: { type: "array", items: { type: "string" } },
|
|
@@ -12497,6 +12837,7 @@ function solveTool(providers, allowlist, bridge, storage, breakers, transcriptsD
|
|
|
12497
12837
|
additionalProperties: true,
|
|
12498
12838
|
properties: {
|
|
12499
12839
|
problem: { type: "string" },
|
|
12840
|
+
reasoning: { type: "string", enum: ["default", "max"], description: '"max" bumps the lead reasoning seat to Fable 5 (premium thinking model) for this call; other seats stay on their normal models. Omit for the Opus 4.8 default.' },
|
|
12500
12841
|
verifier: { type: "object", additionalProperties: true },
|
|
12501
12842
|
context: { type: "string" },
|
|
12502
12843
|
max_attempts: { type: "integer", minimum: 1 },
|
|
@@ -12831,6 +13172,7 @@ function planTool(providers, allowlist, bridge) {
|
|
|
12831
13172
|
additionalProperties: true,
|
|
12832
13173
|
properties: {
|
|
12833
13174
|
goal: { type: "string" },
|
|
13175
|
+
reasoning: { type: "string", enum: ["default", "max"], description: '"max" bumps the plan-synthesis seat to Fable 5 (premium thinking model); the debaters stay on their normal models. Omit for the Opus 4.8 default.' },
|
|
12834
13176
|
constraints: { type: "string" },
|
|
12835
13177
|
context: { type: "string" },
|
|
12836
13178
|
providers: { type: "array", items: { type: "string" } },
|
|
@@ -12860,6 +13202,7 @@ function triangulateTool(providers, allowlist, bridge) {
|
|
|
12860
13202
|
additionalProperties: true,
|
|
12861
13203
|
properties: {
|
|
12862
13204
|
question: { type: "string" },
|
|
13205
|
+
reasoning: { type: "string", enum: ["default", "max"], description: '"max" bumps the synthesizer seat to Fable 5 (premium thinking model); the proposer + critics stay on their normal models. Omit for the default.' },
|
|
12863
13206
|
context: { type: "string" },
|
|
12864
13207
|
providers: { type: "array", items: { type: "string" } },
|
|
12865
13208
|
session_id: { type: "string" },
|
|
@@ -12923,6 +13266,7 @@ function debateTool(providers, allowlist, bridge, innerCallers, storage, pricing
|
|
|
12923
13266
|
providers: { type: "array", items: { type: "string" } },
|
|
12924
13267
|
moderator: { type: "string" },
|
|
12925
13268
|
session_id: { type: "string" },
|
|
13269
|
+
reasoning: { type: "string", enum: ["default", "max"], description: '"max" bumps the moderator-synthesis seat to Fable 5 (premium thinking model); the debaters stay on their normal models. Omit for the Opus 4.8 default.' },
|
|
12926
13270
|
structured: { type: "boolean" },
|
|
12927
13271
|
extract_claims: { type: "boolean" },
|
|
12928
13272
|
early_stop: { type: "boolean" },
|
|
@@ -13007,6 +13351,7 @@ function auditTool(providers, allowlist, bridge, transcriptsDir, pricing, storag
|
|
|
13007
13351
|
additionalProperties: true,
|
|
13008
13352
|
properties: {
|
|
13009
13353
|
output_to_audit: { type: "string" },
|
|
13354
|
+
reasoning: { type: "string", enum: ["default", "max"], description: '"max" bumps the auditor seat to Fable 5 (premium thinking model) in single-auditor mode. Omit for the default.' },
|
|
13010
13355
|
session_id: { type: "string" },
|
|
13011
13356
|
auditor: { type: "string" },
|
|
13012
13357
|
producing_panelists: { type: "array", items: { type: "string" } },
|
|
@@ -13369,7 +13714,7 @@ async function flush() {
|
|
|
13369
13714
|
|
|
13370
13715
|
// src/server.ts
|
|
13371
13716
|
var SERVER_NAME = "crosscheck-agent";
|
|
13372
|
-
var SERVER_VERSION = true ? "0.1.
|
|
13717
|
+
var SERVER_VERSION = true ? "0.1.15" : "0.0.0-dev";
|
|
13373
13718
|
function extractRunSummaryText(out) {
|
|
13374
13719
|
if (out === null || typeof out !== "object" || Array.isArray(out)) return void 0;
|
|
13375
13720
|
const rs = out["run_summary"];
|