Repository navigation
Shared event stream and typed plugin RPC - #13
Merged
Merged
Conversation
…rpc(Definition)) One SSE connection shared by every subscriber with bounded per-subscriber queues, server.connected replay, of_type/for_session/where filters, an on_activity keepalive hook, cancellation under asyncio and trio, and opt-in reconnection with backoff. RpcDefinition/rpc_method/rpc_event declare plugin RPCs for typed calls, mapped RpcCallError exceptions and filtered event subscriptions.
shrijayan
force-pushed
the
feat/shared-events-typed-rpc
branch
from
October 22, 2026 10:11
fd0617d to
ff72565
Compare
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.
Brings event and RPC support to parity with the OpenCode TS client (
v2.1.2:shared-events.ts,promise/rpc.ts,promise/client.ts), and goes further in a few places.What's added
client.events(EventHub/AsyncEventHub, new module_events.py): oneGET /api/eventconnection shared by every subscriber.EventOverflowError. The latestserver.connectedis replayed to late subscribers.of_type(*classes)(narrows the type, e.g.Subscription[SessionIdleEvent]),for_session(id),where(pred). Use withfor/async for,get(timeout=),with/async with.on_activitycallback fires on every chunk, keepalive comments included.close()works from any thread (it shuts down the socket to unblock the reader). Async waits can be cancelled under asyncio and trio, and the subscription stays usable afterwards.reconnect=True | Reconnect(...): jittered exponential backoff after connection errors, 5xx and 429. Duplicateserver.connectedevents are dropped. Documented as volatile.client.event.subscribe()is unchanged.client.rpc(Definition)(_rpc.py): declare a plugin RPC withclass Counter(RpcDefinition, id="counter"),rpc_method(In, Out, errors=...)andrpc_event(Data).call(Counter.add, input)is typed through pydantic.RpcErrormaps toRpcCallErrorandRpcInternalErrormaps toRpcCallInternalError(output that fails validation counts asrpc.invalid_output). Data from declared errors is validated.subscribe(Counter.changed)yields typedRpcEventPayloads, andevents()yields every rawrpc.counter.*event.client.rpc.call(...)still works.Stream.on_activityandStream.interrupt().Generated code is untouched (
codegen --checkpasses). In__init__.py, the new imports sit after an# isort: splitso ruff doesn't sort them into the generated error-import block.Parity versus TS
server.connectedreplayed to late subscribersonActivityon every chunk, keepalives includedon_activitysignalabortclose()(thread-safe) and native async cancellation (asyncio and trio)client.rpc(definition)methods andevents.subscribe(name)call(method, input)andsubscribe(event);events.on(handler)not ported, use a loop or a task{type, message, data}, with decoding of declared errors (rpc-runtime)RpcCallErrorwithjoins eagerly so no events are missed;get(timeout)Difference: calling a method uses
counter.call(Counter.add, x)rather thancounter.add(x). That keeps the return type exact for both the sync and async clients without a second declaration.Tests
tests/test_events.py: sync, plus async on asyncio and trio. Covers multiplexing, replay, overflow isolation, last-leave teardown, cross-thread close, filters, keepalive activity, reconnect with dedupe and backoff,max_attempts, non-retryable errors, and cancelling a request or a wait.tests/test_rpc.py: encoding, error mapping, invalid output, foreign definitions, and filtered typed events (sync and async)._events96%,_rpc95%.Do not merge without review: merging to
mainpublishes a release.