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
composeEventHandlers duplicates every streamed token when two ChatModelStreamHandlers collide #340
That is correct for observer-style handlers. It is wrong for ChatModelStreamHandler, which is not an observer — it is the dispatcher. Running it twice per chunk dispatches every content delta twice.
Reproduction
Two ChatModelStreamHandler instances over the same chunks, against a real graph:
Every token duplicated in the aggregated content the host renders and persists.
How it is reached
The SDK ships both halves of the collision:
getDefaultHandlers supplies [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler().
createRunHandlers always occupies CHAT_MODEL_STREAM with its own wrapper.
Composing the session adapter over the default handlers — a natural thing to do — produces exactly this. composeEventHandlers is public API (export * from './events').
Note on scope
#335 added a SDK_STREAM_DISPATCH brand and dispatchesChatModelStream() so that sealing can recognize a wrapped dispatcher through composeEventHandlers and createRunHandlers. That brand makes the double-dispatch case detectable but does not fix it — nothing currently refuses to compose two dispatchers.
A plausible fix, given the brand now exists: when both sides of a collision are branded as stream dispatchers, keep one rather than chaining them — a dispatcher is idempotent-by-replacement, not composable. Worth deciding whether that should warn.
Activity