Skip to content

Conversation

@BeiXiao
Copy link
Contributor

@BeiXiao BeiXiao commented Sep 15, 2025

Description

  • Issue: aiFetch captured the agent instance at hook init. After reconnect/replace, aiFetch still sent/received via the old (closed) socket (readyState 3) while the current agent was connected (readyState 1), breaking sendMessage and streaming.
  • Fix: keep a ref to the latest agent and read it inside aiFetch; memoize the transport so it doesn’t re-capture stale references.
  • Scope: internal only; no public API changes.

Reproduction

  1. Start a chat;
  2. trigger agent reconnect/replace;
  3. send a new message → no response or broken stream due to old agent being used.

Implementation

  • Add agentRef + effect to track the latest agent.
  • Wrap aiFetch with useCallback and use agentRef.current for send/addEventListener.
  • Wrap transport with useMemo, depending on agentUrlString and aiFetch.

@changeset-bot
Copy link

changeset-bot bot commented Sep 15, 2025

🦋 Changeset detected

Latest commit: 7df04c3

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

@pkg-pr-new
Copy link

pkg-pr-new bot commented Sep 15, 2025

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/agents@465

commit: 7df04c3

@whoiskatrin
Copy link
Contributor

@BeiXiao before we review, could you please fix the build? thank you

@whoiskatrin whoiskatrin added bug Something isn't working on the roadmap Feature accepted and planned for implementation labels Sep 15, 2025

return new Response(stream);
}
}, [agentUrlString]);
Copy link
Contributor

Choose a reason for hiding this comment

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

if we have this, why do we need to put agent on a ref?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

if we have this, why do we need to put agent on a ref?

The agentRef ensures we always use the latest agent object inside the callback. Without it, the callback would be stuck with the old agent from when it was first created.

Copy link
Contributor

Choose a reason for hiding this comment

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

but doesn't agentUrlString changing also capture the new agent instance?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but doesn't agentUrlString changing also capture the new agent instance?

OK, latest commit has removed agentUrlString from the dependency array.
The main issue here is that the agent captured in aiFetch is unconnected, so we used agentRef to preserve the agent instance.

…useCallback and memoize transport to prevent capturing outdated connections
@BeiXiao BeiXiao force-pushed the fix/ai-react-dynamic-agent-ref branch from 8bc7e8e to 763d12c Compare September 15, 2025 12:21
@BeiXiao
Copy link
Contributor Author

BeiXiao commented Sep 15, 2025

@BeiXiao before we review, could you please fix the build? thank you

Hi, fixed it, all checks have passed 🎉
Please continue review, thanks ~

@axuj
Copy link
Contributor

axuj commented Sep 16, 2025

Does this really fix the issue? It seems a bit strange. In the ai-sdk, the transport is used in AbstractChat #L214C2-L214C3, and the Chat instance is created in useChat #L61. The logic for ai-sdk to determine whether to update the chat instance is in useChat #L65. It appears that this change doesn't update the transport in the ai-sdk. To update the instance, you would need to pass a new chat or a new id, like in #440.

@jcheese1
Copy link

FYI just straight up removing <StrictMode /> fixed most of these issues for me

@fforres
Copy link

fforres commented Sep 18, 2025

We encountered something similar, I think this issue is related to this #440

Removing strict-mode prevents the "change of ID" from happening
In a way, similar outcome is done on issue 440. than with this: https://github.com/cloudflare/agents/pull/465/files#diff-c4dd80b36e6832a71f0a59b28423a9acf6068806810ec96899681f0b83e774a8R122-R125

Or if you do something like this:

const agent = useAgent({
  agent: 'chat',
  name: conversationId,
})
const agentChat = useAgentChat({
  agent,
  id: agent._pk,
})

Not sure what approach folks want to go with, but would be great to unify the conversations:

@whoiskatrin
Copy link
Contributor

We encountered something similar, I think this issue is related to this #440

Removing strict-mode prevents the "change of ID" from happening In a way, similar outcome is done on issue 440. than with this: https://github.com/cloudflare/agents/pull/465/files#diff-c4dd80b36e6832a71f0a59b28423a9acf6068806810ec96899681f0b83e774a8R122-R125

Or if you do something like this:

const agent = useAgent({
  agent: 'chat',
  name: conversationId,
})
const agentChat = useAgentChat({
  agent,
  id: agent._pk,
})

Not sure what approach folks want to go with, but would be great to unify the conversations:

super useful feedback, thanks for this, we just need to really dive deeply into whats happening and discuss the best available fix, should be not too long

Copy link
Contributor

@threepointone threepointone left a comment

Choose a reason for hiding this comment

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

ok I see now the problem, since useChat doesn't use the latest fetch passed to it. this PR looks good.

@threepointone
Copy link
Contributor

I don't recommend using _pk as the chat identifier since it's unique per connection, I suspect .name might be better... I need to dig into that. in the meanwhile, this PR seems ok.

@threepointone threepointone merged commit 6db2cd6 into cloudflare:main Sep 23, 2025
3 checks passed
@threepointone threepointone mentioned this pull request Sep 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working on the roadmap Feature accepted and planned for implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants