diff --git a/src/config/codexProviderPresets.ts b/src/config/codexProviderPresets.ts index 5d19dc501..c1a212109 100644 --- a/src/config/codexProviderPresets.ts +++ b/src/config/codexProviderPresets.ts @@ -999,6 +999,30 @@ requires_openai_auth = true`, icon: "novita", iconColor: "#000000", }, + { + name: "xAI (Grok)", + websiteUrl: "https://x.ai/api", + apiKeyUrl: "https://console.x.ai", + auth: generateThirdPartyAuth(""), + config: generateThirdPartyConfig("xai", "https://api.x.ai/v1", "grok-4.5"), + endpointCandidates: ["https://api.x.ai/v1"], + // xAI 官方以 /v1/responses 为一等端点(docs.x.ai api-reference):Codex 硬依赖的 + // store:false / include=["reasoning.encrypted_content"] / reasoning effort 均支持, + // 原生 Responses,无需路由接管转换 + apiFormat: "openai_responses", + modelCatalog: modelCatalog([ + { + model: "grok-4.5", + displayName: "Grok 4.5", + contextWindow: 500000, + supportsParallelToolCalls: true, + inputModalities: ["text", "image"], + }, + ]), + category: "third_party", + icon: "xai", + iconColor: "#000000", + }, { name: "Nvidia", websiteUrl: "https://build.nvidia.com", diff --git a/tests/config/xaiOauthProviderPresets.test.ts b/tests/config/xaiOauthProviderPresets.test.ts index ccf54d6a6..acf66f225 100644 --- a/tests/config/xaiOauthProviderPresets.test.ts +++ b/tests/config/xaiOauthProviderPresets.test.ts @@ -1,6 +1,12 @@ import { describe, expect, it } from "vitest"; import { claudeDesktopProviderPresets } from "@/config/claudeDesktopProviderPresets"; import { providerPresets } from "@/config/claudeProviderPresets"; +import { codexProviderPresets } from "@/config/codexProviderPresets"; +import { + extractCodexBaseUrl, + extractCodexModelName, + extractCodexWireApi, +} from "@/utils/providerConfigUtils"; describe("xAI OAuth provider presets", () => { it("pins the Claude Code preset to managed Responses auth", () => { @@ -48,4 +54,30 @@ describe("xAI OAuth provider presets", () => { }), ]); }); + + it("pins the Codex preset to native Responses via API key (no managed OAuth)", () => { + const preset = codexProviderPresets.find( + (entry) => entry.name === "xAI (Grok)", + ); + expect(preset).toBeDefined(); + expect(preset).toMatchObject({ + category: "third_party", + apiFormat: "openai_responses", + icon: "xai", + }); + // API-key preset: managed-account OAuth is Claude-side only for now. + expect(preset).not.toHaveProperty("providerType"); + expect(preset!.auth).toEqual({ OPENAI_API_KEY: "" }); + expect(extractCodexBaseUrl(preset!.config)).toBe("https://api.x.ai/v1"); + expect(extractCodexWireApi(preset!.config)).toBe("responses"); + expect(extractCodexModelName(preset!.config)).toBe("grok-4.5"); + expect(preset!.modelCatalog).toEqual([ + expect.objectContaining({ + model: "grok-4.5", + contextWindow: 500000, + supportsParallelToolCalls: true, + inputModalities: ["text", "image"], + }), + ]); + }); });