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.js
CHANGED
|
@@ -439,11 +439,18 @@ var ProviderError = class extends Error {
|
|
|
439
439
|
status;
|
|
440
440
|
transient;
|
|
441
441
|
retryAfterS;
|
|
442
|
+
/** True specifically for "the key is fine but this model isn't
|
|
443
|
+
* available to this account/project" (see http-errors.ts's
|
|
444
|
+
* isModelAccessFailure) — the one failure a model fallback chain can
|
|
445
|
+
* actually fix. Distinct from `transient`: this is never worth
|
|
446
|
+
* retrying the SAME model, but IS worth trying a different one. */
|
|
447
|
+
modelAccessFailure;
|
|
442
448
|
constructor(kind, message, opts) {
|
|
443
449
|
super(message);
|
|
444
450
|
this.kind = kind;
|
|
445
451
|
this.status = opts?.status;
|
|
446
452
|
this.transient = opts?.transient ?? defaultTransient(kind);
|
|
453
|
+
this.modelAccessFailure = opts?.modelAccessFailure ?? false;
|
|
447
454
|
if (opts?.retryAfterS !== void 0) {
|
|
448
455
|
this.retryAfterS = opts.retryAfterS;
|
|
449
456
|
}
|
|
@@ -462,8 +469,21 @@ function isCreditsFailure(status, bodyText) {
|
|
|
462
469
|
}
|
|
463
470
|
return false;
|
|
464
471
|
}
|
|
465
|
-
|
|
472
|
+
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;
|
|
473
|
+
function isModelAccessFailure(status, bodyText) {
|
|
474
|
+
if (status < 400 || status >= 500) return false;
|
|
475
|
+
return MODEL_ACCESS_RE.test(bodyText);
|
|
476
|
+
}
|
|
477
|
+
function httpFailureToProviderError(provider, status, bodyText, retryAfterS, model) {
|
|
466
478
|
const detail = bodyText.slice(0, 512);
|
|
479
|
+
if (isModelAccessFailure(status, bodyText)) {
|
|
480
|
+
const modelRef = model ? `"${model}"` : "the configured model";
|
|
481
|
+
return new ProviderError(
|
|
482
|
+
"client",
|
|
483
|
+
`${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}`,
|
|
484
|
+
{ status, modelAccessFailure: true }
|
|
485
|
+
);
|
|
486
|
+
}
|
|
467
487
|
if (isCreditsFailure(status, bodyText)) {
|
|
468
488
|
return new ProviderError(
|
|
469
489
|
"auth",
|
|
@@ -668,6 +688,14 @@ function buildAnthropicRequest(opts) {
|
|
|
668
688
|
if (system !== void 0) {
|
|
669
689
|
body.system = system;
|
|
670
690
|
}
|
|
691
|
+
if (isReasoningModel("anthropic", opts.model)) {
|
|
692
|
+
if (opts.model.toLowerCase().startsWith("claude-fable-5")) {
|
|
693
|
+
body.thinking = { type: "adaptive" };
|
|
694
|
+
body.output_config = { effort: "low" };
|
|
695
|
+
} else {
|
|
696
|
+
body.thinking = { type: "disabled" };
|
|
697
|
+
}
|
|
698
|
+
}
|
|
671
699
|
if (opts.jsonSchema) {
|
|
672
700
|
body.tools = [{
|
|
673
701
|
name: ANTHROPIC_STRUCTURED_TOOL_NAME,
|
|
@@ -735,7 +763,12 @@ function parseAnthropicResponse(opts) {
|
|
|
735
763
|
purpose: opts.purpose
|
|
736
764
|
};
|
|
737
765
|
usage.total_tokens = usage.prompt_tokens + usage.completion_tokens;
|
|
738
|
-
|
|
766
|
+
const stopReasonRaw = r["stop_reason"];
|
|
767
|
+
const stopReason = typeof stopReasonRaw === "string" ? stopReasonRaw : void 0;
|
|
768
|
+
return { text, usage, ...stopReason !== void 0 ? { stopReason } : {} };
|
|
769
|
+
}
|
|
770
|
+
function isEmptyDueToMaxTokens(text, stopReason) {
|
|
771
|
+
return text.trim() === "" && stopReason === "max_tokens";
|
|
739
772
|
}
|
|
740
773
|
function applyPricing(usage, pricing) {
|
|
741
774
|
const { cost_usd, estimated } = calculateCost(
|
|
@@ -753,49 +786,64 @@ function applyPricing(usage, pricing) {
|
|
|
753
786
|
estimated: usage.estimated || estimated
|
|
754
787
|
};
|
|
755
788
|
}
|
|
789
|
+
var MAX_TOKENS_ESCALATIONS = 2;
|
|
790
|
+
var ESCALATION_MULTIPLIER = 2;
|
|
756
791
|
async function sendAnthropic(args) {
|
|
757
|
-
const { url, headers, body } = buildAnthropicRequest({
|
|
758
|
-
model: args.model,
|
|
759
|
-
apiKey: args.apiKey,
|
|
760
|
-
messages: args.messages,
|
|
761
|
-
maxTokens: args.maxTokens,
|
|
762
|
-
temperature: args.temperature,
|
|
763
|
-
...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
|
|
764
|
-
});
|
|
765
792
|
const doFetch = args.fetchImpl ?? globalThis.fetch;
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
793
|
+
let maxTokens = args.maxTokens;
|
|
794
|
+
let result = null;
|
|
795
|
+
let totalAttempts = 0;
|
|
796
|
+
for (let escalation = 0; escalation <= MAX_TOKENS_ESCALATIONS; escalation += 1) {
|
|
797
|
+
const { url, headers, body } = buildAnthropicRequest({
|
|
798
|
+
model: args.model,
|
|
799
|
+
apiKey: args.apiKey,
|
|
800
|
+
messages: args.messages,
|
|
801
|
+
maxTokens,
|
|
802
|
+
temperature: args.temperature,
|
|
803
|
+
...args.jsonSchema ? { jsonSchema: args.jsonSchema } : {}
|
|
804
|
+
});
|
|
805
|
+
const init = {
|
|
806
|
+
method: "POST",
|
|
807
|
+
headers,
|
|
808
|
+
body: JSON.stringify(body)
|
|
809
|
+
};
|
|
810
|
+
if (args.signal) init.signal = args.signal;
|
|
811
|
+
let stopReason;
|
|
812
|
+
const attemptOnce = async () => {
|
|
813
|
+
let respLike;
|
|
782
814
|
try {
|
|
783
|
-
|
|
815
|
+
respLike = await doFetch(url, init);
|
|
784
816
|
} catch (e) {
|
|
785
|
-
throw new ProviderError("
|
|
817
|
+
throw new ProviderError("network", `anthropic: fetch failed: ${e.message}`);
|
|
786
818
|
}
|
|
787
|
-
const
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
819
|
+
const status = respLike.status;
|
|
820
|
+
if (status >= 200 && status < 300) {
|
|
821
|
+
let parsed;
|
|
822
|
+
try {
|
|
823
|
+
parsed = await respLike.json();
|
|
824
|
+
} catch (e) {
|
|
825
|
+
throw new ProviderError("parse", `anthropic: response body not JSON: ${e.message}`);
|
|
826
|
+
}
|
|
827
|
+
const { text, usage, stopReason: sr } = parseAnthropicResponse({
|
|
828
|
+
resp: parsed,
|
|
829
|
+
model: args.model,
|
|
830
|
+
purpose: args.purpose ?? "worker"
|
|
831
|
+
});
|
|
832
|
+
stopReason = sr;
|
|
833
|
+
return { text, attempts: 1, usage: applyPricing(usage, args.pricing) };
|
|
834
|
+
}
|
|
835
|
+
const bodyText = await respLike.text().catch(() => "");
|
|
836
|
+
throw httpFailureToProviderError("anthropic", status, bodyText, parseRetryAfter(respLike), args.model);
|
|
837
|
+
};
|
|
838
|
+
await acquireRateLimit("anthropic", args.signal ? { signal: args.signal } : void 0);
|
|
839
|
+
result = await sendWithRetry(attemptOnce, resolveRetryConfig(), args.signal);
|
|
840
|
+
totalAttempts += result.attempts;
|
|
841
|
+
if (escalation >= MAX_TOKENS_ESCALATIONS || !isEmptyDueToMaxTokens(result.text, stopReason)) {
|
|
842
|
+
break;
|
|
793
843
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
};
|
|
797
|
-
await acquireRateLimit("anthropic", args.signal ? { signal: args.signal } : void 0);
|
|
798
|
-
return sendWithRetry(attemptOnce, resolveRetryConfig(), args.signal);
|
|
844
|
+
maxTokens *= ESCALATION_MULTIPLIER;
|
|
845
|
+
}
|
|
846
|
+
return { ...result, attempts: totalAttempts };
|
|
799
847
|
}
|
|
800
848
|
|
|
801
849
|
// src/providers/gemini.ts
|
|
@@ -970,7 +1018,7 @@ async function sendGemini(args) {
|
|
|
970
1018
|
return { text, attempts: 1, usage: applyPricing2(usage, args.pricing) };
|
|
971
1019
|
}
|
|
972
1020
|
const bodyText = await respLike.text().catch(() => "");
|
|
973
|
-
throw httpFailureToProviderError("gemini", status, bodyText, parseRetryAfter(respLike));
|
|
1021
|
+
throw httpFailureToProviderError("gemini", status, bodyText, parseRetryAfter(respLike), args.model);
|
|
974
1022
|
};
|
|
975
1023
|
await acquireRateLimit("gemini", args.signal ? { signal: args.signal } : void 0);
|
|
976
1024
|
return sendWithRetry(attemptOnce, resolveRetryConfig(), args.signal);
|
|
@@ -1143,7 +1191,7 @@ async function sendOpenAICompatible(args) {
|
|
|
1143
1191
|
return { text, attempts: 1, usage: applyPricing3(usage, args.pricing) };
|
|
1144
1192
|
}
|
|
1145
1193
|
const bodyText = await respLike.text().catch(() => "");
|
|
1146
|
-
throw httpFailureToProviderError(args.provider, status, bodyText, parseRetryAfter(respLike));
|
|
1194
|
+
throw httpFailureToProviderError(args.provider, status, bodyText, parseRetryAfter(respLike), args.model);
|
|
1147
1195
|
};
|
|
1148
1196
|
await acquireRateLimit(args.provider, args.signal ? { signal: args.signal } : void 0);
|
|
1149
1197
|
return sendWithRetry(attemptOnce, resolveRetryConfig(), args.signal);
|
|
@@ -1152,7 +1200,10 @@ async function sendOpenAICompatible(args) {
|
|
|
1152
1200
|
// src/providers/registry.ts
|
|
1153
1201
|
var DEFAULT_MODELS = {
|
|
1154
1202
|
anthropic: "claude-opus-5",
|
|
1155
|
-
|
|
1203
|
+
// gpt-5.5 is not enabled on every OpenAI account/project (some are still
|
|
1204
|
+
// capped at gpt-5) — gpt-5 is the safer, more broadly available default
|
|
1205
|
+
// until a user/org explicitly opts into 5.5 via `crosscheck models set`.
|
|
1206
|
+
openai: "gpt-5",
|
|
1156
1207
|
xai: "grok-4-latest",
|
|
1157
1208
|
mistral: "mistral-large-latest",
|
|
1158
1209
|
groq: "llama-3.3-70b-versatile",
|
|
@@ -1161,12 +1212,31 @@ var DEFAULT_MODELS = {
|
|
|
1161
1212
|
kimi: "kimi-k3",
|
|
1162
1213
|
qwen: "qwen3.8-max"
|
|
1163
1214
|
};
|
|
1215
|
+
var MODEL_ENV_VARS = {
|
|
1216
|
+
anthropic: "ANTHROPIC_MODEL",
|
|
1217
|
+
openai: "OPENAI_MODEL",
|
|
1218
|
+
xai: "XAI_MODEL",
|
|
1219
|
+
mistral: "MISTRAL_MODEL",
|
|
1220
|
+
groq: "GROQ_MODEL",
|
|
1221
|
+
deepseek: "DEEPSEEK_MODEL",
|
|
1222
|
+
gemini: "GEMINI_MODEL",
|
|
1223
|
+
kimi: "KIMI_MODEL",
|
|
1224
|
+
qwen: "QWEN_MODEL"
|
|
1225
|
+
};
|
|
1226
|
+
function parseFallbackModels(raw) {
|
|
1227
|
+
if (!raw) return [];
|
|
1228
|
+
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1229
|
+
}
|
|
1230
|
+
function fallbackModelsFor(env, provider) {
|
|
1231
|
+
const envVar = MODEL_ENV_VARS[provider];
|
|
1232
|
+
return envVar ? parseFallbackModels(env[`${envVar}_FALLBACKS`]) : [];
|
|
1233
|
+
}
|
|
1164
1234
|
function buildProviders(opts) {
|
|
1165
1235
|
const out = {};
|
|
1166
1236
|
const anthropicKey = opts.env["ANTHROPIC_API_KEY"];
|
|
1167
1237
|
if (anthropicKey) {
|
|
1168
1238
|
const model = opts.env["ANTHROPIC_MODEL"] ?? DEFAULT_MODELS.anthropic;
|
|
1169
|
-
out["anthropic"] = makeAnthropicProvider(model, anthropicKey, opts);
|
|
1239
|
+
out["anthropic"] = makeAnthropicProvider(model, anthropicKey, opts, fallbackModelsFor(opts.env, "anthropic"));
|
|
1170
1240
|
}
|
|
1171
1241
|
const openAiCompatSpec = [
|
|
1172
1242
|
{ name: "openai", keyEnv: "OPENAI_API_KEY", modelEnv: "OPENAI_MODEL", defaultModel: DEFAULT_MODELS["openai"] },
|
|
@@ -1181,19 +1251,20 @@ function buildProviders(opts) {
|
|
|
1181
1251
|
const apiKey = opts.env[s.keyEnv];
|
|
1182
1252
|
if (!apiKey) continue;
|
|
1183
1253
|
const model = opts.env[s.modelEnv] ?? s.defaultModel;
|
|
1184
|
-
out[s.name] = makeOpenAICompatibleProvider(s.name, model, apiKey, opts);
|
|
1254
|
+
out[s.name] = makeOpenAICompatibleProvider(s.name, model, apiKey, opts, fallbackModelsFor(opts.env, s.name));
|
|
1185
1255
|
}
|
|
1186
1256
|
const geminiKey = opts.env["GEMINI_API_KEY"];
|
|
1187
1257
|
if (geminiKey) {
|
|
1188
1258
|
const model = opts.env["GEMINI_MODEL"] ?? DEFAULT_MODELS.gemini;
|
|
1189
|
-
out["gemini"] = makeGeminiProvider(model, geminiKey, opts);
|
|
1259
|
+
out["gemini"] = makeGeminiProvider(model, geminiKey, opts, fallbackModelsFor(opts.env, "gemini"));
|
|
1190
1260
|
}
|
|
1191
1261
|
return out;
|
|
1192
1262
|
}
|
|
1193
|
-
function makeAnthropicProvider(model, apiKey, opts) {
|
|
1263
|
+
function makeAnthropicProvider(model, apiKey, opts, fallbackModels = []) {
|
|
1194
1264
|
return {
|
|
1195
1265
|
name: "anthropic",
|
|
1196
1266
|
model,
|
|
1267
|
+
fallbackModels,
|
|
1197
1268
|
send: async (args) => {
|
|
1198
1269
|
const sendOpts = {
|
|
1199
1270
|
...args,
|
|
@@ -1206,11 +1277,12 @@ function makeAnthropicProvider(model, apiKey, opts) {
|
|
|
1206
1277
|
}
|
|
1207
1278
|
};
|
|
1208
1279
|
}
|
|
1209
|
-
function makeOpenAICompatibleProvider(name, model, apiKey, opts) {
|
|
1280
|
+
function makeOpenAICompatibleProvider(name, model, apiKey, opts, fallbackModels = []) {
|
|
1210
1281
|
const url = OPENAI_COMPAT_DEFAULT_URLS[name];
|
|
1211
1282
|
return {
|
|
1212
1283
|
name,
|
|
1213
1284
|
model,
|
|
1285
|
+
fallbackModels,
|
|
1214
1286
|
send: async (args) => {
|
|
1215
1287
|
const sendOpts = {
|
|
1216
1288
|
...args,
|
|
@@ -1225,10 +1297,11 @@ function makeOpenAICompatibleProvider(name, model, apiKey, opts) {
|
|
|
1225
1297
|
}
|
|
1226
1298
|
};
|
|
1227
1299
|
}
|
|
1228
|
-
function makeGeminiProvider(model, apiKey, opts) {
|
|
1300
|
+
function makeGeminiProvider(model, apiKey, opts, fallbackModels = []) {
|
|
1229
1301
|
return {
|
|
1230
1302
|
name: "gemini",
|
|
1231
1303
|
model,
|
|
1304
|
+
fallbackModels,
|
|
1232
1305
|
send: async (args) => {
|
|
1233
1306
|
const sendOpts = {
|
|
1234
1307
|
...args,
|
|
@@ -1247,7 +1320,7 @@ import { z } from "zod";
|
|
|
1247
1320
|
|
|
1248
1321
|
// src/server-meta.ts
|
|
1249
1322
|
var SERVER_NAME = "crosscheck-agent";
|
|
1250
|
-
var SERVER_VERSION = true ? "0.2.
|
|
1323
|
+
var SERVER_VERSION = true ? "0.2.15" : "0.0.0-dev";
|
|
1251
1324
|
|
|
1252
1325
|
// src/tools/audit.ts
|
|
1253
1326
|
import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
|
|
@@ -1898,6 +1971,51 @@ function operatorCeiling(purpose, provider) {
|
|
|
1898
1971
|
return null;
|
|
1899
1972
|
}
|
|
1900
1973
|
|
|
1974
|
+
// src/core/retarget.ts
|
|
1975
|
+
function retargetProvider(p, newModel) {
|
|
1976
|
+
if (p.model === newModel) return p;
|
|
1977
|
+
return {
|
|
1978
|
+
name: p.name,
|
|
1979
|
+
model: newModel,
|
|
1980
|
+
send: (args) => p.send({ ...args, modelOverride: newModel })
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
async function loadProviderWeights(storage, names) {
|
|
1984
|
+
const out = {};
|
|
1985
|
+
for (const raw of names) {
|
|
1986
|
+
const name = raw.toLowerCase();
|
|
1987
|
+
if (name in out) continue;
|
|
1988
|
+
const row = await storage.getProviderStats(name);
|
|
1989
|
+
if (!row) {
|
|
1990
|
+
out[name] = 0.5;
|
|
1991
|
+
continue;
|
|
1992
|
+
}
|
|
1993
|
+
const total = row.wins + row.losses + row.abstains;
|
|
1994
|
+
out[name] = total <= 0 ? 0.5 : (row.wins + 0.5 * row.abstains) / total;
|
|
1995
|
+
}
|
|
1996
|
+
return out;
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
// src/core/model-fallback.ts
|
|
2000
|
+
async function sendWithModelFallback(provider, args) {
|
|
2001
|
+
const chain = [provider.model, ...provider.fallbackModels ?? []];
|
|
2002
|
+
let lastErr;
|
|
2003
|
+
for (let i = 0; i < chain.length; i += 1) {
|
|
2004
|
+
const candidate = chain[i];
|
|
2005
|
+
const p = i === 0 ? provider : retargetProvider(provider, candidate);
|
|
2006
|
+
try {
|
|
2007
|
+
const result = await p.send(args);
|
|
2008
|
+
return { result, modelUsed: candidate };
|
|
2009
|
+
} catch (e) {
|
|
2010
|
+
lastErr = e;
|
|
2011
|
+
const isModelAccessFailure2 = e instanceof ProviderError && e.modelAccessFailure;
|
|
2012
|
+
const hasMoreCandidates = i < chain.length - 1;
|
|
2013
|
+
if (!isModelAccessFailure2 || !hasMoreCandidates) throw e;
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
throw lastErr;
|
|
2017
|
+
}
|
|
2018
|
+
|
|
1901
2019
|
// src/core/structured.ts
|
|
1902
2020
|
async function requestStructured(provider, baseMessages, schema, opts) {
|
|
1903
2021
|
const maxRetries = opts.maxRetries ?? 1;
|
|
@@ -1976,7 +2094,7 @@ async function askOne(provider, messages, opts) {
|
|
|
1976
2094
|
const ceiling = operatorCeiling(opts.purpose, provider.name);
|
|
1977
2095
|
if (ceiling !== null && ceiling < maxTokens) maxTokens = ceiling;
|
|
1978
2096
|
try {
|
|
1979
|
-
const r = await provider
|
|
2097
|
+
const { result: r, modelUsed } = await sendWithModelFallback(provider, {
|
|
1980
2098
|
messages,
|
|
1981
2099
|
maxTokens,
|
|
1982
2100
|
temperature: opts.temperature,
|
|
@@ -1989,7 +2107,10 @@ async function askOne(provider, messages, opts) {
|
|
|
1989
2107
|
const cpuMs = Math.trunc((cpu.user + cpu.system) / 1e3);
|
|
1990
2108
|
return {
|
|
1991
2109
|
provider: provider.name,
|
|
1992
|
-
model
|
|
2110
|
+
// modelUsed reflects whichever model actually answered — the
|
|
2111
|
+
// primary, or a fallback if one was needed. Equivalent to the old
|
|
2112
|
+
// `provider.model` whenever no fallback occurred.
|
|
2113
|
+
model: modelUsed,
|
|
1993
2114
|
response: r.text,
|
|
1994
2115
|
attempts: r.attempts,
|
|
1995
2116
|
usage: r.usage,
|
|
@@ -2699,31 +2820,6 @@ function numberOrNull(v) {
|
|
|
2699
2820
|
// src/tools/audit.ts
|
|
2700
2821
|
import { performance as performance2 } from "perf_hooks";
|
|
2701
2822
|
|
|
2702
|
-
// src/core/retarget.ts
|
|
2703
|
-
function retargetProvider(p, newModel) {
|
|
2704
|
-
if (p.model === newModel) return p;
|
|
2705
|
-
return {
|
|
2706
|
-
name: p.name,
|
|
2707
|
-
model: newModel,
|
|
2708
|
-
send: (args) => p.send({ ...args, modelOverride: newModel })
|
|
2709
|
-
};
|
|
2710
|
-
}
|
|
2711
|
-
async function loadProviderWeights(storage, names) {
|
|
2712
|
-
const out = {};
|
|
2713
|
-
for (const raw of names) {
|
|
2714
|
-
const name = raw.toLowerCase();
|
|
2715
|
-
if (name in out) continue;
|
|
2716
|
-
const row = await storage.getProviderStats(name);
|
|
2717
|
-
if (!row) {
|
|
2718
|
-
out[name] = 0.5;
|
|
2719
|
-
continue;
|
|
2720
|
-
}
|
|
2721
|
-
const total = row.wins + row.losses + row.abstains;
|
|
2722
|
-
out[name] = total <= 0 ? 0.5 : (row.wins + 0.5 * row.abstains) / total;
|
|
2723
|
-
}
|
|
2724
|
-
return out;
|
|
2725
|
-
}
|
|
2726
|
-
|
|
2727
2823
|
// src/core/co-reason.ts
|
|
2728
2824
|
var CO_REASON_MODEL = "gpt-5.6";
|
|
2729
2825
|
var CO_REASON_PROVIDER = "openai";
|
|
@@ -11474,7 +11570,7 @@ var CHECK_INTERVAL_SECONDS = 3 * 24 * 60 * 60;
|
|
|
11474
11570
|
var DEFAULT_PACKAGE = "crosscheck-cli";
|
|
11475
11571
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
11476
11572
|
function engineVersion() {
|
|
11477
|
-
return true ? "0.2.
|
|
11573
|
+
return true ? "0.2.15" : "0.0.0-dev";
|
|
11478
11574
|
}
|
|
11479
11575
|
function defaultUpdateCachePath() {
|
|
11480
11576
|
const base = process.env["CROSSCHECK_DATA_DIR"] || path9.join(os.homedir() || os.tmpdir(), ".crosscheck");
|