fix: repair stale chat agent bindings after workspace rebuild - #28152
fix: repair stale chat agent bindings after workspace rebuild#28152ibetitsmike wants to merge 8 commits into
Conversation
After an attached workspace is rebuilt, the chat's persisted agent_id references an agent from the previous build until the next turn rebinds it. The chat UI resolves the agent by exact ID against the latest build, so the right panel lost its Terminal, Desktop, Browser, and app tabs even though the workspace was running. Repair stale bindings in chat read responses using the same agent selection chatd uses, and refetch the chat once per build when the binding no longer resolves in a running workspace.
Reword comments that overclaimed chatd authorship and persisted-binding repair, drop a test comment that restated its assertions, and flatten workspace agents once in isChatAgentBindingUnresolved.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 99295034b2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Scope binding repair to single-chat reads so chat-list reads keep the nil-fill-only behavior and avoid a per-workspace authorization lookup per listed chat. Move the frontend stale-binding detection from an effect into the workspace watch update handler per FE8, and add a Storybook interaction story covering rebuild recovery.
|
@codex review |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ad482a67f7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The query client disables retries, so a transient refetch failure permanently latched the dedupe key and blocked sidebar recovery until a reload or another rebuild. Clear the key when the refetch errors so the next workspace watch event retries.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2d22d804fa
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Server-side repair is best-effort, so a transient failure returns HTTP 200 with the stale binding and no query error, which permanently latched the dedupe key. Replace the latch and the error-state check with a 30s cooldown per chat/build/binding key so any failed repair retries on a later watch event without refetching on every event.
|
@codex review |
|
Codex Review: Didn't find any major issues. Chef's kiss. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1c48be9c91
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
An idle workspace publishes no watch events (the stats reporter returns early without publishing when there are no active sessions), so event-driven retries alone cannot recover from a transiently failed repair. Give the chat query a conditional refetchInterval that polls every 30s only while the binding is unresolved, and simplify the watch handler back to a once-per-key latch that only provides immediate repair after a rebuild.
|
@codex review |
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Problem
When a chat is bound to a workspace, chatd persists
chats.agent_idpointing at a specific workspace agent, and it only rebinds on the next chat turn. A workspace stop/start creates a new agent with a new ID in the latest build, so the chat page resolves the stale agent ID toundefinedand the right sidebar silently drops Terminal, Desktop, Browser, apps, and ports even though the workspace is running. The existing read-time enrichment only filled nil agent IDs and skipped stale non-nil ones, so refreshing did not help until the user sent another message.Fix
coderd/exp_chats.go: single-chat reads now repair agent IDs that no longer resolve in the workspace's latest build, using the sameagentselect.FindChatAgentselection chatd uses. Bindings that still resolve are preserved, and repair stays best-effort and response-only (no write-on-read). List reads keep the previous nil-fill-only behavior because validating existing bindings would cost a per-workspace authorization lookup per listed chat.site/src/pages/AgentsPage/AgentChatPage.tsx: the workspace watch update handler detects when a running workspace's latest build no longer contains the chat's bound agent and invalidates the chat query once per chat/build/binding key for immediate recovery, and the chat query polls every 30 seconds while the binding remains unresolved so a transiently failed repair retries even when an idle workspace publishes no further watch events. The watch stream replays the current workspace on every (re)connect, so this covers rebuilds that happen while the page is open or disconnected; page loads are covered by the server-side repair. The workspace-watcher bailout now also keys onlatest_build.idso a rebuild propagates while the page is open.Testing
go test ./coderd -run TestEnrichChatAgentIDscovering repair, keep-valid, selection-error, list-mode-skips-bound, and no-workspaces cases.RecoversSidebarAfterWorkspaceRebuildexercising the watch-event to chat-refetch to sidebar-recovery flow (verified red without the invalidation, green with it).pnpm test AgentChatPage.test.tscovering the binding-resolution predicate.