feat(coderd/x/chatd): consume the pinned chat context in prompt generation - #26558
Merged
Conversation
…ation Build the system-prompt instruction block and workspace skills from a chat's pinned context copy (chat_context_resources, populated in #26438) instead of scanning per-turn history, when the chat has a pinned copy. Selection is presence-based, with no experiment: a chat with pinned rows builds its prompt from the pin; a chat without them falls back to the per-turn history path, so older agents that never report context keep their existing behavior. The two paths are mutually exclusive. - contextResourcesToPrompt maps the protojson resource bodies (instruction files and skills) into the instruction block and skill metadata, skipping non-OK statuses, non-prompt body kinds, and malformed bodies (counted so a proto or encoding regression cannot silently drop context). - pinnedWorkspaceContext reads the pin and reports ok=false (history fallback) when there are no pinned rows; read errors propagate. The bound agent only decorates the instruction header with OS and directory, so the pin still resolves when the workspace is unreachable. - resolveTurnWorkspaceContext dispatches between the pinned and history paths; prepareGeneration calls it. Split from #26466. The body decoders this PR inlines are extracted to be shared with the drift/diff API in the follow-up.
sreya
approved these changes
Jun 22, 2026
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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
prepareGenerationnow builds the system-prompt instruction block and workspace skills from a chat's pinned context copy (chat_context_resources, populated in #26438) instead of re-scanning per-turn history, when the chat has a pinned copy. This is the first production reader of the pin.Selection is presence-based, no experiment: a chat with pinned rows builds its prompt from the pin; a chat without them falls back to the existing per-turn history path. The two paths are mutually exclusive, so older agents that never report context keep their current behavior and the per-turn pull stays as the fallback.
How
contextResourcesToPromptmaps the protojson resource bodies (instruction files and skills) into the instruction block and skill metadata, skipping non-OK statuses, non-prompt body kinds, and malformed bodies (the malformed count is logged so a proto/encoding regression cannot silently drop context).pinnedWorkspaceContextreads the pin and reportsok=false(history fallback) when there are no pinned rows; read errors propagate. The bound agent only decorates the instruction header with OS and directory, so the pin still resolves when the workspace is unreachable.resolveTurnWorkspaceContextdispatches between the pinned and history paths;prepareGenerationcalls it.Testing
go test ./coderd/x/chatd/forTestContextResourcesToPrompt,TestPinnedWorkspaceContext(incl....FromHydratedPinagainst real Postgres), andTestResolveTurnWorkspaceContext: pass.make gen(no drift),golangci-lint,gofmt, emdash scan, andgo build/go veton./coderd/x/chatd/...: all clean.Scope
This is the foundational backend slice split from #26466 (the full-stack staging PR). It changes no API surface, schema, proto, or generated files. The remaining pieces land as follow-ups in dependency order:
ChatContextdrift/diff API (resources+changes,ContextDetail). This also extracts the body decoders inlined here so they are shared with the diff path.coder exp chat contextsource CRUD andrefresh(CLI).Why this is the first split
The coderd hydration, the
PUT /chats/{id}/contextrefresh endpoint (#26389), thechat_context_resourcestable (#26430), and the copy-into-pin logic (#26438) are already merged, as is the agent-side push (#26526, #26533). Consuming the pin in prompt building is the step #26438 explicitly deferred, and it is the bottom of the remaining dependency stack: the drift/diff API, the UI indicator, and the CLI are only meaningful once the chat actually builds its prompt from the pin. Keeping it presence-based means it is independently revertable and leaves the per-turn pull intact as a fallback, matching the RFC's Release 3 rollout.The files are taken verbatim from the reviewed #26466 boundary commit (before the diff-API work began), so the deep-review feedback already applied there (CRF-1 through CRF-10) is preserved.
This PR was created by Coder Agents on behalf of @kylecarbs. Split from #26466.