From 30ac80b96b452b7f3efcfc447335256c256227a7 Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Wed, 4 Feb 2026 16:36:37 +0800 Subject: [PATCH 01/14] Add baidu qianfan model provider --- docs/providers/qianfan.md | 291 ++++++++++++++++++ src/agents/model-auth.ts | 1 + src/agents/models-config.providers.ts | 36 +++ src/cli/program/register.onboard.ts | 4 +- .../auth-choice.apply.api-providers.ts | 62 ++++ .../auth-choice.preferred-provider.ts | 1 + src/commands/onboard-auth.config-core.ts | 87 +++++- src/commands/onboard-auth.credentials.ts | 12 + src/commands/onboard-auth.models.ts | 24 ++ src/commands/onboard-auth.ts | 7 + .../local/auth-choice.ts | 25 ++ src/commands/onboard-types.ts | 2 + 12 files changed, 550 insertions(+), 2 deletions(-) create mode 100644 docs/providers/qianfan.md diff --git a/docs/providers/qianfan.md b/docs/providers/qianfan.md new file mode 100644 index 0000000000..dfb663cf3c --- /dev/null +++ b/docs/providers/qianfan.md @@ -0,0 +1,291 @@ +--- +summary: "Use DeepSeek-V3.2 in OpenClaw" +read_when: + - You want a single API key for many LLMs + - You need Baidu Qianfan setup guidance +title: "Qianfan" +--- + +# Baidu Qianfan Provider Guide + +Qianfan is Baidu's MaaS platform, provides a **unified API** that routes requests to many models behind a single +endpoint and API key. It is OpenAI-compatible, so most OpenAI SDKs work by switching the base URL. + + +## Prerequisites + +1. A Baidu Cloud account with Qianfan API access +2. An API key from the Qianfan console +3. OpenClaw installed on your system + +## Getting Your API Key + +1. Visit the [Qianfan Console](https://console.bce.baidu.com/qianfan/ais/console/apiKey) +2. Create a new application or select an existing one +3. Generate an API key (format: `bce-v3/ALTAK-...`) +4. Copy the API key for use with OpenClaw + +## Installation + +### Install OpenClaw + +```bash +# Using npm +npm install -g openclaw + +# Using pnpm +pnpm add -g openclaw + +# Using bun +bun add -g openclaw +``` + +### Verify Installation + +```bash +openclaw --version +``` + +## Configuration Methods + +### Method 1: Environment Variable (Recommended) + +Set the `QIANFAN_API_KEY` environment variable: + +```bash +# Bash/Zsh +export QIANFAN_API_KEY="bce-v3/ALTAK-your-api-key-here" + +# Fish +set -gx QIANFAN_API_KEY "bce-v3/ALTAK-your-api-key-here" + +# PowerShell +$env:QIANFAN_API_KEY = "bce-v3/ALTAK-your-api-key-here" +``` + +Add to your shell profile (`~/.bashrc`, `~/.zshrc`, etc.) for persistence: + +```bash +echo 'export QIANFAN_API_KEY="bce-v3/ALTAK-your-api-key-here"' >> ~/.bashrc +source ~/.bashrc +``` + +### Method 2: Interactive Onboarding + +Run the onboarding wizard: + +```bash +openclaw onboard --auth-choice qianfan-api-key +``` + +Follow the prompts to enter your API key. + +### Method 3: Non-Interactive Setup + +For CI/CD or scripted setups: + +```bash +openclaw onboard \ + --non-interactive \ + --accept-risk \ + --auth-choice token \ + --token-provider qianfan \ + --token "bce-v3/ALTAK-your-api-key-here" +``` + +### Method 4: Configuration File + +Configure manually via `openclaw.json`: + +```json +{ + "models": { + "providers": { + "qianfan": { + "baseUrl": "https://qianfan.baidubce.com/v2", + "api": "openai-completions", + "apiKey": "bce-v3/ALTAK-your-api-key-here", + "models": [ + { + "id": "deepseek-v3.2", + "name": "DeepSeek-V3.2", + "reasoning": true, + "input": ["text"], + "contextWindow": 98304, + "maxTokens": 32768 + } + ] + } + } + }, + "agents": { + "defaults": { + "model": { + "primary": "qianfan/deepseek-v3.2" + } + } + } +} +``` + +## Usage + +### Start a Chat Session + +```bash +# Using default QIANFAN model +openclaw chat + +# Explicitly specify QIANFAN model +openclaw chat --model qianfan/deepseek-v3.2 +``` + +### Send a Single Message + +```bash +openclaw message send "Hello, qianfan!" +``` + +### Use in Agent Mode + +```bash +openclaw agent --model qianfan/deepseek-v3.2 +``` + +### Check Configuration Status + +```bash +# View current configuration +openclaw config get + +# Check provider status +openclaw channels status --probe +``` + +## Model Details + +| Property | Value | +| ----------------- |-------------------------| +| Provider | `qianfan` | +| Model ID | `deepseek-v3.2` | +| Model Reference | `qianfan/deepseek-v3.2` | +| Context Window | 98,304 tokens | +| Max Output Tokens | 32,768 tokens | +| Reasoning | Yes | +| Input Types | Text | + +## Available Models + +The default model is `deepseek-v3.2`. You can configure additional models in your config file: + +```json +{ + "models": { + "providers": { + "qianfan": { + "models": [ + { + "id": "deepseek-v3", + "name": "DeepSeek-V3", + "reasoning": false, + "input": ["text"], + "contextWindow": 131072, + "maxTokens": 16384 + }, + { + "id": "ernie-x1.1", + "name": "ERNIE-X1.1", + "reasoning": true, + "input": ["text"], + "contextWindow": 65536, + "maxTokens": 65536 + } + ] + } + } + } +} +``` + +## Troubleshooting + +### API Key Not Found + +If you see "No API key found for provider qianfan": + +1. Verify the environment variable is set: + + ```bash + echo $QIANFAN_API_KEY + ``` + +2. Re-run onboarding: + + ```bash + openclaw onboard --auth-choice qianfan-api-key + ``` + +3. Check auth profiles: + ```bash + cat ~/.openclaw/auth-profiles.json + ``` + +### Authentication Errors + +If you receive authentication errors: + +1. Verify your API key format starts with `bce-v3/ALTAK-` +2. Check that your Qianfan application has the necessary permissions +3. Ensure your API key hasn't expired + +### Connection Issues + +If you can't connect to the Qianfan API: + +1. Check your network connection +2. Verify the API endpoint is accessible: + + ```bash + curl -I https://qianfan.baidubce.com/v2 + ``` + +3. Check if you're behind a proxy and configure accordingly + +### Model Not Found + +If the model isn't recognized: + +1. Ensure you're using the correct model reference format: `qianfan/` +2. Check available models in your config +3. Verify the model ID matches what's available in Qianfan + +## API Reference + +### Endpoint + +``` +https://qianfan.baidubce.com/v2 +``` + +### Authentication + +The API uses bearer token authentication with your Qianfan API key. + +### Request Format + +OpenClaw uses the OpenAI-compatible API format (`openai-completions`), which Qianfan supports. + +## Best Practices + +1. **Secure your API key**: Never commit API keys to version control +2. **Use environment variables**: Prefer `QIANFAN_API_KEY` over config file storage +3. **Monitor usage**: Track your Qianfan API usage in the console +4. **Handle rate limits**: Implement appropriate retry logic for production use +5. **Test locally first**: Verify your configuration before deploying + +## Related Documentation + +- [OpenClaw Configuration](/configuration) +- [Model Providers](/models/providers) +- [Agent Setup](/agents) +- [Qianfan API Documentation](https://cloud.baidu.com/doc/qianfan-api/s/3m7of64lb) diff --git a/src/agents/model-auth.ts b/src/agents/model-auth.ts index 4a4b5702cc..36527175ba 100644 --- a/src/agents/model-auth.ts +++ b/src/agents/model-auth.ts @@ -300,6 +300,7 @@ export function resolveEnvApiKey(provider: string): EnvApiKeyResult | null { venice: "VENICE_API_KEY", mistral: "MISTRAL_API_KEY", opencode: "OPENCODE_API_KEY", + qianfan: "QIANFAN_API_KEY", }; const envVar = envMap[normalized]; if (!envVar) { diff --git a/src/agents/models-config.providers.ts b/src/agents/models-config.providers.ts index 6ad93813dd..a0ea5c9db2 100644 --- a/src/agents/models-config.providers.ts +++ b/src/agents/models-config.providers.ts @@ -76,6 +76,17 @@ const OLLAMA_DEFAULT_COST = { cacheWrite: 0, }; +const QIANFAN_BASE_URL = "https://qianfan.baidubce.com/v2"; +export const QIANFAN_DEFAULT_MODEL_ID = "deepseek-v3.2"; +const QIANFAN_DEFAULT_CONTEXT_WINDOW = 98304; +const QIANFAN_DEFAULT_MAX_TOKENS = 32768; +const QIANFAN_DEFAULT_COST = { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, +}; + interface OllamaModel { name: string; modified_at: string; @@ -394,6 +405,24 @@ async function buildOllamaProvider(): Promise { }; } +export function buildQianfanProvider(): ProviderConfig { + return { + baseUrl: QIANFAN_BASE_URL, + api: "openai-completions", + models: [ + { + id: QIANFAN_DEFAULT_MODEL_ID, + name: "DEEPSEEK V3.2", + reasoning: true, + input: ["text"], + cost: QIANFAN_DEFAULT_COST, + contextWindow: QIANFAN_DEFAULT_CONTEXT_WINDOW, + maxTokens: QIANFAN_DEFAULT_MAX_TOKENS, + }, + ], + }; +} + export async function resolveImplicitProviders(params: { agentDir: string; }): Promise { @@ -461,6 +490,13 @@ export async function resolveImplicitProviders(params: { providers.ollama = { ...(await buildOllamaProvider()), apiKey: ollamaKey }; } + const qianfanKey = + resolveEnvApiKeyVarName("qianfan") ?? + resolveApiKeyFromProfiles({ provider: "qianfan", store: authStore }); + if (qianfanKey) { + providers.qianfan = { ...buildQianfanProvider(), apiKey: qianfanKey }; + } + return providers; } diff --git a/src/cli/program/register.onboard.ts b/src/cli/program/register.onboard.ts index 94d46fda37..e13c4d918b 100644 --- a/src/cli/program/register.onboard.ts +++ b/src/cli/program/register.onboard.ts @@ -58,7 +58,7 @@ export function registerOnboardCommand(program: Command) { .option("--mode ", "Wizard mode: local|remote") .option( "--auth-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|xiaomi-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip", + "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|xiaomi-api-key|qianfan-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip", ) .option( "--token-provider ", @@ -79,6 +79,7 @@ export function registerOnboardCommand(program: Command) { .option("--gemini-api-key ", "Gemini API key") .option("--zai-api-key ", "Z.AI API key") .option("--xiaomi-api-key ", "Xiaomi API key") + .option("--qianfan-api-key ", "QIANFAN API key") .option("--minimax-api-key ", "MiniMax API key") .option("--synthetic-api-key ", "Synthetic API key") .option("--venice-api-key ", "Venice API key") @@ -130,6 +131,7 @@ export function registerOnboardCommand(program: Command) { geminiApiKey: opts.geminiApiKey as string | undefined, zaiApiKey: opts.zaiApiKey as string | undefined, xiaomiApiKey: opts.xiaomiApiKey as string | undefined, + qianfanApiKey: opts.qianfanApiKey as string | undefined, minimaxApiKey: opts.minimaxApiKey as string | undefined, syntheticApiKey: opts.syntheticApiKey as string | undefined, veniceApiKey: opts.veniceApiKey as string | undefined, diff --git a/src/commands/auth-choice.apply.api-providers.ts b/src/commands/auth-choice.apply.api-providers.ts index ef059e3de4..877065dc92 100644 --- a/src/commands/auth-choice.apply.api-providers.ts +++ b/src/commands/auth-choice.apply.api-providers.ts @@ -13,6 +13,8 @@ import { } from "./google-gemini-model-default.js"; import { applyAuthProfileConfig, + applyQianfanConfig, + applyQianfanProviderConfig, applyKimiCodeConfig, applyKimiCodeProviderConfig, applyMoonshotConfig, @@ -30,6 +32,7 @@ import { applyXiaomiConfig, applyXiaomiProviderConfig, applyZaiConfig, + QIANFAN_DEFAULT_MODEL_REF, KIMI_CODING_MODEL_REF, MOONSHOT_DEFAULT_MODEL_REF, OPENROUTER_DEFAULT_MODEL_REF, @@ -37,6 +40,7 @@ import { VENICE_DEFAULT_MODEL_REF, VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF, XIAOMI_DEFAULT_MODEL_REF, + setQianfanApiKey, setGeminiApiKey, setKimiCodingApiKey, setMoonshotApiKey, @@ -96,6 +100,8 @@ export async function applyAuthChoiceApiProviders( authChoice = "venice-api-key"; } else if (params.opts.tokenProvider === "opencode") { authChoice = "opencode-zen"; + } else if (params.opts.tokenProvider === "qianfan") { + authChoice = "qianfan-api-key"; } } @@ -643,5 +649,61 @@ export async function applyAuthChoiceApiProviders( return { config: nextConfig, agentModelOverride }; } + if (authChoice === "qianfan-api-key") { + let hasCredential = false; + if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "qianfan") { + setQianfanApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir); + hasCredential = true; + } + + if (!hasCredential) { + await params.prompter.note( + [ + "Get your API key at: https://console.bce.baidu.com/qianfan/ais/console/apiKey", + "API key format: bce-v3/ALTAK-...", + ].join("\n"), + "QIANFAN", + ); + } + const envKey = resolveEnvApiKey("qianfan-api-key"); + if (envKey) { + const useExisting = await params.prompter.confirm({ + message: `Use existing QIANFAN_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, + initialValue: true, + }); + if (useExisting) { + setQianfanApiKey(envKey.apiKey, params.agentDir); + hasCredential = true; + } + } + if (!hasCredential) { + const key = await params.prompter.text({ + message: "Enter QIANFAN API key", + validate: validateApiKeyInput, + }); + setQianfanApiKey(normalizeApiKeyInput(String(key)), params.agentDir); + } + nextConfig = applyAuthProfileConfig(nextConfig, { + profileId: "qianfan:default", + provider: "qianfan", + mode: "api_key", + }); + { + const applied = await applyDefaultModelChoice({ + config: nextConfig, + setDefaultModel: params.setDefaultModel, + defaultModel: QIANFAN_DEFAULT_MODEL_REF, + applyDefaultConfig: applyQianfanConfig, + applyProviderConfig: applyQianfanProviderConfig, + noteDefault: QIANFAN_DEFAULT_MODEL_REF, + noteAgentModel, + prompter: params.prompter, + }); + nextConfig = applied.config; + agentModelOverride = applied.agentModelOverride ?? agentModelOverride; + } + return { config: nextConfig, agentModelOverride }; + } + return null; } diff --git a/src/commands/auth-choice.preferred-provider.ts b/src/commands/auth-choice.preferred-provider.ts index 861faf5de9..a3770290ba 100644 --- a/src/commands/auth-choice.preferred-provider.ts +++ b/src/commands/auth-choice.preferred-provider.ts @@ -30,6 +30,7 @@ const PREFERRED_PROVIDER_BY_AUTH_CHOICE: Partial> = { "opencode-zen": "opencode", "qwen-portal": "qwen-portal", "minimax-portal": "minimax-portal", + "qianfan-api-key": "qianfan", }; export function resolvePreferredProviderForAuthChoice(choice: AuthChoice): string | undefined { diff --git a/src/commands/onboard-auth.config-core.ts b/src/commands/onboard-auth.config-core.ts index cd74eb590b..e504fe4e6f 100644 --- a/src/commands/onboard-auth.config-core.ts +++ b/src/commands/onboard-auth.config-core.ts @@ -1,5 +1,11 @@ import type { OpenClawConfig } from "../config/config.js"; -import { buildXiaomiProvider, XIAOMI_DEFAULT_MODEL_ID } from "../agents/models-config.providers.js"; +import type { ModelApi } from "../config/types.models.js"; +import { + buildQianfanProvider, + buildXiaomiProvider, + QIANFAN_DEFAULT_MODEL_ID, + XIAOMI_DEFAULT_MODEL_ID, +} from "../agents/models-config.providers.js"; import { buildSyntheticModelDefinition, SYNTHETIC_BASE_URL, @@ -20,6 +26,8 @@ import { } from "./onboard-auth.credentials.js"; import { buildMoonshotModelDefinition, + QIANFAN_BASE_URL, + QIANFAN_DEFAULT_MODEL_REF, KIMI_CODING_MODEL_REF, MOONSHOT_BASE_URL, MOONSHOT_DEFAULT_MODEL_ID, @@ -505,3 +513,80 @@ export function applyAuthProfileConfig( }, }; } + +export function applyQianfanProviderConfig(cfg: OpenClawConfig): OpenClawConfig { + const models = { ...cfg.agents?.defaults?.models }; + models[QIANFAN_DEFAULT_MODEL_REF] = { + ...models[QIANFAN_DEFAULT_MODEL_REF], + alias: models[QIANFAN_DEFAULT_MODEL_REF]?.alias ?? "QIANFAN", + }; + + const providers = { ...cfg.models?.providers }; + const existingProvider = providers.qianfan; + const defaultProvider = buildQianfanProvider(); + const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : []; + const defaultModels = defaultProvider.models ?? []; + const hasDefaultModel = existingModels.some((model) => model.id === QIANFAN_DEFAULT_MODEL_ID); + const mergedModels = + existingModels.length > 0 + ? hasDefaultModel + ? existingModels + : [...existingModels, ...defaultModels] + : defaultModels; + const { + apiKey: existingApiKey, + baseUrl: existingBaseUrl, + api: existingApi, + ...existingProviderRest + } = (existingProvider ?? {}) as Record as { + apiKey?: string; + baseUrl?: string; + api?: ModelApi; + }; + const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined; + const normalizedApiKey = resolvedApiKey?.trim(); + providers.qianfan = { + ...existingProviderRest, + baseUrl: existingBaseUrl ?? QIANFAN_BASE_URL, + api: existingApi ?? "openai-completions", + ...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}), + models: mergedModels.length > 0 ? mergedModels : defaultProvider.models, + }; + + return { + ...cfg, + agents: { + ...cfg.agents, + defaults: { + ...cfg.agents?.defaults, + models, + }, + }, + models: { + mode: cfg.models?.mode ?? "merge", + providers, + }, + }; +} + +export function applyQianfanConfig(cfg: OpenClawConfig): OpenClawConfig { + const next = applyQianfanProviderConfig(cfg); + const existingModel = next.agents?.defaults?.model; + return { + ...next, + agents: { + ...next.agents, + defaults: { + ...next.agents?.defaults, + model: { + ...(existingModel && "fallbacks" in (existingModel as Record) + ? { + fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks, + } + : undefined), + primary: QIANFAN_DEFAULT_MODEL_REF, + }, + }, + }, + }; +} diff --git a/src/commands/onboard-auth.credentials.ts b/src/commands/onboard-auth.credentials.ts index 1790925d7b..aa1ba0326f 100644 --- a/src/commands/onboard-auth.credentials.ts +++ b/src/commands/onboard-auth.credentials.ts @@ -178,3 +178,15 @@ export async function setOpencodeZenApiKey(key: string, agentDir?: string) { agentDir: resolveAuthAgentDir(agentDir), }); } + +export function setQianfanApiKey(key: string, agentDir?: string) { + upsertAuthProfile({ + profileId: "qianfan:default", + credential: { + type: "api_key", + provider: "qianfan", + key, + }, + agentDir: resolveAuthAgentDir(agentDir), + }); +} diff --git a/src/commands/onboard-auth.models.ts b/src/commands/onboard-auth.models.ts index c77b6bc102..e8523198bf 100644 --- a/src/commands/onboard-auth.models.ts +++ b/src/commands/onboard-auth.models.ts @@ -15,6 +15,18 @@ export const MOONSHOT_DEFAULT_MAX_TOKENS = 8192; export const KIMI_CODING_MODEL_ID = "k2p5"; export const KIMI_CODING_MODEL_REF = `kimi-coding/${KIMI_CODING_MODEL_ID}`; +export const QIANFAN_BASE_URL = "https://qianfan.baidubce.com/v2"; +export const QIANFAN_DEFAULT_MODEL_ID = "deepseek-v3.2"; +export const QIANFAN_DEFAULT_MODEL_REF = `ernie/${QIANFAN_DEFAULT_MODEL_ID}`; +export const QIANFAN_DEFAULT_CONTEXT_WINDOW = 98304; +export const QIANFAN_DEFAULT_MAX_TOKENS = 32768; +export const QIANFAN_DEFAULT_COST = { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, +}; + // Pricing: MiniMax doesn't publish public rates. Override in models.json for accurate costs. export const MINIMAX_API_COST = { input: 15, @@ -91,3 +103,15 @@ export function buildMoonshotModelDefinition(): ModelDefinitionConfig { maxTokens: MOONSHOT_DEFAULT_MAX_TOKENS, }; } + +export function buildQianfanModelDefinition(): ModelDefinitionConfig { + return { + id: QIANFAN_DEFAULT_MODEL_ID, + name: "ERNIE 5.0", + reasoning: true, + input: ["text"], + cost: QIANFAN_DEFAULT_COST, + contextWindow: QIANFAN_DEFAULT_CONTEXT_WINDOW, + maxTokens: QIANFAN_DEFAULT_MAX_TOKENS, + }; +} diff --git a/src/commands/onboard-auth.ts b/src/commands/onboard-auth.ts index af4d22cb1e..773a9e3a66 100644 --- a/src/commands/onboard-auth.ts +++ b/src/commands/onboard-auth.ts @@ -5,6 +5,8 @@ export { export { VENICE_DEFAULT_MODEL_ID, VENICE_DEFAULT_MODEL_REF } from "../agents/venice-models.js"; export { applyAuthProfileConfig, + applyQianfanConfig, + applyQianfanProviderConfig, applyKimiCodeConfig, applyKimiCodeProviderConfig, applyMoonshotConfig, @@ -37,6 +39,7 @@ export { export { OPENROUTER_DEFAULT_MODEL_REF, setAnthropicApiKey, + setQianfanApiKey, setGeminiApiKey, setKimiCodingApiKey, setMinimaxApiKey, @@ -54,10 +57,14 @@ export { ZAI_DEFAULT_MODEL_REF, } from "./onboard-auth.credentials.js"; export { + buildQianfanModelDefinition, buildMinimaxApiModelDefinition, buildMinimaxModelDefinition, buildMoonshotModelDefinition, DEFAULT_MINIMAX_BASE_URL, + QIANFAN_BASE_URL, + QIANFAN_DEFAULT_MODEL_ID, + QIANFAN_DEFAULT_MODEL_REF, KIMI_CODING_MODEL_ID, KIMI_CODING_MODEL_REF, MINIMAX_API_BASE_URL, diff --git a/src/commands/onboard-non-interactive/local/auth-choice.ts b/src/commands/onboard-non-interactive/local/auth-choice.ts index 98d11b002c..18e19a7a62 100644 --- a/src/commands/onboard-non-interactive/local/auth-choice.ts +++ b/src/commands/onboard-non-interactive/local/auth-choice.ts @@ -10,6 +10,7 @@ import { buildTokenProfileId, validateAnthropicSetupToken } from "../../auth-tok import { applyGoogleGeminiModelDefault } from "../../google-gemini-model-default.js"; import { applyAuthProfileConfig, + applyQianfanConfig, applyKimiCodeConfig, applyMinimaxApiConfig, applyMinimaxConfig, @@ -22,6 +23,7 @@ import { applyXiaomiConfig, applyZaiConfig, setAnthropicApiKey, + setQianfanApiKey, setGeminiApiKey, setKimiCodingApiKey, setMinimaxApiKey, @@ -214,6 +216,29 @@ export async function applyNonInteractiveAuthChoice(params: { return applyXiaomiConfig(nextConfig); } + if (authChoice === "qianfan-api-key") { + const resolved = await resolveNonInteractiveApiKey({ + provider: "qianfan", + cfg: baseConfig, + flagValue: opts.qianfanApiKey, + flagName: "--qianfan-api-key", + envVar: "QIANFAN_API_KEY", + runtime, + }); + if (!resolved) { + return null; + } + if (resolved.source !== "profile") { + setQianfanApiKey(resolved.key); + } + nextConfig = applyAuthProfileConfig(nextConfig, { + profileId: "qianfan:default", + provider: "qianfan", + mode: "api_key", + }); + return applyQianfanConfig(nextConfig); + } + if (authChoice === "openai-api-key") { const resolved = await resolveNonInteractiveApiKey({ provider: "openai", diff --git a/src/commands/onboard-types.ts b/src/commands/onboard-types.ts index f3d72051d4..a6ea73017c 100644 --- a/src/commands/onboard-types.ts +++ b/src/commands/onboard-types.ts @@ -33,6 +33,7 @@ export type AuthChoice = | "github-copilot" | "copilot-proxy" | "qwen-portal" + | "qianfan-api-key" | "skip"; export type GatewayAuthChoice = "token" | "password"; export type ResetScope = "config" | "config+creds+sessions" | "full"; @@ -74,6 +75,7 @@ export type OnboardOptions = { syntheticApiKey?: string; veniceApiKey?: string; opencodeZenApiKey?: string; + qianfanApiKey?: string; gatewayPort?: number; gatewayBind?: GatewayBind; gatewayAuth?: GatewayAuthChoice; From 1de05ad068ac0371b4b520a12697a9973faea54d Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Wed, 4 Feb 2026 16:36:37 +0800 Subject: [PATCH 02/14] Add baidu qianfan model provider --- docs/providers/qianfan.md | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/providers/qianfan.md b/docs/providers/qianfan.md index dfb663cf3c..e87e148ded 100644 --- a/docs/providers/qianfan.md +++ b/docs/providers/qianfan.md @@ -11,7 +11,6 @@ title: "Qianfan" Qianfan is Baidu's MaaS platform, provides a **unified API** that routes requests to many models behind a single endpoint and API key. It is OpenAI-compatible, so most OpenAI SDKs work by switching the base URL. - ## Prerequisites 1. A Baidu Cloud account with Qianfan API access @@ -165,7 +164,7 @@ openclaw channels status --probe ## Model Details | Property | Value | -| ----------------- |-------------------------| +| ----------------- | ----------------------- | | Provider | `qianfan` | | Model ID | `deepseek-v3.2` | | Model Reference | `qianfan/deepseek-v3.2` | @@ -184,22 +183,22 @@ The default model is `deepseek-v3.2`. You can configure additional models in you "providers": { "qianfan": { "models": [ - { - "id": "deepseek-v3", - "name": "DeepSeek-V3", - "reasoning": false, - "input": ["text"], - "contextWindow": 131072, - "maxTokens": 16384 - }, - { - "id": "ernie-x1.1", - "name": "ERNIE-X1.1", - "reasoning": true, - "input": ["text"], - "contextWindow": 65536, - "maxTokens": 65536 - } + { + "id": "deepseek-v3", + "name": "DeepSeek-V3", + "reasoning": false, + "input": ["text"], + "contextWindow": 131072, + "maxTokens": 16384 + }, + { + "id": "ernie-x1.1", + "name": "ERNIE-X1.1", + "reasoning": true, + "input": ["text"], + "contextWindow": 65536, + "maxTokens": 65536 + } ] } } From 7bf408060885257e17d77b0674cb39c241e81da9 Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Wed, 4 Feb 2026 22:21:46 +0800 Subject: [PATCH 03/14] Fix format --- docs/docs.json | 7 ++++++- src/commands/onboard-auth.models.ts | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/docs.json b/docs/docs.json index 7e6950c658..d544435b46 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -85,6 +85,10 @@ "source": "/opencode", "destination": "/providers/opencode" }, + { + "source": "/qianfan", + "destination": "/providers/qianfan" + }, { "source": "/mattermost", "destination": "/channels/mattermost" @@ -934,7 +938,8 @@ "providers/opencode", "providers/glm", "providers/zai", - "providers/synthetic" + "providers/synthetic", + "providers/qianfan" ] } ] diff --git a/src/commands/onboard-auth.models.ts b/src/commands/onboard-auth.models.ts index e8523198bf..8be92ea848 100644 --- a/src/commands/onboard-auth.models.ts +++ b/src/commands/onboard-auth.models.ts @@ -17,7 +17,7 @@ export const KIMI_CODING_MODEL_REF = `kimi-coding/${KIMI_CODING_MODEL_ID}`; export const QIANFAN_BASE_URL = "https://qianfan.baidubce.com/v2"; export const QIANFAN_DEFAULT_MODEL_ID = "deepseek-v3.2"; -export const QIANFAN_DEFAULT_MODEL_REF = `ernie/${QIANFAN_DEFAULT_MODEL_ID}`; +export const QIANFAN_DEFAULT_MODEL_REF = `qianfan/${QIANFAN_DEFAULT_MODEL_ID}`; export const QIANFAN_DEFAULT_CONTEXT_WINDOW = 98304; export const QIANFAN_DEFAULT_MAX_TOKENS = 32768; export const QIANFAN_DEFAULT_COST = { From 8c53dfb74f2484c323ffa835995978443f160baf Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Wed, 4 Feb 2026 22:30:42 +0800 Subject: [PATCH 04/14] Optimize doc --- docs/providers/qianfan.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/providers/qianfan.md b/docs/providers/qianfan.md index e87e148ded..eebfabd0ff 100644 --- a/docs/providers/qianfan.md +++ b/docs/providers/qianfan.md @@ -1,5 +1,5 @@ --- -summary: "Use DeepSeek-V3.2 in OpenClaw" +summary: "Use Qifan's unified API to access many models in OpenClaw" read_when: - You want a single API key for many LLMs - You need Baidu Qianfan setup guidance From fb5280e1b5cd0315390f95b3100759020f683ee5 Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Wed, 4 Feb 2026 22:57:34 +0800 Subject: [PATCH 05/14] optimize doc --- docs/providers/qianfan.md | 17 +++-------------- src/commands/onboard-auth.models.ts | 2 +- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/docs/providers/qianfan.md b/docs/providers/qianfan.md index eebfabd0ff..0ec653cd9d 100644 --- a/docs/providers/qianfan.md +++ b/docs/providers/qianfan.md @@ -1,12 +1,12 @@ --- -summary: "Use Qifan's unified API to access many models in OpenClaw" +summary: "Use Qianfan's unified API to access many models in OpenClaw" read_when: - You want a single API key for many LLMs - You need Baidu Qianfan setup guidance title: "Qianfan" --- -# Baidu Qianfan Provider Guide +# Qianfan Provider Guide Qianfan is Baidu's MaaS platform, provides a **unified API** that routes requests to many models behind a single endpoint and API key. It is OpenAI-compatible, so most OpenAI SDKs work by switching the base URL. @@ -79,20 +79,9 @@ openclaw onboard --auth-choice qianfan-api-key Follow the prompts to enter your API key. -### Method 3: Non-Interactive Setup -For CI/CD or scripted setups: -```bash -openclaw onboard \ - --non-interactive \ - --accept-risk \ - --auth-choice token \ - --token-provider qianfan \ - --token "bce-v3/ALTAK-your-api-key-here" -``` - -### Method 4: Configuration File +### Method 3: Configuration File Configure manually via `openclaw.json`: diff --git a/src/commands/onboard-auth.models.ts b/src/commands/onboard-auth.models.ts index 1ac95f4ee6..3bb9bf4a2b 100644 --- a/src/commands/onboard-auth.models.ts +++ b/src/commands/onboard-auth.models.ts @@ -108,7 +108,7 @@ export function buildMoonshotModelDefinition(): ModelDefinitionConfig { export function buildQianfanModelDefinition(): ModelDefinitionConfig { return { id: QIANFAN_DEFAULT_MODEL_ID, - name: "ERNIE 5.0", + name: "DEEPSEEK V3.2", reasoning: true, input: ["text"], cost: QIANFAN_DEFAULT_COST, From c8e67ad5d576ce26bd62041d062daa226a554887 Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Thu, 5 Feb 2026 12:39:38 +0800 Subject: [PATCH 06/14] Fix import error --- src/commands/onboard-auth.config-core.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/commands/onboard-auth.config-core.ts b/src/commands/onboard-auth.config-core.ts index f39a807345..8f57805bfe 100644 --- a/src/commands/onboard-auth.config-core.ts +++ b/src/commands/onboard-auth.config-core.ts @@ -1,16 +1,15 @@ import type { OpenClawConfig } from "../config/config.js"; import type { ModelApi } from "../config/types.models.js"; -import { - buildQianfanProvider, - buildXiaomiProvider, - QIANFAN_DEFAULT_MODEL_ID, - XIAOMI_DEFAULT_MODEL_ID, -} from "../agents/models-config.providers.js"; import { buildCloudflareAiGatewayModelDefinition, resolveCloudflareAiGatewayBaseUrl, } from "../agents/cloudflare-ai-gateway.js"; -import { buildXiaomiProvider, XIAOMI_DEFAULT_MODEL_ID } from "../agents/models-config.providers.js"; +import { + buildXiaomiProvider, + buildQianfanProvider, + XIAOMI_DEFAULT_MODEL_ID, + QIANFAN_DEFAULT_MODEL_ID, +} from "../agents/models-config.providers.js"; import { buildSyntheticModelDefinition, SYNTHETIC_BASE_URL, From 52c9d3480fb4d949e7f471fb8c1a7def1398d5a7 Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Thu, 5 Feb 2026 13:35:35 +0800 Subject: [PATCH 07/14] Add auth choice --- docs/providers/index.md | 1 + docs/providers/models.md | 1 + src/commands/auth-choice-options.ts | 13 ++++++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/providers/index.md b/docs/providers/index.md index cc1dad7ee5..4e4cf2e3e2 100644 --- a/docs/providers/index.md +++ b/docs/providers/index.md @@ -50,6 +50,7 @@ See [Venice AI](/providers/venice). - [MiniMax](/providers/minimax) - [Venice (Venice AI, privacy-focused)](/providers/venice) - [Ollama (local models)](/providers/ollama) +- [Qianfan](/providers/qianfan) ## Transcription providers diff --git a/docs/providers/models.md b/docs/providers/models.md index 64c7d865ec..6854a024af 100644 --- a/docs/providers/models.md +++ b/docs/providers/models.md @@ -46,6 +46,7 @@ See [Venice AI](/providers/venice). - [MiniMax](/providers/minimax) - [Venice (Venice AI)](/providers/venice) - [Amazon Bedrock](/bedrock) +- [Qianfan](/providers/qianfan) For the full provider catalog (xAI, Groq, Mistral, etc.) and advanced configuration, see [Model providers](/concepts/model-providers). diff --git a/src/commands/auth-choice-options.ts b/src/commands/auth-choice-options.ts index c3a281278c..0d61015406 100644 --- a/src/commands/auth-choice-options.ts +++ b/src/commands/auth-choice-options.ts @@ -22,7 +22,8 @@ export type AuthChoiceGroupId = | "minimax" | "synthetic" | "venice" - | "qwen"; + | "qwen" + | "qianfan"; export type AuthChoiceGroup = { value: AuthChoiceGroupId; @@ -127,6 +128,12 @@ const AUTH_CHOICE_GROUP_DEFS: { hint: "Account ID + Gateway ID + API key", choices: ["cloudflare-ai-gateway-api-key"], }, + { + value: "qianfan", + label: "Qianfan", + hint: "API key", + choices: ["qianfan-api-key"], + }, ]; export function buildAuthChoiceOptions(params: { @@ -218,6 +225,10 @@ export function buildAuthChoiceOptions(params: { label: "MiniMax M2.1 Lightning", hint: "Faster, higher output cost", }); + options.push({ + value: "qianfan-api-key", + label: "Qianfan API key", + }); if (params.includeSkip) { options.push({ value: "skip", label: "Skip for now" }); } From ad759c94460c922e6b16951c9b8c1d09f7723baf Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Thu, 5 Feb 2026 13:41:41 +0800 Subject: [PATCH 08/14] Optimize format --- docs/providers/qianfan.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/providers/qianfan.md b/docs/providers/qianfan.md index 0ec653cd9d..3c04bdfd78 100644 --- a/docs/providers/qianfan.md +++ b/docs/providers/qianfan.md @@ -79,8 +79,6 @@ openclaw onboard --auth-choice qianfan-api-key Follow the prompts to enter your API key. - - ### Method 3: Configuration File Configure manually via `openclaw.json`: From ff948a6dd7bb0ae1cd257541c1bb6715e07e91c5 Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Thu, 5 Feb 2026 14:04:23 +0800 Subject: [PATCH 09/14] Optimize doc --- docs/providers/qianfan.md | 241 +------------------------------------- 1 file changed, 1 insertion(+), 240 deletions(-) diff --git a/docs/providers/qianfan.md b/docs/providers/qianfan.md index 3c04bdfd78..b0f7db515e 100644 --- a/docs/providers/qianfan.md +++ b/docs/providers/qianfan.md @@ -24,251 +24,12 @@ endpoint and API key. It is OpenAI-compatible, so most OpenAI SDKs work by switc 3. Generate an API key (format: `bce-v3/ALTAK-...`) 4. Copy the API key for use with OpenClaw -## Installation - -### Install OpenClaw - -```bash -# Using npm -npm install -g openclaw - -# Using pnpm -pnpm add -g openclaw - -# Using bun -bun add -g openclaw -``` - -### Verify Installation - -```bash -openclaw --version -``` - -## Configuration Methods - -### Method 1: Environment Variable (Recommended) - -Set the `QIANFAN_API_KEY` environment variable: - -```bash -# Bash/Zsh -export QIANFAN_API_KEY="bce-v3/ALTAK-your-api-key-here" - -# Fish -set -gx QIANFAN_API_KEY "bce-v3/ALTAK-your-api-key-here" - -# PowerShell -$env:QIANFAN_API_KEY = "bce-v3/ALTAK-your-api-key-here" -``` - -Add to your shell profile (`~/.bashrc`, `~/.zshrc`, etc.) for persistence: - -```bash -echo 'export QIANFAN_API_KEY="bce-v3/ALTAK-your-api-key-here"' >> ~/.bashrc -source ~/.bashrc -``` - -### Method 2: Interactive Onboarding - -Run the onboarding wizard: +## CLI setup ```bash openclaw onboard --auth-choice qianfan-api-key ``` -Follow the prompts to enter your API key. - -### Method 3: Configuration File - -Configure manually via `openclaw.json`: - -```json -{ - "models": { - "providers": { - "qianfan": { - "baseUrl": "https://qianfan.baidubce.com/v2", - "api": "openai-completions", - "apiKey": "bce-v3/ALTAK-your-api-key-here", - "models": [ - { - "id": "deepseek-v3.2", - "name": "DeepSeek-V3.2", - "reasoning": true, - "input": ["text"], - "contextWindow": 98304, - "maxTokens": 32768 - } - ] - } - } - }, - "agents": { - "defaults": { - "model": { - "primary": "qianfan/deepseek-v3.2" - } - } - } -} -``` - -## Usage - -### Start a Chat Session - -```bash -# Using default QIANFAN model -openclaw chat - -# Explicitly specify QIANFAN model -openclaw chat --model qianfan/deepseek-v3.2 -``` - -### Send a Single Message - -```bash -openclaw message send "Hello, qianfan!" -``` - -### Use in Agent Mode - -```bash -openclaw agent --model qianfan/deepseek-v3.2 -``` - -### Check Configuration Status - -```bash -# View current configuration -openclaw config get - -# Check provider status -openclaw channels status --probe -``` - -## Model Details - -| Property | Value | -| ----------------- | ----------------------- | -| Provider | `qianfan` | -| Model ID | `deepseek-v3.2` | -| Model Reference | `qianfan/deepseek-v3.2` | -| Context Window | 98,304 tokens | -| Max Output Tokens | 32,768 tokens | -| Reasoning | Yes | -| Input Types | Text | - -## Available Models - -The default model is `deepseek-v3.2`. You can configure additional models in your config file: - -```json -{ - "models": { - "providers": { - "qianfan": { - "models": [ - { - "id": "deepseek-v3", - "name": "DeepSeek-V3", - "reasoning": false, - "input": ["text"], - "contextWindow": 131072, - "maxTokens": 16384 - }, - { - "id": "ernie-x1.1", - "name": "ERNIE-X1.1", - "reasoning": true, - "input": ["text"], - "contextWindow": 65536, - "maxTokens": 65536 - } - ] - } - } - } -} -``` - -## Troubleshooting - -### API Key Not Found - -If you see "No API key found for provider qianfan": - -1. Verify the environment variable is set: - - ```bash - echo $QIANFAN_API_KEY - ``` - -2. Re-run onboarding: - - ```bash - openclaw onboard --auth-choice qianfan-api-key - ``` - -3. Check auth profiles: - ```bash - cat ~/.openclaw/auth-profiles.json - ``` - -### Authentication Errors - -If you receive authentication errors: - -1. Verify your API key format starts with `bce-v3/ALTAK-` -2. Check that your Qianfan application has the necessary permissions -3. Ensure your API key hasn't expired - -### Connection Issues - -If you can't connect to the Qianfan API: - -1. Check your network connection -2. Verify the API endpoint is accessible: - - ```bash - curl -I https://qianfan.baidubce.com/v2 - ``` - -3. Check if you're behind a proxy and configure accordingly - -### Model Not Found - -If the model isn't recognized: - -1. Ensure you're using the correct model reference format: `qianfan/` -2. Check available models in your config -3. Verify the model ID matches what's available in Qianfan - -## API Reference - -### Endpoint - -``` -https://qianfan.baidubce.com/v2 -``` - -### Authentication - -The API uses bearer token authentication with your Qianfan API key. - -### Request Format - -OpenClaw uses the OpenAI-compatible API format (`openai-completions`), which Qianfan supports. - -## Best Practices - -1. **Secure your API key**: Never commit API keys to version control -2. **Use environment variables**: Prefer `QIANFAN_API_KEY` over config file storage -3. **Monitor usage**: Track your Qianfan API usage in the console -4. **Handle rate limits**: Implement appropriate retry logic for production use -5. **Test locally first**: Verify your configuration before deploying - ## Related Documentation - [OpenClaw Configuration](/configuration) From 4d30f97407a75168a9d7e7683ad2158ee3b3d22c Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Thu, 5 Feb 2026 14:40:56 +0800 Subject: [PATCH 10/14] Fix key resolve --- src/commands/auth-choice.apply.api-providers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/auth-choice.apply.api-providers.ts b/src/commands/auth-choice.apply.api-providers.ts index 462ed0e774..7bb7913898 100644 --- a/src/commands/auth-choice.apply.api-providers.ts +++ b/src/commands/auth-choice.apply.api-providers.ts @@ -819,7 +819,7 @@ export async function applyAuthChoiceApiProviders( "QIANFAN", ); } - const envKey = resolveEnvApiKey("qianfan-api-key"); + const envKey = resolveEnvApiKey("qianfan"); if (envKey) { const useExisting = await params.prompter.confirm({ message: `Use existing QIANFAN_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, From 7af00f040aa055e9a9278e29085d0dcb092e7ae7 Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Thu, 5 Feb 2026 14:53:38 +0800 Subject: [PATCH 11/14] Optimize import --- src/commands/onboard-auth.config-core.ts | 2 +- src/cron/isolated-agent/run.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/commands/onboard-auth.config-core.ts b/src/commands/onboard-auth.config-core.ts index 8f57805bfe..a18d9edf70 100644 --- a/src/commands/onboard-auth.config-core.ts +++ b/src/commands/onboard-auth.config-core.ts @@ -8,7 +8,6 @@ import { buildXiaomiProvider, buildQianfanProvider, XIAOMI_DEFAULT_MODEL_ID, - QIANFAN_DEFAULT_MODEL_ID, } from "../agents/models-config.providers.js"; import { buildSyntheticModelDefinition, @@ -33,6 +32,7 @@ import { buildMoonshotModelDefinition, QIANFAN_BASE_URL, QIANFAN_DEFAULT_MODEL_REF, + QIANFAN_DEFAULT_MODEL_ID, KIMI_CODING_MODEL_REF, MOONSHOT_BASE_URL, MOONSHOT_CN_BASE_URL, diff --git a/src/cron/isolated-agent/run.ts b/src/cron/isolated-agent/run.ts index 422a81fe32..6a557db34d 100644 --- a/src/cron/isolated-agent/run.ts +++ b/src/cron/isolated-agent/run.ts @@ -35,7 +35,6 @@ import { resolveAgentTimeoutMs } from "../../agents/timeout.js"; import { hasNonzeroUsage } from "../../agents/usage.js"; import { ensureAgentWorkspace } from "../../agents/workspace.js"; import { - formatXHighModelHint, normalizeThinkLevel, normalizeVerboseLevel, supportsXHighThinking, From 360851366fb10f71daed55847a66e16d0107b6a4 Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Fri, 6 Feb 2026 17:49:54 +0800 Subject: [PATCH 12/14] Support ERNIE-5.0-Thinking-Preview --- src/agents/models-config.providers.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/agents/models-config.providers.ts b/src/agents/models-config.providers.ts index 7e85723bd7..6c9adca969 100644 --- a/src/agents/models-config.providers.ts +++ b/src/agents/models-config.providers.ts @@ -423,6 +423,15 @@ export function buildQianfanProvider(): ProviderConfig { contextWindow: QIANFAN_DEFAULT_CONTEXT_WINDOW, maxTokens: QIANFAN_DEFAULT_MAX_TOKENS, }, + { + id: "ernie-5.0-thinking-preview", + name: "ERNIE-5.0-Thinking-Preview", + reasoning: true, + input: ["text", "image"], + cost: QIANFAN_DEFAULT_COST, + contextWindow: 119000, + maxTokens: 64000, + }, ], }; } From 7a9deb2400601e28cb173e50de76f780b6611712 Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Fri, 6 Feb 2026 18:13:42 +0800 Subject: [PATCH 13/14] Resolve conflicts --- src/commands/auth-choice-options.ts | 2 +- .../local/auth-choice.ts | 21 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/commands/auth-choice-options.ts b/src/commands/auth-choice-options.ts index cece3f4e29..1b2514fa76 100644 --- a/src/commands/auth-choice-options.ts +++ b/src/commands/auth-choice-options.ts @@ -23,7 +23,7 @@ export type AuthChoiceGroupId = | "synthetic" | "venice" | "qwen" - | "qianfan"; + | "qianfan" | "xai"; export type AuthChoiceGroup = { diff --git a/src/commands/onboard-non-interactive/local/auth-choice.ts b/src/commands/onboard-non-interactive/local/auth-choice.ts index e34e62d40a..62c7fe8ed9 100644 --- a/src/commands/onboard-non-interactive/local/auth-choice.ts +++ b/src/commands/onboard-non-interactive/local/auth-choice.ts @@ -229,13 +229,6 @@ export async function applyNonInteractiveAuthChoice(params: { flagValue: opts.qianfanApiKey, flagName: "--qianfan-api-key", envVar: "QIANFAN_API_KEY", - if (authChoice === "xai-api-key") { - const resolved = await resolveNonInteractiveApiKey({ - provider: "xai", - cfg: baseConfig, - flagValue: opts.xaiApiKey, - flagName: "--xai-api-key", - envVar: "XAI_API_KEY", runtime, }); if (!resolved) { @@ -250,7 +243,19 @@ export async function applyNonInteractiveAuthChoice(params: { mode: "api_key", }); return applyQianfanConfig(nextConfig); - setXaiApiKey(resolved.key); + } + + if (authChoice === "xai-api-key") { + const resolved = await resolveNonInteractiveApiKey({ + provider: "xai", + cfg: baseConfig, + flagValue: opts.xaiApiKey, + flagName: "--xai-api-key", + envVar: "XAI_API_KEY", + runtime, + }); + if (!resolved) { + return null; } nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "xai:default", From 0b51f0d76241a3c13fd6c652ee9e3589338ab915 Mon Sep 17 00:00:00 2001 From: ideoutrea Date: Fri, 6 Feb 2026 18:16:20 +0800 Subject: [PATCH 14/14] Fix conflicts --- src/commands/onboard-non-interactive/local/auth-choice.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/commands/onboard-non-interactive/local/auth-choice.ts b/src/commands/onboard-non-interactive/local/auth-choice.ts index 62c7fe8ed9..e4d4e3f0e9 100644 --- a/src/commands/onboard-non-interactive/local/auth-choice.ts +++ b/src/commands/onboard-non-interactive/local/auth-choice.ts @@ -257,6 +257,9 @@ export async function applyNonInteractiveAuthChoice(params: { if (!resolved) { return null; } + if (resolved.source !== "profile") { + setXaiApiKey(resolved.key); + } nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "xai:default", provider: "xai",