Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions src/providers/fastwire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,34 +143,40 @@ function resolvePolicyAdapter(
inbound: InboundWire,
): { adapter: string; hardPinned: boolean; forwardCallerServiceTier?: boolean } {
// Hard pins and configured overrides deliberately use the same exact-key semantics as
// resolveWireProtocolOverride(). Registry defaults alone normalize ids at their boundary.
// resolveWireProtocolOverride(). Registry route policy normalizes ids at its boundary.
const hardPin = Object.hasOwn(authority.hardPins, modelId)
? authority.hardPins[modelId]
: undefined;
if (typeof hardPin === "string") return { adapter: hardPin, hardPinned: true };
if (authority.modelWireOverrideAllowed) {
const registryDefault = MODEL_ADAPTER_OVERRIDE_ALLOWED.has(authority.providerAdapter)
? registryDefaultForModel(
authority.registryWireDefaults,
modelId,
inbound,
authority.providerAuthMode,
)
: undefined;
const configured = Object.hasOwn(authority.modelAdapters, modelId)
? authority.modelAdapters[modelId]
: undefined;
if (typeof configured === "string" && MODEL_ADAPTER_OVERRIDE_ALLOWED.has(configured)) {
return { adapter: configured, hardPinned: false };
return {
adapter: configured,
hardPinned: false,
...(registryDefault?.forwardCallerServiceTier === false
? { forwardCallerServiceTier: false }
: {}),
};
}
if (MODEL_ADAPTER_OVERRIDE_ALLOWED.has(authority.providerAdapter)) {
const registryDefault = registryDefaultForModel(
authority.registryWireDefaults,
modelId,
inbound,
authority.providerAuthMode,
);
if (registryDefault !== undefined) {
return {
adapter: registryDefault.adapter,
hardPinned: false,
...(registryDefault.forwardCallerServiceTier !== undefined
? { forwardCallerServiceTier: registryDefault.forwardCallerServiceTier }
: {}),
};
}
if (registryDefault !== undefined) {
return {
adapter: registryDefault.adapter,
hardPinned: false,
...(registryDefault.forwardCallerServiceTier !== undefined
? { forwardCallerServiceTier: registryDefault.forwardCallerServiceTier }
: {}),
};
}
}
return { adapter: authority.providerAdapter, hardPinned: false };
Expand Down
11 changes: 5 additions & 6 deletions src/providers/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1026,19 +1026,18 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
// grok-4.5; the reasoning ladder does not — 4.6 adds the documented xhigh rung.
models: ["grok-4.6", "grok-4.5", "grok-4.3", "grok-4.20-0309-reasoning", "grok-4.20-0309-non-reasoning", "grok-build-0.1", "grok-composer-2.5-fast"],
defaultModel: "grok-4.5",
// The current Grok CLI catalog declares both subscription models as native Responses
// backends. Keep API-key and translated Chat/Anthropic callers on their existing wire;
// Codex Responses traffic can relay xAI's SSE as it arrives instead of waiting for the
// Chat Completions compatibility stream to flush at the end of a reasoning turn.
// Keep Codex Responses callers on the compatibility Chat wire until xAI can replay
// opaque reasoning continuation and compaction state across later turns. The scoped
// declaration also keeps caller-owned service tiers off the OAuth subscription route.
modelWireDefaults: {
"grok-4.6": {
wire: "openai-responses",
wire: "openai-chat",
inbound: ["responses"],
authModes: ["oauth"],
forwardCallerServiceTier: false,
Comment on lines 1033 to 1037

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Document the new xAI wire default publicly

This changes user-visible routing for OAuth users of Grok 4.5/4.6 from Responses to Chat, while leaving Responses available only through an explicit modelAdapters override, but the public docs-site/ configuration and provider guides still contain only generic override guidance and do not explain this xAI-specific default, opt-in, or tier behavior. Add the new default and the openai-responses opt-in to the English documentation and keep translated locales synchronized.

AGENTS.md reference: src/AGENTS.md:L28-L28

Useful? React with 👍 / 👎.

},
"grok-4.5": {
wire: "openai-responses",
wire: "openai-chat",
inbound: ["responses"],
authModes: ["oauth"],
forwardCallerServiceTier: false,
Expand Down
16 changes: 8 additions & 8 deletions structure/04_transports-and-sidecars.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,14 @@ different custom destination does not inherit its upstream assumptions. Object-f
also narrow the decision by inbound protocol and authentication mode; an auth-scoped default must
not leak from a subscription transport into an API-key or forwarded-credential route.

xAI keeps `openai-chat` as its provider-wide compatibility wire. The official Grok CLI catalog
declares the Grok 4.5 and 4.6 subscription models as Responses backends, so only OAuth-backed native
Responses traffic for those exact models selects `openai-responses`. API-key requests, translated
Chat/Anthropic callers, other Grok models, and explicit model adapter overrides retain their
existing wire. This lets Codex receive native xAI SSE deltas as they arrive without widening the
credential or compatibility boundary. These OAuth subscription defaults drop caller-owned
`service_tier`; they neither advertise nor inject Fast. The API-key transport remains governed by
its separate capability declaration.
xAI keeps `openai-chat` as both its provider-wide compatibility wire and the default for Grok 4.5
and 4.6 subscription traffic. The official Grok CLI catalog declares those models as Responses
backends, but the current gateway rejects opaque reasoning continuation and compaction state on
later turns. Operators may still select `openai-responses` with an explicit model adapter override
while that compatibility work continues. The OAuth route drops caller-owned `service_tier` even
when an override selects Responses, and native Responses OAuth 401 replay remains available to
explicit opt-ins. API-key requests, translated Chat/Anthropic callers, and other Grok models retain
their existing wire and tier policy.

OpenCode Go documents `gpt-5.6-luna` on `/zen/go/v1/responses` while sibling models use its Chat or
Anthropic endpoints. The built-in preset therefore selects `openai-responses` only for Luna and
Expand Down
14 changes: 8 additions & 6 deletions tests/adapter-resolve.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ describe("registry per-model wire defaults", () => {
});
}

test("routes current xAI subscription models through Responses for native Codex traffic", () => {
test("keeps current xAI subscription models on Chat by default", () => {
for (const model of ["grok-4.6", "grok-4.5"]) {
expect(resolveWireProtocolOverride("xai", model, xai("oauth"), "responses").adapter)
.toBe("openai-responses");
.toBe("openai-chat");
}
});

Expand All @@ -118,10 +118,12 @@ describe("registry per-model wire defaults", () => {
.toBe("openai-chat");
});

test("an explicit xAI Chat override opts out of the subscription Responses default", () => {
const provider = xai("oauth", { modelAdapters: { "grok-4.6": "openai-chat" } });
expect(resolveWireProtocolOverride("xai", "grok-4.6", provider, "responses").adapter)
.toBe("openai-chat");
test("an explicit xAI Responses override opts into the native wire", () => {
for (const model of ["grok-4.6", "grok-4.5"]) {
const provider = xai("oauth", { modelAdapters: { [model]: "openai-responses" } });
expect(resolveWireProtocolOverride("xai", model, provider, "responses").adapter)
.toBe("openai-responses");
}
});

function deepseek(overrides: Partial<OcxProviderConfig> = {}): OcxProviderConfig {
Expand Down
108 changes: 89 additions & 19 deletions tests/fastwire-policy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,25 +256,95 @@ describe("resolveFastPolicy matrix", () => {
expect(fastPolicyForModel(provider, MODEL, "fixture").capability).toBe(false);
});

test("captured xAI registry defaults keep OAuth and key transports separate", () => {
const oauthProvider = Object.freeze({
adapter: "openai-chat",
baseUrl: "https://api.x.ai/v1",
authMode: "oauth" as const,
});
const keyProvider = Object.freeze({
adapter: "openai-chat",
baseUrl: "https://api.x.ai/v1",
authMode: "key" as const,
});

expect(fastPolicyForModel(oauthProvider, "grok-4.6", "xai")).toMatchObject({
adapter: "openai-responses",
eligibility: "unclassified",
forwardCallerTier: false,
});
expect(fastPolicyForModel(keyProvider, "grok-4.6", "xai").adapter)
.toBe("openai-chat");
test("locks the five-row xAI and DeepSeek wire/tier regression matrix", () => {
const rows = [
{
name: "xAI OAuth default",
providerName: "xai",
modelIds: ["grok-4.6", "grok-4.5"],
provider: {
adapter: "openai-chat",
baseUrl: "https://api.x.ai/v1",
authMode: "oauth" as const,
},
adapter: "openai-chat",
forwardCallerTier: false,
callerTier: undefined,
settledCallerTier: undefined,
},
{
name: "xAI OAuth Responses override",
providerName: "xai",
modelIds: ["grok-4.6", "grok-4.5"],
provider: {
adapter: "openai-chat",
baseUrl: "https://api.x.ai/v1",
authMode: "oauth" as const,
modelAdapters: { "grok-4.6": "openai-responses", "grok-4.5": "openai-responses" },
},
adapter: "openai-responses",
forwardCallerTier: false,
callerTier: "flex",
settledCallerTier: undefined,
},
{
name: "xAI API-key default",
providerName: "xai",
modelIds: ["grok-4.6", "grok-4.5"],
provider: {
adapter: "openai-chat",
baseUrl: "https://api.x.ai/v1",
authMode: "key" as const,
},
adapter: "openai-chat",
forwardCallerTier: false,
callerTier: undefined,
settledCallerTier: undefined,
},
{
name: "xAI API-key Responses override",
providerName: "xai",
modelIds: ["grok-4.6", "grok-4.5"],
provider: {
adapter: "openai-chat",
baseUrl: "https://api.x.ai/v1",
authMode: "key" as const,
modelAdapters: { "grok-4.6": "openai-responses", "grok-4.5": "openai-responses" },
},
adapter: "openai-responses",
forwardCallerTier: true,
callerTier: "flex",
settledCallerTier: "flex",
},
{
name: "DeepSeek V4 defaults",
providerName: "deepseek",
modelIds: ["deepseek-v4-flash", "deepseek-v4-pro"],
provider: {
adapter: "openai-chat",
baseUrl: "https://api.deepseek.com",
authMode: "key" as const,
},
adapter: "openai-responses",
forwardCallerTier: false,
callerTier: undefined,
settledCallerTier: undefined,
},
] as const;

for (const row of rows) {
for (const modelId of row.modelIds) {
const policy = fastPolicyForModel(row.provider, modelId, row.providerName);
expect(policy.adapter).toBe(row.adapter);
expect(policy.forwardCallerTier).toBe(row.forwardCallerTier);
expect(tierValueAfterDecision(decideTier(policy, undefined, undefined), undefined))
.toBeUndefined();
if (row.callerTier !== undefined) {
expect(tierValueAfterDecision(decideTier(policy, undefined, row.callerTier), row.callerTier))
.toBe(row.settledCallerTier);
}
}
}
});

test("prototype-named providers and models use only own wire-policy rows", () => {
Expand Down
Loading
Loading