@poolzin/pool-bot 2026.2.4 → 2026.2.6
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/agents/auth-profiles/profiles.js +9 -0
- package/dist/agents/auth-profiles.js +1 -1
- package/dist/agents/huggingface-models.js +166 -0
- package/dist/agents/model-auth.js +6 -0
- package/dist/agents/model-forward-compat.js +187 -0
- package/dist/agents/pi-embedded-runner/model.js +10 -56
- package/dist/browser/constants.js +1 -1
- package/dist/browser/profiles.js +1 -1
- package/dist/build-info.json +3 -3
- package/dist/cli/config-cli.js +17 -3
- package/dist/cli/program/register.onboard.js +38 -5
- package/dist/commands/auth-choice-options.js +71 -7
- package/dist/commands/auth-choice.apply.api-providers.js +202 -97
- package/dist/commands/auth-choice.apply.huggingface.js +130 -0
- package/dist/commands/auth-choice.apply.openrouter.js +77 -0
- package/dist/commands/auth-choice.apply.plugin-provider.js +1 -56
- package/dist/commands/auth-choice.apply.vllm.js +92 -0
- package/dist/commands/auth-choice.preferred-provider.js +10 -0
- package/dist/commands/models/auth.js +1 -58
- package/dist/commands/models/list.errors.js +14 -0
- package/dist/commands/models/list.list-command.js +32 -21
- package/dist/commands/models/list.registry.js +120 -28
- package/dist/commands/models/list.status-command.js +1 -0
- package/dist/commands/models/shared.js +14 -0
- package/dist/commands/onboard-auth.config-core.js +265 -8
- package/dist/commands/onboard-auth.credentials.js +47 -6
- package/dist/commands/onboard-auth.js +3 -3
- package/dist/commands/onboard-auth.models.js +67 -0
- package/dist/commands/onboard-custom.js +181 -70
- package/dist/commands/onboard-non-interactive/api-keys.js +10 -1
- package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +15 -7
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +322 -124
- package/dist/commands/provider-auth-helpers.js +61 -0
- package/dist/commands/zai-endpoint-detect.js +97 -0
- package/dist/config/legacy.migrations.part-3.js +57 -0
- package/dist/terminal/theme.js +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { ensureAuthProfileStore, resolveAuthProfileOrder } from "../agents/auth-profiles.js";
|
|
2
2
|
import { resolveEnvApiKey } from "../agents/model-auth.js";
|
|
3
3
|
import { formatApiKeyPreview, normalizeApiKeyInput, validateApiKeyInput, } from "./auth-choice.api-key.js";
|
|
4
|
+
import { applyAuthChoiceHuggingface } from "./auth-choice.apply.huggingface.js";
|
|
5
|
+
import { applyAuthChoiceOpenRouter } from "./auth-choice.apply.openrouter.js";
|
|
4
6
|
import { applyDefaultModelChoice } from "./auth-choice.default-model.js";
|
|
5
7
|
import { applyGoogleGeminiModelDefault, GOOGLE_GEMINI_DEFAULT_MODEL, } from "./google-gemini-model-default.js";
|
|
6
|
-
import { applyAuthProfileConfig, applyCloudflareAiGatewayConfig, applyCloudflareAiGatewayProviderConfig, applyQianfanConfig, applyQianfanProviderConfig, applyKimiCodeConfig, applyKimiCodeProviderConfig, applyMoonshotConfig, applyMoonshotConfigCn, applyMoonshotProviderConfig, applyMoonshotProviderConfigCn,
|
|
8
|
+
import { applyAuthProfileConfig, applyCloudflareAiGatewayConfig, applyCloudflareAiGatewayProviderConfig, applyQianfanConfig, applyQianfanProviderConfig, applyKimiCodeConfig, applyKimiCodeProviderConfig, applyLitellmConfig, applyLitellmProviderConfig, applyMoonshotConfig, applyMoonshotConfigCn, applyMoonshotProviderConfig, applyMoonshotProviderConfigCn, applyNvidiaConfig, applyNvidiaProviderConfig, applyOpencodeZenConfig, applyOpencodeZenProviderConfig, applySyntheticConfig, applySyntheticProviderConfig, applyTogetherConfig, applyTogetherProviderConfig, applyVeniceConfig, applyVeniceProviderConfig, applyVercelAiGatewayConfig, applyVercelAiGatewayProviderConfig, applyXiaomiConfig, applyXiaomiProviderConfig, applyZaiConfig, applyZaiProviderConfig, CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF, LITELLM_DEFAULT_MODEL_REF, NVIDIA_DEFAULT_MODEL_REF, QIANFAN_DEFAULT_MODEL_REF, KIMI_CODING_MODEL_REF, MOONSHOT_DEFAULT_MODEL_REF, SYNTHETIC_DEFAULT_MODEL_REF, TOGETHER_DEFAULT_MODEL_REF, VENICE_DEFAULT_MODEL_REF, VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF, XIAOMI_DEFAULT_MODEL_REF, setCloudflareAiGatewayConfig, setQianfanApiKey, setGeminiApiKey, setLitellmApiKey, setKimiCodingApiKey, setMoonshotApiKey, setNvidiaApiKey, setOpencodeZenApiKey, setSyntheticApiKey, setTogetherApiKey, setVeniceApiKey, setVercelAiGatewayApiKey, setXiaomiApiKey, setZaiApiKey, ZAI_DEFAULT_MODEL_REF, } from "./onboard-auth.js";
|
|
7
9
|
import { OPENCODE_ZEN_DEFAULT_MODEL } from "./opencode-zen-model-default.js";
|
|
10
|
+
import { detectZaiEndpoint } from "./zai-endpoint-detect.js";
|
|
8
11
|
export async function applyAuthChoiceApiProviders(params) {
|
|
9
12
|
let nextConfig = params.config;
|
|
10
13
|
let agentModelOverride;
|
|
@@ -22,6 +25,9 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
22
25
|
if (params.opts.tokenProvider === "openrouter") {
|
|
23
26
|
authChoice = "openrouter-api-key";
|
|
24
27
|
}
|
|
28
|
+
else if (params.opts.tokenProvider === "litellm") {
|
|
29
|
+
authChoice = "litellm-api-key";
|
|
30
|
+
}
|
|
25
31
|
else if (params.opts.tokenProvider === "vercel-ai-gateway") {
|
|
26
32
|
authChoice = "ai-gateway-api-key";
|
|
27
33
|
}
|
|
@@ -53,83 +59,78 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
53
59
|
else if (params.opts.tokenProvider === "together") {
|
|
54
60
|
authChoice = "together-api-key";
|
|
55
61
|
}
|
|
62
|
+
else if (params.opts.tokenProvider === "huggingface") {
|
|
63
|
+
authChoice = "huggingface-api-key";
|
|
64
|
+
}
|
|
56
65
|
else if (params.opts.tokenProvider === "opencode") {
|
|
57
66
|
authChoice = "opencode-zen";
|
|
58
67
|
}
|
|
59
68
|
else if (params.opts.tokenProvider === "qianfan") {
|
|
60
69
|
authChoice = "qianfan-api-key";
|
|
61
70
|
}
|
|
71
|
+
else if (params.opts.tokenProvider === "nvidia") {
|
|
72
|
+
authChoice = "nvidia-api-key";
|
|
73
|
+
}
|
|
62
74
|
}
|
|
63
75
|
if (authChoice === "openrouter-api-key") {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
store,
|
|
70
|
-
provider: "openrouter",
|
|
71
|
-
});
|
|
76
|
+
return applyAuthChoiceOpenRouter(params);
|
|
77
|
+
}
|
|
78
|
+
if (authChoice === "litellm-api-key") {
|
|
79
|
+
const store = ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false });
|
|
80
|
+
const profileOrder = resolveAuthProfileOrder({ cfg: nextConfig, store, provider: "litellm" });
|
|
72
81
|
const existingProfileId = profileOrder.find((profileId) => Boolean(store.profiles[profileId]));
|
|
73
82
|
const existingCred = existingProfileId ? store.profiles[existingProfileId] : undefined;
|
|
74
|
-
let profileId = "
|
|
75
|
-
let mode = "api_key";
|
|
83
|
+
let profileId = "litellm:default";
|
|
76
84
|
let hasCredential = false;
|
|
77
|
-
if (existingProfileId && existingCred?.type) {
|
|
85
|
+
if (existingProfileId && existingCred?.type === "api_key") {
|
|
78
86
|
profileId = existingProfileId;
|
|
79
|
-
mode =
|
|
80
|
-
existingCred.type === "oauth"
|
|
81
|
-
? "oauth"
|
|
82
|
-
: existingCred.type === "token"
|
|
83
|
-
? "token"
|
|
84
|
-
: "api_key";
|
|
85
87
|
hasCredential = true;
|
|
86
88
|
}
|
|
87
|
-
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "
|
|
88
|
-
await
|
|
89
|
+
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "litellm") {
|
|
90
|
+
await setLitellmApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir);
|
|
89
91
|
hasCredential = true;
|
|
90
92
|
}
|
|
91
93
|
if (!hasCredential) {
|
|
92
|
-
|
|
94
|
+
await params.prompter.note("LiteLLM provides a unified API to 100+ LLM providers.\nGet your API key from your LiteLLM proxy or https://litellm.ai\nDefault proxy runs on http://localhost:4000", "LiteLLM");
|
|
95
|
+
const envKey = resolveEnvApiKey("litellm");
|
|
93
96
|
if (envKey) {
|
|
94
97
|
const useExisting = await params.prompter.confirm({
|
|
95
|
-
message: `Use existing
|
|
98
|
+
message: `Use existing LITELLM_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`,
|
|
96
99
|
initialValue: true,
|
|
97
100
|
});
|
|
98
101
|
if (useExisting) {
|
|
99
|
-
await
|
|
102
|
+
await setLitellmApiKey(envKey.apiKey, params.agentDir);
|
|
100
103
|
hasCredential = true;
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
if (!hasCredential) {
|
|
107
|
+
const key = await params.prompter.text({
|
|
108
|
+
message: "Enter LiteLLM API key",
|
|
109
|
+
validate: validateApiKeyInput,
|
|
110
|
+
});
|
|
111
|
+
await setLitellmApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
112
|
+
hasCredential = true;
|
|
113
|
+
}
|
|
111
114
|
}
|
|
112
115
|
if (hasCredential) {
|
|
113
116
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
114
117
|
profileId,
|
|
115
|
-
provider: "
|
|
116
|
-
mode,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
{
|
|
120
|
-
const applied = await applyDefaultModelChoice({
|
|
121
|
-
config: nextConfig,
|
|
122
|
-
setDefaultModel: params.setDefaultModel,
|
|
123
|
-
defaultModel: OPENROUTER_DEFAULT_MODEL_REF,
|
|
124
|
-
applyDefaultConfig: applyOpenrouterConfig,
|
|
125
|
-
applyProviderConfig: applyOpenrouterProviderConfig,
|
|
126
|
-
noteDefault: OPENROUTER_DEFAULT_MODEL_REF,
|
|
127
|
-
noteAgentModel,
|
|
128
|
-
prompter: params.prompter,
|
|
118
|
+
provider: "litellm",
|
|
119
|
+
mode: "api_key",
|
|
129
120
|
});
|
|
130
|
-
nextConfig = applied.config;
|
|
131
|
-
agentModelOverride = applied.agentModelOverride ?? agentModelOverride;
|
|
132
121
|
}
|
|
122
|
+
const applied = await applyDefaultModelChoice({
|
|
123
|
+
config: nextConfig,
|
|
124
|
+
setDefaultModel: params.setDefaultModel,
|
|
125
|
+
defaultModel: LITELLM_DEFAULT_MODEL_REF,
|
|
126
|
+
applyDefaultConfig: applyLitellmConfig,
|
|
127
|
+
applyProviderConfig: applyLitellmProviderConfig,
|
|
128
|
+
noteDefault: LITELLM_DEFAULT_MODEL_REF,
|
|
129
|
+
noteAgentModel,
|
|
130
|
+
prompter: params.prompter,
|
|
131
|
+
});
|
|
132
|
+
nextConfig = applied.config;
|
|
133
|
+
agentModelOverride = applied.agentModelOverride ?? agentModelOverride;
|
|
133
134
|
return { config: nextConfig, agentModelOverride };
|
|
134
135
|
}
|
|
135
136
|
if (authChoice === "ai-gateway-api-key") {
|
|
@@ -156,7 +157,7 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
156
157
|
message: "Enter Vercel AI Gateway API key",
|
|
157
158
|
validate: validateApiKeyInput,
|
|
158
159
|
});
|
|
159
|
-
await setVercelAiGatewayApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
|
|
160
|
+
await setVercelAiGatewayApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
160
161
|
}
|
|
161
162
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
162
163
|
profileId: "vercel-ai-gateway:default",
|
|
@@ -187,16 +188,16 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
187
188
|
if (!accountId) {
|
|
188
189
|
const value = await params.prompter.text({
|
|
189
190
|
message: "Enter Cloudflare Account ID",
|
|
190
|
-
validate: (val) => (String(val).trim() ? undefined : "Account ID is required"),
|
|
191
|
+
validate: (val) => (String(val ?? "").trim() ? undefined : "Account ID is required"),
|
|
191
192
|
});
|
|
192
|
-
accountId = String(value).trim();
|
|
193
|
+
accountId = String(value ?? "").trim();
|
|
193
194
|
}
|
|
194
195
|
if (!gatewayId) {
|
|
195
196
|
const value = await params.prompter.text({
|
|
196
197
|
message: "Enter Cloudflare AI Gateway ID",
|
|
197
|
-
validate: (val) => (String(val).trim() ? undefined : "Gateway ID is required"),
|
|
198
|
+
validate: (val) => (String(val ?? "").trim() ? undefined : "Gateway ID is required"),
|
|
198
199
|
});
|
|
199
|
-
gatewayId = String(value).trim();
|
|
200
|
+
gatewayId = String(value ?? "").trim();
|
|
200
201
|
}
|
|
201
202
|
};
|
|
202
203
|
const optsApiKey = normalizeApiKeyInput(params.opts?.cloudflareAiGatewayApiKey ?? "");
|
|
@@ -227,7 +228,7 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
227
228
|
message: "Enter Cloudflare AI Gateway API key",
|
|
228
229
|
validate: validateApiKeyInput,
|
|
229
230
|
});
|
|
230
|
-
await setCloudflareAiGatewayConfig(accountId, gatewayId, normalizeApiKeyInput(String(key)), params.agentDir);
|
|
231
|
+
await setCloudflareAiGatewayConfig(accountId, gatewayId, normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
231
232
|
hasCredential = true;
|
|
232
233
|
}
|
|
233
234
|
if (hasCredential) {
|
|
@@ -281,7 +282,7 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
281
282
|
message: "Enter Moonshot API key",
|
|
282
283
|
validate: validateApiKeyInput,
|
|
283
284
|
});
|
|
284
|
-
await setMoonshotApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
|
|
285
|
+
await setMoonshotApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
285
286
|
}
|
|
286
287
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
287
288
|
profileId: "moonshot:default",
|
|
@@ -325,7 +326,7 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
325
326
|
message: "Enter Moonshot API key (.cn)",
|
|
326
327
|
validate: validateApiKeyInput,
|
|
327
328
|
});
|
|
328
|
-
await setMoonshotApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
|
|
329
|
+
await setMoonshotApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
329
330
|
}
|
|
330
331
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
331
332
|
profileId: "moonshot:default",
|
|
@@ -378,7 +379,7 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
378
379
|
message: "Enter Kimi Coding API key",
|
|
379
380
|
validate: validateApiKeyInput,
|
|
380
381
|
});
|
|
381
|
-
await setKimiCodingApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
|
|
382
|
+
await setKimiCodingApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
382
383
|
}
|
|
383
384
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
384
385
|
profileId: "kimi-coding:default",
|
|
@@ -423,7 +424,7 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
423
424
|
message: "Enter Gemini API key",
|
|
424
425
|
validate: validateApiKeyInput,
|
|
425
426
|
});
|
|
426
|
-
await setGeminiApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
|
|
427
|
+
await setGeminiApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
427
428
|
}
|
|
428
429
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
429
430
|
profileId: "google:default",
|
|
@@ -443,10 +444,30 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
443
444
|
}
|
|
444
445
|
return { config: nextConfig, agentModelOverride };
|
|
445
446
|
}
|
|
446
|
-
if (authChoice === "zai-api-key"
|
|
447
|
+
if (authChoice === "zai-api-key" ||
|
|
448
|
+
authChoice === "zai-coding-global" ||
|
|
449
|
+
authChoice === "zai-coding-cn" ||
|
|
450
|
+
authChoice === "zai-global" ||
|
|
451
|
+
authChoice === "zai-cn") {
|
|
452
|
+
let endpoint;
|
|
453
|
+
if (authChoice === "zai-coding-global") {
|
|
454
|
+
endpoint = "coding-global";
|
|
455
|
+
}
|
|
456
|
+
else if (authChoice === "zai-coding-cn") {
|
|
457
|
+
endpoint = "coding-cn";
|
|
458
|
+
}
|
|
459
|
+
else if (authChoice === "zai-global") {
|
|
460
|
+
endpoint = "global";
|
|
461
|
+
}
|
|
462
|
+
else if (authChoice === "zai-cn") {
|
|
463
|
+
endpoint = "cn";
|
|
464
|
+
}
|
|
465
|
+
// Input API key
|
|
447
466
|
let hasCredential = false;
|
|
467
|
+
let apiKey = "";
|
|
448
468
|
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "zai") {
|
|
449
|
-
|
|
469
|
+
apiKey = normalizeApiKeyInput(params.opts.token);
|
|
470
|
+
await setZaiApiKey(apiKey, params.agentDir);
|
|
450
471
|
hasCredential = true;
|
|
451
472
|
}
|
|
452
473
|
const envKey = resolveEnvApiKey("zai");
|
|
@@ -456,7 +477,8 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
456
477
|
initialValue: true,
|
|
457
478
|
});
|
|
458
479
|
if (useExisting) {
|
|
459
|
-
|
|
480
|
+
apiKey = envKey.apiKey;
|
|
481
|
+
await setZaiApiKey(apiKey, params.agentDir);
|
|
460
482
|
hasCredential = true;
|
|
461
483
|
}
|
|
462
484
|
}
|
|
@@ -465,42 +487,71 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
465
487
|
message: "Enter Z.AI API key",
|
|
466
488
|
validate: validateApiKeyInput,
|
|
467
489
|
});
|
|
468
|
-
|
|
490
|
+
apiKey = normalizeApiKeyInput(String(key ?? ""));
|
|
491
|
+
await setZaiApiKey(apiKey, params.agentDir);
|
|
492
|
+
}
|
|
493
|
+
// zai-api-key: auto-detect endpoint + choose a working default model.
|
|
494
|
+
let modelIdOverride;
|
|
495
|
+
if (!endpoint) {
|
|
496
|
+
const detected = await detectZaiEndpoint({ apiKey });
|
|
497
|
+
if (detected) {
|
|
498
|
+
endpoint = detected.endpoint;
|
|
499
|
+
modelIdOverride = detected.modelId;
|
|
500
|
+
await params.prompter.note(detected.note, "Z.AI endpoint");
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
endpoint = await params.prompter.select({
|
|
504
|
+
message: "Select Z.AI endpoint",
|
|
505
|
+
options: [
|
|
506
|
+
{
|
|
507
|
+
value: "coding-global",
|
|
508
|
+
label: "Coding-Plan-Global",
|
|
509
|
+
hint: "GLM Coding Plan Global (api.z.ai)",
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
value: "coding-cn",
|
|
513
|
+
label: "Coding-Plan-CN",
|
|
514
|
+
hint: "GLM Coding Plan CN (open.bigmodel.cn)",
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
value: "global",
|
|
518
|
+
label: "Global",
|
|
519
|
+
hint: "Z.AI Global (api.z.ai)",
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
value: "cn",
|
|
523
|
+
label: "CN",
|
|
524
|
+
hint: "Z.AI CN (open.bigmodel.cn)",
|
|
525
|
+
},
|
|
526
|
+
],
|
|
527
|
+
initialValue: "global",
|
|
528
|
+
});
|
|
529
|
+
}
|
|
469
530
|
}
|
|
470
531
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
471
532
|
profileId: "zai:default",
|
|
472
533
|
provider: "zai",
|
|
473
534
|
mode: "api_key",
|
|
474
535
|
});
|
|
475
|
-
{
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
},
|
|
495
|
-
},
|
|
496
|
-
}),
|
|
497
|
-
noteDefault: ZAI_DEFAULT_MODEL_REF,
|
|
498
|
-
noteAgentModel,
|
|
499
|
-
prompter: params.prompter,
|
|
500
|
-
});
|
|
501
|
-
nextConfig = applied.config;
|
|
502
|
-
agentModelOverride = applied.agentModelOverride ?? agentModelOverride;
|
|
503
|
-
}
|
|
536
|
+
const defaultModel = modelIdOverride ? `zai/${modelIdOverride}` : ZAI_DEFAULT_MODEL_REF;
|
|
537
|
+
const applied = await applyDefaultModelChoice({
|
|
538
|
+
config: nextConfig,
|
|
539
|
+
setDefaultModel: params.setDefaultModel,
|
|
540
|
+
defaultModel,
|
|
541
|
+
applyDefaultConfig: (config) => applyZaiConfig(config, {
|
|
542
|
+
endpoint,
|
|
543
|
+
...(modelIdOverride ? { modelId: modelIdOverride } : {}),
|
|
544
|
+
}),
|
|
545
|
+
applyProviderConfig: (config) => applyZaiProviderConfig(config, {
|
|
546
|
+
endpoint,
|
|
547
|
+
...(modelIdOverride ? { modelId: modelIdOverride } : {}),
|
|
548
|
+
}),
|
|
549
|
+
noteDefault: defaultModel,
|
|
550
|
+
noteAgentModel,
|
|
551
|
+
prompter: params.prompter,
|
|
552
|
+
});
|
|
553
|
+
nextConfig = applied.config;
|
|
554
|
+
agentModelOverride = applied.agentModelOverride ?? agentModelOverride;
|
|
504
555
|
return { config: nextConfig, agentModelOverride };
|
|
505
556
|
}
|
|
506
557
|
if (authChoice === "xiaomi-api-key") {
|
|
@@ -525,7 +576,7 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
525
576
|
message: "Enter Xiaomi API key",
|
|
526
577
|
validate: validateApiKeyInput,
|
|
527
578
|
});
|
|
528
|
-
await setXiaomiApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
|
|
579
|
+
await setXiaomiApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
529
580
|
}
|
|
530
581
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
531
582
|
profileId: "xiaomi:default",
|
|
@@ -550,14 +601,14 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
550
601
|
}
|
|
551
602
|
if (authChoice === "synthetic-api-key") {
|
|
552
603
|
if (params.opts?.token && params.opts?.tokenProvider === "synthetic") {
|
|
553
|
-
await setSyntheticApiKey(String(params.opts.token).trim(), params.agentDir);
|
|
604
|
+
await setSyntheticApiKey(String(params.opts.token ?? "").trim(), params.agentDir);
|
|
554
605
|
}
|
|
555
606
|
else {
|
|
556
607
|
const key = await params.prompter.text({
|
|
557
608
|
message: "Enter Synthetic API key",
|
|
558
609
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
|
559
610
|
});
|
|
560
|
-
await setSyntheticApiKey(String(key).trim(), params.agentDir);
|
|
611
|
+
await setSyntheticApiKey(String(key ?? "").trim(), params.agentDir);
|
|
561
612
|
}
|
|
562
613
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
563
614
|
profileId: "synthetic:default",
|
|
@@ -609,7 +660,7 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
609
660
|
message: "Enter Venice AI API key",
|
|
610
661
|
validate: validateApiKeyInput,
|
|
611
662
|
});
|
|
612
|
-
await setVeniceApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
|
|
663
|
+
await setVeniceApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
613
664
|
}
|
|
614
665
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
615
666
|
profileId: "venice:default",
|
|
@@ -661,7 +712,7 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
661
712
|
message: "Enter OpenCode Zen API key",
|
|
662
713
|
validate: validateApiKeyInput,
|
|
663
714
|
});
|
|
664
|
-
await setOpencodeZenApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
|
|
715
|
+
await setOpencodeZenApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
665
716
|
}
|
|
666
717
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
667
718
|
profileId: "opencode:default",
|
|
@@ -712,7 +763,7 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
712
763
|
message: "Enter Together AI API key",
|
|
713
764
|
validate: validateApiKeyInput,
|
|
714
765
|
});
|
|
715
|
-
await setTogetherApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
|
|
766
|
+
await setTogetherApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
716
767
|
}
|
|
717
768
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
718
769
|
profileId: "together:default",
|
|
@@ -735,6 +786,9 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
735
786
|
}
|
|
736
787
|
return { config: nextConfig, agentModelOverride };
|
|
737
788
|
}
|
|
789
|
+
if (authChoice === "huggingface-api-key") {
|
|
790
|
+
return applyAuthChoiceHuggingface({ ...params, authChoice });
|
|
791
|
+
}
|
|
738
792
|
if (authChoice === "qianfan-api-key") {
|
|
739
793
|
let hasCredential = false;
|
|
740
794
|
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "qianfan") {
|
|
@@ -763,7 +817,7 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
763
817
|
message: "Enter QIANFAN API key",
|
|
764
818
|
validate: validateApiKeyInput,
|
|
765
819
|
});
|
|
766
|
-
setQianfanApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
|
|
820
|
+
setQianfanApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
767
821
|
}
|
|
768
822
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
769
823
|
profileId: "qianfan:default",
|
|
@@ -786,5 +840,56 @@ export async function applyAuthChoiceApiProviders(params) {
|
|
|
786
840
|
}
|
|
787
841
|
return { config: nextConfig, agentModelOverride };
|
|
788
842
|
}
|
|
843
|
+
if (authChoice === "nvidia-api-key") {
|
|
844
|
+
let hasCredential = false;
|
|
845
|
+
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "nvidia") {
|
|
846
|
+
setNvidiaApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir);
|
|
847
|
+
hasCredential = true;
|
|
848
|
+
}
|
|
849
|
+
if (!hasCredential) {
|
|
850
|
+
await params.prompter.note([
|
|
851
|
+
"Get your API key at: https://build.nvidia.com/settings/api-key",
|
|
852
|
+
"Free tier includes 1,000 requests/day across 23+ frontier models.",
|
|
853
|
+
].join("\n"), "NVIDIA");
|
|
854
|
+
}
|
|
855
|
+
const envKey = resolveEnvApiKey("nvidia");
|
|
856
|
+
if (envKey) {
|
|
857
|
+
const useExisting = await params.prompter.confirm({
|
|
858
|
+
message: `Use existing NVIDIA_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`,
|
|
859
|
+
initialValue: true,
|
|
860
|
+
});
|
|
861
|
+
if (useExisting) {
|
|
862
|
+
setNvidiaApiKey(envKey.apiKey, params.agentDir);
|
|
863
|
+
hasCredential = true;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
if (!hasCredential) {
|
|
867
|
+
const key = await params.prompter.text({
|
|
868
|
+
message: "Enter NVIDIA API key",
|
|
869
|
+
validate: validateApiKeyInput,
|
|
870
|
+
});
|
|
871
|
+
setNvidiaApiKey(normalizeApiKeyInput(String(key ?? "")), params.agentDir);
|
|
872
|
+
}
|
|
873
|
+
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
874
|
+
profileId: "nvidia:default",
|
|
875
|
+
provider: "nvidia",
|
|
876
|
+
mode: "api_key",
|
|
877
|
+
});
|
|
878
|
+
{
|
|
879
|
+
const applied = await applyDefaultModelChoice({
|
|
880
|
+
config: nextConfig,
|
|
881
|
+
setDefaultModel: params.setDefaultModel,
|
|
882
|
+
defaultModel: NVIDIA_DEFAULT_MODEL_REF,
|
|
883
|
+
applyDefaultConfig: applyNvidiaConfig,
|
|
884
|
+
applyProviderConfig: applyNvidiaProviderConfig,
|
|
885
|
+
noteDefault: NVIDIA_DEFAULT_MODEL_REF,
|
|
886
|
+
noteAgentModel,
|
|
887
|
+
prompter: params.prompter,
|
|
888
|
+
});
|
|
889
|
+
nextConfig = applied.config;
|
|
890
|
+
agentModelOverride = applied.agentModelOverride ?? agentModelOverride;
|
|
891
|
+
}
|
|
892
|
+
return { config: nextConfig, agentModelOverride };
|
|
893
|
+
}
|
|
789
894
|
return null;
|
|
790
895
|
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { discoverHuggingfaceModels, isHuggingfacePolicyLocked, } from "../agents/huggingface-models.js";
|
|
2
|
+
import { resolveEnvApiKey } from "../agents/model-auth.js";
|
|
3
|
+
import { formatApiKeyPreview, normalizeApiKeyInput, validateApiKeyInput, } from "./auth-choice.api-key.js";
|
|
4
|
+
import { applyDefaultModelChoice } from "./auth-choice.default-model.js";
|
|
5
|
+
import { ensureModelAllowlistEntry } from "./model-allowlist.js";
|
|
6
|
+
import { applyAuthProfileConfig, applyHuggingfaceProviderConfig, setHuggingfaceApiKey, HUGGINGFACE_DEFAULT_MODEL_REF, } from "./onboard-auth.js";
|
|
7
|
+
export async function applyAuthChoiceHuggingface(params) {
|
|
8
|
+
if (params.authChoice !== "huggingface-api-key") {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
let nextConfig = params.config;
|
|
12
|
+
let agentModelOverride;
|
|
13
|
+
const noteAgentModel = async (model) => {
|
|
14
|
+
if (!params.agentId) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
await params.prompter.note(`Default model set to ${model} for agent "${params.agentId}".`, "Model configured");
|
|
18
|
+
};
|
|
19
|
+
let hasCredential = false;
|
|
20
|
+
let hfKey = "";
|
|
21
|
+
if (!hasCredential && params.opts?.token && params.opts.tokenProvider === "huggingface") {
|
|
22
|
+
hfKey = normalizeApiKeyInput(params.opts.token);
|
|
23
|
+
await setHuggingfaceApiKey(hfKey, params.agentDir);
|
|
24
|
+
hasCredential = true;
|
|
25
|
+
}
|
|
26
|
+
if (!hasCredential) {
|
|
27
|
+
await params.prompter.note([
|
|
28
|
+
"Hugging Face Inference Providers offer OpenAI-compatible chat completions.",
|
|
29
|
+
"Create a token at: https://huggingface.co/settings/tokens (fine-grained, 'Make calls to Inference Providers').",
|
|
30
|
+
].join("\n"), "Hugging Face");
|
|
31
|
+
}
|
|
32
|
+
if (!hasCredential) {
|
|
33
|
+
const envKey = resolveEnvApiKey("huggingface");
|
|
34
|
+
if (envKey) {
|
|
35
|
+
const useExisting = await params.prompter.confirm({
|
|
36
|
+
message: `Use existing Hugging Face token (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`,
|
|
37
|
+
initialValue: true,
|
|
38
|
+
});
|
|
39
|
+
if (useExisting) {
|
|
40
|
+
hfKey = envKey.apiKey;
|
|
41
|
+
await setHuggingfaceApiKey(hfKey, params.agentDir);
|
|
42
|
+
hasCredential = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (!hasCredential) {
|
|
47
|
+
const key = await params.prompter.text({
|
|
48
|
+
message: "Enter Hugging Face API key (HF token)",
|
|
49
|
+
validate: validateApiKeyInput,
|
|
50
|
+
});
|
|
51
|
+
hfKey = normalizeApiKeyInput(String(key ?? ""));
|
|
52
|
+
await setHuggingfaceApiKey(hfKey, params.agentDir);
|
|
53
|
+
}
|
|
54
|
+
nextConfig = applyAuthProfileConfig(nextConfig, {
|
|
55
|
+
profileId: "huggingface:default",
|
|
56
|
+
provider: "huggingface",
|
|
57
|
+
mode: "api_key",
|
|
58
|
+
});
|
|
59
|
+
const models = await discoverHuggingfaceModels(hfKey);
|
|
60
|
+
const modelRefPrefix = "huggingface/";
|
|
61
|
+
const options = [];
|
|
62
|
+
for (const m of models) {
|
|
63
|
+
const baseRef = `${modelRefPrefix}${m.id}`;
|
|
64
|
+
const label = m.name ?? m.id;
|
|
65
|
+
options.push({ value: baseRef, label });
|
|
66
|
+
options.push({ value: `${baseRef}:cheapest`, label: `${label} (cheapest)` });
|
|
67
|
+
options.push({ value: `${baseRef}:fastest`, label: `${label} (fastest)` });
|
|
68
|
+
}
|
|
69
|
+
const defaultRef = HUGGINGFACE_DEFAULT_MODEL_REF;
|
|
70
|
+
options.sort((a, b) => {
|
|
71
|
+
if (a.value === defaultRef) {
|
|
72
|
+
return -1;
|
|
73
|
+
}
|
|
74
|
+
if (b.value === defaultRef) {
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
return a.label.localeCompare(b.label, undefined, { sensitivity: "base" });
|
|
78
|
+
});
|
|
79
|
+
const selectedModelRef = options.length === 0
|
|
80
|
+
? defaultRef
|
|
81
|
+
: options.length === 1
|
|
82
|
+
? options[0].value
|
|
83
|
+
: await params.prompter.select({
|
|
84
|
+
message: "Default Hugging Face model",
|
|
85
|
+
options,
|
|
86
|
+
initialValue: options.some((o) => o.value === defaultRef)
|
|
87
|
+
? defaultRef
|
|
88
|
+
: options[0].value,
|
|
89
|
+
});
|
|
90
|
+
if (isHuggingfacePolicyLocked(selectedModelRef)) {
|
|
91
|
+
await params.prompter.note("Provider locked — router will choose backend by cost or speed.", "Hugging Face");
|
|
92
|
+
}
|
|
93
|
+
const applied = await applyDefaultModelChoice({
|
|
94
|
+
config: nextConfig,
|
|
95
|
+
setDefaultModel: params.setDefaultModel,
|
|
96
|
+
defaultModel: selectedModelRef,
|
|
97
|
+
applyDefaultConfig: (config) => {
|
|
98
|
+
const withProvider = applyHuggingfaceProviderConfig(config);
|
|
99
|
+
const existingModel = withProvider.agents?.defaults?.model;
|
|
100
|
+
const withPrimary = {
|
|
101
|
+
...withProvider,
|
|
102
|
+
agents: {
|
|
103
|
+
...withProvider.agents,
|
|
104
|
+
defaults: {
|
|
105
|
+
...withProvider.agents?.defaults,
|
|
106
|
+
model: {
|
|
107
|
+
...(existingModel && typeof existingModel === "object" && "fallbacks" in existingModel
|
|
108
|
+
? {
|
|
109
|
+
fallbacks: existingModel.fallbacks,
|
|
110
|
+
}
|
|
111
|
+
: {}),
|
|
112
|
+
primary: selectedModelRef,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
return ensureModelAllowlistEntry({
|
|
118
|
+
cfg: withPrimary,
|
|
119
|
+
modelRef: selectedModelRef,
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
applyProviderConfig: applyHuggingfaceProviderConfig,
|
|
123
|
+
noteDefault: selectedModelRef,
|
|
124
|
+
noteAgentModel,
|
|
125
|
+
prompter: params.prompter,
|
|
126
|
+
});
|
|
127
|
+
nextConfig = applied.config;
|
|
128
|
+
agentModelOverride = applied.agentModelOverride ?? agentModelOverride;
|
|
129
|
+
return { config: nextConfig, agentModelOverride };
|
|
130
|
+
}
|