Add nano-gpt.com as a provider

This commit is contained in:
0xGingi 2026-01-25 12:55:26 -05:00
parent c8063bdcd8
commit 45b353d39a
No known key found for this signature in database
21 changed files with 535 additions and 2 deletions

View File

@ -297,7 +297,7 @@ Options:
- `--non-interactive`
- `--mode <local|remote>`
- `--flow <quickstart|advanced|manual>` (manual is an alias for advanced)
- `--auth-choice <setup-token|claude-cli|token|openai-codex|openai-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|kimi-code-api-key|codex-cli|gemini-api-key|zai-api-key|apiKey|minimax-api|opencode-zen|skip>`
- `--auth-choice <setup-token|claude-cli|token|openai-codex|openai-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|kimi-code-api-key|nanogpt-api-key|codex-cli|gemini-api-key|zai-api-key|apiKey|minimax-api|opencode-zen|skip>`
- `--token-provider <id>` (non-interactive; used with `--auth-choice token`)
- `--token <token>` (non-interactive; used with `--auth-choice token`)
- `--token-profile-id <id>` (non-interactive; default: `<provider>:manual`)
@ -308,6 +308,7 @@ Options:
- `--ai-gateway-api-key <key>`
- `--moonshot-api-key <key>`
- `--kimi-code-api-key <key>`
- `--nanogpt-api-key <key>`
- `--gemini-api-key <key>`
- `--zai-api-key <key>`
- `--minimax-api-key <key>`

View File

@ -157,6 +157,34 @@ Moonshot uses OpenAI-compatible endpoints, so configure it as a custom provider:
}
```
### NanoGPT
NanoGPT exposes OpenAI-compatible endpoints:
- Provider: `nanogpt`
- Auth: `NANOGPT_API_KEY`
- Example model: `nanogpt/zai-org/glm-4.7`
- CLI: `clawdbot onboard --auth-choice nanogpt-api-key`
```json5
{
agents: {
defaults: { model: { primary: "nanogpt/zai-org/glm-4.7" } }
},
models: {
mode: "merge",
providers: {
nanogpt: {
baseUrl: "https://nano-gpt.com/api/v1",
apiKey: "${NANOGPT_API_KEY}",
api: "openai-completions",
models: [{ id: "zai-org/glm-4.7", name: "GLM 4.7" }]
}
}
}
}
```
### Kimi Code
Kimi Code uses a dedicated endpoint and key (separate from Moonshot):

View File

@ -36,6 +36,7 @@ See [Venice AI](/providers/venice).
- [OpenAI (API + Codex)](/providers/openai)
- [Anthropic (API + Claude Code CLI)](/providers/anthropic)
- [Qwen (OAuth)](/providers/qwen)
- [NanoGPT](/providers/nanogpt)
- [OpenRouter](/providers/openrouter)
- [Vercel AI Gateway](/providers/vercel-ai-gateway)
- [Moonshot AI (Kimi + Kimi Code)](/providers/moonshot)

View File

@ -33,6 +33,7 @@ See [Venice AI](/providers/venice).
- [OpenAI (API + Codex)](/providers/openai)
- [Anthropic (API + Claude Code CLI)](/providers/anthropic)
- [NanoGPT](/providers/nanogpt)
- [OpenRouter](/providers/openrouter)
- [Vercel AI Gateway](/providers/vercel-ai-gateway)
- [Moonshot AI (Kimi + Kimi Code)](/providers/moonshot)

66
docs/providers/nanogpt.md Normal file
View File

@ -0,0 +1,66 @@
---
summary: "Use NanoGPT's OpenAI-compatible API in Clawdbot"
read_when:
- You want to use NanoGPT as a model provider
- You need a NanoGPT API key or base URL setup
---
# NanoGPT
NanoGPT exposes OpenAI-compatible endpoints. Clawdbot registers it as the
`nanogpt` provider.
## Quick setup
1) Set `NANOGPT_API_KEY` (or run the wizard below).
2) Run onboarding:
```bash
clawdbot onboard --auth-choice nanogpt-api-key
```
The default model is set to:
```
nanogpt/zai-org/glm-4.7
```
## Config example
```json5
{
env: { NANOGPT_API_KEY: "sk-..." },
agents: {
defaults: {
model: { primary: "nanogpt/zai-org/glm-4.7" },
models: { "nanogpt/zai-org/glm-4.7": { alias: "GLM 4.7" } }
}
},
models: {
mode: "merge",
providers: {
nanogpt: {
baseUrl: "https://nano-gpt.com/api/v1",
apiKey: "${NANOGPT_API_KEY}",
api: "openai-completions",
models: [
{
id: "zai-org/glm-4.7",
name: "GLM 4.7",
reasoning: true,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 200000,
maxTokens: 65535
}
]
}
}
}
}
```
## Notes
- Model refs use `nanogpt/<modelId>`.
- If you enable a model allowlist (`agents.defaults.models`), add every model you plan to use.
- For the full provider catalog and configuration rules, see [Model providers](/concepts/model-providers).

View File

@ -248,6 +248,17 @@ clawdbot onboard --non-interactive \
--gateway-bind loopback
```
NanoGPT example:
```bash
clawdbot onboard --non-interactive \
--mode local \
--auth-choice nanogpt-api-key \
--nanogpt-api-key "$NANOGPT_API_KEY" \
--gateway-port 18789 \
--gateway-bind loopback
```
OpenCode Zen example:
```bash

View File

@ -285,6 +285,7 @@ export function resolveEnvApiKey(provider: string): EnvApiKeyResult | null {
venice: "VENICE_API_KEY",
mistral: "MISTRAL_API_KEY",
opencode: "OPENCODE_API_KEY",
nanogpt: "NANOGPT_API_KEY",
};
const envVar = envMap[normalized];
if (!envVar) return null;

View File

@ -29,6 +29,7 @@ export function normalizeProviderId(provider: string): string {
if (normalized === "z.ai" || normalized === "z-ai") return "zai";
if (normalized === "opencode-zen") return "opencode";
if (normalized === "qwen") return "qwen-portal";
if (normalized === "nano-gpt") return "nanogpt";
return normalized;
}

View File

@ -13,6 +13,11 @@ import {
SYNTHETIC_MODEL_CATALOG,
} from "./synthetic-models.js";
import { discoverVeniceModels, VENICE_BASE_URL } from "./venice-models.js";
import {
buildNanoGptModelDefinition,
NANOGPT_BASE_URL,
NANOGPT_MODEL_CATALOG,
} from "./nanogpt-models.js";
type ModelsConfig = NonNullable<ClawdbotConfig["models"]>;
export type ProviderConfig = NonNullable<ModelsConfig["providers"]>[string];
@ -359,6 +364,14 @@ async function buildOllamaProvider(): Promise<ProviderConfig> {
};
}
function buildNanoGptProvider(): ProviderConfig {
return {
baseUrl: NANOGPT_BASE_URL,
api: "openai-completions",
models: NANOGPT_MODEL_CATALOG.map(buildNanoGptModelDefinition),
};
}
export async function resolveImplicitProviders(params: {
agentDir: string;
}): Promise<ModelsConfig["providers"]> {
@ -410,6 +423,13 @@ export async function resolveImplicitProviders(params: {
};
}
const nanogptKey =
resolveEnvApiKeyVarName("nanogpt") ??
resolveApiKeyFromProfiles({ provider: "nanogpt", store: authStore });
if (nanogptKey) {
providers.nanogpt = { ...buildNanoGptProvider(), apiKey: nanogptKey };
}
// Ollama provider - only add if explicitly configured
const ollamaKey =
resolveEnvApiKeyVarName("ollama") ??

View File

@ -0,0 +1,188 @@
import type { ModelDefinitionConfig } from "../config/types.js";
export const NANOGPT_BASE_URL = "https://nano-gpt.com/api/v1";
export const NANOGPT_DEFAULT_MODEL_ID = "zai-org/glm-4.7";
export const NANOGPT_DEFAULT_MODEL_REF = `nanogpt/${NANOGPT_DEFAULT_MODEL_ID}`;
export const NANOGPT_DEFAULT_COST = {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
};
export const NANOGPT_MODEL_CATALOG = [
{
id: NANOGPT_DEFAULT_MODEL_ID,
name: "GLM 4.7",
reasoning: true,
input: ["text"],
contextWindow: 200000,
maxTokens: 65535,
},
{
id: "zai-org/glm-4.7:thinking",
name: "GLM 4.7 Thinking",
reasoning: true,
input: ["text"],
contextWindow: 200000,
maxTokens: 65535,
},
{
id: "zai-org/glm-4.7-original",
name: "GLM 4.7 Original",
reasoning: true,
input: ["text"],
contextWindow: 200000,
maxTokens: 65535,
},
{
id: "zai-org/glm-4.7-original:thinking",
name: "GLM 4.7 Original Thinking",
reasoning: true,
input: ["text"],
contextWindow: 200000,
maxTokens: 65535,
},
{
id: "zai-org/glm-4.7-flash",
name: "GLM 4.7 Flash",
reasoning: true,
input: ["text"],
contextWindow: 200000,
maxTokens: 128000,
},
{
id: "zai-org/glm-4.7-flash:thinking",
name: "GLM 4.7 Flash Thinking",
reasoning: true,
input: ["text"],
contextWindow: 200000,
maxTokens: 128000,
},
{
id: "zai-org/glm-4.7-flash-original",
name: "GLM 4.7 Flash Original",
reasoning: true,
input: ["text"],
contextWindow: 200000,
maxTokens: 128000,
},
{
id: "zai-org/glm-4.7-flash-original:thinking",
name: "GLM 4.7 Flash Original Thinking",
reasoning: true,
input: ["text"],
contextWindow: 200000,
maxTokens: 128000,
},
{
id: "minimax/minimax-m2.1",
name: "MiniMax M2.1",
reasoning: true,
input: ["text"],
contextWindow: 200000,
maxTokens: 131072,
},
{
id: "Qwen/Qwen3-VL-235B-A22B-Instruct",
name: "Qwen3 VL 235B A22B Instruct",
reasoning: false,
input: ["text", "image"],
contextWindow: 128000,
maxTokens: 262144,
},
{
id: "claude-opus-4-5-20251101",
name: "Claude 4.5 Opus",
reasoning: true,
input: ["text", "image"],
contextWindow: 200000,
maxTokens: 32000,
},
{
id: "claude-opus-4-5-20251101:thinking",
name: "Claude 4.5 Opus Thinking",
reasoning: true,
input: ["text", "image"],
contextWindow: 200000,
maxTokens: 32000,
},
{
id: "claude-sonnet-4-5-20250929",
name: "Claude Sonnet 4.5",
reasoning: false,
input: ["text", "image"],
contextWindow: 1000000,
maxTokens: 64000,
},
{
id: "claude-sonnet-4-5-20250929-thinking",
name: "Claude Sonnet 4.5 Thinking",
reasoning: true,
input: ["text", "image"],
contextWindow: 1000000,
maxTokens: 64000,
},
{
id: "claude-haiku-4-5-20251001",
name: "Claude Haiku 4.5",
reasoning: false,
input: ["text", "image"],
contextWindow: 200000,
maxTokens: 64000,
},
{
id: "claude-3-5-haiku-20241022",
name: "Claude 3.5 Haiku",
reasoning: false,
input: ["text", "image"],
contextWindow: 200000,
maxTokens: 8192,
},
{
id: "openai/gpt-5.2-chat",
name: "GPT 5.2 Chat",
reasoning: true,
input: ["text", "image"],
contextWindow: 400000,
maxTokens: 16384,
},
{
id: "openai/gpt-5.2",
name: "GPT 5.2",
reasoning: true,
input: ["text", "image"],
contextWindow: 400000,
maxTokens: 128000,
},
{
id: "openai/gpt-5.2-codex",
name: "GPT 5.2 Codex",
reasoning: true,
input: ["text", "image"],
contextWindow: 400000,
maxTokens: 128000,
},
{
id: "openai/gpt-5.2-pro",
name: "GPT 5.2 Pro",
reasoning: true,
input: ["text", "image"],
contextWindow: 400000,
maxTokens: 128000,
},
] as const;
export type NanoGptCatalogEntry = (typeof NANOGPT_MODEL_CATALOG)[number];
export function buildNanoGptModelDefinition(entry: NanoGptCatalogEntry): ModelDefinitionConfig {
return {
id: entry.id,
name: entry.name,
reasoning: entry.reasoning,
input: [...entry.input],
cost: NANOGPT_DEFAULT_COST,
contextWindow: entry.contextWindow,
maxTokens: entry.maxTokens,
};
}

View File

@ -176,6 +176,12 @@ describe("cli program (smoke)", () => {
key: "sk-synthetic-test",
field: "syntheticApiKey",
},
{
authChoice: "nanogpt-api-key",
flag: "--nanogpt-api-key",
key: "sk-nanogpt-test",
field: "nanogptApiKey",
},
{
authChoice: "zai-api-key",
flag: "--zai-api-key",

View File

@ -52,7 +52,7 @@ export function registerOnboardCommand(program: Command) {
.option("--mode <mode>", "Wizard mode: local|remote")
.option(
"--auth-choice <choice>",
"Auth: setup-token|claude-cli|token|chutes|openai-codex|openai-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|kimi-code-api-key|synthetic-api-key|codex-cli|gemini-api-key|zai-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip",
"Auth: setup-token|claude-cli|token|chutes|openai-codex|openai-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|kimi-code-api-key|synthetic-api-key|nanogpt-api-key|codex-cli|gemini-api-key|zai-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip",
)
.option(
"--token-provider <id>",
@ -74,6 +74,7 @@ export function registerOnboardCommand(program: Command) {
.option("--zai-api-key <key>", "Z.AI API key")
.option("--minimax-api-key <key>", "MiniMax API key")
.option("--synthetic-api-key <key>", "Synthetic API key")
.option("--nanogpt-api-key <key>", "NanoGPT API key")
.option("--opencode-zen-api-key <key>", "OpenCode Zen API key")
.option("--gateway-port <port>", "Gateway port")
.option("--gateway-bind <mode>", "Gateway bind: loopback|tailnet|lan|auto|custom")
@ -123,6 +124,7 @@ export function registerOnboardCommand(program: Command) {
zaiApiKey: opts.zaiApiKey as string | undefined,
minimaxApiKey: opts.minimaxApiKey as string | undefined,
syntheticApiKey: opts.syntheticApiKey as string | undefined,
nanogptApiKey: opts.nanogptApiKey as string | undefined,
opencodeZenApiKey: opts.opencodeZenApiKey as string | undefined,
gatewayPort:
typeof gatewayPort === "number" && Number.isFinite(gatewayPort)

View File

@ -127,6 +127,18 @@ describe("buildAuthChoiceOptions", () => {
expect(options.some((opt) => opt.value === "synthetic-api-key")).toBe(true);
});
it("includes NanoGPT auth choice", () => {
const store: AuthProfileStore = { version: 1, profiles: {} };
const options = buildAuthChoiceOptions({
store,
includeSkip: false,
includeClaudeCliIfMissing: true,
platform: "darwin",
});
expect(options.some((opt) => opt.value === "nanogpt-api-key")).toBe(true);
});
it("includes Chutes OAuth auth choice", () => {
const store: AuthProfileStore = { version: 1, profiles: {} };
const options = buildAuthChoiceOptions({

View File

@ -21,6 +21,7 @@ export type AuthChoiceGroupId =
| "opencode-zen"
| "minimax"
| "synthetic"
| "nanogpt"
| "venice"
| "qwen";
@ -67,6 +68,12 @@ const AUTH_CHOICE_GROUP_DEFS: {
hint: "Anthropic-compatible (multi-model)",
choices: ["synthetic-api-key"],
},
{
value: "nanogpt",
label: "NanoGPT",
hint: "OpenAI-compatible API",
choices: ["nanogpt-api-key"],
},
{
value: "venice",
label: "Venice AI",
@ -202,6 +209,10 @@ export function buildAuthChoiceOptions(params: {
label: "Venice AI API key",
hint: "Privacy-focused inference (uncensored models)",
});
options.push({
value: "nanogpt-api-key",
label: "NanoGPT API key",
});
options.push({
value: "github-copilot",
label: "GitHub Copilot (GitHub device login)",

View File

@ -17,6 +17,8 @@ import {
applyKimiCodeProviderConfig,
applyMoonshotConfig,
applyMoonshotProviderConfig,
applyNanoGptConfig,
applyNanoGptProviderConfig,
applyOpencodeZenConfig,
applyOpencodeZenProviderConfig,
applyOpenrouterConfig,
@ -32,6 +34,7 @@ import {
MOONSHOT_DEFAULT_MODEL_REF,
OPENROUTER_DEFAULT_MODEL_REF,
SYNTHETIC_DEFAULT_MODEL_REF,
NANOGPT_DEFAULT_MODEL_REF,
VENICE_DEFAULT_MODEL_REF,
VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
setGeminiApiKey,
@ -39,6 +42,7 @@ import {
setMoonshotApiKey,
setOpencodeZenApiKey,
setOpenrouterApiKey,
setNanoGptApiKey,
setSyntheticApiKey,
setVeniceApiKey,
setVercelAiGatewayApiKey,
@ -83,6 +87,11 @@ export async function applyAuthChoiceApiProviders(
authChoice = "synthetic-api-key";
} else if (params.opts.tokenProvider === "venice") {
authChoice = "venice-api-key";
} else if (
params.opts.tokenProvider === "nanogpt" ||
params.opts.tokenProvider === "nano-gpt"
) {
authChoice = "nanogpt-api-key";
} else if (params.opts.tokenProvider === "opencode") {
authChoice = "opencode-zen";
}
@ -463,6 +472,59 @@ export async function applyAuthChoiceApiProviders(
return { config: nextConfig, agentModelOverride };
}
if (authChoice === "nanogpt-api-key") {
let hasCredential = false;
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider) {
const provider = params.opts.tokenProvider;
if (provider === "nanogpt" || provider === "nano-gpt") {
await setNanoGptApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir);
hasCredential = true;
}
}
const envKey = resolveEnvApiKey("nanogpt");
if (!hasCredential && envKey) {
const useExisting = await params.prompter.confirm({
message: `Use existing NANOGPT_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`,
initialValue: true,
});
if (useExisting) {
await setNanoGptApiKey(envKey.apiKey, params.agentDir);
hasCredential = true;
}
}
if (!hasCredential) {
const key = await params.prompter.text({
message: "Enter NanoGPT API key",
validate: validateApiKeyInput,
});
await setNanoGptApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
}
nextConfig = applyAuthProfileConfig(nextConfig, {
profileId: "nanogpt:default",
provider: "nanogpt",
mode: "api_key",
});
{
const applied = await applyDefaultModelChoice({
config: nextConfig,
setDefaultModel: params.setDefaultModel,
defaultModel: NANOGPT_DEFAULT_MODEL_REF,
applyDefaultConfig: applyNanoGptConfig,
applyProviderConfig: applyNanoGptProviderConfig,
noteDefault: NANOGPT_DEFAULT_MODEL_REF,
noteAgentModel,
prompter: params.prompter,
});
nextConfig = applied.config;
agentModelOverride = applied.agentModelOverride ?? agentModelOverride;
}
return { config: nextConfig, agentModelOverride };
}
if (authChoice === "venice-api-key") {
let hasCredential = false;

View File

@ -20,6 +20,7 @@ const PREFERRED_PROVIDER_BY_AUTH_CHOICE: Partial<Record<AuthChoice, string>> = {
"zai-api-key": "zai",
"synthetic-api-key": "synthetic",
"venice-api-key": "venice",
"nanogpt-api-key": "nanogpt",
"github-copilot": "github-copilot",
"copilot-proxy": "copilot-proxy",
"minimax-cloud": "minimax",

View File

@ -10,6 +10,12 @@ import {
VENICE_DEFAULT_MODEL_REF,
VENICE_MODEL_CATALOG,
} from "../agents/venice-models.js";
import {
buildNanoGptModelDefinition,
NANOGPT_BASE_URL,
NANOGPT_DEFAULT_MODEL_REF,
NANOGPT_MODEL_CATALOG,
} from "../agents/nanogpt-models.js";
import type { ClawdbotConfig } from "../config/config.js";
import {
OPENROUTER_DEFAULT_MODEL_REF,
@ -336,6 +342,81 @@ export function applySyntheticConfig(cfg: ClawdbotConfig): ClawdbotConfig {
};
}
/**
* Apply NanoGPT provider configuration without changing the default model.
*/
export function applyNanoGptProviderConfig(cfg: ClawdbotConfig): ClawdbotConfig {
const models = { ...cfg.agents?.defaults?.models };
models[NANOGPT_DEFAULT_MODEL_REF] = {
...models[NANOGPT_DEFAULT_MODEL_REF],
alias: models[NANOGPT_DEFAULT_MODEL_REF]?.alias ?? "GLM 4.7",
};
const providers = { ...cfg.models?.providers };
const existingProvider = providers.nanogpt;
const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : [];
const nanogptModels = NANOGPT_MODEL_CATALOG.map(buildNanoGptModelDefinition);
const mergedModels = [
...existingModels,
...nanogptModels.filter(
(model) => !existingModels.some((existing) => existing.id === model.id),
),
];
const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as Record<
string,
unknown
> as { apiKey?: string };
const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined;
const normalizedApiKey = resolvedApiKey?.trim();
providers.nanogpt = {
...existingProviderRest,
baseUrl: NANOGPT_BASE_URL,
api: "openai-completions",
...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}),
models: mergedModels.length > 0 ? mergedModels : nanogptModels,
};
return {
...cfg,
agents: {
...cfg.agents,
defaults: {
...cfg.agents?.defaults,
models,
},
},
models: {
mode: cfg.models?.mode ?? "merge",
providers,
},
};
}
/**
* Apply NanoGPT provider configuration AND set NanoGPT as the default model.
*/
export function applyNanoGptConfig(cfg: ClawdbotConfig): ClawdbotConfig {
const next = applyNanoGptProviderConfig(cfg);
const existingModel = next.agents?.defaults?.model;
return {
...next,
agents: {
...next.agents,
defaults: {
...next.agents?.defaults,
model: {
...(existingModel && "fallbacks" in (existingModel as Record<string, unknown>)
? {
fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks,
}
: undefined),
primary: NANOGPT_DEFAULT_MODEL_REF,
},
},
},
};
}
/**
* Apply Venice provider configuration without changing the default model.
* Registers Venice models and sets up the provider, but preserves existing model selection.

View File

@ -99,6 +99,19 @@ export async function setSyntheticApiKey(key: string, agentDir?: string) {
});
}
export async function setNanoGptApiKey(key: string, agentDir?: string) {
// Write to resolved agent dir so gateway finds credentials on startup.
upsertAuthProfile({
profileId: "nanogpt:default",
credential: {
type: "api_key",
provider: "nanogpt",
key,
},
agentDir: resolveAuthAgentDir(agentDir),
});
}
export async function setVeniceApiKey(key: string, agentDir?: string) {
// Write to resolved agent dir so gateway finds credentials on startup.
upsertAuthProfile({

View File

@ -2,6 +2,7 @@ export {
SYNTHETIC_DEFAULT_MODEL_ID,
SYNTHETIC_DEFAULT_MODEL_REF,
} from "../agents/synthetic-models.js";
export { NANOGPT_DEFAULT_MODEL_ID, NANOGPT_DEFAULT_MODEL_REF } from "../agents/nanogpt-models.js";
export { VENICE_DEFAULT_MODEL_ID, VENICE_DEFAULT_MODEL_REF } from "../agents/venice-models.js";
export {
applyAuthProfileConfig,
@ -11,6 +12,8 @@ export {
applyMoonshotProviderConfig,
applyOpenrouterConfig,
applyOpenrouterProviderConfig,
applyNanoGptConfig,
applyNanoGptProviderConfig,
applySyntheticConfig,
applySyntheticProviderConfig,
applyVeniceConfig,
@ -41,6 +44,7 @@ export {
setMoonshotApiKey,
setOpencodeZenApiKey,
setOpenrouterApiKey,
setNanoGptApiKey,
setSyntheticApiKey,
setVeniceApiKey,
setVercelAiGatewayApiKey,

View File

@ -17,6 +17,7 @@ import {
applyMinimaxApiConfig,
applyMinimaxConfig,
applyMoonshotConfig,
applyNanoGptConfig,
applyOpencodeZenConfig,
applyOpenrouterConfig,
applySyntheticConfig,
@ -27,6 +28,7 @@ import {
setKimiCodeApiKey,
setMinimaxApiKey,
setMoonshotApiKey,
setNanoGptApiKey,
setOpencodeZenApiKey,
setOpenrouterApiKey,
setSyntheticApiKey,
@ -272,6 +274,25 @@ export async function applyNonInteractiveAuthChoice(params: {
return applySyntheticConfig(nextConfig);
}
if (authChoice === "nanogpt-api-key") {
const resolved = await resolveNonInteractiveApiKey({
provider: "nanogpt",
cfg: baseConfig,
flagValue: opts.nanogptApiKey,
flagName: "--nanogpt-api-key",
envVar: "NANOGPT_API_KEY",
runtime,
});
if (!resolved) return null;
if (resolved.source !== "profile") await setNanoGptApiKey(resolved.key);
nextConfig = applyAuthProfileConfig(nextConfig, {
profileId: "nanogpt:default",
provider: "nanogpt",
mode: "api_key",
});
return applyNanoGptConfig(nextConfig);
}
if (
authChoice === "minimax-cloud" ||
authChoice === "minimax-api" ||

View File

@ -16,6 +16,7 @@ export type AuthChoice =
| "moonshot-api-key"
| "kimi-code-api-key"
| "synthetic-api-key"
| "nanogpt-api-key"
| "venice-api-key"
| "codex-cli"
| "apiKey"
@ -69,6 +70,7 @@ export type OnboardOptions = {
zaiApiKey?: string;
minimaxApiKey?: string;
syntheticApiKey?: string;
nanogptApiKey?: string;
veniceApiKey?: string;
opencodeZenApiKey?: string;
gatewayPort?: number;