claudish 7.49.0 → 7.51.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 +914 -104
- 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.51.0";
|
|
733
733
|
|
|
734
734
|
// src/logger.ts
|
|
735
735
|
var exports_logger = {};
|
|
@@ -27509,6 +27509,9 @@ function loadConfig() {
|
|
|
27509
27509
|
if (config2.customEndpoints !== undefined) {
|
|
27510
27510
|
merged.customEndpoints = config2.customEndpoints;
|
|
27511
27511
|
}
|
|
27512
|
+
if (config2.predefinedEndpoints !== undefined) {
|
|
27513
|
+
merged.predefinedEndpoints = config2.predefinedEndpoints;
|
|
27514
|
+
}
|
|
27512
27515
|
if (config2.behavior !== undefined) {
|
|
27513
27516
|
merged.behavior = config2.behavior;
|
|
27514
27517
|
}
|
|
@@ -27933,24 +27936,44 @@ function getApiKeyInfo(providerName) {
|
|
|
27933
27936
|
oauthFallback: def.oauthFallback
|
|
27934
27937
|
};
|
|
27935
27938
|
}
|
|
27939
|
+
function describeMissingCredential(providerName) {
|
|
27940
|
+
const info = getApiKeyInfo(providerName);
|
|
27941
|
+
const keyNames = info?.envVar ? [info.envVar, ...info.aliases ?? []].join(" or ") : undefined;
|
|
27942
|
+
const signup = info?.url ? ` Get one at ${info.url}.` : "";
|
|
27943
|
+
const def = getProviderByName(providerName);
|
|
27944
|
+
if (isLocalTransport(providerName)) {
|
|
27945
|
+
const where = def ? ` Claudish will use ${getEffectiveBaseUrl(def)}.` : "";
|
|
27946
|
+
const keyClause = keyNames ? ` (Only set ${keyNames} if your local server requires a bearer token.)` : "";
|
|
27947
|
+
return `Provider "${providerName}" is a LOCAL server and is not enabled. ` + "Enable it in `claudish config` (Providers tab), or add " + `"localProviders": ["${providerName}"] to ~/.claudish/config.json.${where}${keyClause}`;
|
|
27948
|
+
}
|
|
27949
|
+
if (def?.oauthFallback) {
|
|
27950
|
+
const keyClause = keyNames ? ` Or set ${keyNames} (env, config, or 1Password import) to use a metered API key instead.${signup}` : "";
|
|
27951
|
+
return `No credential for provider "${providerName}". Sign in with ` + `\`claudish login ${providerName}\` to use your existing subscription.${keyClause}`;
|
|
27952
|
+
}
|
|
27953
|
+
return keyNames ? `No API key for provider "${providerName}". Set ${keyNames} (env, config, or 1Password import).${signup}` : `No API key for provider "${providerName}".`;
|
|
27954
|
+
}
|
|
27936
27955
|
function getDisplayName(providerName) {
|
|
27937
27956
|
const def = getProviderByName(providerName);
|
|
27938
27957
|
return def?.displayName || providerName.charAt(0).toUpperCase() + providerName.slice(1);
|
|
27939
27958
|
}
|
|
27940
|
-
function
|
|
27941
|
-
|
|
27942
|
-
|
|
27943
|
-
|
|
27944
|
-
|
|
27945
|
-
|
|
27946
|
-
|
|
27947
|
-
|
|
27948
|
-
|
|
27949
|
-
|
|
27950
|
-
|
|
27951
|
-
|
|
27959
|
+
function baseUrlOverrideCandidates(baseUrlEnvVars) {
|
|
27960
|
+
const found = [];
|
|
27961
|
+
if (!baseUrlEnvVars || baseUrlEnvVars.length === 0)
|
|
27962
|
+
return found;
|
|
27963
|
+
for (const envVar of baseUrlEnvVars) {
|
|
27964
|
+
const fromConfig = getEndpoint(envVar);
|
|
27965
|
+
if (fromConfig)
|
|
27966
|
+
found.push({ envVar, value: fromConfig, source: "config" });
|
|
27967
|
+
}
|
|
27968
|
+
for (const envVar of baseUrlEnvVars) {
|
|
27969
|
+
const value = process.env[envVar];
|
|
27970
|
+
if (value)
|
|
27971
|
+
found.push({ envVar, value, source: "env" });
|
|
27952
27972
|
}
|
|
27953
|
-
return
|
|
27973
|
+
return found;
|
|
27974
|
+
}
|
|
27975
|
+
function getEffectiveBaseUrl(def) {
|
|
27976
|
+
return baseUrlOverrideCandidates(def.baseUrlEnvVars)[0]?.value ?? def.baseUrl;
|
|
27954
27977
|
}
|
|
27955
27978
|
function isLocalTransport(providerName) {
|
|
27956
27979
|
if (!_localProvidersCache) {
|
|
@@ -30850,6 +30873,22 @@ var init_antigravity_credential = __esm(() => {
|
|
|
30850
30873
|
init_antigravity_user();
|
|
30851
30874
|
});
|
|
30852
30875
|
|
|
30876
|
+
// src/auth/credentials/local-api-key.ts
|
|
30877
|
+
function resolveLocalApiKey(q) {
|
|
30878
|
+
return realValue(process.env[q.envVar]) || (q.aliases ?? []).map((a) => realValue(process.env[a])).find((v) => !!v) || realValue(getApiKey(q.envVar));
|
|
30879
|
+
}
|
|
30880
|
+
function hasLocalApiKey(q) {
|
|
30881
|
+
try {
|
|
30882
|
+
return !!resolveLocalApiKey(q);
|
|
30883
|
+
} catch {
|
|
30884
|
+
return false;
|
|
30885
|
+
}
|
|
30886
|
+
}
|
|
30887
|
+
var init_local_api_key = __esm(() => {
|
|
30888
|
+
init_env_placeholder();
|
|
30889
|
+
init_profile_config();
|
|
30890
|
+
});
|
|
30891
|
+
|
|
30853
30892
|
// src/auth/credentials/api-key-credential.ts
|
|
30854
30893
|
import { existsSync as existsSync8 } from "fs";
|
|
30855
30894
|
import { homedir as homedir10 } from "os";
|
|
@@ -30877,7 +30916,7 @@ class ApiKeyCredentialProvider {
|
|
|
30877
30916
|
this.declaredKey = descriptor.declaredKey;
|
|
30878
30917
|
}
|
|
30879
30918
|
resolveFromEnvConfig() {
|
|
30880
|
-
return
|
|
30919
|
+
return resolveLocalApiKey({ envVar: this.envVar, aliases: this.aliases }) || realValue(this.resolveDeclared());
|
|
30881
30920
|
}
|
|
30882
30921
|
resolveDeclared() {
|
|
30883
30922
|
try {
|
|
@@ -30958,7 +30997,7 @@ class ApiKeyCredentialProvider {
|
|
|
30958
30997
|
}
|
|
30959
30998
|
var init_api_key_credential = __esm(() => {
|
|
30960
30999
|
init_env_placeholder();
|
|
30961
|
-
|
|
31000
|
+
init_local_api_key();
|
|
30962
31001
|
init_op_source();
|
|
30963
31002
|
});
|
|
30964
31003
|
|
|
@@ -32359,7 +32398,7 @@ var init_authority = __esm(() => {
|
|
|
32359
32398
|
});
|
|
32360
32399
|
|
|
32361
32400
|
// src/config-schema.ts
|
|
32362
|
-
var BuiltinDefaultProviderSchema, CustomEndpointSimpleSchema, CustomEndpointComplexSchema, CustomEndpointSchema, DefaultProviderSchema;
|
|
32401
|
+
var BuiltinDefaultProviderSchema, CustomEndpointSimpleSchema, CustomEndpointComplexSchema, CustomEndpointSchema, PredefinedEndpointsConfigSchema, DefaultProviderSchema;
|
|
32363
32402
|
var init_config_schema = __esm(() => {
|
|
32364
32403
|
init_zod();
|
|
32365
32404
|
BuiltinDefaultProviderSchema = exports_external.enum([
|
|
@@ -32394,6 +32433,11 @@ var init_config_schema = __esm(() => {
|
|
|
32394
32433
|
CustomEndpointSimpleSchema,
|
|
32395
32434
|
CustomEndpointComplexSchema
|
|
32396
32435
|
]);
|
|
32436
|
+
PredefinedEndpointsConfigSchema = exports_external.object({
|
|
32437
|
+
enabled: exports_external.boolean().optional(),
|
|
32438
|
+
disable: exports_external.array(exports_external.string()).optional(),
|
|
32439
|
+
enable: exports_external.array(exports_external.string()).optional()
|
|
32440
|
+
});
|
|
32397
32441
|
DefaultProviderSchema = exports_external.union([BuiltinDefaultProviderSchema, exports_external.string().min(1)]);
|
|
32398
32442
|
});
|
|
32399
32443
|
|
|
@@ -36581,7 +36625,14 @@ class OpenAIProviderTransport {
|
|
|
36581
36625
|
async getHeaders() {
|
|
36582
36626
|
const headers = {};
|
|
36583
36627
|
if (this.apiKey) {
|
|
36584
|
-
|
|
36628
|
+
if (this.provider.authScheme === "x-api-key") {
|
|
36629
|
+
headers["x-api-key"] = this.apiKey;
|
|
36630
|
+
} else {
|
|
36631
|
+
headers.Authorization = `Bearer ${this.apiKey}`;
|
|
36632
|
+
}
|
|
36633
|
+
}
|
|
36634
|
+
if (this.provider.headers) {
|
|
36635
|
+
Object.assign(headers, this.provider.headers);
|
|
36585
36636
|
}
|
|
36586
36637
|
return headers;
|
|
36587
36638
|
}
|
|
@@ -41383,6 +41434,21 @@ var init_composed_handler = __esm(() => {
|
|
|
41383
41434
|
STREAM_RETRY_DELAYS_MS = [3000, 15000, 30000];
|
|
41384
41435
|
});
|
|
41385
41436
|
|
|
41437
|
+
// src/providers/endpoint-diagnostics.ts
|
|
41438
|
+
function recordEndpointUnavailable(name, reason) {
|
|
41439
|
+
reasons.set(name, reason);
|
|
41440
|
+
}
|
|
41441
|
+
function clearEndpointUnavailable(name) {
|
|
41442
|
+
reasons.delete(name);
|
|
41443
|
+
}
|
|
41444
|
+
function getEndpointUnavailableReason(name) {
|
|
41445
|
+
return reasons.get(name);
|
|
41446
|
+
}
|
|
41447
|
+
var reasons;
|
|
41448
|
+
var init_endpoint_diagnostics = __esm(() => {
|
|
41449
|
+
reasons = new Map;
|
|
41450
|
+
});
|
|
41451
|
+
|
|
41386
41452
|
// src/providers/devin/devin-request.ts
|
|
41387
41453
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
41388
41454
|
function encodeChatMetadata(meta3) {
|
|
@@ -42645,6 +42711,21 @@ var init_litellm = __esm(() => {
|
|
|
42645
42711
|
});
|
|
42646
42712
|
|
|
42647
42713
|
// src/providers/custom-endpoints-loader.ts
|
|
42714
|
+
function registerEndpoint(name, entry, ovr) {
|
|
42715
|
+
const validated = CustomEndpointSchema.parse(entry);
|
|
42716
|
+
const def = buildProviderDefinition(name, validated, ovr);
|
|
42717
|
+
const profile = buildProviderProfile(validated, ovr);
|
|
42718
|
+
registerRuntimeProvider(def);
|
|
42719
|
+
registerRuntimeProfile(name, profile);
|
|
42720
|
+
credentials.registerApiKeyProvider({
|
|
42721
|
+
name: def.name,
|
|
42722
|
+
envVar: def.apiKeyEnvVar,
|
|
42723
|
+
aliases: def.apiKeyAliases,
|
|
42724
|
+
authScheme: def.authScheme === "x-api-key" ? "x-api-key" : "bearer",
|
|
42725
|
+
declaredKey: () => resolveDeclaredEndpointKey(validated)
|
|
42726
|
+
});
|
|
42727
|
+
clearEndpointUnavailable(name);
|
|
42728
|
+
}
|
|
42648
42729
|
function loadCustomEndpoints(config2) {
|
|
42649
42730
|
const result = { registered: 0, errors: [] };
|
|
42650
42731
|
const raw = config2.customEndpoints;
|
|
@@ -42652,17 +42733,7 @@ function loadCustomEndpoints(config2) {
|
|
|
42652
42733
|
return result;
|
|
42653
42734
|
for (const [name, entry] of Object.entries(raw)) {
|
|
42654
42735
|
try {
|
|
42655
|
-
|
|
42656
|
-
const def = buildProviderDefinition(name, validated);
|
|
42657
|
-
const profile = buildProviderProfile(validated);
|
|
42658
|
-
registerRuntimeProvider(def);
|
|
42659
|
-
registerRuntimeProfile(name, profile);
|
|
42660
|
-
credentials.registerApiKeyProvider({
|
|
42661
|
-
name: def.name,
|
|
42662
|
-
envVar: def.apiKeyEnvVar,
|
|
42663
|
-
authScheme: def.authScheme === "x-api-key" ? "x-api-key" : "bearer",
|
|
42664
|
-
declaredKey: () => resolveDeclaredEndpointKey(validated)
|
|
42665
|
-
});
|
|
42736
|
+
registerEndpoint(name, entry);
|
|
42666
42737
|
result.registered++;
|
|
42667
42738
|
} catch (err) {
|
|
42668
42739
|
const message = err instanceof exports_external.ZodError ? err.issues.map((i) => i.message).join(", ") : err instanceof Error ? err.message : String(err);
|
|
@@ -42671,22 +42742,28 @@ function loadCustomEndpoints(config2) {
|
|
|
42671
42742
|
}
|
|
42672
42743
|
return result;
|
|
42673
42744
|
}
|
|
42674
|
-
function buildProviderDefinition(name, ep) {
|
|
42745
|
+
function buildProviderDefinition(name, ep, ovr) {
|
|
42746
|
+
const apiKeyEnvVar = ovr?.apiKeyEnvVar ?? customEndpointKeyEnvVar(name);
|
|
42747
|
+
const apiKeyAliases = ovr?.apiKeyAliases;
|
|
42748
|
+
const baseUrlEnvVars = ovr?.baseUrlEnvVars;
|
|
42749
|
+
const apiKeyUrl = ovr?.apiKeyUrl ?? "";
|
|
42675
42750
|
if (ep.kind === "simple") {
|
|
42676
42751
|
return {
|
|
42677
42752
|
name,
|
|
42678
42753
|
displayName: name,
|
|
42679
42754
|
transport: ep.format,
|
|
42680
42755
|
baseUrl: stripTrailingSlash(ep.url),
|
|
42756
|
+
baseUrlEnvVars,
|
|
42681
42757
|
apiPath: "/chat/completions",
|
|
42682
|
-
apiKeyEnvVar
|
|
42683
|
-
|
|
42684
|
-
|
|
42758
|
+
apiKeyEnvVar,
|
|
42759
|
+
apiKeyAliases,
|
|
42760
|
+
apiKeyDescription: ovr?.apiKeyDescription ?? `${name} (custom endpoint)`,
|
|
42761
|
+
apiKeyUrl,
|
|
42685
42762
|
shortcuts: [name],
|
|
42686
42763
|
legacyPrefixes: [],
|
|
42687
42764
|
isDirectApi: true,
|
|
42688
42765
|
shortestPrefix: name,
|
|
42689
|
-
description: `Custom endpoint: ${name}`,
|
|
42766
|
+
description: ovr?.description ?? `Custom endpoint: ${name}`,
|
|
42690
42767
|
authScheme: "bearer"
|
|
42691
42768
|
};
|
|
42692
42769
|
}
|
|
@@ -42695,33 +42772,68 @@ function buildProviderDefinition(name, ep) {
|
|
|
42695
42772
|
displayName: ep.displayName,
|
|
42696
42773
|
transport: ep.transport,
|
|
42697
42774
|
baseUrl: stripTrailingSlash(ep.baseUrl),
|
|
42775
|
+
baseUrlEnvVars,
|
|
42698
42776
|
apiPath: ep.apiPath ?? "/v1/chat/completions",
|
|
42699
|
-
apiKeyEnvVar
|
|
42700
|
-
|
|
42701
|
-
|
|
42777
|
+
apiKeyEnvVar,
|
|
42778
|
+
apiKeyAliases,
|
|
42779
|
+
apiKeyDescription: ovr?.apiKeyDescription ?? `${ep.displayName} (custom endpoint)`,
|
|
42780
|
+
apiKeyUrl,
|
|
42702
42781
|
shortcuts: [name],
|
|
42703
42782
|
legacyPrefixes: [],
|
|
42704
42783
|
isDirectApi: true,
|
|
42705
42784
|
shortestPrefix: name,
|
|
42706
|
-
description: `Custom endpoint: ${ep.displayName}`,
|
|
42785
|
+
description: ovr?.description ?? `Custom endpoint: ${ep.displayName}`,
|
|
42707
42786
|
headers: ep.headers,
|
|
42708
42787
|
authScheme: ep.authScheme ?? "bearer"
|
|
42709
42788
|
};
|
|
42710
42789
|
}
|
|
42711
|
-
function buildProviderProfile(ep) {
|
|
42790
|
+
function buildProviderProfile(ep, ovr) {
|
|
42712
42791
|
return {
|
|
42713
42792
|
createHandler(ctx) {
|
|
42714
42793
|
const apiKey = ctx.apiKey || resolveCustomEndpointApiKey(ep);
|
|
42794
|
+
const declaredBaseUrl = ep.kind === "simple" ? ep.url : ep.baseUrl;
|
|
42795
|
+
const resolved = classifyEndpointBaseUrl(declaredBaseUrl, ovr?.baseUrlEnvVars);
|
|
42796
|
+
if (!resolved.ok) {
|
|
42797
|
+
const reason = describeBadBaseUrlOverride(resolved, declaredBaseUrl);
|
|
42798
|
+
console.error(`[claudish] ${reason}`);
|
|
42799
|
+
recordEndpointUnavailable(ctx.provider.name, `its ${reason}`);
|
|
42800
|
+
return null;
|
|
42801
|
+
}
|
|
42802
|
+
const baseUrl = resolved.url;
|
|
42715
42803
|
if (ep.kind === "simple") {
|
|
42716
|
-
return buildSimpleHandler(ep, ctx, apiKey);
|
|
42804
|
+
return buildSimpleHandler(ep, ctx, apiKey, baseUrl);
|
|
42717
42805
|
}
|
|
42718
|
-
return buildComplexHandler(ep, ctx, apiKey);
|
|
42806
|
+
return buildComplexHandler(ep, ctx, apiKey, baseUrl);
|
|
42719
42807
|
}
|
|
42720
42808
|
};
|
|
42721
42809
|
}
|
|
42722
|
-
function
|
|
42810
|
+
function classifyEndpointBaseUrl(declared, baseUrlEnvVars) {
|
|
42811
|
+
for (const candidate of baseUrlOverrideCandidates(baseUrlEnvVars)) {
|
|
42812
|
+
const value = realValue(candidate.value)?.trim();
|
|
42813
|
+
if (!value)
|
|
42814
|
+
continue;
|
|
42815
|
+
if (!isHttpUrl(value)) {
|
|
42816
|
+
return { ok: false, envVar: candidate.envVar, value, source: candidate.source };
|
|
42817
|
+
}
|
|
42818
|
+
return { ok: true, url: stripTrailingSlash(value) };
|
|
42819
|
+
}
|
|
42820
|
+
return { ok: true, url: stripTrailingSlash(declared) };
|
|
42821
|
+
}
|
|
42822
|
+
function describeBadBaseUrlOverride(bad, declared) {
|
|
42823
|
+
const where = bad.source === "config" ? `config.endpoints["${bad.envVar}"] is set to '${bad.value}'` : `${bad.envVar} is set to '${bad.value}'`;
|
|
42824
|
+
const remedy = bad.source === "config" ? "Fix or remove it (claudish config -> Providers)." : "Fix or unset it.";
|
|
42825
|
+
return `${where}, which is not a valid http(s) URL. ` + `${remedy} (Not falling back to ${declared} \u2014 the override was set on purpose.)`;
|
|
42826
|
+
}
|
|
42827
|
+
function isHttpUrl(value) {
|
|
42828
|
+
try {
|
|
42829
|
+
const parsed = new URL(value);
|
|
42830
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
42831
|
+
} catch {
|
|
42832
|
+
return false;
|
|
42833
|
+
}
|
|
42834
|
+
}
|
|
42835
|
+
function buildSimpleHandler(ep, ctx, apiKey, baseUrl) {
|
|
42723
42836
|
const finalModel = ep.modelPrefix ? `${ep.modelPrefix}${ctx.modelName}` : ctx.modelName;
|
|
42724
|
-
const baseUrl = stripTrailingSlash(ep.url);
|
|
42725
42837
|
if (ep.format === "openai") {
|
|
42726
42838
|
const remoteProvider2 = {
|
|
42727
42839
|
name: ctx.provider.name,
|
|
@@ -42756,9 +42868,8 @@ function buildSimpleHandler(ep, ctx, apiKey) {
|
|
|
42756
42868
|
...ctx.sharedOpts
|
|
42757
42869
|
});
|
|
42758
42870
|
}
|
|
42759
|
-
function buildComplexHandler(ep, ctx, apiKey) {
|
|
42871
|
+
function buildComplexHandler(ep, ctx, apiKey, baseUrl) {
|
|
42760
42872
|
const finalModel = ep.modelPrefix ? `${ep.modelPrefix}${ctx.modelName}` : ctx.modelName;
|
|
42761
|
-
const baseUrl = stripTrailingSlash(ep.baseUrl);
|
|
42762
42873
|
const apiPath = ep.apiPath ?? "/v1/chat/completions";
|
|
42763
42874
|
switch (ep.transport) {
|
|
42764
42875
|
case "litellm": {
|
|
@@ -42830,6 +42941,9 @@ function resolveDeclaredEndpointKey(ep) {
|
|
|
42830
42941
|
function stripTrailingSlash(url2) {
|
|
42831
42942
|
return url2.replace(/\/+$/, "");
|
|
42832
42943
|
}
|
|
42944
|
+
function customEndpointKeyEnvVar(name) {
|
|
42945
|
+
return `CUSTOM_${sanitizeEnvName(name)}_KEY`;
|
|
42946
|
+
}
|
|
42833
42947
|
function sanitizeEnvName(name) {
|
|
42834
42948
|
return name.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
42835
42949
|
}
|
|
@@ -42840,13 +42954,518 @@ var init_custom_endpoints_loader = __esm(() => {
|
|
|
42840
42954
|
init_openai_api_format();
|
|
42841
42955
|
init_authority();
|
|
42842
42956
|
init_config_schema();
|
|
42957
|
+
init_env_placeholder();
|
|
42843
42958
|
init_composed_handler();
|
|
42959
|
+
init_endpoint_diagnostics();
|
|
42960
|
+
init_provider_definitions();
|
|
42844
42961
|
init_runtime_providers();
|
|
42845
42962
|
init_anthropic_compat();
|
|
42846
42963
|
init_litellm();
|
|
42847
42964
|
init_openai();
|
|
42848
42965
|
});
|
|
42849
42966
|
|
|
42967
|
+
// src/providers/picker-alias-extra.ts
|
|
42968
|
+
var PROVIDER_FILTER_ALIAS_EXTRA;
|
|
42969
|
+
var init_picker_alias_extra = __esm(() => {
|
|
42970
|
+
PROVIDER_FILTER_ALIAS_EXTRA = {
|
|
42971
|
+
gem: "google",
|
|
42972
|
+
zen: "opencode-zen"
|
|
42973
|
+
};
|
|
42974
|
+
});
|
|
42975
|
+
|
|
42976
|
+
// src/providers/predefined-catalog.ts
|
|
42977
|
+
var PREDEFINED_ENDPOINTS;
|
|
42978
|
+
var init_predefined_catalog = __esm(() => {
|
|
42979
|
+
PREDEFINED_ENDPOINTS = [
|
|
42980
|
+
{
|
|
42981
|
+
name: "groq",
|
|
42982
|
+
displayName: "Groq",
|
|
42983
|
+
baseUrl: "https://api.groq.com/openai",
|
|
42984
|
+
apiPath: "/v1/chat/completions",
|
|
42985
|
+
format: "openai",
|
|
42986
|
+
apiKeyEnvVar: "GROQ_API_KEY",
|
|
42987
|
+
apiKeyUrl: "https://console.groq.com/keys",
|
|
42988
|
+
description: "Groq LPU inference (groq@)",
|
|
42989
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
42990
|
+
},
|
|
42991
|
+
{
|
|
42992
|
+
name: "cerebras",
|
|
42993
|
+
displayName: "Cerebras",
|
|
42994
|
+
baseUrl: "https://api.cerebras.ai",
|
|
42995
|
+
apiPath: "/v1/chat/completions",
|
|
42996
|
+
format: "openai",
|
|
42997
|
+
apiKeyEnvVar: "CEREBRAS_API_KEY",
|
|
42998
|
+
apiKeyUrl: "https://cloud.cerebras.ai",
|
|
42999
|
+
description: "Cerebras Inference wafer-scale hosting (cerebras@)",
|
|
43000
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43001
|
+
},
|
|
43002
|
+
{
|
|
43003
|
+
name: "together",
|
|
43004
|
+
displayName: "Together AI",
|
|
43005
|
+
baseUrl: "https://api.together.xyz",
|
|
43006
|
+
apiPath: "/v1/chat/completions",
|
|
43007
|
+
format: "openai",
|
|
43008
|
+
apiKeyEnvVar: "TOGETHER_API_KEY",
|
|
43009
|
+
apiKeyUrl: "https://api.together.xyz/settings/api-keys",
|
|
43010
|
+
description: "Together AI direct inference API (together@) \u2014 distinct from the 'together-ai' vendor id models-index uses as an aggregator label",
|
|
43011
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43012
|
+
},
|
|
43013
|
+
{
|
|
43014
|
+
name: "fireworks",
|
|
43015
|
+
displayName: "Fireworks AI",
|
|
43016
|
+
baseUrl: "https://api.fireworks.ai/inference",
|
|
43017
|
+
apiPath: "/v1/chat/completions",
|
|
43018
|
+
format: "openai",
|
|
43019
|
+
apiKeyEnvVar: "FIREWORKS_API_KEY",
|
|
43020
|
+
apiKeyUrl: "https://fireworks.ai/account/api-keys",
|
|
43021
|
+
description: "Fireworks AI serverless inference (fireworks@)",
|
|
43022
|
+
evidence: {
|
|
43023
|
+
tier: "probe",
|
|
43024
|
+
verdict: "model-gate",
|
|
43025
|
+
status: 404,
|
|
43026
|
+
measuredAt: "2026-08-14",
|
|
43027
|
+
note: "404 rejecting the fake model ('Model not found, inaccessible, and/or not deployed'); the bogus sibling path answered 'Path not found', so the route resolved"
|
|
43028
|
+
}
|
|
43029
|
+
},
|
|
43030
|
+
{
|
|
43031
|
+
name: "deepinfra",
|
|
43032
|
+
displayName: "DeepInfra",
|
|
43033
|
+
baseUrl: "https://api.deepinfra.com/v1/openai",
|
|
43034
|
+
apiPath: "/chat/completions",
|
|
43035
|
+
format: "openai",
|
|
43036
|
+
apiKeyEnvVar: "DEEPINFRA_API_KEY",
|
|
43037
|
+
apiKeyUrl: "https://deepinfra.com/dash/api_keys",
|
|
43038
|
+
description: "DeepInfra hosted open models (deepinfra@)",
|
|
43039
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43040
|
+
},
|
|
43041
|
+
{
|
|
43042
|
+
name: "nebius",
|
|
43043
|
+
displayName: "Nebius AI Studio",
|
|
43044
|
+
baseUrl: "https://api.studio.nebius.com",
|
|
43045
|
+
apiPath: "/v1/chat/completions",
|
|
43046
|
+
format: "openai",
|
|
43047
|
+
apiKeyEnvVar: "NEBIUS_API_KEY",
|
|
43048
|
+
apiKeyUrl: "https://studio.nebius.com",
|
|
43049
|
+
description: "Nebius AI Studio hosted open models (nebius@)",
|
|
43050
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43051
|
+
},
|
|
43052
|
+
{
|
|
43053
|
+
name: "hyperbolic",
|
|
43054
|
+
displayName: "Hyperbolic",
|
|
43055
|
+
baseUrl: "https://api.hyperbolic.xyz",
|
|
43056
|
+
apiPath: "/v1/chat/completions",
|
|
43057
|
+
format: "openai",
|
|
43058
|
+
apiKeyEnvVar: "HYPERBOLIC_API_KEY",
|
|
43059
|
+
apiKeyUrl: "https://app.hyperbolic.xyz",
|
|
43060
|
+
description: "Hyperbolic decentralized GPU inference (hyperbolic@)",
|
|
43061
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43062
|
+
},
|
|
43063
|
+
{
|
|
43064
|
+
name: "sambanova",
|
|
43065
|
+
displayName: "SambaNova Cloud",
|
|
43066
|
+
baseUrl: "https://api.sambanova.ai",
|
|
43067
|
+
apiPath: "/v1/chat/completions",
|
|
43068
|
+
format: "openai",
|
|
43069
|
+
apiKeyEnvVar: "SAMBANOVA_API_KEY",
|
|
43070
|
+
apiKeyUrl: "https://cloud.sambanova.ai",
|
|
43071
|
+
description: "SambaNova Cloud RDU inference (sambanova@)",
|
|
43072
|
+
evidence: {
|
|
43073
|
+
tier: "probe",
|
|
43074
|
+
verdict: "model-gate",
|
|
43075
|
+
status: 404,
|
|
43076
|
+
measuredAt: "2026-08-14",
|
|
43077
|
+
note: "404 naming our fake model ('The model `probe-nonexistent-model-zzz` does not exist'), i.e. the route resolved and the model was rejected before auth"
|
|
43078
|
+
}
|
|
43079
|
+
},
|
|
43080
|
+
{
|
|
43081
|
+
name: "novita",
|
|
43082
|
+
displayName: "Novita AI",
|
|
43083
|
+
baseUrl: "https://api.novita.ai/v3/openai",
|
|
43084
|
+
apiPath: "/chat/completions",
|
|
43085
|
+
format: "openai",
|
|
43086
|
+
apiKeyEnvVar: "NOVITA_API_KEY",
|
|
43087
|
+
apiKeyUrl: "https://novita.ai/settings",
|
|
43088
|
+
description: "Novita AI hosted open models (novita@)",
|
|
43089
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43090
|
+
},
|
|
43091
|
+
{
|
|
43092
|
+
name: "baseten",
|
|
43093
|
+
displayName: "Baseten",
|
|
43094
|
+
baseUrl: "https://inference.baseten.co",
|
|
43095
|
+
apiPath: "/v1/chat/completions",
|
|
43096
|
+
format: "openai",
|
|
43097
|
+
apiKeyEnvVar: "BASETEN_API_KEY",
|
|
43098
|
+
apiKeyUrl: "https://app.baseten.co",
|
|
43099
|
+
description: "Baseten model APIs (baseten@)",
|
|
43100
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 403, measuredAt: "2026-08-14" }
|
|
43101
|
+
},
|
|
43102
|
+
{
|
|
43103
|
+
name: "perplexity",
|
|
43104
|
+
displayName: "Perplexity",
|
|
43105
|
+
baseUrl: "https://api.perplexity.ai",
|
|
43106
|
+
apiPath: "/chat/completions",
|
|
43107
|
+
format: "openai",
|
|
43108
|
+
apiKeyEnvVar: "PERPLEXITY_API_KEY",
|
|
43109
|
+
apiKeyUrl: "https://www.perplexity.ai/settings/api",
|
|
43110
|
+
description: "Perplexity Sonar search-grounded models (perplexity@)",
|
|
43111
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43112
|
+
},
|
|
43113
|
+
{
|
|
43114
|
+
name: "venice",
|
|
43115
|
+
displayName: "Venice AI",
|
|
43116
|
+
baseUrl: "https://api.venice.ai/api",
|
|
43117
|
+
apiPath: "/v1/chat/completions",
|
|
43118
|
+
format: "openai",
|
|
43119
|
+
apiKeyEnvVar: "VENICE_API_KEY",
|
|
43120
|
+
apiKeyUrl: "https://venice.ai/settings/api",
|
|
43121
|
+
description: "Venice AI privacy-focused open models (venice@)",
|
|
43122
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43123
|
+
},
|
|
43124
|
+
{
|
|
43125
|
+
name: "chutes",
|
|
43126
|
+
displayName: "Chutes",
|
|
43127
|
+
baseUrl: "https://llm.chutes.ai",
|
|
43128
|
+
apiPath: "/v1/chat/completions",
|
|
43129
|
+
format: "openai",
|
|
43130
|
+
apiKeyEnvVar: "CHUTES_API_KEY",
|
|
43131
|
+
description: "Chutes decentralized inference on Bittensor (chutes@)",
|
|
43132
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43133
|
+
},
|
|
43134
|
+
{
|
|
43135
|
+
name: "featherless",
|
|
43136
|
+
displayName: "Featherless AI",
|
|
43137
|
+
baseUrl: "https://api.featherless.ai",
|
|
43138
|
+
apiPath: "/v1/chat/completions",
|
|
43139
|
+
format: "openai",
|
|
43140
|
+
apiKeyEnvVar: "FEATHERLESS_API_KEY",
|
|
43141
|
+
description: "Featherless AI serverless HuggingFace model hosting (featherless@)",
|
|
43142
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43143
|
+
},
|
|
43144
|
+
{
|
|
43145
|
+
name: "parasail",
|
|
43146
|
+
displayName: "Parasail",
|
|
43147
|
+
baseUrl: "https://api.parasail.io",
|
|
43148
|
+
apiPath: "/v1/chat/completions",
|
|
43149
|
+
format: "openai",
|
|
43150
|
+
apiKeyEnvVar: "PARASAIL_API_KEY",
|
|
43151
|
+
description: "Parasail on-demand GPU inference (parasail@)",
|
|
43152
|
+
evidence: {
|
|
43153
|
+
tier: "probe",
|
|
43154
|
+
verdict: "auth-realm",
|
|
43155
|
+
status: 401,
|
|
43156
|
+
measuredAt: "2026-08-14",
|
|
43157
|
+
note: "non-OpenAI error shape: plain text 'Unauthorized. Invalid token.' under content-type application/json;charset=ISO-8859-1. Classified terminal on the 401 status, so no retry is burned; see validation/error-shape-probe.md"
|
|
43158
|
+
}
|
|
43159
|
+
},
|
|
43160
|
+
{
|
|
43161
|
+
name: "inference-net",
|
|
43162
|
+
displayName: "Inference.net",
|
|
43163
|
+
baseUrl: "https://api.inference.net",
|
|
43164
|
+
apiPath: "/v1/chat/completions",
|
|
43165
|
+
format: "openai",
|
|
43166
|
+
apiKeyEnvVar: "INFERENCE_NET_API_KEY",
|
|
43167
|
+
description: "Inference.net distributed open-model inference (inference-net@)",
|
|
43168
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43169
|
+
},
|
|
43170
|
+
{
|
|
43171
|
+
name: "aimlapi",
|
|
43172
|
+
displayName: "AI/ML API",
|
|
43173
|
+
baseUrl: "https://api.aimlapi.com",
|
|
43174
|
+
apiPath: "/v1/chat/completions",
|
|
43175
|
+
format: "openai",
|
|
43176
|
+
apiKeyEnvVar: "AIMLAPI_API_KEY",
|
|
43177
|
+
description: "AI/ML API multi-vendor aggregator (aimlapi@)",
|
|
43178
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43179
|
+
},
|
|
43180
|
+
{
|
|
43181
|
+
name: "requesty",
|
|
43182
|
+
displayName: "Requesty",
|
|
43183
|
+
baseUrl: "https://router.requesty.ai",
|
|
43184
|
+
apiPath: "/v1/chat/completions",
|
|
43185
|
+
format: "openai",
|
|
43186
|
+
apiKeyEnvVar: "REQUESTY_API_KEY",
|
|
43187
|
+
description: "Requesty LLM router (requesty@)",
|
|
43188
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 403, measuredAt: "2026-08-14" }
|
|
43189
|
+
},
|
|
43190
|
+
{
|
|
43191
|
+
name: "nanogpt",
|
|
43192
|
+
displayName: "NanoGPT",
|
|
43193
|
+
baseUrl: "https://nano-gpt.com/api",
|
|
43194
|
+
apiPath: "/v1/chat/completions",
|
|
43195
|
+
format: "openai",
|
|
43196
|
+
apiKeyEnvVar: "NANOGPT_API_KEY",
|
|
43197
|
+
description: "NanoGPT pay-per-prompt multi-vendor aggregator (nanogpt@)",
|
|
43198
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43199
|
+
},
|
|
43200
|
+
{
|
|
43201
|
+
name: "cohere",
|
|
43202
|
+
displayName: "Cohere",
|
|
43203
|
+
baseUrl: "https://api.cohere.ai/compatibility",
|
|
43204
|
+
apiPath: "/v1/chat/completions",
|
|
43205
|
+
format: "openai",
|
|
43206
|
+
apiKeyEnvVar: "COHERE_API_KEY",
|
|
43207
|
+
apiKeyUrl: "https://dashboard.cohere.com/api-keys",
|
|
43208
|
+
description: "Cohere Command models via their OpenAI-compatibility layer (cohere@)",
|
|
43209
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43210
|
+
},
|
|
43211
|
+
{
|
|
43212
|
+
name: "scaleway",
|
|
43213
|
+
displayName: "Scaleway Generative APIs",
|
|
43214
|
+
baseUrl: "https://api.scaleway.ai",
|
|
43215
|
+
apiPath: "/v1/chat/completions",
|
|
43216
|
+
format: "openai",
|
|
43217
|
+
apiKeyEnvVar: "SCALEWAY_API_KEY",
|
|
43218
|
+
apiKeyUrl: "https://console.scaleway.com",
|
|
43219
|
+
description: "Scaleway Generative APIs, EU-hosted open models (scaleway@)",
|
|
43220
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 403, measuredAt: "2026-08-14" }
|
|
43221
|
+
},
|
|
43222
|
+
{
|
|
43223
|
+
name: "upstage",
|
|
43224
|
+
displayName: "Upstage",
|
|
43225
|
+
baseUrl: "https://api.upstage.ai",
|
|
43226
|
+
apiPath: "/v1/chat/completions",
|
|
43227
|
+
format: "openai",
|
|
43228
|
+
apiKeyEnvVar: "UPSTAGE_API_KEY",
|
|
43229
|
+
apiKeyUrl: "https://console.upstage.ai",
|
|
43230
|
+
description: "Upstage Solar models (upstage@)",
|
|
43231
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43232
|
+
},
|
|
43233
|
+
{
|
|
43234
|
+
name: "writer",
|
|
43235
|
+
displayName: "Writer",
|
|
43236
|
+
baseUrl: "https://api.writer.com",
|
|
43237
|
+
apiPath: "/v1/chat/completions",
|
|
43238
|
+
format: "openai",
|
|
43239
|
+
apiKeyEnvVar: "WRITER_API_KEY",
|
|
43240
|
+
description: "Writer Palmyra models (writer@)",
|
|
43241
|
+
evidence: {
|
|
43242
|
+
tier: "probe",
|
|
43243
|
+
verdict: "auth-realm",
|
|
43244
|
+
status: 401,
|
|
43245
|
+
measuredAt: "2026-08-14",
|
|
43246
|
+
note: 'non-OpenAI error shape: {"tpe":"fail.auth","errors":[{"description":\u2026}]} with no top-level `error` object. Classified terminal on the 401 status, so no retry is burned; see validation/error-shape-probe.md'
|
|
43247
|
+
}
|
|
43248
|
+
},
|
|
43249
|
+
{
|
|
43250
|
+
name: "moonshot-cn",
|
|
43251
|
+
displayName: "Moonshot AI (China)",
|
|
43252
|
+
baseUrl: "https://api.moonshot.cn",
|
|
43253
|
+
apiPath: "/v1/chat/completions",
|
|
43254
|
+
format: "openai",
|
|
43255
|
+
apiKeyEnvVar: "MOONSHOT_CN_API_KEY",
|
|
43256
|
+
apiKeyUrl: "https://platform.moonshot.cn",
|
|
43257
|
+
description: "Moonshot AI China-region endpoint (moonshot-cn@) \u2014 a separate product from the builtin Kimi provider reached by moonshot@/kimi@",
|
|
43258
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43259
|
+
},
|
|
43260
|
+
{
|
|
43261
|
+
name: "tuningengines",
|
|
43262
|
+
displayName: "Tuning Engines",
|
|
43263
|
+
baseUrl: "https://api.tuningengines.com",
|
|
43264
|
+
apiPath: "/v1/chat/completions",
|
|
43265
|
+
format: "openai",
|
|
43266
|
+
apiKeyEnvVar: "TUNING_ENGINES_API_KEY",
|
|
43267
|
+
baseUrlEnvVars: ["TUNING_ENGINES_BASE_URL"],
|
|
43268
|
+
description: "Tuning Engines enterprise LLM gateway (tuningengines@); self-hosted instances point TUNING_ENGINES_BASE_URL at their own host",
|
|
43269
|
+
evidence: { tier: "probe", verdict: "auth-realm", status: 401, measuredAt: "2026-08-14" }
|
|
43270
|
+
}
|
|
43271
|
+
];
|
|
43272
|
+
});
|
|
43273
|
+
|
|
43274
|
+
// src/providers/predefined-endpoints.ts
|
|
43275
|
+
function warnOnce2(message) {
|
|
43276
|
+
if (warnedMessages2.has(message))
|
|
43277
|
+
return;
|
|
43278
|
+
warnedMessages2.add(message);
|
|
43279
|
+
console.error(message);
|
|
43280
|
+
}
|
|
43281
|
+
function activeCatalog() {
|
|
43282
|
+
return catalogOverride ?? PREDEFINED_ENDPOINTS;
|
|
43283
|
+
}
|
|
43284
|
+
function reservedNamespace() {
|
|
43285
|
+
const reserved = new Map;
|
|
43286
|
+
for (const def of BUILTIN_PROVIDERS) {
|
|
43287
|
+
reserved.set(def.name.toLowerCase(), def.name);
|
|
43288
|
+
for (const shortcut of def.shortcuts) {
|
|
43289
|
+
reserved.set(shortcut.toLowerCase(), def.name);
|
|
43290
|
+
}
|
|
43291
|
+
for (const legacy of def.legacyPrefixes) {
|
|
43292
|
+
reserved.set(legacy.prefix.replace(/[/:]+$/, "").toLowerCase(), def.name);
|
|
43293
|
+
}
|
|
43294
|
+
}
|
|
43295
|
+
for (const [alias, owner] of Object.entries(PROVIDER_FILTER_ALIAS_EXTRA)) {
|
|
43296
|
+
reserved.set(alias.toLowerCase(), owner);
|
|
43297
|
+
}
|
|
43298
|
+
return reserved;
|
|
43299
|
+
}
|
|
43300
|
+
function readOptOut(config2) {
|
|
43301
|
+
const off = { disabled: true, disable: new Set, enable: new Set };
|
|
43302
|
+
if (process.env[KILL_SWITCH_ENV] === "1")
|
|
43303
|
+
return off;
|
|
43304
|
+
const raw = config2?.predefinedEndpoints;
|
|
43305
|
+
let parsed = {};
|
|
43306
|
+
if (raw !== undefined) {
|
|
43307
|
+
const result = PredefinedEndpointsConfigSchema.safeParse(raw);
|
|
43308
|
+
if (result.success) {
|
|
43309
|
+
parsed = result.data;
|
|
43310
|
+
} else {
|
|
43311
|
+
warnOnce2("[claudish] config 'predefinedEndpoints' is not valid and was ignored: " + result.error.issues.map((i) => `${i.path.join(".") || "(root)"} ${i.message}`).join(", "));
|
|
43312
|
+
}
|
|
43313
|
+
}
|
|
43314
|
+
return {
|
|
43315
|
+
disabled: parsed.enabled === false,
|
|
43316
|
+
disable: new Set((parsed.disable ?? []).map((n) => n.trim().toLowerCase())),
|
|
43317
|
+
enable: new Set((parsed.enable ?? []).map((n) => n.trim().toLowerCase()))
|
|
43318
|
+
};
|
|
43319
|
+
}
|
|
43320
|
+
function compileToCustomEndpoint(entry) {
|
|
43321
|
+
return {
|
|
43322
|
+
kind: "complex",
|
|
43323
|
+
displayName: entry.displayName,
|
|
43324
|
+
transport: entry.format,
|
|
43325
|
+
baseUrl: entry.baseUrl,
|
|
43326
|
+
apiPath: entry.apiPath,
|
|
43327
|
+
apiKey: `\${${entry.apiKeyEnvVar}}`,
|
|
43328
|
+
authScheme: entry.authScheme,
|
|
43329
|
+
headers: entry.headers,
|
|
43330
|
+
modelPrefix: entry.modelPrefix
|
|
43331
|
+
};
|
|
43332
|
+
}
|
|
43333
|
+
function credentialEnvVars(entry) {
|
|
43334
|
+
return {
|
|
43335
|
+
envVar: entry.apiKeyEnvVar,
|
|
43336
|
+
aliases: [...entry.apiKeyAliases ?? [], customEndpointKeyEnvVar(entry.name)]
|
|
43337
|
+
};
|
|
43338
|
+
}
|
|
43339
|
+
function overridesFor(entry) {
|
|
43340
|
+
const { envVar, aliases } = credentialEnvVars(entry);
|
|
43341
|
+
return {
|
|
43342
|
+
apiKeyEnvVar: envVar,
|
|
43343
|
+
apiKeyAliases: aliases,
|
|
43344
|
+
baseUrlEnvVars: entry.baseUrlEnvVars,
|
|
43345
|
+
apiKeyUrl: entry.apiKeyUrl ?? "",
|
|
43346
|
+
apiKeyDescription: `${entry.displayName} (${envVar})`,
|
|
43347
|
+
description: entry.description ?? `${entry.displayName} (bundled endpoint)`
|
|
43348
|
+
};
|
|
43349
|
+
}
|
|
43350
|
+
function loadPredefinedEndpoints(config2, opts = {}) {
|
|
43351
|
+
const result = { registered: [], skipped: [] };
|
|
43352
|
+
const optOut = readOptOut(config2);
|
|
43353
|
+
const catalog = opts.catalog ?? activeCatalog();
|
|
43354
|
+
const runtime = getRuntimeProviders();
|
|
43355
|
+
const noteStale = (entry, name, reason) => {
|
|
43356
|
+
if (!ownRegistrations.has(name) || !runtime.has(entry.name))
|
|
43357
|
+
return;
|
|
43358
|
+
warnOnce2(`[claudish] predefined endpoint '${entry.name}' is no longer eligible (${reason}) but stays ` + "registered for the rest of this process \u2014 runtime provider registration cannot be " + "undone. Restart claudish to apply the change.");
|
|
43359
|
+
};
|
|
43360
|
+
if (optOut.disabled) {
|
|
43361
|
+
for (const entry of catalog) {
|
|
43362
|
+
result.skipped.push({ name: entry.name, reason: "catalog off" });
|
|
43363
|
+
noteStale(entry, entry.name.toLowerCase(), "catalog off");
|
|
43364
|
+
}
|
|
43365
|
+
return result;
|
|
43366
|
+
}
|
|
43367
|
+
const reserved = reservedNamespace();
|
|
43368
|
+
const userEndpoints = new Set(Object.keys(config2?.customEndpoints ?? {}).map((n) => n.toLowerCase()));
|
|
43369
|
+
const seen = new Set;
|
|
43370
|
+
for (const entry of catalog) {
|
|
43371
|
+
const name = entry.name.toLowerCase();
|
|
43372
|
+
const skip = (reason) => result.skipped.push({ name: entry.name, reason });
|
|
43373
|
+
const skipStale = (reason) => {
|
|
43374
|
+
skip(reason);
|
|
43375
|
+
noteStale(entry, name, reason);
|
|
43376
|
+
};
|
|
43377
|
+
if (seen.has(name)) {
|
|
43378
|
+
warnOnce2(`[claudish] predefined endpoint '${entry.name}' appears more than once in the bundled ` + "catalog. The first row wins; the later one is ignored.");
|
|
43379
|
+
skip("duplicate row");
|
|
43380
|
+
continue;
|
|
43381
|
+
}
|
|
43382
|
+
seen.add(name);
|
|
43383
|
+
const owner = reserved.get(name);
|
|
43384
|
+
if (owner) {
|
|
43385
|
+
const reason = `'${entry.name}' is already claimed by builtin provider '${owner}' ` + "(as its name, a shortcut, or a legacy prefix)";
|
|
43386
|
+
warnOnce2(`[claudish] predefined endpoint '${entry.name}' skipped: ${reason}. ` + "The builtin wins; the bundled entry is inactive.");
|
|
43387
|
+
recordEndpointUnavailable(entry.name, `bundled endpoint was skipped because ${reason}`);
|
|
43388
|
+
skip("collides with builtin");
|
|
43389
|
+
continue;
|
|
43390
|
+
}
|
|
43391
|
+
if (runtime.has(entry.name) && !ownRegistrations.has(name)) {
|
|
43392
|
+
warnOnce2(`[claudish] predefined endpoint '${entry.name}' skipped: a provider named ` + `'${entry.name}' is already registered for this process.`);
|
|
43393
|
+
skip("already registered");
|
|
43394
|
+
continue;
|
|
43395
|
+
}
|
|
43396
|
+
if (userEndpoints.has(name)) {
|
|
43397
|
+
if (hasLocalApiKey({ envVar: entry.apiKeyEnvVar })) {
|
|
43398
|
+
warnOnce2(`[claudish] customEndpoints['${entry.name}'] replaces the bundled entry entirely; ` + `${entry.apiKeyEnvVar} no longer applies to it. Add ` + `"apiKey": "\${${entry.apiKeyEnvVar}}" to that entry to keep using it.`);
|
|
43399
|
+
}
|
|
43400
|
+
skipStale("replaced by customEndpoints");
|
|
43401
|
+
continue;
|
|
43402
|
+
}
|
|
43403
|
+
if (optOut.disable.has(name)) {
|
|
43404
|
+
skipStale("disabled in config");
|
|
43405
|
+
continue;
|
|
43406
|
+
}
|
|
43407
|
+
const { envVar, aliases } = credentialEnvVars(entry);
|
|
43408
|
+
const permitted = optOut.enable.has(name) || hasLocalApiKey({ envVar, aliases });
|
|
43409
|
+
if (!permitted) {
|
|
43410
|
+
skipStale("no local credential");
|
|
43411
|
+
continue;
|
|
43412
|
+
}
|
|
43413
|
+
const resolvedUrl = classifyEndpointBaseUrl(entry.baseUrl, entry.baseUrlEnvVars);
|
|
43414
|
+
if (!resolvedUrl.ok) {
|
|
43415
|
+
const detail = describeBadBaseUrlOverride(resolvedUrl, entry.baseUrl);
|
|
43416
|
+
warnOnce2(`[claudish] predefined endpoint '${entry.name}' skipped: ${detail}`);
|
|
43417
|
+
recordEndpointUnavailable(entry.name, detail);
|
|
43418
|
+
skipStale("invalid base URL override");
|
|
43419
|
+
continue;
|
|
43420
|
+
}
|
|
43421
|
+
try {
|
|
43422
|
+
registerEndpoint(entry.name, compileToCustomEndpoint(entry), overridesFor(entry));
|
|
43423
|
+
ownRegistrations.add(name);
|
|
43424
|
+
result.registered.push(entry.name);
|
|
43425
|
+
} catch (err) {
|
|
43426
|
+
warnOnce2(`[claudish] predefined endpoint '${entry.name}' skipped: ` + `${err instanceof Error ? err.message : String(err)}`);
|
|
43427
|
+
skip("invalid catalog row");
|
|
43428
|
+
}
|
|
43429
|
+
}
|
|
43430
|
+
return result;
|
|
43431
|
+
}
|
|
43432
|
+
var KILL_SWITCH_ENV = "CLAUDISH_NO_PREDEFINED_ENDPOINTS", warnedMessages2, ownRegistrations, catalogOverride = null;
|
|
43433
|
+
var init_predefined_endpoints = __esm(() => {
|
|
43434
|
+
init_local_api_key();
|
|
43435
|
+
init_config_schema();
|
|
43436
|
+
init_custom_endpoints_loader();
|
|
43437
|
+
init_endpoint_diagnostics();
|
|
43438
|
+
init_picker_alias_extra();
|
|
43439
|
+
init_predefined_catalog();
|
|
43440
|
+
init_provider_definitions();
|
|
43441
|
+
init_runtime_providers();
|
|
43442
|
+
warnedMessages2 = new Set;
|
|
43443
|
+
ownRegistrations = new Set;
|
|
43444
|
+
});
|
|
43445
|
+
|
|
43446
|
+
// src/providers/endpoint-registration.ts
|
|
43447
|
+
var exports_endpoint_registration = {};
|
|
43448
|
+
__export(exports_endpoint_registration, {
|
|
43449
|
+
invalidateEndpointRegistration: () => invalidateEndpointRegistration,
|
|
43450
|
+
ensureEndpointsRegistered: () => ensureEndpointsRegistered
|
|
43451
|
+
});
|
|
43452
|
+
function ensureEndpointsRegistered(opts = {}) {
|
|
43453
|
+
if (registered && !opts.force)
|
|
43454
|
+
return;
|
|
43455
|
+
registered = true;
|
|
43456
|
+
try {
|
|
43457
|
+
loadPredefinedEndpoints(opts.config ?? loadConfig());
|
|
43458
|
+
} catch {}
|
|
43459
|
+
}
|
|
43460
|
+
function invalidateEndpointRegistration() {
|
|
43461
|
+
registered = false;
|
|
43462
|
+
}
|
|
43463
|
+
var registered = false;
|
|
43464
|
+
var init_endpoint_registration = __esm(() => {
|
|
43465
|
+
init_profile_config();
|
|
43466
|
+
init_predefined_endpoints();
|
|
43467
|
+
});
|
|
43468
|
+
|
|
42850
43469
|
// src/providers/provider-registry.ts
|
|
42851
43470
|
function resolveBaseUrl2(envVar, fallbackEnvVars, staticDefault) {
|
|
42852
43471
|
for (const v of [envVar, ...fallbackEnvVars]) {
|
|
@@ -43715,7 +44334,9 @@ async function prepareParentRoutingContext() {
|
|
|
43715
44334
|
if (!parentRoutingContextReady) {
|
|
43716
44335
|
parentRoutingContextReady = true;
|
|
43717
44336
|
try {
|
|
43718
|
-
|
|
44337
|
+
const config2 = loadConfig();
|
|
44338
|
+
ensureEndpointsRegistered({ config: config2 });
|
|
44339
|
+
loadCustomEndpoints(config2);
|
|
43719
44340
|
} catch {}
|
|
43720
44341
|
}
|
|
43721
44342
|
try {
|
|
@@ -43765,6 +44386,7 @@ var init_prehydrate = __esm(() => {
|
|
|
43765
44386
|
init_auto_route();
|
|
43766
44387
|
init_catalog_client();
|
|
43767
44388
|
init_custom_endpoints_loader();
|
|
44389
|
+
init_endpoint_registration();
|
|
43768
44390
|
init_model_parser();
|
|
43769
44391
|
init_onepassword();
|
|
43770
44392
|
init_provider_resolver();
|
|
@@ -47534,38 +48156,6 @@ var init_native_handler = __esm(() => {
|
|
|
47534
48156
|
init_anthropic_error();
|
|
47535
48157
|
});
|
|
47536
48158
|
|
|
47537
|
-
// src/providers/api-key-map.ts
|
|
47538
|
-
var API_KEY_MAP;
|
|
47539
|
-
var init_api_key_map = __esm(() => {
|
|
47540
|
-
API_KEY_MAP = {
|
|
47541
|
-
litellm: { envVar: "LITELLM_API_KEY" },
|
|
47542
|
-
openrouter: { envVar: "OPENROUTER_API_KEY" },
|
|
47543
|
-
google: { envVar: "GEMINI_API_KEY" },
|
|
47544
|
-
openai: { envVar: "OPENAI_API_KEY" },
|
|
47545
|
-
minimax: { envVar: "MINIMAX_API_KEY" },
|
|
47546
|
-
"minimax-coding": { envVar: "MINIMAX_CODING_API_KEY" },
|
|
47547
|
-
kimi: { envVar: "MOONSHOT_API_KEY", aliases: ["KIMI_API_KEY"] },
|
|
47548
|
-
"kimi-coding": { envVar: "KIMI_CODING_API_KEY" },
|
|
47549
|
-
glm: { envVar: "ZHIPU_API_KEY", aliases: ["GLM_API_KEY"] },
|
|
47550
|
-
"glm-coding": { envVar: "GLM_CODING_API_KEY", aliases: ["ZAI_CODING_API_KEY"] },
|
|
47551
|
-
"z-ai": { envVar: "ZAI_API_KEY" },
|
|
47552
|
-
deepseek: { envVar: "DEEPSEEK_API_KEY" },
|
|
47553
|
-
mistralai: { envVar: "MISTRAL_API_KEY" },
|
|
47554
|
-
sakana: { envVar: "SAKANA_API_KEY" },
|
|
47555
|
-
"sakana-subscription": {
|
|
47556
|
-
envVar: "SAKANA_SUBSCRIPTION_API_KEY",
|
|
47557
|
-
aliases: ["SAKANA_CODING_API_KEY"]
|
|
47558
|
-
},
|
|
47559
|
-
"qwen-cloud": { envVar: "QWEN_CLOUD_PLAN_API_KEY" },
|
|
47560
|
-
"qwen-payg": { envVar: "DASHSCOPE_API_KEY", aliases: ["QWEN_API_KEY"] },
|
|
47561
|
-
ollamacloud: { envVar: "OLLAMA_API_KEY" },
|
|
47562
|
-
"opencode-zen": { envVar: "OPENCODE_API_KEY" },
|
|
47563
|
-
"opencode-zen-go": { envVar: "OPENCODE_GO_API_KEY", aliases: ["OPENCODE_API_KEY"] },
|
|
47564
|
-
vertex: { envVar: "VERTEX_API_KEY", aliases: ["VERTEX_PROJECT"] },
|
|
47565
|
-
poe: { envVar: "POE_API_KEY" }
|
|
47566
|
-
};
|
|
47567
|
-
});
|
|
47568
|
-
|
|
47569
48159
|
// src/providers/devin/tool-descriptions.ts
|
|
47570
48160
|
function currentMonthAndYear(now = new Date) {
|
|
47571
48161
|
return `${MONTHS[now.getMonth()]} ${now.getFullYear()}`;
|
|
@@ -49411,7 +50001,9 @@ __export(exports_proxy_server, {
|
|
|
49411
50001
|
});
|
|
49412
50002
|
async function createProxyServer(port, _openrouterApiKey, model, monitorMode = false, anthropicApiKey, modelMap, options = {}) {
|
|
49413
50003
|
try {
|
|
49414
|
-
const
|
|
50004
|
+
const config2 = loadConfig();
|
|
50005
|
+
ensureEndpointsRegistered({ config: config2 });
|
|
50006
|
+
const customEpResult = loadCustomEndpoints(config2);
|
|
49415
50007
|
if (customEpResult.registered > 0) {
|
|
49416
50008
|
log(`[Proxy] Registered ${customEpResult.registered} custom endpoint(s) from config`);
|
|
49417
50009
|
}
|
|
@@ -49704,9 +50296,11 @@ ${plan.hint}` : `[Route] ${plan.reason}`;
|
|
|
49704
50296
|
if (hasExplicitProvider) {
|
|
49705
50297
|
const parsedExplicit = parseModelSpec(target);
|
|
49706
50298
|
if (parsedExplicit.provider !== "openrouter") {
|
|
49707
|
-
const
|
|
49708
|
-
|
|
49709
|
-
|
|
50299
|
+
const recorded = getEndpointUnavailableReason(parsedExplicit.provider);
|
|
50300
|
+
if (recorded) {
|
|
50301
|
+
throw new RoutingError(`Explicit model "${target}" could not be routed \u2014 ${recorded}`);
|
|
50302
|
+
}
|
|
50303
|
+
const hint = describeMissingCredential(parsedExplicit.provider);
|
|
49710
50304
|
throw new RoutingError(`Explicit model "${target}" could not be routed \u2014 its provider has no credential. ${hint}`);
|
|
49711
50305
|
}
|
|
49712
50306
|
}
|
|
@@ -49858,11 +50452,13 @@ var init_proxy_server = __esm(() => {
|
|
|
49858
50452
|
init_logger();
|
|
49859
50453
|
init_model_loader();
|
|
49860
50454
|
init_profile_config();
|
|
49861
|
-
init_api_key_map();
|
|
49862
50455
|
init_auto_route();
|
|
49863
50456
|
init_catalog_client();
|
|
49864
50457
|
init_custom_endpoints_loader();
|
|
50458
|
+
init_endpoint_diagnostics();
|
|
50459
|
+
init_endpoint_registration();
|
|
49865
50460
|
init_model_parser();
|
|
50461
|
+
init_provider_definitions();
|
|
49866
50462
|
init_provider_profiles();
|
|
49867
50463
|
init_provider_registry();
|
|
49868
50464
|
init_provider_resolver();
|
|
@@ -50087,12 +50683,132 @@ function writeStatusFile(sessionPath, manifest, status, opts) {
|
|
|
50087
50683
|
var CHANNEL_LINE_BUDGET = 58;
|
|
50088
50684
|
var init_team_stats = () => {};
|
|
50089
50685
|
|
|
50686
|
+
// src/team-stream-capture.ts
|
|
50687
|
+
function extractAssistantText(event) {
|
|
50688
|
+
if (event.type !== "assistant")
|
|
50689
|
+
return [];
|
|
50690
|
+
const message = event.message;
|
|
50691
|
+
const content = message?.content;
|
|
50692
|
+
if (typeof content === "string") {
|
|
50693
|
+
return content.length > 0 ? [content] : [];
|
|
50694
|
+
}
|
|
50695
|
+
if (!Array.isArray(content))
|
|
50696
|
+
return [];
|
|
50697
|
+
const out = [];
|
|
50698
|
+
for (const raw2 of content) {
|
|
50699
|
+
const block = raw2;
|
|
50700
|
+
if (block?.type !== "text")
|
|
50701
|
+
continue;
|
|
50702
|
+
if (typeof block.text !== "string" || block.text.length === 0)
|
|
50703
|
+
continue;
|
|
50704
|
+
out.push(block.text);
|
|
50705
|
+
}
|
|
50706
|
+
return out;
|
|
50707
|
+
}
|
|
50708
|
+
function createAssistantTextCapture() {
|
|
50709
|
+
let pending = "";
|
|
50710
|
+
let emittedAny = false;
|
|
50711
|
+
let endsWithNewline = false;
|
|
50712
|
+
let dedupeTail = "";
|
|
50713
|
+
let lastWasMessage = false;
|
|
50714
|
+
const record4 = (text, kind) => {
|
|
50715
|
+
emittedAny = true;
|
|
50716
|
+
lastWasMessage = kind === "message";
|
|
50717
|
+
endsWithNewline = text.endsWith(`
|
|
50718
|
+
`);
|
|
50719
|
+
dedupeTail = (dedupeTail + text).slice(-DEDUPE_TAIL_LIMIT);
|
|
50720
|
+
};
|
|
50721
|
+
const messageSeparator = () => {
|
|
50722
|
+
if (!emittedAny)
|
|
50723
|
+
return "";
|
|
50724
|
+
return endsWithNewline ? `
|
|
50725
|
+
` : `
|
|
50726
|
+
|
|
50727
|
+
`;
|
|
50728
|
+
};
|
|
50729
|
+
const rawSeparator = () => {
|
|
50730
|
+
if (!emittedAny || endsWithNewline)
|
|
50731
|
+
return "";
|
|
50732
|
+
return `
|
|
50733
|
+
`;
|
|
50734
|
+
};
|
|
50735
|
+
const consumeLine = (line, terminated) => {
|
|
50736
|
+
if (line.trim().length === 0)
|
|
50737
|
+
return "";
|
|
50738
|
+
const passthrough = () => {
|
|
50739
|
+
const out = `${rawSeparator()}${line}${terminated ? `
|
|
50740
|
+
` : ""}`;
|
|
50741
|
+
record4(out, "raw");
|
|
50742
|
+
return out;
|
|
50743
|
+
};
|
|
50744
|
+
let event;
|
|
50745
|
+
try {
|
|
50746
|
+
event = JSON.parse(line);
|
|
50747
|
+
} catch {
|
|
50748
|
+
return passthrough();
|
|
50749
|
+
}
|
|
50750
|
+
if (typeof event.type !== "string" || !STREAM_JSON_EVENT_TYPES.has(event.type)) {
|
|
50751
|
+
return passthrough();
|
|
50752
|
+
}
|
|
50753
|
+
const texts = extractAssistantText(event);
|
|
50754
|
+
if (texts.length > 0) {
|
|
50755
|
+
let out = "";
|
|
50756
|
+
for (const text of texts) {
|
|
50757
|
+
const piece = `${messageSeparator()}${text}`;
|
|
50758
|
+
out += piece;
|
|
50759
|
+
record4(piece, "message");
|
|
50760
|
+
}
|
|
50761
|
+
return out;
|
|
50762
|
+
}
|
|
50763
|
+
if (event.type === "result" && event.is_error === true) {
|
|
50764
|
+
const result = typeof event.result === "string" ? event.result : "";
|
|
50765
|
+
if (result.trim().length > 0 && !dedupeTail.includes(result)) {
|
|
50766
|
+
const out = `${messageSeparator()}${result}`;
|
|
50767
|
+
record4(out, "message");
|
|
50768
|
+
return out;
|
|
50769
|
+
}
|
|
50770
|
+
}
|
|
50771
|
+
return "";
|
|
50772
|
+
};
|
|
50773
|
+
return {
|
|
50774
|
+
write(chunk) {
|
|
50775
|
+
pending += chunk;
|
|
50776
|
+
let out = "";
|
|
50777
|
+
let newlineAt = pending.indexOf(`
|
|
50778
|
+
`);
|
|
50779
|
+
while (newlineAt !== -1) {
|
|
50780
|
+
const line = pending.slice(0, newlineAt);
|
|
50781
|
+
pending = pending.slice(newlineAt + 1);
|
|
50782
|
+
out += consumeLine(line, true);
|
|
50783
|
+
newlineAt = pending.indexOf(`
|
|
50784
|
+
`);
|
|
50785
|
+
}
|
|
50786
|
+
return out;
|
|
50787
|
+
},
|
|
50788
|
+
end() {
|
|
50789
|
+
let out = pending.length > 0 ? consumeLine(pending, false) : "";
|
|
50790
|
+
pending = "";
|
|
50791
|
+
if (emittedAny && !endsWithNewline && lastWasMessage) {
|
|
50792
|
+
out += `
|
|
50793
|
+
`;
|
|
50794
|
+
endsWithNewline = true;
|
|
50795
|
+
}
|
|
50796
|
+
return out;
|
|
50797
|
+
}
|
|
50798
|
+
};
|
|
50799
|
+
}
|
|
50800
|
+
var DEDUPE_TAIL_LIMIT = 4096, STREAM_JSON_EVENT_TYPES;
|
|
50801
|
+
var init_team_stream_capture = __esm(() => {
|
|
50802
|
+
STREAM_JSON_EVENT_TYPES = new Set(["system", "assistant", "user", "result"]);
|
|
50803
|
+
});
|
|
50804
|
+
|
|
50090
50805
|
// src/team-orchestrator.ts
|
|
50091
50806
|
var exports_team_orchestrator = {};
|
|
50092
50807
|
__export(exports_team_orchestrator, {
|
|
50093
50808
|
validateSessionPath: () => validateSessionPath,
|
|
50094
50809
|
setupSession: () => setupSession,
|
|
50095
50810
|
runModels: () => runModels,
|
|
50811
|
+
resolveCaptureMode: () => resolveCaptureMode,
|
|
50096
50812
|
parseJudgeVotes: () => parseJudgeVotes,
|
|
50097
50813
|
judgeResponses: () => judgeResponses,
|
|
50098
50814
|
getStatus: () => getStatus,
|
|
@@ -50100,6 +50816,7 @@ __export(exports_team_orchestrator, {
|
|
|
50100
50816
|
classifyRunOutput: () => classifyRunOutput,
|
|
50101
50817
|
buildJudgePrompt: () => buildJudgePrompt,
|
|
50102
50818
|
aggregateVerdict: () => aggregateVerdict,
|
|
50819
|
+
TEAM_CAPTURE_ENV_VAR: () => TEAM_CAPTURE_ENV_VAR,
|
|
50103
50820
|
STDOUT_TAIL_LIMIT: () => STDOUT_TAIL_LIMIT,
|
|
50104
50821
|
DEFAULT_MIN_OUTPUT_BYTES: () => DEFAULT_MIN_OUTPUT_BYTES
|
|
50105
50822
|
});
|
|
@@ -50113,8 +50830,21 @@ import {
|
|
|
50113
50830
|
writeFileSync as writeFileSync12
|
|
50114
50831
|
} from "fs";
|
|
50115
50832
|
import { join as join28, resolve as resolve3 } from "path";
|
|
50833
|
+
function resolveCaptureMode(explicit, env = process.env) {
|
|
50834
|
+
if (explicit)
|
|
50835
|
+
return explicit;
|
|
50836
|
+
return env[TEAM_CAPTURE_ENV_VAR]?.trim().toLowerCase() === "print" ? "print" : "stream-json";
|
|
50837
|
+
}
|
|
50116
50838
|
function classifyRunOutput(opts) {
|
|
50117
|
-
const {
|
|
50839
|
+
const {
|
|
50840
|
+
outputSize,
|
|
50841
|
+
stdoutTail,
|
|
50842
|
+
stderr,
|
|
50843
|
+
minOutputBytes,
|
|
50844
|
+
requirePattern,
|
|
50845
|
+
fullOutput,
|
|
50846
|
+
captureMode = "print"
|
|
50847
|
+
} = opts;
|
|
50118
50848
|
const apiError = API_ERROR_RE.exec(stdoutTail);
|
|
50119
50849
|
if (apiError) {
|
|
50120
50850
|
return {
|
|
@@ -50151,9 +50881,10 @@ function classifyRunOutput(opts) {
|
|
|
50151
50881
|
re = null;
|
|
50152
50882
|
}
|
|
50153
50883
|
if (re && !re.test(haystack)) {
|
|
50884
|
+
const cause = captureMode === "stream-json" ? "Every assistant message this child produced was captured and concatenated, " + "so this is not the print-mode dropout: the model genuinely never emitted the " + "required shape. Re-prompt it, or relax the contract." : "This is the signature of a child that answered and then took one more turn: " + "`claude -p` prints only the FINAL assistant message, so a background task " + "completing (or any late notification) replaces the real answer with an " + "epilogue about it. The answer was generated, it just was not the last thing " + "said \u2014 re-run with the default stream-json capture to keep it.";
|
|
50154
50885
|
return {
|
|
50155
50886
|
reason: "shape_mismatch",
|
|
50156
|
-
detail: `Child exited 0 with ${outputSize} B, but the response does not match the ` + `required pattern /${requirePattern}/.
|
|
50887
|
+
detail: `Child exited 0 with ${outputSize} B, but the response does not match the ` + `required pattern /${requirePattern}/. ${cause}`
|
|
50157
50888
|
};
|
|
50158
50889
|
}
|
|
50159
50890
|
}
|
|
@@ -50269,6 +51000,7 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
50269
51000
|
}
|
|
50270
51001
|
const minOutputBytes = opts.minOutputBytes ?? DEFAULT_MIN_OUTPUT_BYTES;
|
|
50271
51002
|
const requirePattern = opts.requirePattern;
|
|
51003
|
+
const captureMode = resolveCaptureMode(opts.captureMode);
|
|
50272
51004
|
mkdirSync12(statsDir(sessionPath), { recursive: true });
|
|
50273
51005
|
const processes = new Map;
|
|
50274
51006
|
const runtimes = new Map;
|
|
@@ -50285,7 +51017,14 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
50285
51017
|
const outputPath = join28(sessionPath, `response-${anonId}.md`);
|
|
50286
51018
|
const errorLogPath = join28(sessionPath, "errors", `${anonId}.log`);
|
|
50287
51019
|
const spawnModel = spawnPlan.pinned.get(entry.model) ?? entry.model;
|
|
50288
|
-
const args = [
|
|
51020
|
+
const args = [
|
|
51021
|
+
"--model",
|
|
51022
|
+
spawnModel,
|
|
51023
|
+
"-y",
|
|
51024
|
+
"--stdin",
|
|
51025
|
+
...captureMode === "stream-json" ? ["--verbose", "--quiet", "--output-format", "stream-json"] : ["--quiet"],
|
|
51026
|
+
...opts.claudeFlags ?? []
|
|
51027
|
+
];
|
|
50289
51028
|
updateModelStatus(anonId, {
|
|
50290
51029
|
state: "RUNNING",
|
|
50291
51030
|
startedAt: new Date().toISOString()
|
|
@@ -50301,12 +51040,36 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
50301
51040
|
});
|
|
50302
51041
|
let byteCount = 0;
|
|
50303
51042
|
let stdoutTail = "";
|
|
50304
|
-
proc.stdout?.on("data", (chunk) => {
|
|
50305
|
-
byteCount += chunk.length;
|
|
50306
|
-
stdoutTail = (stdoutTail + chunk.toString()).slice(-STDOUT_TAIL_LIMIT);
|
|
50307
|
-
});
|
|
50308
51043
|
const outputStream = createWriteStream2(outputPath);
|
|
50309
|
-
|
|
51044
|
+
let flushPartial = () => {};
|
|
51045
|
+
if (captureMode === "print") {
|
|
51046
|
+
proc.stdout?.on("data", (chunk) => {
|
|
51047
|
+
byteCount += chunk.length;
|
|
51048
|
+
stdoutTail = (stdoutTail + chunk.toString()).slice(-STDOUT_TAIL_LIMIT);
|
|
51049
|
+
});
|
|
51050
|
+
proc.stdout?.pipe(outputStream);
|
|
51051
|
+
} else {
|
|
51052
|
+
const capture = createAssistantTextCapture();
|
|
51053
|
+
const absorb = (text) => {
|
|
51054
|
+
if (text.length === 0)
|
|
51055
|
+
return;
|
|
51056
|
+
byteCount += Buffer.byteLength(text);
|
|
51057
|
+
stdoutTail = (stdoutTail + text).slice(-STDOUT_TAIL_LIMIT);
|
|
51058
|
+
outputStream.write(text);
|
|
51059
|
+
};
|
|
51060
|
+
proc.stdout?.on("data", (chunk) => absorb(capture.write(chunk.toString())));
|
|
51061
|
+
flushPartial = () => absorb(capture.end());
|
|
51062
|
+
let captureFinalized = false;
|
|
51063
|
+
const finalizeCapture = () => {
|
|
51064
|
+
if (captureFinalized)
|
|
51065
|
+
return;
|
|
51066
|
+
captureFinalized = true;
|
|
51067
|
+
absorb(capture.end());
|
|
51068
|
+
outputStream.end();
|
|
51069
|
+
};
|
|
51070
|
+
proc.stdout?.on("end", finalizeCapture);
|
|
51071
|
+
proc.stdout?.on("close", finalizeCapture);
|
|
51072
|
+
}
|
|
50310
51073
|
let stderr = "";
|
|
50311
51074
|
proc.stderr?.on("data", (chunk) => {
|
|
50312
51075
|
stderr += chunk.toString();
|
|
@@ -50317,7 +51080,8 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
50317
51080
|
errorLogPath,
|
|
50318
51081
|
getStderr: () => stderr,
|
|
50319
51082
|
getStdoutTail: () => stdoutTail,
|
|
50320
|
-
getByteCount: () => byteCount
|
|
51083
|
+
getByteCount: () => byteCount,
|
|
51084
|
+
flushPartial: () => flushPartial()
|
|
50321
51085
|
});
|
|
50322
51086
|
proc.stdin?.write(inputContent);
|
|
50323
51087
|
proc.stdin?.end();
|
|
@@ -50347,7 +51111,8 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
50347
51111
|
stderr,
|
|
50348
51112
|
minOutputBytes,
|
|
50349
51113
|
requirePattern,
|
|
50350
|
-
fullOutput
|
|
51114
|
+
fullOutput,
|
|
51115
|
+
captureMode
|
|
50351
51116
|
});
|
|
50352
51117
|
const failed = crashed || degraded !== null;
|
|
50353
51118
|
const state = crashed ? "FAILED" : degraded ? "EMPTY" : "COMPLETED";
|
|
@@ -50444,10 +51209,11 @@ async function runModels(sessionPath, opts = {}) {
|
|
|
50444
51209
|
if (!proc.killed)
|
|
50445
51210
|
proc.kill("SIGTERM");
|
|
50446
51211
|
const rt = runtimes.get(id);
|
|
51212
|
+
rt?.flushPartial();
|
|
50447
51213
|
const stderr = rt?.getStderr() ?? "";
|
|
50448
51214
|
const stdoutTail = rt?.getStdoutTail() ?? "";
|
|
50449
51215
|
const bytes2 = rt?.getByteCount() ?? 0;
|
|
50450
|
-
const detail = `Killed by the orchestrator after ${timeoutMs / 1000}s with ${bytes2} B of stdout. ` + "
|
|
51216
|
+
const detail = `Killed by the orchestrator after ${timeoutMs / 1000}s with ${bytes2} B of stdout. ` + "That figure counts the ANSWER, not the wire format, so 0 B means the child had " + `not produced an assistant message yet \u2014 "did not finish", not "produced nothing".`;
|
|
50451
51217
|
if (rt)
|
|
50452
51218
|
persistErrorLog(rt.errorLogPath, `TIMEOUT: ${detail}`, stderr, stdoutTail);
|
|
50453
51219
|
updateModelStatus(id, {
|
|
@@ -50659,11 +51425,12 @@ function formatVerdict(verdict, sessionPath) {
|
|
|
50659
51425
|
}
|
|
50660
51426
|
return output;
|
|
50661
51427
|
}
|
|
50662
|
-
var STDOUT_TAIL_LIMIT = 4000, API_ERROR_RE, BG_CEILING_RE, DEFAULT_MIN_OUTPUT_BYTES = 0, SENTINEL_MODELS;
|
|
51428
|
+
var TEAM_CAPTURE_ENV_VAR = "CLAUDISH_TEAM_CAPTURE", STDOUT_TAIL_LIMIT = 4000, API_ERROR_RE, BG_CEILING_RE, DEFAULT_MIN_OUTPUT_BYTES = 0, SENTINEL_MODELS;
|
|
50663
51429
|
var init_team_orchestrator = __esm(() => {
|
|
50664
51430
|
init_prehydrate();
|
|
50665
51431
|
init_redact();
|
|
50666
51432
|
init_team_stats();
|
|
51433
|
+
init_team_stream_capture();
|
|
50667
51434
|
API_ERROR_RE = /\[API Error:\s*([^\]]{0,300})\]/i;
|
|
50668
51435
|
BG_CEILING_RE = /Background tasks still running after (\d+)s; terminating/i;
|
|
50669
51436
|
SENTINEL_MODELS = new Set([
|
|
@@ -51189,7 +51956,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
|
|
|
51189
51956
|
timeout: { type: "number", description: "Per-model timeout in seconds (default: 300)" },
|
|
51190
51957
|
require_pattern: {
|
|
51191
51958
|
type: "string",
|
|
51192
|
-
description: "Regex the response MUST match, or the slot is reported FAILED (state EMPTY, " + "reason 'shape_mismatch') instead of succeeded. Strongly recommended whenever " + "your prompt mandates an output shape \u2014 e.g. '```vote' for a voting panel. " + "Exit code 0 is not a success oracle:
|
|
51959
|
+
description: "Regex the response MUST match, or the slot is reported FAILED (state EMPTY, " + "reason 'shape_mismatch') instead of succeeded. Strongly recommended whenever " + "your prompt mandates an output shape \u2014 e.g. '```vote' for a voting panel. " + "Exit code 0 is not a success oracle: it is 0 on API errors and on a child " + "that simply never followed the format. Answers are no longer LOST to print " + "mode (every assistant message is captured), so a mismatch now means the model " + "did not produce the shape, not that the shape was discarded."
|
|
51193
51960
|
},
|
|
51194
51961
|
min_output_bytes: {
|
|
51195
51962
|
type: "number",
|
|
@@ -51771,7 +52538,7 @@ var init_mcp_server = __esm(() => {
|
|
|
51771
52538
|
api_error: "retry once, or route via a different provider (or@<model>)",
|
|
51772
52539
|
background_task_ceiling: "set CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0 for children, or forbid background work in the prompt",
|
|
51773
52540
|
empty_output: "retry once; if it repeats, drop the model",
|
|
51774
|
-
shape_mismatch: "the
|
|
52541
|
+
shape_mismatch: "the response does not carry the shape you required. Every assistant message the " + "child emitted was captured, so nothing was lost in transit \u2014 the model did not " + "produce it. Re-prompt with the required format restated; do NOT count this slot " + "as a vote"
|
|
51775
52542
|
};
|
|
51776
52543
|
sanitize = sanitizeForReport;
|
|
51777
52544
|
EVENT_TO_TASK_STATUS = new Map([
|
|
@@ -51863,6 +52630,7 @@ async function serveCommand(args) {
|
|
|
51863
52630
|
console.error("[claudish serve] --models <path> is required");
|
|
51864
52631
|
process.exit(1);
|
|
51865
52632
|
}
|
|
52633
|
+
ensureEndpointsRegistered();
|
|
51866
52634
|
let slotMap;
|
|
51867
52635
|
let slotIds;
|
|
51868
52636
|
try {
|
|
@@ -51883,6 +52651,7 @@ async function serveCommand(args) {
|
|
|
51883
52651
|
await new Promise(() => {});
|
|
51884
52652
|
}
|
|
51885
52653
|
var init_serve_command = __esm(() => {
|
|
52654
|
+
init_endpoint_registration();
|
|
51886
52655
|
init_proxy_server();
|
|
51887
52656
|
});
|
|
51888
52657
|
|
|
@@ -65179,7 +65948,8 @@ var init_antigravity_oauth = __esm(() => {
|
|
|
65179
65948
|
var exports_auth_commands = {};
|
|
65180
65949
|
__export(exports_auth_commands, {
|
|
65181
65950
|
logoutCommand: () => logoutCommand,
|
|
65182
|
-
loginCommand: () => loginCommand
|
|
65951
|
+
loginCommand: () => loginCommand,
|
|
65952
|
+
findProvider: () => findProvider
|
|
65183
65953
|
});
|
|
65184
65954
|
function getAuthStatus(provider) {
|
|
65185
65955
|
const hasCredentials = provider.registryKeys.some((k) => hasOAuthCredentials(k)) || provider.name === "antigravity" && hasSharedAntigravityToken();
|
|
@@ -65694,7 +66464,7 @@ __export(exports_model_selector, {
|
|
|
65694
66464
|
buildDiscoveredModelRows: () => buildDiscoveredModelRows
|
|
65695
66465
|
});
|
|
65696
66466
|
function isUserDeployedProvider(value) {
|
|
65697
|
-
return LOCAL_OR_USER_DEPLOYED.has(value);
|
|
66467
|
+
return LOCAL_OR_USER_DEPLOYED.has(value) || getRuntimeProviders().has(value);
|
|
65698
66468
|
}
|
|
65699
66469
|
function firebaseSlugToProviderName(slug) {
|
|
65700
66470
|
const lower = slug.toLowerCase();
|
|
@@ -66454,7 +67224,7 @@ async function selectProfile(profiles) {
|
|
|
66454
67224
|
async function confirmAction(message) {
|
|
66455
67225
|
return dist_default4({ message, default: false });
|
|
66456
67226
|
}
|
|
66457
|
-
var pickerProviderToFirebaseSlug, LOCAL_OR_USER_DEPLOYED, SUBSCRIPTION_PRICING,
|
|
67227
|
+
var pickerProviderToFirebaseSlug, LOCAL_OR_USER_DEPLOYED, SUBSCRIPTION_PRICING, PICKER_COPY, PICKER_ORDER, PROVIDER_MODEL_PREFIX_OVERRIDE;
|
|
66458
67228
|
var init_model_selector = __esm(() => {
|
|
66459
67229
|
init_dist16();
|
|
66460
67230
|
init_model_catalog();
|
|
@@ -66464,7 +67234,9 @@ var init_model_selector = __esm(() => {
|
|
|
66464
67234
|
init_model_catalog2();
|
|
66465
67235
|
init_model_discovery();
|
|
66466
67236
|
init_registry2();
|
|
67237
|
+
init_picker_alias_extra();
|
|
66467
67238
|
init_provider_definitions();
|
|
67239
|
+
init_runtime_providers();
|
|
66468
67240
|
init_probe_discovery();
|
|
66469
67241
|
pickerProviderToFirebaseSlug = {
|
|
66470
67242
|
openrouter: "openrouter",
|
|
@@ -66492,10 +67264,6 @@ var init_model_selector = __esm(() => {
|
|
|
66492
67264
|
output: "SUB",
|
|
66493
67265
|
average: "SUB"
|
|
66494
67266
|
};
|
|
66495
|
-
PROVIDER_FILTER_ALIAS_EXTRA = {
|
|
66496
|
-
gem: "google",
|
|
66497
|
-
zen: "opencode-zen"
|
|
66498
|
-
};
|
|
66499
67267
|
PICKER_COPY = {
|
|
66500
67268
|
openrouter: { description: "580+ models via unified API" },
|
|
66501
67269
|
"opencode-zen": { name: "OpenCode Zen", description: "Free models, no API key needed" },
|
|
@@ -69198,6 +69966,38 @@ var init_probe_tui_runtime = __esm(() => {
|
|
|
69198
69966
|
init_probe_tui_app();
|
|
69199
69967
|
});
|
|
69200
69968
|
|
|
69969
|
+
// src/providers/api-key-map.ts
|
|
69970
|
+
var API_KEY_MAP;
|
|
69971
|
+
var init_api_key_map = __esm(() => {
|
|
69972
|
+
API_KEY_MAP = {
|
|
69973
|
+
litellm: { envVar: "LITELLM_API_KEY" },
|
|
69974
|
+
openrouter: { envVar: "OPENROUTER_API_KEY" },
|
|
69975
|
+
google: { envVar: "GEMINI_API_KEY" },
|
|
69976
|
+
openai: { envVar: "OPENAI_API_KEY" },
|
|
69977
|
+
minimax: { envVar: "MINIMAX_API_KEY" },
|
|
69978
|
+
"minimax-coding": { envVar: "MINIMAX_CODING_API_KEY" },
|
|
69979
|
+
kimi: { envVar: "MOONSHOT_API_KEY", aliases: ["KIMI_API_KEY"] },
|
|
69980
|
+
"kimi-coding": { envVar: "KIMI_CODING_API_KEY" },
|
|
69981
|
+
glm: { envVar: "ZHIPU_API_KEY", aliases: ["GLM_API_KEY"] },
|
|
69982
|
+
"glm-coding": { envVar: "GLM_CODING_API_KEY", aliases: ["ZAI_CODING_API_KEY"] },
|
|
69983
|
+
"z-ai": { envVar: "ZAI_API_KEY" },
|
|
69984
|
+
deepseek: { envVar: "DEEPSEEK_API_KEY" },
|
|
69985
|
+
mistralai: { envVar: "MISTRAL_API_KEY" },
|
|
69986
|
+
sakana: { envVar: "SAKANA_API_KEY" },
|
|
69987
|
+
"sakana-subscription": {
|
|
69988
|
+
envVar: "SAKANA_SUBSCRIPTION_API_KEY",
|
|
69989
|
+
aliases: ["SAKANA_CODING_API_KEY"]
|
|
69990
|
+
},
|
|
69991
|
+
"qwen-cloud": { envVar: "QWEN_CLOUD_PLAN_API_KEY" },
|
|
69992
|
+
"qwen-payg": { envVar: "DASHSCOPE_API_KEY", aliases: ["QWEN_API_KEY"] },
|
|
69993
|
+
ollamacloud: { envVar: "OLLAMA_API_KEY" },
|
|
69994
|
+
"opencode-zen": { envVar: "OPENCODE_API_KEY" },
|
|
69995
|
+
"opencode-zen-go": { envVar: "OPENCODE_GO_API_KEY", aliases: ["OPENCODE_API_KEY"] },
|
|
69996
|
+
vertex: { envVar: "VERTEX_API_KEY", aliases: ["VERTEX_PROJECT"] },
|
|
69997
|
+
poe: { envVar: "POE_API_KEY" }
|
|
69998
|
+
};
|
|
69999
|
+
});
|
|
70000
|
+
|
|
69201
70001
|
// src/providers/probe-runner.ts
|
|
69202
70002
|
function pinProbeModelSpec(link) {
|
|
69203
70003
|
if (link.provider === "native-anthropic")
|
|
@@ -69517,6 +70317,7 @@ async function parseArgs(args) {
|
|
|
69517
70317
|
probeTimeoutMs = parsed * 1000;
|
|
69518
70318
|
}
|
|
69519
70319
|
}
|
|
70320
|
+
ensureEndpointsRegistered();
|
|
69520
70321
|
await probeModelRouting(expandedModels, hasJsonFlag, {
|
|
69521
70322
|
live: !noProbeFlag,
|
|
69522
70323
|
timeoutMs: probeTimeoutMs
|
|
@@ -70858,6 +71659,7 @@ var init_cli = __esm(() => {
|
|
|
70858
71659
|
init_profile_config();
|
|
70859
71660
|
init_api_key_map();
|
|
70860
71661
|
init_api_key_provenance();
|
|
71662
|
+
init_endpoint_registration();
|
|
70861
71663
|
init_model_parser();
|
|
70862
71664
|
init_probe_live();
|
|
70863
71665
|
init_probe_runner();
|
|
@@ -76563,6 +77365,7 @@ function App({ requestLogin } = {}) {
|
|
|
76563
77365
|
const selectedProviderIsLocal = !!(selectedProvider.isLocal || selectedProviderDef?.isLocal);
|
|
76564
77366
|
const selectedLocalEnabled = selectedProviderIsLocal && isLocalProviderEnabled(selectedProvider.catalogName, config3);
|
|
76565
77367
|
const refreshConfig = useCallback3(() => {
|
|
77368
|
+
ensureEndpointsRegistered({ force: true });
|
|
76566
77369
|
setConfig(loadConfig());
|
|
76567
77370
|
setBufStats(getBufferStats());
|
|
76568
77371
|
setOpTick((t) => t + 1);
|
|
@@ -78116,6 +78919,7 @@ var init_App = __esm(() => {
|
|
|
78116
78919
|
init_op_source();
|
|
78117
78920
|
init_profile_config();
|
|
78118
78921
|
init_default_routing_rules();
|
|
78922
|
+
init_endpoint_registration();
|
|
78119
78923
|
init_local_liveness();
|
|
78120
78924
|
init_onepassword_config();
|
|
78121
78925
|
init_onepassword();
|
|
@@ -78155,6 +78959,7 @@ import { createCliRenderer as createCliRenderer2 } from "@opentui/core";
|
|
|
78155
78959
|
import { createRoot as createRoot2 } from "@opentui/react";
|
|
78156
78960
|
import { jsxDEV as jsxDEV17 } from "@opentui/react/jsx-dev-runtime";
|
|
78157
78961
|
async function startConfigTui() {
|
|
78962
|
+
ensureEndpointsRegistered();
|
|
78158
78963
|
setStderrQuiet(true);
|
|
78159
78964
|
const loginRequest = {
|
|
78160
78965
|
slug: null
|
|
@@ -78214,6 +79019,7 @@ var init_tui = __esm(() => {
|
|
|
78214
79019
|
init_codex_oauth();
|
|
78215
79020
|
init_kimi_oauth();
|
|
78216
79021
|
init_logger();
|
|
79022
|
+
init_endpoint_registration();
|
|
78217
79023
|
init_App();
|
|
78218
79024
|
if (isDirectRun) {
|
|
78219
79025
|
startConfigTui().catch((err) => {
|
|
@@ -82344,6 +83150,10 @@ async function runCli() {
|
|
|
82344
83150
|
}
|
|
82345
83151
|
try {
|
|
82346
83152
|
const cliConfig = await traceSpan("startup:parse-args", () => parseArgs2(process.argv.slice(2)));
|
|
83153
|
+
await traceSpan("startup:endpoint-registration", async () => {
|
|
83154
|
+
const { ensureEndpointsRegistered: ensureEndpointsRegistered2 } = await Promise.resolve().then(() => (init_endpoint_registration(), exports_endpoint_registration));
|
|
83155
|
+
ensureEndpointsRegistered2();
|
|
83156
|
+
});
|
|
82347
83157
|
if (cliConfig.team && cliConfig.team.length > 0) {
|
|
82348
83158
|
let prompt = cliConfig.claudeArgs.join(" ");
|
|
82349
83159
|
if (cliConfig.inputFile) {
|