diff --git a/src/providers/registry.ts b/src/providers/registry.ts index 6d84efe529..220e6db34f 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -1265,14 +1265,19 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ baseUrl: "https://api.x.ai/v1", authKind: "oauth", allowKeyAuthOverride: true, - // Priority Processing is documented for xAI's public API-key Chat Completions and - // Responses endpoints. OAuth is a separate Grok CLI subscription gateway and remains - // unclassified; do not turn this into a provider-wide supportsServiceTier declaration. + // Priority Processing is offered on both xAI endpoints — the public api.x.ai key-auth + // lane and the Grok CLI OAuth gateway cli-chat-proxy.grok.com. A 2026-09-09 live probe + // against the OAuth gateway carrying service_tier "priority" completed with + // response.service_tier "priority" while the same request without the field completed + // with "default". Declare Fast support auth-agnostically so OAuth callers (grok-4.6, + // grok-4.5, grok-4.20-*, grok-composer-2.5-fast) can pass a caller/pinned tier through; + // keyAuthServiceTier stays as the chat-encoding carrier for the key lane. + supportsServiceTier: true, keyAuthServiceTier: { supportsServiceTier: true, chatServiceTier: true, }, - fastTierDescription: "Priority processing, 2x token price", + fastTierDescription: "Priority processing; tier pricing applies on key auth only", featured: true, oauthId: "xai", jawcodeBundle: "xai", @@ -1312,20 +1317,21 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ // Grok 4.6/4.5 subscription Responses callers use the native wire with the existing // namespace/web-search/replay normalization. Chat remains an explicit modelAdapters // opt-in. Multi-agent has no Chat wire and uses Responses under both auth modes. - // Caller-owned service tiers stay off the unclassified OAuth subscription route; key-auth - // Fast remains proxy-owned and is still selected through keyAuthServiceTier above. + // The unclassified-subscription comment above is retired: the OAuth Responses gateway + // demonstrably honors service_tier "priority". Caller-owned tiers therefore pass on + // the routes below; no wire default stays drop-for-tiers. modelWireDefaults: { "grok-4.6": { wire: "openai-responses", inbound: ["responses"], authModes: ["oauth"], - forwardCallerServiceTier: false, + forwardCallerServiceTier: true, }, "grok-4.5": { wire: "openai-responses", inbound: ["responses"], authModes: ["oauth"], - forwardCallerServiceTier: false, + forwardCallerServiceTier: true, }, "grok-4.20-multi-agent-0309": { // Even at high effort it emits no reasoning-summary deltas or encrypted replay @@ -1338,7 +1344,7 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ // openai-chat adapter and sent this model to the wire it 400s on. wire: "openai-responses", inbound: ["responses", "chat", "anthropic"], - forwardCallerServiceTier: false, + forwardCallerServiceTier: true, }, }, // Vision lineup per docs.x.ai model-capabilities/images/understanding: the grok-4.x chat diff --git a/tests/routing/fastwire-policy.test.ts b/tests/routing/fastwire-policy.test.ts index e9918dc6ce..5df908bb91 100644 --- a/tests/routing/fastwire-policy.test.ts +++ b/tests/routing/fastwire-policy.test.ts @@ -259,6 +259,9 @@ describe("resolveFastPolicy matrix", () => { test("locks the five-row xAI and DeepSeek wire/tier regression matrix", () => { const rows = [ { + // 2026-09-09 live probe: the OAuth Responses gateway honors service_tier "priority" + // (returns service_tier "priority", matches "default" without the field), so the + // previously drop-by-default OAuth route now forwards caller tiers like key auth. name: "xAI OAuth default", providerName: "xai", modelIds: ["grok-4.6", "grok-4.5"], @@ -268,9 +271,9 @@ describe("resolveFastPolicy matrix", () => { authMode: "oauth" as const, }, adapter: "openai-responses", - forwardCallerTier: false, + forwardCallerTier: true, callerTier: "flex", - settledCallerTier: undefined, + settledCallerTier: "flex", }, { name: "xAI OAuth Responses override", @@ -283,9 +286,9 @@ describe("resolveFastPolicy matrix", () => { modelAdapters: { "grok-4.6": "openai-responses", "grok-4.5": "openai-responses" }, }, adapter: "openai-responses", - forwardCallerTier: false, + forwardCallerTier: true, callerTier: "flex", - settledCallerTier: undefined, + settledCallerTier: "flex", }, { // B2: key-auth Chat Completions is a documented Priority Processing transport. diff --git a/tests/service/service-tier-capability.test.ts b/tests/service/service-tier-capability.test.ts index 4f8161c3e9..0f6b206ef2 100644 --- a/tests/service/service-tier-capability.test.ts +++ b/tests/service/service-tier-capability.test.ts @@ -110,21 +110,22 @@ describe("xAI Fast capability follows the captured authentication transport", () supportsServiceTier: true, chatServiceTier: true, }); - expect(entry.supportsServiceTier).toBeUndefined(); - expect(entry.chatServiceTier).toBeUndefined(); + // Provider-level: after a 2026-09-09 live probe showed the OAuth Responses gateway + // honors service_tier "priority", support is declared auth-agnostically. + expect(entry.supportsServiceTier).toBe(true); const keyPolicy = fastPolicyForModel(xaiProvider("key"), "grok-4.6", "xai"); expect(keyPolicy).toMatchObject({ capability: true, eligibility: "eligible", forwardCallerTier: true, - fastTierDescription: "Priority processing, 2x token price", + fastTierDescription: "Priority processing; tier pricing applies on key auth only", }); const oauthPolicy = fastPolicyForModel(xaiProvider("oauth"), "grok-4.6", "xai"); - expect(oauthPolicy.capability).toBeUndefined(); - expect(oauthPolicy.eligibility).toBe("unclassified"); - expect(oauthPolicy.forwardCallerTier).toBe(false); + expect(oauthPolicy.capability).toBe(true); + expect(oauthPolicy.eligibility).toBe("eligible"); + expect(oauthPolicy.forwardCallerTier).toBe(true); }); test("catalog and runtime publish the same key/OAuth conclusion", async () => { @@ -135,7 +136,7 @@ describe("xAI Fast capability follows the captured authentication transport", () expect(keyCatalog?.service_tiers).toEqual([{ id: "priority", name: "Fast", - description: "Priority processing, 2x token price", + description: "Priority processing; tier pricing applies on key auth only", }]); expect(keyCatalog?.additional_speed_tiers).toEqual(["fast"]); expect(decideTier(keyPolicy, true, undefined)).toEqual({ kind: "set", value: "priority" }); @@ -143,10 +144,16 @@ describe("xAI Fast capability follows the captured authentication transport", () const oauthProvider = xaiProvider("oauth"); const oauthPolicy = fastPolicyForModel(oauthProvider, "grok-4.6", "xai"); const oauthCatalog = await catalogEntry(oauthProvider); - expect(serviceTierSupportFromPolicy(oauthPolicy)).toBe(false); - expect(oauthCatalog).not.toHaveProperty("service_tiers"); - expect(oauthCatalog).not.toHaveProperty("additional_speed_tiers"); - expect(decideTier(oauthPolicy, true, undefined)).toEqual({ kind: "drop" }); + // With auth-agnostic supportsServiceTier the OAuth row now publishes the same Fast + // capability as key auth, and a caller tier is forwarded rather than dropped. + expect(serviceTierSupportFromPolicy(oauthPolicy)).toBe(true); + expect(oauthCatalog?.service_tiers).toEqual([{ + id: "priority", + name: "Fast", + description: "Priority processing; tier pricing applies on key auth only", + }]); + expect(oauthCatalog?.additional_speed_tiers).toEqual(["fast"]); + expect(decideTier(oauthPolicy, true, undefined)).toEqual({ kind: "set", value: "priority" }); }); test("explicit supportsServiceTier=false wins in policy and catalog for both transports", async () => {