feat: add MCP discovery phase and agent run id to context sync - #29449
ibetitsmike wants to merge 4 commits into
Conversation
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 679a4c1d0e
ℹ️ 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".
679a4c1 to
7fd79c7
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7fd79c77ac
ℹ️ 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".
7fd79c7 to
e12f99d
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e12f99df94
ℹ️ 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".
e12f99d to
c1910f1
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! 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". |
c1910f1 to
69b5d2d
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 69b5d2d5cd
ℹ️ 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".
69b5d2d to
1bc859a
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. 🚀 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". |
1bc859a to
cf21c91
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. 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". |
…gisters A push without an agent run id previously skipped the agent row check. A current legacy process clears the row in UpdateStartup, so a nonempty row means a newer process has registered and the push is stale.
The push path already caps agent_run_id at 64 bytes; an oversized value written through UpdateStartup would then fail every matching push. Also correct the comment on the run id check: the previous process's push can land after a newer UpdateStartup, and readers treat it as stale until the new process's initial push replaces it.
cf21c91 to
c513825
Compare
|
@codex review |
|
Codex Review: Didn't find any major issues. 🚀 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". |
Stack context
This stack replaces #29114 after review feedback that a single
mcp_settledbool was underdeveloped and the change too large to review. It defines how workspace MCP discovery is communicated from the agent to chats: the agent publishes one discovery report inside the existing context snapshot (PushContextState), coderd persists it atomically with the resources, and chatd,find_tools, the create/start workspace tools, and the chat context UI all consume that same committed report.The report has three parts. Completeness:
MCPDiscovery.phaseisPENDINGuntil the agent's initial MCP reload has finished (success, failure, or zero servers all count) andCOMPLETEafterwards for the rest of the process; later reloads update outcomes but never move it back. Per-source outcomes stay on the existingContextResourcerows:mcp_configrows carry structural and semantic config errors,mcp_serverrows carry discovered servers (including zero tools), failed servers with a sanitized error, and a retained previous connection as OK plus a warning. Freshness: every snapshot carries theagent_run_idof the process that produced it, and the agent reports the same id inStartup, so a snapshot is known to describe the current process when the two ids match. Timestamps are deliberately not used for freshness becauseready_atis agent clock andreceived_atis coderd clock.Discovery completeness, per-source outcomes, turn eligibility, and the result of an actual tool invocation stay separate facts. Out of scope: continuous health monitoring, reconnect detection, automatic retries, and any retry or reload UI.
Layers, bottom to top: #29448 agent diagnostics, #29449 protocol and persistence, #29450 agent publication, #29451 chat projection, #29452 first-turn gate, #29453 context UI. Each layer builds and passes its tests on its own. The composed stack was validated end to end with remote UAT; the record is on #29453.
Why
coderd had no way to know whether an agent's MCP discovery had finished, and no way to tell whether a stored snapshot described the agent process that is running now. Both are needed before chatd can wait for discovery or withhold a previous process's tool definitions.
Fix
Protocol:
PushContextStateRequestgainsagent_run_idand a nestedMCPDiscoverymessage with aPhaseenum (PHASE_UNSPECIFIED,PENDING,COMPLETE);Startupgainsagent_run_id. The run id is a UUID generated once per agent process, stable across RPC reconnects and different after a restart. Legacy agents leave both empty, which means "no guarantee".UpdateStartuprejects a run id above the same 64-byte cap the push path enforces.Persistence: migration
000596addsworkspace_agents.agent_run_id,workspace_agent_context_snapshots.agent_run_id, andworkspace_agent_context_snapshots.mcp_discovery_phase(new enumworkspace_agent_mcp_discovery_phase).UpdateStartupalways overwrites the agent row's run id (empty for legacy agents).PushContextStatepersists the run id and phase in the same transaction as the resources, and ignores a push whose run id differs from the agent row's non-empty run id, because within one processUpdateStartupalways precedes the first push, so such a push can only come from a previous process. That includes a push with an empty run id: a current legacy process clears the row inUpdateStartup, so a non-empty row means a newer process has registered since. The handler also reports whether the phase or run id changed so the next layer can notify chats on phase-only transitions; this layer only plumbs that flag.No agent behavior changes here; the agent starts sending these fields in #29450.
Testing
coderd/agentapitests cover round trips of phase and run id, unspecified phase for requests without the message, stale-run rejection leaving the row untouched, same-run acceptance, empty-run acceptance against an empty row and rejection against a non-empty row, andUpdateStartupoverwriting the run id including to empty. Database tests cover the new columns. Remote UAT of the composed stack is recorded on #29453.Review record
679a4c1d0e: 1 finding. P2 empty request run id skipped the agent row check and accepted a known-stale legacy push: confirmed, fixed;TestPushContextState/MCPDiscovery/LegacyRequestAfterCurrentRunDroppedfailed on the old code and passes now.7fd79c77ac: 3 findings. P2 agent row not locked during the run id check: declined with the window analysis (a late push from the previous process is read as stale until the new process's initial push replaces it); the comment is corrected. P2 rolling-deployment invalidation: declined, Coder upgrades happen in scheduled downtime, not rolling. P2 unbounded run id in UpdateStartup: confirmed, fixed (TestUpdateStartup/OversizedRunID).e12f99df94: 1 finding. P2 agent row not locked during the run id check, re-raised via the chat row copy: declined; a push that commits afterUpdateStartupleaves the same state as a push committed just before the restart (a lock would only reorder the two), a fresher snapshot cannot be overwritten because both pushes write the same row under repeatable read, and every tool-building reader of the chat rows in this stack goes through feat: project MCP discovery state and freshness into chat context #29451's run id comparison.c1910f133c: no findings onc1910f133c. TheUpdateStartupcomment on how chatd reads an empty run id was then adjusted to match feat: project MCP discovery state and freshness into chat context #29451.69b5d2d5cd: 1 finding. P2 a superseded process reconnecting could reclaim the agent row throughUpdateStartup: declined, two live processes on one agent token is not a supported configuration (restart ends the previous process, rebuild gives the replacement its own row), and a legacy rollback is the case the run id rule already reads as stale.1bc859a218: no findings on1bc859a218.cf21c917d0: no findings oncf21c917d0.c5138256dd: pending.