Skip to content

Conversation

@DukeDeSouth
Copy link

@DukeDeSouth DukeDeSouth commented Feb 6, 2026

Human View

Summary

Fixes #7819

The transport option (including body, headers) passed to useChat was captured once when the Chat instance was created and never updated on subsequent renders. This caused transport.body values referencing React state to always send the initial (stale) value, even when the state changed.

Problem

const [subagent, setSubagent] = useState('todos-agent');

useChat({
  transport: new DefaultChatTransport({
    body: { subagent }, // ← always sends initial value 'todos-agent'
  }),
});

Workarounds like passing body as a function also didn't help because the entire transport was stale.

Fix

Applied the same ref-based indirection pattern already used for callbacks (onToolCall, onFinish, onData, onError, sendAutomaticallyWhen) to the transport option:

  1. A transportRef is created and updated on every render with the latest transport
  2. The Chat instance receives stable wrapper functions that always delegate to transportRef.current
  3. When sendMessages or reconnectToStream is called, it executes on the latest transport with fresh body/headers values

This is a minimal, non-breaking change — only packages/react/src/use-chat.ts is modified, following the existing pattern exactly.

Verification

  • Existing test suite passes (28 pre-existing failures on Node 25, identical on main)
  • No new test failures introduced
  • Pattern is identical to the existing callbacks ref pattern (lines 64-86) that already prevents stale closures for onToolCall etc.

AI View (DCCE Protocol v1.0)

Metadata

  • Generator: Claude (Anthropic) via Cursor IDE
  • Methodology: AI-assisted development with human oversight and review

AI Contribution Summary

  • Solution design and implementation

Verification Steps Performed

  1. Reproduced the reported issue
  2. Analyzed source code to identify root cause
  3. Implemented and tested the fix

Human Review Guidance

  • Core changes are in: transport.body, transportRef.current, packages/react/src/use-chat.ts
  • Review the breaking change implications

Made with M7 Cursor

Apply the same ref-based indirection pattern used for callbacks (onToolCall,
onFinish, etc.) to the transport option. The transport is now wrapped in
stable delegate functions that always read from the latest ref, ensuring
state-dependent body/headers values are fresh when sendMessages is called.

Fixes vercel#7819

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel-ai-sdk vercel-ai-sdk bot added the ai/ui label Feb 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

In useChat in @ai-sdk/react, state sent via transport#body is always stale

1 participant