claudish 6.2.2 → 6.3.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 +619 -14
- package/package.json +1 -1
- package/recommended-models.json +1 -1
package/dist/index.js
CHANGED
|
@@ -37103,7 +37103,7 @@ async function fetchGLMCodingModels() {
|
|
|
37103
37103
|
return [];
|
|
37104
37104
|
}
|
|
37105
37105
|
}
|
|
37106
|
-
var __filename4, __dirname4, VERSION = "6.
|
|
37106
|
+
var __filename4, __dirname4, VERSION = "6.3.0", CACHE_MAX_AGE_DAYS2 = 2, CLAUDISH_CACHE_DIR2, BUNDLED_MODELS_PATH, CACHED_MODELS_PATH, ALL_MODELS_JSON_PATH;
|
|
37107
37107
|
var init_cli = __esm(() => {
|
|
37108
37108
|
init_config();
|
|
37109
37109
|
init_model_loader();
|
|
@@ -98318,6 +98318,141 @@ var init_react = __esm(async () => {
|
|
|
98318
98318
|
extend2({ "time-to-first-draw": TimeToFirstDrawRenderable });
|
|
98319
98319
|
});
|
|
98320
98320
|
|
|
98321
|
+
// src/tui/test-provider.ts
|
|
98322
|
+
function resolveBaseUrl(def) {
|
|
98323
|
+
if (def.baseUrlEnvVars) {
|
|
98324
|
+
for (const envVar of def.baseUrlEnvVars) {
|
|
98325
|
+
const val = process.env[envVar];
|
|
98326
|
+
if (val)
|
|
98327
|
+
return val.replace(/\/$/, "");
|
|
98328
|
+
}
|
|
98329
|
+
}
|
|
98330
|
+
return def.baseUrl.replace(/\/$/, "");
|
|
98331
|
+
}
|
|
98332
|
+
function getApiFamily(def) {
|
|
98333
|
+
switch (def.transport) {
|
|
98334
|
+
case "openai":
|
|
98335
|
+
case "openrouter":
|
|
98336
|
+
case "litellm":
|
|
98337
|
+
case "kimi-coding":
|
|
98338
|
+
return "openai";
|
|
98339
|
+
case "anthropic":
|
|
98340
|
+
return "anthropic";
|
|
98341
|
+
case "gemini":
|
|
98342
|
+
case "gemini-oauth":
|
|
98343
|
+
return "gemini";
|
|
98344
|
+
case "ollamacloud":
|
|
98345
|
+
return "ollamacloud";
|
|
98346
|
+
default:
|
|
98347
|
+
return "unsupported";
|
|
98348
|
+
}
|
|
98349
|
+
}
|
|
98350
|
+
async function testOpenAI(baseUrl, apiKey) {
|
|
98351
|
+
const url2 = `${baseUrl}/v1/models`;
|
|
98352
|
+
const signal = AbortSignal.timeout(TIMEOUT_MS);
|
|
98353
|
+
try {
|
|
98354
|
+
const resp = await fetch(url2, {
|
|
98355
|
+
method: "GET",
|
|
98356
|
+
headers: {
|
|
98357
|
+
Authorization: `Bearer ${apiKey}`,
|
|
98358
|
+
"Content-Type": "application/json"
|
|
98359
|
+
},
|
|
98360
|
+
signal
|
|
98361
|
+
});
|
|
98362
|
+
if (resp.ok)
|
|
98363
|
+
return "valid";
|
|
98364
|
+
return `invalid (HTTP ${resp.status})`;
|
|
98365
|
+
} catch (err) {
|
|
98366
|
+
if (err instanceof Error && err.name === "TimeoutError")
|
|
98367
|
+
return "timeout";
|
|
98368
|
+
return `error: ${err instanceof Error ? err.message : String(err)}`;
|
|
98369
|
+
}
|
|
98370
|
+
}
|
|
98371
|
+
async function testAnthropic(baseUrl, apiKey, authScheme = "x-api-key") {
|
|
98372
|
+
const url2 = `${baseUrl}/anthropic/v1/messages`;
|
|
98373
|
+
const signal = AbortSignal.timeout(TIMEOUT_MS);
|
|
98374
|
+
const authHeader = authScheme === "bearer" ? { Authorization: `Bearer ${apiKey}` } : { "x-api-key": apiKey };
|
|
98375
|
+
try {
|
|
98376
|
+
const resp = await fetch(url2, {
|
|
98377
|
+
method: "POST",
|
|
98378
|
+
headers: {
|
|
98379
|
+
"Content-Type": "application/json",
|
|
98380
|
+
"anthropic-version": "2023-06-01",
|
|
98381
|
+
...authHeader
|
|
98382
|
+
},
|
|
98383
|
+
body: JSON.stringify({
|
|
98384
|
+
model: "claude-3-haiku-20240307",
|
|
98385
|
+
max_tokens: 1,
|
|
98386
|
+
messages: [{ role: "user", content: "Hi" }]
|
|
98387
|
+
}),
|
|
98388
|
+
signal
|
|
98389
|
+
});
|
|
98390
|
+
if (resp.ok || resp.status === 400)
|
|
98391
|
+
return "valid";
|
|
98392
|
+
return `invalid (HTTP ${resp.status})`;
|
|
98393
|
+
} catch (err) {
|
|
98394
|
+
if (err instanceof Error && err.name === "TimeoutError")
|
|
98395
|
+
return "timeout";
|
|
98396
|
+
return `error: ${err instanceof Error ? err.message : String(err)}`;
|
|
98397
|
+
}
|
|
98398
|
+
}
|
|
98399
|
+
async function testGemini(baseUrl, apiKey) {
|
|
98400
|
+
const url2 = `${baseUrl}/v1beta/models?key=${encodeURIComponent(apiKey)}`;
|
|
98401
|
+
const signal = AbortSignal.timeout(TIMEOUT_MS);
|
|
98402
|
+
try {
|
|
98403
|
+
const resp = await fetch(url2, { signal });
|
|
98404
|
+
if (resp.ok)
|
|
98405
|
+
return "valid";
|
|
98406
|
+
return `invalid (HTTP ${resp.status})`;
|
|
98407
|
+
} catch (err) {
|
|
98408
|
+
if (err instanceof Error && err.name === "TimeoutError")
|
|
98409
|
+
return "timeout";
|
|
98410
|
+
return `error: ${err instanceof Error ? err.message : String(err)}`;
|
|
98411
|
+
}
|
|
98412
|
+
}
|
|
98413
|
+
async function testOllamaCloud(baseUrl, apiKey) {
|
|
98414
|
+
const url2 = `${baseUrl}/api/tags`;
|
|
98415
|
+
const signal = AbortSignal.timeout(TIMEOUT_MS);
|
|
98416
|
+
try {
|
|
98417
|
+
const resp = await fetch(url2, {
|
|
98418
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
98419
|
+
signal
|
|
98420
|
+
});
|
|
98421
|
+
if (resp.ok)
|
|
98422
|
+
return "valid";
|
|
98423
|
+
return `invalid (HTTP ${resp.status})`;
|
|
98424
|
+
} catch (err) {
|
|
98425
|
+
if (err instanceof Error && err.name === "TimeoutError")
|
|
98426
|
+
return "timeout";
|
|
98427
|
+
return `error: ${err instanceof Error ? err.message : String(err)}`;
|
|
98428
|
+
}
|
|
98429
|
+
}
|
|
98430
|
+
async function testProviderKey(providerName, apiKey) {
|
|
98431
|
+
const allDefs = getAllProviders();
|
|
98432
|
+
const canonicalName = providerName === "gemini" ? "google" : providerName;
|
|
98433
|
+
const def = allDefs.find((d2) => d2.name === canonicalName);
|
|
98434
|
+
if (!def)
|
|
98435
|
+
return "unsupported provider";
|
|
98436
|
+
const family = getApiFamily(def);
|
|
98437
|
+
const baseUrl = resolveBaseUrl(def);
|
|
98438
|
+
switch (family) {
|
|
98439
|
+
case "openai":
|
|
98440
|
+
return testOpenAI(baseUrl, apiKey);
|
|
98441
|
+
case "anthropic":
|
|
98442
|
+
return testAnthropic(baseUrl, apiKey, def.authScheme === "bearer" ? "bearer" : "x-api-key");
|
|
98443
|
+
case "gemini":
|
|
98444
|
+
return testGemini(baseUrl, apiKey);
|
|
98445
|
+
case "ollamacloud":
|
|
98446
|
+
return testOllamaCloud(baseUrl, apiKey);
|
|
98447
|
+
default:
|
|
98448
|
+
return "unsupported provider";
|
|
98449
|
+
}
|
|
98450
|
+
}
|
|
98451
|
+
var TIMEOUT_MS = 1e4;
|
|
98452
|
+
var init_test_provider = __esm(() => {
|
|
98453
|
+
init_provider_definitions();
|
|
98454
|
+
});
|
|
98455
|
+
|
|
98321
98456
|
// src/tui/providers.ts
|
|
98322
98457
|
function toProviderDef(def) {
|
|
98323
98458
|
return {
|
|
@@ -98403,6 +98538,10 @@ function App() {
|
|
|
98403
98538
|
const [chainOrder, setChainOrder] = import_react13.useState([]);
|
|
98404
98539
|
const [chainCursor, setChainCursor] = import_react13.useState(0);
|
|
98405
98540
|
const [statusMsg, setStatusMsg] = import_react13.useState(null);
|
|
98541
|
+
const [testResults, setTestResults] = import_react13.useState({});
|
|
98542
|
+
const [probeMode, setProbeMode] = import_react13.useState("idle");
|
|
98543
|
+
const [probeModel, setProbeModel] = import_react13.useState("");
|
|
98544
|
+
const [probeResults, setProbeResults] = import_react13.useState([]);
|
|
98406
98545
|
const CHAIN_PROVIDERS = PROVIDERS;
|
|
98407
98546
|
const quit = import_react13.useCallback(() => renderer.destroy(), [renderer]);
|
|
98408
98547
|
const displayProviders = import_react13.useMemo(() => {
|
|
@@ -98434,6 +98573,110 @@ function App() {
|
|
|
98434
98573
|
useKeyboard((key) => {
|
|
98435
98574
|
if (key.ctrl && key.name === "c")
|
|
98436
98575
|
return quit();
|
|
98576
|
+
if (probeMode === "input") {
|
|
98577
|
+
if (key.name === "return" || key.name === "enter") {
|
|
98578
|
+
const model = probeModel.trim();
|
|
98579
|
+
if (!model) {
|
|
98580
|
+
setProbeModel("");
|
|
98581
|
+
setProbeMode("idle");
|
|
98582
|
+
return;
|
|
98583
|
+
}
|
|
98584
|
+
const parsed = parseModelSpec(model);
|
|
98585
|
+
const chain = getFallbackChain(model, parsed.provider);
|
|
98586
|
+
if (chain.length === 0) {
|
|
98587
|
+
setProbeResults([
|
|
98588
|
+
{
|
|
98589
|
+
provider: "none",
|
|
98590
|
+
displayName: "No routes found",
|
|
98591
|
+
status: "failed",
|
|
98592
|
+
error: "No credentials configured for any provider"
|
|
98593
|
+
}
|
|
98594
|
+
]);
|
|
98595
|
+
setProbeMode("done");
|
|
98596
|
+
return;
|
|
98597
|
+
}
|
|
98598
|
+
const ruleEntries2 = Object.entries(config3.routing ?? {});
|
|
98599
|
+
const matchedRule = ruleEntries2.find(([pat]) => {
|
|
98600
|
+
if (pat === model)
|
|
98601
|
+
return true;
|
|
98602
|
+
if (pat.includes("*")) {
|
|
98603
|
+
const regex2 = new RegExp("^" + pat.replace(/\*/g, ".*") + "$");
|
|
98604
|
+
return regex2.test(model);
|
|
98605
|
+
}
|
|
98606
|
+
return false;
|
|
98607
|
+
});
|
|
98608
|
+
const initial = chain.map((r) => {
|
|
98609
|
+
const provDef = PROVIDERS.find((p) => p.name === r.provider);
|
|
98610
|
+
const hk = !!(provDef && (config3.apiKeys?.[provDef.apiKeyEnvVar] || process.env[provDef.apiKeyEnvVar]));
|
|
98611
|
+
return {
|
|
98612
|
+
provider: r.provider,
|
|
98613
|
+
displayName: r.displayName,
|
|
98614
|
+
status: hk ? "pending" : "no_key",
|
|
98615
|
+
hasKey: hk,
|
|
98616
|
+
reason: matchedRule ? `Custom rule: ${matchedRule[0]}` : "Default fallback chain"
|
|
98617
|
+
};
|
|
98618
|
+
});
|
|
98619
|
+
setProbeResults(initial);
|
|
98620
|
+
setProbeMode("running");
|
|
98621
|
+
(async () => {
|
|
98622
|
+
for (let i = 0;i < chain.length; i++) {
|
|
98623
|
+
const entry = initial[i];
|
|
98624
|
+
if (!entry.hasKey) {
|
|
98625
|
+
continue;
|
|
98626
|
+
}
|
|
98627
|
+
setProbeResults((prev) => prev.map((e, idx) => idx === i ? { ...e, status: "testing" } : e));
|
|
98628
|
+
const startMs = Date.now();
|
|
98629
|
+
const provDef = PROVIDERS.find((p) => p.name === chain[i].provider);
|
|
98630
|
+
const apiKey = (provDef ? config3.apiKeys?.[provDef.apiKeyEnvVar] || process.env[provDef.apiKeyEnvVar] : undefined) ?? "";
|
|
98631
|
+
const elapsed = () => Date.now() - startMs;
|
|
98632
|
+
const result = await testProviderKey(chain[i].provider, apiKey);
|
|
98633
|
+
const ms = elapsed();
|
|
98634
|
+
const ok = result === "valid";
|
|
98635
|
+
setProbeResults((prev) => prev.map((e, idx) => {
|
|
98636
|
+
if (idx === i)
|
|
98637
|
+
return { ...e, status: ok ? "success" : "failed", error: ok ? undefined : result, ms };
|
|
98638
|
+
if (idx > i && ok && e.status !== "no_key")
|
|
98639
|
+
return { ...e, status: "skipped" };
|
|
98640
|
+
return e;
|
|
98641
|
+
}));
|
|
98642
|
+
if (ok)
|
|
98643
|
+
break;
|
|
98644
|
+
}
|
|
98645
|
+
setProbeMode("done");
|
|
98646
|
+
})();
|
|
98647
|
+
return;
|
|
98648
|
+
} else if (key.name === "escape") {
|
|
98649
|
+
setProbeModel("");
|
|
98650
|
+
setProbeMode("idle");
|
|
98651
|
+
} else if (key.name === "backspace" || key.name === "delete") {
|
|
98652
|
+
setProbeModel((p) => p.slice(0, -1));
|
|
98653
|
+
} else if (key.raw && key.raw.length === 1 && !key.ctrl && !key.meta) {
|
|
98654
|
+
setProbeModel((p) => p + key.raw);
|
|
98655
|
+
}
|
|
98656
|
+
return;
|
|
98657
|
+
}
|
|
98658
|
+
if (probeMode === "running" && activeTab === "routing") {
|
|
98659
|
+
if (key.name === "escape") {
|
|
98660
|
+
setProbeModel("");
|
|
98661
|
+
setProbeResults([]);
|
|
98662
|
+
setProbeMode("idle");
|
|
98663
|
+
}
|
|
98664
|
+
return;
|
|
98665
|
+
}
|
|
98666
|
+
if (probeMode === "done" && activeTab === "routing") {
|
|
98667
|
+
if (key.name === "q") {
|
|
98668
|
+
return quit();
|
|
98669
|
+
} else if (key.name === "escape" || key.name === "p") {
|
|
98670
|
+
setProbeModel("");
|
|
98671
|
+
setProbeResults([]);
|
|
98672
|
+
setProbeMode("idle");
|
|
98673
|
+
} else if (key.name === "return" || key.name === "enter") {
|
|
98674
|
+
setProbeModel("");
|
|
98675
|
+
setProbeResults([]);
|
|
98676
|
+
setProbeMode("input");
|
|
98677
|
+
}
|
|
98678
|
+
return;
|
|
98679
|
+
}
|
|
98437
98680
|
if (mode === "input_key" || mode === "input_endpoint") {
|
|
98438
98681
|
if (key.name === "return" || key.name === "enter") {
|
|
98439
98682
|
const val = inputValue.trim();
|
|
@@ -98591,6 +98834,23 @@ function App() {
|
|
|
98591
98834
|
} else {
|
|
98592
98835
|
setStatusMsg("No stored key to remove.");
|
|
98593
98836
|
}
|
|
98837
|
+
} else if (key.name === "t") {
|
|
98838
|
+
const apiKey = config3.apiKeys?.[selectedProvider.apiKeyEnvVar] || process.env[selectedProvider.apiKeyEnvVar];
|
|
98839
|
+
const provName = selectedProvider.name;
|
|
98840
|
+
if (!apiKey) {
|
|
98841
|
+
setTestResults((prev) => ({ ...prev, [provName]: { status: "failed", error: "No key configured" } }));
|
|
98842
|
+
return;
|
|
98843
|
+
}
|
|
98844
|
+
setTestResults((prev) => ({ ...prev, [provName]: { status: "testing" } }));
|
|
98845
|
+
const startMs = Date.now();
|
|
98846
|
+
testProviderKey(provName, apiKey).then((result) => {
|
|
98847
|
+
const ms = Date.now() - startMs;
|
|
98848
|
+
const ok = result === "valid";
|
|
98849
|
+
setTestResults((prev) => ({
|
|
98850
|
+
...prev,
|
|
98851
|
+
[provName]: ok ? { status: "valid", ms } : { status: "failed", error: result, ms }
|
|
98852
|
+
}));
|
|
98853
|
+
});
|
|
98594
98854
|
}
|
|
98595
98855
|
} else if (activeTab === "routing") {
|
|
98596
98856
|
if (key.name === "a") {
|
|
@@ -98615,6 +98875,11 @@ function App() {
|
|
|
98615
98875
|
setProviderIndex((i) => Math.max(0, i - 1));
|
|
98616
98876
|
} else if (key.name === "down" || key.name === "j") {
|
|
98617
98877
|
setProviderIndex((i) => Math.min(Math.max(0, ruleEntries.length - 1), i + 1));
|
|
98878
|
+
} else if (key.name === "p") {
|
|
98879
|
+
setProbeModel("");
|
|
98880
|
+
setProbeResults([]);
|
|
98881
|
+
setStatusMsg(null);
|
|
98882
|
+
setProbeMode("input");
|
|
98618
98883
|
}
|
|
98619
98884
|
} else if (activeTab === "privacy") {
|
|
98620
98885
|
if (key.name === "t") {
|
|
@@ -98771,6 +99036,21 @@ function App() {
|
|
|
98771
99036
|
const isFirstUnready = !isReady && !separatorRendered;
|
|
98772
99037
|
if (isFirstUnready)
|
|
98773
99038
|
separatorRendered = true;
|
|
99039
|
+
const tr = testResults[p.name];
|
|
99040
|
+
let statusFg = isReady ? C2.green : C2.dim;
|
|
99041
|
+
let statusText = isReady ? "ready " : "not set";
|
|
99042
|
+
if (tr) {
|
|
99043
|
+
if (tr.status === "testing") {
|
|
99044
|
+
statusFg = C2.yellow;
|
|
99045
|
+
statusText = "testing";
|
|
99046
|
+
} else if (tr.status === "valid") {
|
|
99047
|
+
statusFg = C2.green;
|
|
99048
|
+
statusText = tr.ms !== undefined ? `ready ${tr.ms}ms` : "ready \u2713";
|
|
99049
|
+
} else {
|
|
99050
|
+
statusFg = C2.red;
|
|
99051
|
+
statusText = "FAIL ";
|
|
99052
|
+
}
|
|
99053
|
+
}
|
|
98774
99054
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
98775
99055
|
flexDirection: "column",
|
|
98776
99056
|
children: [
|
|
@@ -98794,8 +99074,8 @@ function App() {
|
|
|
98794
99074
|
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
98795
99075
|
children: [
|
|
98796
99076
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
98797
|
-
fg: isReady ? C2.green : C2.dim,
|
|
98798
|
-
children: isReady ? "\u25CF" : "\u25CB"
|
|
99077
|
+
fg: tr?.status === "testing" ? C2.yellow : isReady ? C2.green : C2.dim,
|
|
99078
|
+
children: tr?.status === "testing" ? "\u25CC" : isReady ? "\u25CF" : "\u25CB"
|
|
98799
99079
|
}, undefined, false, undefined, this),
|
|
98800
99080
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
98801
99081
|
children: " "
|
|
@@ -98809,13 +99089,10 @@ function App() {
|
|
|
98809
99089
|
fg: C2.dim,
|
|
98810
99090
|
children: " "
|
|
98811
99091
|
}, undefined, false, undefined, this),
|
|
98812
|
-
|
|
98813
|
-
fg:
|
|
98814
|
-
bold:
|
|
98815
|
-
children:
|
|
98816
|
-
}, undefined, false, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
98817
|
-
fg: C2.dim,
|
|
98818
|
-
children: "not set"
|
|
99092
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99093
|
+
fg: statusFg,
|
|
99094
|
+
bold: tr?.status === "valid" || isReady,
|
|
99095
|
+
children: statusText
|
|
98819
99096
|
}, undefined, false, undefined, this),
|
|
98820
99097
|
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
98821
99098
|
fg: C2.dim,
|
|
@@ -98951,6 +99228,7 @@ function App() {
|
|
|
98951
99228
|
]
|
|
98952
99229
|
}, undefined, true, undefined, this);
|
|
98953
99230
|
}
|
|
99231
|
+
const tr = testResults[selectedProvider.name];
|
|
98954
99232
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
98955
99233
|
height: DETAIL_H,
|
|
98956
99234
|
border: true,
|
|
@@ -99055,6 +99333,50 @@ function App() {
|
|
|
99055
99333
|
children: selectedProvider.keyUrl
|
|
99056
99334
|
}, undefined, false, undefined, this)
|
|
99057
99335
|
]
|
|
99336
|
+
}, undefined, true, undefined, this),
|
|
99337
|
+
tr && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99338
|
+
children: [
|
|
99339
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99340
|
+
fg: C2.blue,
|
|
99341
|
+
bold: true,
|
|
99342
|
+
children: "Test: "
|
|
99343
|
+
}, undefined, false, undefined, this),
|
|
99344
|
+
tr.status === "testing" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99345
|
+
fg: C2.yellow,
|
|
99346
|
+
bold: true,
|
|
99347
|
+
children: "\u25CC testing..."
|
|
99348
|
+
}, undefined, false, undefined, this),
|
|
99349
|
+
tr.status === "valid" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
|
|
99350
|
+
children: [
|
|
99351
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99352
|
+
fg: C2.green,
|
|
99353
|
+
bold: true,
|
|
99354
|
+
children: "\u25CF valid"
|
|
99355
|
+
}, undefined, false, undefined, this),
|
|
99356
|
+
tr.ms !== undefined && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99357
|
+
fg: C2.dim,
|
|
99358
|
+
children: ` ${tr.ms}ms`
|
|
99359
|
+
}, undefined, false, undefined, this),
|
|
99360
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99361
|
+
fg: C2.fgMuted,
|
|
99362
|
+
children: " API key is valid and endpoint is reachable."
|
|
99363
|
+
}, undefined, false, undefined, this)
|
|
99364
|
+
]
|
|
99365
|
+
}, undefined, true, undefined, this),
|
|
99366
|
+
tr.status === "failed" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
|
|
99367
|
+
children: [
|
|
99368
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99369
|
+
fg: C2.red,
|
|
99370
|
+
bold: true,
|
|
99371
|
+
children: "\u2717 failed"
|
|
99372
|
+
}, undefined, false, undefined, this),
|
|
99373
|
+
tr.error && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99374
|
+
fg: C2.red,
|
|
99375
|
+
children: ` ${tr.error}`
|
|
99376
|
+
}, undefined, false, undefined, this)
|
|
99377
|
+
]
|
|
99378
|
+
}, undefined, true, undefined, this)
|
|
99379
|
+
]
|
|
99058
99380
|
}, undefined, true, undefined, this)
|
|
99059
99381
|
]
|
|
99060
99382
|
}, undefined, true, undefined, this);
|
|
@@ -99062,7 +99384,265 @@ function App() {
|
|
|
99062
99384
|
function chainStr(chain) {
|
|
99063
99385
|
return chain.join(" \u2192 ");
|
|
99064
99386
|
}
|
|
99387
|
+
const PROVIDER_REASONS = {
|
|
99388
|
+
litellm: "LiteLLM proxy",
|
|
99389
|
+
"opencode-zen": "Free tier (OpenCode Zen)",
|
|
99390
|
+
"opencode-zen-go": "Zen Go plan",
|
|
99391
|
+
kimi: "Native Kimi API",
|
|
99392
|
+
"kimi-coding": "Kimi Coding Plan",
|
|
99393
|
+
minimax: "Native MiniMax API",
|
|
99394
|
+
"minimax-coding": "MiniMax Coding Plan",
|
|
99395
|
+
glm: "Native GLM API",
|
|
99396
|
+
"glm-coding": "GLM Coding Plan",
|
|
99397
|
+
google: "Direct Gemini API",
|
|
99398
|
+
openai: "Direct OpenAI API",
|
|
99399
|
+
zai: "Z.AI API",
|
|
99400
|
+
ollamacloud: "Cloud Ollama",
|
|
99401
|
+
vertex: "Vertex AI Express",
|
|
99402
|
+
openrouter: "Fallback: 580+ models"
|
|
99403
|
+
};
|
|
99065
99404
|
function RoutingContent() {
|
|
99405
|
+
const probeBoxH = contentH + DETAIL_H + 1;
|
|
99406
|
+
if (probeMode === "input") {
|
|
99407
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
99408
|
+
height: probeBoxH,
|
|
99409
|
+
border: true,
|
|
99410
|
+
borderStyle: "single",
|
|
99411
|
+
borderColor: C2.focusBorder,
|
|
99412
|
+
backgroundColor: C2.bg,
|
|
99413
|
+
flexDirection: "column",
|
|
99414
|
+
paddingX: 2,
|
|
99415
|
+
paddingY: 1,
|
|
99416
|
+
children: [
|
|
99417
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99418
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99419
|
+
fg: C2.white,
|
|
99420
|
+
bold: true,
|
|
99421
|
+
children: "Route Probe"
|
|
99422
|
+
}, undefined, false, undefined, this)
|
|
99423
|
+
}, undefined, false, undefined, this),
|
|
99424
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99425
|
+
children: " "
|
|
99426
|
+
}, undefined, false, undefined, this),
|
|
99427
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99428
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99429
|
+
fg: C2.fgMuted,
|
|
99430
|
+
children: "Enter a model name to trace its routing chain:"
|
|
99431
|
+
}, undefined, false, undefined, this)
|
|
99432
|
+
}, undefined, false, undefined, this),
|
|
99433
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
99434
|
+
flexDirection: "row",
|
|
99435
|
+
height: 1,
|
|
99436
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99437
|
+
children: [
|
|
99438
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99439
|
+
fg: C2.green,
|
|
99440
|
+
bold: true,
|
|
99441
|
+
children: "> "
|
|
99442
|
+
}, undefined, false, undefined, this),
|
|
99443
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99444
|
+
fg: C2.white,
|
|
99445
|
+
children: probeModel
|
|
99446
|
+
}, undefined, false, undefined, this),
|
|
99447
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99448
|
+
fg: C2.cyan,
|
|
99449
|
+
children: "\u2588"
|
|
99450
|
+
}, undefined, false, undefined, this)
|
|
99451
|
+
]
|
|
99452
|
+
}, undefined, true, undefined, this)
|
|
99453
|
+
}, undefined, false, undefined, this),
|
|
99454
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99455
|
+
children: " "
|
|
99456
|
+
}, undefined, false, undefined, this),
|
|
99457
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99458
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99459
|
+
fg: C2.dim,
|
|
99460
|
+
children: "Examples: kimi-k2 deepseek-r1 gemini-2.0-flash gpt-4o"
|
|
99461
|
+
}, undefined, false, undefined, this)
|
|
99462
|
+
}, undefined, false, undefined, this),
|
|
99463
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99464
|
+
children: " "
|
|
99465
|
+
}, undefined, false, undefined, this),
|
|
99466
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99467
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99468
|
+
fg: C2.fgMuted,
|
|
99469
|
+
children: "The probe resolves the fallback chain and tests each provider's"
|
|
99470
|
+
}, undefined, false, undefined, this)
|
|
99471
|
+
}, undefined, false, undefined, this),
|
|
99472
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99473
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99474
|
+
fg: C2.fgMuted,
|
|
99475
|
+
children: "API key in order, stopping at the first success."
|
|
99476
|
+
}, undefined, false, undefined, this)
|
|
99477
|
+
}, undefined, false, undefined, this)
|
|
99478
|
+
]
|
|
99479
|
+
}, undefined, true, undefined, this);
|
|
99480
|
+
}
|
|
99481
|
+
if (probeMode === "running" || probeMode === "done") {
|
|
99482
|
+
const successEntry = probeResults.find((e) => e.status === "success");
|
|
99483
|
+
const allFailed = probeMode === "done" && !successEntry;
|
|
99484
|
+
const totalMs = successEntry?.ms;
|
|
99485
|
+
const statusBadge = probeMode === "running" ? { text: "probing...", color: C2.yellow } : successEntry ? { text: "routed", color: C2.green } : { text: "no route", color: C2.red };
|
|
99486
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
99487
|
+
height: probeBoxH,
|
|
99488
|
+
border: true,
|
|
99489
|
+
borderStyle: "single",
|
|
99490
|
+
borderColor: probeMode === "running" ? C2.focusBorder : C2.blue,
|
|
99491
|
+
backgroundColor: C2.bg,
|
|
99492
|
+
flexDirection: "column",
|
|
99493
|
+
paddingX: 2,
|
|
99494
|
+
paddingY: 1,
|
|
99495
|
+
children: [
|
|
99496
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
99497
|
+
flexDirection: "row",
|
|
99498
|
+
height: 1,
|
|
99499
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99500
|
+
children: [
|
|
99501
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99502
|
+
fg: C2.white,
|
|
99503
|
+
bold: true,
|
|
99504
|
+
children: probeMode === "done" ? "Probe: " : "Probing: "
|
|
99505
|
+
}, undefined, false, undefined, this),
|
|
99506
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99507
|
+
fg: C2.cyan,
|
|
99508
|
+
bold: true,
|
|
99509
|
+
children: probeModel
|
|
99510
|
+
}, undefined, false, undefined, this),
|
|
99511
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99512
|
+
fg: C2.dim,
|
|
99513
|
+
children: " "
|
|
99514
|
+
}, undefined, false, undefined, this),
|
|
99515
|
+
probeMode === "done" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99516
|
+
fg: statusBadge.color,
|
|
99517
|
+
bold: true,
|
|
99518
|
+
children: [
|
|
99519
|
+
successEntry ? "\u25CF " : "\u2717 ",
|
|
99520
|
+
statusBadge.text
|
|
99521
|
+
]
|
|
99522
|
+
}, undefined, true, undefined, this),
|
|
99523
|
+
probeMode === "running" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99524
|
+
fg: C2.yellow,
|
|
99525
|
+
children: "\u25CC probing..."
|
|
99526
|
+
}, undefined, false, undefined, this)
|
|
99527
|
+
]
|
|
99528
|
+
}, undefined, true, undefined, this)
|
|
99529
|
+
}, undefined, false, undefined, this),
|
|
99530
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99531
|
+
children: " "
|
|
99532
|
+
}, undefined, false, undefined, this),
|
|
99533
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99534
|
+
children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99535
|
+
fg: C2.fgMuted,
|
|
99536
|
+
children: probeResults[0]?.reason ?? `Chain (${probeResults.length} providers):`
|
|
99537
|
+
}, undefined, false, undefined, this)
|
|
99538
|
+
}, undefined, false, undefined, this),
|
|
99539
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99540
|
+
children: " "
|
|
99541
|
+
}, undefined, false, undefined, this),
|
|
99542
|
+
probeResults.map((entry, idx) => {
|
|
99543
|
+
const isNoKey = entry.status === "no_key";
|
|
99544
|
+
const isNotReached = entry.status === "skipped";
|
|
99545
|
+
const isSelected = entry.status === "success" && probeMode === "done";
|
|
99546
|
+
const statusIcon = entry.status === "success" ? "\u25CF" : entry.status === "failed" ? "\u2717" : entry.status === "testing" ? "\u25CC" : isNoKey ? "\u25CB" : isNotReached ? "\xB7" : "\u25CB";
|
|
99547
|
+
const statusColor = entry.status === "success" ? C2.green : entry.status === "failed" ? C2.red : entry.status === "testing" ? C2.yellow : C2.dim;
|
|
99548
|
+
const nameCol = entry.displayName.padEnd(18).substring(0, 18);
|
|
99549
|
+
const statusText = entry.status === "success" ? entry.ms !== undefined ? `${entry.ms}ms` : "success" : entry.status === "failed" ? entry.error ?? "failed" : entry.status === "testing" ? "testing..." : isNoKey ? "not configured, skipping" : isNotReached ? "not reached" : "waiting";
|
|
99550
|
+
const reason = PROVIDER_REASONS[entry.provider] ?? entry.provider;
|
|
99551
|
+
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
99552
|
+
flexDirection: "column",
|
|
99553
|
+
children: [
|
|
99554
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99555
|
+
children: [
|
|
99556
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99557
|
+
fg: C2.dim,
|
|
99558
|
+
children: `${idx + 1}. `
|
|
99559
|
+
}, undefined, false, undefined, this),
|
|
99560
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99561
|
+
fg: isNoKey ? C2.dim : isSelected ? C2.white : isNotReached ? C2.dim : C2.fgMuted,
|
|
99562
|
+
bold: isSelected,
|
|
99563
|
+
children: nameCol
|
|
99564
|
+
}, undefined, false, undefined, this),
|
|
99565
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99566
|
+
fg: C2.dim,
|
|
99567
|
+
children: " "
|
|
99568
|
+
}, undefined, false, undefined, this),
|
|
99569
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99570
|
+
fg: statusColor,
|
|
99571
|
+
bold: entry.status === "success",
|
|
99572
|
+
children: [
|
|
99573
|
+
statusIcon,
|
|
99574
|
+
" ",
|
|
99575
|
+
statusText
|
|
99576
|
+
]
|
|
99577
|
+
}, undefined, true, undefined, this),
|
|
99578
|
+
isSelected && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99579
|
+
fg: C2.green,
|
|
99580
|
+
bold: true,
|
|
99581
|
+
children: " \u2190 routed here"
|
|
99582
|
+
}, undefined, false, undefined, this)
|
|
99583
|
+
]
|
|
99584
|
+
}, undefined, true, undefined, this),
|
|
99585
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99586
|
+
children: [
|
|
99587
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99588
|
+
fg: C2.dim,
|
|
99589
|
+
children: " \u21B3 "
|
|
99590
|
+
}, undefined, false, undefined, this),
|
|
99591
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99592
|
+
fg: isNoKey ? C2.dim : C2.fgMuted,
|
|
99593
|
+
children: reason
|
|
99594
|
+
}, undefined, false, undefined, this)
|
|
99595
|
+
]
|
|
99596
|
+
}, undefined, true, undefined, this)
|
|
99597
|
+
]
|
|
99598
|
+
}, entry.provider, true, undefined, this);
|
|
99599
|
+
}),
|
|
99600
|
+
probeMode === "done" && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
|
|
99601
|
+
children: [
|
|
99602
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99603
|
+
children: " "
|
|
99604
|
+
}, undefined, false, undefined, this),
|
|
99605
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
|
|
99606
|
+
children: allFailed ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
|
|
99607
|
+
children: [
|
|
99608
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99609
|
+
fg: C2.red,
|
|
99610
|
+
bold: true,
|
|
99611
|
+
children: "Result: "
|
|
99612
|
+
}, undefined, false, undefined, this),
|
|
99613
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99614
|
+
fg: C2.red,
|
|
99615
|
+
children: "\u2717 No provider could serve this model"
|
|
99616
|
+
}, undefined, false, undefined, this)
|
|
99617
|
+
]
|
|
99618
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
|
|
99619
|
+
children: [
|
|
99620
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99621
|
+
fg: C2.green,
|
|
99622
|
+
bold: true,
|
|
99623
|
+
children: "Result: "
|
|
99624
|
+
}, undefined, false, undefined, this),
|
|
99625
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99626
|
+
fg: C2.fgMuted,
|
|
99627
|
+
children: "Routed to "
|
|
99628
|
+
}, undefined, false, undefined, this),
|
|
99629
|
+
/* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99630
|
+
fg: C2.cyan,
|
|
99631
|
+
bold: true,
|
|
99632
|
+
children: successEntry.displayName
|
|
99633
|
+
}, undefined, false, undefined, this),
|
|
99634
|
+
totalMs !== undefined && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("span", {
|
|
99635
|
+
fg: C2.fgMuted,
|
|
99636
|
+
children: ` in ${totalMs}ms`
|
|
99637
|
+
}, undefined, false, undefined, this)
|
|
99638
|
+
]
|
|
99639
|
+
}, undefined, true, undefined, this)
|
|
99640
|
+
}, undefined, false, undefined, this)
|
|
99641
|
+
]
|
|
99642
|
+
}, undefined, true, undefined, this)
|
|
99643
|
+
]
|
|
99644
|
+
}, undefined, true, undefined, this);
|
|
99645
|
+
}
|
|
99066
99646
|
const innerH = contentH - 2;
|
|
99067
99647
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
99068
99648
|
height: contentH,
|
|
@@ -99340,6 +99920,9 @@ function App() {
|
|
|
99340
99920
|
}, undefined, true, undefined, this);
|
|
99341
99921
|
}
|
|
99342
99922
|
function RoutingDetail() {
|
|
99923
|
+
if (probeMode !== "idle") {
|
|
99924
|
+
return null;
|
|
99925
|
+
}
|
|
99343
99926
|
return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
|
|
99344
99927
|
height: DETAIL_H,
|
|
99345
99928
|
border: true,
|
|
@@ -99661,11 +100244,29 @@ function App() {
|
|
|
99661
100244
|
}
|
|
99662
100245
|
function Footer() {
|
|
99663
100246
|
let keys;
|
|
99664
|
-
if (activeTab === "
|
|
100247
|
+
if (activeTab === "routing" && probeMode === "input") {
|
|
100248
|
+
keys = [
|
|
100249
|
+
[C2.green, "Enter", "probe"],
|
|
100250
|
+
[C2.red, "Esc", "cancel"]
|
|
100251
|
+
];
|
|
100252
|
+
} else if (activeTab === "routing" && probeMode === "running") {
|
|
100253
|
+
keys = [
|
|
100254
|
+
[C2.yellow, "\u25CC", "probing..."],
|
|
100255
|
+
[C2.red, "Esc", "cancel"]
|
|
100256
|
+
];
|
|
100257
|
+
} else if (activeTab === "routing" && probeMode === "done") {
|
|
100258
|
+
keys = [
|
|
100259
|
+
[C2.cyan, "p", "back to routes"],
|
|
100260
|
+
[C2.green, "Enter", "probe another"],
|
|
100261
|
+
[C2.red, "Esc", "back to routes"],
|
|
100262
|
+
[C2.dim, "q", "quit"]
|
|
100263
|
+
];
|
|
100264
|
+
} else if (activeTab === "providers") {
|
|
99665
100265
|
keys = [
|
|
99666
100266
|
[C2.blue, "\u2191\u2193", "navigate"],
|
|
99667
100267
|
[C2.green, "s", "set key"],
|
|
99668
100268
|
[C2.green, "e", "endpoint"],
|
|
100269
|
+
[C2.cyan, "t", "test key"],
|
|
99669
100270
|
[C2.red, "x", "remove"],
|
|
99670
100271
|
[C2.blue, "Tab", "section"],
|
|
99671
100272
|
[C2.dim, "q", "quit"]
|
|
@@ -99675,6 +100276,7 @@ function App() {
|
|
|
99675
100276
|
[C2.blue, "\u2191\u2193", "navigate"],
|
|
99676
100277
|
[C2.green, "a", "add rule"],
|
|
99677
100278
|
[C2.red, "d", "delete"],
|
|
100279
|
+
[C2.cyan, "p", "probe"],
|
|
99678
100280
|
[C2.blue, "Tab", "section"],
|
|
99679
100281
|
[C2.dim, "q", "quit"]
|
|
99680
100282
|
];
|
|
@@ -99801,7 +100403,10 @@ function App() {
|
|
|
99801
100403
|
var import_react13, VERSION2 = "v5.16";
|
|
99802
100404
|
var init_App = __esm(async () => {
|
|
99803
100405
|
init_profile_config();
|
|
100406
|
+
init_auto_route();
|
|
100407
|
+
init_model_parser();
|
|
99804
100408
|
init_stats_buffer();
|
|
100409
|
+
init_test_provider();
|
|
99805
100410
|
init_providers();
|
|
99806
100411
|
init_theme2();
|
|
99807
100412
|
init_jsx_dev_runtime();
|
|
@@ -105265,7 +105870,7 @@ async function describeImage(image, auth) {
|
|
|
105265
105870
|
if (auth["x-api-key"])
|
|
105266
105871
|
headers["x-api-key"] = auth["x-api-key"];
|
|
105267
105872
|
const controller = new AbortController;
|
|
105268
|
-
const timeoutId = setTimeout(() => controller.abort(),
|
|
105873
|
+
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS2);
|
|
105269
105874
|
try {
|
|
105270
105875
|
const response = await fetch(VISION_ENDPOINT, {
|
|
105271
105876
|
method: "POST",
|
|
@@ -105289,7 +105894,7 @@ async function describeImage(image, auth) {
|
|
|
105289
105894
|
} catch (err) {
|
|
105290
105895
|
clearTimeout(timeoutId);
|
|
105291
105896
|
if (err.name === "AbortError") {
|
|
105292
|
-
log(`[VisionProxy] Request timed out after ${
|
|
105897
|
+
log(`[VisionProxy] Request timed out after ${TIMEOUT_MS2}ms`);
|
|
105293
105898
|
} else {
|
|
105294
105899
|
log(`[VisionProxy] Fetch error: ${err.message}`);
|
|
105295
105900
|
}
|
|
@@ -105312,7 +105917,7 @@ async function describeImages(images, auth) {
|
|
|
105312
105917
|
return null;
|
|
105313
105918
|
}
|
|
105314
105919
|
}
|
|
105315
|
-
var VISION_MODEL = "claude-sonnet-4-20250514", MAX_TOKENS_PER_IMAGE = 1024, VISION_ENDPOINT = "https://api.anthropic.com/v1/messages",
|
|
105920
|
+
var VISION_MODEL = "claude-sonnet-4-20250514", MAX_TOKENS_PER_IMAGE = 1024, VISION_ENDPOINT = "https://api.anthropic.com/v1/messages", TIMEOUT_MS2 = 30000, DESCRIPTION_PROMPT = `Describe this image in detail for a model that cannot see images. Provide:
|
|
105316
105921
|
- All visible text content (exact quotes where possible)
|
|
105317
105922
|
- Layout and structure (how elements are arranged spatially)
|
|
105318
105923
|
- Colors, visual style, and key visual elements
|
package/package.json
CHANGED