crosscheck-mcp 0.2.3 → 0.2.5

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.
@@ -464,6 +464,7 @@ interface FetchConfig {
464
464
 
465
465
  declare const SERVER_NAME = "crosscheck-agent";
466
466
  declare const SERVER_VERSION: string;
467
+
467
468
  interface CreateServerOptions {
468
469
  /** Optional Python bridge. When supplied, the bridge's tools are
469
470
  * merged into the registry as proxy entries — they forward `tools/call`
@@ -464,6 +464,7 @@ interface FetchConfig {
464
464
 
465
465
  declare const SERVER_NAME = "crosscheck-agent";
466
466
  declare const SERVER_VERSION: string;
467
+
467
468
  interface CreateServerOptions {
468
469
  /** Optional Python bridge. When supplied, the bridge's tools are
469
470
  * merged into the registry as proxy entries — they forward `tools/call`
@@ -1174,6 +1174,14 @@ var PROVIDER_CAPS = {
1174
1174
  mistral: { family: "openai_chat", system_role: "inline", supports_temperature: true },
1175
1175
  groq: { family: "openai_chat", system_role: "inline", supports_temperature: true },
1176
1176
  deepseek: { family: "openai_chat", system_role: "inline", supports_temperature: true },
1177
+ kimi: {
1178
+ family: "openai_chat",
1179
+ system_role: "inline",
1180
+ // Kimi K3 is reasoning-class: it rejects temperature != 1 and wants
1181
+ // max_completion_tokens (like OpenAI's gpt-5 / o-series).
1182
+ supports_temperature: "model",
1183
+ reasoning_prefixes: ["kimi-k3"]
1184
+ },
1177
1185
  gemini: {
1178
1186
  family: "gemini",
1179
1187
  system_role: "separate",
@@ -1459,7 +1467,10 @@ function buildAnthropicRequest(opts) {
1459
1467
  const headers = {
1460
1468
  "content-type": "application/json",
1461
1469
  "x-api-key": opts.apiKey,
1462
- "anthropic-version": ANTHROPIC_VERSION_HEADER
1470
+ "anthropic-version": ANTHROPIC_VERSION_HEADER,
1471
+ // Required for browser-origin calls (the Chrome extension); harmless from
1472
+ // Node. Without it the Anthropic API rejects requests made from a browser.
1473
+ "anthropic-dangerous-direct-browser-access": "true"
1463
1474
  };
1464
1475
  return { url: ANTHROPIC_API_URL, headers, body };
1465
1476
  }
@@ -1758,7 +1769,9 @@ var OPENAI_COMPAT_DEFAULT_URLS = {
1758
1769
  xai: "https://api.x.ai/v1/chat/completions",
1759
1770
  mistral: "https://api.mistral.ai/v1/chat/completions",
1760
1771
  groq: "https://api.groq.com/openai/v1/chat/completions",
1761
- deepseek: "https://api.deepseek.com/v1/chat/completions"
1772
+ deepseek: "https://api.deepseek.com/v1/chat/completions",
1773
+ // Moonshot AI (Kimi). OpenAI-compatible chat completions endpoint.
1774
+ kimi: "https://api.moonshot.ai/v1/chat/completions"
1762
1775
  };
1763
1776
  var OPENAI_COMPAT_NATIVE_STRUCTURED = /* @__PURE__ */ new Set([
1764
1777
  "openai"
@@ -1926,7 +1939,8 @@ var DEFAULT_MODELS = {
1926
1939
  mistral: "mistral-large-latest",
1927
1940
  groq: "llama-3.3-70b-versatile",
1928
1941
  deepseek: "deepseek-chat",
1929
- gemini: "gemini-3.1-pro-preview"
1942
+ gemini: "gemini-3.1-pro-preview",
1943
+ kimi: "kimi-k3"
1930
1944
  };
1931
1945
  function buildProviders(opts) {
1932
1946
  const out = {};
@@ -1940,7 +1954,8 @@ function buildProviders(opts) {
1940
1954
  { name: "xai", keyEnv: "XAI_API_KEY", modelEnv: "XAI_MODEL", defaultModel: DEFAULT_MODELS["xai"] },
1941
1955
  { name: "mistral", keyEnv: "MISTRAL_API_KEY", modelEnv: "MISTRAL_MODEL", defaultModel: DEFAULT_MODELS["mistral"] },
1942
1956
  { name: "groq", keyEnv: "GROQ_API_KEY", modelEnv: "GROQ_MODEL", defaultModel: DEFAULT_MODELS["groq"] },
1943
- { name: "deepseek", keyEnv: "DEEPSEEK_API_KEY", modelEnv: "DEEPSEEK_MODEL", defaultModel: DEFAULT_MODELS["deepseek"] }
1957
+ { name: "deepseek", keyEnv: "DEEPSEEK_API_KEY", modelEnv: "DEEPSEEK_MODEL", defaultModel: DEFAULT_MODELS["deepseek"] },
1958
+ { name: "kimi", keyEnv: "KIMI_API_KEY", modelEnv: "KIMI_MODEL", defaultModel: DEFAULT_MODELS["kimi"] }
1944
1959
  ];
1945
1960
  for (const s of openAiCompatSpec) {
1946
1961
  const apiKey = opts.env[s.keyEnv];
@@ -2135,6 +2150,11 @@ Spend visibility:
2135
2150
  init_esm_shims();
2136
2151
  import { z } from "zod";
2137
2152
 
2153
+ // src/server-meta.ts
2154
+ init_esm_shims();
2155
+ var SERVER_NAME = "crosscheck-agent";
2156
+ var SERVER_VERSION = true ? "0.2.5" : "0.0.0-dev";
2157
+
2138
2158
  // src/tools/audit.ts
2139
2159
  init_esm_shims();
2140
2160
  import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
@@ -3633,6 +3653,51 @@ async function loadProviderWeights(storage, names) {
3633
3653
  return out;
3634
3654
  }
3635
3655
 
3656
+ // src/core/co-reason.ts
3657
+ init_esm_shims();
3658
+ var CO_REASON_MODEL = "gpt-5.6";
3659
+ var CO_REASON_PROVIDER = "openai";
3660
+ var CO_REASON_LABEL = "GPT-5.6";
3661
+ function pickCoReasoner(providers, upgradeRequested) {
3662
+ if (!upgradeRequested) return null;
3663
+ const base = providers[CO_REASON_PROVIDER];
3664
+ return base ? retargetProvider(base, CO_REASON_MODEL) : null;
3665
+ }
3666
+ async function coReasonThenInject(opts) {
3667
+ const { provider, messages, maxTokens } = opts;
3668
+ if (!provider) return { messages, answer: null };
3669
+ const answer = await askOne(provider, messages, {
3670
+ maxTokens,
3671
+ temperature: 0.3,
3672
+ purpose: opts.purpose ?? "co-reason"
3673
+ });
3674
+ const text = typeof answer.response === "string" ? answer.response.trim() : "";
3675
+ if (answer.error !== void 0 || !text) {
3676
+ return { messages, answer };
3677
+ }
3678
+ return { messages: injectSecondOpinion(messages, text), answer };
3679
+ }
3680
+ function secondOpinionBlock(analysis) {
3681
+ return `
3682
+
3683
+ --- SECOND-OPINION ANALYSIS (${CO_REASON_LABEL}) ---
3684
+ Another top-tier model analyzed the same task. Weigh it critically \u2014 it may be wrong or incomplete \u2014 then produce your own final answer.
3685
+
3686
+ ${analysis}`;
3687
+ }
3688
+ function injectSecondOpinion(messages, analysis) {
3689
+ const block = secondOpinionBlock(analysis);
3690
+ const out = messages.map((m) => ({ ...m }));
3691
+ for (let i = out.length - 1; i >= 0; i--) {
3692
+ if (out[i].role === "user") {
3693
+ out[i] = { ...out[i], content: String(out[i].content) + block };
3694
+ return out;
3695
+ }
3696
+ }
3697
+ out.push({ role: "user", content: block.trimStart() });
3698
+ return out;
3699
+ }
3700
+
3636
3701
  // src/core/tiers.ts
3637
3702
  init_esm_shims();
3638
3703
 
@@ -3827,7 +3892,7 @@ function buildSuggestedUpgrade(toolName, assessment) {
3827
3892
  model: UPGRADE_MODEL,
3828
3893
  label: UPGRADE_LABEL,
3829
3894
  reason: assessment.reason,
3830
- 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.`
3895
+ how: `re-run \`${toolName}\` with reasoning:"max" (or upgrade:true) to route the lead reasoning seat to ${UPGRADE_LABEL}, and \u2014 when an OpenAI key is configured \u2014 add a GPT-5.6 second-opinion pass that ${UPGRADE_LABEL} weighs before finalizing. Other panel seats stay on their normal models.`
3831
3896
  };
3832
3897
  }
3833
3898
 
@@ -3976,7 +4041,7 @@ ${outputResolved}
3976
4041
 
3977
4042
  RUBRIC ITEMS:
3978
4043
  ${rubricText}`;
3979
- const msgs = [
4044
+ let msgs = [
3980
4045
  { role: "system", content: sysMsg },
3981
4046
  { role: "user", content: userMsg }
3982
4047
  ];
@@ -4100,6 +4165,15 @@ ${rubricText}`;
4100
4165
  const upgradeRequested = isUpgradeRequested(args);
4101
4166
  const upgraded = upgradeRequested && opts.providers["anthropic"] !== void 0;
4102
4167
  const auditorForCall = upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : auditor;
4168
+ const coReason = await coReasonThenInject({
4169
+ provider: pickCoReasoner(opts.providers, upgradeRequested),
4170
+ messages: msgs,
4171
+ maxTokens: 2048,
4172
+ purpose: "audit-coreason"
4173
+ });
4174
+ msgs = coReason.messages;
4175
+ if (coReason.answer) auditAnswers.push(coReason.answer);
4176
+ const coReasoned = coReason.answer !== null;
4103
4177
  const r = await requestStructured(auditorForCall, msgs, AUDIT_RUBRIC_SCHEMA, {
4104
4178
  maxTokens: 2048,
4105
4179
  maxRetries: 1,
@@ -4155,7 +4229,8 @@ ${rubricText}`;
4155
4229
  applied: true,
4156
4230
  model: UPGRADE_MODEL,
4157
4231
  label: UPGRADE_LABEL,
4158
- seat: "auditor"
4232
+ seat: "auditor",
4233
+ ...coReasoned ? { co_reasoner: { model: CO_REASON_MODEL, label: CO_REASON_LABEL } } : {}
4159
4234
  };
4160
4235
  } else if (upgradeRequested) {
4161
4236
  result["reasoning_upgrade"] = {
@@ -5681,7 +5756,7 @@ ${ctxBody}` });
5681
5756
  args["worker_tool_cost_cap_mode"],
5682
5757
  opts.workerToolsCfg
5683
5758
  );
5684
- const workerCall = (p) => {
5759
+ const dispatchOne = (p) => {
5685
5760
  if (acceptedWorkerTools.length > 0 && opts.innerCallers) {
5686
5761
  const opts2 = {
5687
5762
  provider: p,
@@ -5703,6 +5778,15 @@ ${ctxBody}` });
5703
5778
  purpose: "confer"
5704
5779
  });
5705
5780
  };
5781
+ const onAnswer = opts.onAnswer;
5782
+ const workerCall = onAnswer ? async (p) => {
5783
+ const answer = await dispatchOne(p);
5784
+ try {
5785
+ onAnswer(answer, p.name);
5786
+ } catch {
5787
+ }
5788
+ return answer;
5789
+ } : dispatchOne;
5706
5790
  if (earlyStop && selected.length >= 3) {
5707
5791
  const phase1 = await Promise.all(selected.slice(0, 2).map(workerCall));
5708
5792
  const phase1Clean = phase1.filter(
@@ -7831,7 +7915,7 @@ Synthesize the node outputs into a single coherent deliverable. Preserve any [MI
7831
7915
  });
7832
7916
  const personaMeta = persona.meta;
7833
7917
  const recombineSys = "You are the orchestrator. Combine node outputs into the final result.";
7834
- const recMsgs = [
7918
+ let recMsgs = [
7835
7919
  { role: "system", content: persona.block ? `${persona.block}
7836
7920
 
7837
7921
  ${recombineSys}` : recombineSys },
@@ -7870,6 +7954,15 @@ ${recombineSys}` : recombineSys },
7870
7954
  provider: synthProvider.name
7871
7955
  } }
7872
7956
  );
7957
+ const coReason = await coReasonThenInject({
7958
+ provider: pickCoReasoner(opts.providers, upgradeRequested),
7959
+ messages: recMsgs,
7960
+ maxTokens,
7961
+ purpose: "orchestrate-coreason"
7962
+ });
7963
+ recMsgs = coReason.messages;
7964
+ if (coReason.answer) orchAnswers.push(coReason.answer);
7965
+ const coReasoned = coReason.answer !== null;
7873
7966
  let synthAns = await askOne(synthProvider, recMsgs, {
7874
7967
  maxTokens,
7875
7968
  temperature: 0.4,
@@ -7920,7 +8013,8 @@ ${recombineSys}` : recombineSys },
7920
8013
  applied: true,
7921
8014
  model: UPGRADE_MODEL,
7922
8015
  label: UPGRADE_LABEL,
7923
- seat: "recombine/synthesis"
8016
+ seat: "recombine/synthesis",
8017
+ ...coReasoned ? { co_reasoner: { model: CO_REASON_MODEL, label: CO_REASON_LABEL } } : {}
7924
8018
  };
7925
8019
  } else if (upgradeRequested) {
7926
8020
  result["reasoning_upgrade"] = {
@@ -9241,7 +9335,7 @@ ${proposalRender}`
9241
9335
  critiqueAnswers[i]?.response ?? ""
9242
9336
  )
9243
9337
  ).join("\n\n") : "(no critiques)";
9244
- const synthMessages = [
9338
+ let synthMessages = [
9245
9339
  { role: "system", content: synthSystem },
9246
9340
  {
9247
9341
  role: "user",
@@ -9254,6 +9348,14 @@ CRITIQUES:
9254
9348
  ${critiqueBlock}`
9255
9349
  }
9256
9350
  ];
9351
+ const coReason = await coReasonThenInject({
9352
+ provider: pickCoReasoner(opts.providers, upgradeRequested),
9353
+ messages: synthMessages,
9354
+ maxTokens,
9355
+ purpose: "coordinate-coreason"
9356
+ });
9357
+ synthMessages = coReason.messages;
9358
+ const coReasonAns = coReason.answer;
9257
9359
  const synthResult = await requestStructured(
9258
9360
  synthForCall,
9259
9361
  synthMessages,
@@ -9309,7 +9411,8 @@ ${critiqueBlock}`
9309
9411
  applied: true,
9310
9412
  model: UPGRADE_MODEL,
9311
9413
  label: UPGRADE_LABEL,
9312
- seat: "synthesizer"
9414
+ seat: "synthesizer",
9415
+ ...coReasonAns ? { co_reasoner: { model: CO_REASON_MODEL, label: CO_REASON_LABEL } } : {}
9313
9416
  };
9314
9417
  } else if (upgradeRequested) {
9315
9418
  result["reasoning_upgrade"] = {
@@ -9325,6 +9428,7 @@ ${critiqueBlock}`
9325
9428
  const allCallEnvelopes = [
9326
9429
  scannedProposal,
9327
9430
  ...scannedCritiques,
9431
+ ...coReasonAns ? [coReasonAns] : [],
9328
9432
  synthAns
9329
9433
  ];
9330
9434
  const wallMs = Math.trunc(performance8.now() - callStartedWall);
@@ -9889,7 +9993,14 @@ ${prior}` });
9889
9993
  }
9890
9994
  for (const p of selected) {
9891
9995
  const entry = await callPanelist(p, roundMessages);
9892
- transcript.push({ ...entry, round: rnd });
9996
+ const withRound = { ...entry, round: rnd };
9997
+ transcript.push(withRound);
9998
+ if (opts.onTurn) {
9999
+ try {
10000
+ opts.onTurn(withRound, rnd, p.name);
10001
+ } catch {
10002
+ }
10003
+ }
9893
10004
  }
9894
10005
  if (earlyStopOpt && rnd < maxRounds) {
9895
10006
  const thisRound = transcript.filter(
@@ -9924,6 +10035,7 @@ ${prior}` });
9924
10035
  let synthesisStructured = null;
9925
10036
  let synthesisErrors = [];
9926
10037
  let personaMeta = null;
10038
+ let coReasoned = false;
9927
10039
  if (moderator) {
9928
10040
  const synthProvider = upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : moderator;
9929
10041
  const condensed = transcript.map(
@@ -9939,7 +10051,7 @@ ${e.response ?? "(error)"}`
9939
10051
  });
9940
10052
  personaMeta = persona.meta;
9941
10053
  const synthSys = "You are the moderator. Synthesise the debate into a single grounded recommendation.";
9942
- const synthMessages = [
10054
+ let synthMessages = [
9943
10055
  {
9944
10056
  role: "system",
9945
10057
  content: persona.block ? `${persona.block}
@@ -9954,6 +10066,15 @@ TRANSCRIPT:
9954
10066
  ${condensed}`
9955
10067
  }
9956
10068
  ];
10069
+ const coReason = await coReasonThenInject({
10070
+ provider: pickCoReasoner(opts.providers, upgradeRequested),
10071
+ messages: synthMessages,
10072
+ maxTokens,
10073
+ purpose: "debate-coreason"
10074
+ });
10075
+ synthMessages = coReason.messages;
10076
+ if (coReason.answer) extraAnswers.push(coReason.answer);
10077
+ coReasoned = coReason.answer !== null;
9957
10078
  if (structuredOpt) {
9958
10079
  const r = await requestStructured(
9959
10080
  synthProvider,
@@ -9971,6 +10092,12 @@ ${condensed}`
9971
10092
  purpose: "synth"
9972
10093
  });
9973
10094
  }
10095
+ if (synthesis && opts.onSynthesis) {
10096
+ try {
10097
+ opts.onSynthesis(synthesis);
10098
+ } catch {
10099
+ }
10100
+ }
9974
10101
  }
9975
10102
  let claimsBlock = null;
9976
10103
  if (Boolean(args["extract_claims"])) {
@@ -10002,7 +10129,8 @@ ${condensed}`
10002
10129
  applied: true,
10003
10130
  model: UPGRADE_MODEL,
10004
10131
  label: UPGRADE_LABEL,
10005
- seat: "moderator synthesis"
10132
+ seat: "moderator synthesis",
10133
+ ...coReasoned ? { co_reasoner: { model: CO_REASON_MODEL, label: CO_REASON_LABEL } } : {}
10006
10134
  };
10007
10135
  } else if (upgradeRequested) {
10008
10136
  result["reasoning_upgrade"] = {
@@ -11803,7 +11931,7 @@ async function runSolve(args, opts) {
11803
11931
  return { error: "no active providers have API keys in .env" };
11804
11932
  }
11805
11933
  const systemMsg = "You are solving a problem step-by-step. Produce ONLY the literal solution (code, command, or text) with no commentary, no markdown fences, no preamble. Your output is fed directly to a verifier.";
11806
- const userBlock = context ? `CONTEXT:
11934
+ let userBlock = context ? `CONTEXT:
11807
11935
  ${context}
11808
11936
 
11809
11937
  PROBLEM:
@@ -11830,6 +11958,20 @@ ${problem}` : problem;
11830
11958
  const upgradeRequested = isUpgradeRequested(args);
11831
11959
  const fableProvider = upgradeRequested && opts.providers["anthropic"] ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : null;
11832
11960
  const upgraded = fableProvider !== null;
11961
+ const coProvider = pickCoReasoner(opts.providers, upgradeRequested);
11962
+ let coReasoned = false;
11963
+ if (coProvider) {
11964
+ const coAns = await askOne(
11965
+ coProvider,
11966
+ [{ role: "system", content: systemMsg }, { role: "user", content: userBlock }],
11967
+ { maxTokens, temperature: 0.3, purpose: "solve-coreason" }
11968
+ );
11969
+ solveAnswers.push(coAns);
11970
+ coReasoned = true;
11971
+ if (coAns.error === void 0 && typeof coAns.response === "string" && coAns.response.trim()) {
11972
+ userBlock += secondOpinionBlock(coAns.response.trim());
11973
+ }
11974
+ }
11833
11975
  for (let i = 1; i <= maxAttempts; i++) {
11834
11976
  const provider = fableProvider ?? selected[(i - 1) % selected.length];
11835
11977
  const msgs = [
@@ -11933,7 +12075,8 @@ Re-emit the FULL solution. No commentary.`
11933
12075
  applied: true,
11934
12076
  model: UPGRADE_MODEL,
11935
12077
  label: UPGRADE_LABEL,
11936
- seat: "solver"
12078
+ seat: "solver",
12079
+ ...coReasoned ? { co_reasoner: { model: CO_REASON_MODEL, label: CO_REASON_LABEL } } : {}
11937
12080
  };
11938
12081
  } else if (upgradeRequested) {
11939
12082
  result["reasoning_upgrade"] = {
@@ -12224,7 +12367,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
12224
12367
  var DEFAULT_PACKAGE = "crosscheck-cli";
12225
12368
  var FETCH_TIMEOUT_MS = 3e3;
12226
12369
  function engineVersion() {
12227
- return true ? "0.2.3" : "0.0.0-dev";
12370
+ return true ? "0.2.5" : "0.0.0-dev";
12228
12371
  }
12229
12372
  function defaultUpdateCachePath() {
12230
12373
  const base = process.env["CROSSCHECK_DATA_DIR"] || path10.join(os.homedir() || os.tmpdir(), ".crosscheck");
@@ -14075,8 +14218,6 @@ async function flush() {
14075
14218
  }
14076
14219
 
14077
14220
  // src/server.ts
14078
- var SERVER_NAME = "crosscheck-agent";
14079
- var SERVER_VERSION = true ? "0.2.3" : "0.0.0-dev";
14080
14221
  function extractRunSummaryText(out) {
14081
14222
  if (out === null || typeof out !== "object" || Array.isArray(out)) return void 0;
14082
14223
  const rec = out;