Repository navigation
fix(sse): route the public OpenAI GPT-5.6 family through the Responses API - #7242
Conversation
…s API OpenAI's Chat Completions endpoint rejects GPT-5.6 requests that combine function tools with an active reasoning_effort: 400 "Function tools with reasoning_effort are not supported for <model> in /v1/chat/completions. Please use /v1/responses instead." The openai (API-key) registry entries for gpt-5.6 / -sol / -terra / -luna were missing the per-model `targetFormat` tag, so every request was posted to /v1/chat/completions. Any agentic client sending tools + reasoning to openai/gpt-5.6-sol hit the 400 and burned a combo fallback attempt. OmniRoute already has the generic mechanism this needs — the same per-model `targetFormat: "openai-responses"` override that routes gpt-5.5-pro / gpt-5.4-pro (#5842). It drives BOTH the outbound URL (DefaultExecutor.buildUrl → api.openai.com/v1/responses) and the body translation (chatCore's resolveChatCoreTargetFormat → openai-responses). Tagging GPT_5_6_API_CAPABILITIES is therefore the whole fix; no new transport table or routing branch is required. Scoped to the public OpenAI API catalog: the codex provider has its own Responses transport and is untouched. Co-authored-by: Sutarto Jordan Chrisfivo <Jordannst@users.noreply.github.com> Inspired-by: decolua/9router#2547
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Aprovado tecnicamente — fail-without-fix confirmado (2/4 falham sem o fix) e sem colisão de arquivo com #7012/#7209 (constantes/arquivos diferentes). Mas o PR já sinaliza corretamente o ponto crítico: o #7101 ataca a MESMA causa-raiz com estratégia OPOSTA (descarta reasoning_effort em vez de re-rotear) e não exclui gpt-5.6 do seu escopo — se os dois forem mergeados sem decisão, o comportamento final de gpt-5.6+tools+reasoning depende da ordem de execução em chatCore.ts e pode anular este fix. Recomendo decidir ANTES de mergear ambos: ou #7101 exclui explicitamente os modelos com targetFormat já resolvido para 'openai-responses', ou só um dos dois entra. |
stripGpt5ReasoningWhenTools gated on provider+model-name alone, so once #7242 routes the public GPT-5.6 family to /v1/responses (targetFormat "openai-responses", which natively supports tools + reasoning), the two PRs would compose into the worst of both worlds: routed to the endpoint that supports reasoning, but reasoning stripped anyway. Pass the request's already-resolved targetFormat into the guard and skip the strip whenever it is not going out over /chat/completions, so the guard tracks the actual upstream surface instead of a model-name list that would need updating for every future GPT-5.x family. Reported-by: Tech Solution (@techsolutionmta) (decolua/9router#2540)
…n tools (#7101) * fix(openai): strip reasoning_effort when GPT-5.x tools present (port from 9router#2540) Raw api.openai.com Chat Completions rejects GPT-5.x reasoning models that carry both function tools and an active reasoning_effort with HTTP 400 ("Function tools with reasoning_effort are not supported ... Please use /v1/responses instead"). The existing forceResponsesUpstream guard only reroutes openai-compatible-* connections carrying MCP/tool_search tool shapes; the plain openai provider had no equivalent guard, so gpt-5.x models used with a coding client (function tools + any explicit reasoning effort) still hit the upstream 400. Add stripGpt5ReasoningWhenTools() (gpt5SamplingGuard.ts), wired into chatCore.ts alongside the existing sampling guard, to drop reasoning_effort/reasoning when function tools are present and reasoning is active, letting the request succeed on /v1/chat/completions. Reported-by: Tech Solution (@techsolutionmta) (decolua/9router#2540) * fix(openai): scope reasoning-strip guard to /chat/completions only stripGpt5ReasoningWhenTools gated on provider+model-name alone, so once #7242 routes the public GPT-5.6 family to /v1/responses (targetFormat "openai-responses", which natively supports tools + reasoning), the two PRs would compose into the worst of both worlds: routed to the endpoint that supports reasoning, but reasoning stripped anyway. Pass the request's already-resolved targetFormat into the guard and skip the strip whenever it is not going out over /chat/completions, so the guard tracks the actual upstream surface instead of a model-name list that would need updating for every future GPT-5.x family. Reported-by: Tech Solution (@techsolutionmta) (decolua/9router#2540)
…heaper-inference#7663) The PR added a `^gpt-5\.6(?:$|[-.])` fallback in getModelTargetFormat alongside the existing `-pro$` heuristic, but the only existing test file exercises curated ids (gpt-5.6/-sol/-terra/-luna) that already hit the registry's targetFormat fast path via GPT_5_6_API_CAPABILITIES (cheaper-inference#7242) — so the new regex branch itself was untested. Add cases for an un-curated variant, the gpt-5.60 non-match, and the openai-only scoping (never codex) to close the gap per Hard Rule cheaper-inference#8. Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouzapw@users.noreply.github.com>
…s API (cheaper-inference#7242) * fix(sse): route the public OpenAI GPT-5.6 family through the Responses API OpenAI's Chat Completions endpoint rejects GPT-5.6 requests that combine function tools with an active reasoning_effort: 400 "Function tools with reasoning_effort are not supported for <model> in /v1/chat/completions. Please use /v1/responses instead." The openai (API-key) registry entries for gpt-5.6 / -sol / -terra / -luna were missing the per-model `targetFormat` tag, so every request was posted to /v1/chat/completions. Any agentic client sending tools + reasoning to openai/gpt-5.6-sol hit the 400 and burned a combo fallback attempt. OmniRoute already has the generic mechanism this needs — the same per-model `targetFormat: "openai-responses"` override that routes gpt-5.5-pro / gpt-5.4-pro (cheaper-inference#5842). It drives BOTH the outbound URL (DefaultExecutor.buildUrl → api.openai.com/v1/responses) and the body translation (chatCore's resolveChatCoreTargetFormat → openai-responses). Tagging GPT_5_6_API_CAPABILITIES is therefore the whole fix; no new transport table or routing branch is required. Scoped to the public OpenAI API catalog: the codex provider has its own Responses transport and is untouched. Co-authored-by: Sutarto Jordan Chrisfivo <Jordannst@users.noreply.github.com> Inspired-by: decolua/9router#2547 * chore(changelog): fragment for cheaper-inference#7242 --------- Co-authored-by: Sutarto Jordan Chrisfivo <Jordannst@users.noreply.github.com>
…n tools (cheaper-inference#7101) * fix(openai): strip reasoning_effort when GPT-5.x tools present (port from 9router#2540) Raw api.openai.com Chat Completions rejects GPT-5.x reasoning models that carry both function tools and an active reasoning_effort with HTTP 400 ("Function tools with reasoning_effort are not supported ... Please use /v1/responses instead"). The existing forceResponsesUpstream guard only reroutes openai-compatible-* connections carrying MCP/tool_search tool shapes; the plain openai provider had no equivalent guard, so gpt-5.x models used with a coding client (function tools + any explicit reasoning effort) still hit the upstream 400. Add stripGpt5ReasoningWhenTools() (gpt5SamplingGuard.ts), wired into chatCore.ts alongside the existing sampling guard, to drop reasoning_effort/reasoning when function tools are present and reasoning is active, letting the request succeed on /v1/chat/completions. Reported-by: Tech Solution (@techsolutionmta) (decolua/9router#2540) * fix(openai): scope reasoning-strip guard to /chat/completions only stripGpt5ReasoningWhenTools gated on provider+model-name alone, so once cheaper-inference#7242 routes the public GPT-5.6 family to /v1/responses (targetFormat "openai-responses", which natively supports tools + reasoning), the two PRs would compose into the worst of both worlds: routed to the endpoint that supports reasoning, but reasoning stripped anyway. Pass the request's already-resolved targetFormat into the guard and skip the strip whenever it is not going out over /chat/completions, so the guard tracks the actual upstream surface instead of a model-name list that would need updating for every future GPT-5.x family. Reported-by: Tech Solution (@techsolutionmta) (decolua/9router#2540)
…s API (cheaper-inference#7242) * fix(sse): route the public OpenAI GPT-5.6 family through the Responses API OpenAI's Chat Completions endpoint rejects GPT-5.6 requests that combine function tools with an active reasoning_effort: 400 "Function tools with reasoning_effort are not supported for <model> in /v1/chat/completions. Please use /v1/responses instead." The openai (API-key) registry entries for gpt-5.6 / -sol / -terra / -luna were missing the per-model `targetFormat` tag, so every request was posted to /v1/chat/completions. Any agentic client sending tools + reasoning to openai/gpt-5.6-sol hit the 400 and burned a combo fallback attempt. OmniRoute already has the generic mechanism this needs — the same per-model `targetFormat: "openai-responses"` override that routes gpt-5.5-pro / gpt-5.4-pro (cheaper-inference#5842). It drives BOTH the outbound URL (DefaultExecutor.buildUrl → api.openai.com/v1/responses) and the body translation (chatCore's resolveChatCoreTargetFormat → openai-responses). Tagging GPT_5_6_API_CAPABILITIES is therefore the whole fix; no new transport table or routing branch is required. Scoped to the public OpenAI API catalog: the codex provider has its own Responses transport and is untouched. Co-authored-by: Sutarto Jordan Chrisfivo <Jordannst@users.noreply.github.com> Inspired-by: decolua/9router#2547 * chore(changelog): fragment for cheaper-inference#7242 --------- Co-authored-by: Sutarto Jordan Chrisfivo <Jordannst@users.noreply.github.com>
…n tools (cheaper-inference#7101) * fix(openai): strip reasoning_effort when GPT-5.x tools present (port from 9router#2540) Raw api.openai.com Chat Completions rejects GPT-5.x reasoning models that carry both function tools and an active reasoning_effort with HTTP 400 ("Function tools with reasoning_effort are not supported ... Please use /v1/responses instead"). The existing forceResponsesUpstream guard only reroutes openai-compatible-* connections carrying MCP/tool_search tool shapes; the plain openai provider had no equivalent guard, so gpt-5.x models used with a coding client (function tools + any explicit reasoning effort) still hit the upstream 400. Add stripGpt5ReasoningWhenTools() (gpt5SamplingGuard.ts), wired into chatCore.ts alongside the existing sampling guard, to drop reasoning_effort/reasoning when function tools are present and reasoning is active, letting the request succeed on /v1/chat/completions. Reported-by: Tech Solution (@techsolutionmta) (decolua/9router#2540) * fix(openai): scope reasoning-strip guard to /chat/completions only stripGpt5ReasoningWhenTools gated on provider+model-name alone, so once cheaper-inference#7242 routes the public GPT-5.6 family to /v1/responses (targetFormat "openai-responses", which natively supports tools + reasoning), the two PRs would compose into the worst of both worlds: routed to the endpoint that supports reasoning, but reasoning stripped anyway. Pass the request's already-resolved targetFormat into the guard and skip the strip whenever it is not going out over /chat/completions, so the guard tracks the actual upstream surface instead of a model-name list that would need updating for every future GPT-5.x family. Reported-by: Tech Solution (@techsolutionmta) (decolua/9router#2540)
Summary
reasoning_effort—400 "Function tools with reasoning_effort are not supported for <model> in /v1/chat/completions. Please use /v1/responses instead."Any agentic client hittingopenai/gpt-5.6-solwith tools + reasoning got the 400 and burned a combo fallback attempt.openai(API-key) registry entries forgpt-5.6/-sol/-terra/-lunawere missing the per-modeltargetFormattag, so every request went to/v1/chat/completions.targetFormat: "openai-responses"override that already routesgpt-5.5-pro/gpt-5.4-pro(fix(providers): Various OpenAI model returns [404] error due to endpoint #5842). It drives BOTH the outbound URL (DefaultExecutor.buildUrl→api.openai.com/v1/responses) and the body translation (resolveChatCoreTargetFormat→openai-responses). No new transport table or routing branch needed.Attribution
Thanks to @Jordannst for the original implementation.
Changes
open-sse/config/providers/shared.ts— addtargetFormat: "openai-responses"toGPT_5_6_API_CAPABILITIES(consumed only by the 4 public OpenAI GPT-5.6 catalog entries). Scoped to the public OpenAI API catalog; thecodexprovider has its own Responses transport and is untouched.tests/unit/openai-gpt56-responses-routing.test.ts— new regression test.Test plan
targeted unit test (new, fails before / passes after)
Before (on
release/v3.8.49):After:
ℹ tests 4 / ℹ pass 4 / ℹ fail 0npm run typecheck:core— cleannpx eslinton changed files — clean (exit 0)Negative coverage included:
gpt-5.4still resolves tonull//v1/chat/completions.Another in-flight change targets the same root cause (GPT-5.6 + tools + reasoning) with the opposite strategy, and the two should not land together without a decision:
reasoning_effortby routing the request to the Responses API.tests/unit/gpt5-tools-reasoning-guard.test.ts, currently uncommitted WIP) drops the client's reasoning when tools are present.They are mutually exclusive in intent: one keeps reasoning by changing the endpoint, the other silently discards it. Worth picking one deliberately rather than merging both.
FWIW that WIP test currently does not import — it pulls
stripGpt5ReasoningWhenToolsfromopen-sse/services/gpt5SamplingGuard.ts, which does not export that symbol.