Skip to content

fix(actor-plugin): live sessionEvent streaming over the RivetKit actor path#1541

Merged
NathanFlurry merged 1 commit into
mainfrom
stack/fix-actor-plugin-live-sessionevent-streaming-over-the-rivetkit-actor-path-ntmzqmwv
Jun 26, 2026
Merged

fix(actor-plugin): live sessionEvent streaming over the RivetKit actor path#1541
NathanFlurry merged 1 commit into
mainfrom
stack/fix-actor-plugin-live-sessionevent-streaming-over-the-rivetkit-actor-path-ntmzqmwv

Conversation

@NathanFlurry

Copy link
Copy Markdown
Member

The published 0.2.1 quickstart streamed ZERO sessionEvents (conn.on("sessionEvent")).
Root-caused three distinct bugs in the native actor plugin, each blocking the next:

  1. actor_loop starvation (WS-setup timeout). The single event loop ran
    ensure_vm().await inline on the first action; a cold VM boot (>5s) starved the
    queued ConnOpen, so RivetKit-core failed connection setup at 5000ms
    ("actor websocket connection setup timed out after 5000 ms") and no events
    could flow. Fix: move VM-touching work (Action/Http/Sleep/Destroy) onto a
    dedicated serial worker task; the loop now answers connection-lifecycle events
    inline and never blocks on the VM.

  2. Subscribe event rejected. RivetKit delivers an AbiEventTag::Subscribe to the
    plugin when a client subscribes to an event name; the loop had no arm, so it
    hit the generic "event not supported" reply, REJECTING every subscription. With
    no subscription registered, broadcast() (which filters on is_subscribed) routed
    zero events to the connection. Fix: accept Subscribe inline (reply_ok).

  3. sessionEvent broadcast missing + mis-encoded. spawn_event_capture only persisted
    each event to SQLite and never broadcast it. Added the broadcast, encoded as the
    RivetKit event wire expects: a CBOR array of handler arguments
    ([{ "event": }]) so the client (data) => data.event listener
    receives it. Also fixed vmBooted/vmShutdown, which had the same JSON-instead-of-
    CBOR encoding bug.

Verified locally against the published 0.2.1 npm packages with AGENTOS_PLUGIN_BIN
override + a real Anthropic key: 13 live session/update events stream end-to-end.

Known residual: a timing race remains between subscription registration and the
event burst (reliable under normal/slower timing, ~50% under rapid back-to-back
connections). The action reaches the plugin ~before the subscribe, and the engine
spawns actions without blocking, so this appears to live in the RivetKit
client/engine subscribe-vs-action ordering (preview dep), not the plugin.

@NathanFlurry

Copy link
Copy Markdown
Member Author

Stack for rivet-dev/agentos

Get stack: forklift get 1541
Push local edits: forklift submit
Merge when ready: forklift merge 1541

@railway-app railway-app Bot temporarily deployed to agentos / agentos-pr-1541 June 26, 2026 04:19 Destroyed
@railway-app railway-app Bot temporarily deployed to rivet-frontend / agentos-pr-1541 June 26, 2026 04:19 Destroyed
@railway-app

railway-app Bot commented Jun 26, 2026

Copy link
Copy Markdown

🚅 Deployed to the agentos-pr-1541 environment in agentos

Service Status Web Updated (UTC)
agentos 😴 Sleeping (View Logs) Web Jun 26, 2026 at 4:25 am

🚅 Deployed to the agentos-pr-1541 environment in rivet-frontend

Service Status Web Updated (UTC)
agent-os 😴 Sleeping (View Logs) Jun 26, 2026 at 4:27 am

…r path

The published 0.2.1 quickstart streamed ZERO sessionEvents (conn.on("sessionEvent")).
Root-caused three distinct bugs in the native actor plugin, each blocking the next:

1. actor_loop starvation (WS-setup timeout). The single event loop ran
   ensure_vm().await inline on the first action; a cold VM boot (>5s) starved the
   queued ConnOpen, so RivetKit-core failed connection setup at 5000ms
   ("actor websocket connection setup timed out after 5000 ms") and no events
   could flow. Fix: move VM-touching work (Action/Http/Sleep/Destroy) onto a
   dedicated serial worker task; the loop now answers connection-lifecycle events
   inline and never blocks on the VM.

2. Subscribe event rejected. RivetKit delivers an AbiEventTag::Subscribe to the
   plugin when a client subscribes to an event name; the loop had no arm, so it
   hit the generic "event not supported" reply, REJECTING every subscription. With
   no subscription registered, broadcast() (which filters on is_subscribed) routed
   zero events to the connection. Fix: accept Subscribe inline (reply_ok).

3. sessionEvent broadcast missing + mis-encoded. spawn_event_capture only persisted
   each event to SQLite and never broadcast it. Added the broadcast, encoded as the
   RivetKit event wire expects: a CBOR array of handler arguments
   ([{ "event": <notification> }]) so the client `(data) => data.event` listener
   receives it. Also fixed vmBooted/vmShutdown, which had the same JSON-instead-of-
   CBOR encoding bug.

Verified locally against the published 0.2.1 npm packages with AGENTOS_PLUGIN_BIN
override + a real Anthropic key: 13 live session/update events stream end-to-end.

Known residual: a timing race remains between subscription registration and the
event burst (reliable under normal/slower timing, ~50% under rapid back-to-back
connections). The action reaches the plugin ~before the subscribe, and the engine
spawns actions without blocking, so this appears to live in the RivetKit
client/engine subscribe-vs-action ordering (preview dep), not the plugin.
@NathanFlurry NathanFlurry force-pushed the stack/fix-actor-plugin-live-sessionevent-streaming-over-the-rivetkit-actor-path-ntmzqmwv branch from 7d4cf86 to 4c2b9bb Compare June 26, 2026 05:12
@railway-app railway-app Bot temporarily deployed to agentos / agentos-pr-1541 June 26, 2026 05:12 Destroyed
@railway-app railway-app Bot temporarily deployed to rivet-frontend / agentos-pr-1541 June 26, 2026 05:12 Destroyed
@NathanFlurry NathanFlurry merged commit 4c2b9bb into main Jun 26, 2026
0 of 4 checks passed
@NathanFlurry NathanFlurry deleted the stack/fix-actor-plugin-live-sessionevent-streaming-over-the-rivetkit-actor-path-ntmzqmwv branch June 26, 2026 05:13
@railway-app railway-app Bot temporarily deployed to rivet-frontend / preview June 26, 2026 05:13 Inactive
@railway-app railway-app Bot temporarily deployed to agentos / production June 26, 2026 05:13 Inactive
@railway-app railway-app Bot temporarily deployed to agentos / preview June 26, 2026 05:13 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant