From b0602491b85bef40416bd97909d36c196f337ed6 Mon Sep 17 00:00:00 2001 From: olddonkey Date: Tue, 18 Aug 2026 15:52:49 -0700 Subject: [PATCH 1/2] fix(chat): apply the Fast capability gate to the native passthrough MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The native /v1/chat/completions passthrough decided service-tier forwarding with a single provider-level check: if (provider.chatServiceTier && rawBody.service_tier !== undefined) That bypassed the FastWire policy layer entirely, and the worst consequence was not the one A0 recorded. An explicit supportsServiceTier: false — the fail-closed declaration meaning "this upstream is documented not to accept the field" — was ignored here, so a caller tier still reached that upstream whenever chatServiceTier happened to be true. Exact-model false was likewise ignored (the bug A0 locked), and B1's split between capability-authorized canonical Fast and CallerTierForward-authorized foreign tiers never reached this surface. Both Chat surfaces now call one shared gate, so they cannot drift apart by construction rather than by convention. The passthrough resolves its policy in chat-native.ts, where the route and config already live, and the key-rotation rebuild path resolves it too. What deliberately still differs: the Responses surface normalizes a caller's "fast" spelling to the provider's canonical wire value, while the passthrough forwards the caller's exact bytes. That is this builder's documented contract — caller fields retain their exact wire representation while capability gates stay centralized — and the difference is now asserted by a test and explained at the call site, so a future reader does not mistake it for a missed translation. Known gap, left for its own unit: the passthrough neither runs through the adapter registry decorator nor calls recordAdapterTier, so it produces no AttemptTierOutcome and a stripped tier is not yet visible as callerTierDropped. Building half of that pipeline here would have been worse than naming it. Full suite: 13332 pass / 10 skip / 2 fail — the pre-existing dev-side key-login-live-update regression, and one load-sensitive codex-shim timeout that passes in isolation (69 pass). Co-Authored-By: Claude Fable 5 --- src/adapters/openai-chat.ts | 40 +++- src/server/chat-native.ts | 12 +- tests/fastwire-characterization-wire.test.ts | 26 ++- tests/openai-chat-native-policy.test.ts | 221 +++++++++++++++++++ tests/openrouter-provider-routing.test.ts | 3 +- 5 files changed, 280 insertions(+), 22 deletions(-) create mode 100644 tests/openai-chat-native-policy.test.ts diff --git a/src/adapters/openai-chat.ts b/src/adapters/openai-chat.ts index a6d13fa1f4..b565f1f14d 100644 --- a/src/adapters/openai-chat.ts +++ b/src/adapters/openai-chat.ts @@ -19,6 +19,7 @@ import { import { canonicalFastTierMarker, createAdapterTierMetadata, + type ResolvedFastPolicy, } from "../providers/fastwire"; import { openaiChatCompletionsUrl } from "./openai-chat-url"; import { stripResponsesOnlyEncryptedMarker } from "./responses-tool-schema"; @@ -95,6 +96,7 @@ export function buildOpenAIChatPassthroughRequest( rawBody: Record, modelId: string, stream: boolean, + fastPolicy: ResolvedFastPolicy, ): AdapterRequest { const { url, headers, hasCredential } = openAIChatTransport(provider); @@ -118,7 +120,10 @@ export function buildOpenAIChatPassthroughRequest( } if (modelInList(provider.noStructuredOutputModels, modelId)) delete body.response_format; - if (provider.chatServiceTier && rawBody.service_tier !== undefined) { + // Share the ordinary openai-chat adapter's capability gate, while preserving the + // caller's exact wire representation promised by this passthrough contract. The + // Responses surface may normalize canonical Fast spelling; this difference is intentional. + if (canSerializeOpenAIChatServiceTier(provider, modelId, rawBody.service_tier, undefined, fastPolicy)) { body.service_tier = rawBody.service_tier; } if (provider.promptCacheKey && rawBody.prompt_cache_key !== undefined) { @@ -1280,6 +1285,26 @@ function thinkingBudgetForEffort(parsed: OcxParsedRequest, reasoningEffort: stri return fraction === undefined ? undefined : Math.max(1, Math.floor(maxBudget * fraction)); } +function canSerializeOpenAIChatServiceTier( + provider: OcxProviderConfig, + modelId: string, + serviceTier: unknown, + tierDecision?: OcxParsedRequest["options"]["tierDecision"], + resolvedPolicy?: Pick, +): boolean { + if (serviceTier === undefined) return false; + if (tierDecision !== undefined) { + return tierDecision.kind === "set" || tierDecision.kind === "forward-caller"; + } + const callerTier = typeof serviceTier === "string" ? serviceTier : undefined; + const callerCanonicalFast = canonicalFastTierMarker(callerTier) !== undefined; + const capability = resolvedPolicy === undefined + ? supportsServiceTierForModel(provider, modelId) + : resolvedPolicy.capability; + const callerTierForwardAllowed = canForwardForeignServiceTierForChatModel(provider, modelId); + return callerTierForwardAllowed || (callerCanonicalFast && capability === true); +} + export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAdapter { return { name: "openai-chat", @@ -1302,13 +1327,12 @@ export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAd // unclassified Chat routes remain behind the caller-forwarding opt-in. const serviceTier = parsed.options.serviceTier; const tierDecision = parsed.options.tierDecision; - const callerCanonicalFast = canonicalFastTierMarker(serviceTier) !== undefined; - const callerTierForwardAllowed = canForwardForeignServiceTierForChatModel(provider, parsed.modelId); - const canonicalFastCapability = callerCanonicalFast - && supportsServiceTierForModel(provider, parsed.modelId) === true; - const canSerializeServiceTier = tierDecision?.kind === "set" - || tierDecision?.kind === "forward-caller" - || (tierDecision === undefined && (callerTierForwardAllowed || canonicalFastCapability)); + const canSerializeServiceTier = canSerializeOpenAIChatServiceTier( + provider, + parsed.modelId, + serviceTier, + tierDecision, + ); if (canSerializeServiceTier && serviceTier !== undefined) { body.service_tier = serviceTier; } diff --git a/src/server/chat-native.ts b/src/server/chat-native.ts index cc6738b313..5aa4a89cf8 100644 --- a/src/server/chat-native.ts +++ b/src/server/chat-native.ts @@ -27,6 +27,7 @@ import { rateLimitRetryPolicyFor, rotateProviderTransportOn429, } from "../providers/key-failover"; +import { fastPolicyForModel } from "../providers/service-tier"; import type { RouteResult } from "../router"; import type { OcxConfig, OcxProviderConfig } from "../types"; import { fetchWithHeaderTimeout, providerFetch, safeHostLabel } from "./responses/fetch-helpers"; @@ -154,8 +155,15 @@ export async function handleNativeChatCompletions(options: HandleNativeChatOptio translatorBudget.chargeRetained(bytes, { kind: "request_copies" }); retainedRequestBytes = bytes; }; + const buildActiveRequest = () => buildOpenAIChatPassthroughRequest( + activeProvider, + options.chatBody, + route.modelId, + requestedStream, + fastPolicyForModel(activeProvider, route.modelId, route.providerName, "chat"), + ); try { - activeRequest = buildOpenAIChatPassthroughRequest(activeProvider, options.chatBody, route.modelId, requestedStream); + activeRequest = buildActiveRequest(); retainRequest(activeRequest); } catch (error) { releaseRetainedRequest(); @@ -222,7 +230,7 @@ export async function handleNativeChatCompletions(options: HandleNativeChatOptio activeProvider = rotated; activeAdapter = createOpenAIChatAdapter(activeProvider); releaseRetainedRequest(); - activeRequest = buildOpenAIChatPassthroughRequest(activeProvider, options.chatBody, route.modelId, requestedStream); + activeRequest = buildActiveRequest(); retainRequest(activeRequest); response = await send(activeRequest, "key-429"); } diff --git a/tests/fastwire-characterization-wire.test.ts b/tests/fastwire-characterization-wire.test.ts index 0b4e89fbf3..4ae9e38242 100644 --- a/tests/fastwire-characterization-wire.test.ts +++ b/tests/fastwire-characterization-wire.test.ts @@ -1,6 +1,7 @@ import { afterEach, describe, expect, spyOn, test } from "bun:test"; import { buildOpenAIChatPassthroughRequest } from "../src/adapters/openai-chat"; import { chatCompletionsToResponsesBody } from "../src/chat/inbound"; +import { fastPolicyForModel } from "../src/providers/service-tier"; import * as adapterResolveModule from "../src/server/adapter-resolve"; import type { RequestLogContext } from "../src/server/request-log"; import { handleResponses } from "../src/server/responses/core"; @@ -364,17 +365,19 @@ describe("FastWire characterization: rawBody observation point", () => { }); describe("FastWire characterization: known bugs", () => { - test("characterization (known bug): native chat passthrough ignores exact-model false", () => { + test("characterization: native chat passthrough honors exact-model false", () => { + // FastWire #1886 native-chat policy fix: exact-model false now strips the caller tier. + const provider: OcxProviderConfig = { + adapter: "openai-chat", + baseUrl: "https://native-chat.example.test/v1", + authMode: "key", + apiKey: "sk-test", + supportsServiceTier: true, + chatServiceTier: true, + modelSupportsServiceTier: { model: false }, + }; const request = buildOpenAIChatPassthroughRequest( - { - adapter: "openai-chat", - baseUrl: "https://native-chat.example.test/v1", - authMode: "key", - apiKey: "sk-test", - supportsServiceTier: true, - chatServiceTier: true, - modelSupportsServiceTier: { model: false }, - }, + provider, { model: "model", messages: [{ role: "user", content: "ping" }], @@ -382,9 +385,10 @@ describe("FastWire characterization: known bugs", () => { }, "model", false, + fastPolicyForModel(provider, "model", "native-chat", "chat"), ); const body = JSON.parse(request.body) as Record; - expect(body.service_tier).toBe("flex"); + expect(body).not.toHaveProperty("service_tier"); }); test("characterization: chat-to-responses conversion preserves service_tier", () => { diff --git a/tests/openai-chat-native-policy.test.ts b/tests/openai-chat-native-policy.test.ts new file mode 100644 index 0000000000..4910652cae --- /dev/null +++ b/tests/openai-chat-native-policy.test.ts @@ -0,0 +1,221 @@ +import { afterEach, describe, expect, test } from "bun:test"; +import { + buildOpenAIChatPassthroughRequest, + createOpenAIChatAdapter, +} from "../src/adapters/openai-chat"; +import { + decideTier, + tierValueAfterDecision, +} from "../src/providers/fastwire"; +import { fastPolicyForModel } from "../src/providers/service-tier"; +import { handleChatCompletions } from "../src/server/chat-completions"; +import type { OcxConfig, OcxParsedRequest, OcxProviderConfig } from "../src/types"; + +const PROVIDER_NAME = "native-tier-fixture"; +const MODEL_ID = "model"; +const originalFetch = globalThis.fetch; + +afterEach(() => { + globalThis.fetch = originalFetch; +}); + +function provider(overrides: Partial = {}): OcxProviderConfig { + return { + adapter: "openai-chat", + baseUrl: "https://native-tier.example.test/v1", + authMode: "key", + apiKey: "sk-test", + ...overrides, + }; +} + +function nativeBody( + target: OcxProviderConfig, + callerTier: string, + modelId = MODEL_ID, +): Record { + const policy = fastPolicyForModel(target, modelId, PROVIDER_NAME, "chat"); + const request = buildOpenAIChatPassthroughRequest( + target, + { + model: modelId, + messages: [{ role: "user", content: "ping" }], + service_tier: callerTier, + }, + modelId, + false, + policy, + ); + return JSON.parse(request.body) as Record; +} + +function mainPathBody( + target: OcxProviderConfig, + callerTier: string, + modelId = MODEL_ID, +): Record { + const policy = fastPolicyForModel(target, modelId, PROVIDER_NAME, "chat"); + const tierDecision = decideTier(policy, undefined, callerTier); + const serviceTier = tierValueAfterDecision(tierDecision, callerTier); + const parsed: OcxParsedRequest = { + modelId, + stream: false, + context: { messages: [{ role: "user", content: "ping" }], tools: [] }, + options: { + ...(serviceTier === undefined ? {} : { serviceTier }), + tierDecision, + }, + }; + const request = createOpenAIChatAdapter(target).buildRequest(parsed); + return JSON.parse(request.body) as Record; +} + +function forwardsTier(body: Record): boolean { + return Object.hasOwn(body, "service_tier"); +} + +describe("native Chat passthrough service-tier policy", () => { + test.each([ + { + name: "provider false stays fail-closed even with CallerTierForward", + config: { supportsServiceTier: false, chatServiceTier: true }, + callerTier: "priority", + expectedTier: undefined, + }, + { + name: "exact-model false narrows provider support", + config: { + supportsServiceTier: true, + chatServiceTier: true, + modelSupportsServiceTier: { [MODEL_ID]: false }, + }, + callerTier: "priority", + expectedTier: undefined, + }, + { + name: "exact-model true authorizes canonical Fast without CallerTierForward", + config: { modelSupportsServiceTier: { [MODEL_ID]: true } }, + callerTier: "FAST", + expectedTier: "FAST", + }, + { + name: "exact-model true does not authorize a foreign tier", + config: { modelSupportsServiceTier: { [MODEL_ID]: true } }, + callerTier: "flex", + expectedTier: undefined, + }, + { + name: "unclassified support drops a caller tier without CallerTierForward", + config: {}, + callerTier: "flex", + expectedTier: undefined, + }, + { + name: "unclassified support forwards a caller tier with CallerTierForward", + config: { chatServiceTier: true }, + callerTier: "flex", + expectedTier: "flex", + }, + ] as const)("$name", ({ config, callerTier, expectedTier }) => { + const body = nativeBody(provider(config), callerTier); + if (expectedTier === undefined) expect(body).not.toHaveProperty("service_tier"); + else expect(body.service_tier).toBe(expectedTier); + }); + + test("the native handler passes its resolved fail-closed policy to the builder", async () => { + const captured: Record[] = []; + globalThis.fetch = (async (_input: RequestInfo | URL, init?: RequestInit) => { + captured.push(JSON.parse(String(init?.body ?? "{}")) as Record); + return Response.json({ + id: "chatcmpl_native_tier", + object: "chat.completion", + choices: [{ index: 0, message: { role: "assistant", content: "ok" }, finish_reason: "stop" }], + }); + }) as typeof fetch; + const target = provider({ supportsServiceTier: false, chatServiceTier: true }); + const config = { + port: 0, + defaultProvider: PROVIDER_NAME, + providers: { [PROVIDER_NAME]: target }, + } as OcxConfig; + + const response = await handleChatCompletions( + new Request("http://localhost/v1/chat/completions", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + model: `${PROVIDER_NAME}/${MODEL_ID}`, + messages: [{ role: "user", content: "ping" }], + service_tier: "priority", + }), + }), + config, + { model: "", provider: "" }, + ); + + expect(response.status).toBe(200); + expect(captured).toHaveLength(1); + expect(captured[0]).not.toHaveProperty("service_tier"); + }); +}); + +describe("main and native Chat tier authorization parity", () => { + test.each([ + { + name: "provider fail-closed", + config: { supportsServiceTier: false, chatServiceTier: true }, + callerTier: "priority", + forwarded: false, + }, + { + name: "exact-model fail-closed", + config: { + supportsServiceTier: true, + chatServiceTier: true, + modelSupportsServiceTier: { [MODEL_ID]: false }, + }, + callerTier: "priority", + forwarded: false, + }, + { + name: "exact-model canonical Fast", + config: { modelSupportsServiceTier: { [MODEL_ID]: true } }, + callerTier: "fast", + forwarded: true, + mainTier: "priority", + nativeTier: "fast", + }, + { + name: "exact-model foreign tier", + config: { modelSupportsServiceTier: { [MODEL_ID]: true } }, + callerTier: "flex", + forwarded: false, + }, + { + name: "unclassified without CallerTierForward", + config: {}, + callerTier: "priority", + forwarded: false, + }, + { + name: "unclassified with CallerTierForward", + config: { chatServiceTier: true }, + callerTier: "flex", + forwarded: true, + mainTier: "flex", + nativeTier: "flex", + }, + ] as const)("$name makes the same forward/drop decision", row => { + const target = provider(row.config); + const main = mainPathBody(target, row.callerTier); + const native = nativeBody(target, row.callerTier); + + expect(forwardsTier(main)).toBe(row.forwarded); + expect(forwardsTier(native)).toBe(row.forwarded); + expect(forwardsTier(native)).toBe(forwardsTier(main)); + if (row.forwarded) { + expect(main.service_tier).toBe(row.mainTier); + expect(native.service_tier).toBe(row.nativeTier); + } + }); +}); diff --git a/tests/openrouter-provider-routing.test.ts b/tests/openrouter-provider-routing.test.ts index b6ee368f3f..7a833a5b7a 100644 --- a/tests/openrouter-provider-routing.test.ts +++ b/tests/openrouter-provider-routing.test.ts @@ -7,6 +7,7 @@ import { openRouterRoutingConfigError, openRouterProviderPayload, } from "../src/providers/openrouter-routing"; +import { fastPolicyForModel } from "../src/providers/service-tier"; import { clearKeyCooldowns, rotateProviderTransportOn429 } from "../src/providers/key-failover"; import { routeModel } from "../src/router"; import { providerManagementConfigError, safeConfigDTO } from "../src/server/auth-cors"; @@ -39,7 +40,7 @@ function passthroughBody( const request = buildOpenAIChatPassthroughRequest(providerConfig, { messages: [{ role: "user", content: "hello" }], ...rawBody, - }, modelId, false); + }, modelId, false, fastPolicyForModel(providerConfig, modelId, undefined, "chat")); return JSON.parse(request.body as string) as Record; } From 01c823e2485311a1ef9aaf656d6ce879e76bdda0 Mon Sep 17 00:00:00 2001 From: olddonkey Date: Tue, 18 Aug 2026 22:55:45 -0700 Subject: [PATCH 2/2] fix(chat): align native passthrough tier policy --- src/adapters/openai-chat.ts | 24 +++-- src/server/chat-native.ts | 1 + tests/openai-chat-native-policy.test.ts | 128 +++++++++++++++++++++++- 3 files changed, 140 insertions(+), 13 deletions(-) diff --git a/src/adapters/openai-chat.ts b/src/adapters/openai-chat.ts index a42c74963b..3ce0e9214d 100644 --- a/src/adapters/openai-chat.ts +++ b/src/adapters/openai-chat.ts @@ -14,11 +14,13 @@ import { buildNonOpenAIToolCatalogNudgeForTools, shouldInjectNonOpenAIToolCatalo import { openRouterProviderPayload, resolveOpenRouterRouting } from "../providers/openrouter-routing"; import { canForwardForeignServiceTierForChatModel, + fastPolicyForModel, supportsServiceTierForModel, } from "../providers/service-tier"; import { canonicalFastTierMarker, createAdapterTierMetadata, + decideTier, type ResolvedFastPolicy, } from "../providers/fastwire"; import { openaiChatCompletionsUrl } from "./openai-chat-url"; @@ -96,7 +98,8 @@ export function buildOpenAIChatPassthroughRequest( rawBody: Record, modelId: string, stream: boolean, - fastPolicy: ResolvedFastPolicy, + fastPolicy: ResolvedFastPolicy = fastPolicyForModel(provider, modelId, undefined, "chat"), + fastMode?: boolean, ): AdapterRequest { const { url, headers, hasCredential } = openAIChatTransport(provider); @@ -124,10 +127,16 @@ export function buildOpenAIChatPassthroughRequest( // `:` siblings the operator never opted out, silently returning prose. if (provider.noStructuredOutputModels?.includes(modelId)) delete body.response_format; - // Share the ordinary openai-chat adapter's capability gate, while preserving the - // caller's exact wire representation promised by this passthrough contract. The - // Responses surface may normalize canonical Fast spelling; this difference is intentional. - if (canSerializeOpenAIChatServiceTier(provider, modelId, rawBody.service_tier, undefined, fastPolicy)) { + // Run the same complete Fast policy as the translated Chat path, including explicit + // fastMode and foreign-tier handling. On inherited canonical Fast, the passthrough still + // retains the caller's exact spelling; forced Fast uses the policy-owned wire value. + const callerTier = typeof rawBody.service_tier === "string" ? rawBody.service_tier : undefined; + const tierDecision = decideTier(fastPolicy, fastMode, callerTier); + if (tierDecision.kind === "set") { + body.service_tier = fastMode === undefined && canonicalFastTierMarker(callerTier) !== undefined + ? callerTier + : tierDecision.value; + } else if (tierDecision.kind === "forward-caller" && rawBody.service_tier !== undefined) { body.service_tier = rawBody.service_tier; } if (provider.promptCacheKey && rawBody.prompt_cache_key !== undefined) { @@ -1294,7 +1303,6 @@ function canSerializeOpenAIChatServiceTier( modelId: string, serviceTier: unknown, tierDecision?: OcxParsedRequest["options"]["tierDecision"], - resolvedPolicy?: Pick, ): boolean { if (serviceTier === undefined) return false; if (tierDecision !== undefined) { @@ -1302,9 +1310,7 @@ function canSerializeOpenAIChatServiceTier( } const callerTier = typeof serviceTier === "string" ? serviceTier : undefined; const callerCanonicalFast = canonicalFastTierMarker(callerTier) !== undefined; - const capability = resolvedPolicy === undefined - ? supportsServiceTierForModel(provider, modelId) - : resolvedPolicy.capability; + const capability = supportsServiceTierForModel(provider, modelId); const callerTierForwardAllowed = canForwardForeignServiceTierForChatModel(provider, modelId); return callerTierForwardAllowed || (callerCanonicalFast && capability === true); } diff --git a/src/server/chat-native.ts b/src/server/chat-native.ts index 5aa4a89cf8..b27f29c962 100644 --- a/src/server/chat-native.ts +++ b/src/server/chat-native.ts @@ -161,6 +161,7 @@ export async function handleNativeChatCompletions(options: HandleNativeChatOptio route.modelId, requestedStream, fastPolicyForModel(activeProvider, route.modelId, route.providerName, "chat"), + config.fastMode, ); try { activeRequest = buildActiveRequest(); diff --git a/tests/openai-chat-native-policy.test.ts b/tests/openai-chat-native-policy.test.ts index 4910652cae..f9657551f5 100644 --- a/tests/openai-chat-native-policy.test.ts +++ b/tests/openai-chat-native-policy.test.ts @@ -1,4 +1,7 @@ import { afterEach, describe, expect, test } from "bun:test"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; import { buildOpenAIChatPassthroughRequest, createOpenAIChatAdapter, @@ -7,6 +10,7 @@ import { decideTier, tierValueAfterDecision, } from "../src/providers/fastwire"; +import { clearKeyCooldowns } from "../src/providers/key-failover"; import { fastPolicyForModel } from "../src/providers/service-tier"; import { handleChatCompletions } from "../src/server/chat-completions"; import type { OcxConfig, OcxParsedRequest, OcxProviderConfig } from "../src/types"; @@ -17,6 +21,7 @@ const originalFetch = globalThis.fetch; afterEach(() => { globalThis.fetch = originalFetch; + clearKeyCooldowns(PROVIDER_NAME); }); function provider(overrides: Partial = {}): OcxProviderConfig { @@ -31,8 +36,9 @@ function provider(overrides: Partial = {}): OcxProviderConfig function nativeBody( target: OcxProviderConfig, - callerTier: string, + callerTier: string | undefined, modelId = MODEL_ID, + fastMode?: boolean, ): Record { const policy = fastPolicyForModel(target, modelId, PROVIDER_NAME, "chat"); const request = buildOpenAIChatPassthroughRequest( @@ -40,22 +46,24 @@ function nativeBody( { model: modelId, messages: [{ role: "user", content: "ping" }], - service_tier: callerTier, + ...(callerTier === undefined ? {} : { service_tier: callerTier }), }, modelId, false, policy, + fastMode, ); return JSON.parse(request.body) as Record; } function mainPathBody( target: OcxProviderConfig, - callerTier: string, + callerTier: string | undefined, modelId = MODEL_ID, + fastMode?: boolean, ): Record { const policy = fastPolicyForModel(target, modelId, PROVIDER_NAME, "chat"); - const tierDecision = decideTier(policy, undefined, callerTier); + const tierDecision = decideTier(policy, fastMode, callerTier); const serviceTier = tierValueAfterDecision(tierDecision, callerTier); const parsed: OcxParsedRequest = { modelId, @@ -116,6 +124,20 @@ describe("native Chat passthrough service-tier policy", () => { callerTier: "flex", expectedTier: "flex", }, + { + name: "classified foreign-tier drop overrides CallerTierForward", + config: { + supportsServiceTier: true, + chatServiceTier: true, + fastWire: { + kind: "service-tier", + canonicalToWire: { priority: "priority" }, + foreignCallerTiers: "drop", + }, + }, + callerTier: "flex", + expectedTier: undefined, + }, ] as const)("$name", ({ config, callerTier, expectedTier }) => { const body = nativeBody(provider(config), callerTier); if (expectedTier === undefined) expect(body).not.toHaveProperty("service_tier"); @@ -157,6 +179,79 @@ describe("native Chat passthrough service-tier policy", () => { expect(captured).toHaveLength(1); expect(captured[0]).not.toHaveProperty("service_tier"); }); + + test("forced Fast injects the policy wire value and forced default drops the caller tier", () => { + const target = provider({ supportsServiceTier: true, chatServiceTier: true }); + + expect(nativeBody(target, "flex", MODEL_ID, true).service_tier).toBe("priority"); + expect(nativeBody(target, undefined, MODEL_ID, true).service_tier).toBe("priority"); + expect(nativeBody(target, "priority", MODEL_ID, false)).not.toHaveProperty("service_tier"); + }); + + test("key failover rebuilds the request without reintroducing a dropped foreign tier", async () => { + const previousHome = process.env.OPENCODEX_HOME; + const home = mkdtempSync(join(tmpdir(), "ocx-native-tier-failover-")); + process.env.OPENCODEX_HOME = home; + const captured: Array<{ authorization: string | null; body: Record }> = []; + globalThis.fetch = (async (_input: RequestInfo | URL, init?: RequestInit) => { + captured.push({ + authorization: new Headers(init?.headers).get("authorization"), + body: JSON.parse(String(init?.body ?? "{}")) as Record, + }); + if (captured.length === 1) { + return Response.json({ error: { message: "rate limited" } }, { + status: 429, + headers: { "retry-after": "0" }, + }); + } + return Response.json({ + id: "chatcmpl_native_tier_failover", + object: "chat.completion", + choices: [{ index: 0, message: { role: "assistant", content: "ok" }, finish_reason: "stop" }], + }); + }) as typeof fetch; + const target = provider({ + supportsServiceTier: true, + chatServiceTier: true, + fastWire: { + kind: "service-tier", + canonicalToWire: { priority: "priority" }, + foreignCallerTiers: "drop", + }, + apiKey: "key-one", + apiKeyPool: [{ id: "one", key: "key-one" }, { id: "two", key: "key-two" }], + }); + const config = { + port: 0, + defaultProvider: PROVIDER_NAME, + providers: { [PROVIDER_NAME]: target }, + } as OcxConfig; + + try { + const response = await handleChatCompletions( + new Request("http://localhost/v1/chat/completions", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + model: `${PROVIDER_NAME}/${MODEL_ID}`, + messages: [{ role: "user", content: "ping" }], + service_tier: "flex", + }), + }), + config, + { model: "", provider: "" }, + ); + + expect(response.status).toBe(200); + expect(captured.map(entry => entry.authorization)).toEqual(["Bearer key-one", "Bearer key-two"]); + expect(captured).toHaveLength(2); + for (const entry of captured) expect(entry.body).not.toHaveProperty("service_tier"); + } finally { + if (previousHome === undefined) delete process.env.OPENCODEX_HOME; + else process.env.OPENCODEX_HOME = previousHome; + rmSync(home, { recursive: true, force: true }); + } + }); }); describe("main and native Chat tier authorization parity", () => { @@ -205,6 +300,20 @@ describe("main and native Chat tier authorization parity", () => { mainTier: "flex", nativeTier: "flex", }, + { + name: "classified foreign-tier drop with CallerTierForward", + config: { + supportsServiceTier: true, + chatServiceTier: true, + fastWire: { + kind: "service-tier", + canonicalToWire: { priority: "priority" }, + foreignCallerTiers: "drop", + }, + }, + callerTier: "flex", + forwarded: false, + }, ] as const)("$name makes the same forward/drop decision", row => { const target = provider(row.config); const main = mainPathBody(target, row.callerTier); @@ -218,4 +327,15 @@ describe("main and native Chat tier authorization parity", () => { expect(native.service_tier).toBe(row.nativeTier); } }); + + test("forced Fast and forced default make the same decision on both Chat paths", () => { + const target = provider({ supportsServiceTier: true, chatServiceTier: true }); + + for (const fastMode of [true, false] as const) { + const main = mainPathBody(target, "flex", MODEL_ID, fastMode); + const native = nativeBody(target, "flex", MODEL_ID, fastMode); + expect(forwardsTier(native)).toBe(forwardsTier(main)); + expect(native.service_tier).toBe(main.service_tier); + } + }); });