|
| 1 | +import { describe, expect, test } from "bun:test"; |
| 2 | +import { createOpenAIChatAdapter } from "../src/adapters/openai-chat"; |
| 3 | +import { buildModelsRequest } from "../src/oauth"; |
| 4 | +import { |
| 5 | + resolveProviderTransport, |
| 6 | + XAI_GROK_CLI_BASE_URL, |
| 7 | + XAI_GROK_CLIENT_VERSION, |
| 8 | +} from "../src/providers/xai-transport"; |
| 9 | +import type { OcxParsedRequest, OcxProviderConfig } from "../src/types"; |
| 10 | + |
| 11 | +function provider(authMode: "oauth" | "key"): OcxProviderConfig { |
| 12 | + return { |
| 13 | + adapter: "openai-chat", |
| 14 | + baseUrl: "https://api.x.ai/v1", |
| 15 | + authMode, |
| 16 | + apiKey: authMode === "oauth" ? "oauth-token" : "xai-api-key", |
| 17 | + defaultModel: "grok-4.5", |
| 18 | + }; |
| 19 | +} |
| 20 | + |
| 21 | +function parsed(): OcxParsedRequest { |
| 22 | + return { |
| 23 | + modelId: "grok-4.5", |
| 24 | + context: { messages: [{ role: "user", content: "hi", timestamp: 0 }] }, |
| 25 | + stream: false, |
| 26 | + options: { reasoning: "low" }, |
| 27 | + }; |
| 28 | +} |
| 29 | + |
| 30 | +describe("xAI auth-mode transport selection", () => { |
| 31 | + test("OAuth selects the Grok CLI subscription transport and required headers", () => { |
| 32 | + const effective = resolveProviderTransport("xai", provider("oauth")); |
| 33 | + const request = createOpenAIChatAdapter(effective).buildRequest(parsed()); |
| 34 | + |
| 35 | + expect(effective.baseUrl).toBe(XAI_GROK_CLI_BASE_URL); |
| 36 | + expect(request.url).toBe(`${XAI_GROK_CLI_BASE_URL}/chat/completions`); |
| 37 | + expect(request.headers).toMatchObject({ |
| 38 | + Authorization: "Bearer oauth-token", |
| 39 | + "x-grok-client-identifier": "opencodex", |
| 40 | + "x-grok-client-version": XAI_GROK_CLIENT_VERSION, |
| 41 | + "x-xai-token-auth": "xai-grok-cli", |
| 42 | + }); |
| 43 | + }); |
| 44 | + |
| 45 | + test("OAuth model discovery uses the subscription transport", () => { |
| 46 | + const request = buildModelsRequest(provider("oauth"), "oauth-token", "xai"); |
| 47 | + |
| 48 | + expect(request.url).toBe(`${XAI_GROK_CLI_BASE_URL}/models`); |
| 49 | + expect(request.headers).toMatchObject({ |
| 50 | + Authorization: "Bearer oauth-token", |
| 51 | + "x-grok-client-identifier": "opencodex", |
| 52 | + "x-grok-client-version": XAI_GROK_CLIENT_VERSION, |
| 53 | + "x-xai-token-auth": "xai-grok-cli", |
| 54 | + }); |
| 55 | + }); |
| 56 | + |
| 57 | + test("API key keeps the xAI API transport without subscription headers", () => { |
| 58 | + const configured = provider("key"); |
| 59 | + const effective = resolveProviderTransport("xai", configured); |
| 60 | + const request = createOpenAIChatAdapter(effective).buildRequest(parsed()); |
| 61 | + const modelsRequest = buildModelsRequest(configured, "xai-api-key", "xai"); |
| 62 | + |
| 63 | + expect(effective).toBe(configured); |
| 64 | + expect(request.url).toBe("https://api.x.ai/v1/chat/completions"); |
| 65 | + expect(modelsRequest.url).toBe("https://api.x.ai/v1/models"); |
| 66 | + expect(request.headers).toEqual({ |
| 67 | + "Content-Type": "application/json", |
| 68 | + Authorization: "Bearer xai-api-key", |
| 69 | + }); |
| 70 | + expect(modelsRequest.headers).toEqual({ Authorization: "Bearer xai-api-key" }); |
| 71 | + }); |
| 72 | + |
| 73 | + test("custom providers and configured header overrides remain untouched", () => { |
| 74 | + const custom = provider("oauth"); |
| 75 | + custom.headers = { "x-grok-client-version": "0.2.94", "x-custom": "kept" }; |
| 76 | + |
| 77 | + expect(resolveProviderTransport("custom-xai", custom)).toBe(custom); |
| 78 | + expect(resolveProviderTransport("xai", custom).headers).toMatchObject({ |
| 79 | + "x-grok-client-version": "0.2.94", |
| 80 | + "x-custom": "kept", |
| 81 | + "x-grok-client-identifier": "opencodex", |
| 82 | + "x-xai-token-auth": "xai-grok-cli", |
| 83 | + }); |
| 84 | + }); |
| 85 | +}); |
0 commit comments