Skip to content

Commit bc978f7

Browse files
committed
fix(providers): pass max reasoning effort through on the Responses API for probe-verified models
1 parent d59bac5 commit bc978f7

2 files changed

Lines changed: 46 additions & 6 deletions

File tree

src/core/llm/providers/__tests__/model-effort.test.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import {
44
isEffortLevel,
55
EFFORT_LEVELS,
66
mapEffortToOpenAiReasoningEffort,
7+
mapEffortToOpenAiReasoningEffortForModel,
78
mapEffortToOpenAiResponsesEffort,
89
modelAcceptsXhighResponsesEffort,
10+
modelAcceptsMaxResponsesEffort,
911
} from '../model-effort.js';
1012

1113
describe('modelSupportsEffort', () => {
@@ -85,11 +87,23 @@ describe('mapEffortToOpenAiResponsesEffort (model-aware /v1/responses effort)',
8587
expect(mapEffortToOpenAiResponsesEffort('gpt-5.5', 'xhigh')).toBe('xhigh');
8688
});
8789

88-
it('passes xhigh through for gpt-5.6 / gpt-5.6-sol (max -> xhigh, allow-listed)', () => {
89-
expect(mapEffortToOpenAiResponsesEffort('gpt-5.6', 'max')).toBe('xhigh');
90+
it('passes the real max tier through for the gpt-5.6 family (live-probed 2026-08-06)', () => {
91+
expect(modelAcceptsMaxResponsesEffort('gpt-5.6')).toBe(true);
92+
expect(modelAcceptsMaxResponsesEffort('gpt-5.6-sol')).toBe(true);
93+
expect(mapEffortToOpenAiResponsesEffort('gpt-5.6', 'max')).toBe('max');
94+
expect(mapEffortToOpenAiResponsesEffort('gpt-5.6-sol', 'max')).toBe('max');
95+
// xhigh stays xhigh — the unlock only touches the max tier.
9096
expect(mapEffortToOpenAiResponsesEffort('gpt-5.6-sol', 'xhigh')).toBe('xhigh');
9197
});
9298

99+
it('keeps max clamped to xhigh off the allow-list (gpt-5.5) and chat-side everywhere', () => {
100+
expect(modelAcceptsMaxResponsesEffort('gpt-5.5')).toBe(false);
101+
expect(modelAcceptsMaxResponsesEffort('gpt-5.4')).toBe(false);
102+
expect(mapEffortToOpenAiResponsesEffort('gpt-5.5', 'max')).toBe('xhigh');
103+
// Chat Completions rejects max for the 5.6 family (probed 2026-07-20 + 2026-08-06).
104+
expect(mapEffortToOpenAiReasoningEffortForModel('max', 'gpt-5.6')).toBe('xhigh');
105+
});
106+
93107
it('caps xhigh -> high for a non-allow-listed gpt-5 model', () => {
94108
expect(mapEffortToOpenAiResponsesEffort('gpt-5.4', 'max')).toBe('high');
95109
expect(mapEffortToOpenAiResponsesEffort('gpt-5-mini', 'xhigh')).toBe('high');

src/core/llm/providers/model-effort.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,44 @@ export function modelAcceptsXhighResponsesEffort(modelId: string): boolean {
6868
return /^gpt-5\.[56]/i.test(modelId);
6969
}
7070

71+
/**
72+
* Responses-API models whose `reasoning.effort` accepts `'max'` — the tier
73+
* ABOVE `xhigh`, and a Responses-API-only surface (Chat Completions rejects
74+
* `max` for the same family; see {@link CHAT_MAX_EFFORT_MODELS} below).
75+
* Live-probed per entry — record request shape, status, response summary,
76+
* date, and the exact model alias in this comment when adding one.
77+
*
78+
* 2026-08-06 probe (POST /v1/responses, `reasoning: {effort: 'max'}`,
79+
* max_output_tokens 2000): HTTP 200 `status: completed` on `gpt-5.6` (bare
80+
* alias), on `gpt-5.6-sol`, and on `gpt-5.6-sol` WITH function tools
81+
* attached (the agentic shape). Boundary probes the same day: `'ultra'` is
82+
* rejected on both aliases (`Invalid value: 'ultra'. Supported values are:
83+
* 'none', 'minimal', 'low', 'medium', 'high', 'xhigh', and 'max'.`), and
84+
* chat.completions still 400s on `max` for the family. Widen only after a
85+
* fresh Responses probe returns HTTP 200 on the new id.
86+
*/
87+
const RESPONSES_MAX_EFFORT_MODELS: readonly string[] = ['gpt-5.6'];
88+
89+
/** Whether `modelId` is on the probe-verified Responses `max` allow-list. */
90+
export function modelAcceptsMaxResponsesEffort(modelId: string): boolean {
91+
return RESPONSES_MAX_EFFORT_MODELS.some((f) => modelId.toLowerCase().startsWith(f));
92+
}
93+
7194
/**
7295
* Map the agentos effort scale onto OpenAI's `/v1/responses` `reasoning.effort`
73-
* for `modelId`. Identical to {@link mapEffortToOpenAiReasoningEffort} EXCEPT it
74-
* caps `xhigh` → `high` for any model NOT on
75-
* {@link modelAcceptsXhighResponsesEffort} — a model-aware guard so a request
96+
* for `modelId`. Identical to {@link mapEffortToOpenAiReasoningEffort} EXCEPT:
97+
* `max` passes through as the real `'max'` tier on models probe-verified via
98+
* {@link modelAcceptsMaxResponsesEffort} (elsewhere it clamps to `'xhigh'` as
99+
* before), and `xhigh` caps to `high` for any model NOT on
100+
* {@link modelAcceptsXhighResponsesEffort} — model-aware guards so a request
76101
* for maximum depth degrades one step instead of 400ing the whole Responses
77-
* call on a model that rejects `xhigh`.
102+
* call on a model that rejects the tier.
78103
*/
79104
export function mapEffortToOpenAiResponsesEffort(
80105
modelId: string,
81106
effort: unknown,
82107
): string | undefined {
108+
if (effort === 'max' && modelAcceptsMaxResponsesEffort(modelId)) return 'max';
83109
const base = mapEffortToOpenAiReasoningEffort(effort);
84110
if (base === undefined) return undefined;
85111
return base === 'xhigh' && !modelAcceptsXhighResponsesEffort(modelId) ? 'high' : base;

0 commit comments

Comments
 (0)