feat: mount chat API routes under /api/v2 - #28496
Conversation
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 69dd96a36e
ℹ️ 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".
69dd96a to
9b7aa41
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9b7aa41e86
ℹ️ 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".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 80d2708c38
ℹ️ 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".
|
@codex review |
|
Codex Review: Didn't find any major issues. Nice work! 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: 816d7eddad
ℹ️ 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".
|
@codex review Please review current head
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d28c59cafa
ℹ️ 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".
|
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 832bf3aed4
ℹ️ 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".
|
@codex review Please review current head
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 860c858b82
ℹ️ 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".
|
@codex review Please review current head
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bb0f664995
ℹ️ 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".
bb0f664 to
12c3c47
Compare
|
@codex review Please review current head
|
|
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". |
49ed887 to
054d748
Compare
Publish pagination params on GET /chats, describe the stream frame as an event array, document the raw upload body via form data instead of a parser exemption, restore the media-type contracts on the file download routes and the OAuth callback, extend permissive MCP CORS to /api/v2/mcp/, and share one FilesRateLimit limiter across both prefix mounts with prefix-stripped endpoint keys.
Publish the stream parts frame as an event array and the stream after_id resume cursor, type the queued-message path IDs as integers, and move the chatd architecture TODO markers into this PR where the dual mounts land.
054d748 to
f06af18
Compare
| return api.chatFilesRateLimit | ||
| } | ||
|
|
||
| func (api *API) registerChatFileDownloadRoute(r chi.Router) { |
There was a problem hiding this comment.
It would be nice to have fewer of these methods and consolidate them, the endpoints are so spread out it's hard to follow. Although that may cause a need to invert where the exceptions are defined (i.e. moving them here vs keep in coderd).
There was a problem hiding this comment.
Consolidated in 968b807. The per-group helpers are collapsed into a single registerChatAPIRoutes(r, apiKeyMiddleware, prefix) mounted once per API prefix, with the exceptions inverted into chat_routes.go: the unpromoted experimental routes and the /api/v2 404-reservations now sit behind a chatAPIPrefix selector instead of being spread through coderd.go. The MCP OAuth2 pair merged into one registerMCPServerOAuth2Routes(r, prefix) and the org-scoped MCP server config routes folded into registerOrganizationChatRoutes. coderd.go is down to one call per prefix plus the org/member mounts that hang off existing route trees.
🤖 Posted by Xum on Mike's behalf.
| } | ||
|
|
||
| func (api *API) registerExperimentalMCPServerOAuth2Routes(r chi.Router) { | ||
| // TODO(CODAGT-922): migrate provider redirect URIs before promoting this callback. |
There was a problem hiding this comment.
IIRC provider redirect URI cannot be changed for existing sessions, so refresh flows would break and require re-authing.
There was a problem hiding this comment.
Good point - reworded the comment in 968b807: providers pin the redirect URI when a session is established, so it cannot change for existing sessions without breaking token refresh and forcing re-auth. The callback stays experimental-only, and CODAGT-922 now tracks promotion as needing a re-auth story rather than a redirect URI migration.\n\n> 🤖 Posted by Xum on Mike'''s behalf.
| var allowedProduceTypes = []string{"json", "text/event-stream", "text/html", "text/plain"} | ||
|
|
||
| func assertProduce(t *testing.T, comment SwaggerComment) { | ||
| if comment.method == "get" && (comment.router == "/api/v2/chats/files/{file}" || |
There was a problem hiding this comment.
Why do these need to be separate from the rest below?
There was a problem hiding this comment.
#28632 will fully rip out the default organization model routes anyway
There was a problem hiding this comment.
Dropped in 968b807: GET /chats/models stays experimental-only since the org-scoped collection supersedes it and #28632 removes it. The doc-only wrapper handler is deleted and /api/v2/chats/models now 404s via the segment reservation (covered in TestChatRoutesCompatibility).\n\n> 🤖 Posted by Xum on Mike'''s behalf.
Address review feedback on the /api/v2 chat promotion: - Collapse the per-group chat register helpers into a single registerChatAPIRoutes mounted once per API prefix, inverting the unpromoted experimental routes and the /api/v2 404 reservations into chat_routes.go behind a chatAPIPrefix selector. Merge the MCP OAuth2 helper pair and fold the organization MCP server config routes into registerOrganizationChatRoutes. - Keep GET /chats/models experimental-only instead of promoting it: the organization-scoped models collection supersedes it and #28632 removes it. /api/v2/chats/models now 404s via a segment reservation. - Reword the MCP OAuth2 callback TODO: providers pin the redirect URI for existing sessions, so promotion needs a re-auth story rather than a redirect URI migration. - Fold the chat file @produce exceptions into the swagger parser's existing no-response-model exception list.
## Stack context This is the second PR in the 3-PR chat API promotion stack: server compatibility mounts (#28496), codersdk promotion (this PR), and frontend path updates (#28498). ## Summary Move the promoted chat and MCP SDK methods from `ExperimentalClient` to `Client` and update them to use `/api/v2`. Methods for routes that remain experimental stay on `ExperimentalClient`. Update in-repository callers and generated types. The multi-replica chat stream relay dials `/api/v2` directly: mixed-version replica sets are not a supported upgrade path, so no experimental-path fallback is kept (per review). Remote dogfood UAT passed for the composed stack. > [!NOTE] > Xum acted on Mike's behalf in this pull request. <!-- xum-attribution: model=claude-fable-5 thinking=high -->
## Stack context This is the final PR in the 3-PR chat API promotion stack: server compatibility mounts (#28496), codersdk promotion (#28497), and frontend path updates (this PR). ## Summary Switch promoted frontend chat and MCP REST and WebSocket calls to `/api/v2`. Debug runs, virtual desktop streaming, advisor, and computer-use provider routes remain on `/api/experimental` because those surfaces were not promoted. Update the matching tests, stories, helpers, and end-to-end route expectations. Remote dogfood UAT passed with chat traffic verified on the v2 routes. > [!NOTE] > Xum acted on Mike's behalf in this pull request. <!-- xum-attribution: model=claude-fable-5 thinking=high -->
Batch backport of ibetitsmike's PRs that merged into `main` after the `release/2.37` branch was cut (merge-base `c275327fb72`, 2026-08-24). ## Included (9 cherry-picks, in order) | PR | Title | |----|-------| | #28470 | fix(coderd/x): surface Gemini malformed-function-call stream deaths as retryable errors | | #28471 | fix: apply MCP server selection when editing a chat message | | #28460 | refactor: consolidate viewport hooks and remove defineProperty matchMedia stub | | #28476 | feat(coderd/x/chatd/chattool): improve find_tools relevance and model guidance | | #28400 | fix(coderd/x/chatd/mcpclient): enforce MCP connect budget and unblock session cleanup | | #28589 | fix(coderd/x/chatd): truncate overlong generated chat titles instead of rejecting them | | #28496 | feat: mount chat API routes under /api/v2 | | #28497 | feat: promote codersdk chat API methods to Client | | #28498 | feat(site): use /api/v2 chat API paths | All picks applied cleanly with `git cherry-pick -x` onto `release/2.37`. ## Excluded and follow-up backports The remaining post-cut PRs are cherry-picked onto this PR as a GitHub stack (#28692) that merges bottom-up, so the dependency order is enforced by the PR bases: | Stack order | Original PR | Backport PR | Notes | |-------------|-------------|-------------|-------| | 1 | #28462 (repair failing Storybook stories) | #28687 | One fixture adaptation: 2.37's `OrganizationModelsContextValue` has no `organizations` field | | 2 | #28186 (enable Coder Agents for organization members) | #28688 | One story-assertion conflict resolved to the picked regex; ships no migration by design | | 3 | #28593 (allow sharing MCP servers with users and groups) | #28686 | Clean pick on top of #28688, plus the 1-line test fix #28657 (expect v2 MCP ACL path) | | 4 | #28659 (point MCP server ACL msw handlers at v2 paths) | #28689 | Clean pick on top of #28686 | Intentionally skipped: #28587 (restore agents-access cleanup migration). Release branches cannot take a migration unless its sequence number matches main with no gap. ## Validation - `go build ./...` and test-binary compilation for `./coderd/... ./codersdk/... ./enterprise/... ./site` pass - `pnpm check` and `pnpm lint:types` pass - Targeted Vitest on all touched test files: unit 281/281 pass; Storybook 180/181 pass. The single failure (`AgentChatPage.stories.tsx` > Queued For Capacity After Polling) reproduces identically on the untouched `release/2.37` baseline, so it is pre-existing and unrelated. > Xum acted on Mike's behalf. <!-- xum-attribution: model=claude-fable-5 thinking=high -->
> [!IMPORTANT]
> Most of the added lines in this PR are generated API reference content
for publishing the organization-scoped `GET` and `POST
/api/v2/organizations/{organization}/chats/models` replacements. There
is no matching generated-doc deletion because the three removed
default-organization endpoints are experimental and are not present in
the generated public API reference on the current base. The removed
paths remain only as explicit 404 reservations, with no
default-organization shim or functional handler.
## Summary
Remove the unused default-organization chat model collection routes:
```text
GET /api/experimental/chats/models
GET /api/experimental/chats/model-configs
POST /api/experimental/chats/model-configs
```
Use the organization-scoped collection instead:
```text
GET /api/v2/organizations/{organization}/chats/models
POST /api/v2/organizations/{organization}/chats/models
```
## Context
The intention of PR #28440 was to consolidate model availability into
the organization-scoped models collection for CODAGT-898 and remove the
superseded collection routes. That PR removed
`/organizations/{organization}/chats/models/available`, but it missed
these older default-organization routes and explicitly retained one of
them. This PR completes the intended #28440 cutover. The repository has
no SDK, CLI, or frontend consumer for the removed routes.
This change also prevents PR #28496 from promoting the missed
default-organization `/chats/models` route into the stable `/api/v2`
API.
This change is separate from the one-release `/api/experimental`
compatibility window in CODAGT-921. That window preserves experimental
versions of the intended stable API. It does not require compatibility
routes for unused deployment-scoped endpoints.
Refs CODAGT-898.
## Breaking change
Clients that call the removed routes must use the organization-scoped
model collection and provide an organization.
## Changelog
Remove unused default-organization Coder Agents model API routes. API
clients must use the organization-scoped chat models collection.
> [!NOTE]
> Coder Agents generated this pull request on Ethan Dickson's behalf.
> [!IMPORTANT]
> Most of the added lines in this PR are generated API reference content
for publishing the organization-scoped `GET` and `POST
/api/v2/organizations/{organization}/chats/models` replacements. There
is no matching generated-doc deletion because the three removed
default-organization endpoints are experimental and are not present in
the generated public API reference on the current base. The removed
paths remain only as explicit 404 reservations, with no
default-organization shim or functional handler.
## Summary
Remove the unused default-organization chat model collection routes:
```text
GET /api/experimental/chats/models
GET /api/experimental/chats/model-configs
POST /api/experimental/chats/model-configs
```
Use the organization-scoped collection instead:
```text
GET /api/v2/organizations/{organization}/chats/models
POST /api/v2/organizations/{organization}/chats/models
```
## Context
The intention of PR #28440 was to consolidate model availability into
the organization-scoped models collection for CODAGT-898 and remove the
superseded collection routes. That PR removed
`/organizations/{organization}/chats/models/available`, but it missed
these older default-organization routes and explicitly retained one of
them. This PR completes the intended #28440 cutover. The repository has
no SDK, CLI, or frontend consumer for the removed routes.
This change also prevents PR #28496 from promoting the missed
default-organization `/chats/models` route into the stable `/api/v2`
API.
This change is separate from the one-release `/api/experimental`
compatibility window in CODAGT-921. That window preserves experimental
versions of the intended stable API. It does not require compatibility
routes for unused deployment-scoped endpoints.
Refs CODAGT-898.
## Breaking change
Clients that call the removed routes must use the organization-scoped
model collection and provide an organization.
## Changelog
Remove unused default-organization Coder Agents model API routes. API
clients must use the organization-scoped chat models collection.
> [!NOTE]
> Coder Agents generated this pull request on Ethan Dickson's behalf.
(cherry picked from commit 0f5c7b3)

Stack context
This is the base of a 3-PR stack promoting the chat API from
/api/experimentalto/api/v2: server compatibility mounts (this PR), codersdk promotion (#28497), and frontend path updates (#28498).Summary
Double-mount the stable chat and MCP handlers under
/api/v2while retaining the existing experimental routes for the one-release compatibility window decided in CODAGT-921. CODAGT-922 tracks removing the compatibility mounts.The shared route builders preserve existing authentication and middleware behavior. Experiment-gated, debug, tombstone, and legacy default-organization model routes remain experimental-only. Signed file URLs, external OAuth callback URLs, and mixed-version replica relays also remain on the experimental prefix during the transition.
Update Swagger and the generated API reference for the promoted routes, including the workspace lookup and a runnable raw-body chat file upload example. Retain internal endpoints outside the published reference, share chat-file rate limits across both prefixes, enable CORS for the v2 MCP routes, and cover dual mounts plus exclusions with compatibility tests. Remote dogfood UAT passed for the promoted chat, model, MCP, and file flows.
Note
Xum acted on Mike's behalf in this pull request.