Skip to content

Keep daemon connections lean across the app, CLI, and plugins - #4470

Merged
boudra merged 2 commits into
mainfrom
investigate-plugin-auto-connect-memory
Sep 8, 2026
Merged

Keep daemon connections lean across the app, CLI, and plugins#4470
boudra merged 2 commits into
mainfrom
investigate-plugin-auto-connect-memory

Conversation

@boudra

@boudra boudra commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Linked issue

Refs #4151. This addresses the unwanted traffic reported there; it does not eliminate the separate memory cost of importing the SDK.

Type of change

  • Bug fix
  • Enhancement
  • Refactor

Reasoning

Plugin and SDK connections fell back to global timeline broadcasts because optimized protocol capabilities were declared by the app. A real RPC-only plugin received all 3,000 timeline messages in the reproduction (about 188 MiB), despite never using its Paseo API.

The client now owns exhaustive protocol defaults and accepts caller overrides. Timeline subscriptions establish and release shared network demand, expose initial acknowledgement through unsubscribe.ready, restore demand after reconnect, and expose history replacement events. Provider references resolve only for interested consumers, retaining unresolved announcements across reconnect. The daemon sends project, provider, permission, and attention events only to capable clients that request them, and skips agent hydration for idle sessions. CLI log-following and attach use the same subscription interface.

Goals

  • Give the app, CLI, SDK, and server plugins the client's supported protocol optimizations by default.
  • Keep idle connections free of timeline and catalog traffic, including during other agents' turns.
  • Preserve subscribed delivery, unsubscribe, reconnect, shared app/plugin membership, and explicit capability overrides.
  • Preserve legacy wire behavior when the peer has not adopted explicit subscriptions.

Non-goals

  • Lazy SDK imports, manual plugin connection lifecycle, or a manifest opt-out.
  • Moving application caches or visible-agent selection into the transport.
  • Claiming to fix the reported 700 MiB growth; that magnitude was not reproduced.

QA

  • Failing-first regressions reproduced missing default capabilities, SDK listeners lacking network membership or awaitable acknowledgement, lost provider updates during reconnect, and idle sessions unnecessarily hydrating agent snapshots.
  • 351 tests passed across eight targeted files: client connection, low-level client, public client API, daemon session, agent updates, provider catalog, plugin Paseo API, and the new real plugin connection test.
  • The real plugin test runs a forked RPC-only worker, creates and runs an agent, refreshes providers, and verifies zero unsolicited data. A subscribed client receives the timeline and stops receiving it after unsubscribe. A legacy-capability control still receives its broadcast stream.
  • Tested logs --follow and attach as real CLI subprocesses against an isolated daemon; each received a single event emitted immediately after its readiness banner, three times per command with default capabilities.
  • npm run build:client, npm run typecheck, npm run lint, npm run format, and SDK example typecheck passed.

Risk surface: the SDK timeline callback now includes a documented replacement event. Internal raw-stream consumers have been migrated to explicit subscriptions. Live-provider and voice journeys were not run locally; the client and daemon checks used test providers. No UI layout changes.

Protocol compatibility: new hello/server-info fields are optional. The new subscription RPC is sent only when advertised by the daemon. Clients without the new capability retain legacy broadcasts; existing wire fields and variants remain accepted.

Checklist

  • Plugin changes follow the SDK import boundaries
  • One focused change
  • npm run typecheck passes
  • npm run lint passes
  • npm run format passes
  • QA evidence
  • Tests added or updated where it made sense

Protocol capabilities were partly app-owned, leaving SDK and plugin clients on legacy global streams. Own the supported defaults, timeline demand, and provider reference decoding in the client, and require explicit event demand on capable connections.
@greptile-apps

greptile-apps Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR moves protocol capability ownership into the shared client, adds explicit timeline and session-event demand, and filters daemon broadcasts so idle app, CLI, SDK, and plugin connections avoid unsolicited traffic.

  • Adds acknowledgement-backed timeline subscriptions with unsubscribe and reconnect restoration.
  • Resolves provider snapshot references only for interested consumers and retains unresolved announcements across reconnect.
  • Adds daemon-side event membership, selective routing, and idle-session hydration avoidance.
  • Migrates CLI follow/attach and internal consumers to the subscription API while documenting compatibility behavior.
  • Both previous findings are fixed: CLI callers now await daemon acknowledgement, and unresolved provider announcements are retained and safely refetched after reconnect.

Confidence Score: 4/5

The behavior appears correct, but the repository’s explicit test-shape requirement must be satisfied before merging.

The two previous correctness findings are fully addressed: timeline consumers can await the daemon’s membership acknowledgement, and provider announcements survive reconnect without allowing stale in-flight responses to overwrite or discard retained work. The remaining issue is the repository-rule violation caused by raw protocol framing in the newly added tests.

Files Needing Attention: packages/client/src/connection.test.ts; packages/server/src/server/plugins/connection-demand.e2e.test.ts

Important Files Changed

Filename Overview
packages/client/src/connection/index.ts Owns shared timeline and event demand, acknowledgement readiness, unsubscribe behavior, and reconnect restoration.
packages/client/src/daemon-client.ts Integrates capability defaults, selective subscriptions, provider-reference resolution, and lifecycle restoration into the client.
packages/client/src/provider-snapshots/index.ts Coalesces provider announcements and safely invalidates old in-flight fetches while preserving reconnect work.
packages/server/src/server/session.ts Tracks per-source event membership and filters project, provider, permission, and attention delivery.
packages/protocol/src/messages.ts Adds backward-compatible schemas for explicit session-event subscriptions and daemon feature negotiation.
packages/client/src/connection.test.ts Covers capability, membership, readiness, reconnect, and provider behavior but violates the required domain-level test shape.
packages/server/src/server/plugins/connection-demand.e2e.test.ts Verifies idle and legacy plugin traffic behavior while directly parsing protocol frames in the test fixture.

Sequence Diagram

sequenceDiagram
  participant Consumer as App / CLI / Plugin
  participant Client as Shared client
  participant Daemon as Daemon session
  participant Agent as Agent/provider services

  Consumer->>Client: subscribe to timeline/events
  Client->>Daemon: set explicit membership
  Daemon-->>Client: correlated acknowledgement
  Client-->>Consumer: ready resolves
  Agent-->>Daemon: timeline/catalog update
  Daemon-->>Client: deliver only requested stream
  Client-->>Consumer: typed callback
  Consumer->>Client: unsubscribe
  Client->>Daemon: release membership
Loading

Reviews (2): Last reviewed commit: "fix(client): acknowledge timeline demand..." | Re-trigger Greptile

Comment thread packages/client/src/connection/index.ts Outdated
Comment thread packages/client/src/provider-snapshots/index.ts
Comment thread packages/client/src/connection.test.ts
@boudra
boudra merged commit 18aaec2 into main Sep 8, 2026
24 checks passed
@boudra
boudra deleted the investigate-plugin-auto-connect-memory branch September 8, 2026 10:59
omorsi45 pushed a commit to omorsi45/paseo that referenced this pull request Sep 8, 2026
Move supported protocol capabilities into client defaults and make session traffic subscription-driven. Preserve timeline readiness and reconnect recovery across SDK, CLI, and plugin consumers.
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