feat(gateway): opt-in SSE side-channel for live token streaming to external chat clients - #876
Open
hashbender wants to merge 1 commit into
Open
feat(gateway): opt-in SSE side-channel for live token streaming to external chat clients#876hashbender wants to merge 1 commit into
hashbender wants to merge 1 commit into
Conversation
…ternal chat clients
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
An opt-in, transient Server-Sent-Events side-channel that lets an external chat client render assistant tokens live without platform edit-streaming. Built for (and shipping with) Keryx, an Android Matrix client that acts as a command interface for a Hermes agent — but the mechanism is platform-agnostic.
gateway/keryx_stream.py(new) — in-process pub/sub hub keyed by(platform, chat_id)+ the aiohttp handler forGET /keryx/stream?platform=…&chat_id=…on the existing API server (same Bearer auth viaAPI_SERVER_KEY, 20 s keepalive pings, bounded per-subscriber queues that drop on overflow rather than ever blocking the agent's worker thread).gateway/stream_consumer.py— mirrorsdelta/segment/stopevents to the hub (thread-safe:call_soon_threadsafeonto each subscriber's loop), and while a subscriber is attached, suppresses interval/threshold platform edits for that chat: the side-channel carries the tokens and the platform receives only the single final committed message.gateway/platforms/api_server.py— one route registration, wrapped in try/except so the API server is unaffected if the module is absent.Why
Matrix is the motivating case:
m.replaceedit-streaming bloats homeserver databases (every partial is a persisted event) and heavy edit-streams can corrupt client timelines (we hit Trixnity's "loop in timeline generation" in the wild). With this side-channel a client gets full live token rendering while the room's event history stays exactly one message per turn. Clients subscribe right before sending a command and the switch is evaluated per flush, so attachment mid-turn behaves correctly.Default behaviour is unchanged
With no subscriber attached, every path flows exactly as today. The only behavioural knob is opt-in:
KERYX_STREAM_FALLBACK_EDITS=1lets Matrix fall back to throttledm.replaceedits (driven by the standardstreaming.edit_interval/buffer_thresholdconfig) when the side-channel client is offline — off by default.Wire protocol
Testing
Running in production on my gateway (Matrix + Keryx client): verified 200/
text/event-streamwith valid key, 401 without, live delta mirroring during agent turns, single final Matrix commit per turn with a subscriber attached, and no change to/health,/v1/models, or existing chat-completions routes. All three touched filespy_compileclean.Happy to rename the module/route to something more generic (e.g.
client_stream) if you'd prefer — kept the shipping name so the released client and this PR match.🤖 Generated with Claude Code
Mirror-of: NousResearch#57091
NousResearch#57091