crosscheck-mcp 0.2.19 → 0.2.21

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.
@@ -1192,7 +1192,13 @@ var PROVIDER_CAPS = {
1192
1192
  family: "openai_chat",
1193
1193
  system_role: "inline",
1194
1194
  supports_temperature: "model",
1195
- reasoning_prefixes: ["gpt-5", "o1", "o3", "o4"]
1195
+ // gpt-6 added 2026-09-06: GPT-6 Astra rejects `max_tokens` outright
1196
+ // ("Unsupported parameter ... use max_completion_tokens"), which is a 400,
1197
+ // NOT a model-access failure — so the fallback chain correctly declines to
1198
+ // fire and the provider silently drops out of the panel instead. Reasoning
1199
+ // -class routing is what selects max_completion_tokens and omits
1200
+ // temperature, so the prefix is the fix.
1201
+ reasoning_prefixes: ["gpt-5", "gpt-6", "o1", "o3", "o4"]
1196
1202
  },
1197
1203
  xai: { family: "openai_chat", system_role: "inline", supports_temperature: true },
1198
1204
  mistral: { family: "openai_chat", system_role: "inline", supports_temperature: true },
@@ -1248,12 +1254,20 @@ var ProviderError = class extends Error {
1248
1254
  * actually fix. Distinct from `transient`: this is never worth
1249
1255
  * retrying the SAME model, but IS worth trying a different one. */
1250
1256
  modelAccessFailure;
1257
+ /** True for "the key works, the account is out of credit / over a spend
1258
+ * limit." Rides alongside kind "auth" rather than replacing it, because
1259
+ * every retry and fallback decision downstream is already tuned to that
1260
+ * kind — but the two are completely different things to a human, and
1261
+ * reporting "API key rejected" for an unpaid invoice sends people to
1262
+ * regenerate a key that was never the problem. */
1263
+ billing;
1251
1264
  constructor(kind, message, opts) {
1252
1265
  super(message);
1253
1266
  this.kind = kind;
1254
1267
  this.status = opts?.status;
1255
1268
  this.transient = opts?.transient ?? defaultTransient(kind);
1256
1269
  this.modelAccessFailure = opts?.modelAccessFailure ?? false;
1270
+ this.billing = opts?.billing ?? false;
1257
1271
  if (opts?.retryAfterS !== void 0) {
1258
1272
  this.retryAfterS = opts.retryAfterS;
1259
1273
  }
@@ -1292,7 +1306,7 @@ function httpFailureToProviderError(provider, status, bodyText, retryAfterS, mod
1292
1306
  return new ProviderError(
1293
1307
  "auth",
1294
1308
  `${provider}: out of credits or billing isn't set up (HTTP ${status}). Your API key is reaching ${provider}, but the account has no usable balance \u2014 add credits / enable billing in your ${provider} console, then retry. Detail: ${detail}`,
1295
- { status }
1309
+ { status, billing: true }
1296
1310
  );
1297
1311
  }
1298
1312
  if (status === 401 || status === 403) {
@@ -2286,7 +2300,7 @@ var import_zod = require("zod");
2286
2300
  // src/server-meta.ts
2287
2301
  init_cjs_shims();
2288
2302
  var SERVER_NAME = "crosscheck-agent";
2289
- var SERVER_VERSION = true ? "0.2.19" : "0.0.0-dev";
2303
+ var SERVER_VERSION = true ? "0.2.21" : "0.0.0-dev";
2290
2304
 
2291
2305
  // src/tools/audit.ts
2292
2306
  init_cjs_shims();
@@ -2799,7 +2813,9 @@ async function attachUsageBlock(result, answers, opts) {
2799
2813
  purpose: a.usage?.purpose ?? null,
2800
2814
  wall_ms: a.elapsed_ms ?? 0,
2801
2815
  cpu_ms: a.cpu_ms ?? 0,
2802
- cache_hit: Boolean(a.cache_hit)
2816
+ cache_hit: Boolean(a.cache_hit),
2817
+ ...a.error_kind ? { error_kind: a.error_kind } : {},
2818
+ ...a.error_billing ? { error_billing: true } : {}
2803
2819
  }))
2804
2820
  };
2805
2821
  result["timing"] = timing;
@@ -3108,11 +3124,13 @@ async function askOne(provider, messages, opts) {
3108
3124
  const cpuMs = Math.trunc((cpu.user + cpu.system) / 1e3);
3109
3125
  const kind = e instanceof ProviderError ? e.kind : "other";
3110
3126
  const msg = e instanceof Error ? e.message : String(e);
3127
+ const billing = e instanceof ProviderError && e.billing;
3111
3128
  return {
3112
3129
  provider: provider.name,
3113
3130
  model: provider.model,
3114
3131
  error: msg,
3115
3132
  error_kind: kind,
3133
+ ...billing ? { error_billing: true } : {},
3116
3134
  attempts: 0,
3117
3135
  usage: emptyUsage(provider.name, provider.model, opts.purpose),
3118
3136
  cache_hit: false,
@@ -12774,7 +12792,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
12774
12792
  var DEFAULT_PACKAGE = "crosscheck-cli";
12775
12793
  var FETCH_TIMEOUT_MS = 3e3;
12776
12794
  function engineVersion() {
12777
- return true ? "0.2.19" : "0.0.0-dev";
12795
+ return true ? "0.2.21" : "0.0.0-dev";
12778
12796
  }
12779
12797
  function defaultUpdateCachePath() {
12780
12798
  const base = process.env["CROSSCHECK_DATA_DIR"] || import_node_path13.default.join(import_node_os2.default.homedir() || import_node_os2.default.tmpdir(), ".crosscheck");
@@ -14789,6 +14807,23 @@ function getConfig2() {
14789
14807
  config = { url, seatId, orgId, seatKey };
14790
14808
  return config;
14791
14809
  }
14810
+ function errorClassFor(kind) {
14811
+ switch (kind) {
14812
+ case "auth":
14813
+ return "auth";
14814
+ case "rate_limit":
14815
+ return "rate_limit";
14816
+ case "timeout":
14817
+ return "timeout";
14818
+ case "server":
14819
+ return "server";
14820
+ // network/parse/client/other all mean "we don't know that the key is
14821
+ // bad", and guessing wrong here is what produces a dashboard that cries
14822
+ // wolf. Say unknown.
14823
+ default:
14824
+ return "unknown";
14825
+ }
14826
+ }
14792
14827
  function intNonNeg(v) {
14793
14828
  const n = Math.trunc(Number(v));
14794
14829
  return Number.isFinite(n) && n > 0 ? n : 0;
@@ -14796,12 +14831,14 @@ function intNonNeg(v) {
14796
14831
  function usageEventsFromEnvelope(out, toolName) {
14797
14832
  if (!out || typeof out !== "object" || Array.isArray(out)) return [];
14798
14833
  const usage = out["usage"];
14799
- if (!usage || typeof usage !== "object") return [];
14800
- const byCall = usage["by_call"];
14801
- if (!Array.isArray(byCall) || byCall.length === 0) return [];
14834
+ const rawByCall = usage && typeof usage === "object" ? usage["by_call"] : void 0;
14835
+ const byCall = Array.isArray(rawByCall) ? rawByCall : [];
14802
14836
  const timing = out["timing"];
14803
14837
  const timingByCall = timing && typeof timing === "object" ? timing["by_call"] : void 0;
14804
- const latencies = Array.isArray(timingByCall) ? timingByCall : [];
14838
+ const allTiming = Array.isArray(timingByCall) ? timingByCall : [];
14839
+ const latencies = allTiming.filter(
14840
+ (t) => !t?.["error_kind"]
14841
+ );
14805
14842
  const aligned = latencies.length === byCall.length;
14806
14843
  const pattern = toolToPattern(toolName);
14807
14844
  const events = [];
@@ -14826,6 +14863,28 @@ function usageEventsFromEnvelope(out, toolName) {
14826
14863
  purpose: normalizePurpose(u.purpose)
14827
14864
  });
14828
14865
  }
14866
+ for (const t of allTiming) {
14867
+ const row = t;
14868
+ const kind = row["error_kind"];
14869
+ if (!kind) continue;
14870
+ const provider = providerToSchema(String(row["provider"] ?? ""));
14871
+ if (!provider) continue;
14872
+ events.push({
14873
+ provider,
14874
+ model: String(row["model"] ?? "").slice(0, 128) || "unknown",
14875
+ pattern,
14876
+ // A failure consumed no tokens and cost nothing. Recording it with a
14877
+ // nonzero cost would corrupt the per-feature ledger with money nobody
14878
+ // spent.
14879
+ promptTokens: 0,
14880
+ completionTokens: 0,
14881
+ costUsdEstimate: 0,
14882
+ latencyMs: intNonNeg(row["wall_ms"]),
14883
+ status: "error",
14884
+ errorClass: row["error_billing"] ? "auth" : errorClassFor(String(kind)),
14885
+ purpose: normalizePurpose(row["purpose"])
14886
+ });
14887
+ }
14829
14888
  return events;
14830
14889
  }
14831
14890
  var queue = [];
@@ -14852,6 +14911,10 @@ function enqueue(cfg2, input, runId, fingerprint) {
14852
14911
  costUsdEstimate: input.costUsdEstimate,
14853
14912
  latencyMs: input.latencyMs,
14854
14913
  status: input.status,
14914
+ // Only present on failures. The canonical body renders an absent
14915
+ // errorClass as "", so omitting and sending "" sign identically — but
14916
+ // omitting keeps the JSON honest about what we actually know.
14917
+ ...input.errorClass === void 0 ? {} : { errorClass: input.errorClass },
14855
14918
  runId,
14856
14919
  // Omit entirely (not "") when unknown, so the canonical body stays
14857
14920
  // consistent with what the server reconstructs from the JSON.