Add pull-wake runners for desktop dispatch#4305
Open
KyleAMathews wants to merge 31 commits intomainfrom
Open
Conversation
- Fix pull-wake runner reconnection on clean stream close - Add missing .catch() on fire-and-forget dispatch - Log auth errors instead of silently swallowing them - Log heartbeat error-handler failures as last-resort fallback - Separate JSON parse errors from business logic in wake registration - Eliminate duplicate authenticateIncomingRequest call in spawn - Log drainWakes shutdown errors instead of discarding - Log desktop settings load failures - Align compareOffsets to use BigInt (matching registry) - Replace non-null assertions with explicit guard in dispatch router - Consolidate WakeNotification to single source in agents-runtime - Remove unsupported worker-pool dispatch target variant - Make DispatchPolicy.targets readonly - Use satisfies-based validation Sets for compile-time safety - Extract InternalWakeNotification type for writeToken handling - Replace nested ternary with if/else in tags logic - Remove duplicate readBody, use shared import Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4305 +/- ##
===========================================
- Coverage 54.09% 40.05% -14.05%
===========================================
Files 206 170 -36
Lines 20775 13264 -7511
Branches 5493 4270 -1223
===========================================
- Hits 11239 5313 -5926
+ Misses 9532 7945 -1587
- Partials 4 6 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.
Summary
Adds pull-wake runners — a polling-based dispatch mechanism where desktop runners register with the server and pull wake notifications from a dedicated durable stream, replacing the need for direct webhook pushes to desktop clients that sit behind NAT.
Reviewer Guidance
Motivation
Desktop agents can't receive inbound webhooks (NAT, firewalls, dynamic IPs). Pull-wake flips the model: the server writes wake notifications to a per-runner durable stream, and the runner tails it. This gives desktop runners the same dispatch semantics as cloud workers without requiring a stable inbound address.
Architecture
The dispatch lifecycle follows a state machine tracked in Postgres:
Key components:
DispatchWakeRouter(dispatch-wake-router.ts) — Orchestrates wake enrichment, materialization, and delivery to either webhook or runner-stream targets. Handles coalescing (skip duplicate wakes for entities already being processed).PostgresRegistryextensions (electric-agents-registry.ts) — Tracksentity_dispatch_state,wake_notifications,consumer_claims, andrunnerstables. Manages lease-based runner liveness, claim lifecycle, and recovery of expired/stale dispatches.createPullWakeRunner(pull-wake-runner.ts) — Client-side runner that tails the wake stream with reconnection + exponential backoff, heartbeats for liveness, and dispatches received wakes to the runtime.Callback-forward auth (
server.ts handleCallbackForward) — Proxies claim/heartbeat/done requests from runners through the server, rewriting claim tokens and validating runner ownership. This lets the server remain the single authority for entity lifecycle.Asserted identity (
assertedIdentity.ts,dev-asserted-auth.ts) — Desktop app propagates user identity throughX-Electric-Asserted-*headers, enablingcreated_bytagging on spawned entities.Key Invariants
Non-goals
EntityDispatchStatetype redesign as discriminated union (deferred — works correctly, just permissive at the type level)Trade-offs
Verification
Files Changed
New files:
pull-wake-runner.ts— Client-side pull-wake runner with reconnection, heartbeat, and stream tailingdispatch-wake-router.ts— Server-side wake enrichment, materialization, and delivery routingelectric-agents-types.ts— Shared type definitions (DispatchTarget, DispatchPolicy, EntityDispatchState, WakeNotificationRow)stream-client.tsextensions —headOffset()andmintWakeNotification()for dispatchauthenticated-user-format.ts/dev-asserted-auth.ts— Identity formatting and dev-mode authassertedIdentity.ts/auth-fetch.ts— UI-side identity extraction and authenticated fetch0004_pull_wake_control_plane.sql— Migration for runners, entity_dispatch_state, wake_notifications, consumer_claims tablesentrypoint-lib.ts(server + agents) — Environment variable parsing for new dispatch optionsModified files:
server.ts— Dispatch recovery loop, callback-forward proxy, wake-on-send integration, runner management endpointselectric-agents-registry.ts— Runner CRUD, dispatch state machine, claim lifecycle, stale recovery querieselectric-agents-routes.ts— Runner HTTP endpoints, dispatch_policy on spawn, auth plumbingprocess-wake.ts— Claim token header transport, idempotent producers, BigInt offset comparisoncreate-handler.ts—dispatchWakemethod on RuntimeRouter for pull-wake notificationsagents/server.ts— BuiltinAgentsServer pull-wake runner lifecycle (start/stop/drain)agents-desktop/main.ts— Desktop runner registration, settings persistence, asserted auth headersElectricAgentsProvider.tsx— Collection caching with cleanup, dispatch_policy in spawn, preloadingentity-connection.ts— Reconnecting SSE with abort support and auth headers