Skip to content

fix(models): reasoning_effort for azure grok-4.3 - #3438

Closed
andyst-dev wants to merge 5 commits into
theopenco:mainfrom
andyst-dev:fix/xai-reasoning-effort-params
Closed

andyst-dev wants to merge 5 commits into
theopenco:mainfrom
andyst-dev:fix/xai-reasoning-effort-params

Conversation

@andyst-dev

@andyst-dev andyst-dev commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

Refs #3436, refs #3403 — see "Deliberately not changed" for why neither is fully closed here.

Problem

azure-ai-foundry/grok-4.3 declares reasoning: true but omits reasoning_effort from its supportedParameters, so any effort value a client sends is silently dropped at the default-case gate in prepare-request-body.ts before the request is built. The same underlying model already forwards the parameter on its xai and aws-bedrock mappings, both of which declare reasoningEfforts: ["none", "low", "medium", "high"] — Azure Foundry was simply never given the equivalent fix (#3159 scoped its change to the native mappings).

Change

packages/models/src/models/xai.ts:

  • Add reasoning_effort to azure-ai-foundry/grok-4.3's inline supportedParameters, and declare reasoningEfforts matching its sibling mappings so /v1/models publishes the accepted tiers.
  • Document on xaiSupportedParamsNoFreqPresence why reasoning_effort is deliberately absent from the shared const, so the next reader doesn't add it back wholesale.

packages/models/src/model-metadata.spec.ts:

  • New invariant: every xAI mapping that advertises reasoning_effort must also declare reasoningEfforts. The tiers are the record that the deployment was actually verified; without them neither the gateway nor a client knows which values are safe.

packages/actions/src/prepare-request-body.spec.ts:

  • Dedicated prepareRequestBody - xAI reasoning_effort describe: positive case for the Azure Foundry mapping, plus negative cases pinning the mappings that deliberately still drop the parameter.
  • The pre-existing keeps Grok 4.3 as Azure Foundry chat completions test now asserts reasoning_effort: "medium" is forwarded, where it previously asserted undefined and encoded the bug.

Deliberately not changed

An earlier revision of this PR also enabled reasoning_effort on xai/grok-4, azure-ai-foundry/grok-4-1-fast-reasoning, vertex-openai/grok-4.20-reasoning, xai/grok-4.20-beta-0309-reasoning and xai/grok-build-0.1. Those are reverted:

The gateway forwards effort verbatim, each of those models has a single routable mapping, and auto routing injects reasoning_effort: "low" on its own — so an unaccepted parameter is a hard user-visible error with no fallback to absorb it. Enabling them needs one live call each first. #3403 and the grok-4-1-fast-reasoning half of #3436 therefore stay open.

Two adjacent gaps are also out of scope here:

  • Neither xai nor azure-ai-foundry is in handlesNoneNatively, so none is normalized away on both hosts even though grok-4.3 declares it and aws-bedrock forwards it. Pre-existing on the native mapping; a gateway fix, not a catalogue one.
  • The new invariant is xAI-scoped on purpose. A catalogue-wide "reasoning implies reasoning_effort" rule flags 49 mappings, including every OpenAI GPT-5 and Anthropic mapping — correct code, because those providers are handled before the supportedParameters gate.

Validation

  • tsc -p packages/actions clean (the previous revision's test helper failed with TS2339 and broke pnpm build).
  • 753 tests pass across packages/models, packages/actions, and the gateway/playground specs that touch grok models.
  • New metadata invariant confirmed non-vacuous: removing the reasoningEfforts declaration makes it fail and name the offending mapping.
  • pnpm format and a full pnpm build.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added configurable reasoning effort for Azure AI Foundry’s Grok 4.3 model, with support for none, low, medium, and high levels.
    • Grok 4.3 now uses medium reasoning effort by default where applicable.
  • Bug Fixes

    • Improved reasoning-effort handling across xAI-compatible model integrations.
    • Unsupported reasoning settings are now omitted instead of being forwarded incorrectly.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The change adds provider-specific reasoning_effort support for Azure AI Foundry Grok 4.3. It documents the xAI parameter exception, validates metadata declarations, and adds request-body regression tests for forwarding and omission.

Changes

xAI reasoning effort support

Layer / File(s) Summary
Declare xAI reasoning parameters
packages/models/src/models/xai.ts, packages/models/src/model-metadata.spec.ts
Azure Grok 4.3 declares none, low, medium, and high reasoning tiers. Metadata tests verify that mappings supporting reasoning_effort declare corresponding tiers.
Validate request forwarding
packages/actions/src/prepare-request-body.spec.ts
Tests verify forwarding for Azure Grok 4.3, omission for unsupported xAI and Vertex OpenAI mappings, and the "medium" expectation for Azure Grok 4.3.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: steebchen, smakosh

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR fixes Grok 4.3 but does not resolve the linked requirements for Azure Grok 4.1 fast reasoning or Vertex Grok 4.20 reasoning. Address the remaining linked mappings, or explicitly split and defer those issue requirements with maintainer approval.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The implementation and regression tests stay within the linked objectives for reasoning_effort mapping and request handling.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: fixing reasoning_effort support for the Azure Grok 4.3 model mapping.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/actions/src/prepare-request-body.spec.ts`:
- Around line 1120-1141: Update the reasoning_effort test around
prepareRequestBody to verify the supportedParameters gate rather than only
serialization. Assert that all six relevant provider mappings include
"reasoning_effort", or invoke the caller path that filters unsupported
parameters before prepareRequestBody receives them, ensuring the test fails when
the mapping removes the parameter.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 86c2ed39-2532-490f-bd3e-bb5f5633a07d

📥 Commits

Reviewing files that changed from the base of the PR and between 87a403b and ed47305.

📒 Files selected for processing (2)
  • packages/actions/src/prepare-request-body.spec.ts
  • packages/models/src/models/xai.ts

Comment on lines +1120 to +1141
test.each(xaiEffortCases)(
"forwards reasoning_effort for %s/%s once declared in supportedParameters",
async (provider, model, effort) => {
const requestBody = (await prepareRequestBody(
provider,
model,
null,
model,
[{ role: "user", content: "Hello!" }],
false, // stream
undefined, // temperature
undefined, // max_tokens
undefined, // top_p
undefined, // frequency_penalty
undefined, // presence_penalty
undefined, // response_format
undefined, // tools
undefined, // tool_choice
effort,
true, // supportsReasoning
)) as unknown as Record<string, unknown>;
expect(requestBody.reasoning_effort).toBe(effort);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Test the supportedParameters gate.

prepareRequestBody serializes any defined reasoning_effort. This test passes if a mapping removes "reasoning_effort" because it passes effort directly to the serializer.

Assert that the six provider mappings contain "reasoning_effort", or exercise the caller that removes unsupported parameters before it calls prepareRequestBody.

Based on learnings: supportedParameters is the source of truth, and the gateway maps unsupported parameters to undefined before request construction.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/actions/src/prepare-request-body.spec.ts` around lines 1120 - 1141,
Update the reasoning_effort test around prepareRequestBody to verify the
supportedParameters gate rather than only serialization. Assert that all six
relevant provider mappings include "reasoning_effort", or invoke the caller path
that filters unsupported parameters before prepareRequestBody receives them,
ensuring the test fails when the mapping removes the parameter.

Source: Learnings

@AmineAce

AmineAce commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

The Minor comment about test fidelity is worth addressing before merge — right now the tests confirm the request body ends up correct, but don't actually assert that supportedParameters contains "reasoning_effort" for the 6 fixed mappings. That distinction matters: if a future refactor changes how the gate reads supportedParameters, a serialization-only test could keep passing while the actual capability check silently regresses. A direct assertion on each mapping's supportedParameters array would catch that class of regression, not just today's behavior.

…ings

grok-4-3 and grok-4-1-fast-reasoning (azure-ai-foundry), grok-4-20-reasoning
(vertex-openai), grok-4, grok-4-20-beta-0309-reasoning and grok-build-0-1
(xai) all declare reasoning: true but omitted reasoning_effort from their
supportedParameters, so any effort value was silently dropped before the
request was built. Inline the shared xaiSupportedParamsNoFreqPresence list
(following theopenco#3159) and add reasoning_effort to each active reasoning mapping;
deactivated and non-reasoning mappings keep the shared constant untouched.

Fixes theopenco#3436, Fixes theopenco#3403
…or xAI mappings

Direct capability assertion on each fixed mapping's supportedParameters
array, not just the serialized request body — catches a future refactor
that stops reading supportedParameters while serialization tests keep
passing.
@andyst-dev
andyst-dev force-pushed the fix/xai-reasoning-effort-params branch from ed47305 to 7cff5cc Compare August 8, 2026 09:47
@andyst-dev

Copy link
Copy Markdown
Contributor Author

Good point — the serialization assertion alone wouldn't catch a refactor that stops reading supportedParameters. Each case now also asserts the capability directly on the mapping:

const modelDef = models.find((m) => m.id === model);
const mapping = modelDef?.providers.find((p) => p.providerId === provider);
expect(mapping?.supportedParameters).toContain("reasoning_effort");

This walks the same resolution path the request builder uses (models.find → providers.find), so a regression in either the catalog entries or the gate's read of supportedParameters fails the test immediately, for all 6 fixed mappings (azure-ai-foundry/grok-4-3, azure-ai-foundry/grok-4-1-fast-reasoning, vertex-openai/grok-4-20-reasoning, xai/grok-4, xai/grok-4-20-beta-0309-reasoning, xai/grok-build-0-1). The body-forwarding assertion stays alongside it.

Validation:

pnpm exec vitest run --config vitest.config.mts packages/actions/src/prepare-request-body.spec.ts
Test Files  1 passed (1)
Tests       249 passed (249)

Branch rebased on current main. New head: 7cff5cc.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/actions/src/prepare-request-body.spec.ts (1)

2683-2703: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Replace broad type escapes with narrow payload types.

The new tests use any and as any. Define local provider-specific request-body types, then cast through unknown only where the prepareRequestBody union requires narrowing.

  • packages/actions/src/prepare-request-body.spec.ts#L2683-L2703: Type the Google tool request body and its schema parameters.
  • packages/actions/src/prepare-request-body.spec.ts#L2760-L2780: Reuse the same Google tool request-body type.
  • packages/actions/src/prepare-request-body.spec.ts#L5995-L6021: Type provider, webSearchTool, and the DashScope request payload without any.

As per coding guidelines, **/*.{ts,tsx} must “avoid any and as any unless absolutely necessary.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/actions/src/prepare-request-body.spec.ts` around lines 2683 - 2703,
Replace broad any/as any escapes in prepare-request-body.spec.ts with local
provider-specific types: at lines 2683-2703 define and use a Google tool
request-body type including schema parameters, and at lines 2760-2780 reuse it;
at lines 5995-6021 type provider, webSearchTool, and the DashScope request
payload explicitly. Cast through unknown only where prepareRequestBody’s union
requires narrowing, and make no other changes.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/actions/src/prepare-request-body.spec.ts`:
- Around line 2683-2703: Replace broad any/as any escapes in
prepare-request-body.spec.ts with local provider-specific types: at lines
2683-2703 define and use a Google tool request-body type including schema
parameters, and at lines 2760-2780 reuse it; at lines 5995-6021 type provider,
webSearchTool, and the DashScope request payload explicitly. Cast through
unknown only where prepareRequestBody’s union requires narrowing, and make no
other changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ac3f09c1-3dad-4987-874d-f578198997cf

📥 Commits

Reviewing files that changed from the base of the PR and between ed47305 and 7cff5cc.

📒 Files selected for processing (1)
  • packages/actions/src/prepare-request-body.spec.ts

smakosh added 3 commits August 8, 2026 14:12
Only azure-ai-foundry/grok-4.3 keeps the parameter: its sibling xai and
aws-bedrock mappings of the same model already declare reasoningEfforts,
so the deployment is known to accept it. The other five mappings go back
to the shared const — grok-4 is documented as rejecting reasoning_effort
(its own comment says it always reasons), grok-build-0.1 and
grok-4.20-beta-0309-reasoning were deliberately skipped in theopenco#3046 for lack
of documented values, and the vertex-openai and Grok 4.1 Fast mappings
are the live checks theopenco#3403 and theopenco#3436 explicitly asked for before enabling.
Each of those models has a single routable mapping, so a rejected
parameter is a hard error with no fallback, and auto routing injects
reasoning_effort: "low" on its own.

Azure Foundry grok-4.3 now also declares reasoningEfforts so clients can
discover the accepted tiers, and a metadata invariant keeps every future
xAI mapping that advertises the parameter from omitting them.

Claude-Session: https://claude.ai/code/session_01BrVPkQMps6NrMacF8Pkx1r
The table read supportedParameters off the const-asserted catalogue
union, which is a TS2339 error and broke tsc for the whole package even
though vitest transpiled it fine. It also passed internal model ids as
usedExternalId, so the vertex-openai case built a partner-prefixed model
string production never emits, and it sat inside the Moonshot describe.

Replace it with a dedicated describe that uses real external ids, keeps
the positive case for the one mapping that forwards the parameter, and
restores negative coverage for the mappings that deliberately drop it.

Claude-Session: https://claude.ai/code/session_01BrVPkQMps6NrMacF8Pkx1r
@smakosh smakosh changed the title fix(models): add reasoning_effort to supportedParameters for xAI mappings fix(models): reasoning_effort for azure grok-4.3 Aug 8, 2026
steebchen pushed a commit that referenced this pull request Aug 8, 2026
e2e against api.x.ai shows three of the six mappings widened in #3438
answer reasoning_effort with 400 'does not support parameter
reasoningEffort': xai/grok-4-20-beta-0309-reasoning, xai/grok-build-0-1,
and vertex-openai/grok-4-20-reasoning (same upstream model as the
former). Declaring the parameter made the gateway forward it, turning
every effort-bearing request into an upstream 400 — 4 gateway e2e tests
that pass on main fail with it.

Restore the shared parameter list for those three, with a comment on
each recording why the omission is deliberate, and split the spec's
table so the rejecting mappings assert the drop rather than the forward.

xai/grok-4 keeps the parameter (verified 200; it aliases to grok-4.3
upstream). The two azure-ai-foundry mappings keep it as well and remain
unverified here — no Azure credentials.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RbUnEaa7vrZZkD82wSStTr

Copy link
Copy Markdown
Member

Closing in favor of #3483, which carries this work forward with a correction.

E2E-verified this branch against a live xAI key. Three of the six mappings widened here reject reasoning_effort upstream — api.x.ai answers 400 does not support parameter reasoningEffort for grok-4.20-beta-0309-reasoning, grok-build-0.1, and grok-4.20-reasoning. Control requests without the parameter return 200, so the parameter is the sole cause, and streaming behaves the same. For those mappings the omission was the catalogue correctly reflecting upstream rather than the gap #3436/#3403 describe, so declaring it turns every effort-bearing request into a 400.

Concretely, TEST_MODELS="xai/grok-4,xai/grok-4-20-beta-0309-reasoning,xai/grok-build-0-1" pnpm test:e2e fails 4 tests on this branch (chat-reasoning.e2e.ts > basic reasoning and chat-rs.e2e.ts > reasoning + streaming, for both models). The same four pass on main.

Separately, pnpm build fails here: the new spec reads .supportedParameters off the raw catalogue union, which tsc rejects with TS2339 since not every member declares it.

#3483 keeps your addition for xai/grok-4 and the two azure-ai-foundry mappings, restores the shared list for the three rejecting ones with a comment on each explaining why, adds the inverse regression test, and fixes the type error. Scoped e2e is green there. Thanks for finding the underlying gate — the grok-4 and grok-4.3 half of this was a real fix.


Generated by Claude Code

@steebchen steebchen closed this Aug 8, 2026
steebchen added a commit that referenced this pull request Aug 8, 2026
Supersedes #3438 (fixes #3436, #3403).

## Problem

Six xAI mappings declare `reasoning: true` but omit `reasoning_effort`
from `supportedParameters`, so a caller-supplied effort is dropped at
the gate in `packages/actions/src/prepare-request-body.ts:4077-4086`.
#3438 treated all six as the same oversight and declared the parameter
on every one.

E2E against `api.x.ai` shows that premise does not hold. Three of those
deployments reason unconditionally but reject the effort knob outright:

| externalId | `reasoning_effort` | Result |
| --- | --- | --- |
| `grok-4` | low | 200 (aliases to `grok-4.3` upstream) |
| `grok-4.3` | low | 200 |
| `grok-4.20-beta-0309-reasoning` | low / medium / high | **400** `does
not support parameter reasoningEffort` |
| `grok-build-0.1` | low / medium / high | **400** same |
| `grok-4.20-reasoning` | low | **400** same |

Control requests with the parameter omitted return 200 for all three, so
the parameter is the sole cause; streaming behaves identically. For
those mappings the omission was the catalogue correctly reflecting
upstream, not the bug the issues describe — declaring it turns every
effort-bearing request into an upstream 400.

## Change

`packages/models/src/models/xai.ts` — keep #3438's addition for
`xai/grok-4`, `azure-ai-foundry/grok-4-3` and
`azure-ai-foundry/grok-4-1-fast-reasoning`; restore the shared
`xaiSupportedParamsNoFreqPresence` list for the three rejecting
mappings, each with a comment recording why the omission is load-bearing
so it does not get "fixed" again:

- `xai` / `grok-4-20-beta-0309-reasoning`
- `xai` / `grok-build-0-1`
- `vertex-openai` / `grok-4-20-reasoning` — same upstream model as the
first

`packages/actions/src/prepare-request-body.spec.ts` — split #3438's
six-row table into a positive table (three mappings forward the effort)
and a negative one asserting the rejecting mappings are `reasoning:
true`, do **not** list `reasoning_effort`, and drop the value from the
request body. Also narrows the mapping lookup to `ProviderModelMapping`;
reading `.supportedParameters` off the raw catalogue union fails `tsc`
with TS2339, which broke `pnpm build` on #3438.

## Verification

Ran with a live xAI key.

-
`TEST_MODELS="xai/grok-4,xai/grok-4-20-beta-0309-reasoning,xai/grok-build-0-1"
pnpm test:e2e` — **29 passed, 2 skipped, 0 failed**. On #3438 the same
command produced 4 failures (`chat-reasoning.e2e.ts > basic reasoning`
and `chat-rs.e2e.ts > reasoning + streaming`, both models, 400 vs
expected 200). Those four pass on `main`, confirming the regression
rather than a pre-existing failure.
- `prepare-request-body.spec.ts` + models specs: 380 passed.
- `pnpm build`, `pnpm format`, `pnpm lint`: clean.

## Not verified

`azure-ai-foundry/grok-4-1-fast-reasoning` keeps the parameter but was
not exercised — no Azure credentials here, and the id does not resolve
on native xAI (`grok-4.1-fast-reasoning` → "Model not found"; our `xai`
mapping for it is deactivated). Since every xAI reasoning model probed
except `grok-4.3` rejects `reasoning_effort`, this one is worth a `/e2e`
run with the Azure key before merging. `azure-ai-foundry/grok-4-3` is
safer — native `grok-4.3` accepts the parameter.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01RbUnEaa7vrZZkD82wSStTr

---
_Generated by [Claude
Code](https://claude.ai/code/session_01RbUnEaa7vrZZkD82wSStTr)_

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved handling of the `reasoning_effort` setting across supported
xAI and Azure AI Foundry models.
* Ensured the setting is forwarded only when supported and omitted for
deployments that reject it.
* Updated Azure AI Foundry Grok 4.3 to use a default reasoning effort of
`medium`.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: andyst-dev <150129844+andyst-dev@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants