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.
@@ -1282,7 +1282,7 @@ init_esm_shims();
1282
1282
  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;
1283
1283
  function isCreditsFailure(status, bodyText) {
1284
1284
  if (status === 402) return true;
1285
- if (status === 401 || status === 403 || status === 429 || status === 400) {
1285
+ if (status === 401 || status === 403 || status === 400) {
1286
1286
  return CREDIT_RE.test(bodyText);
1287
1287
  }
1288
1288
  return false;
@@ -1319,7 +1319,7 @@ function httpFailureToProviderError(provider, status, bodyText, retryAfterS, mod
1319
1319
  if (status === 429) {
1320
1320
  return new ProviderError(
1321
1321
  "rate_limit",
1322
- `${provider}: rate limited (HTTP 429). Detail: ${detail}`,
1322
+ `${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}`,
1323
1323
  { status, ...retryAfterS !== void 0 ? { retryAfterS } : {} }
1324
1324
  );
1325
1325
  }
@@ -2109,10 +2109,20 @@ function fallbackModelsFor(env, provider) {
2109
2109
  if (pinned && pinned !== DEFAULT_MODELS[provider]) return [];
2110
2110
  return DEFAULT_FALLBACKS[provider] ?? [];
2111
2111
  }
2112
+ var DEFAULT_EXCLUDED_PROVIDERS = ["mistral", "groq"];
2113
+ function excludedProviders(env) {
2114
+ const parse = (v) => (v ?? "").split(",").map((x) => x.trim().toLowerCase()).filter((x) => x !== "");
2115
+ const excluded = new Set(
2116
+ parse(env["CROSSCHECK_EXCLUDE_PROVIDERS"]).length > 0 ? parse(env["CROSSCHECK_EXCLUDE_PROVIDERS"]) : DEFAULT_EXCLUDED_PROVIDERS
2117
+ );
2118
+ for (const name of parse(env["CROSSCHECK_ENABLE_PROVIDERS"])) excluded.delete(name);
2119
+ return excluded;
2120
+ }
2112
2121
  function buildProviders(opts) {
2113
2122
  const out = {};
2123
+ const excluded = excludedProviders(opts.env);
2114
2124
  const anthropicKey = opts.env["ANTHROPIC_API_KEY"];
2115
- if (anthropicKey) {
2125
+ if (anthropicKey && !excluded.has("anthropic")) {
2116
2126
  const model = opts.env["ANTHROPIC_MODEL"] ?? DEFAULT_MODELS.anthropic;
2117
2127
  out["anthropic"] = makeAnthropicProvider(model, anthropicKey, opts, fallbackModelsFor(opts.env, "anthropic"));
2118
2128
  }
@@ -2128,11 +2138,12 @@ function buildProviders(opts) {
2128
2138
  for (const s of openAiCompatSpec) {
2129
2139
  const apiKey = opts.env[s.keyEnv];
2130
2140
  if (!apiKey) continue;
2141
+ if (excluded.has(s.name)) continue;
2131
2142
  const model = opts.env[s.modelEnv] ?? s.defaultModel;
2132
2143
  out[s.name] = makeOpenAICompatibleProvider(s.name, model, apiKey, opts, fallbackModelsFor(opts.env, s.name));
2133
2144
  }
2134
2145
  const geminiKey = opts.env["GEMINI_API_KEY"];
2135
- if (geminiKey) {
2146
+ if (geminiKey && !excluded.has("gemini")) {
2136
2147
  const model = opts.env["GEMINI_MODEL"] ?? DEFAULT_MODELS.gemini;
2137
2148
  out["gemini"] = makeGeminiProvider(model, geminiKey, opts, fallbackModelsFor(opts.env, "gemini"));
2138
2149
  }
@@ -2331,7 +2342,7 @@ import { z } from "zod";
2331
2342
  // src/server-meta.ts
2332
2343
  init_esm_shims();
2333
2344
  var SERVER_NAME = "crosscheck-agent";
2334
- var SERVER_VERSION = true ? "0.2.22" : "0.0.0-dev";
2345
+ var SERVER_VERSION = true ? "0.2.24" : "0.0.0-dev";
2335
2346
 
2336
2347
  // src/tools/audit.ts
2337
2348
  init_esm_shims();
@@ -10198,6 +10209,66 @@ function isObj6(v) {
10198
10209
 
10199
10210
  // src/tools/debate.ts
10200
10211
  init_esm_shims();
10212
+
10213
+ // src/core/debate-compaction.ts
10214
+ init_esm_shims();
10215
+ var DEFAULT_PRIOR_BUDGET_CHARS = 12e3;
10216
+ function renderTurn(e) {
10217
+ return `[${e.provider} \u2014 round ${e.round}]
10218
+ ${e.response ?? "(error)"}`;
10219
+ }
10220
+ function buildPriorTurns(transcript, opts = {}) {
10221
+ if (transcript.length === 0) {
10222
+ return { body: "", includedTurns: 0, omittedTurns: 0, chars: 0 };
10223
+ }
10224
+ const rendered = transcript.map(renderTurn);
10225
+ const full = rendered.join("\n\n");
10226
+ if (!opts.compress) {
10227
+ return { body: full, includedTurns: transcript.length, omittedTurns: 0, chars: full.length };
10228
+ }
10229
+ const budget = Math.max(0, opts.budgetChars ?? DEFAULT_PRIOR_BUDGET_CHARS);
10230
+ if (full.length <= budget) {
10231
+ return { body: full, includedTurns: transcript.length, omittedTurns: 0, chars: full.length };
10232
+ }
10233
+ const latestRound = Math.max(...transcript.map((e) => e.round));
10234
+ const keep = /* @__PURE__ */ new Set();
10235
+ let spent = 0;
10236
+ for (let i = transcript.length - 1; i >= 0; i -= 1) {
10237
+ const isLatest = transcript[i].round === latestRound;
10238
+ const cost = rendered[i].length + 2;
10239
+ if (isLatest) {
10240
+ keep.add(i);
10241
+ spent += cost;
10242
+ continue;
10243
+ }
10244
+ if (spent + cost > budget) continue;
10245
+ keep.add(i);
10246
+ spent += cost;
10247
+ }
10248
+ const parts = [];
10249
+ let omitted = 0;
10250
+ let pendingGap = 0;
10251
+ for (let i = 0; i < transcript.length; i += 1) {
10252
+ if (keep.has(i)) {
10253
+ if (pendingGap > 0) {
10254
+ parts.push(`[${pendingGap} earlier turn(s) omitted for length]`);
10255
+ pendingGap = 0;
10256
+ }
10257
+ parts.push(rendered[i]);
10258
+ } else {
10259
+ omitted += 1;
10260
+ pendingGap += 1;
10261
+ }
10262
+ }
10263
+ if (pendingGap > 0) parts.push(`[${pendingGap} earlier turn(s) omitted for length]`);
10264
+ const body = parts.join("\n\n");
10265
+ return { body, includedTurns: keep.size, omittedTurns: omitted, chars: body.length };
10266
+ }
10267
+ function buildModeratorTranscript(transcript) {
10268
+ return transcript.map(renderTurn).join("\n\n");
10269
+ }
10270
+
10271
+ // src/tools/debate.ts
10201
10272
  import { performance as performance10 } from "perf_hooks";
10202
10273
  var DEFERRED_OPTS4 = [
10203
10274
  // empty — every debate opt runs natively when its deps
@@ -10245,6 +10316,9 @@ async function runDebate(args, opts) {
10245
10316
  1,
10246
10317
  Math.trunc(Number(args["max_rounds"] ?? 3)) || 3
10247
10318
  );
10319
+ const compressRounds = args["compress_rounds"] === true;
10320
+ const priorBudgetChars = Math.trunc(Number(args["prior_budget_chars"] ?? DEFAULT_PRIOR_BUDGET_CHARS)) || DEFAULT_PRIOR_BUDGET_CHARS;
10321
+ let compactionMeta = null;
10248
10322
  const sessionId = typeof args["session_id"] === "string" ? args["session_id"] : null;
10249
10323
  const breakerEnv = await maybeBreakerEnvelope(
10250
10324
  opts.storage,
@@ -10355,7 +10429,7 @@ async function runDebate(args, opts) {
10355
10429
  const roundMessages = [
10356
10430
  {
10357
10431
  role: "system",
10358
- content: `You are debating peers from other model families. Round ${rnd}/${maxRounds}. Disagree where warranted, concede where right, and keep replies short and specific.`
10432
+ content: "You are debating peers from other model families. Disagree where warranted, concede where right, and keep replies short and specific."
10359
10433
  }
10360
10434
  ];
10361
10435
  if (context) {
@@ -10367,13 +10441,22 @@ ${context}` });
10367
10441
  TOPIC: ${topic}` : `TOPIC: ${topic}`;
10368
10442
  roundMessages.push({ role: "user", content: topicLine });
10369
10443
  if (transcript.length > 0) {
10370
- const prior = transcript.map(
10371
- (e) => `[${e.provider} \u2014 round ${e.round}]
10372
- ${e.response ?? "(error)"}`
10373
- ).join("\n\n");
10444
+ const prior = buildPriorTurns(transcript, {
10445
+ compress: compressRounds,
10446
+ budgetChars: priorBudgetChars
10447
+ });
10448
+ if (prior.omittedTurns > 0) compactionMeta = {
10449
+ omitted_turns: prior.omittedTurns,
10450
+ included_turns: prior.includedTurns,
10451
+ budget_chars: priorBudgetChars
10452
+ };
10374
10453
  roundMessages.push({ role: "user", content: `PRIOR TURNS:
10375
- ${prior}` });
10454
+ ${prior.body}` });
10376
10455
  }
10456
+ roundMessages.push({
10457
+ role: "user",
10458
+ content: `This is round ${rnd} of ${maxRounds}. Reply for this round.`
10459
+ });
10377
10460
  for (const p of selected) {
10378
10461
  const entry = await callPanelist(p, roundMessages);
10379
10462
  const withRound = { ...entry, round: rnd };
@@ -10421,10 +10504,7 @@ ${prior}` });
10421
10504
  let coReasoned = false;
10422
10505
  if (moderator) {
10423
10506
  const synthProvider = superRequested && opts.providers["anthropic"] ? retargetForSuper(opts.providers["anthropic"]) : upgraded ? retargetProvider(opts.providers["anthropic"], UPGRADE_MODEL) : moderator;
10424
- const condensed = transcript.map(
10425
- (e) => `[${e.provider} \u2014 round ${e.round}]
10426
- ${e.response ?? "(error)"}`
10427
- ).join("\n\n");
10507
+ const condensed = buildModeratorTranscript(transcript);
10428
10508
  const persona = buildPersonaInjection({
10429
10509
  toolName: "debate",
10430
10510
  prompt: topic,
@@ -10507,6 +10587,7 @@ ${condensed}`
10507
10587
  synthesis
10508
10588
  };
10509
10589
  if (personaMeta && personaMeta.used !== null) result["persona"] = personaMeta;
10590
+ if (compactionMeta) result["round_compaction"] = compactionMeta;
10510
10591
  if (upgraded) {
10511
10592
  result["reasoning_upgrade"] = {
10512
10593
  applied: true,
@@ -12840,7 +12921,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
12840
12921
  var DEFAULT_PACKAGE = "crosscheck-cli";
12841
12922
  var FETCH_TIMEOUT_MS = 3e3;
12842
12923
  function engineVersion() {
12843
- return true ? "0.2.22" : "0.0.0-dev";
12924
+ return true ? "0.2.24" : "0.0.0-dev";
12844
12925
  }
12845
12926
  function defaultUpdateCachePath() {
12846
12927
  const base = process.env["CROSSCHECK_DATA_DIR"] || path10.join(os.homedir() || os.tmpdir(), ".crosscheck");