Description
pruneMessages({ reasoning: 'all' }) removes reasoning text parts but leaves reasoning-file parts. reasoning: 'before-last-message' also leaves reasoning files in older messages.
This means intermediate reasoning images remain in history and are sent to the next model call even when the caller explicitly removes reasoning. I reproduced that with responseMessages from both generateText and streamText using the SDK test model.
Expected: remove both kinds of reasoning in the selected messages, while keeping regular file and text parts. Preserve reasoning in the last message for before-last-message.
The filter on current main only checks part.type !== 'reasoning'.
Related: #13430 concerns reasoning left behind after pruning tool calls; #11036 concerns OpenAI references after pruning. This report is about explicitly pruning the reasoning-file content type, without tool calls or provider metadata.
Reproduction
No API key or provider request is needed. In an empty directory:
npm init -y
npm install --ignore-scripts --save-exact ai@7.0.106 zod@4.4.3
node repro.mts
Save as repro.mts and run with Node 22.20+ or 24:
import { pruneMessages, type ModelMessage } from 'ai';
// Synthetic one-pixel PNG, representing an intermediate reasoning image.
const image = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGP4//8/AAX+Av4N70a4AAAAAElFTkSuQmCC';
const messages: ModelMessage[] = [{
role: 'assistant',
content: [
{ type: 'reasoning', text: 'Intermediate reasoning.' },
{ type: 'reasoning-file', mediaType: 'image/png', data: image },
{ type: 'file', mediaType: 'image/png', data: image },
{ type: 'text', text: 'Done.' },
],
}];
const pruned = pruneMessages({ messages, reasoning: 'all' });
console.log(pruned.flatMap(message =>
typeof message.content === 'string' ? [] : message.content.map(part => part.type),
));
// Actual: ['reasoning-file', 'file', 'text']
// Expected: ['file', 'text']
The fix appears to be extending the existing filter:
content: message.content.filter(
part => part.type !== 'reasoning' && part.type !== 'reasoning-file',
),
Local tests cover both pruning modes, empty-message handling, ordinary file preservation, unchanged input history, and a second model call using pruned SDK-generated history. There are 6 failing regressions and 6 passing controls on both tested package versions and Node runtimes. Testing the current-main helper in isolation gives the same result; the proposed filter change makes all 12 pass. Full upstream suites have not been run. The reproduction passes strict TypeScript checking.
I used AI assistance to investigate and prepare the synthetic reproduction, tests, and proposed change.
AI SDK Version
ai: 7.0.101 and 7.0.106 (unmodified npm packages)
zod: 4.4.3
- Node.js: 22.20.0 and 24.13.0
- Main helper tested in isolation at
9528712c364c6cb46caf97b901bb742d0c623cd7; the full main checkout was not rebuilt.
Code of Conduct
Description
pruneMessages({ reasoning: 'all' })removesreasoningtext parts but leavesreasoning-fileparts.reasoning: 'before-last-message'also leaves reasoning files in older messages.This means intermediate reasoning images remain in history and are sent to the next model call even when the caller explicitly removes reasoning. I reproduced that with
responseMessagesfrom bothgenerateTextandstreamTextusing the SDK test model.Expected: remove both kinds of reasoning in the selected messages, while keeping regular
fileandtextparts. Preserve reasoning in the last message forbefore-last-message.The filter on current main only checks
part.type !== 'reasoning'.Related: #13430 concerns reasoning left behind after pruning tool calls; #11036 concerns OpenAI references after pruning. This report is about explicitly pruning the
reasoning-filecontent type, without tool calls or provider metadata.Reproduction
No API key or provider request is needed. In an empty directory:
Save as
repro.mtsand run with Node 22.20+ or 24:The fix appears to be extending the existing filter:
Local tests cover both pruning modes, empty-message handling, ordinary file preservation, unchanged input history, and a second model call using pruned SDK-generated history. There are 6 failing regressions and 6 passing controls on both tested package versions and Node runtimes. Testing the current-main helper in isolation gives the same result; the proposed filter change makes all 12 pass. Full upstream suites have not been run. The reproduction passes strict TypeScript checking.
I used AI assistance to investigate and prepare the synthetic reproduction, tests, and proposed change.
AI SDK Version
ai: 7.0.101 and 7.0.106 (unmodified npm packages)zod: 4.4.39528712c364c6cb46caf97b901bb742d0c623cd7; the full main checkout was not rebuilt.Code of Conduct