You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Think sends cf_agent_chat_messages / cf_agent_use_chat_response to connections where shouldSendProtocolMessages() returns false #2637
Versions:@cloudflare/think 0.20.2 and agents 0.28.1. Still reproduces on 0.21.0 and 0.29.0, and the inspected main at fc7f59f has the same code.
What happens
Agent.shouldSendProtocolMessages() is documented as: "When this returns false for a connection, that connection will not receive any protocol text frames — neither on connect nor via broadcasts." The base Agent honours it: no identity, state or MCP frames are sent. Think doesn't:
Think's onConnect wrapper (_setupProtocolHandlers) sends _buildIdleConnectMessages() (the whole transcript) or _notifyStreamResuming() to every new connection. That wrapper is installed in onStart, so it runs before the base Agent's wrapper sets the per-connection protocol flag. _preStream.park() can also send cf_agent_stream_pending there.
_broadcastChat() and _broadcast() call this.broadcast() with no protocol filter. The base Agent's _broadcastProtocol() excludes connections where isConnectionProtocolEnabled() is false.
Reproduction
exportclassFramesAgentextendsThink<Env>{getModel(){returnscripted(()=>text("one two three four five"));}shouldSendProtocolMessages(){returnfalse;}// every connection opts outonMessage(){}// the socket speaks the app's own protocolasyncturn(){returnthis.runTurn({input: "hi"});}}
Open a WebSocket to /agents/frames-agent/x, then call turn() over RPC. The socket receives:
on connect: cf_agent_chat_messages
during turn: cf_agent_use_chat_response ×12, cf_agent_chat_messages ×2
Expected: none of those frames. No cf_agent_identity, cf_agent_state or cf_agent_mcp_servers arrive, which is correct.
Workaround: override broadcast() to exclude the app's sockets, and replace the private _buildIdleConnectMessages and _notifyStreamResuming on the instance.
Proposed fix
In Think's onConnect wrapper, skip the transcript, resume and park frames when !this.shouldSendProtocolMessages(connection, ctx). Asking the hook directly is needed because the flag isn't set yet at that point.
In _broadcastChat() and _broadcast(), exclude connections where !this.isConnectionProtocolEnabled(c), as _broadcastProtocol() does. Alternatively, route both through _broadcastProtocol().
Patching those three places in the 0.21.0 build gives zero frames on the opted-out socket. In-browser clients using useAgentChat are unaffected, because they keep the default true.
Activity