Skip to content

Commit 78f15fe

Browse files
Fix reasoning token streaming for gpt-5-mini and gpt-5-nano models (#94)
* fix: reasoning token streaming for gpt-5-mini and gpt-5-nano models * feat: add model-specific reasoning summary types (concise only for computer-use-preview) --------- Co-authored-by: Alem Tuzlak <t.zlak@hotmail.com>
1 parent f8b345b commit 78f15fe

File tree

6 files changed

+99
-19
lines changed

6 files changed

+99
-19
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@tanstack/ai-openai': patch
3+
---
4+
5+
Fix reasoning token streaming for `gpt-5-mini` and `gpt-5-nano` models
6+
7+
- Added `OpenAIReasoningOptions` to type definitions for `gpt-5-mini` and `gpt-5-nano` models
8+
- Fixed `summary` option placement in `OpenAIReasoningOptions` (moved inside `reasoning` object to match OpenAI SDK)
9+
- Added handler for `response.reasoning_summary_text.delta` events to stream reasoning summaries
10+
- Added model-specific `reasoning.summary` types: `concise` only available for `computer-use-preview`
11+
- Added `OpenAIReasoningOptionsWithConcise` for `computer-use-preview` model

docs/adapters/openai.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ Enable reasoning for models that support it (e.g., GPT-5). This allows the model
131131
```typescript
132132
providerOptions: {
133133
reasoning: {
134-
effort: "medium", // "minimal" | "low" | "medium" | "high"
134+
effort: "medium", // "none" | "minimal" | "low" | "medium" | "high"
135+
summary: "detailed", // "auto" | "detailed" (optional)
135136
},
136137
}
137138
```

packages/typescript/ai-openai/src/model-meta.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type {
22
OpenAIBaseOptions,
33
OpenAIMetadataOptions,
44
OpenAIReasoningOptions,
5+
OpenAIReasoningOptionsWithConcise,
56
OpenAIStreamingOptions,
67
OpenAIStructuredOutputOptions,
78
OpenAIToolsOptions,
@@ -198,6 +199,7 @@ const GPT5_MINI = {
198199
},
199200
} as const satisfies ModelMeta<
200201
OpenAIBaseOptions &
202+
OpenAIReasoningOptions &
201203
OpenAIStructuredOutputOptions &
202204
OpenAIToolsOptions &
203205
OpenAIStreamingOptions &
@@ -233,6 +235,7 @@ const GPT5_NANO = {
233235
},
234236
} as const satisfies ModelMeta<
235237
OpenAIBaseOptions &
238+
OpenAIReasoningOptions &
236239
OpenAIStructuredOutputOptions &
237240
OpenAIToolsOptions &
238241
OpenAIStreamingOptions &
@@ -815,6 +818,7 @@ const COMPUTER_USE_PREVIEW = {
815818
},
816819
} as const satisfies ModelMeta<
817820
OpenAIBaseOptions &
821+
OpenAIReasoningOptionsWithConcise &
818822
OpenAIToolsOptions &
819823
OpenAIStreamingOptions &
820824
OpenAIMetadataOptions
@@ -1787,11 +1791,13 @@ export type OpenAIChatModelProviderOptionsByName = {
17871791
OpenAIStreamingOptions &
17881792
OpenAIMetadataOptions
17891793
[GPT5_MINI.name]: OpenAIBaseOptions &
1794+
OpenAIReasoningOptions &
17901795
OpenAIStructuredOutputOptions &
17911796
OpenAIToolsOptions &
17921797
OpenAIStreamingOptions &
17931798
OpenAIMetadataOptions
17941799
[GPT5_NANO.name]: OpenAIBaseOptions &
1800+
OpenAIReasoningOptions &
17951801
OpenAIStructuredOutputOptions &
17961802
OpenAIToolsOptions &
17971803
OpenAIStreamingOptions &
@@ -1920,6 +1926,7 @@ export type OpenAIChatModelProviderOptionsByName = {
19201926

19211927
// Special models
19221928
[COMPUTER_USE_PREVIEW.name]: OpenAIBaseOptions &
1929+
OpenAIReasoningOptionsWithConcise &
19231930
OpenAIToolsOptions &
19241931
OpenAIStreamingOptions &
19251932
OpenAIMetadataOptions

packages/typescript/ai-openai/src/openai-adapter.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,29 @@ export class OpenAI extends BaseAdapter<
343343
}
344344
}
345345

346+
// Handle reasoning summary deltas (when using reasoning.summary option)
347+
// response.reasoning_summary_text.delta provides incremental summary updates
348+
if (
349+
chunk.type === 'response.reasoning_summary_text.delta' &&
350+
chunk.delta
351+
) {
352+
const summaryDelta =
353+
typeof chunk.delta === 'string' ? chunk.delta : ''
354+
355+
if (summaryDelta) {
356+
accumulatedReasoning += summaryDelta
357+
hasStreamedReasoningDeltas = true
358+
yield {
359+
type: 'thinking',
360+
id: responseId || generateId(),
361+
model: model || options.model,
362+
timestamp,
363+
delta: summaryDelta,
364+
content: accumulatedReasoning,
365+
}
366+
}
367+
}
368+
346369
// handle content_part added events for text, reasoning and refusals
347370
if (chunk.type === 'response.content_part.added') {
348371
const contentPart = chunk.part

packages/typescript/ai-openai/src/text/text-provider-options.ts

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ https://platform.openai.com/docs/api-reference/responses/create#responses_create
125125
}
126126

127127
// Feature fragments that can be stitched per-model
128+
129+
// Shared base types for reasoning options
130+
type ReasoningEffort = 'none' | 'minimal' | 'low' | 'medium' | 'high'
131+
type ReasoningSummary = 'auto' | 'detailed'
132+
133+
/**
134+
* Reasoning options for most models (excludes 'concise' summary).
135+
*/
128136
export interface OpenAIReasoningOptions {
129137
/**
130138
* Reasoning controls for models that support it.
@@ -138,13 +146,39 @@ export interface OpenAIReasoningOptions {
138146
* All models before gpt-5.1 default to medium reasoning effort, and do not support none.
139147
* The gpt-5-pro model defaults to (and only supports) high reasoning effort.
140148
*/
141-
effort?: 'none' | 'minimal' | 'low' | 'medium' | 'high'
149+
effort?: ReasoningEffort
150+
/**
151+
* A summary of the reasoning performed by the model. This can be useful for debugging and understanding the model's reasoning process.
152+
* https://platform.openai.com/docs/api-reference/responses/create#responses_create-reasoning-summary
153+
*/
154+
summary?: ReasoningSummary
142155
}
156+
}
157+
158+
/**
159+
* Reasoning options for computer-use-preview model (includes 'concise' summary).
160+
*/
161+
export interface OpenAIReasoningOptionsWithConcise {
143162
/**
144-
* A summary of the reasoning performed by the model. This can be useful for debugging and understanding the model's reasoning process
145-
* https://platform.openai.com/docs/api-reference/responses/create#responses_create-reasoning-summary
163+
* Reasoning controls for models that support it.
164+
* Lets you guide how much chain-of-thought computation to spend.
165+
* https://platform.openai.com/docs/api-reference/responses/create#responses_create-reasoning
166+
* https://platform.openai.com/docs/guides/reasoning
146167
*/
147-
summary?: 'auto' | 'concise' | 'detailed'
168+
reasoning?: {
169+
/**
170+
* gpt-5.1 defaults to none, which does not perform reasoning. The supported reasoning values for gpt-5.1 are none, low, medium, and high. Tool calls are supported for all reasoning values in gpt-5.1.
171+
* All models before gpt-5.1 default to medium reasoning effort, and do not support none.
172+
* The gpt-5-pro model defaults to (and only supports) high reasoning effort.
173+
*/
174+
effort?: ReasoningEffort
175+
/**
176+
* A summary of the reasoning performed by the model. This can be useful for debugging and understanding the model's reasoning process.
177+
* `concise` is only supported for `computer-use-preview` models.
178+
* https://platform.openai.com/docs/api-reference/responses/create#responses_create-reasoning-summary
179+
*/
180+
summary?: ReasoningSummary | 'concise'
181+
}
148182
}
149183

150184
export interface OpenAIStructuredOutputOptions {

packages/typescript/ai-openai/tests/model-meta.test.ts

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
import type {
77
OpenAIBaseOptions,
88
OpenAIReasoningOptions,
9+
OpenAIReasoningOptionsWithConcise,
910
OpenAIStructuredOutputOptions,
1011
OpenAIToolsOptions,
1112
OpenAIStreamingOptions,
@@ -111,12 +112,12 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
111112
})
112113
})
113114

114-
describe('Models WITH structured output AND tools but WITHOUT reasoning (Standard)', () => {
115-
it('gpt-5-mini should have structured output and tools but NOT reasoning', () => {
115+
describe('Models WITH reasoning AND structured output AND tools (gpt-5-mini/nano)', () => {
116+
it('gpt-5-mini should have reasoning, structured output and tools', () => {
116117
type Options = OpenAIChatModelProviderOptionsByName['gpt-5-mini']
117118

118-
// Should NOT have reasoning options
119-
expectTypeOf<Options>().not.toExtend<OpenAIReasoningOptions>()
119+
// Should have reasoning options
120+
expectTypeOf<Options>().toExtend<OpenAIReasoningOptions>()
120121

121122
// Should have structured output options
122123
expectTypeOf<Options>().toExtend<OpenAIStructuredOutputOptions>()
@@ -131,16 +132,18 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
131132
expectTypeOf<Options>().toExtend<BaseOptions>()
132133
})
133134

134-
it('gpt-5-nano should have structured output and tools but NOT reasoning', () => {
135+
it('gpt-5-nano should have reasoning, structured output and tools', () => {
135136
type Options = OpenAIChatModelProviderOptionsByName['gpt-5-nano']
136137

137-
expectTypeOf<Options>().not.toExtend<OpenAIReasoningOptions>()
138+
expectTypeOf<Options>().toExtend<OpenAIReasoningOptions>()
138139
expectTypeOf<Options>().toExtend<OpenAIStructuredOutputOptions>()
139140
expectTypeOf<Options>().toExtend<OpenAIToolsOptions>()
140141
expectTypeOf<Options>().toExtend<OpenAIStreamingOptions>()
141142
expectTypeOf<Options>().toExtend<BaseOptions>()
142143
})
144+
})
143145

146+
describe('Models WITH structured output AND tools but WITHOUT reasoning (Standard)', () => {
144147
it('gpt-5-codex should have structured output and tools but NOT reasoning', () => {
145148
type Options = OpenAIChatModelProviderOptionsByName['gpt-5-codex']
146149

@@ -439,11 +442,12 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
439442
expectTypeOf<Options>().toExtend<BaseOptions>()
440443
})
441444

442-
it('computer-use-preview should have tools but NOT structured output', () => {
445+
it('computer-use-preview should have tools and reasoning with concise but NOT structured output', () => {
443446
type Options =
444447
OpenAIChatModelProviderOptionsByName['computer-use-preview']
445448

446-
expectTypeOf<Options>().not.toExtend<OpenAIReasoningOptions>()
449+
// Should have reasoning options with 'concise' summary support
450+
expectTypeOf<Options>().toExtend<OpenAIReasoningOptionsWithConcise>()
447451
expectTypeOf<Options>().not.toExtend<OpenAIStructuredOutputOptions>()
448452
expectTypeOf<Options>().toExtend<OpenAIToolsOptions>()
449453
expectTypeOf<Options>().toExtend<OpenAIStreamingOptions>()
@@ -698,13 +702,16 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
698702
>().toExtend<FullFeaturedOptions>()
699703
})
700704

701-
it('standard models should NOT extend reasoning options but should extend structured output and tools', () => {
705+
it('gpt-5-mini and gpt-5-nano should extend FullFeaturedOptions (reasoning + structured output + tools)', () => {
702706
expectTypeOf<
703707
OpenAIChatModelProviderOptionsByName['gpt-5-mini']
704-
>().toExtend<StandardOptions>()
708+
>().toExtend<FullFeaturedOptions>()
705709
expectTypeOf<
706710
OpenAIChatModelProviderOptionsByName['gpt-5-nano']
707-
>().toExtend<StandardOptions>()
711+
>().toExtend<FullFeaturedOptions>()
712+
})
713+
714+
it('standard models should NOT extend reasoning options but should extend structured output and tools', () => {
708715
expectTypeOf<
709716
OpenAIChatModelProviderOptionsByName['gpt-4.1']
710717
>().toExtend<StandardOptions>()
@@ -719,9 +726,6 @@ describe('OpenAI Chat Model Provider Options Type Assertions', () => {
719726
>().toExtend<StandardOptions>()
720727

721728
// Verify these do NOT extend reasoning options (discrimination already tested above)
722-
expectTypeOf<
723-
OpenAIChatModelProviderOptionsByName['gpt-5-mini']
724-
>().not.toExtend<OpenAIReasoningOptions>()
725729
expectTypeOf<
726730
OpenAIChatModelProviderOptionsByName['gpt-4.1']
727731
>().not.toExtend<OpenAIReasoningOptions>()

0 commit comments

Comments
 (0)