Skip to content

fix(ai): skip stringifying text when streaming partial text#14123

Merged
aayush-kapoor merged 5 commits intomainfrom
aayush/stream-text-stringify
Apr 7, 2026
Merged

fix(ai): skip stringifying text when streaming partial text#14123
aayush-kapoor merged 5 commits intomainfrom
aayush/stream-text-stringify

Conversation

@aayush-kapoor
Copy link
Copy Markdown
Collaborator

@aayush-kapoor aayush-kapoor commented Apr 3, 2026

Background

#13839

streamText with the default text output called JSON.stringify on the full accumulated text on every single streaming chunk that creates increasingly large string copies per stream casuing memory issues

Summary

  • skip JSON.stringify when the partial output is already a string
  • structured outputs still go through stringify as before since they need serialization to compare.
  • compare the text directly
  • no extra full-string serialization per chunk

Manual Verification

tried reproducing via

repro
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';
import { run } from '../../lib/run';

run(async () => {
  const result = streamText({
    model: openai.responses('gpt-4o-mini'),
    prompt:
      'Write an extremely detailed 5000-word essay about the history of computing. Include every detail you can.',
  });

  let chunks = 0;
  for await (const textPart of result.textStream) {
    chunks++;
    if (chunks % 100 === 0) {
      const mb = (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(1);
      console.log(`chunk ${chunks} — heap: ${mb}MB`);
    }
  }

  console.log(`\nTotal chunks: ${chunks}`);
  console.log(
    `Final heap: ${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(1)}MB`,
  );
});

Checklist

  • Tests have been added / updated (for bug fixes / features)
  • Documentation has been added / updated (for bug fixes / features)
  • A patch changeset for relevant packages has been added (for bug fixes / features - run pnpm changeset in the project root)
  • I have reviewed this pull request (self-review)

Related Issues

fixes #13839

@tigent tigent bot added ai/core core functions like generateText, streamText, etc. Provider utils, and provider spec. bug Something isn't working as documented reproduction provided labels Apr 3, 2026
if (result !== undefined) {
// only send new json if it has changed:
const currentJson = JSON.stringify(result.partial);
const currentJson =
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

worth adding a comment why the logic is here

Copy link
Copy Markdown
Collaborator

@lgrammel lgrammel Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also this can lead to downstream issues, because currentJson is not JSON in those cases (the variable name is now misleading)

lgrammel
lgrammel previously approved these changes Apr 7, 2026
@lgrammel lgrammel self-requested a review April 7, 2026 08:44
@lgrammel lgrammel dismissed their stale review April 7, 2026 08:45

concern found

@aayush-kapoor aayush-kapoor added the backport Admins only: add this label to a pull request in order to backport it to the prior version label Apr 7, 2026
@aayush-kapoor aayush-kapoor merged commit e68be55 into main Apr 7, 2026
21 checks passed
@aayush-kapoor aayush-kapoor deleted the aayush/stream-text-stringify branch April 7, 2026 18:34
vercel-ai-sdk bot pushed a commit that referenced this pull request Apr 7, 2026
## Background

#13839

streamText with the default text output called JSON.stringify on the
full accumulated text on every single streaming chunk that creates
increasingly large string copies per stream casuing memory issues

## Summary

- skip `JSON.stringify` when the partial output is already a string
- structured outputs still go through stringify as before since they
need serialization to compare.
- compare the text directly
- no extra full-string serialization per chunk

## Manual Verification

tried reproducing via 
<details>
<summary>repro</summary>

```ts
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';
import { run } from '../../lib/run';

run(async () => {
  const result = streamText({
    model: openai.responses('gpt-4o-mini'),
    prompt:
      'Write an extremely detailed 5000-word essay about the history of computing. Include every detail you can.',
  });

  let chunks = 0;
  for await (const textPart of result.textStream) {
    chunks++;
    if (chunks % 100 === 0) {
      const mb = (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(1);
      console.log(`chunk ${chunks} — heap: ${mb}MB`);
    }
  }

  console.log(`\nTotal chunks: ${chunks}`);
  console.log(
    `Final heap: ${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(1)}MB`,
  );
});
```
</details>

## Checklist

- [x] Tests have been added / updated (for bug fixes / features)
- [ ] Documentation has been added / updated (for bug fixes / features)
- [x] A _patch_ changeset for relevant packages has been added (for bug
fixes / features - run `pnpm changeset` in the project root)
- [x] I have reviewed this pull request (self-review)

## Related Issues

fixes #13839
@vercel-ai-sdk vercel-ai-sdk bot removed the backport Admins only: add this label to a pull request in order to backport it to the prior version label Apr 7, 2026
@vercel-ai-sdk
Copy link
Copy Markdown
Contributor

vercel-ai-sdk bot commented Apr 7, 2026

✅ Backport PR created: #14200

vercel-ai-sdk bot added a commit that referenced this pull request Apr 7, 2026
…#14200)

This is an automated backport of #14123 to the release-v6.0 branch. FYI
@aayush-kapoor

Co-authored-by: Aayush Kapoor <83492835+aayush-kapoor@users.noreply.github.com>
gr2m pushed a commit that referenced this pull request Apr 7, 2026
## Background

#13839

streamText with the default text output called JSON.stringify on the
full accumulated text on every single streaming chunk that creates
increasingly large string copies per stream casuing memory issues

## Summary

- skip `JSON.stringify` when the partial output is already a string
- structured outputs still go through stringify as before since they
need serialization to compare.
- compare the text directly
- no extra full-string serialization per chunk

## Manual Verification

tried reproducing via 
<details>
<summary>repro</summary>

```ts
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';
import { run } from '../../lib/run';

run(async () => {
  const result = streamText({
    model: openai.responses('gpt-4o-mini'),
    prompt:
      'Write an extremely detailed 5000-word essay about the history of computing. Include every detail you can.',
  });

  let chunks = 0;
  for await (const textPart of result.textStream) {
    chunks++;
    if (chunks % 100 === 0) {
      const mb = (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(1);
      console.log(`chunk ${chunks} — heap: ${mb}MB`);
    }
  }

  console.log(`\nTotal chunks: ${chunks}`);
  console.log(
    `Final heap: ${(process.memoryUsage().heapUsed / 1024 / 1024).toFixed(1)}MB`,
  );
});
```
</details>

## Checklist

- [x] Tests have been added / updated (for bug fixes / features)
- [ ] Documentation has been added / updated (for bug fixes / features)
- [x] A _patch_ changeset for relevant packages has been added (for bug
fixes / features - run `pnpm changeset` in the project root)
- [x] I have reviewed this pull request (self-review)

## Related Issues

fixes #13839
@vercel-ai-sdk
Copy link
Copy Markdown
Contributor

vercel-ai-sdk bot commented Apr 7, 2026

🚀 Published in:

Package Version
ai 7.0.0-beta.71
@ai-sdk/angular 3.0.0-beta.71
@ai-sdk/gateway 4.0.0-beta.40
@ai-sdk/langchain 3.0.0-beta.71
@ai-sdk/llamaindex 3.0.0-beta.71
@ai-sdk/otel 1.0.0-beta.17
@ai-sdk/react 4.0.0-beta.71
@ai-sdk/rsc 3.0.0-beta.72
@ai-sdk/svelte 5.0.0-beta.71
@ai-sdk/vue 4.0.0-beta.71

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai/core core functions like generateText, streamText, etc. Provider utils, and provider spec. bug Something isn't working as documented reproduction provided

Projects

None yet

Development

Successfully merging this pull request may close these issues.

streamText Memory Issue: parsePartialOutput creates O(n) string copies

2 participants