crosscheck-mcp 0.2.22 → 0.2.24

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.
@@ -550,7 +550,7 @@ function defaultTransient(kind) {
550
550
  var CREDIT_RE = /insufficient|no\s+credit|credits?|billing|quota|payment\s*required|exceeded your current quota|not\s+enough|fund|no active subscription|spend limit/i;
551
551
  function isCreditsFailure(status, bodyText) {
552
552
  if (status === 402) return true;
553
- if (status === 401 || status === 403 || status === 429 || status === 400) {
553
+ if (status === 401 || status === 403 || status === 400) {
554
554
  return CREDIT_RE.test(bodyText);
555
555
  }
556
556
  return false;
@@ -587,7 +587,7 @@ function httpFailureToProviderError(provider, status, bodyText, retryAfterS, mod
587
587
  if (status === 429) {
588
588
  return new ProviderError(
589
589
  "rate_limit",
590
- `${provider}: rate limited (HTTP 429). Detail: ${detail}`,
590
+ `${provider}: rate limited (HTTP 429) \u2014 retrying with backoff. Note that some providers word a rate limit as a balance problem; check your balance before topping up. Detail: ${detail}`,
591
591
  { status, ...retryAfterS !== void 0 ? { retryAfterS } : {} }
592
592
  );
593
593
  }
@@ -1355,10 +1355,20 @@ function fallbackModelsFor(env, provider) {
1355
1355
  if (pinned && pinned !== DEFAULT_MODELS[provider]) return [];
1356
1356
  return DEFAULT_FALLBACKS[provider] ?? [];
1357
1357
  }
1358
+ var DEFAULT_EXCLUDED_PROVIDERS = ["mistral", "groq"];
1359
+ function excludedProviders(env) {
1360
+ const parse = (v) => (v ?? "").split(",").map((x) => x.trim().toLowerCase()).filter((x) => x !== "");
1361
+ const excluded = new Set(
1362
+ parse(env["CROSSCHECK_EXCLUDE_PROVIDERS"]).length > 0 ? parse(env["CROSSCHECK_EXCLUDE_PROVIDERS"]) : DEFAULT_EXCLUDED_PROVIDERS
1363
+ );
1364
+ for (const name of parse(env["CROSSCHECK_ENABLE_PROVIDERS"])) excluded.delete(name);
1365
+ return excluded;
1366
+ }
1358
1367
  function buildProviders(opts) {
1359
1368
  const out = {};
1369
+ const excluded = excludedProviders(opts.env);
1360
1370
  const anthropicKey = opts.env["ANTHROPIC_API_KEY"];
1361
- if (anthropicKey) {
1371
+ if (anthropicKey && !excluded.has("anthropic")) {
1362
1372
  const model = opts.env["ANTHROPIC_MODEL"] ?? DEFAULT_MODELS.anthropic;
1363
1373
  out["anthropic"] = makeAnthropicProvider(model, anthropicKey, opts, fallbackModelsFor(opts.env, "anthropic"));
1364
1374
  }
@@ -1374,11 +1384,12 @@ function buildProviders(opts) {
1374
1384
  for (const s of openAiCompatSpec) {
1375
1385
  const apiKey = opts.env[s.keyEnv];
1376
1386
  if (!apiKey) continue;
1387
+ if (excluded.has(s.name)) continue;
1377
1388
  const model = opts.env[s.modelEnv] ?? s.defaultModel;
1378
1389
  out[s.name] = makeOpenAICompatibleProvider(s.name, model, apiKey, opts, fallbackModelsFor(opts.env, s.name));
1379
1390
  }
1380
1391
  const geminiKey = opts.env["GEMINI_API_KEY"];
1381
- if (geminiKey) {
1392
+ if (geminiKey && !excluded.has("gemini")) {
1382
1393
  const model = opts.env["GEMINI_MODEL"] ?? DEFAULT_MODELS.gemini;
1383
1394
  out["gemini"] = makeGeminiProvider(model, geminiKey, opts, fallbackModelsFor(opts.env, "gemini"));
1384
1395
  }
@@ -1444,7 +1455,7 @@ var import_zod = require("zod");
1444
1455
 
1445
1456
  // src/server-meta.ts
1446
1457
  var SERVER_NAME = "crosscheck-agent";
1447
- var SERVER_VERSION = true ? "0.2.22" : "0.0.0-dev";
1458
+ var SERVER_VERSION = true ? "0.2.24" : "0.0.0-dev";
1448
1459
 
1449
1460
  // src/tools/audit.ts
1450
1461
  var import_node_fs4 = require("fs");
@@ -9221,6 +9232,63 @@ function isObj6(v) {
9221
9232
  return typeof v === "object" && v !== null && !Array.isArray(v);
9222
9233
  }
9223
9234
 
9235
+ // src/core/debate-compaction.ts
9236
+ var DEFAULT_PRIOR_BUDGET_CHARS = 12e3;
9237
+ function renderTurn(e) {
9238
+ return `[${e.provider} \u2014 round ${e.round}]
9239
+ ${e.response ?? "(error)"}`;
9240
+ }
9241
+ function buildPriorTurns(transcript, opts = {}) {
9242
+ if (transcript.length === 0) {
9243
+ return { body: "", includedTurns: 0, omittedTurns: 0, chars: 0 };
9244
+ }
9245
+ const rendered = transcript.map(renderTurn);
9246
+ const full = rendered.join("\n\n");
9247
+ if (!opts.compress) {
9248
+ return { body: full, includedTurns: transcript.length, omittedTurns: 0, chars: full.length };
9249
+ }
9250
+ const budget = Math.max(0, opts.budgetChars ?? DEFAULT_PRIOR_BUDGET_CHARS);
9251
+ if (full.length <= budget) {
9252
+ return { body: full, includedTurns: transcript.length, omittedTurns: 0, chars: full.length };
9253
+ }
9254
+ const latestRound = Math.max(...transcript.map((e) => e.round));
9255
+ const keep = /* @__PURE__ */ new Set();
9256
+ let spent = 0;
9257
+ for (let i = transcript.length - 1; i >= 0; i -= 1) {
9258
+ const isLatest = transcript[i].round === latestRound;
9259
+ const cost = rendered[i].length + 2;
9260
+ if (isLatest) {
9261
+ keep.add(i);
9262
+ spent += cost;
9263
+ continue;
9264
+ }
9265
+ if (spent + cost > budget) continue;
9266
+ keep.add(i);
9267
+ spent += cost;
9268
+ }
9269
+ const parts = [];
9270
+ let omitted = 0;
9271
+ let pendingGap = 0;
9272
+ for (let i = 0; i < transcript.length; i += 1) {
9273
+ if (keep.has(i)) {
9274
+ if (pendingGap > 0) {
9275
+ parts.push(`[${pendingGap} earlier turn(s) omitted for length]`);
9276
+ pendingGap = 0;
9277
+ }
9278
+ parts.push(rendered[i]);
9279
+ } else {
9280
+ omitted += 1;
9281
+ pendingGap += 1;
9282
+ }
9283
+ }
9284
+ if (pendingGap > 0) parts.push(`[${pendingGap} earlier turn(s) omitted for length]`);
9285
+ const body = parts.join("\n\n");
9286
+ return { body, includedTurns: keep.size, omittedTurns: omitted, chars: body.length };
9287
+ }
9288
+ function buildModeratorTranscript(transcript) {
9289
+ return transcript.map(renderTurn).join("\n\n");
9290
+ }
9291
+
9224
9292
  // src/tools/debate.ts
9225
9293
  var import_node_perf_hooks9 = require("perf_hooks");
9226
9294
  var DEFERRED_OPTS4 = [
@@ -9269,6 +9337,9 @@ async function runDebate(args, opts) {
9269
9337
  1,
9270
9338
  Math.trunc(Number(args["max_rounds"] ?? 3)) || 3
9271
9339
  );
9340
+ const compressRounds = args["compress_rounds"] === true;
9341
+ const priorBudgetChars = Math.trunc(Number(args["prior_budget_chars"] ?? DEFAULT_PRIOR_BUDGET_CHARS)) || DEFAULT_PRIOR_BUDGET_CHARS;
9342
+ let compactionMeta = null;
9272
9343
  const sessionId = typeof args["session_id"] === "string" ? args["session_id"] : null;
9273
9344
  const breakerEnv = await maybeBreakerEnvelope(
9274
9345
  opts.storage,
@@ -9379,7 +9450,7 @@ async function runDebate(args, opts) {
9379
9450
  const roundMessages = [
9380
9451
  {
9381
9452
  role: "system",
9382
- content: `You are debating peers from other model families. Round ${rnd}/${maxRounds}. Disagree where warranted, concede where right, and keep replies short and specific.`
9453
+ content: "You are debating peers from other model families. Disagree where warranted, concede where right, and keep replies short and specific."
9383
9454
  }
9384
9455
  ];
9385
9456
  if (context) {
@@ -9391,13 +9462,22 @@ ${context}` });
9391
9462
  TOPIC: ${topic}` : `TOPIC: ${topic}`;
9392
9463
  roundMessages.push({ role: "user", content: topicLine });
9393
9464
  if (transcript.length > 0) {
9394
- const prior = transcript.map(
9395
- (e) => `[${e.provider} \u2014 round ${e.round}]
9396
- ${e.response ?? "(error)"}`
9397
- ).join("\n\n");
9465
+ const prior = buildPriorTurns(transcript, {
9466
+ compress: compressRounds,
9467
+ budgetChars: priorBudgetChars
9468
+ });
9469
+ if (prior.omittedTurns > 0) compactionMeta = {
9470
+ omitted_turns: prior.omittedTurns,
9471
+ included_turns: prior.includedTurns,
9472
+ budget_chars: priorBudgetChars
9473
+ };
9398
9474
  roundMessages.push({ role: "user", content: `PRIOR TURNS:
9399
- ${prior}` });
9475
+ ${prior.body}` });
9400
9476
  }
9477
+ roundMessages.push({
9478
+ role: "user",
9479
+ content: `This is round ${rnd} of ${maxRounds}. Reply for this round.`
9480
+ });
9401
9481
  for (const p of selected) {
9402
9482
  const entry = await callPanelist(p, roundMessages);
9403
9483
  const withRound = { ...entry, round: rnd };
@@ -9445,10 +9525,7 @@ ${prior}` });
9445
9525
  let coReasoned = false;
9446
9526
  if (moderator) {
9447
9527
  const synthProvider = superRequested && opts.providers["anthropic"] ? retargetForSuper(opts.providers["anthropic"]) : upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : moderator;
9448
- const condensed = transcript.map(
9449
- (e) => `[${e.provider} \u2014 round ${e.round}]
9450
- ${e.response ?? "(error)"}`
9451
- ).join("\n\n");
9528
+ const condensed = buildModeratorTranscript(transcript);
9452
9529
  const persona = buildPersonaInjection({
9453
9530
  toolName: "debate",
9454
9531
  prompt: topic,
@@ -9531,6 +9608,7 @@ ${condensed}`
9531
9608
  synthesis
9532
9609
  };
9533
9610
  if (personaMeta && personaMeta.used !== null) result["persona"] = personaMeta;
9611
+ if (compactionMeta) result["round_compaction"] = compactionMeta;
9534
9612
  if (upgraded) {
9535
9613
  result["reasoning_upgrade"] = {
9536
9614
  applied: true,
@@ -11850,7 +11928,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
11850
11928
  var DEFAULT_PACKAGE = "crosscheck-cli";
11851
11929
  var FETCH_TIMEOUT_MS = 3e3;
11852
11930
  function engineVersion() {
11853
- return true ? "0.2.22" : "0.0.0-dev";
11931
+ return true ? "0.2.24" : "0.0.0-dev";
11854
11932
  }
11855
11933
  function defaultUpdateCachePath() {
11856
11934
  const base = process.env["CROSSCHECK_DATA_DIR"] || import_node_path12.default.join(import_node_os2.default.homedir() || import_node_os2.default.tmpdir(), ".crosscheck");