crosscheck-mcp 0.2.13 → 0.2.15
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.
- package/dist/browser-ext.cjs +173 -77
- package/dist/browser-ext.cjs.map +1 -1
- package/dist/browser-ext.js +173 -77
- package/dist/browser-ext.js.map +1 -1
- package/dist/node-stdio.cjs +169 -81
- package/dist/node-stdio.cjs.map +1 -1
- package/dist/node-stdio.d.cts +9 -0
- package/dist/node-stdio.d.ts +9 -0
- package/dist/node-stdio.js +166 -78
- package/dist/node-stdio.js.map +1 -1
- package/package.json +1 -1
package/dist/browser-ext.cjs
CHANGED
|
@@ -472,11 +472,18 @@ var ProviderError = class extends Error {
|
|
|
472
472
|
status;
|
|
473
473
|
transient;
|
|
474
474
|
retryAfterS;
|
|
475
|
+
/** True specifically for "the key is fine but this model isn't
|
|
476
|
+
* available to this account/project" (see http-errors.ts's
|
|
477
|
+
* isModelAccessFailure) — the one failure a model fallback chain can
|
|
478
|
+
* actually fix. Distinct from `transient`: this is never worth
|
|
479
|
+
* retrying the SAME model, but IS worth trying a different one. */
|
|
480
|
+
modelAccessFailure;
|
|
475
481
|
constructor(kind, message, opts) {
|
|
476
482
|
super(message);
|
|
477
483
|
this.kind = kind;
|
|
478
484
|
this.status = opts?.status;
|
|
479
485
|
this.transient = opts?.transient ?? defaultTransient(kind);
|
|
486
|
+
this.modelAccessFailure = opts?.modelAccessFailure ?? false;
|
|
480
487
|
if (opts?.retryAfterS !== void 0) {
|
|
481
488
|
this.retryAfterS = opts.retryAfterS;
|
|
482
489
|
}
|
|
@@ -495,8 +502,21 @@ function isCreditsFailure(status, bodyText) {
|
|
|
495
502
|
}
|
|
496
503
|
return false;
|
|
497
504
|
}
|
|
498
|
-
|
|
505
|
+
var MODEL_ACCESS_RE = /model_not_found|does not have access to model|does not exist|model[\s_]not[\s_]found|invalid model|unknown model|unsupported model/i;
|
|
506
|
+
function isModelAccessFailure(status, bodyText) {
|
|
507
|
+
if (status < 400 || status >= 500) return false;
|
|
508
|
+
return MODEL_ACCESS_RE.test(bodyText);
|
|
509
|
+
}
|
|
510
|
+
function httpFailureToProviderError(provider, status, bodyText, retryAfterS, model) {
|
|
499
511
|
const detail = bodyText.slice(0, 512);
|
|
512
|
+
if (isModelAccessFailure(status, bodyText)) {
|
|
513
|
+
const modelRef = model ? `"${model}"` : "the configured model";
|
|
514
|
+
return new ProviderError(
|
|
515
|
+
"client",
|
|
516
|
+
`${provider}: your account/project doesn't have access to ${modelRef} (HTTP ${status}). This is a model-access problem, not a key problem \u2014 your ${provider} API key is fine, ${modelRef} just isn't enabled for this account/project. Fix: run \`crosscheck models set ${provider} <a-model-you-have-access-to>\` (or set ${provider.toUpperCase()}_MODEL in your .env until that's available). Detail: ${detail}`,
|
|
517
|
+
{ status, modelAccessFailure: true }
|
|
518
|
+
);
|
|
519
|
+
}
|
|
500
520
|
if (isCreditsFailure(status, bodyText)) {
|
|
501
521
|
return new ProviderError(
|
|
502
522
|
"auth",
|
|
@@ -701,6 +721,14 @@ function buildAnthropicRequest(opts) {
|
|
|
701
721
|
if (system !== void 0) {
|
|
702
722
|
body.system = system;
|
|
703
723
|
}
|
|
724
|
+
if (isReasoningModel("anthropic", opts.model)) {
|
|
725
|
+
if (opts.model.toLowerCase().startsWith("claude-fable-5")) {
|
|
726
|
+
body.thinking = { type: "adaptive" };
|
|
727
|
+
body.output_config = { effort: "low" };
|
|
728
|
+
} else {
|
|
729
|
+
body.thinking = { type: "disabled" };
|
|
730
|
+
}
|
|
731
|
+
}
|
|
704
732
|
if (opts.jsonSchema) {
|
|
705
733
|
body.tools = [{
|
|
706
734
|
name: ANTHROPIC_STRUCTURED_TOOL_NAME,
|
|
@@ -768,7 +796,12 @@ function parseAnthropicResponse(opts) {
|
|
|
768
796
|
purpose: opts.purpose
|
|
769
797
|
};
|
|
770
798
|
usage.total_tokens = usage.prompt_tokens + usage.completion_tokens;
|
|
771
|
-
|
|
799
|
+
const stopReasonRaw = r["stop_reason"];
|
|
800
|
+
const stopReason = typeof stopReasonRaw === "string" ? stopReasonRaw : void 0;
|
|
801
|
+
return { text, usage, ...stopReason !== void 0 ? { stopReason } : {} };
|
|
802
|
+
}
|
|
803
|
+
function isEmptyDueToMaxTokens(text, stopReason) {
|
|
804
|
+
return text.trim() === "" && stopReason === "max_tokens";
|
|
772
805
|
}
|
|
773
806
|
function applyPricing(usage, pricing) {
|
|
774
807
|
const { cost_usd, estimated } = calculateCost(
|
|
@@ -786,49 +819,64 @@ function applyPricing(usage, pricing) {
|
|
|
786
819
|
estimated: usage.estimated || estimated
|
|
787
820
|
};
|
|
788
821
|
}
|
|
822
|
+
var MAX_TOKENS_ESCALATIONS = 2;
|
|
823
|
+
var ESCALATION_MULTIPLIER = 2;
|
|
789
824
|
async function sendAnthropic(args) {
|
|
790
|
-
const { url, headers, body } = buildAnthropicRequest({
|
|
791
|
-
model: args.model,
|
|
792
|
-
apiKey: args.apiKey,
|
|
793
|
-
messages: args.messages,
|
|
794
|
-
maxTokens: args.maxTokens,
|
|
795
|
-
temperature: args.temperature,
|
|
796
|
-
...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
|
|
797
|
-
});
|
|
798
825
|
const doFetch = args.fetchImpl ?? globalThis.fetch;
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
826
|
+
let maxTokens = args.maxTokens;
|
|
827
|
+
let result = null;
|
|
828
|
+
let totalAttempts = 0;
|
|
829
|
+
for (let escalation = 0; escalation <= MAX_TOKENS_ESCALATIONS; escalation += 1) {
|
|
830
|
+
const { url, headers, body } = buildAnthropicRequest({
|
|
831
|
+
model: args.model,
|
|
832
|
+
apiKey: args.apiKey,
|
|
833
|
+
messages: args.messages,
|
|
834
|
+
maxTokens,
|
|
835
|
+
temperature: args.temperature,
|
|
836
|
+
...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
|
|
837
|
+
});
|
|
838
|
+
const init = {
|
|
839
|
+
method: "POST",
|
|
840
|
+
headers,
|
|
841
|
+
body: JSON.stringify(body)
|
|
842
|
+
};
|
|
843
|
+
if (args.signal) init.signal = args.signal;
|
|
844
|
+
let stopReason;
|
|
845
|
+
const attemptOnce = async () => {
|
|
846
|
+
let respLike;
|
|
815
847
|
try {
|
|
816
|
-
|
|
848
|
+
respLike = await doFetch(url, init);
|
|
817
849
|
} catch (e) {
|
|
818
|
-
throw new ProviderError("
|
|
850
|
+
throw new ProviderError("network", `anthropic: fetch failed: ${e.message}`);
|
|
819
851
|
}
|
|
820
|
-
const
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
852
|
+
const status = respLike.status;
|
|
853
|
+
if (status >= 200 && status < 300) {
|
|
854
|
+
let parsed;
|
|
855
|
+
try {
|
|
856
|
+
parsed = await respLike.json();
|
|
857
|
+
} catch (e) {
|
|
858
|
+
throw new ProviderError("parse", `anthropic: response body not JSON: ${e.message}`);
|
|
859
|
+
}
|
|
860
|
+
const { text, usage, stopReason: sr } = parseAnthropicResponse({
|
|
861
|
+
resp: parsed,
|
|
862
|
+
model: args.model,
|
|
863
|
+
purpose: args.purpose ?? "worker"
|
|
864
|
+
});
|
|
865
|
+
stopReason = sr;
|
|
866
|
+
return { text, attempts: 1, usage: applyPricing(usage, args.pricing) };
|
|
867
|
+
}
|
|
868
|
+
const bodyText = await respLike.text().catch(() => "");
|
|
869
|
+
throw httpFailureToProviderError("anthropic", status, bodyText, parseRetryAfter(respLike), args.model);
|
|
870
|
+
};
|
|
871
|
+
await acquireRateLimit("anthropic", args.signal ? { signal: args.signal } : void 0);
|
|
872
|
+
result = await sendWithRetry(attemptOnce, resolveRetryConfig(), args.signal);
|
|
873
|
+
totalAttempts += result.attempts;
|
|
874
|
+
if (escalation >= MAX_TOKENS_ESCALATIONS || !isEmptyDueToMaxTokens(result.text, stopReason)) {
|
|
875
|
+
break;
|
|
826
876
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
};
|
|
830
|
-
await acquireRateLimit("anthropic", args.signal ? { signal: args.signal } : void 0);
|
|
831
|
-
return sendWithRetry(attemptOnce, resolveRetryConfig(), args.signal);
|
|
877
|
+
maxTokens *= ESCALATION_MULTIPLIER;
|
|
878
|
+
}
|
|
879
|
+
return { ...result, attempts: totalAttempts };
|
|
832
880
|
}
|
|
833
881
|
|
|
834
882
|
// src/providers/gemini.ts
|
|
@@ -1003,7 +1051,7 @@ async function sendGemini(args) {
|
|
|
1003
1051
|
return { text, attempts: 1, usage: applyPricing2(usage, args.pricing) };
|
|
1004
1052
|
}
|
|
1005
1053
|
const bodyText = await respLike.text().catch(() => "");
|
|
1006
|
-
throw httpFailureToProviderError("gemini", status, bodyText, parseRetryAfter(respLike));
|
|
1054
|
+
throw httpFailureToProviderError("gemini", status, bodyText, parseRetryAfter(respLike), args.model);
|
|
1007
1055
|
};
|
|
1008
1056
|
await acquireRateLimit("gemini", args.signal ? { signal: args.signal } : void 0);
|
|
1009
1057
|
return sendWithRetry(attemptOnce, resolveRetryConfig(), args.signal);
|
|
@@ -1176,7 +1224,7 @@ async function sendOpenAICompatible(args) {
|
|
|
1176
1224
|
return { text, attempts: 1, usage: applyPricing3(usage, args.pricing) };
|
|
1177
1225
|
}
|
|
1178
1226
|
const bodyText = await respLike.text().catch(() => "");
|
|
1179
|
-
throw httpFailureToProviderError(args.provider, status, bodyText, parseRetryAfter(respLike));
|
|
1227
|
+
throw httpFailureToProviderError(args.provider, status, bodyText, parseRetryAfter(respLike), args.model);
|
|
1180
1228
|
};
|
|
1181
1229
|
await acquireRateLimit(args.provider, args.signal ? { signal: args.signal } : void 0);
|
|
1182
1230
|
return sendWithRetry(attemptOnce, resolveRetryConfig(), args.signal);
|
|
@@ -1185,7 +1233,10 @@ async function sendOpenAICompatible(args) {
|
|
|
1185
1233
|
// src/providers/registry.ts
|
|
1186
1234
|
var DEFAULT_MODELS = {
|
|
1187
1235
|
anthropic: "claude-opus-5",
|
|
1188
|
-
|
|
1236
|
+
// gpt-5.5 is not enabled on every OpenAI account/project (some are still
|
|
1237
|
+
// capped at gpt-5) — gpt-5 is the safer, more broadly available default
|
|
1238
|
+
// until a user/org explicitly opts into 5.5 via `crosscheck models set`.
|
|
1239
|
+
openai: "gpt-5",
|
|
1189
1240
|
xai: "grok-4-latest",
|
|
1190
1241
|
mistral: "mistral-large-latest",
|
|
1191
1242
|
groq: "llama-3.3-70b-versatile",
|
|
@@ -1194,12 +1245,31 @@ var DEFAULT_MODELS = {
|
|
|
1194
1245
|
kimi: "kimi-k3",
|
|
1195
1246
|
qwen: "qwen3.8-max"
|
|
1196
1247
|
};
|
|
1248
|
+
var MODEL_ENV_VARS = {
|
|
1249
|
+
anthropic: "ANTHROPIC_MODEL",
|
|
1250
|
+
openai: "OPENAI_MODEL",
|
|
1251
|
+
xai: "XAI_MODEL",
|
|
1252
|
+
mistral: "MISTRAL_MODEL",
|
|
1253
|
+
groq: "GROQ_MODEL",
|
|
1254
|
+
deepseek: "DEEPSEEK_MODEL",
|
|
1255
|
+
gemini: "GEMINI_MODEL",
|
|
1256
|
+
kimi: "KIMI_MODEL",
|
|
1257
|
+
qwen: "QWEN_MODEL"
|
|
1258
|
+
};
|
|
1259
|
+
function parseFallbackModels(raw) {
|
|
1260
|
+
if (!raw) return [];
|
|
1261
|
+
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1262
|
+
}
|
|
1263
|
+
function fallbackModelsFor(env, provider) {
|
|
1264
|
+
const envVar = MODEL_ENV_VARS[provider];
|
|
1265
|
+
return envVar ? parseFallbackModels(env[`${envVar}_FALLBACKS`]) : [];
|
|
1266
|
+
}
|
|
1197
1267
|
function buildProviders(opts) {
|
|
1198
1268
|
const out = {};
|
|
1199
1269
|
const anthropicKey = opts.env["ANTHROPIC_API_KEY"];
|
|
1200
1270
|
if (anthropicKey) {
|
|
1201
1271
|
const model = opts.env["ANTHROPIC_MODEL"] ?? DEFAULT_MODELS.anthropic;
|
|
1202
|
-
out["anthropic"] = makeAnthropicProvider(model, anthropicKey, opts);
|
|
1272
|
+
out["anthropic"] = makeAnthropicProvider(model, anthropicKey, opts, fallbackModelsFor(opts.env, "anthropic"));
|
|
1203
1273
|
}
|
|
1204
1274
|
const openAiCompatSpec = [
|
|
1205
1275
|
{ name: "openai", keyEnv: "OPENAI_API_KEY", modelEnv: "OPENAI_MODEL", defaultModel: DEFAULT_MODELS["openai"] },
|
|
@@ -1214,19 +1284,20 @@ function buildProviders(opts) {
|
|
|
1214
1284
|
const apiKey = opts.env[s.keyEnv];
|
|
1215
1285
|
if (!apiKey) continue;
|
|
1216
1286
|
const model = opts.env[s.modelEnv] ?? s.defaultModel;
|
|
1217
|
-
out[s.name] = makeOpenAICompatibleProvider(s.name, model, apiKey, opts);
|
|
1287
|
+
out[s.name] = makeOpenAICompatibleProvider(s.name, model, apiKey, opts, fallbackModelsFor(opts.env, s.name));
|
|
1218
1288
|
}
|
|
1219
1289
|
const geminiKey = opts.env["GEMINI_API_KEY"];
|
|
1220
1290
|
if (geminiKey) {
|
|
1221
1291
|
const model = opts.env["GEMINI_MODEL"] ?? DEFAULT_MODELS.gemini;
|
|
1222
|
-
out["gemini"] = makeGeminiProvider(model, geminiKey, opts);
|
|
1292
|
+
out["gemini"] = makeGeminiProvider(model, geminiKey, opts, fallbackModelsFor(opts.env, "gemini"));
|
|
1223
1293
|
}
|
|
1224
1294
|
return out;
|
|
1225
1295
|
}
|
|
1226
|
-
function makeAnthropicProvider(model, apiKey, opts) {
|
|
1296
|
+
function makeAnthropicProvider(model, apiKey, opts, fallbackModels = []) {
|
|
1227
1297
|
return {
|
|
1228
1298
|
name: "anthropic",
|
|
1229
1299
|
model,
|
|
1300
|
+
fallbackModels,
|
|
1230
1301
|
send: async (args) => {
|
|
1231
1302
|
const sendOpts = {
|
|
1232
1303
|
...args,
|
|
@@ -1239,11 +1310,12 @@ function makeAnthropicProvider(model, apiKey, opts) {
|
|
|
1239
1310
|
}
|
|
1240
1311
|
};
|
|
1241
1312
|
}
|
|
1242
|
-
function makeOpenAICompatibleProvider(name, model, apiKey, opts) {
|
|
1313
|
+
function makeOpenAICompatibleProvider(name, model, apiKey, opts, fallbackModels = []) {
|
|
1243
1314
|
const url = OPENAI_COMPAT_DEFAULT_URLS[name];
|
|
1244
1315
|
return {
|
|
1245
1316
|
name,
|
|
1246
1317
|
model,
|
|
1318
|
+
fallbackModels,
|
|
1247
1319
|
send: async (args) => {
|
|
1248
1320
|
const sendOpts = {
|
|
1249
1321
|
...args,
|
|
@@ -1258,10 +1330,11 @@ function makeOpenAICompatibleProvider(name, model, apiKey, opts) {
|
|
|
1258
1330
|
}
|
|
1259
1331
|
};
|
|
1260
1332
|
}
|
|
1261
|
-
function makeGeminiProvider(model, apiKey, opts) {
|
|
1333
|
+
function makeGeminiProvider(model, apiKey, opts, fallbackModels = []) {
|
|
1262
1334
|
return {
|
|
1263
1335
|
name: "gemini",
|
|
1264
1336
|
model,
|
|
1337
|
+
fallbackModels,
|
|
1265
1338
|
send: async (args) => {
|
|
1266
1339
|
const sendOpts = {
|
|
1267
1340
|
...args,
|
|
@@ -1280,7 +1353,7 @@ var import_zod = require("zod");
|
|
|
1280
1353
|
|
|
1281
1354
|
// src/server-meta.ts
|
|
1282
1355
|
var SERVER_NAME = "crosscheck-agent";
|
|
1283
|
-
var SERVER_VERSION = true ? "0.2.
|
|
1356
|
+
var SERVER_VERSION = true ? "0.2.15" : "0.0.0-dev";
|
|
1284
1357
|
|
|
1285
1358
|
// src/tools/audit.ts
|
|
1286
1359
|
var import_node_fs4 = require("fs");
|
|
@@ -1931,6 +2004,51 @@ function operatorCeiling(purpose, provider) {
|
|
|
1931
2004
|
return null;
|
|
1932
2005
|
}
|
|
1933
2006
|
|
|
2007
|
+
// src/core/retarget.ts
|
|
2008
|
+
function retargetProvider(p, newModel) {
|
|
2009
|
+
if (p.model === newModel) return p;
|
|
2010
|
+
return {
|
|
2011
|
+
name: p.name,
|
|
2012
|
+
model: newModel,
|
|
2013
|
+
send: (args) => p.send({ ...args, modelOverride: newModel })
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
async function loadProviderWeights(storage, names) {
|
|
2017
|
+
const out = {};
|
|
2018
|
+
for (const raw of names) {
|
|
2019
|
+
const name = raw.toLowerCase();
|
|
2020
|
+
if (name in out) continue;
|
|
2021
|
+
const row = await storage.getProviderStats(name);
|
|
2022
|
+
if (!row) {
|
|
2023
|
+
out[name] = 0.5;
|
|
2024
|
+
continue;
|
|
2025
|
+
}
|
|
2026
|
+
const total = row.wins + row.losses + row.abstains;
|
|
2027
|
+
out[name] = total <= 0 ? 0.5 : (row.wins + 0.5 * row.abstains) / total;
|
|
2028
|
+
}
|
|
2029
|
+
return out;
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
// src/core/model-fallback.ts
|
|
2033
|
+
async function sendWithModelFallback(provider, args) {
|
|
2034
|
+
const chain = [provider.model, ...provider.fallbackModels ?? []];
|
|
2035
|
+
let lastErr;
|
|
2036
|
+
for (let i = 0; i < chain.length; i += 1) {
|
|
2037
|
+
const candidate = chain[i];
|
|
2038
|
+
const p = i === 0 ? provider : retargetProvider(provider, candidate);
|
|
2039
|
+
try {
|
|
2040
|
+
const result = await p.send(args);
|
|
2041
|
+
return { result, modelUsed: candidate };
|
|
2042
|
+
} catch (e) {
|
|
2043
|
+
lastErr = e;
|
|
2044
|
+
const isModelAccessFailure2 = e instanceof ProviderError && e.modelAccessFailure;
|
|
2045
|
+
const hasMoreCandidates = i < chain.length - 1;
|
|
2046
|
+
if (!isModelAccessFailure2 || !hasMoreCandidates) throw e;
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
throw lastErr;
|
|
2050
|
+
}
|
|
2051
|
+
|
|
1934
2052
|
// src/core/structured.ts
|
|
1935
2053
|
async function requestStructured(provider, baseMessages, schema, opts) {
|
|
1936
2054
|
const maxRetries = opts.maxRetries ?? 1;
|
|
@@ -2009,7 +2127,7 @@ async function askOne(provider, messages, opts) {
|
|
|
2009
2127
|
const ceiling = operatorCeiling(opts.purpose, provider.name);
|
|
2010
2128
|
if (ceiling !== null && ceiling < maxTokens) maxTokens = ceiling;
|
|
2011
2129
|
try {
|
|
2012
|
-
const r = await provider
|
|
2130
|
+
const { result: r, modelUsed } = await sendWithModelFallback(provider, {
|
|
2013
2131
|
messages,
|
|
2014
2132
|
maxTokens,
|
|
2015
2133
|
temperature: opts.temperature,
|
|
@@ -2022,7 +2140,10 @@ async function askOne(provider, messages, opts) {
|
|
|
2022
2140
|
const cpuMs = Math.trunc((cpu.user + cpu.system) / 1e3);
|
|
2023
2141
|
return {
|
|
2024
2142
|
provider: provider.name,
|
|
2025
|
-
model
|
|
2143
|
+
// modelUsed reflects whichever model actually answered — the
|
|
2144
|
+
// primary, or a fallback if one was needed. Equivalent to the old
|
|
2145
|
+
// `provider.model` whenever no fallback occurred.
|
|
2146
|
+
model: modelUsed,
|
|
2026
2147
|
response: r.text,
|
|
2027
2148
|
attempts: r.attempts,
|
|
2028
2149
|
usage: r.usage,
|
|
@@ -2732,31 +2853,6 @@ function numberOrNull(v) {
|
|
|
2732
2853
|
// src/tools/audit.ts
|
|
2733
2854
|
var import_node_perf_hooks = require("perf_hooks");
|
|
2734
2855
|
|
|
2735
|
-
// src/core/retarget.ts
|
|
2736
|
-
function retargetProvider(p, newModel) {
|
|
2737
|
-
if (p.model === newModel) return p;
|
|
2738
|
-
return {
|
|
2739
|
-
name: p.name,
|
|
2740
|
-
model: newModel,
|
|
2741
|
-
send: (args) => p.send({ ...args, modelOverride: newModel })
|
|
2742
|
-
};
|
|
2743
|
-
}
|
|
2744
|
-
async function loadProviderWeights(storage, names) {
|
|
2745
|
-
const out = {};
|
|
2746
|
-
for (const raw of names) {
|
|
2747
|
-
const name = raw.toLowerCase();
|
|
2748
|
-
if (name in out) continue;
|
|
2749
|
-
const row = await storage.getProviderStats(name);
|
|
2750
|
-
if (!row) {
|
|
2751
|
-
out[name] = 0.5;
|
|
2752
|
-
continue;
|
|
2753
|
-
}
|
|
2754
|
-
const total = row.wins + row.losses + row.abstains;
|
|
2755
|
-
out[name] = total <= 0 ? 0.5 : (row.wins + 0.5 * row.abstains) / total;
|
|
2756
|
-
}
|
|
2757
|
-
return out;
|
|
2758
|
-
}
|
|
2759
|
-
|
|
2760
2856
|
// src/core/co-reason.ts
|
|
2761
2857
|
var CO_REASON_MODEL = "gpt-5.6";
|
|
2762
2858
|
var CO_REASON_PROVIDER = "openai";
|
|
@@ -11490,7 +11586,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
|
|
|
11490
11586
|
var DEFAULT_PACKAGE = "crosscheck-cli";
|
|
11491
11587
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
11492
11588
|
function engineVersion() {
|
|
11493
|
-
return true ? "0.2.
|
|
11589
|
+
return true ? "0.2.15" : "0.0.0-dev";
|
|
11494
11590
|
}
|
|
11495
11591
|
function defaultUpdateCachePath() {
|
|
11496
11592
|
const base = process.env["CROSSCHECK_DATA_DIR"] || import_node_path12.default.join(import_node_os2.default.homedir() || import_node_os2.default.tmpdir(), ".crosscheck");
|