mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-05 23:10:20 +00:00
feat: Provider/Mistral full support for Mistral on OpenClaw 🇫🇷 (#23845)
* Onboard: add Mistral auth choice and CLI flags * Onboard/Auth: add Mistral provider config defaults * Auth choice: wire Mistral API-key flow * Onboard non-interactive: support --mistral-api-key * Media understanding: add Mistral Voxtral audio provider * Changelog: note Mistral onboarding and media support * Docs: add Mistral provider and onboarding/media references * Tests: cover Mistral media registry/defaults and auth mapping * Memory: add Mistral embeddings provider support * Onboarding: refresh Mistral model metadata * Docs: document Mistral embeddings and endpoints * Memory: persist Mistral embedding client state in managers * Memory: add regressions for mistral provider wiring * Gateway: add live tool probe retry helper * Gateway: cover live tool probe retry helper * Gateway: retry malformed live tool-read probe responses * Memory: support plain-text batch error bodies * Tests: add Mistral Voxtral live transcription smoke * Docs: add Mistral live audio test command * Revert: remove Mistral live voice test and docs entry * Onboard: re-export Mistral default model ref from models * Changelog: credit joeVenner for Mistral work * fix: include Mistral in auto audio key fallback * Update CHANGELOG.md * Update CHANGELOG.md --------- Co-authored-by: Shakker <shakkerdroid@gmail.com>
This commit is contained in:
@@ -43,6 +43,7 @@ describe("buildAuthChoiceOptions", () => {
|
||||
["Chutes OAuth auth choice", ["chutes"]],
|
||||
["Qwen auth choice", ["qwen-portal"]],
|
||||
["xAI auth choice", ["xai-api-key"]],
|
||||
["Mistral auth choice", ["mistral-api-key"]],
|
||||
["Volcano Engine auth choice", ["volcengine-api-key"]],
|
||||
["BytePlus auth choice", ["byteplus-api-key"]],
|
||||
["vLLM auth choice", ["vllm"]],
|
||||
|
||||
@@ -70,6 +70,12 @@ const AUTH_CHOICE_GROUP_DEFS: {
|
||||
hint: "API key",
|
||||
choices: ["xai-api-key"],
|
||||
},
|
||||
{
|
||||
value: "mistral",
|
||||
label: "Mistral AI",
|
||||
hint: "API key",
|
||||
choices: ["mistral-api-key"],
|
||||
},
|
||||
{
|
||||
value: "volcengine",
|
||||
label: "Volcano Engine",
|
||||
@@ -191,6 +197,7 @@ const BASE_AUTH_CHOICE_OPTIONS: ReadonlyArray<AuthChoiceOption> = [
|
||||
hint: "Local/self-hosted OpenAI-compatible server",
|
||||
},
|
||||
{ value: "openai-api-key", label: "OpenAI API key" },
|
||||
{ value: "mistral-api-key", label: "Mistral API key" },
|
||||
{ value: "xai-api-key", label: "xAI (Grok) API key" },
|
||||
{ value: "volcengine-api-key", label: "Volcano Engine API key" },
|
||||
{ value: "byteplus-api-key", label: "BytePlus API key" },
|
||||
|
||||
@@ -29,6 +29,8 @@ import {
|
||||
applyKimiCodeProviderConfig,
|
||||
applyLitellmConfig,
|
||||
applyLitellmProviderConfig,
|
||||
applyMistralConfig,
|
||||
applyMistralProviderConfig,
|
||||
applyMoonshotConfig,
|
||||
applyMoonshotConfigCn,
|
||||
applyMoonshotProviderConfig,
|
||||
@@ -52,6 +54,7 @@ import {
|
||||
QIANFAN_DEFAULT_MODEL_REF,
|
||||
KIMI_CODING_MODEL_REF,
|
||||
MOONSHOT_DEFAULT_MODEL_REF,
|
||||
MISTRAL_DEFAULT_MODEL_REF,
|
||||
SYNTHETIC_DEFAULT_MODEL_REF,
|
||||
TOGETHER_DEFAULT_MODEL_REF,
|
||||
VENICE_DEFAULT_MODEL_REF,
|
||||
@@ -62,6 +65,7 @@ import {
|
||||
setGeminiApiKey,
|
||||
setLitellmApiKey,
|
||||
setKimiCodingApiKey,
|
||||
setMistralApiKey,
|
||||
setMoonshotApiKey,
|
||||
setOpencodeZenApiKey,
|
||||
setSyntheticApiKey,
|
||||
@@ -91,6 +95,7 @@ const API_KEY_TOKEN_PROVIDER_AUTH_CHOICE: Record<string, AuthChoice> = {
|
||||
venice: "venice-api-key",
|
||||
together: "together-api-key",
|
||||
huggingface: "huggingface-api-key",
|
||||
mistral: "mistral-api-key",
|
||||
opencode: "opencode-zen",
|
||||
qianfan: "qianfan-api-key",
|
||||
};
|
||||
@@ -190,6 +195,18 @@ const SIMPLE_API_KEY_PROVIDER_FLOWS: Partial<Record<AuthChoice, SimpleApiKeyProv
|
||||
applyProviderConfig: applyXiaomiProviderConfig,
|
||||
noteDefault: XIAOMI_DEFAULT_MODEL_REF,
|
||||
},
|
||||
"mistral-api-key": {
|
||||
provider: "mistral",
|
||||
profileId: "mistral:default",
|
||||
expectedProviders: ["mistral"],
|
||||
envLabel: "MISTRAL_API_KEY",
|
||||
promptMessage: "Enter Mistral API key",
|
||||
setCredential: setMistralApiKey,
|
||||
defaultModel: MISTRAL_DEFAULT_MODEL_REF,
|
||||
applyDefaultConfig: applyMistralConfig,
|
||||
applyProviderConfig: applyMistralProviderConfig,
|
||||
noteDefault: MISTRAL_DEFAULT_MODEL_REF,
|
||||
},
|
||||
"venice-api-key": {
|
||||
provider: "venice",
|
||||
profileId: "venice:default",
|
||||
|
||||
@@ -20,6 +20,7 @@ const PREFERRED_PROVIDER_BY_AUTH_CHOICE: Partial<Record<AuthChoice, string>> = {
|
||||
"gemini-api-key": "google",
|
||||
"google-antigravity": "google-antigravity",
|
||||
"google-gemini-cli": "google-gemini-cli",
|
||||
"mistral-api-key": "mistral",
|
||||
"zai-api-key": "zai",
|
||||
"zai-coding-global": "zai",
|
||||
"zai-coding-cn": "zai",
|
||||
|
||||
@@ -66,6 +66,7 @@ describe("applyAuthChoice", () => {
|
||||
"AI_GATEWAY_API_KEY",
|
||||
"CLOUDFLARE_AI_GATEWAY_API_KEY",
|
||||
"MOONSHOT_API_KEY",
|
||||
"MISTRAL_API_KEY",
|
||||
"KIMI_API_KEY",
|
||||
"GEMINI_API_KEY",
|
||||
"XIAOMI_API_KEY",
|
||||
@@ -527,6 +528,13 @@ describe("applyAuthChoice", () => {
|
||||
provider: "moonshot",
|
||||
modelPrefix: "moonshot/",
|
||||
},
|
||||
{
|
||||
authChoice: "mistral-api-key",
|
||||
tokenProvider: "mistral",
|
||||
profileId: "mistral:default",
|
||||
provider: "mistral",
|
||||
modelPrefix: "mistral/",
|
||||
},
|
||||
{
|
||||
authChoice: "kimi-code-api-key",
|
||||
tokenProvider: "kimi-code",
|
||||
@@ -1267,6 +1275,10 @@ describe("resolvePreferredProviderForAuthChoice", () => {
|
||||
expect(resolvePreferredProviderForAuthChoice("qwen-portal")).toBe("qwen-portal");
|
||||
});
|
||||
|
||||
it("maps mistral-api-key to the provider", () => {
|
||||
expect(resolvePreferredProviderForAuthChoice("mistral-api-key")).toBe("mistral");
|
||||
});
|
||||
|
||||
it("returns undefined for unknown choices", () => {
|
||||
expect(resolvePreferredProviderForAuthChoice("unknown" as AuthChoice)).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -104,6 +104,28 @@ describe("noteMemorySearchHealth", () => {
|
||||
});
|
||||
expect(note).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("resolves mistral auth for explicit mistral embedding provider", async () => {
|
||||
resolveMemorySearchConfig.mockReturnValue({
|
||||
provider: "mistral",
|
||||
local: {},
|
||||
remote: {},
|
||||
});
|
||||
resolveApiKeyForProvider.mockResolvedValue({
|
||||
apiKey: "k",
|
||||
source: "env: MISTRAL_API_KEY",
|
||||
mode: "api-key",
|
||||
});
|
||||
|
||||
await noteMemorySearchHealth(cfg);
|
||||
|
||||
expect(resolveApiKeyForProvider).toHaveBeenCalledWith({
|
||||
provider: "mistral",
|
||||
cfg,
|
||||
agentDir: "/tmp/agent-default",
|
||||
});
|
||||
expect(note).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("detectLegacyWorkspaceDirs", () => {
|
||||
|
||||
@@ -76,7 +76,7 @@ export async function noteMemorySearchHealth(cfg: OpenClawConfig): Promise<void>
|
||||
if (hasLocalEmbeddings(resolved.local)) {
|
||||
return;
|
||||
}
|
||||
for (const provider of ["openai", "gemini", "voyage"] as const) {
|
||||
for (const provider of ["openai", "gemini", "voyage", "mistral"] as const) {
|
||||
if (hasRemoteApiKey || (await hasApiKeyForProvider(provider, cfg, agentDir))) {
|
||||
return;
|
||||
}
|
||||
@@ -88,7 +88,7 @@ export async function noteMemorySearchHealth(cfg: OpenClawConfig): Promise<void>
|
||||
"Semantic recall will not work without an embedding provider.",
|
||||
"",
|
||||
"Fix (pick one):",
|
||||
"- Set OPENAI_API_KEY or GEMINI_API_KEY in your environment",
|
||||
"- Set OPENAI_API_KEY, GEMINI_API_KEY, VOYAGE_API_KEY, or MISTRAL_API_KEY in your environment",
|
||||
`- Add credentials: ${formatCliCommand("openclaw auth add --provider openai")}`,
|
||||
`- For local embeddings: configure agents.defaults.memorySearch.provider and local model path`,
|
||||
`- To disable: ${formatCliCommand("openclaw config set agents.defaults.memorySearch.enabled false")}`,
|
||||
@@ -119,7 +119,7 @@ function hasLocalEmbeddings(local: { modelPath?: string }): boolean {
|
||||
}
|
||||
|
||||
async function hasApiKeyForProvider(
|
||||
provider: "openai" | "gemini" | "voyage",
|
||||
provider: "openai" | "gemini" | "voyage" | "mistral",
|
||||
cfg: OpenClawConfig,
|
||||
agentDir: string,
|
||||
): Promise<boolean> {
|
||||
|
||||
@@ -31,6 +31,7 @@ import type { OpenClawConfig } from "../config/config.js";
|
||||
import type { ModelApi } from "../config/types.models.js";
|
||||
import {
|
||||
HUGGINGFACE_DEFAULT_MODEL_REF,
|
||||
MISTRAL_DEFAULT_MODEL_REF,
|
||||
OPENROUTER_DEFAULT_MODEL_REF,
|
||||
TOGETHER_DEFAULT_MODEL_REF,
|
||||
XIAOMI_DEFAULT_MODEL_REF,
|
||||
@@ -57,9 +58,12 @@ import {
|
||||
applyProviderConfigWithModelCatalog,
|
||||
} from "./onboard-auth.config-shared.js";
|
||||
import {
|
||||
buildMistralModelDefinition,
|
||||
buildZaiModelDefinition,
|
||||
buildMoonshotModelDefinition,
|
||||
buildXaiModelDefinition,
|
||||
MISTRAL_BASE_URL,
|
||||
MISTRAL_DEFAULT_MODEL_ID,
|
||||
QIANFAN_BASE_URL,
|
||||
QIANFAN_DEFAULT_MODEL_REF,
|
||||
KIMI_CODING_MODEL_ID,
|
||||
@@ -402,6 +406,30 @@ export function applyXaiConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
return applyAgentDefaultModelPrimary(next, XAI_DEFAULT_MODEL_REF);
|
||||
}
|
||||
|
||||
export function applyMistralProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
const models = { ...cfg.agents?.defaults?.models };
|
||||
models[MISTRAL_DEFAULT_MODEL_REF] = {
|
||||
...models[MISTRAL_DEFAULT_MODEL_REF],
|
||||
alias: models[MISTRAL_DEFAULT_MODEL_REF]?.alias ?? "Mistral",
|
||||
};
|
||||
|
||||
const defaultModel = buildMistralModelDefinition();
|
||||
|
||||
return applyProviderConfigWithDefaultModel(cfg, {
|
||||
agentModels: models,
|
||||
providerId: "mistral",
|
||||
api: "openai-completions",
|
||||
baseUrl: MISTRAL_BASE_URL,
|
||||
defaultModel,
|
||||
defaultModelId: MISTRAL_DEFAULT_MODEL_ID,
|
||||
});
|
||||
}
|
||||
|
||||
export function applyMistralConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||
const next = applyMistralProviderConfig(cfg);
|
||||
return applyAgentDefaultModelPrimary(next, MISTRAL_DEFAULT_MODEL_REF);
|
||||
}
|
||||
|
||||
export function applyAuthProfileConfig(
|
||||
cfg: OpenClawConfig,
|
||||
params: {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { resolveOpenClawAgentDir } from "../agents/agent-paths.js";
|
||||
import { upsertAuthProfile } from "../agents/auth-profiles.js";
|
||||
import { resolveStateDir } from "../config/paths.js";
|
||||
export { CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF } from "../agents/cloudflare-ai-gateway.js";
|
||||
export { XAI_DEFAULT_MODEL_REF } from "./onboard-auth.models.js";
|
||||
export { MISTRAL_DEFAULT_MODEL_REF, XAI_DEFAULT_MODEL_REF } from "./onboard-auth.models.js";
|
||||
|
||||
const resolveAuthAgentDir = (agentDir?: string) => agentDir ?? resolveOpenClawAgentDir();
|
||||
|
||||
@@ -360,3 +360,15 @@ export function setXaiApiKey(key: string, agentDir?: string) {
|
||||
agentDir: resolveAuthAgentDir(agentDir),
|
||||
});
|
||||
}
|
||||
|
||||
export async function setMistralApiKey(key: string, agentDir?: string) {
|
||||
upsertAuthProfile({
|
||||
profileId: "mistral:default",
|
||||
credential: {
|
||||
type: "api_key",
|
||||
provider: "mistral",
|
||||
key,
|
||||
},
|
||||
agentDir: resolveAuthAgentDir(agentDir),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -137,6 +137,30 @@ export function buildMoonshotModelDefinition(): ModelDefinitionConfig {
|
||||
};
|
||||
}
|
||||
|
||||
export const MISTRAL_BASE_URL = "https://api.mistral.ai/v1";
|
||||
export const MISTRAL_DEFAULT_MODEL_ID = "mistral-large-latest";
|
||||
export const MISTRAL_DEFAULT_MODEL_REF = `mistral/${MISTRAL_DEFAULT_MODEL_ID}`;
|
||||
export const MISTRAL_DEFAULT_CONTEXT_WINDOW = 262144;
|
||||
export const MISTRAL_DEFAULT_MAX_TOKENS = 262144;
|
||||
export const MISTRAL_DEFAULT_COST = {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
};
|
||||
|
||||
export function buildMistralModelDefinition(): ModelDefinitionConfig {
|
||||
return {
|
||||
id: MISTRAL_DEFAULT_MODEL_ID,
|
||||
name: "Mistral Large",
|
||||
reasoning: false,
|
||||
input: ["text", "image"],
|
||||
cost: MISTRAL_DEFAULT_COST,
|
||||
contextWindow: MISTRAL_DEFAULT_CONTEXT_WINDOW,
|
||||
maxTokens: MISTRAL_DEFAULT_MAX_TOKENS,
|
||||
};
|
||||
}
|
||||
|
||||
export function buildZaiModelDefinition(params: {
|
||||
id: string;
|
||||
name?: string;
|
||||
|
||||
@@ -7,6 +7,8 @@ import type { OpenClawConfig } from "../config/config.js";
|
||||
import {
|
||||
applyAuthProfileConfig,
|
||||
applyLitellmProviderConfig,
|
||||
applyMistralConfig,
|
||||
applyMistralProviderConfig,
|
||||
applyMinimaxApiConfig,
|
||||
applyMinimaxApiProviderConfig,
|
||||
applyOpencodeZenConfig,
|
||||
@@ -22,6 +24,7 @@ import {
|
||||
applyZaiConfig,
|
||||
applyZaiProviderConfig,
|
||||
OPENROUTER_DEFAULT_MODEL_REF,
|
||||
MISTRAL_DEFAULT_MODEL_REF,
|
||||
SYNTHETIC_DEFAULT_MODEL_ID,
|
||||
SYNTHETIC_DEFAULT_MODEL_REF,
|
||||
XAI_DEFAULT_MODEL_REF,
|
||||
@@ -540,9 +543,46 @@ describe("applyXaiProviderConfig", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("applyMistralConfig", () => {
|
||||
it("adds Mistral provider with correct settings", () => {
|
||||
const cfg = applyMistralConfig({});
|
||||
expect(cfg.models?.providers?.mistral).toMatchObject({
|
||||
baseUrl: "https://api.mistral.ai/v1",
|
||||
api: "openai-completions",
|
||||
});
|
||||
expect(cfg.agents?.defaults?.model?.primary).toBe(MISTRAL_DEFAULT_MODEL_REF);
|
||||
});
|
||||
});
|
||||
|
||||
describe("applyMistralProviderConfig", () => {
|
||||
it("merges Mistral models and keeps existing provider overrides", () => {
|
||||
const cfg = applyMistralProviderConfig(
|
||||
createLegacyProviderConfig({
|
||||
providerId: "mistral",
|
||||
api: "anthropic-messages",
|
||||
modelId: "custom-model",
|
||||
modelName: "Custom",
|
||||
}),
|
||||
);
|
||||
|
||||
expect(cfg.models?.providers?.mistral?.baseUrl).toBe("https://api.mistral.ai/v1");
|
||||
expect(cfg.models?.providers?.mistral?.api).toBe("openai-completions");
|
||||
expect(cfg.models?.providers?.mistral?.apiKey).toBe("old-key");
|
||||
expect(cfg.models?.providers?.mistral?.models.map((m) => m.id)).toEqual([
|
||||
"custom-model",
|
||||
"mistral-large-latest",
|
||||
]);
|
||||
const mistralDefault = cfg.models?.providers?.mistral?.models.find(
|
||||
(model) => model.id === "mistral-large-latest",
|
||||
);
|
||||
expect(mistralDefault?.contextWindow).toBe(262144);
|
||||
expect(mistralDefault?.maxTokens).toBe(262144);
|
||||
});
|
||||
});
|
||||
|
||||
describe("fallback preservation helpers", () => {
|
||||
it("preserves existing model fallbacks", () => {
|
||||
const fallbackCases = [applyMinimaxApiConfig, applyXaiConfig] as const;
|
||||
const fallbackCases = [applyMinimaxApiConfig, applyXaiConfig, applyMistralConfig] as const;
|
||||
for (const applyConfig of fallbackCases) {
|
||||
const cfg = applyConfig(createConfigWithFallbacks());
|
||||
expectFallbacksPreserved(cfg);
|
||||
@@ -563,6 +603,11 @@ describe("provider alias defaults", () => {
|
||||
modelRef: XAI_DEFAULT_MODEL_REF,
|
||||
alias: "Grok",
|
||||
},
|
||||
{
|
||||
applyConfig: () => applyMistralProviderConfig({}),
|
||||
modelRef: MISTRAL_DEFAULT_MODEL_REF,
|
||||
alias: "Mistral",
|
||||
},
|
||||
] as const;
|
||||
for (const testCase of aliasCases) {
|
||||
const cfg = testCase.applyConfig();
|
||||
|
||||
@@ -15,6 +15,8 @@ export {
|
||||
applyKimiCodeProviderConfig,
|
||||
applyLitellmConfig,
|
||||
applyLitellmProviderConfig,
|
||||
applyMistralConfig,
|
||||
applyMistralProviderConfig,
|
||||
applyMoonshotConfig,
|
||||
applyMoonshotConfigCn,
|
||||
applyMoonshotProviderConfig,
|
||||
@@ -62,6 +64,7 @@ export {
|
||||
setLitellmApiKey,
|
||||
setKimiCodingApiKey,
|
||||
setMinimaxApiKey,
|
||||
setMistralApiKey,
|
||||
setMoonshotApiKey,
|
||||
setOpencodeZenApiKey,
|
||||
setOpenrouterApiKey,
|
||||
@@ -79,11 +82,13 @@ export {
|
||||
XIAOMI_DEFAULT_MODEL_REF,
|
||||
ZAI_DEFAULT_MODEL_REF,
|
||||
TOGETHER_DEFAULT_MODEL_REF,
|
||||
MISTRAL_DEFAULT_MODEL_REF,
|
||||
XAI_DEFAULT_MODEL_REF,
|
||||
} from "./onboard-auth.credentials.js";
|
||||
export {
|
||||
buildMinimaxApiModelDefinition,
|
||||
buildMinimaxModelDefinition,
|
||||
buildMistralModelDefinition,
|
||||
buildMoonshotModelDefinition,
|
||||
buildZaiModelDefinition,
|
||||
DEFAULT_MINIMAX_BASE_URL,
|
||||
@@ -100,6 +105,8 @@ export {
|
||||
MOONSHOT_BASE_URL,
|
||||
MOONSHOT_DEFAULT_MODEL_ID,
|
||||
MOONSHOT_DEFAULT_MODEL_REF,
|
||||
MISTRAL_BASE_URL,
|
||||
MISTRAL_DEFAULT_MODEL_ID,
|
||||
resolveZaiBaseUrl,
|
||||
ZAI_CODING_CN_BASE_URL,
|
||||
ZAI_DEFAULT_MODEL_ID,
|
||||
|
||||
@@ -253,6 +253,23 @@ describe("onboard (non-interactive): provider auth", () => {
|
||||
});
|
||||
}, 60_000);
|
||||
|
||||
it("infers Mistral auth choice from --mistral-api-key and sets default model", async () => {
|
||||
await withOnboardEnv("openclaw-onboard-mistral-infer-", async (env) => {
|
||||
const cfg = await runOnboardingAndReadConfig(env, {
|
||||
mistralApiKey: "mistral-test-key",
|
||||
});
|
||||
|
||||
expect(cfg.auth?.profiles?.["mistral:default"]?.provider).toBe("mistral");
|
||||
expect(cfg.auth?.profiles?.["mistral:default"]?.mode).toBe("api_key");
|
||||
expect(cfg.agents?.defaults?.model?.primary).toBe("mistral/mistral-large-latest");
|
||||
await expectApiKeyProfile({
|
||||
profileId: "mistral:default",
|
||||
provider: "mistral",
|
||||
key: "mistral-test-key",
|
||||
});
|
||||
});
|
||||
}, 60_000);
|
||||
|
||||
it("stores Volcano Engine API key and sets default model", async () => {
|
||||
await withOnboardEnv("openclaw-onboard-volcengine-", async (env) => {
|
||||
const cfg = await runOnboardingAndReadConfig(env, {
|
||||
|
||||
@@ -12,6 +12,7 @@ type AuthChoiceFlagOptions = Pick<
|
||||
| "anthropicApiKey"
|
||||
| "geminiApiKey"
|
||||
| "openaiApiKey"
|
||||
| "mistralApiKey"
|
||||
| "openrouterApiKey"
|
||||
| "aiGatewayApiKey"
|
||||
| "cloudflareAiGatewayApiKey"
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
applyHuggingfaceConfig,
|
||||
applyVercelAiGatewayConfig,
|
||||
applyLitellmConfig,
|
||||
applyMistralConfig,
|
||||
applyXaiConfig,
|
||||
applyXiaomiConfig,
|
||||
applyZaiConfig,
|
||||
@@ -36,6 +37,7 @@ import {
|
||||
setGeminiApiKey,
|
||||
setKimiCodingApiKey,
|
||||
setLitellmApiKey,
|
||||
setMistralApiKey,
|
||||
setMinimaxApiKey,
|
||||
setMoonshotApiKey,
|
||||
setOpencodeZenApiKey,
|
||||
@@ -304,6 +306,29 @@ export async function applyNonInteractiveAuthChoice(params: {
|
||||
return applyXaiConfig(nextConfig);
|
||||
}
|
||||
|
||||
if (authChoice === "mistral-api-key") {
|
||||
const resolved = await resolveNonInteractiveApiKey({
|
||||
provider: "mistral",
|
||||
cfg: baseConfig,
|
||||
flagValue: opts.mistralApiKey,
|
||||
flagName: "--mistral-api-key",
|
||||
envVar: "MISTRAL_API_KEY",
|
||||
runtime,
|
||||
});
|
||||
if (!resolved) {
|
||||
return null;
|
||||
}
|
||||
if (resolved.source !== "profile") {
|
||||
await setMistralApiKey(resolved.key);
|
||||
}
|
||||
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||
profileId: "mistral:default",
|
||||
provider: "mistral",
|
||||
mode: "api_key",
|
||||
});
|
||||
return applyMistralConfig(nextConfig);
|
||||
}
|
||||
|
||||
if (authChoice === "volcengine-api-key") {
|
||||
const resolved = await resolveNonInteractiveApiKey({
|
||||
provider: "volcengine",
|
||||
|
||||
@@ -4,6 +4,7 @@ type OnboardProviderAuthOptionKey = keyof Pick<
|
||||
OnboardOptions,
|
||||
| "anthropicApiKey"
|
||||
| "openaiApiKey"
|
||||
| "mistralApiKey"
|
||||
| "openrouterApiKey"
|
||||
| "aiGatewayApiKey"
|
||||
| "cloudflareAiGatewayApiKey"
|
||||
@@ -49,6 +50,13 @@ export const ONBOARD_PROVIDER_AUTH_FLAGS: ReadonlyArray<OnboardProviderAuthFlag>
|
||||
cliOption: "--openai-api-key <key>",
|
||||
description: "OpenAI API key",
|
||||
},
|
||||
{
|
||||
optionKey: "mistralApiKey",
|
||||
authChoice: "mistral-api-key",
|
||||
cliFlag: "--mistral-api-key",
|
||||
cliOption: "--mistral-api-key <key>",
|
||||
description: "Mistral API key",
|
||||
},
|
||||
{
|
||||
optionKey: "openrouterApiKey",
|
||||
authChoice: "openrouter-api-key",
|
||||
|
||||
@@ -45,6 +45,7 @@ export type AuthChoice =
|
||||
| "copilot-proxy"
|
||||
| "qwen-portal"
|
||||
| "xai-api-key"
|
||||
| "mistral-api-key"
|
||||
| "volcengine-api-key"
|
||||
| "byteplus-api-key"
|
||||
| "qianfan-api-key"
|
||||
@@ -68,6 +69,7 @@ export type AuthChoiceGroupId =
|
||||
| "minimax"
|
||||
| "synthetic"
|
||||
| "venice"
|
||||
| "mistral"
|
||||
| "qwen"
|
||||
| "together"
|
||||
| "huggingface"
|
||||
@@ -105,6 +107,7 @@ export type OnboardOptions = {
|
||||
tokenExpiresIn?: string;
|
||||
anthropicApiKey?: string;
|
||||
openaiApiKey?: string;
|
||||
mistralApiKey?: string;
|
||||
openrouterApiKey?: string;
|
||||
litellmApiKey?: string;
|
||||
aiGatewayApiKey?: string;
|
||||
|
||||
Reference in New Issue
Block a user