diff --git a/src/config/claudeDesktopProviderPresets.ts b/src/config/claudeDesktopProviderPresets.ts index 0bb548ec6..c082ce700 100644 --- a/src/config/claudeDesktopProviderPresets.ts +++ b/src/config/claudeDesktopProviderPresets.ts @@ -56,7 +56,7 @@ export interface ClaudeDesktopProviderPreset { mode: "direct" | "proxy"; apiFormat?: ClaudeDesktopApiFormat; modelRoutes?: ClaudeDesktopRoutePreset[]; - providerType?: "github_copilot" | "codex_oauth"; + providerType?: "github_copilot" | "codex_oauth" | "xai_oauth"; requiresOAuth?: boolean; endpointCandidates?: string[]; @@ -398,6 +398,19 @@ export const claudeDesktopProviderPresets: ClaudeDesktopProviderPreset[] = [ icon: "openai", iconColor: "#000000", }, + { + name: "xAI (Grok)", + websiteUrl: "https://x.ai/grok", + category: "third_party", + baseUrl: "https://api.x.ai/v1", + mode: "proxy", + apiFormat: "openai_responses", + providerType: "xai_oauth", + requiresOAuth: true, + modelRoutes: brandedRoutes("grok-4.5", "grok-4.5", "grok-4.5"), + icon: "xai", + iconColor: "#000000", + }, { name: "DeepSeek", websiteUrl: "https://platform.deepseek.com", diff --git a/src/config/claudeProviderPresets.ts b/src/config/claudeProviderPresets.ts index 9673ecc6a..f13b8171d 100644 --- a/src/config/claudeProviderPresets.ts +++ b/src/config/claudeProviderPresets.ts @@ -60,7 +60,7 @@ export interface ProviderPreset { // 供应商类型标识(用于特殊供应商检测) // - "github_copilot": GitHub Copilot 供应商(需要 OAuth 认证) // - "codex_oauth": OpenAI Codex via ChatGPT Plus/Pro 反代(需要 OAuth 认证) - providerType?: "github_copilot" | "codex_oauth"; + providerType?: "github_copilot" | "codex_oauth" | "xai_oauth"; // 是否需要 OAuth 认证(而非 API Key) requiresOAuth?: boolean; @@ -1269,6 +1269,26 @@ export const providerPresets: ProviderPreset[] = [ icon: "openai", iconColor: "#000000", }, + { + name: "xAI (Grok)", + websiteUrl: "https://x.ai/grok", + settingsConfig: { + env: { + // The proxy enforces both this origin and the Responses wire format. + ANTHROPIC_BASE_URL: "https://api.x.ai/v1", + ANTHROPIC_MODEL: "grok-4.5", + ANTHROPIC_DEFAULT_HAIKU_MODEL: "grok-4.5", + ANTHROPIC_DEFAULT_SONNET_MODEL: "grok-4.5", + ANTHROPIC_DEFAULT_OPUS_MODEL: "grok-4.5", + }, + }, + category: "third_party", + apiFormat: "openai_responses", + providerType: "xai_oauth", + requiresOAuth: true, + icon: "xai", + iconColor: "#000000", + }, { name: "Nvidia", websiteUrl: "https://build.nvidia.com", diff --git a/src/config/constants.ts b/src/config/constants.ts index c4ae2143f..db5258e68 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -2,6 +2,7 @@ export const PROVIDER_TYPES = { GITHUB_COPILOT: "github_copilot", CODEX_OAUTH: "codex_oauth", + XAI_OAUTH: "xai_oauth", } as const; // 用量脚本模板类型常量 diff --git a/tests/config/xaiOauthProviderPresets.test.ts b/tests/config/xaiOauthProviderPresets.test.ts new file mode 100644 index 000000000..ccf54d6a6 --- /dev/null +++ b/tests/config/xaiOauthProviderPresets.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, it } from "vitest"; +import { claudeDesktopProviderPresets } from "@/config/claudeDesktopProviderPresets"; +import { providerPresets } from "@/config/claudeProviderPresets"; + +describe("xAI OAuth provider presets", () => { + it("pins the Claude Code preset to managed Responses auth", () => { + const preset = providerPresets.find((entry) => entry.name === "xAI (Grok)"); + expect(preset).toBeDefined(); + expect(preset).toMatchObject({ + category: "third_party", + apiFormat: "openai_responses", + providerType: "xai_oauth", + requiresOAuth: true, + icon: "xai", + }); + expect((preset!.settingsConfig as any).env).toMatchObject({ + ANTHROPIC_BASE_URL: "https://api.x.ai/v1", + ANTHROPIC_MODEL: "grok-4.5", + ANTHROPIC_DEFAULT_HAIKU_MODEL: "grok-4.5", + ANTHROPIC_DEFAULT_SONNET_MODEL: "grok-4.5", + ANTHROPIC_DEFAULT_OPUS_MODEL: "grok-4.5", + }); + expect((preset!.settingsConfig as any).env).not.toHaveProperty( + "ANTHROPIC_API_KEY", + ); + expect((preset!.settingsConfig as any).env).not.toHaveProperty( + "ANTHROPIC_AUTH_TOKEN", + ); + }); + + it("pins the Claude Desktop preset to proxy Responses mode without 1M", () => { + const preset = claudeDesktopProviderPresets.find( + (entry) => entry.name === "xAI (Grok)", + ); + expect(preset).toMatchObject({ + category: "third_party", + baseUrl: "https://api.x.ai/v1", + mode: "proxy", + apiFormat: "openai_responses", + providerType: "xai_oauth", + requiresOAuth: true, + icon: "xai", + }); + expect(preset!.modelRoutes).toEqual([ + expect.objectContaining({ + upstreamModel: "grok-4.5", + supports1m: false, + }), + ]); + }); +});