claudish 7.56.0 → 7.57.0
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/index.js +636 -401
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -729,7 +729,7 @@ var init_onepassword_config = __esm(() => {
|
|
|
729
729
|
});
|
|
730
730
|
|
|
731
731
|
// src/version.ts
|
|
732
|
-
var VERSION = "7.
|
|
732
|
+
var VERSION = "7.57.0";
|
|
733
733
|
|
|
734
734
|
// src/logger.ts
|
|
735
735
|
var exports_logger = {};
|
|
@@ -28077,6 +28077,7 @@ var init_provider_definitions = __esm(() => {
|
|
|
28077
28077
|
{ prefix: "dv/", stripPrefix: true },
|
|
28078
28078
|
{ prefix: "devin/", stripPrefix: true }
|
|
28079
28079
|
],
|
|
28080
|
+
nativeModelPatterns: [{ pattern: /^swe-/i }],
|
|
28080
28081
|
modelDiscovery: { path: "", format: "devin-connect" },
|
|
28081
28082
|
isDirectApi: true,
|
|
28082
28083
|
description: "Devin subscription (dv@, devin@)"
|
|
@@ -28214,6 +28215,7 @@ var init_provider_definitions = __esm(() => {
|
|
|
28214
28215
|
baseUrl: "https://api.minimax.io",
|
|
28215
28216
|
baseUrlEnvVars: ["MINIMAX_CODING_BASE_URL"],
|
|
28216
28217
|
apiPath: "/anthropic/v1/messages",
|
|
28218
|
+
modelDiscovery: { path: "/v1/models", format: "openai-models-list" },
|
|
28217
28219
|
apiKeyEnvVar: "MINIMAX_CODING_API_KEY",
|
|
28218
28220
|
apiKeyDescription: "MiniMax Coding Plan API Key",
|
|
28219
28221
|
apiKeyUrl: "https://platform.minimax.io/user-center/basic-information/interface-key",
|
|
@@ -28250,6 +28252,7 @@ var init_provider_definitions = __esm(() => {
|
|
|
28250
28252
|
baseUrl: "https://api.moonshot.ai",
|
|
28251
28253
|
baseUrlEnvVars: ["MOONSHOT_BASE_URL", "KIMI_BASE_URL"],
|
|
28252
28254
|
apiPath: "/anthropic/v1/messages",
|
|
28255
|
+
modelDiscovery: { path: "/v1/models", format: "openai-models-list" },
|
|
28253
28256
|
apiKeyEnvVar: "MOONSHOT_API_KEY",
|
|
28254
28257
|
apiKeyAliases: ["KIMI_API_KEY"],
|
|
28255
28258
|
apiKeyDescription: "Kimi/Moonshot API Key",
|
|
@@ -28301,6 +28304,7 @@ var init_provider_definitions = __esm(() => {
|
|
|
28301
28304
|
tokenStrategy: "delta-aware",
|
|
28302
28305
|
baseUrl: "https://api.z.ai",
|
|
28303
28306
|
apiPath: "/api/coding/paas/v4/chat/completions",
|
|
28307
|
+
modelDiscovery: { path: "/api/coding/paas/v4/models", format: "openai-models-list" },
|
|
28304
28308
|
apiKeyEnvVar: "GLM_CODING_API_KEY",
|
|
28305
28309
|
apiKeyAliases: ["ZAI_CODING_API_KEY"],
|
|
28306
28310
|
apiKeyDescription: "GLM Coding Plan API Key",
|
|
@@ -28377,6 +28381,7 @@ var init_provider_definitions = __esm(() => {
|
|
|
28377
28381
|
baseUrl: "https://opencode.ai/zen/go",
|
|
28378
28382
|
baseUrlEnvVars: ["OPENCODE_GO_BASE_URL"],
|
|
28379
28383
|
apiPath: "/v1/chat/completions",
|
|
28384
|
+
modelDiscovery: { path: "/v1/models", format: "openai-models-list" },
|
|
28380
28385
|
apiKeyEnvVar: "OPENCODE_GO_API_KEY",
|
|
28381
28386
|
apiKeyAliases: ["OPENCODE_API_KEY"],
|
|
28382
28387
|
apiKeyDescription: "OpenCode Zen Go (Lite Plan) API Key",
|
|
@@ -28594,6 +28599,7 @@ var init_provider_definitions = __esm(() => {
|
|
|
28594
28599
|
baseUrl: "https://api.sakana.ai",
|
|
28595
28600
|
baseUrlEnvVars: ["SAKANA_BASE_URL"],
|
|
28596
28601
|
apiPath: "/v1/chat/completions",
|
|
28602
|
+
modelDiscovery: { path: "/v1/models", format: "openai-models-list" },
|
|
28597
28603
|
apiKeyEnvVar: "SAKANA_SUBSCRIPTION_API_KEY",
|
|
28598
28604
|
apiKeyAliases: ["SAKANA_CODING_API_KEY"],
|
|
28599
28605
|
apiKeyDescription: "Sakana Fugu Subscription API Key",
|
|
@@ -28741,6 +28747,8 @@ var init_all_models_cache = __esm(() => {
|
|
|
28741
28747
|
|
|
28742
28748
|
// src/providers/catalog-client.ts
|
|
28743
28749
|
function getCatalogEntries() {
|
|
28750
|
+
if (_catalogEntriesForTest !== undefined)
|
|
28751
|
+
return _catalogEntriesForTest;
|
|
28744
28752
|
if (_memCache)
|
|
28745
28753
|
return _memCache;
|
|
28746
28754
|
const cache = readAllModelsCache();
|
|
@@ -28760,6 +28768,26 @@ function getCatalogEntries() {
|
|
|
28760
28768
|
}
|
|
28761
28769
|
return null;
|
|
28762
28770
|
}
|
|
28771
|
+
function latestAnthropicTierModelId(tier) {
|
|
28772
|
+
const entries = getCatalogEntries();
|
|
28773
|
+
if (!entries)
|
|
28774
|
+
return null;
|
|
28775
|
+
const family = new RegExp(`^claude-${tier}-`, "i");
|
|
28776
|
+
const opus = entries.filter((e) => family.test(e.modelId));
|
|
28777
|
+
if (opus.length === 0)
|
|
28778
|
+
return null;
|
|
28779
|
+
opus.sort((a, b) => {
|
|
28780
|
+
const byDate = (b.releaseDate ?? "").localeCompare(a.releaseDate ?? "");
|
|
28781
|
+
if (byDate !== 0)
|
|
28782
|
+
return byDate;
|
|
28783
|
+
const aFast = /-fast$/i.test(a.modelId) ? 1 : 0;
|
|
28784
|
+
const bFast = /-fast$/i.test(b.modelId) ? 1 : 0;
|
|
28785
|
+
if (aFast !== bFast)
|
|
28786
|
+
return aFast - bFast;
|
|
28787
|
+
return b.modelId.localeCompare(a.modelId);
|
|
28788
|
+
});
|
|
28789
|
+
return opus[0].modelId;
|
|
28790
|
+
}
|
|
28763
28791
|
function isCatalogWarm() {
|
|
28764
28792
|
return _memCache !== null && _memCache.length > 0;
|
|
28765
28793
|
}
|
|
@@ -28902,7 +28930,7 @@ async function ensureCatalogReady(timeoutMs = 5000) {
|
|
|
28902
28930
|
new Promise((resolve) => setTimeout(resolve, timeoutMs))
|
|
28903
28931
|
]);
|
|
28904
28932
|
}
|
|
28905
|
-
var FIREBASE_CATALOG_URL, _memCache = null, _warmPromise = null;
|
|
28933
|
+
var FIREBASE_CATALOG_URL, _memCache = null, _catalogEntriesForTest, _warmPromise = null;
|
|
28906
28934
|
var init_catalog_client = __esm(() => {
|
|
28907
28935
|
init_all_models_cache();
|
|
28908
28936
|
FIREBASE_CATALOG_URL = process.env.CLAUDISH_CATALOG_URL ?? process.env.FIREBASE_CATALOG_URL ?? "https://us-central1-claudish-6da10.cloudfunctions.net/queryModels?status=active&catalog=slim&limit=1000";
|
|
@@ -39714,6 +39742,24 @@ var init_devin_stream_head_sniffer = __esm(() => {
|
|
|
39714
39742
|
QUOTA_MESSAGE_RE = /quota|out of credits|credit balance|billing|plan limit|exceeded your/i;
|
|
39715
39743
|
});
|
|
39716
39744
|
|
|
39745
|
+
// src/handlers/shared/model-unsupported.ts
|
|
39746
|
+
function hasModelUnsupportedWording(errorBody) {
|
|
39747
|
+
const lower = (errorBody || "").toLowerCase();
|
|
39748
|
+
return UNSUPPORTED_PHRASES.some((phrase) => lower.includes(phrase));
|
|
39749
|
+
}
|
|
39750
|
+
var UNSUPPORTED_PHRASES;
|
|
39751
|
+
var init_model_unsupported = __esm(() => {
|
|
39752
|
+
UNSUPPORTED_PHRASES = [
|
|
39753
|
+
"not supported",
|
|
39754
|
+
"unsupported model",
|
|
39755
|
+
"unsupported_model",
|
|
39756
|
+
"model not found",
|
|
39757
|
+
"model_not_found",
|
|
39758
|
+
"unknown model",
|
|
39759
|
+
"no such model"
|
|
39760
|
+
];
|
|
39761
|
+
});
|
|
39762
|
+
|
|
39717
39763
|
// src/handlers/shared/stream-head-sniffer.ts
|
|
39718
39764
|
function isRetryableStreamError(code, type, message) {
|
|
39719
39765
|
if (RETRYABLE_ERROR_CODES.has(code))
|
|
@@ -42515,7 +42561,7 @@ function getRecoveryHint(status, errorText, providerName, transportTerminal429)
|
|
|
42515
42561
|
return "Rate limited. Wait, reduce concurrency, or check plan limits.";
|
|
42516
42562
|
}
|
|
42517
42563
|
if (status === 401 || status === 403) {
|
|
42518
|
-
if (
|
|
42564
|
+
if (hasModelUnsupportedWording(errorText)) {
|
|
42519
42565
|
return "Model not supported by this provider. Verify model name.";
|
|
42520
42566
|
}
|
|
42521
42567
|
if (isQuotaExhaustionError(status, errorText)) {
|
|
@@ -42558,6 +42604,7 @@ var init_composed_handler = __esm(() => {
|
|
|
42558
42604
|
init_collect_sse_message();
|
|
42559
42605
|
init_connection_error();
|
|
42560
42606
|
init_devin_stream_head_sniffer();
|
|
42607
|
+
init_model_unsupported();
|
|
42561
42608
|
init_openai_compat();
|
|
42562
42609
|
init_quota_exhaustion();
|
|
42563
42610
|
init_stream_head_sniffer();
|
|
@@ -43277,6 +43324,11 @@ async function discoverProviderModels(providerName) {
|
|
|
43277
43324
|
return recordFailure({ kind: "no-credentials", provider: providerName, endpoint });
|
|
43278
43325
|
}
|
|
43279
43326
|
}
|
|
43327
|
+
headers = {
|
|
43328
|
+
"User-Agent": `claudish/${VERSION}`,
|
|
43329
|
+
...def.headers ?? {},
|
|
43330
|
+
...headers
|
|
43331
|
+
};
|
|
43280
43332
|
let response;
|
|
43281
43333
|
try {
|
|
43282
43334
|
response = await fetch(endpoint, {
|
|
@@ -44954,6 +45006,7 @@ var init_default_routing_rules = __esm(() => {
|
|
|
44954
45006
|
"ministral-*": ["mistralai", "openrouter"],
|
|
44955
45007
|
"codestral-*": ["mistralai", "openrouter"],
|
|
44956
45008
|
"labs-*": ["mistralai"],
|
|
45009
|
+
"swe-*": ["devin"],
|
|
44957
45010
|
fugu: ["sakana-subscription", "sakana"],
|
|
44958
45011
|
"fugu-*": ["sakana-subscription", "sakana"],
|
|
44959
45012
|
"*-zen": ["opencode-zen"],
|
|
@@ -46369,6 +46422,15 @@ function normalizePricingDisplay(raw) {
|
|
|
46369
46422
|
return "FREE";
|
|
46370
46423
|
return pricing;
|
|
46371
46424
|
}
|
|
46425
|
+
function formatListingPrice(entry, opts) {
|
|
46426
|
+
const rate = normalizePricingDisplay(entry.pricing?.average);
|
|
46427
|
+
if (rate !== "N/A")
|
|
46428
|
+
return rate;
|
|
46429
|
+
const plan = entry.subscription?.plan;
|
|
46430
|
+
if (!plan)
|
|
46431
|
+
return "N/A";
|
|
46432
|
+
return opts?.compact ? "SUB" : `SUB (${plan})`;
|
|
46433
|
+
}
|
|
46372
46434
|
function computeQuickPicks(primaries) {
|
|
46373
46435
|
if (primaries.length === 0) {
|
|
46374
46436
|
return {
|
|
@@ -46603,6 +46665,412 @@ async function isPortAvailable(port) {
|
|
|
46603
46665
|
}
|
|
46604
46666
|
var init_port_manager = () => {};
|
|
46605
46667
|
|
|
46668
|
+
// src/providers/probe-live.ts
|
|
46669
|
+
function effortForProvider(provider) {
|
|
46670
|
+
return MINIMAL_EFFORT_UNSUPPORTED.has(provider) ? "low" : "minimal";
|
|
46671
|
+
}
|
|
46672
|
+
async function probeLink(proxyUrl, link, timeoutMs) {
|
|
46673
|
+
const isOAuth = OAUTH_PROVIDERS2.has(link.provider);
|
|
46674
|
+
if (!link.hasCredentials && !isOAuth) {
|
|
46675
|
+
return {
|
|
46676
|
+
state: "key-missing",
|
|
46677
|
+
latencyMs: 0,
|
|
46678
|
+
errorMessage: link.credentialHint
|
|
46679
|
+
};
|
|
46680
|
+
}
|
|
46681
|
+
const startedAt = Date.now();
|
|
46682
|
+
let response;
|
|
46683
|
+
try {
|
|
46684
|
+
response = await fetch(`${proxyUrl}/v1/messages`, {
|
|
46685
|
+
method: "POST",
|
|
46686
|
+
headers: {
|
|
46687
|
+
"Content-Type": "application/json"
|
|
46688
|
+
},
|
|
46689
|
+
body: JSON.stringify({
|
|
46690
|
+
model: link.modelSpec,
|
|
46691
|
+
system: "You are a helpful assistant.",
|
|
46692
|
+
messages: [{ role: "user", content: PROBE_PROMPT }],
|
|
46693
|
+
max_tokens: PROBE_MAX_TOKENS,
|
|
46694
|
+
output_config: { effort: effortForProvider(link.provider) },
|
|
46695
|
+
stream: true
|
|
46696
|
+
}),
|
|
46697
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
46698
|
+
});
|
|
46699
|
+
} catch (e) {
|
|
46700
|
+
const latencyMs = Date.now() - startedAt;
|
|
46701
|
+
const name = e?.name || "";
|
|
46702
|
+
const msg2 = String(e?.message || e);
|
|
46703
|
+
if (name === "TimeoutError" || name === "AbortError" || /timeout/i.test(msg2)) {
|
|
46704
|
+
return { state: "timeout", latencyMs, errorMessage: msg2 };
|
|
46705
|
+
}
|
|
46706
|
+
return { state: "network-error", latencyMs, errorMessage: msg2 };
|
|
46707
|
+
}
|
|
46708
|
+
const ttfbMs = Date.now() - startedAt;
|
|
46709
|
+
if (!response.ok) {
|
|
46710
|
+
const body = await safeReadBody(response);
|
|
46711
|
+
return annotateOAuthHint(classifyHttpError(response.status, body, ttfbMs), link.provider, isOAuth);
|
|
46712
|
+
}
|
|
46713
|
+
const streamResult = await consumeProbeStream(response, timeoutMs, startedAt);
|
|
46714
|
+
const totalMs = Date.now() - startedAt;
|
|
46715
|
+
let timing2;
|
|
46716
|
+
if (streamResult.state === "live" && streamResult.ttftMs !== undefined && !streamResult.truncated) {
|
|
46717
|
+
const ttftMs = streamResult.ttftMs;
|
|
46718
|
+
const tokens = streamResult.tokens ?? 0;
|
|
46719
|
+
const streamMs = Math.max(STREAM_MS_FLOOR, totalMs - ttftMs);
|
|
46720
|
+
const tokensPerSec = tokens > 0 ? tokens / streamMs * 1000 : 0;
|
|
46721
|
+
timing2 = { ttfbMs, ttftMs, totalMs, tokens, tokensPerSec };
|
|
46722
|
+
}
|
|
46723
|
+
const { ttftMs: _ttft, tokens: _tok, truncated: _trunc, ...rest } = streamResult;
|
|
46724
|
+
return annotateOAuthHint({
|
|
46725
|
+
...rest,
|
|
46726
|
+
latencyMs: totalMs,
|
|
46727
|
+
timing: timing2
|
|
46728
|
+
}, link.provider, isOAuth);
|
|
46729
|
+
}
|
|
46730
|
+
function annotateOAuthHint(result, provider, isOAuth) {
|
|
46731
|
+
if (!isOAuth)
|
|
46732
|
+
return result;
|
|
46733
|
+
if (result.state === "live")
|
|
46734
|
+
return result;
|
|
46735
|
+
const loginCommand = provider === "antigravity" ? "claudish login antigravity" : provider === "vertex" ? "gcloud auth application-default login" : provider === "devin" ? "devin login" : undefined;
|
|
46736
|
+
if (!loginCommand)
|
|
46737
|
+
return result;
|
|
46738
|
+
if (result.httpStatus === 403)
|
|
46739
|
+
return result;
|
|
46740
|
+
const looksLikeAuthFailure = result.state === "auth-failed" || /auth|token|login|credential|unauthor/i.test(result.errorMessage || "");
|
|
46741
|
+
if (!looksLikeAuthFailure)
|
|
46742
|
+
return result;
|
|
46743
|
+
return {
|
|
46744
|
+
...result,
|
|
46745
|
+
state: "auth-failed",
|
|
46746
|
+
actionHint: `run: ${loginCommand}`
|
|
46747
|
+
};
|
|
46748
|
+
}
|
|
46749
|
+
async function safeReadBody(response) {
|
|
46750
|
+
try {
|
|
46751
|
+
const text = await response.text();
|
|
46752
|
+
return text.slice(0, 500);
|
|
46753
|
+
} catch {
|
|
46754
|
+
return "";
|
|
46755
|
+
}
|
|
46756
|
+
}
|
|
46757
|
+
function extractUpstreamStatus(body) {
|
|
46758
|
+
if (!body)
|
|
46759
|
+
return;
|
|
46760
|
+
try {
|
|
46761
|
+
const parsed = JSON.parse(body);
|
|
46762
|
+
const status = parsed?.error?.upstream_status;
|
|
46763
|
+
return typeof status === "number" ? status : undefined;
|
|
46764
|
+
} catch {
|
|
46765
|
+
return;
|
|
46766
|
+
}
|
|
46767
|
+
}
|
|
46768
|
+
function extractErrorType(body) {
|
|
46769
|
+
if (!body)
|
|
46770
|
+
return;
|
|
46771
|
+
try {
|
|
46772
|
+
const parsed = JSON.parse(body);
|
|
46773
|
+
const t = parsed?.error?.type;
|
|
46774
|
+
return typeof t === "string" ? t : undefined;
|
|
46775
|
+
} catch {
|
|
46776
|
+
return;
|
|
46777
|
+
}
|
|
46778
|
+
}
|
|
46779
|
+
function classifyHttpError(status, body, latencyMs) {
|
|
46780
|
+
const lowered = body.toLowerCase();
|
|
46781
|
+
if (extractErrorType(body) === "connection_error") {
|
|
46782
|
+
return {
|
|
46783
|
+
state: "network-error",
|
|
46784
|
+
latencyMs,
|
|
46785
|
+
httpStatus: status,
|
|
46786
|
+
errorMessage: extractErrorMessage(body) || "Cannot reach provider"
|
|
46787
|
+
};
|
|
46788
|
+
}
|
|
46789
|
+
const upstream = status === 400 ? extractUpstreamStatus(body) : undefined;
|
|
46790
|
+
if (status === 401 || status === 403 || upstream === 401 || upstream === 403) {
|
|
46791
|
+
const authStatus = upstream ?? status;
|
|
46792
|
+
if (hasModelUnsupportedWording(body)) {
|
|
46793
|
+
return {
|
|
46794
|
+
state: "model-not-found",
|
|
46795
|
+
latencyMs,
|
|
46796
|
+
httpStatus: authStatus,
|
|
46797
|
+
errorMessage: extractErrorMessage(body) || `HTTP ${authStatus}`
|
|
46798
|
+
};
|
|
46799
|
+
}
|
|
46800
|
+
return {
|
|
46801
|
+
state: "auth-failed",
|
|
46802
|
+
latencyMs,
|
|
46803
|
+
httpStatus: authStatus,
|
|
46804
|
+
errorMessage: extractErrorMessage(body) || `HTTP ${authStatus}`
|
|
46805
|
+
};
|
|
46806
|
+
}
|
|
46807
|
+
if (status === 404 || /model[_ ]not[_ ]found|no such model|unknown model/.test(lowered)) {
|
|
46808
|
+
return {
|
|
46809
|
+
state: "model-not-found",
|
|
46810
|
+
latencyMs,
|
|
46811
|
+
httpStatus: status,
|
|
46812
|
+
errorMessage: extractErrorMessage(body) || `HTTP ${status}`
|
|
46813
|
+
};
|
|
46814
|
+
}
|
|
46815
|
+
if (status === 429) {
|
|
46816
|
+
return {
|
|
46817
|
+
state: "rate-limited",
|
|
46818
|
+
latencyMs,
|
|
46819
|
+
httpStatus: status,
|
|
46820
|
+
errorMessage: extractErrorMessage(body) || "Rate limited"
|
|
46821
|
+
};
|
|
46822
|
+
}
|
|
46823
|
+
if (upstream === 429 || status === 402) {
|
|
46824
|
+
return {
|
|
46825
|
+
state: "out-of-credit",
|
|
46826
|
+
latencyMs,
|
|
46827
|
+
httpStatus: upstream ?? status,
|
|
46828
|
+
errorMessage: extractErrorMessage(body) || "Out of credit \u2014 account balance or plan exhausted"
|
|
46829
|
+
};
|
|
46830
|
+
}
|
|
46831
|
+
if (status >= 500) {
|
|
46832
|
+
return {
|
|
46833
|
+
state: "server-error",
|
|
46834
|
+
latencyMs,
|
|
46835
|
+
httpStatus: status,
|
|
46836
|
+
errorMessage: extractErrorMessage(body) || `HTTP ${status}`
|
|
46837
|
+
};
|
|
46838
|
+
}
|
|
46839
|
+
return {
|
|
46840
|
+
state: "error",
|
|
46841
|
+
latencyMs,
|
|
46842
|
+
httpStatus: status,
|
|
46843
|
+
errorMessage: extractErrorMessage(body) || `HTTP ${status}`
|
|
46844
|
+
};
|
|
46845
|
+
}
|
|
46846
|
+
function extractErrorMessage(body) {
|
|
46847
|
+
if (!body)
|
|
46848
|
+
return;
|
|
46849
|
+
try {
|
|
46850
|
+
const parsed = JSON.parse(body);
|
|
46851
|
+
const msg2 = parsed?.error?.message || parsed?.error?.error?.message || parsed?.message || parsed?.detail;
|
|
46852
|
+
if (typeof msg2 === "string" && msg2.length > 0) {
|
|
46853
|
+
return msg2.length > 160 ? `${msg2.slice(0, 157)}...` : msg2;
|
|
46854
|
+
}
|
|
46855
|
+
} catch {}
|
|
46856
|
+
const trimmed2 = body.trim();
|
|
46857
|
+
if (!trimmed2)
|
|
46858
|
+
return;
|
|
46859
|
+
return trimmed2.length > 160 ? `${trimmed2.slice(0, 157)}...` : trimmed2;
|
|
46860
|
+
}
|
|
46861
|
+
async function consumeProbeStream(response, timeoutMs, startedAt) {
|
|
46862
|
+
const body = response.body;
|
|
46863
|
+
if (!body) {
|
|
46864
|
+
return { state: "error", errorMessage: "empty response body" };
|
|
46865
|
+
}
|
|
46866
|
+
const reader = body.getReader();
|
|
46867
|
+
const decoder = new TextDecoder;
|
|
46868
|
+
let buffered = "";
|
|
46869
|
+
const deadline = Date.now() + timeoutMs;
|
|
46870
|
+
let ttftMs;
|
|
46871
|
+
let sawContent = false;
|
|
46872
|
+
let textChars = 0;
|
|
46873
|
+
let reportedTokens;
|
|
46874
|
+
let stopReason;
|
|
46875
|
+
let errorVerdict = null;
|
|
46876
|
+
let completed = false;
|
|
46877
|
+
try {
|
|
46878
|
+
while (Date.now() < deadline) {
|
|
46879
|
+
const { value, done } = await reader.read();
|
|
46880
|
+
if (done) {
|
|
46881
|
+
completed = true;
|
|
46882
|
+
break;
|
|
46883
|
+
}
|
|
46884
|
+
buffered += decoder.decode(value, { stream: true });
|
|
46885
|
+
const events = buffered.split(`
|
|
46886
|
+
|
|
46887
|
+
`);
|
|
46888
|
+
buffered = events.pop() ?? "";
|
|
46889
|
+
for (const event of events) {
|
|
46890
|
+
const verdict = interpretSseEvent(event);
|
|
46891
|
+
if (verdict && typeof verdict === "object" && verdict.state !== "live") {
|
|
46892
|
+
errorVerdict = verdict;
|
|
46893
|
+
break;
|
|
46894
|
+
}
|
|
46895
|
+
const acct = accountStreamEvent(event);
|
|
46896
|
+
if (acct.contentDelta) {
|
|
46897
|
+
if (ttftMs === undefined)
|
|
46898
|
+
ttftMs = Date.now() - startedAt;
|
|
46899
|
+
sawContent = true;
|
|
46900
|
+
}
|
|
46901
|
+
if (acct.textChars)
|
|
46902
|
+
textChars += acct.textChars;
|
|
46903
|
+
if (acct.outputTokens !== undefined)
|
|
46904
|
+
reportedTokens = acct.outputTokens;
|
|
46905
|
+
if (acct.stopReason)
|
|
46906
|
+
stopReason = acct.stopReason;
|
|
46907
|
+
}
|
|
46908
|
+
if (errorVerdict)
|
|
46909
|
+
break;
|
|
46910
|
+
}
|
|
46911
|
+
} catch (e) {
|
|
46912
|
+
if (!sawContent) {
|
|
46913
|
+
return { state: "network-error", errorMessage: String(e?.message || e) };
|
|
46914
|
+
}
|
|
46915
|
+
} finally {
|
|
46916
|
+
try {
|
|
46917
|
+
await reader.cancel();
|
|
46918
|
+
} catch {}
|
|
46919
|
+
}
|
|
46920
|
+
if (errorVerdict)
|
|
46921
|
+
return errorVerdict;
|
|
46922
|
+
if (sawContent) {
|
|
46923
|
+
const tokens = reportedTokens ?? Math.max(1, Math.round(textChars / 4));
|
|
46924
|
+
return { state: "live", ttftMs, tokens, truncated: !completed };
|
|
46925
|
+
}
|
|
46926
|
+
const truncationReason = stopReason === "max_tokens" || stopReason === "length" ? stopReason : undefined;
|
|
46927
|
+
if (truncationReason || reportedTokens !== undefined && reportedTokens >= PROBE_MAX_TOKENS) {
|
|
46928
|
+
const cause = truncationReason ? `finish: ${truncationReason}` : `${reportedTokens} tokens consumed, none visible`;
|
|
46929
|
+
return {
|
|
46930
|
+
state: "error",
|
|
46931
|
+
errorMessage: `no visible output within probe budget (${cause})`
|
|
46932
|
+
};
|
|
46933
|
+
}
|
|
46934
|
+
return { state: "error", errorMessage: "stream ended without content" };
|
|
46935
|
+
}
|
|
46936
|
+
function accountStreamEvent(rawEvent) {
|
|
46937
|
+
let dataPayload = "";
|
|
46938
|
+
for (const line of rawEvent.split(`
|
|
46939
|
+
`)) {
|
|
46940
|
+
if (line.startsWith("data:"))
|
|
46941
|
+
dataPayload += line.slice(5).trim();
|
|
46942
|
+
}
|
|
46943
|
+
if (!dataPayload || dataPayload === "[DONE]") {
|
|
46944
|
+
return { contentDelta: false, textChars: 0 };
|
|
46945
|
+
}
|
|
46946
|
+
let parsed;
|
|
46947
|
+
try {
|
|
46948
|
+
parsed = JSON.parse(dataPayload);
|
|
46949
|
+
} catch {
|
|
46950
|
+
return { contentDelta: false, textChars: 0 };
|
|
46951
|
+
}
|
|
46952
|
+
let textChars = 0;
|
|
46953
|
+
let contentDelta = false;
|
|
46954
|
+
const text = parsed?.delta?.text ?? (Array.isArray(parsed?.choices) ? parsed.choices[0]?.delta?.content : undefined);
|
|
46955
|
+
if (typeof text === "string" && text.length > 0) {
|
|
46956
|
+
contentDelta = true;
|
|
46957
|
+
textChars = text.length;
|
|
46958
|
+
} else if (parsed?.type === "content_block_delta" || parsed?.type === "content_block_start") {
|
|
46959
|
+
contentDelta = true;
|
|
46960
|
+
}
|
|
46961
|
+
const outputTokens = parsed?.usage?.output_tokens ?? parsed?.message?.usage?.output_tokens ?? parsed?.usage?.completion_tokens;
|
|
46962
|
+
const stopReason = parsed?.delta?.stop_reason ?? (Array.isArray(parsed?.choices) ? parsed.choices[0]?.finish_reason : undefined);
|
|
46963
|
+
return {
|
|
46964
|
+
contentDelta,
|
|
46965
|
+
textChars,
|
|
46966
|
+
outputTokens: typeof outputTokens === "number" ? outputTokens : undefined,
|
|
46967
|
+
stopReason: typeof stopReason === "string" ? stopReason : undefined
|
|
46968
|
+
};
|
|
46969
|
+
}
|
|
46970
|
+
function interpretSseEvent(rawEvent) {
|
|
46971
|
+
const lines = rawEvent.split(`
|
|
46972
|
+
`);
|
|
46973
|
+
let eventType = "";
|
|
46974
|
+
let dataPayload = "";
|
|
46975
|
+
for (const line of lines) {
|
|
46976
|
+
if (line.startsWith("event:"))
|
|
46977
|
+
eventType = line.slice(6).trim();
|
|
46978
|
+
else if (line.startsWith("data:"))
|
|
46979
|
+
dataPayload += line.slice(5).trim();
|
|
46980
|
+
}
|
|
46981
|
+
if (!dataPayload)
|
|
46982
|
+
return null;
|
|
46983
|
+
if (dataPayload === "[DONE]")
|
|
46984
|
+
return null;
|
|
46985
|
+
let parsed;
|
|
46986
|
+
try {
|
|
46987
|
+
parsed = JSON.parse(dataPayload);
|
|
46988
|
+
} catch {
|
|
46989
|
+
return null;
|
|
46990
|
+
}
|
|
46991
|
+
if (parsed?.type === "error" || eventType === "error" || parsed?.error) {
|
|
46992
|
+
const message = parsed?.error?.message || parsed?.error?.error?.message || parsed?.message || "provider returned error event";
|
|
46993
|
+
const status = parsed?.error?.status || parsed?.status;
|
|
46994
|
+
if (typeof status === "number") {
|
|
46995
|
+
return {
|
|
46996
|
+
state: status === 401 || status === 403 ? "auth-failed" : "error",
|
|
46997
|
+
httpStatus: status,
|
|
46998
|
+
errorMessage: message
|
|
46999
|
+
};
|
|
47000
|
+
}
|
|
47001
|
+
return { state: "error", errorMessage: message };
|
|
47002
|
+
}
|
|
47003
|
+
if (isContentEvent(parsed, eventType)) {
|
|
47004
|
+
return "live";
|
|
47005
|
+
}
|
|
47006
|
+
return null;
|
|
47007
|
+
}
|
|
47008
|
+
function isContentEvent(parsed, eventType) {
|
|
47009
|
+
if (eventType === "content_block_start" || eventType === "content_block_delta")
|
|
47010
|
+
return true;
|
|
47011
|
+
if (eventType === "message_start")
|
|
47012
|
+
return true;
|
|
47013
|
+
if (parsed?.type === "content_block_start")
|
|
47014
|
+
return true;
|
|
47015
|
+
if (parsed?.type === "content_block_delta")
|
|
47016
|
+
return true;
|
|
47017
|
+
if (parsed?.type === "message_start")
|
|
47018
|
+
return true;
|
|
47019
|
+
if (parsed?.type === "message_delta")
|
|
47020
|
+
return true;
|
|
47021
|
+
if (Array.isArray(parsed?.choices) && parsed.choices.length > 0) {
|
|
47022
|
+
const choice = parsed.choices[0];
|
|
47023
|
+
if (choice?.delta || choice?.message || choice?.text || choice?.finish_reason)
|
|
47024
|
+
return true;
|
|
47025
|
+
}
|
|
47026
|
+
if (parsed?.candidates)
|
|
47027
|
+
return true;
|
|
47028
|
+
return false;
|
|
47029
|
+
}
|
|
47030
|
+
function withDetail(base, message) {
|
|
47031
|
+
return message ? `${base} \u2014 ${message}` : base;
|
|
47032
|
+
}
|
|
47033
|
+
function describeProbeState(result) {
|
|
47034
|
+
const status = result.httpStatus ?? "";
|
|
47035
|
+
const latency = result.latencyMs ? ` \xB7 ${result.latencyMs}ms` : "";
|
|
47036
|
+
switch (result.state) {
|
|
47037
|
+
case "live":
|
|
47038
|
+
return `live \xB7 ${result.latencyMs}ms`;
|
|
47039
|
+
case "key-missing":
|
|
47040
|
+
return result.errorMessage ? `missing (${result.errorMessage})` : "missing";
|
|
47041
|
+
case "auth-failed":
|
|
47042
|
+
return withDetail(`auth failed \xB7 ${status}${latency}`.trim(), result.errorMessage);
|
|
47043
|
+
case "model-not-found":
|
|
47044
|
+
return withDetail(`model not found \xB7 ${status}${latency}`.trim(), result.errorMessage);
|
|
47045
|
+
case "rate-limited":
|
|
47046
|
+
return withDetail(`rate limited \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
47047
|
+
case "out-of-credit":
|
|
47048
|
+
return withDetail(`out of credit \xB7 ${status}${latency}`.trim(), result.errorMessage);
|
|
47049
|
+
case "server-error":
|
|
47050
|
+
return withDetail(`server error \xB7 ${status} \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
47051
|
+
case "timeout":
|
|
47052
|
+
return withDetail(`timeout \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
47053
|
+
case "network-error":
|
|
47054
|
+
return withDetail(`network error \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
47055
|
+
case "error": {
|
|
47056
|
+
const base = `error${result.httpStatus ? ` \xB7 ${result.httpStatus}` : ""}${latency}`;
|
|
47057
|
+
return withDetail(base, result.errorMessage);
|
|
47058
|
+
}
|
|
47059
|
+
}
|
|
47060
|
+
}
|
|
47061
|
+
function isReadyState(state) {
|
|
47062
|
+
return state === "live";
|
|
47063
|
+
}
|
|
47064
|
+
function isFailureState(state) {
|
|
47065
|
+
return state === "auth-failed" || state === "model-not-found" || state === "rate-limited" || state === "out-of-credit" || state === "server-error" || state === "timeout" || state === "network-error" || state === "error";
|
|
47066
|
+
}
|
|
47067
|
+
var STREAM_MS_FLOOR = 50, OAUTH_PROVIDERS2, PROBE_PROMPT = "Count from one to twenty in words, one per line.", PROBE_MAX_TOKENS = 512, MINIMAL_EFFORT_UNSUPPORTED;
|
|
47068
|
+
var init_probe_live = __esm(() => {
|
|
47069
|
+
init_model_unsupported();
|
|
47070
|
+
OAUTH_PROVIDERS2 = new Set(["vertex", "antigravity", "devin"]);
|
|
47071
|
+
MINIMAL_EFFORT_UNSUPPORTED = new Set(["native-anthropic", "anthropic"]);
|
|
47072
|
+
});
|
|
47073
|
+
|
|
46606
47074
|
// ../../node_modules/.bun/hono@4.10.6/node_modules/hono/dist/compose.js
|
|
46607
47075
|
var compose = (middleware, onError, onNotFound) => {
|
|
46608
47076
|
return (context, next) => {
|
|
@@ -53052,7 +53520,7 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
|
|
|
53052
53520
|
};
|
|
53053
53521
|
const renderGroup = (group) => {
|
|
53054
53522
|
const m = group.primary;
|
|
53055
|
-
const pricing =
|
|
53523
|
+
const pricing = formatListingPrice(m);
|
|
53056
53524
|
const ctx = m.context || "N/A";
|
|
53057
53525
|
const caps = [];
|
|
53058
53526
|
if (m.supportsTools)
|
|
@@ -53257,6 +53725,112 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
53257
53725
|
return { content: [{ type: "text", text: output }] };
|
|
53258
53726
|
}
|
|
53259
53727
|
});
|
|
53728
|
+
tools.push({
|
|
53729
|
+
name: "preflight",
|
|
53730
|
+
description: "Check a roster of models BEFORE spending a run on it. For each model: which provider " + "will actually serve it, whether that hop is covered by a SUBSCRIPTION or billed per " + "token, and whether it is reachable right now. Call this before `team` or a batch of " + "`create_session` calls \u2014 a dead or unexpectedly-metered model is then caught while " + "the roster can still be adjusted, instead of costing a slot minutes into the run.",
|
|
53731
|
+
inputSchema: {
|
|
53732
|
+
type: "object",
|
|
53733
|
+
properties: {
|
|
53734
|
+
models: {
|
|
53735
|
+
type: "array",
|
|
53736
|
+
items: { type: "string" },
|
|
53737
|
+
description: "Model ids to check \u2014 bare (`glm-5.2`) or explicit (`dv@swe-1.7`). Bare names go " + "through the SAME routing rules and credential filter a real run would use, so " + "the provider reported here is the provider that would serve it."
|
|
53738
|
+
},
|
|
53739
|
+
probe: {
|
|
53740
|
+
type: "boolean",
|
|
53741
|
+
description: "Send a real short request to each resolved route (default true). Set false for " + "a routing/billing answer only \u2014 far faster, but it cannot tell you the provider " + "is actually reachable, which is the failure this tool exists to catch."
|
|
53742
|
+
},
|
|
53743
|
+
timeout_ms: {
|
|
53744
|
+
type: "number",
|
|
53745
|
+
description: "Per-model probe timeout in ms (default 20000)."
|
|
53746
|
+
}
|
|
53747
|
+
},
|
|
53748
|
+
required: ["models"]
|
|
53749
|
+
},
|
|
53750
|
+
group: "agentic",
|
|
53751
|
+
heartbeat: true,
|
|
53752
|
+
handler: async (args, ctx) => {
|
|
53753
|
+
const models = Array.isArray(args.models) ? args.models : [];
|
|
53754
|
+
if (models.length === 0) {
|
|
53755
|
+
return {
|
|
53756
|
+
content: [{ type: "text", text: "preflight: no models given." }],
|
|
53757
|
+
isError: true
|
|
53758
|
+
};
|
|
53759
|
+
}
|
|
53760
|
+
const doProbe = args.probe !== false;
|
|
53761
|
+
const timeoutMs = typeof args.timeout_ms === "number" ? args.timeout_ms : 20000;
|
|
53762
|
+
const proxy = doProbe ? await getProxy() : null;
|
|
53763
|
+
const rows = [];
|
|
53764
|
+
const readyModels = [];
|
|
53765
|
+
const failedModels = [];
|
|
53766
|
+
let subCount = 0;
|
|
53767
|
+
let meteredCount = 0;
|
|
53768
|
+
for (const model of models) {
|
|
53769
|
+
ctx.reportProgress(`preflight: ${model}`);
|
|
53770
|
+
let plan;
|
|
53771
|
+
try {
|
|
53772
|
+
plan = await route(model);
|
|
53773
|
+
} catch (err) {
|
|
53774
|
+
failedModels.push(model);
|
|
53775
|
+
rows.push(`| \`${model}\` | \u2014 | \u2014 | \u274C route error | ${err instanceof Error ? err.message : String(err)} |`);
|
|
53776
|
+
continue;
|
|
53777
|
+
}
|
|
53778
|
+
if (plan.kind === "no-route") {
|
|
53779
|
+
failedModels.push(model);
|
|
53780
|
+
rows.push(`| \`${model}\` | \u2014 | \u2014 | \u274C no route | ${plan.reason} |`);
|
|
53781
|
+
continue;
|
|
53782
|
+
}
|
|
53783
|
+
const primary = plan.primary;
|
|
53784
|
+
const billing = isLocalProviderName(primary.provider) ? "local" : isSubscriptionProvider(primary.provider) ? "SUB" : "metered";
|
|
53785
|
+
if (billing === "SUB")
|
|
53786
|
+
subCount++;
|
|
53787
|
+
else if (billing === "metered")
|
|
53788
|
+
meteredCount++;
|
|
53789
|
+
let status = "not probed";
|
|
53790
|
+
let ok = true;
|
|
53791
|
+
if (proxy) {
|
|
53792
|
+
try {
|
|
53793
|
+
const result = await probeLink(proxy.url, {
|
|
53794
|
+
provider: primary.provider,
|
|
53795
|
+
modelSpec: primary.modelSpec,
|
|
53796
|
+
hasCredentials: true
|
|
53797
|
+
}, timeoutMs);
|
|
53798
|
+
ok = isReadyState(result.state);
|
|
53799
|
+
status = ok ? `\u2705 ${result.state}` : `\u274C ${result.state}${result.errorMessage ? ` \u2014 ${result.errorMessage}` : ""}`;
|
|
53800
|
+
} catch (err) {
|
|
53801
|
+
ok = false;
|
|
53802
|
+
status = `\u274C probe error \u2014 ${err instanceof Error ? err.message : String(err)}`;
|
|
53803
|
+
}
|
|
53804
|
+
}
|
|
53805
|
+
if (ok)
|
|
53806
|
+
readyModels.push(model);
|
|
53807
|
+
else
|
|
53808
|
+
failedModels.push(model);
|
|
53809
|
+
const fallbacks = plan.fallbacks.length > 0 ? ` (+${plan.fallbacks.length} fallback)` : "";
|
|
53810
|
+
rows.push(`| \`${model}\` | ${primary.displayName}${fallbacks} | ${billing} | ${status} | \`${primary.modelSpec}\` |`);
|
|
53811
|
+
}
|
|
53812
|
+
const lines = [
|
|
53813
|
+
`# Preflight \u2014 ${models.length} model${models.length === 1 ? "" : "s"}`,
|
|
53814
|
+
"",
|
|
53815
|
+
`**Ready: ${readyModels.length}** \xB7 **Failed: ${failedModels.length}** \xB7 ` + `subscription: ${subCount} \xB7 metered: ${meteredCount}`,
|
|
53816
|
+
"",
|
|
53817
|
+
"| Model | Provider | Billing | Status | Wire id |",
|
|
53818
|
+
"|---|---|---|---|---|",
|
|
53819
|
+
...rows
|
|
53820
|
+
];
|
|
53821
|
+
if (failedModels.length > 0) {
|
|
53822
|
+
lines.push("", `\u26A0\uFE0F Drop or replace before running: ${failedModels.map((m) => `\`${m}\``).join(", ")}`);
|
|
53823
|
+
}
|
|
53824
|
+
if (meteredCount > 0) {
|
|
53825
|
+
lines.push("", `\uD83D\uDCB8 ${meteredCount} model${meteredCount === 1 ? "" : "s"} will be billed PER TOKEN. ` + "A bare name can land on a metered provider when the subscription that covers it " + "has no credential configured \u2014 name the provider explicitly to pin it.");
|
|
53826
|
+
}
|
|
53827
|
+
if (!doProbe) {
|
|
53828
|
+
lines.push("", "\u2139\uFE0F `probe: false` \u2014 routing and billing only. Reachability was NOT checked.");
|
|
53829
|
+
}
|
|
53830
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
53831
|
+
`) }] };
|
|
53832
|
+
}
|
|
53833
|
+
});
|
|
53260
53834
|
tools.push({
|
|
53261
53835
|
name: "team",
|
|
53262
53836
|
description: "Run AI models on a task with anonymized outputs and optional blind judging. Modes: 'run' (execute models), 'judge' (blind-vote on existing outputs), 'run-and-judge' (full pipeline), 'status' (check progress).",
|
|
@@ -53851,11 +54425,15 @@ var init_mcp_server = __esm(() => {
|
|
|
53851
54425
|
init_prehydrate();
|
|
53852
54426
|
init_diagnostics();
|
|
53853
54427
|
init_channel();
|
|
54428
|
+
init_remote_provider_types();
|
|
53854
54429
|
init_progress_heartbeat();
|
|
53855
54430
|
init_model_loader();
|
|
53856
54431
|
init_port_manager();
|
|
54432
|
+
init_model_parser();
|
|
53857
54433
|
init_onepassword();
|
|
54434
|
+
init_probe_live();
|
|
53858
54435
|
init_provider_definitions();
|
|
54436
|
+
init_routing_rules();
|
|
53859
54437
|
init_proxy_server();
|
|
53860
54438
|
init_redact();
|
|
53861
54439
|
init_team_orchestrator();
|
|
@@ -68684,399 +69262,6 @@ var init_model_selector = __esm(() => {
|
|
|
68684
69262
|
};
|
|
68685
69263
|
});
|
|
68686
69264
|
|
|
68687
|
-
// src/providers/probe-live.ts
|
|
68688
|
-
async function probeLink(proxyUrl, link, timeoutMs) {
|
|
68689
|
-
const isOAuth = OAUTH_PROVIDERS2.has(link.provider);
|
|
68690
|
-
if (!link.hasCredentials && !isOAuth) {
|
|
68691
|
-
return {
|
|
68692
|
-
state: "key-missing",
|
|
68693
|
-
latencyMs: 0,
|
|
68694
|
-
errorMessage: link.credentialHint
|
|
68695
|
-
};
|
|
68696
|
-
}
|
|
68697
|
-
const startedAt = Date.now();
|
|
68698
|
-
let response;
|
|
68699
|
-
try {
|
|
68700
|
-
response = await fetch(`${proxyUrl}/v1/messages`, {
|
|
68701
|
-
method: "POST",
|
|
68702
|
-
headers: {
|
|
68703
|
-
"Content-Type": "application/json"
|
|
68704
|
-
},
|
|
68705
|
-
body: JSON.stringify({
|
|
68706
|
-
model: link.modelSpec,
|
|
68707
|
-
system: "You are a helpful assistant.",
|
|
68708
|
-
messages: [{ role: "user", content: PROBE_PROMPT }],
|
|
68709
|
-
max_tokens: PROBE_MAX_TOKENS,
|
|
68710
|
-
output_config: { effort: "minimal" },
|
|
68711
|
-
stream: true
|
|
68712
|
-
}),
|
|
68713
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
68714
|
-
});
|
|
68715
|
-
} catch (e) {
|
|
68716
|
-
const latencyMs = Date.now() - startedAt;
|
|
68717
|
-
const name = e?.name || "";
|
|
68718
|
-
const msg2 = String(e?.message || e);
|
|
68719
|
-
if (name === "TimeoutError" || name === "AbortError" || /timeout/i.test(msg2)) {
|
|
68720
|
-
return { state: "timeout", latencyMs, errorMessage: msg2 };
|
|
68721
|
-
}
|
|
68722
|
-
return { state: "network-error", latencyMs, errorMessage: msg2 };
|
|
68723
|
-
}
|
|
68724
|
-
const ttfbMs = Date.now() - startedAt;
|
|
68725
|
-
if (!response.ok) {
|
|
68726
|
-
const body = await safeReadBody(response);
|
|
68727
|
-
return annotateOAuthHint(classifyHttpError(response.status, body, ttfbMs), link.provider, isOAuth);
|
|
68728
|
-
}
|
|
68729
|
-
const streamResult = await consumeProbeStream(response, timeoutMs, startedAt);
|
|
68730
|
-
const totalMs = Date.now() - startedAt;
|
|
68731
|
-
let timing2;
|
|
68732
|
-
if (streamResult.state === "live" && streamResult.ttftMs !== undefined && !streamResult.truncated) {
|
|
68733
|
-
const ttftMs = streamResult.ttftMs;
|
|
68734
|
-
const tokens = streamResult.tokens ?? 0;
|
|
68735
|
-
const streamMs = Math.max(STREAM_MS_FLOOR, totalMs - ttftMs);
|
|
68736
|
-
const tokensPerSec = tokens > 0 ? tokens / streamMs * 1000 : 0;
|
|
68737
|
-
timing2 = { ttfbMs, ttftMs, totalMs, tokens, tokensPerSec };
|
|
68738
|
-
}
|
|
68739
|
-
const { ttftMs: _ttft, tokens: _tok, truncated: _trunc, ...rest } = streamResult;
|
|
68740
|
-
return annotateOAuthHint({
|
|
68741
|
-
...rest,
|
|
68742
|
-
latencyMs: totalMs,
|
|
68743
|
-
timing: timing2
|
|
68744
|
-
}, link.provider, isOAuth);
|
|
68745
|
-
}
|
|
68746
|
-
function annotateOAuthHint(result, provider, isOAuth) {
|
|
68747
|
-
if (!isOAuth)
|
|
68748
|
-
return result;
|
|
68749
|
-
if (result.state === "live")
|
|
68750
|
-
return result;
|
|
68751
|
-
const loginCommand2 = provider === "antigravity" ? "claudish login antigravity" : provider === "vertex" ? "gcloud auth application-default login" : provider === "devin" ? "devin login" : undefined;
|
|
68752
|
-
if (!loginCommand2)
|
|
68753
|
-
return result;
|
|
68754
|
-
if (result.httpStatus === 403)
|
|
68755
|
-
return result;
|
|
68756
|
-
const looksLikeAuthFailure = result.state === "auth-failed" || /auth|token|login|credential|unauthor/i.test(result.errorMessage || "");
|
|
68757
|
-
if (!looksLikeAuthFailure)
|
|
68758
|
-
return result;
|
|
68759
|
-
return {
|
|
68760
|
-
...result,
|
|
68761
|
-
state: "auth-failed",
|
|
68762
|
-
actionHint: `run: ${loginCommand2}`
|
|
68763
|
-
};
|
|
68764
|
-
}
|
|
68765
|
-
async function safeReadBody(response) {
|
|
68766
|
-
try {
|
|
68767
|
-
const text = await response.text();
|
|
68768
|
-
return text.slice(0, 500);
|
|
68769
|
-
} catch {
|
|
68770
|
-
return "";
|
|
68771
|
-
}
|
|
68772
|
-
}
|
|
68773
|
-
function extractUpstreamStatus(body) {
|
|
68774
|
-
if (!body)
|
|
68775
|
-
return;
|
|
68776
|
-
try {
|
|
68777
|
-
const parsed = JSON.parse(body);
|
|
68778
|
-
const status = parsed?.error?.upstream_status;
|
|
68779
|
-
return typeof status === "number" ? status : undefined;
|
|
68780
|
-
} catch {
|
|
68781
|
-
return;
|
|
68782
|
-
}
|
|
68783
|
-
}
|
|
68784
|
-
function extractErrorType(body) {
|
|
68785
|
-
if (!body)
|
|
68786
|
-
return;
|
|
68787
|
-
try {
|
|
68788
|
-
const parsed = JSON.parse(body);
|
|
68789
|
-
const t = parsed?.error?.type;
|
|
68790
|
-
return typeof t === "string" ? t : undefined;
|
|
68791
|
-
} catch {
|
|
68792
|
-
return;
|
|
68793
|
-
}
|
|
68794
|
-
}
|
|
68795
|
-
function classifyHttpError(status, body, latencyMs) {
|
|
68796
|
-
const lowered = body.toLowerCase();
|
|
68797
|
-
if (extractErrorType(body) === "connection_error") {
|
|
68798
|
-
return {
|
|
68799
|
-
state: "network-error",
|
|
68800
|
-
latencyMs,
|
|
68801
|
-
httpStatus: status,
|
|
68802
|
-
errorMessage: extractErrorMessage(body) || "Cannot reach provider"
|
|
68803
|
-
};
|
|
68804
|
-
}
|
|
68805
|
-
const upstream = status === 400 ? extractUpstreamStatus(body) : undefined;
|
|
68806
|
-
if (status === 401 || status === 403 || upstream === 401 || upstream === 403) {
|
|
68807
|
-
const authStatus = upstream ?? status;
|
|
68808
|
-
return {
|
|
68809
|
-
state: "auth-failed",
|
|
68810
|
-
latencyMs,
|
|
68811
|
-
httpStatus: authStatus,
|
|
68812
|
-
errorMessage: extractErrorMessage(body) || `HTTP ${authStatus}`
|
|
68813
|
-
};
|
|
68814
|
-
}
|
|
68815
|
-
if (status === 404 || /model[_ ]not[_ ]found|no such model|unknown model/.test(lowered)) {
|
|
68816
|
-
return {
|
|
68817
|
-
state: "model-not-found",
|
|
68818
|
-
latencyMs,
|
|
68819
|
-
httpStatus: status,
|
|
68820
|
-
errorMessage: extractErrorMessage(body) || `HTTP ${status}`
|
|
68821
|
-
};
|
|
68822
|
-
}
|
|
68823
|
-
if (status === 429) {
|
|
68824
|
-
return {
|
|
68825
|
-
state: "rate-limited",
|
|
68826
|
-
latencyMs,
|
|
68827
|
-
httpStatus: status,
|
|
68828
|
-
errorMessage: extractErrorMessage(body) || "Rate limited"
|
|
68829
|
-
};
|
|
68830
|
-
}
|
|
68831
|
-
if (upstream === 429 || status === 402) {
|
|
68832
|
-
return {
|
|
68833
|
-
state: "out-of-credit",
|
|
68834
|
-
latencyMs,
|
|
68835
|
-
httpStatus: upstream ?? status,
|
|
68836
|
-
errorMessage: extractErrorMessage(body) || "Out of credit \u2014 account balance or plan exhausted"
|
|
68837
|
-
};
|
|
68838
|
-
}
|
|
68839
|
-
if (status >= 500) {
|
|
68840
|
-
return {
|
|
68841
|
-
state: "server-error",
|
|
68842
|
-
latencyMs,
|
|
68843
|
-
httpStatus: status,
|
|
68844
|
-
errorMessage: extractErrorMessage(body) || `HTTP ${status}`
|
|
68845
|
-
};
|
|
68846
|
-
}
|
|
68847
|
-
return {
|
|
68848
|
-
state: "error",
|
|
68849
|
-
latencyMs,
|
|
68850
|
-
httpStatus: status,
|
|
68851
|
-
errorMessage: extractErrorMessage(body) || `HTTP ${status}`
|
|
68852
|
-
};
|
|
68853
|
-
}
|
|
68854
|
-
function extractErrorMessage(body) {
|
|
68855
|
-
if (!body)
|
|
68856
|
-
return;
|
|
68857
|
-
try {
|
|
68858
|
-
const parsed = JSON.parse(body);
|
|
68859
|
-
const msg2 = parsed?.error?.message || parsed?.error?.error?.message || parsed?.message || parsed?.detail;
|
|
68860
|
-
if (typeof msg2 === "string" && msg2.length > 0) {
|
|
68861
|
-
return msg2.length > 160 ? `${msg2.slice(0, 157)}...` : msg2;
|
|
68862
|
-
}
|
|
68863
|
-
} catch {}
|
|
68864
|
-
const trimmed2 = body.trim();
|
|
68865
|
-
if (!trimmed2)
|
|
68866
|
-
return;
|
|
68867
|
-
return trimmed2.length > 160 ? `${trimmed2.slice(0, 157)}...` : trimmed2;
|
|
68868
|
-
}
|
|
68869
|
-
async function consumeProbeStream(response, timeoutMs, startedAt) {
|
|
68870
|
-
const body = response.body;
|
|
68871
|
-
if (!body) {
|
|
68872
|
-
return { state: "error", errorMessage: "empty response body" };
|
|
68873
|
-
}
|
|
68874
|
-
const reader = body.getReader();
|
|
68875
|
-
const decoder = new TextDecoder;
|
|
68876
|
-
let buffered = "";
|
|
68877
|
-
const deadline = Date.now() + timeoutMs;
|
|
68878
|
-
let ttftMs;
|
|
68879
|
-
let sawContent = false;
|
|
68880
|
-
let textChars = 0;
|
|
68881
|
-
let reportedTokens;
|
|
68882
|
-
let stopReason;
|
|
68883
|
-
let errorVerdict = null;
|
|
68884
|
-
let completed = false;
|
|
68885
|
-
try {
|
|
68886
|
-
while (Date.now() < deadline) {
|
|
68887
|
-
const { value, done } = await reader.read();
|
|
68888
|
-
if (done) {
|
|
68889
|
-
completed = true;
|
|
68890
|
-
break;
|
|
68891
|
-
}
|
|
68892
|
-
buffered += decoder.decode(value, { stream: true });
|
|
68893
|
-
const events = buffered.split(`
|
|
68894
|
-
|
|
68895
|
-
`);
|
|
68896
|
-
buffered = events.pop() ?? "";
|
|
68897
|
-
for (const event of events) {
|
|
68898
|
-
const verdict = interpretSseEvent(event);
|
|
68899
|
-
if (verdict && typeof verdict === "object" && verdict.state !== "live") {
|
|
68900
|
-
errorVerdict = verdict;
|
|
68901
|
-
break;
|
|
68902
|
-
}
|
|
68903
|
-
const acct = accountStreamEvent(event);
|
|
68904
|
-
if (acct.contentDelta) {
|
|
68905
|
-
if (ttftMs === undefined)
|
|
68906
|
-
ttftMs = Date.now() - startedAt;
|
|
68907
|
-
sawContent = true;
|
|
68908
|
-
}
|
|
68909
|
-
if (acct.textChars)
|
|
68910
|
-
textChars += acct.textChars;
|
|
68911
|
-
if (acct.outputTokens !== undefined)
|
|
68912
|
-
reportedTokens = acct.outputTokens;
|
|
68913
|
-
if (acct.stopReason)
|
|
68914
|
-
stopReason = acct.stopReason;
|
|
68915
|
-
}
|
|
68916
|
-
if (errorVerdict)
|
|
68917
|
-
break;
|
|
68918
|
-
}
|
|
68919
|
-
} catch (e) {
|
|
68920
|
-
if (!sawContent) {
|
|
68921
|
-
return { state: "network-error", errorMessage: String(e?.message || e) };
|
|
68922
|
-
}
|
|
68923
|
-
} finally {
|
|
68924
|
-
try {
|
|
68925
|
-
await reader.cancel();
|
|
68926
|
-
} catch {}
|
|
68927
|
-
}
|
|
68928
|
-
if (errorVerdict)
|
|
68929
|
-
return errorVerdict;
|
|
68930
|
-
if (sawContent) {
|
|
68931
|
-
const tokens = reportedTokens ?? Math.max(1, Math.round(textChars / 4));
|
|
68932
|
-
return { state: "live", ttftMs, tokens, truncated: !completed };
|
|
68933
|
-
}
|
|
68934
|
-
const truncationReason = stopReason === "max_tokens" || stopReason === "length" ? stopReason : undefined;
|
|
68935
|
-
if (truncationReason || reportedTokens !== undefined && reportedTokens >= PROBE_MAX_TOKENS) {
|
|
68936
|
-
const cause = truncationReason ? `finish: ${truncationReason}` : `${reportedTokens} tokens consumed, none visible`;
|
|
68937
|
-
return {
|
|
68938
|
-
state: "error",
|
|
68939
|
-
errorMessage: `no visible output within probe budget (${cause})`
|
|
68940
|
-
};
|
|
68941
|
-
}
|
|
68942
|
-
return { state: "error", errorMessage: "stream ended without content" };
|
|
68943
|
-
}
|
|
68944
|
-
function accountStreamEvent(rawEvent) {
|
|
68945
|
-
let dataPayload = "";
|
|
68946
|
-
for (const line of rawEvent.split(`
|
|
68947
|
-
`)) {
|
|
68948
|
-
if (line.startsWith("data:"))
|
|
68949
|
-
dataPayload += line.slice(5).trim();
|
|
68950
|
-
}
|
|
68951
|
-
if (!dataPayload || dataPayload === "[DONE]") {
|
|
68952
|
-
return { contentDelta: false, textChars: 0 };
|
|
68953
|
-
}
|
|
68954
|
-
let parsed;
|
|
68955
|
-
try {
|
|
68956
|
-
parsed = JSON.parse(dataPayload);
|
|
68957
|
-
} catch {
|
|
68958
|
-
return { contentDelta: false, textChars: 0 };
|
|
68959
|
-
}
|
|
68960
|
-
let textChars = 0;
|
|
68961
|
-
let contentDelta = false;
|
|
68962
|
-
const text = parsed?.delta?.text ?? (Array.isArray(parsed?.choices) ? parsed.choices[0]?.delta?.content : undefined);
|
|
68963
|
-
if (typeof text === "string" && text.length > 0) {
|
|
68964
|
-
contentDelta = true;
|
|
68965
|
-
textChars = text.length;
|
|
68966
|
-
} else if (parsed?.type === "content_block_delta" || parsed?.type === "content_block_start") {
|
|
68967
|
-
contentDelta = true;
|
|
68968
|
-
}
|
|
68969
|
-
const outputTokens = parsed?.usage?.output_tokens ?? parsed?.message?.usage?.output_tokens ?? parsed?.usage?.completion_tokens;
|
|
68970
|
-
const stopReason = parsed?.delta?.stop_reason ?? (Array.isArray(parsed?.choices) ? parsed.choices[0]?.finish_reason : undefined);
|
|
68971
|
-
return {
|
|
68972
|
-
contentDelta,
|
|
68973
|
-
textChars,
|
|
68974
|
-
outputTokens: typeof outputTokens === "number" ? outputTokens : undefined,
|
|
68975
|
-
stopReason: typeof stopReason === "string" ? stopReason : undefined
|
|
68976
|
-
};
|
|
68977
|
-
}
|
|
68978
|
-
function interpretSseEvent(rawEvent) {
|
|
68979
|
-
const lines = rawEvent.split(`
|
|
68980
|
-
`);
|
|
68981
|
-
let eventType = "";
|
|
68982
|
-
let dataPayload = "";
|
|
68983
|
-
for (const line of lines) {
|
|
68984
|
-
if (line.startsWith("event:"))
|
|
68985
|
-
eventType = line.slice(6).trim();
|
|
68986
|
-
else if (line.startsWith("data:"))
|
|
68987
|
-
dataPayload += line.slice(5).trim();
|
|
68988
|
-
}
|
|
68989
|
-
if (!dataPayload)
|
|
68990
|
-
return null;
|
|
68991
|
-
if (dataPayload === "[DONE]")
|
|
68992
|
-
return null;
|
|
68993
|
-
let parsed;
|
|
68994
|
-
try {
|
|
68995
|
-
parsed = JSON.parse(dataPayload);
|
|
68996
|
-
} catch {
|
|
68997
|
-
return null;
|
|
68998
|
-
}
|
|
68999
|
-
if (parsed?.type === "error" || eventType === "error" || parsed?.error) {
|
|
69000
|
-
const message = parsed?.error?.message || parsed?.error?.error?.message || parsed?.message || "provider returned error event";
|
|
69001
|
-
const status = parsed?.error?.status || parsed?.status;
|
|
69002
|
-
if (typeof status === "number") {
|
|
69003
|
-
return {
|
|
69004
|
-
state: status === 401 || status === 403 ? "auth-failed" : "error",
|
|
69005
|
-
httpStatus: status,
|
|
69006
|
-
errorMessage: message
|
|
69007
|
-
};
|
|
69008
|
-
}
|
|
69009
|
-
return { state: "error", errorMessage: message };
|
|
69010
|
-
}
|
|
69011
|
-
if (isContentEvent(parsed, eventType)) {
|
|
69012
|
-
return "live";
|
|
69013
|
-
}
|
|
69014
|
-
return null;
|
|
69015
|
-
}
|
|
69016
|
-
function isContentEvent(parsed, eventType) {
|
|
69017
|
-
if (eventType === "content_block_start" || eventType === "content_block_delta")
|
|
69018
|
-
return true;
|
|
69019
|
-
if (eventType === "message_start")
|
|
69020
|
-
return true;
|
|
69021
|
-
if (parsed?.type === "content_block_start")
|
|
69022
|
-
return true;
|
|
69023
|
-
if (parsed?.type === "content_block_delta")
|
|
69024
|
-
return true;
|
|
69025
|
-
if (parsed?.type === "message_start")
|
|
69026
|
-
return true;
|
|
69027
|
-
if (parsed?.type === "message_delta")
|
|
69028
|
-
return true;
|
|
69029
|
-
if (Array.isArray(parsed?.choices) && parsed.choices.length > 0) {
|
|
69030
|
-
const choice = parsed.choices[0];
|
|
69031
|
-
if (choice?.delta || choice?.message || choice?.text || choice?.finish_reason)
|
|
69032
|
-
return true;
|
|
69033
|
-
}
|
|
69034
|
-
if (parsed?.candidates)
|
|
69035
|
-
return true;
|
|
69036
|
-
return false;
|
|
69037
|
-
}
|
|
69038
|
-
function withDetail(base, message) {
|
|
69039
|
-
return message ? `${base} \u2014 ${message}` : base;
|
|
69040
|
-
}
|
|
69041
|
-
function describeProbeState(result) {
|
|
69042
|
-
const status = result.httpStatus ?? "";
|
|
69043
|
-
const latency = result.latencyMs ? ` \xB7 ${result.latencyMs}ms` : "";
|
|
69044
|
-
switch (result.state) {
|
|
69045
|
-
case "live":
|
|
69046
|
-
return `live \xB7 ${result.latencyMs}ms`;
|
|
69047
|
-
case "key-missing":
|
|
69048
|
-
return result.errorMessage ? `missing (${result.errorMessage})` : "missing";
|
|
69049
|
-
case "auth-failed":
|
|
69050
|
-
return withDetail(`auth failed \xB7 ${status}${latency}`.trim(), result.errorMessage);
|
|
69051
|
-
case "model-not-found":
|
|
69052
|
-
return withDetail(`model not found \xB7 ${status}${latency}`.trim(), result.errorMessage);
|
|
69053
|
-
case "rate-limited":
|
|
69054
|
-
return withDetail(`rate limited \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
69055
|
-
case "out-of-credit":
|
|
69056
|
-
return withDetail(`out of credit \xB7 ${status}${latency}`.trim(), result.errorMessage);
|
|
69057
|
-
case "server-error":
|
|
69058
|
-
return withDetail(`server error \xB7 ${status} \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
69059
|
-
case "timeout":
|
|
69060
|
-
return withDetail(`timeout \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
69061
|
-
case "network-error":
|
|
69062
|
-
return withDetail(`network error \xB7 ${result.latencyMs}ms`, result.errorMessage);
|
|
69063
|
-
case "error": {
|
|
69064
|
-
const base = `error${result.httpStatus ? ` \xB7 ${result.httpStatus}` : ""}${latency}`;
|
|
69065
|
-
return withDetail(base, result.errorMessage);
|
|
69066
|
-
}
|
|
69067
|
-
}
|
|
69068
|
-
}
|
|
69069
|
-
function isReadyState(state) {
|
|
69070
|
-
return state === "live";
|
|
69071
|
-
}
|
|
69072
|
-
function isFailureState(state) {
|
|
69073
|
-
return state === "auth-failed" || state === "model-not-found" || state === "rate-limited" || state === "out-of-credit" || state === "server-error" || state === "timeout" || state === "network-error" || state === "error";
|
|
69074
|
-
}
|
|
69075
|
-
var STREAM_MS_FLOOR = 50, OAUTH_PROVIDERS2, PROBE_PROMPT = "Count from one to twenty in words, one per line.", PROBE_MAX_TOKENS = 512;
|
|
69076
|
-
var init_probe_live = __esm(() => {
|
|
69077
|
-
OAUTH_PROVIDERS2 = new Set(["vertex", "antigravity", "devin"]);
|
|
69078
|
-
});
|
|
69079
|
-
|
|
69080
69265
|
// src/tui/theme.ts
|
|
69081
69266
|
import { createTextAttributes } from "@opentui/core";
|
|
69082
69267
|
function latencyBucket(ms) {
|
|
@@ -71350,6 +71535,21 @@ var init_api_key_map = __esm(() => {
|
|
|
71350
71535
|
};
|
|
71351
71536
|
});
|
|
71352
71537
|
|
|
71538
|
+
// src/providers/claude-code-aliases.ts
|
|
71539
|
+
function claudeCodeTierAlias(model) {
|
|
71540
|
+
return TIER_ALIASES[model.trim().toLowerCase()] ?? null;
|
|
71541
|
+
}
|
|
71542
|
+
var TIER_ALIASES;
|
|
71543
|
+
var init_claude_code_aliases = __esm(() => {
|
|
71544
|
+
TIER_ALIASES = {
|
|
71545
|
+
opus: "opus",
|
|
71546
|
+
sonnet: "sonnet",
|
|
71547
|
+
haiku: "haiku",
|
|
71548
|
+
internal: "opus",
|
|
71549
|
+
default: "opus"
|
|
71550
|
+
};
|
|
71551
|
+
});
|
|
71552
|
+
|
|
71353
71553
|
// src/providers/probe-runner.ts
|
|
71354
71554
|
function pinProbeModelSpec(link) {
|
|
71355
71555
|
if (link.provider === "native-anthropic")
|
|
@@ -72041,7 +72241,7 @@ async function printRecommendedModels(jsonOutput, forceUpdate) {
|
|
|
72041
72241
|
const rawId = m.id;
|
|
72042
72242
|
const modelId = rawId.length > 28 ? `${rawId.substring(0, 25)}...` : rawId;
|
|
72043
72243
|
const modelIdPadded = modelId.padEnd(28);
|
|
72044
|
-
const pricing =
|
|
72244
|
+
const pricing = formatListingPrice(m, { compact: true });
|
|
72045
72245
|
const pricingPadded = pricing.padEnd(10);
|
|
72046
72246
|
const context = m.context || "N/A";
|
|
72047
72247
|
const contextPadded = context.padEnd(6);
|
|
@@ -72133,13 +72333,19 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
|
|
|
72133
72333
|
};
|
|
72134
72334
|
}
|
|
72135
72335
|
if (parsed.provider === "native-anthropic") {
|
|
72136
|
-
const
|
|
72336
|
+
const tier = claudeCodeTierAlias(parsed.model);
|
|
72337
|
+
const tierEnv = {
|
|
72338
|
+
opus: process.env[ENV.CLAUDISH_MODEL_OPUS] || process.env[ENV.ANTHROPIC_DEFAULT_OPUS_MODEL],
|
|
72339
|
+
sonnet: process.env[ENV.CLAUDISH_MODEL_SONNET] || process.env[ENV.ANTHROPIC_DEFAULT_SONNET_MODEL],
|
|
72340
|
+
haiku: process.env[ENV.CLAUDISH_MODEL_HAIKU] || process.env[ENV.ANTHROPIC_DEFAULT_HAIKU_MODEL]
|
|
72341
|
+
};
|
|
72342
|
+
const opusModel = tier ? tierEnv[tier] || latestAnthropicTierModelId(tier) || "claude-opus-5" : parsed.model;
|
|
72137
72343
|
return {
|
|
72138
72344
|
routes: [
|
|
72139
72345
|
{
|
|
72140
72346
|
provider: "native-anthropic",
|
|
72141
72347
|
modelSpec: opusModel,
|
|
72142
|
-
displayName:
|
|
72348
|
+
displayName: tier ? `Claude Code (${tier})` : "Claude Code"
|
|
72143
72349
|
}
|
|
72144
72350
|
],
|
|
72145
72351
|
source: "auto-chain",
|
|
@@ -72233,6 +72439,33 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
|
|
|
72233
72439
|
}
|
|
72234
72440
|
return chain.source;
|
|
72235
72441
|
}
|
|
72442
|
+
function buildDirectChainEntry(parsed, directProbe) {
|
|
72443
|
+
const providerDef = getProviderByName(parsed.provider);
|
|
72444
|
+
const keyInfo = API_KEY_MAP[parsed.provider];
|
|
72445
|
+
if (!providerDef && !keyInfo)
|
|
72446
|
+
return [];
|
|
72447
|
+
let hasCredentials;
|
|
72448
|
+
let provenance;
|
|
72449
|
+
if (providerDef?.isLocal) {
|
|
72450
|
+
hasCredentials = isLocalProviderEnabled(parsed.provider);
|
|
72451
|
+
} else if (!keyInfo?.envVar) {
|
|
72452
|
+
hasCredentials = true;
|
|
72453
|
+
} else {
|
|
72454
|
+
provenance = resolveApiKeyProvenance(keyInfo.envVar, keyInfo.aliases);
|
|
72455
|
+
hasCredentials = provenance.hasValue || (keyInfo.aliases?.some((a) => !!process.env[a]) ?? false);
|
|
72456
|
+
}
|
|
72457
|
+
return [
|
|
72458
|
+
{
|
|
72459
|
+
provider: parsed.provider,
|
|
72460
|
+
displayName: providerDef?.displayName ?? parsed.provider,
|
|
72461
|
+
modelSpec: parsed.model,
|
|
72462
|
+
hasCredentials,
|
|
72463
|
+
credentialHint: !hasCredentials ? providerDef?.isLocal ? "enable local provider in global config" : keyInfo?.envVar : undefined,
|
|
72464
|
+
provenance,
|
|
72465
|
+
probe: directProbe
|
|
72466
|
+
}
|
|
72467
|
+
];
|
|
72468
|
+
}
|
|
72236
72469
|
function buildResultLinks(parsed, chainDetails, directProbe) {
|
|
72237
72470
|
if (chainDetails.length === 0) {
|
|
72238
72471
|
const directProviderDef = getProviderByName(parsed.provider);
|
|
@@ -72383,7 +72616,7 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
|
|
|
72383
72616
|
isExplicit: parsed.isExplicitProvider,
|
|
72384
72617
|
routingSource: chain.source,
|
|
72385
72618
|
matchedPattern: chain.matchedPattern,
|
|
72386
|
-
chain: chainDetails,
|
|
72619
|
+
chain: chainDetails.length > 0 ? chainDetails : buildDirectChainEntry(parsed, directProbeResult),
|
|
72387
72620
|
directProbe: directProbeResult,
|
|
72388
72621
|
wiring
|
|
72389
72622
|
});
|
|
@@ -73010,6 +73243,8 @@ var init_cli = __esm(() => {
|
|
|
73010
73243
|
init_profile_config();
|
|
73011
73244
|
init_api_key_map();
|
|
73012
73245
|
init_api_key_provenance();
|
|
73246
|
+
init_catalog_client();
|
|
73247
|
+
init_claude_code_aliases();
|
|
73013
73248
|
init_endpoint_registration();
|
|
73014
73249
|
init_model_parser();
|
|
73015
73250
|
init_probe_live();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudish",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.57.0",
|
|
4
4
|
"description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
"ai"
|
|
61
61
|
],
|
|
62
62
|
"optionalDependencies": {
|
|
63
|
-
"@claudish/magmux-darwin-arm64": "7.
|
|
64
|
-
"@claudish/magmux-darwin-x64": "7.
|
|
65
|
-
"@claudish/magmux-linux-arm64": "7.
|
|
66
|
-
"@claudish/magmux-linux-x64": "7.
|
|
63
|
+
"@claudish/magmux-darwin-arm64": "7.57.0",
|
|
64
|
+
"@claudish/magmux-darwin-x64": "7.57.0",
|
|
65
|
+
"@claudish/magmux-linux-arm64": "7.57.0",
|
|
66
|
+
"@claudish/magmux-linux-x64": "7.57.0"
|
|
67
67
|
},
|
|
68
68
|
"author": "Jack Rudenko <i@madappgang.com>",
|
|
69
69
|
"license": "MIT",
|