@poolzin/pool-bot 2026.2.5 → 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 +5 -0
- package/dist/build-info.json +3 -3
- package/dist/cli/config-cli.js +17 -3
- package/dist/cli/program/register.onboard.js +34 -11
- package/dist/commands/auth-choice-options.js +60 -7
- package/dist/commands/auth-choice.apply.api-providers.js +149 -98
- 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.vllm.js +92 -0
- package/dist/commands/auth-choice.preferred-provider.js +9 -0
- package/dist/commands/onboard-auth.config-core.js +207 -8
- package/dist/commands/onboard-auth.credentials.js +35 -5
- package/dist/commands/onboard-auth.js +3 -3
- package/dist/commands/onboard-auth.models.js +45 -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 +14 -7
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +322 -144
- package/dist/commands/zai-endpoint-detect.js +97 -0
- package/dist/config/legacy.migrations.part-3.js +57 -0
- package/package.json +1 -1
|
@@ -33,6 +33,15 @@ export function upsertAuthProfile(params) {
|
|
|
33
33
|
store.profiles[params.profileId] = params.credential;
|
|
34
34
|
saveAuthProfileStore(store, params.agentDir);
|
|
35
35
|
}
|
|
36
|
+
export async function upsertAuthProfileWithLock(params) {
|
|
37
|
+
return await updateAuthProfileStoreWithLock({
|
|
38
|
+
agentDir: params.agentDir,
|
|
39
|
+
updater: (store) => {
|
|
40
|
+
store.profiles[params.profileId] = params.credential;
|
|
41
|
+
return true;
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
36
45
|
export function listProfilesForProvider(store, provider) {
|
|
37
46
|
const providerKey = normalizeProviderId(provider);
|
|
38
47
|
return Object.entries(store.profiles)
|
|
@@ -4,7 +4,7 @@ export { formatAuthDoctorHint } from "./auth-profiles/doctor.js";
|
|
|
4
4
|
export { resolveApiKeyForProfile } from "./auth-profiles/oauth.js";
|
|
5
5
|
export { resolveAuthProfileOrder } from "./auth-profiles/order.js";
|
|
6
6
|
export { resolveAuthStorePathForDisplay } from "./auth-profiles/paths.js";
|
|
7
|
-
export { listProfilesForProvider, markAuthProfileGood, setAuthProfileOrder, upsertAuthProfile, } from "./auth-profiles/profiles.js";
|
|
7
|
+
export { listProfilesForProvider, markAuthProfileGood, setAuthProfileOrder, upsertAuthProfile, upsertAuthProfileWithLock, } from "./auth-profiles/profiles.js";
|
|
8
8
|
export { repairOAuthProfileIdMismatch, suggestOAuthProfileIdForLegacyDefault, } from "./auth-profiles/repair.js";
|
|
9
9
|
export { ensureAuthProfileStore, loadAuthProfileStore, saveAuthProfileStore, } from "./auth-profiles/store.js";
|
|
10
10
|
export { calculateAuthProfileCooldownMs, clearAuthProfileCooldown, isProfileInCooldown, markAuthProfileCooldown, markAuthProfileFailure, markAuthProfileUsed, resolveProfileUnusableUntilForDisplay, } from "./auth-profiles/usage.js";
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/** Hugging Face Inference Providers (router) — OpenAI-compatible chat completions. */
|
|
2
|
+
export const HUGGINGFACE_BASE_URL = "https://router.huggingface.co/v1";
|
|
3
|
+
/** Router policy suffixes: router picks backend by cost or speed; no specific provider selection. */
|
|
4
|
+
export const HUGGINGFACE_POLICY_SUFFIXES = ["cheapest", "fastest"];
|
|
5
|
+
/**
|
|
6
|
+
* True when the model ref uses :cheapest or :fastest. When true, provider choice is locked
|
|
7
|
+
* (router decides); do not show an interactive "prefer specific backend" option.
|
|
8
|
+
*/
|
|
9
|
+
export function isHuggingfacePolicyLocked(modelRef) {
|
|
10
|
+
const ref = String(modelRef).trim();
|
|
11
|
+
return HUGGINGFACE_POLICY_SUFFIXES.some((s) => ref.endsWith(`:${s}`) || ref === s);
|
|
12
|
+
}
|
|
13
|
+
/** Default cost when not in static catalog (HF pricing varies by provider). */
|
|
14
|
+
const HUGGINGFACE_DEFAULT_COST = {
|
|
15
|
+
input: 0,
|
|
16
|
+
output: 0,
|
|
17
|
+
cacheRead: 0,
|
|
18
|
+
cacheWrite: 0,
|
|
19
|
+
};
|
|
20
|
+
/** Defaults for models discovered from GET /v1/models. */
|
|
21
|
+
const HUGGINGFACE_DEFAULT_CONTEXT_WINDOW = 131072;
|
|
22
|
+
const HUGGINGFACE_DEFAULT_MAX_TOKENS = 8192;
|
|
23
|
+
export const HUGGINGFACE_MODEL_CATALOG = [
|
|
24
|
+
{
|
|
25
|
+
id: "deepseek-ai/DeepSeek-R1",
|
|
26
|
+
name: "DeepSeek R1",
|
|
27
|
+
reasoning: true,
|
|
28
|
+
input: ["text"],
|
|
29
|
+
contextWindow: 131072,
|
|
30
|
+
maxTokens: 8192,
|
|
31
|
+
cost: { input: 3.0, output: 7.0, cacheRead: 3.0, cacheWrite: 3.0 },
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "deepseek-ai/DeepSeek-V3.1",
|
|
35
|
+
name: "DeepSeek V3.1",
|
|
36
|
+
reasoning: false,
|
|
37
|
+
input: ["text"],
|
|
38
|
+
contextWindow: 131072,
|
|
39
|
+
maxTokens: 8192,
|
|
40
|
+
cost: { input: 0.6, output: 1.25, cacheRead: 0.6, cacheWrite: 0.6 },
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "meta-llama/Llama-3.3-70B-Instruct-Turbo",
|
|
44
|
+
name: "Llama 3.3 70B Instruct Turbo",
|
|
45
|
+
reasoning: false,
|
|
46
|
+
input: ["text"],
|
|
47
|
+
contextWindow: 131072,
|
|
48
|
+
maxTokens: 8192,
|
|
49
|
+
cost: { input: 0.88, output: 0.88, cacheRead: 0.88, cacheWrite: 0.88 },
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "openai/gpt-oss-120b",
|
|
53
|
+
name: "GPT-OSS 120B",
|
|
54
|
+
reasoning: false,
|
|
55
|
+
input: ["text"],
|
|
56
|
+
contextWindow: 131072,
|
|
57
|
+
maxTokens: 8192,
|
|
58
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
export function buildHuggingfaceModelDefinition(model) {
|
|
62
|
+
return {
|
|
63
|
+
id: model.id,
|
|
64
|
+
name: model.name,
|
|
65
|
+
reasoning: model.reasoning,
|
|
66
|
+
input: model.input,
|
|
67
|
+
cost: model.cost,
|
|
68
|
+
contextWindow: model.contextWindow,
|
|
69
|
+
maxTokens: model.maxTokens,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Infer reasoning and display name from Hub-style model id (e.g. "deepseek-ai/DeepSeek-R1").
|
|
74
|
+
*/
|
|
75
|
+
function inferredMetaFromModelId(id) {
|
|
76
|
+
const base = id.split("/").pop() ?? id;
|
|
77
|
+
const reasoning = /r1|reasoning|thinking|reason/i.test(id) || /-\d+[tb]?-thinking/i.test(base);
|
|
78
|
+
const name = base.replace(/-/g, " ").replace(/\b(\w)/g, (c) => c.toUpperCase());
|
|
79
|
+
return { name, reasoning };
|
|
80
|
+
}
|
|
81
|
+
/** Prefer API-supplied display name, then owned_by/id, then inferred from id. */
|
|
82
|
+
function displayNameFromApiEntry(entry, inferredName) {
|
|
83
|
+
const fromApi = (typeof entry.name === "string" && entry.name.trim()) ||
|
|
84
|
+
(typeof entry.title === "string" && entry.title.trim()) ||
|
|
85
|
+
(typeof entry.display_name === "string" && entry.display_name.trim());
|
|
86
|
+
if (fromApi) {
|
|
87
|
+
return fromApi;
|
|
88
|
+
}
|
|
89
|
+
if (typeof entry.owned_by === "string" && entry.owned_by.trim()) {
|
|
90
|
+
const base = entry.id.split("/").pop() ?? entry.id;
|
|
91
|
+
return `${entry.owned_by.trim()}/${base}`;
|
|
92
|
+
}
|
|
93
|
+
return inferredName;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Discover chat-completion models from Hugging Face Inference Providers (GET /v1/models).
|
|
97
|
+
* Requires a valid HF token. Falls back to static catalog on failure or in test env.
|
|
98
|
+
*/
|
|
99
|
+
export async function discoverHuggingfaceModels(apiKey) {
|
|
100
|
+
if (process.env.VITEST === "true" || process.env.NODE_ENV === "test") {
|
|
101
|
+
return HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
|
|
102
|
+
}
|
|
103
|
+
const trimmedKey = apiKey?.trim();
|
|
104
|
+
if (!trimmedKey) {
|
|
105
|
+
return HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
// GET https://router.huggingface.co/v1/models — response: { object, data: [{ id, owned_by, architecture: { input_modalities }, providers: [{ provider, context_length?, pricing? }] }] }. POST /v1/chat/completions requires Authorization.
|
|
109
|
+
const response = await fetch(`${HUGGINGFACE_BASE_URL}/models`, {
|
|
110
|
+
signal: AbortSignal.timeout(10_000),
|
|
111
|
+
headers: {
|
|
112
|
+
Authorization: `Bearer ${trimmedKey}`,
|
|
113
|
+
"Content-Type": "application/json",
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
console.warn(`[huggingface-models] GET /v1/models failed: HTTP ${response.status}, using static catalog`);
|
|
118
|
+
return HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
|
|
119
|
+
}
|
|
120
|
+
const body = (await response.json());
|
|
121
|
+
const data = body?.data;
|
|
122
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
123
|
+
console.warn("[huggingface-models] No models in response, using static catalog");
|
|
124
|
+
return HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
|
|
125
|
+
}
|
|
126
|
+
const catalogById = new Map(HUGGINGFACE_MODEL_CATALOG.map((m) => [m.id, m]));
|
|
127
|
+
const seen = new Set();
|
|
128
|
+
const models = [];
|
|
129
|
+
for (const entry of data) {
|
|
130
|
+
const id = typeof entry?.id === "string" ? entry.id.trim() : "";
|
|
131
|
+
if (!id || seen.has(id)) {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
seen.add(id);
|
|
135
|
+
const catalogEntry = catalogById.get(id);
|
|
136
|
+
if (catalogEntry) {
|
|
137
|
+
models.push(buildHuggingfaceModelDefinition(catalogEntry));
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
const inferred = inferredMetaFromModelId(id);
|
|
141
|
+
const name = displayNameFromApiEntry(entry, inferred.name);
|
|
142
|
+
const modalities = entry.architecture?.input_modalities;
|
|
143
|
+
const input = Array.isArray(modalities) && modalities.includes("image") ? ["text", "image"] : ["text"];
|
|
144
|
+
const providers = Array.isArray(entry.providers) ? entry.providers : [];
|
|
145
|
+
const providerWithContext = providers.find((p) => typeof p?.context_length === "number" && p.context_length > 0);
|
|
146
|
+
const contextLength = providerWithContext?.context_length ?? HUGGINGFACE_DEFAULT_CONTEXT_WINDOW;
|
|
147
|
+
models.push({
|
|
148
|
+
id,
|
|
149
|
+
name,
|
|
150
|
+
reasoning: inferred.reasoning,
|
|
151
|
+
input,
|
|
152
|
+
cost: HUGGINGFACE_DEFAULT_COST,
|
|
153
|
+
contextWindow: contextLength,
|
|
154
|
+
maxTokens: HUGGINGFACE_DEFAULT_MAX_TOKENS,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return models.length > 0
|
|
159
|
+
? models
|
|
160
|
+
: HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
console.warn(`[huggingface-models] Discovery failed: ${String(error)}, using static catalog`);
|
|
164
|
+
return HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -205,6 +205,9 @@ export function resolveEnvApiKey(provider) {
|
|
|
205
205
|
if (normalized === "kimi-coding") {
|
|
206
206
|
return pick("KIMI_API_KEY") ?? pick("KIMICODE_API_KEY");
|
|
207
207
|
}
|
|
208
|
+
if (normalized === "huggingface") {
|
|
209
|
+
return pick("HUGGINGFACE_HUB_TOKEN") ?? pick("HF_TOKEN");
|
|
210
|
+
}
|
|
208
211
|
const envMap = {
|
|
209
212
|
openai: "OPENAI_API_KEY",
|
|
210
213
|
google: "GEMINI_API_KEY",
|
|
@@ -214,6 +217,7 @@ export function resolveEnvApiKey(provider) {
|
|
|
214
217
|
cerebras: "CEREBRAS_API_KEY",
|
|
215
218
|
xai: "XAI_API_KEY",
|
|
216
219
|
openrouter: "OPENROUTER_API_KEY",
|
|
220
|
+
litellm: "LITELLM_API_KEY",
|
|
217
221
|
"vercel-ai-gateway": "AI_GATEWAY_API_KEY",
|
|
218
222
|
"cloudflare-ai-gateway": "CLOUDFLARE_AI_GATEWAY_API_KEY",
|
|
219
223
|
moonshot: "MOONSHOT_API_KEY",
|
|
@@ -227,6 +231,7 @@ export function resolveEnvApiKey(provider) {
|
|
|
227
231
|
qianfan: "QIANFAN_API_KEY",
|
|
228
232
|
nvidia: "NVIDIA_API_KEY",
|
|
229
233
|
ollama: "OLLAMA_API_KEY",
|
|
234
|
+
vllm: "VLLM_API_KEY",
|
|
230
235
|
};
|
|
231
236
|
const envVar = envMap[normalized];
|
|
232
237
|
if (!envVar)
|
package/dist/build-info.json
CHANGED
package/dist/cli/config-cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import JSON5 from "json5";
|
|
2
|
-
import { readConfigFileSnapshot, writeConfigFile } from "../config/config.js";
|
|
2
|
+
import { readConfigFileSnapshot, validateConfigObjectWithPlugins, writeConfigFile, } from "../config/config.js";
|
|
3
3
|
import { danger, info } from "../globals.js";
|
|
4
4
|
import { defaultRuntime } from "../runtime.js";
|
|
5
5
|
import { formatDocsLink } from "../terminal/links.js";
|
|
@@ -259,7 +259,14 @@ export function registerConfigCli(program) {
|
|
|
259
259
|
const snapshot = await loadValidConfig();
|
|
260
260
|
const next = snapshot.config;
|
|
261
261
|
setAtPath(next, parsedPath, parsedValue);
|
|
262
|
-
|
|
262
|
+
const validated = validateConfigObjectWithPlugins(next);
|
|
263
|
+
if (!validated.ok) {
|
|
264
|
+
const issue = validated.issues[0];
|
|
265
|
+
defaultRuntime.error(danger(`Config invalid after set: ${issue.path}: ${issue.message}`));
|
|
266
|
+
defaultRuntime.exit(1);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
await writeConfigFile(validated.config);
|
|
263
270
|
defaultRuntime.log(info(`Updated ${path}. Restart the gateway to apply.`));
|
|
264
271
|
}
|
|
265
272
|
catch (err) {
|
|
@@ -284,7 +291,14 @@ export function registerConfigCli(program) {
|
|
|
284
291
|
defaultRuntime.exit(1);
|
|
285
292
|
return;
|
|
286
293
|
}
|
|
287
|
-
|
|
294
|
+
const validated = validateConfigObjectWithPlugins(next);
|
|
295
|
+
if (!validated.ok) {
|
|
296
|
+
const issue = validated.issues[0];
|
|
297
|
+
defaultRuntime.error(danger(`Config invalid after unset: ${issue.path}: ${issue.message}`));
|
|
298
|
+
defaultRuntime.exit(1);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
await writeConfigFile(validated.config);
|
|
288
302
|
defaultRuntime.log(info(`Removed ${path}. Restart the gateway to apply.`));
|
|
289
303
|
}
|
|
290
304
|
catch (err) {
|
|
@@ -4,15 +4,18 @@ import { formatDocsLink } from "../../terminal/links.js";
|
|
|
4
4
|
import { theme } from "../../terminal/theme.js";
|
|
5
5
|
import { runCommandWithRuntime } from "../cli-utils.js";
|
|
6
6
|
function resolveInstallDaemonFlag(command, opts) {
|
|
7
|
-
if (!command || typeof command !== "object")
|
|
7
|
+
if (!command || typeof command !== "object") {
|
|
8
8
|
return undefined;
|
|
9
|
+
}
|
|
9
10
|
const getOptionValueSource = "getOptionValueSource" in command ? command.getOptionValueSource : undefined;
|
|
10
|
-
if (typeof getOptionValueSource !== "function")
|
|
11
|
+
if (typeof getOptionValueSource !== "function") {
|
|
11
12
|
return undefined;
|
|
13
|
+
}
|
|
12
14
|
// Commander doesn't support option conflicts natively; keep original behavior.
|
|
13
15
|
// If --skip-daemon is explicitly passed, it wins.
|
|
14
|
-
if (getOptionValueSource.call(command, "skipDaemon") === "cli")
|
|
16
|
+
if (getOptionValueSource.call(command, "skipDaemon") === "cli") {
|
|
15
17
|
return false;
|
|
18
|
+
}
|
|
16
19
|
if (getOptionValueSource.call(command, "installDaemon") === "cli") {
|
|
17
20
|
return Boolean(opts.installDaemon);
|
|
18
21
|
}
|
|
@@ -29,7 +32,7 @@ export function registerOnboardCommand(program) {
|
|
|
29
32
|
.option("--accept-risk", "Acknowledge that agents are powerful and full system access is risky (required for --non-interactive)", false)
|
|
30
33
|
.option("--flow <flow>", "Wizard flow: quickstart|advanced|manual")
|
|
31
34
|
.option("--mode <mode>", "Wizard mode: local|remote")
|
|
32
|
-
.option("--auth-choice <choice>", "Auth: setup-token|token|chutes|openai-codex|openai-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|kimi-code-api-key|synthetic-api-key|venice-api-key|gemini-api-key|zai-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip")
|
|
35
|
+
.option("--auth-choice <choice>", "Auth: setup-token|token|chutes|vllm|openai-codex|openai-api-key|xai-api-key|qianfan-api-key|openrouter-api-key|litellm-api-key|ai-gateway-api-key|cloudflare-ai-gateway-api-key|moonshot-api-key|moonshot-api-key-cn|kimi-code-api-key|synthetic-api-key|venice-api-key|gemini-api-key|zai-api-key|zai-coding-global|zai-coding-cn|zai-global|zai-cn|xiaomi-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|custom-api-key|skip|together-api-key|huggingface-api-key|nvidia-api-key")
|
|
33
36
|
.option("--token-provider <id>", "Token provider id (non-interactive; used with --auth-choice token)")
|
|
34
37
|
.option("--token <token>", "Token value (non-interactive; used with --auth-choice token)")
|
|
35
38
|
.option("--token-profile-id <id>", "Auth profile id (non-interactive; default: <provider>:manual)")
|
|
@@ -38,19 +41,29 @@ export function registerOnboardCommand(program) {
|
|
|
38
41
|
.option("--openai-api-key <key>", "OpenAI API key")
|
|
39
42
|
.option("--openrouter-api-key <key>", "OpenRouter API key")
|
|
40
43
|
.option("--ai-gateway-api-key <key>", "Vercel AI Gateway API key")
|
|
44
|
+
.option("--cloudflare-ai-gateway-account-id <id>", "Cloudflare Account ID")
|
|
45
|
+
.option("--cloudflare-ai-gateway-gateway-id <id>", "Cloudflare AI Gateway ID")
|
|
46
|
+
.option("--cloudflare-ai-gateway-api-key <key>", "Cloudflare AI Gateway API key")
|
|
41
47
|
.option("--moonshot-api-key <key>", "Moonshot API key")
|
|
42
|
-
.option("--kimi-code-api-key <key>", "Kimi
|
|
48
|
+
.option("--kimi-code-api-key <key>", "Kimi Coding API key")
|
|
43
49
|
.option("--gemini-api-key <key>", "Gemini API key")
|
|
44
50
|
.option("--zai-api-key <key>", "Z.AI API key")
|
|
51
|
+
.option("--xiaomi-api-key <key>", "Xiaomi API key")
|
|
45
52
|
.option("--minimax-api-key <key>", "MiniMax API key")
|
|
46
53
|
.option("--synthetic-api-key <key>", "Synthetic API key")
|
|
47
54
|
.option("--venice-api-key <key>", "Venice API key")
|
|
55
|
+
.option("--together-api-key <key>", "Together AI API key")
|
|
56
|
+
.option("--huggingface-api-key <key>", "Hugging Face API key (HF token)")
|
|
48
57
|
.option("--opencode-zen-api-key <key>", "OpenCode Zen API key")
|
|
49
58
|
.option("--xai-api-key <key>", "xAI API key")
|
|
50
|
-
.option("--together-api-key <key>", "Together AI API key")
|
|
51
|
-
.option("--qianfan-api-key <key>", "Qianfan API key")
|
|
52
|
-
.option("--xiaomi-api-key <key>", "Xiaomi API key")
|
|
53
59
|
.option("--nvidia-api-key <key>", "NVIDIA API key")
|
|
60
|
+
.option("--litellm-api-key <key>", "LiteLLM API key")
|
|
61
|
+
.option("--qianfan-api-key <key>", "QIANFAN API key")
|
|
62
|
+
.option("--custom-base-url <url>", "Custom provider base URL")
|
|
63
|
+
.option("--custom-api-key <key>", "Custom provider API key (optional)")
|
|
64
|
+
.option("--custom-model-id <id>", "Custom provider model ID")
|
|
65
|
+
.option("--custom-provider-id <id>", "Custom provider ID (optional; auto-derived by default)")
|
|
66
|
+
.option("--custom-compatibility <mode>", "Custom provider API compatibility: openai|anthropic (default: openai)")
|
|
54
67
|
.option("--gateway-port <port>", "Gateway port")
|
|
55
68
|
.option("--gateway-bind <mode>", "Gateway bind: loopback|tailnet|lan|auto|custom")
|
|
56
69
|
.option("--gateway-auth <mode>", "Gateway auth: token|password")
|
|
@@ -91,19 +104,29 @@ export function registerOnboardCommand(program) {
|
|
|
91
104
|
openaiApiKey: opts.openaiApiKey,
|
|
92
105
|
openrouterApiKey: opts.openrouterApiKey,
|
|
93
106
|
aiGatewayApiKey: opts.aiGatewayApiKey,
|
|
107
|
+
cloudflareAiGatewayAccountId: opts.cloudflareAiGatewayAccountId,
|
|
108
|
+
cloudflareAiGatewayGatewayId: opts.cloudflareAiGatewayGatewayId,
|
|
109
|
+
cloudflareAiGatewayApiKey: opts.cloudflareAiGatewayApiKey,
|
|
94
110
|
moonshotApiKey: opts.moonshotApiKey,
|
|
95
111
|
kimiCodeApiKey: opts.kimiCodeApiKey,
|
|
96
112
|
geminiApiKey: opts.geminiApiKey,
|
|
97
113
|
zaiApiKey: opts.zaiApiKey,
|
|
114
|
+
xiaomiApiKey: opts.xiaomiApiKey,
|
|
115
|
+
qianfanApiKey: opts.qianfanApiKey,
|
|
98
116
|
minimaxApiKey: opts.minimaxApiKey,
|
|
99
117
|
syntheticApiKey: opts.syntheticApiKey,
|
|
100
118
|
veniceApiKey: opts.veniceApiKey,
|
|
119
|
+
togetherApiKey: opts.togetherApiKey,
|
|
120
|
+
huggingfaceApiKey: opts.huggingfaceApiKey,
|
|
101
121
|
opencodeZenApiKey: opts.opencodeZenApiKey,
|
|
102
122
|
xaiApiKey: opts.xaiApiKey,
|
|
103
|
-
togetherApiKey: opts.togetherApiKey,
|
|
104
|
-
qianfanApiKey: opts.qianfanApiKey,
|
|
105
|
-
xiaomiApiKey: opts.xiaomiApiKey,
|
|
106
123
|
nvidiaApiKey: opts.nvidiaApiKey,
|
|
124
|
+
litellmApiKey: opts.litellmApiKey,
|
|
125
|
+
customBaseUrl: opts.customBaseUrl,
|
|
126
|
+
customApiKey: opts.customApiKey,
|
|
127
|
+
customModelId: opts.customModelId,
|
|
128
|
+
customProviderId: opts.customProviderId,
|
|
129
|
+
customCompatibility: opts.customCompatibility,
|
|
107
130
|
gatewayPort: typeof gatewayPort === "number" && Number.isFinite(gatewayPort)
|
|
108
131
|
? gatewayPort
|
|
109
132
|
: undefined,
|
|
@@ -11,10 +11,16 @@ const AUTH_CHOICE_GROUP_DEFS = [
|
|
|
11
11
|
hint: "setup-token + API key",
|
|
12
12
|
choices: ["token", "apiKey"],
|
|
13
13
|
},
|
|
14
|
+
{
|
|
15
|
+
value: "vllm",
|
|
16
|
+
label: "vLLM",
|
|
17
|
+
hint: "Local/self-hosted OpenAI-compatible",
|
|
18
|
+
choices: ["vllm"],
|
|
19
|
+
},
|
|
14
20
|
{
|
|
15
21
|
value: "minimax",
|
|
16
22
|
label: "MiniMax",
|
|
17
|
-
hint: "M2.
|
|
23
|
+
hint: "M2.5 (recommended)",
|
|
18
24
|
choices: ["minimax-portal", "minimax-api", "minimax-api-lightning"],
|
|
19
25
|
},
|
|
20
26
|
{
|
|
@@ -55,9 +61,9 @@ const AUTH_CHOICE_GROUP_DEFS = [
|
|
|
55
61
|
},
|
|
56
62
|
{
|
|
57
63
|
value: "zai",
|
|
58
|
-
label: "Z.AI
|
|
59
|
-
hint: "
|
|
60
|
-
choices: ["zai-
|
|
64
|
+
label: "Z.AI",
|
|
65
|
+
hint: "GLM Coding Plan / Global / CN",
|
|
66
|
+
choices: ["zai-coding-global", "zai-coding-cn", "zai-global", "zai-cn"],
|
|
61
67
|
},
|
|
62
68
|
{
|
|
63
69
|
value: "qianfan",
|
|
@@ -101,12 +107,24 @@ const AUTH_CHOICE_GROUP_DEFS = [
|
|
|
101
107
|
hint: "API key",
|
|
102
108
|
choices: ["together-api-key"],
|
|
103
109
|
},
|
|
110
|
+
{
|
|
111
|
+
value: "huggingface",
|
|
112
|
+
label: "Hugging Face",
|
|
113
|
+
hint: "Inference API (HF token)",
|
|
114
|
+
choices: ["huggingface-api-key"],
|
|
115
|
+
},
|
|
104
116
|
{
|
|
105
117
|
value: "venice",
|
|
106
118
|
label: "Venice AI",
|
|
107
119
|
hint: "Privacy-focused (uncensored models)",
|
|
108
120
|
choices: ["venice-api-key"],
|
|
109
121
|
},
|
|
122
|
+
{
|
|
123
|
+
value: "litellm",
|
|
124
|
+
label: "LiteLLM",
|
|
125
|
+
hint: "Unified LLM gateway (100+ providers)",
|
|
126
|
+
choices: ["litellm-api-key"],
|
|
127
|
+
},
|
|
110
128
|
{
|
|
111
129
|
value: "cloudflare-ai-gateway",
|
|
112
130
|
label: "Cloudflare AI Gateway",
|
|
@@ -133,6 +151,11 @@ export function buildAuthChoiceOptions(params) {
|
|
|
133
151
|
label: "OpenAI Codex (ChatGPT OAuth)",
|
|
134
152
|
});
|
|
135
153
|
options.push({ value: "chutes", label: "Chutes (OAuth)" });
|
|
154
|
+
options.push({
|
|
155
|
+
value: "vllm",
|
|
156
|
+
label: "vLLM (custom URL + model)",
|
|
157
|
+
hint: "Local/self-hosted OpenAI-compatible server",
|
|
158
|
+
});
|
|
136
159
|
options.push({ value: "openai-api-key", label: "OpenAI API key" });
|
|
137
160
|
options.push({ value: "xai-api-key", label: "xAI (Grok) API key" });
|
|
138
161
|
options.push({
|
|
@@ -145,6 +168,11 @@ export function buildAuthChoiceOptions(params) {
|
|
|
145
168
|
label: "Qianfan API key",
|
|
146
169
|
});
|
|
147
170
|
options.push({ value: "openrouter-api-key", label: "OpenRouter API key" });
|
|
171
|
+
options.push({
|
|
172
|
+
value: "litellm-api-key",
|
|
173
|
+
label: "LiteLLM API key",
|
|
174
|
+
hint: "Unified gateway for 100+ LLM providers",
|
|
175
|
+
});
|
|
148
176
|
options.push({
|
|
149
177
|
value: "ai-gateway-api-key",
|
|
150
178
|
label: "Vercel AI Gateway API key",
|
|
@@ -177,6 +205,11 @@ export function buildAuthChoiceOptions(params) {
|
|
|
177
205
|
label: "Together AI API key",
|
|
178
206
|
hint: "Access to Llama, DeepSeek, Qwen, and more open models",
|
|
179
207
|
});
|
|
208
|
+
options.push({
|
|
209
|
+
value: "huggingface-api-key",
|
|
210
|
+
label: "Hugging Face API key (HF token)",
|
|
211
|
+
hint: "Inference Providers — OpenAI-compatible chat",
|
|
212
|
+
});
|
|
180
213
|
options.push({
|
|
181
214
|
value: "github-copilot",
|
|
182
215
|
label: "GitHub Copilot (GitHub device login)",
|
|
@@ -193,7 +226,27 @@ export function buildAuthChoiceOptions(params) {
|
|
|
193
226
|
label: "Google Gemini CLI OAuth",
|
|
194
227
|
hint: "Uses the bundled Gemini CLI auth plugin",
|
|
195
228
|
});
|
|
196
|
-
options.push({ value: "zai-api-key", label: "Z.AI
|
|
229
|
+
options.push({ value: "zai-api-key", label: "Z.AI API key" });
|
|
230
|
+
options.push({
|
|
231
|
+
value: "zai-coding-global",
|
|
232
|
+
label: "Coding-Plan-Global",
|
|
233
|
+
hint: "GLM Coding Plan Global (api.z.ai)",
|
|
234
|
+
});
|
|
235
|
+
options.push({
|
|
236
|
+
value: "zai-coding-cn",
|
|
237
|
+
label: "Coding-Plan-CN",
|
|
238
|
+
hint: "GLM Coding Plan CN (open.bigmodel.cn)",
|
|
239
|
+
});
|
|
240
|
+
options.push({
|
|
241
|
+
value: "zai-global",
|
|
242
|
+
label: "Global",
|
|
243
|
+
hint: "Z.AI Global (api.z.ai)",
|
|
244
|
+
});
|
|
245
|
+
options.push({
|
|
246
|
+
value: "zai-cn",
|
|
247
|
+
label: "CN",
|
|
248
|
+
hint: "Z.AI CN (open.bigmodel.cn)",
|
|
249
|
+
});
|
|
197
250
|
options.push({
|
|
198
251
|
value: "xiaomi-api-key",
|
|
199
252
|
label: "Xiaomi API key",
|
|
@@ -216,10 +269,10 @@ export function buildAuthChoiceOptions(params) {
|
|
|
216
269
|
label: "OpenCode Zen (multi-model proxy)",
|
|
217
270
|
hint: "Claude, GPT, Gemini via opencode.ai/zen",
|
|
218
271
|
});
|
|
219
|
-
options.push({ value: "minimax-api", label: "MiniMax M2.
|
|
272
|
+
options.push({ value: "minimax-api", label: "MiniMax M2.5" });
|
|
220
273
|
options.push({
|
|
221
274
|
value: "minimax-api-lightning",
|
|
222
|
-
label: "MiniMax M2.
|
|
275
|
+
label: "MiniMax M2.5 Lightning",
|
|
223
276
|
hint: "Faster, higher output cost",
|
|
224
277
|
});
|
|
225
278
|
options.push({ value: "custom-api-key", label: "Custom Provider" });
|