Repository navigation
D15: Studio event bus WS /events - #852
Merged
Merged
Conversation
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.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.
What changed
One Studio-wide WebSocket,
WS /events, pushesStudioEvents to every open tab; the agents list refreshes when any agent changes, replacing polling.New code
shared/wireTypes.ts:StudioEventunion (agent.changed,version.summary,draft.changed,suggestion.new,inbox.count).server/events/eventBus.ts:StudioEventBus— synchronous fan-out overEventEmitter(setMaxListeners(0)),publish/subscribe.server/ws/upgradeRouter.ts: the ONEupgradelistener on the http.Server. Runs the shared Host/Origin/token gate (moved fromwsServer.ts), then dispatches by pathname to the first matching registered route (exact string or RegExp, registration order); unmatched paths are destroyed; duplicate registrations throw. Later WS endpoints (e.g. the Author stream) register on it.server/events/eventsWs.ts:attachEventsWebSocket(router, events)registers/events; each socket gets every published event as JSON; nothing on connect.src/runtime/runtimeClient.ts:subscribeEvents(onEvent, connection?)—WS /events?token=.src/state/useStudioEvents.ts: subscribes once, reconnects 2 s after loss (same pattern asuseAgentStream).Changed code
server/wsServer.ts: no longer listens toupgradeitself — registers/^\/agents\/([^/]+)\/stream$/on the router; stream behavior (status + chat snapshot on connect, id validation) unchanged.server/workspace/context.ts:events: StudioEventBusonWorkspaceContext, built increateWorkspaceContext— the bus is per workspace.server/app.ts:eventBus?: StudioEventBusinCreateAppOptions(test seam for the default context);/eventsadded toAPI_PREFIXESand the SPA fallback regex.workspaceOf(req).events.publish(...)after the write succeeds):PUT/DELETE /agents/:id→agent.changed 'save';POST /agents(blank/template/copy) →'save';PATCH /agents/:id/meta→'meta';POST /agents/:id/versions→'version'(not on a no-op save); restore →'restore'; draft create/withdraw/approve/reject →draft.changed(+agent.changed 'draft'on approve).server/index.ts:createUpgradeRouter(server, access),attachWebSocketServer(router, runs),attachEventsWebSocket(router, bus);upgradeRouterexposed onStudioServerHandle.src/state/useAgentDocument.ts:agent.changed→refreshAgents(), debounced 300 ms.vite.config.ts:/eventsproxied withws: true.Test summary
server/__tests__/eventBus.test.ts(4): publish/subscribe/unsubscribe, many listeners.server/ws/__tests__/upgradeRouter.test.ts(8): exact-path and RegExp match, registration order, duplicate throws, unmatched destroyed, gate rejects 401/403 before any handler runs.server/__tests__/eventsWs.test.ts(11): realstartStudioServer—agent.changedframe afterPUT /agents/:id, 401 without token, unknown path destroyed, stream still answersstatus; plus per-route publish assertions against an injected bus.src/state/__tests__/useStudioEvents.test.tsx(4): subscribe once, reconnect after loss, unsubscribe on unmount, debounced agents-list refresh.Gates: Studio
typecheck,typecheck:server,test:server(842), clientvitest --run(946) all green; roottsc --noEmit,lint,test:coverage(7163),fallow,docs:ratchet,api:check,docs:llms:check,size-checkall green. No uncaused failures observed (coverage needed--minWorkers=1 --maxWorkers=4locally).Acceptance criteria
/events?token=<t>receivesagent.changedwithin one tick of aPUT /agents/x(eventsWs.test)/eventswithout the token is rejected with 401, same as the stream (eventsWs.test)/agents/x/streamstill works;/otheris destroyed (eventsWs.test, upgradeRouter.test)Generated with Devin