Skip to content

feat(providers/openai): allow reasoning-model overrides and recognize gpt-6+ - #57

Merged
ibetitsmike merged 3 commits into
coder_2_33from
mike/responses-reasoning-model-override
Sep 15, 2026
Merged

ibetitsmike merged 3 commits into
coder_2_33from
mike/responses-reasoning-model-override

Conversation

@ibetitsmike

Copy link
Copy Markdown

Why

Bedrock Mantle and direct OpenAI both expose gpt-6-astra, but the fork's Responses client still classifies only gpt-5* (and o-series/codex) as reasoning models. For any newer generation it omits the reasoning parameter entirely (effort and summary are silently dropped) and forwards temperature, which OpenAI rejects with HTTP 400. Upstream charmbracelet#354 (cherry-picked here as-is) only widened the public IsResponsesModel/IsResponsesReasoningModel helpers; getResponsesModelConfig, which gates the request parameters, was left on gpt-5.

Every new model generation currently needs a fork release before chatd can use it correctly. Callers need a way to decide the classification themselves.

What

  • Cherry-pick upstream cfb0530 (fix: gpt series 6+ (#354)) unchanged.
  • getResponsesModelConfig treats gpt-5 and every later generation (gpt-6, gpt-10, ...) as reasoning models; -chat variants stay non-reasoning; gpt-4 is unchanged.
  • New provider option openai.WithReasoningModelFunc(fn func(modelID string) bool), mirroring WithResponsesAPIFunc: when set it replaces the built-in name heuristics for both the Responses client (reasoning params, temperature/top_p filtering, developer vs system role) and the Chat Completions client (WithLanguageModelReasoningModelFunc, including the logprobs/logit_bias filtering in DefaultPrepareCallFunc).

Validation

  • go build ./..., go test ./providers/openai/... -count=1, golangci-lint run ./providers/openai/..., gofumpt clean on touched files.
  • New tests: TestPrepareParams_ReasoningModelClassification, TestPrepareParams_ChatReasoningModelOverride (plus upstream's TestIsResponsesModel/TestIsResponsesReasoningModel). Mutation checks confirmed each assertion fails when the corresponding change is removed.
  • Live probe through the dev AI gateway with this branch: gpt-6-astra now sends reasoning: {"effort":"low"} without temperature and returns 200; forcing non-reasoning on gpt-5.6-luna via the new option sends temperature and gets OpenAI's 400, showing the override takes effect.

Follow-up: coder/coder will bump its pin and expose the override as an openai_config.reasoning_model model-config flag.

Xum acted on behalf of @ibetitsmike for this PR.

andrinoff and others added 2 commits September 11, 2026 11:38
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-11T11:54:06.960700Z f5b3f25 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ibetitsmike

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: f5b3f253c1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ibetitsmike

Copy link
Copy Markdown
Author

Note on CI: the govulncheck job fails for reasons unrelated to this change. It reports stdlib advisories fixed in Go 1.26.6 (net/url, crypto/tls, encoding/xml; the workflow builds with 1.26.5 from go.mod) and golang.org/x/image@v0.44.0 reached only through providers/kronk. Both need a toolchain and dependency bump on coder_2_33, which is a separate chore. Build (3 OSes) and lint are green.

@ibetitsmike
ibetitsmike merged commit a511353 into coder_2_33 Sep 15, 2026
6 checks passed
ibetitsmike added a commit to coder/coder that referenced this pull request Sep 15, 2026
coder/fantasy#57 squash-merged into coder_2_33 as a511353f83eb. The openai provider is byte-identical to the previously pinned PR head f5b3f253c112; the new pin also carries coder/fantasy#58 (Gemini media tool results) and indirect x/image and x/text bumps that fix the govulncheck findings.
ibetitsmike added a commit to coder/coder that referenced this pull request Sep 16, 2026
## Why

Bedrock Mantle's OpenAI Responses endpoint rejects `reasoning.summary`
values other than `auto` with HTTP 400 (`Unsupported parameter:
'reasoning.summary' is not supported with the 'openai.gpt-5.6-sol'
model`). chatd forwards `provider_options.openai.reasoning_summary` from
the model config unchanged, so every chat turn and quickgen title call
through a Bedrock model config carrying `concise`/`detailed` fails. On
dogfood this produced 43 user-visible "chat generation failed" errors
and 118 title-generation failures in one day; five Bedrock configs still
carry `detailed`.

## What

`resolveModelCall` now coerces
`provider_options.openai.reasoning_summary` to `auto` for Bedrock
providers whose model uses the OpenAI wire format (non-`anthropic.`
model IDs), before per-call provider options are built. Mantle accepts
`auto` (it returns no summaries today, but encrypted reasoning
continuity keeps working). Coercing instead of dropping keeps one config
portable between Bedrock and direct OpenAI, and summaries start flowing
if AWS adds support. Anthropic models on Bedrock and every non-Bedrock
provider are untouched. Only the derived provider options see the
coerced value; the resolved call config keeps the configured one, so
computer-use rerouting to direct OpenAI is unaffected. A TODO item in
`coderd/x/chatd/ARCHITECTURE.md` marks the section for the human author,
per the chatd guardrail.

## Validation

- `TestAIGatewayModelBedrockReasoningSummary` drives the real
`resolveModelCall` path (newModel + ProviderOptionsForCall) with a
request-capturing transport: Bedrock + `openai.gpt-5.6-luna` with
`detailed` sends `"summary":"auto"`; Bedrock + Anthropic and direct
OpenAI are unchanged. `TestBedrockReasoningSummary` covers the helper
table. Red-green: removing the resolver call or the helper body fails
the body assertion (`expected "auto", actual "detailed"`).
- `go test ./coderd/x/chatd/ -run 'TestAIGateway|Bedrock'`, `go test
./coderd/x/chatd/chatprovider/...`, `golangci-lint run
./coderd/x/chatd/...` (0 issues), `make pre-commit`.
- Remote dogfood UAT (Coder Agents) against a mock Bedrock upstream and
the real OpenAI gateway: Bedrock `openai.gpt-5.6-luna` configs with
`detailed`/`concise`/odd-cased values send `"summary":"auto"` and
complete chats and titles; direct OpenAI keeps `detailed` with visible
summaries; Bedrock Anthropic requests gain no OpenAI fields. UAT ran on
the first head (a4878f8); the follow-up commit only stops the coerced
config from leaking into provider substitution and swaps the doc
paragraph for a TODO.
- The local `pre-push` hook failed only on unrelated pre-existing
failures in this checkout (`provisioner/terraform TestGetModulesArchive`
hash mismatch from the host umask, two untouched site tests), so the
push bypassed it; CI is the gate.

Related follow-ups: coder/fantasy#57 (gpt-6+ reasoning classification
and an override hook) and a coder PR exposing an
`openai_config.reasoning_model` flag in the model config UI.

> Xum acted on behalf of @ibetitsmike for this PR.
ibetitsmike added a commit to coder/coder that referenced this pull request Sep 16, 2026
…9230)

## Why

The coder/fantasy fork classifies OpenAI reasoning models by name. The
pinned version did not know `gpt-6-astra`, so the Responses client
omitted the `reasoning` parameter (the reasoning effort picker did
nothing) and forwarded `temperature` (quickgen title calls got HTTP 400
`Unsupported parameter: 'temperature'` and retried). Every new model
generation would need a fork release to fix this. Admins need a switch
in the model config instead.

## What

- Bump `charm.land/fantasy` to coder/fantasy `a511353f83eb`, the
`coder_2_33` commit that squash-merged coder/fantasy#57 (the pin also
carries coder/fantasy#58, Gemini media tool results): gpt-6 and later
generations are recognized as reasoning models, and the provider gains
`WithReasoningModelFunc` to override the classification.
- New tri-state `openai_config.reasoning_model` on
`ChatModelCallConfig`: unset keeps fantasy's name heuristics, `true`
forces reasoning-model handling (effort and summary sent,
temperature/top_p dropped), `false` forces plain sampling. It is applied
once at client construction next to `use_responses_api`. The generated
model editor shows it for `openai` and `bedrock` providers, since
Bedrock Mantle also serves OpenAI-format models; it is ignored for
Anthropic models on Bedrock.
- Remove the `IsGPT6Astra` transport fallback in
`chatopenai.UsesResponsesAPI`; the bumped SDK recognizes gpt-6 itself
(`IsGPT6Astra` stays for the effort clamp).
- Regenerated API docs, swagger, TypeScript types, and the model options
schema; ARCHITECTURE.md documents the flag.

## Validation

- New tests: `TestChatModelCallConfig_ReasoningModelRoundTrip`,
`TestModelFromConfig_OpenAIReasoningModelOverride` (request body has
`reasoning` and no `temperature` when forced on an unknown model; forced
off on gpt-5 drops `reasoning` and keeps `temperature`; unset
unchanged), `TestAIGatewayModelBedrockReasoningModelOverride` (Bedrock
provider path), `TestIsZeroChatModelCallConfigReasoningModel`, and
form-logic cases serializing the field for openai and bedrock.
Red-green: removing the constructor wiring fails the request-body
assertions.
- `go test ./coderd/x/chatd/... -count=1` (full), `go test
./codersdk/... -run ChatModel`, `go test ./coderd/ -run
'ChatModel|Chats'`, `golangci-lint run ./coderd/x/chatd/...
./codersdk/... ./coderd/` (0 issues), `make gen` (stable on rerun),
Vitest for `src/modules/aiModels` and `src/api/chatModelOptions` (174
tests), Biome, `tsc --noEmit`, `make pre-commit`.
- Remote dogfood UAT (Coder Agents) exercised the editor and chat on the
dev AI gateway: the switch shows for OpenAI and Bedrock providers only,
persists true/false/unset, and `gpt-daybreak-blue-latest` (an alias the
SDK does not recognize) sends `reasoning` without `temperature` when
forced on and gets OpenAI's temperature 400 when off or unset. UAT also
found the new switch colliding with `Use Responses API` at 375px;
tri-state switches now take the full row below `sm`. One open
observation for follow-up: in Coder chats on `gpt-6-astra` the upstream
stream carried no reasoning-summary events even though
`reasoning.summary=detailed` was sent, while the same model returns
summaries to a standalone fantasy client; not attributed to this change.
- Merged `origin/main` (`eceae296e8d`; the only conflict was the
ARCHITECTURE.md TODO block, resolved by keeping main's
transport-selection prose and adding a TODO for the GPT-6 Astra sentence
this PR makes stale) and moved the pin (`553bfb86bf5`). On that head:
`go build ./...`, `go vet ./coderd/x/chatd/... ./codersdk/`, `go test
./coderd/x/chatd/ -run
'ReasoningModel|TestAIGateway|Bedrock|ChatModelCallConfig|Quickgen|Transport'`,
`go test ./coderd/x/chatd/chatopenai/...
./coderd/x/chatd/chatprovider/... ./coderd/x/chatd/chatdebug/...`, `go
test ./codersdk/ -run 'ChatModel|Reasoning'`, and the pre-commit hook on
both commits. The `providers/openai` tree at `a511353f83eb` is
byte-identical to the previously pinned PR head `f5b3f253c112`.
- The local `pre-push` hook fails in this checkout only on unrelated
tests (umask-dependent `TestGetModulesArchive`, two untouched site
tests), so the push bypassed it; CI is the gate. For the pin-bump push
the hook ran once in full (31,276 tests passed; the only 2 failures were
`TestGetModulesArchive`, proven to be this checkout's 0600 file modes:
passes after normalizing modes and on an untouched `origin/main`
worktree) and was then opted out for this worktree per Mike's
instruction.

coder/fantasy#57 is merged (`a511353f83eb` on `coder_2_33`) and the pin
points at it. Related: #29229 (Bedrock `reasoning_summary` coercion).

> Xum acted on behalf of @ibetitsmike for this PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants