Skip to content

fix(agent-tools): clone run parts so StrictMode doesn't double streamed text (#1835)#1836

Merged
threepointone merged 1 commit into
mainfrom
fix/agent-tool-events-strictmode-double-text
Jun 29, 2026
Merged

fix(agent-tools): clone run parts so StrictMode doesn't double streamed text (#1835)#1836
threepointone merged 1 commit into
mainfrom
fix/agent-tool-events-strictmode-double-text

Conversation

@threepointone

@threepointone threepointone commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #1835useAgentToolEvents doubles every word of streamed text in React StrictMode / SSR frameworks (Next.js, TanStack Start, Remix).

Root cause

The agent-tool-event reducer is impure. In applyToRun (packages/agents/src/chat/agent-tools.ts), the chunk case did:

const parts = [...seeded.parts];

This is a shallow array copy — the new array's elements are the same object references as prev.parts. It then calls applyChunkToParts, which mutates part objects in place (e.g. lastTextPart.text += delta). So the mutation leaks back into the previous state object.

React double-invokes setState updaters in StrictMode and during dev hydration (hydrateRoot). Because useAgentToolEvents updates via setState((prev) => applyAgentToolEvent(prev, message)), each text-delta is applied twice against the same, already-mutated prev → doubled text.

Fix

Clone each part before mutating, so the reducer stays pure:

const parts = seeded.parts.map((part) => ({ ...part }) as Part);

Every mutation in applyChunkToParts targets a top-level field of a part (text, state, input, output, data, …), so a per-part shallow copy is sufficient — no deep clone needed. This matches the one-line fix proposed in the issue, with a typed cast for the generic Part.

Validity / accuracy of the report

Confirmed valid and accurate: the mechanism (shared references + in-place mutation + StrictMode double-invoke) is exactly as described, and the proposed fix resolves it.

Test plan

  • Added a regression test in packages/agents/src/chat/__tests__/agent-tools.test.ts that replays a text-delta against the same prev twice (simulating StrictMode) and asserts the result is not doubled and prev is left untouched.
  • vitest --project chat — all 24 tests pass.
  • oxlint + oxfmt --check clean on edited files.
  • tsc --noEmit clean for the agents package.
  • Changeset added (agents patch).

Made with Cursor


Open in Devin Review

…ouble text (#1835)

`applyToRun` shallow-copied a run's parts with `[...seeded.parts]`, sharing
element references with the previous state. `applyChunkToParts` then mutated
those part objects in place (e.g. `text += delta`), leaking the mutation into
`prev`. React double-invokes setState updaters in StrictMode / dev hydration,
so each text-delta was applied twice against the same already-mutated prev,
doubling streamed text in Next.js, TanStack Start, Remix, and any
<StrictMode> app. Clone each part before mutating to keep the reducer pure.

Co-authored-by: Cursor <cursoragent@cursor.com>
@changeset-bot

changeset-bot Bot commented Jun 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b9bbd64

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agents Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@pkg-pr-new

pkg-pr-new Bot commented Jun 29, 2026

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@1836

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@1836

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@1836

create-think

npm i https://pkg.pr.new/create-think@1836

hono-agents

npm i https://pkg.pr.new/hono-agents@1836

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@1836

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@1836

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@1836

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@1836

commit: b9bbd64

@threepointone threepointone merged commit 0544aa2 into main Jun 29, 2026
8 checks passed
@threepointone threepointone deleted the fix/agent-tool-events-strictmode-double-text branch June 29, 2026 18:34
@github-actions github-actions Bot mentioned this pull request Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

useAgentToolEvents doubles text in React StrictMode / SSR frameworks

1 participant