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.
@@ -517,7 +517,7 @@ function defaultTransient(kind) {
517
517
  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;
518
518
  function isCreditsFailure(status, bodyText) {
519
519
  if (status === 402) return true;
520
- if (status === 401 || status === 403 || status === 429 || status === 400) {
520
+ if (status === 401 || status === 403 || status === 400) {
521
521
  return CREDIT_RE.test(bodyText);
522
522
  }
523
523
  return false;
@@ -554,7 +554,7 @@ function httpFailureToProviderError(provider, status, bodyText, retryAfterS, mod
554
554
  if (status === 429) {
555
555
  return new ProviderError(
556
556
  "rate_limit",
557
- `${provider}: rate limited (HTTP 429). Detail: ${detail}`,
557
+ `${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}`,
558
558
  { status, ...retryAfterS !== void 0 ? { retryAfterS } : {} }
559
559
  );
560
560
  }
@@ -1322,10 +1322,20 @@ function fallbackModelsFor(env, provider) {
1322
1322
  if (pinned && pinned !== DEFAULT_MODELS[provider]) return [];
1323
1323
  return DEFAULT_FALLBACKS[provider] ?? [];
1324
1324
  }
1325
+ var DEFAULT_EXCLUDED_PROVIDERS = ["mistral", "groq"];
1326
+ function excludedProviders(env) {
1327
+ const parse = (v) => (v ?? "").split(",").map((x) => x.trim().toLowerCase()).filter((x) => x !== "");
1328
+ const excluded = new Set(
1329
+ parse(env["CROSSCHECK_EXCLUDE_PROVIDERS"]).length > 0 ? parse(env["CROSSCHECK_EXCLUDE_PROVIDERS"]) : DEFAULT_EXCLUDED_PROVIDERS
1330
+ );
1331
+ for (const name of parse(env["CROSSCHECK_ENABLE_PROVIDERS"])) excluded.delete(name);
1332
+ return excluded;
1333
+ }
1325
1334
  function buildProviders(opts) {
1326
1335
  const out = {};
1336
+ const excluded = excludedProviders(opts.env);
1327
1337
  const anthropicKey = opts.env["ANTHROPIC_API_KEY"];
1328
- if (anthropicKey) {
1338
+ if (anthropicKey && !excluded.has("anthropic")) {
1329
1339
  const model = opts.env["ANTHROPIC_MODEL"] ?? DEFAULT_MODELS.anthropic;
1330
1340
  out["anthropic"] = makeAnthropicProvider(model, anthropicKey, opts, fallbackModelsFor(opts.env, "anthropic"));
1331
1341
  }
@@ -1341,11 +1351,12 @@ function buildProviders(opts) {
1341
1351
  for (const s of openAiCompatSpec) {
1342
1352
  const apiKey = opts.env[s.keyEnv];
1343
1353
  if (!apiKey) continue;
1354
+ if (excluded.has(s.name)) continue;
1344
1355
  const model = opts.env[s.modelEnv] ?? s.defaultModel;
1345
1356
  out[s.name] = makeOpenAICompatibleProvider(s.name, model, apiKey, opts, fallbackModelsFor(opts.env, s.name));
1346
1357
  }
1347
1358
  const geminiKey = opts.env["GEMINI_API_KEY"];
1348
- if (geminiKey) {
1359
+ if (geminiKey && !excluded.has("gemini")) {
1349
1360
  const model = opts.env["GEMINI_MODEL"] ?? DEFAULT_MODELS.gemini;
1350
1361
  out["gemini"] = makeGeminiProvider(model, geminiKey, opts, fallbackModelsFor(opts.env, "gemini"));
1351
1362
  }
@@ -1411,7 +1422,7 @@ import { z } from "zod";
1411
1422
 
1412
1423
  // src/server-meta.ts
1413
1424
  var SERVER_NAME = "crosscheck-agent";
1414
- var SERVER_VERSION = true ? "0.2.22" : "0.0.0-dev";
1425
+ var SERVER_VERSION = true ? "0.2.24" : "0.0.0-dev";
1415
1426
 
1416
1427
  // src/tools/audit.ts
1417
1428
  import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
@@ -9205,6 +9216,63 @@ function isObj6(v) {
9205
9216
  return typeof v === "object" && v !== null && !Array.isArray(v);
9206
9217
  }
9207
9218
 
9219
+ // src/core/debate-compaction.ts
9220
+ var DEFAULT_PRIOR_BUDGET_CHARS = 12e3;
9221
+ function renderTurn(e) {
9222
+ return `[${e.provider} \u2014 round ${e.round}]
9223
+ ${e.response ?? "(error)"}`;
9224
+ }
9225
+ function buildPriorTurns(transcript, opts = {}) {
9226
+ if (transcript.length === 0) {
9227
+ return { body: "", includedTurns: 0, omittedTurns: 0, chars: 0 };
9228
+ }
9229
+ const rendered = transcript.map(renderTurn);
9230
+ const full = rendered.join("\n\n");
9231
+ if (!opts.compress) {
9232
+ return { body: full, includedTurns: transcript.length, omittedTurns: 0, chars: full.length };
9233
+ }
9234
+ const budget = Math.max(0, opts.budgetChars ?? DEFAULT_PRIOR_BUDGET_CHARS);
9235
+ if (full.length <= budget) {
9236
+ return { body: full, includedTurns: transcript.length, omittedTurns: 0, chars: full.length };
9237
+ }
9238
+ const latestRound = Math.max(...transcript.map((e) => e.round));
9239
+ const keep = /* @__PURE__ */ new Set();
9240
+ let spent = 0;
9241
+ for (let i = transcript.length - 1; i >= 0; i -= 1) {
9242
+ const isLatest = transcript[i].round === latestRound;
9243
+ const cost = rendered[i].length + 2;
9244
+ if (isLatest) {
9245
+ keep.add(i);
9246
+ spent += cost;
9247
+ continue;
9248
+ }
9249
+ if (spent + cost > budget) continue;
9250
+ keep.add(i);
9251
+ spent += cost;
9252
+ }
9253
+ const parts = [];
9254
+ let omitted = 0;
9255
+ let pendingGap = 0;
9256
+ for (let i = 0; i < transcript.length; i += 1) {
9257
+ if (keep.has(i)) {
9258
+ if (pendingGap > 0) {
9259
+ parts.push(`[${pendingGap} earlier turn(s) omitted for length]`);
9260
+ pendingGap = 0;
9261
+ }
9262
+ parts.push(rendered[i]);
9263
+ } else {
9264
+ omitted += 1;
9265
+ pendingGap += 1;
9266
+ }
9267
+ }
9268
+ if (pendingGap > 0) parts.push(`[${pendingGap} earlier turn(s) omitted for length]`);
9269
+ const body = parts.join("\n\n");
9270
+ return { body, includedTurns: keep.size, omittedTurns: omitted, chars: body.length };
9271
+ }
9272
+ function buildModeratorTranscript(transcript) {
9273
+ return transcript.map(renderTurn).join("\n\n");
9274
+ }
9275
+
9208
9276
  // src/tools/debate.ts
9209
9277
  import { performance as performance10 } from "perf_hooks";
9210
9278
  var DEFERRED_OPTS4 = [
@@ -9253,6 +9321,9 @@ async function runDebate(args, opts) {
9253
9321
  1,
9254
9322
  Math.trunc(Number(args["max_rounds"] ?? 3)) || 3
9255
9323
  );
9324
+ const compressRounds = args["compress_rounds"] === true;
9325
+ const priorBudgetChars = Math.trunc(Number(args["prior_budget_chars"] ?? DEFAULT_PRIOR_BUDGET_CHARS)) || DEFAULT_PRIOR_BUDGET_CHARS;
9326
+ let compactionMeta = null;
9256
9327
  const sessionId = typeof args["session_id"] === "string" ? args["session_id"] : null;
9257
9328
  const breakerEnv = await maybeBreakerEnvelope(
9258
9329
  opts.storage,
@@ -9363,7 +9434,7 @@ async function runDebate(args, opts) {
9363
9434
  const roundMessages = [
9364
9435
  {
9365
9436
  role: "system",
9366
- content: `You are debating peers from other model families. Round ${rnd}/${maxRounds}. Disagree where warranted, concede where right, and keep replies short and specific.`
9437
+ content: "You are debating peers from other model families. Disagree where warranted, concede where right, and keep replies short and specific."
9367
9438
  }
9368
9439
  ];
9369
9440
  if (context) {
@@ -9375,13 +9446,22 @@ ${context}` });
9375
9446
  TOPIC: ${topic}` : `TOPIC: ${topic}`;
9376
9447
  roundMessages.push({ role: "user", content: topicLine });
9377
9448
  if (transcript.length > 0) {
9378
- const prior = transcript.map(
9379
- (e) => `[${e.provider} \u2014 round ${e.round}]
9380
- ${e.response ?? "(error)"}`
9381
- ).join("\n\n");
9449
+ const prior = buildPriorTurns(transcript, {
9450
+ compress: compressRounds,
9451
+ budgetChars: priorBudgetChars
9452
+ });
9453
+ if (prior.omittedTurns > 0) compactionMeta = {
9454
+ omitted_turns: prior.omittedTurns,
9455
+ included_turns: prior.includedTurns,
9456
+ budget_chars: priorBudgetChars
9457
+ };
9382
9458
  roundMessages.push({ role: "user", content: `PRIOR TURNS:
9383
- ${prior}` });
9459
+ ${prior.body}` });
9384
9460
  }
9461
+ roundMessages.push({
9462
+ role: "user",
9463
+ content: `This is round ${rnd} of ${maxRounds}. Reply for this round.`
9464
+ });
9385
9465
  for (const p of selected) {
9386
9466
  const entry = await callPanelist(p, roundMessages);
9387
9467
  const withRound = { ...entry, round: rnd };
@@ -9429,10 +9509,7 @@ ${prior}` });
9429
9509
  let coReasoned = false;
9430
9510
  if (moderator) {
9431
9511
  const synthProvider = superRequested && opts.providers["anthropic"] ? retargetForSuper(opts.providers["anthropic"]) : upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : moderator;
9432
- const condensed = transcript.map(
9433
- (e) => `[${e.provider} \u2014 round ${e.round}]
9434
- ${e.response ?? "(error)"}`
9435
- ).join("\n\n");
9512
+ const condensed = buildModeratorTranscript(transcript);
9436
9513
  const persona = buildPersonaInjection({
9437
9514
  toolName: "debate",
9438
9515
  prompt: topic,
@@ -9515,6 +9592,7 @@ ${condensed}`
9515
9592
  synthesis
9516
9593
  };
9517
9594
  if (personaMeta && personaMeta.used !== null) result["persona"] = personaMeta;
9595
+ if (compactionMeta) result["round_compaction"] = compactionMeta;
9518
9596
  if (upgraded) {
9519
9597
  result["reasoning_upgrade"] = {
9520
9598
  applied: true,
@@ -11834,7 +11912,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
11834
11912
  var DEFAULT_PACKAGE = "crosscheck-cli";
11835
11913
  var FETCH_TIMEOUT_MS = 3e3;
11836
11914
  function engineVersion() {
11837
- return true ? "0.2.22" : "0.0.0-dev";
11915
+ return true ? "0.2.24" : "0.0.0-dev";
11838
11916
  }
11839
11917
  function defaultUpdateCachePath() {
11840
11918
  const base = process.env["CROSSCHECK_DATA_DIR"] || path9.join(os.homedir() || os.tmpdir(), ".crosscheck");