Skip to content

perf(ws): scope preview frames and drop repeated shell payloads - #298

Merged
leoisadev1 merged 7 commits into
mainfrom
perf/ws-payloads
Sep 27, 2026
Merged

leoisadev1 merged 7 commits into
mainfrom
perf/ws-payloads

Conversation

@leoisadev1

@leoisadev1 leoisadev1 commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

Stacked on perf/server-hot-paths.

The WebSocket layer sent far more than clients needed, which matters most over SSH, Tailscale, and tunnels. Bot browser preview frames, full-viewport PNGs of 100 KB to 1 MB as base64, went to every subscribed client regardless of which chat owned them, with filtering only in the browser. Every thread event made each client refetch and re-send that thread's shell even when nothing visible changed. Subscribing to server config forcibly re-probed every provider by spawning CLI version checks and always broadcast the result, because the probe timestamp defeated the change comparison. Stream budgets charged the raw event size, so one tool result over 8 MB failed every client's shell subscription at once.

The preview subscription now takes an optional threadId and the server filters frames before serialization, an additive contract change that keeps old clients working. Shell subscriptions remember the last shell sent per thread and drop identical refetches. Config subscribes serve the cached provider snapshot, re-probing only entries older than 60 seconds, and the change comparison ignores probe timestamps. The shell stream stores slim thread references instead of raw events, and activity slimming is cached per event so it runs once regardless of subscriber count.

Verified with 210 passing tests across six suites, including new tests for preview scoping and shell de-duplication, with the dedupe test confirmed to fail when the fix is disabled. The preview event queue deliberately stays unbounded because a sliding queue could drop lifecycle events and desync clients.

Created with Claude Fable 5.1 in Claude Code.

🤖 Generated with Claude Code


Devin Review

@vercel

vercel Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
akeru-bot-landing Ready Ready Preview Sep 26, 2026 5:53pm UTC

Request Review

@github-actions github-actions Bot added type:provider Agent provider contribution. vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L labels Sep 26, 2026
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@greptile-apps

greptile-apps Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium risk] Optimizes preview and provider status messaging to reduce bandwidth.

The reproduced cache-write issue is non-blocking; the review found no outstanding issue that prevents merging.

Fix All in Claude CodeFindings

  1. P2 Older Refresh Overwrites Cache ▶

Summary

The PR scopes preview subscriptions by chat and reduces WebSocket traffic. Concurrent refreshes of one provider can leave an older status and authentication snapshot in its disk cache after a newer result wins in memory. Ordering cache writes would prevent stale data from being read during startup.

Reviews (6) · Last reviewed commit: "fix(server): skip unavailable providers ..."

greptile-apps[bot]

This comment was marked as resolved.

@greptile-apps

greptile-apps Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Comments Outside Diff

These findings sit on lines the diff does not cover, so they could not be posted inline. Each one leaves this list once its file changes.

  • P2 Concurrent refreshes can persist an older provider result last ▶

    • Bug
      • When two refreshes of one instance overlap, the newer result can be retained in memory while the older result overwrites its cache file. A subsequent cache read and hydration then yields stale status and auth.
    • Cause
      • The checkedAt comparison is atomic with the in-memory Ref.modify, but persistProvider runs afterward without per-instance ordering; its atomic renames can finish in the opposite order.
    • Fix
      • Serialize persistence per instance, or recheck that a snapshot is still the latest immediately before its cache-file rename.

leoisadev1 and others added 5 commits September 27, 2026 16:22
Preview frames went to every client regardless of thread; the subscription
now filters by threadId server-side. Shell subscriptions skip upserts equal
to the last one sent, config subscribes no longer force provider probes or
broadcast unchanged lists, and stream budgets charge the slim payloads
clients actually receive.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Background probes that only moved checkedAt were no longer broadcast, so
Settings showed a stale last-check time. Completed probes now publish a new
checkedAt; snapshot re-syncs stay quiet.

Concurrent server-config subscriptions could each queue a probe for the same
stale provider. A server-wide in-flight set now probes each stale instance
once per burst.

Dropping unchanged shell upserts also froze the client's resume cursor, so a
long run of unchanged events pushed reconnects past the replay window. An
unchanged shell is re-sent once the cursor would lag 500 events.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Subscription-triggered provider probes are deduplicated across connections,
but each ran in the scope of the subscription that started it. When that
client disconnected, the probe was cancelled while other clients waited on
it. The probes now run in the server's scope.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A slow background provider probe could finish after a newer explicit
refresh and overwrite its fresh status with stale data. ProviderRegistry
now stamps each probe of an instance with a start generation and only
applies a result if no newer probe of that instance has already landed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the area:connectors Plugin and MCP connector runtime. label Sep 27, 2026
@github-actions github-actions Bot removed the area:connectors Plugin and MCP connector runtime. label Sep 27, 2026

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 5 new potential issues.

Devin Review

Comment thread apps/server/src/provider/Layers/ProviderRegistry.ts Outdated
Comment thread apps/server/src/ws.ts
Comment thread apps/server/src/preview/Manager.ts
Comment thread .changeset/perf-ws-payloads.md
Comment thread apps/server/src/server.test.ts Outdated
greptile-apps[bot]

This comment was marked as resolved.

leoisadev1 and others added 2 commits September 27, 2026 16:45
Change-stream results skipped the probe generation guard, so a late
stream item could overwrite a newer explicit refresh, and one global
semaphore serialized applies across unrelated instances. Probe and
stream results now keep the snapshot with the newest checkedAt, decided
inside the providers Ref.modify, so no lock is needed. A stored
checkedAt in the future never blocks, in case the clock moved back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Instances without a driver cannot be probed, so their checkedAt never
advanced and every subscription past the TTL scheduled a no-op refresh
for them. The shell dedup test also drops its timeout, since it already
waits on a known sequence of events.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread apps/server/src/provider/Layers/ProviderRegistry.ts
@leoisadev1
leoisadev1 merged commit 0632aa5 into main Sep 27, 2026
11 of 12 checks passed
@leoisadev1
leoisadev1 deleted the perf/ws-payloads branch September 27, 2026 21:00

This branch had an error being deployed

1 failed deployment
Preview — 6c53d36c Deployed Sep 27, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L type:provider Agent provider contribution. vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant