feat(coder): split coder into thin entity + coding-session resource#4267
Open
kevin-dp wants to merge 2 commits intokevin/coder-sdk-runnersfrom
Open
feat(coder): split coder into thin entity + coding-session resource#4267kevin-dp wants to merge 2 commits intokevin/coder-sdk-runnersfrom
kevin-dp wants to merge 2 commits intokevin/coder-sdk-runnersfrom
Conversation
The coder entity used to own three collections (sessionMeta, cursorState, events) so the session history was bound to one entity instance. Pull the durable, portable parts (event history + session-info facts) onto a shared-state resource — the entity becomes a thin wrapper over the SDK runner that reads/writes the resource and tracks only its own run lifecycle (runStatus, inboxCursor). This is the prerequisite for forking sessions, sharing a session across devices/users, and surfacing the same history through multiple entities — the resource sits at a stable shared-state id (`coder-session/<entityId>`) and survives independently of any particular entity. Why two collections, not one: - `sessionInfo` carries the static facts about which session this is (agent, cwd, electricSessionId, nativeSessionId, createdAt). - `transcript` carries the normalized event stream. Originally named `events`, but ObservationHandle reserves that field for ChangeEvent[] and Object.assign clobbers any like-named collection on the SharedStateHandle the runtime returns from `observe(db(...))`. `transcript` sidesteps the collision. The wrapper entity tags itself with `coderResource` pointing at its resource id; the UI fetches the entity, reads the tag, and attaches to the shared-state stream alongside the entity stream. On a freshly spawned coder the resource stream isn't registered on disk until the entity's first wake commits its mkdb manifest entry, so `connectSharedStateStream` retries on 404 with bounded backoff to cover the spawn → first-wake race. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## kevin/coder-sdk-runners #4267 +/- ##
===========================================================
- Coverage 64.83% 60.98% -3.86%
===========================================================
Files 147 123 -24
Lines 19373 16925 -2448
Branches 4785 4166 -619
===========================================================
- Hits 12561 10321 -2240
+ Misses 6807 6601 -206
+ Partials 5 3 -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:
|
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
The coder entity used to own its session's full history on three of its own collections (
sessionMeta,cursorState,events), so the durable session state was bound to one entity instance. This PR pulls the durable, portable parts onto a shared-state resource at a stable id (`coder-session/`), and slims the wrapper entity down to just its run lifecycle bookkeeping (runStatus,inboxCursor).This is the prerequisite for forking sessions, attaching multiple wrappers to the same history, sharing a coder URL across devices/users, and surfacing the same session through specialised viewers — all without entangling those use cases with the SDK runner that produces events.
What changed
packages/agents-runtime/src/coding-session-resource.ts: schema + helpers (codingSessionResourceSchema,codingSessionResourceId,CODER_RESOURCE_TAG).packages/agents/src/agents/coding-session.tsrewritten: handler creates the resource via `mkdb` on first wake, observes it on every wake, and writes events / sessionInfo to it. Tags the entity with `coderResource` pointing at its resource id.events,meta) keeps working.Naming note
The transcript collection on the resource is called
transcript, notevents. Reason: the runtime's `ObservationHandle` reserves the field `events: ChangeEvent[]` and `Object.assign`s it onto the SharedStateHandle returned by `observe(db(...))`, silently clobbering any like-named collection. Renaming sidesteps the collision.Out of scope
Forking sessions and a `forkCodingSession` helper come in a follow-up. The resource shape is what makes that possible; this PR doesn't ship the operation.
Stacked on top of #4263 (coder SDK runners). Base is set to `kevin/coder-sdk-runners` so the diff stays focused.
Test plan
🤖 Generated with Claude Code