mirror of
https://github.com/coder/coder.git
synced 2026-11-01 21:13:14 +08:00
dcf3cce51c80f59a1e5f52c289e3975cebd73708
5594
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
dcf3cce51c |
fix(site/src/pages/AgentsPage): clarify empty context usage popover state (#27389)
## Summary The context usage badge popover showed "Context usage unavailable" before any assistant message reported token usage, which read like an error. This changes the empty-state copy to "Context usage will appear after sending a message." and fixes a spacing bug that state exposed: the pinned context list's top margin was conditional on a usage percentage being present, so without usage data the list sat flush against the message. ## Changes - `ContextUsageIndicator`: new empty-state copy; unconditional `mt-2` on the context list. - Stories: `NoUsage` (message only) and `NoUsageWithContext` (message plus pinned resource list), both asserting the new copy via hover interactions. ## Testing - Storybook interaction stories cover both empty states. - `biome check` and `tsc --noEmit` pass; verified visually in Storybook. > This PR was authored by Mux, an AI coding agent, acting on Mike's behalf. |
||
|
|
a9a1dcc65d |
feat: add network calls column to AI sessions table (#27269)
Add a "Total/blocked network calls" column to the AIBridge sessions table. Update `ListAIBridgeSessions` query to calculate network called made and blocked per session. See query plan [here](https://explain.dalibo.com/plan/54355c90b165ggb4). --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6014a44c85 | fix(site): keep mobile model picker effort row and last model visible (#27336) | ||
|
|
3227cac217 |
feat: add manual chat compaction via /compact (#27081)
Adds a user-triggered `/compact` action for Coder Agents chats: typing
`/compact` in the composer (or picking it from the `/` trigger menu)
summarizes the conversation so far to free up context window space.
## How it works
- New `POST /api/experimental/chats/{chat}/compact` endpoint
(owner-only, RBAC `ActionUpdate`, excluded from the public API reference
via `x-apidocgen skip`). It marks the chat with a durable one-shot
`chats.compaction_requested_at` signal and moves it `waiting -> running`
via a new `RequestCompaction` state transition; no message row is
inserted. AI Gateway attribution needs no per-request key: generation
preparation resolves the owner's synthetic API key (#27170) like any
other turn.
- `RequestCompaction` hands off chat ownership (clears
`worker_id`/`runner_id`) so a worker acquisition hint is published;
since the transition changes no history, the previous runner could
otherwise miss the request under reordered pubsub delivery.
- The background chat worker picks the chat up like any other turn. A
pending manual request takes precedence over turn completion in the
generation decision, and forces compaction even below the automatic
threshold (and when compaction is disabled via threshold=100). The
commit step consumes the request marker in the same transaction; any
transition that ends the turn clears stale markers.
- The summary triplet reuses the automatic-compaction path, now tagged
with a `source` (`automatic` | `manual`) that is plumbed through
streamed progress parts, persisted tool JSON, and the UI label
("Summarized (manual)").
- Validation order: busy chats reject with 409 (state-machine conflict),
empty/already-compacted chats with 409 "nothing to compact", archived
chats with 400; the owner usage-limit check runs last so no-op requests
surface the specific conflict instead of a limit error.
- Web UI: the `/` trigger menu now has a built-in "Commands" group
listing `/compact`; submit intercepts exactly `/compact` and calls the
endpoint instead of sending a message. A personal or workspace skill
named `compact` takes precedence over the built-in command; while skill
collisions are still resolving, an exact `/compact` submission is
blocked with a retryable hint instead of leaking as message text.
History and queued-message edits are never intercepted. After
compaction, the context usage indicator resets to its unknown state
until the next assistant response reports fresh usage, instead of
showing the stale pre-compaction number.
- codersdk: `ExperimentalClient.CompactChat`.
Worker-path execution (rather than compacting synchronously in the
handler) reuses the existing lock fencing, live "Summarizing..."
streaming, retry accounting, restart resilience, and debug-run
observability. Rationale documented in `coderd/x/chatd/ARCHITECTURE.md`.
## Testing
- State machine: transition-matrix coverage for `RequestCompaction`,
marker lifecycle tests (carried by lease renewals/queue appends, cleared
by terminal transitions, consumed by commit), ownership handoff +
acquisition hint assertions.
- Worker: decision-ordering and forced-compaction unit tests;
active-server end-to-end test (manual compact below threshold produces a
`source=manual` summary, returns to `waiting`, no assistant follow-up;
busy chat rejected).
- API: success, archived, non-owner, RBAC-denied, empty-chat, no-daemon
cases; usage-limit ordering (at-limit owners still get
state/nothing-to-compact conflicts for no-op requests, with marker
rollback).
- Frontend: Storybook play tests for the Commands menu group, submit
intercept, skill-name collision, queued-edit passthrough, and
manual/automatic tool rendering; unit tests for command availability
resolution and the post-compaction context usage reset.
> This PR was created by Mux, an AI coding agent, working on Mike's
behalf.
|
||
|
|
69a045f944 |
chore: bump axios from 1.16.1 to 1.18.0 in /site (#27350)
Bumps [axios](https://github.com/axios/axios) from 1.16.1 to 1.18.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/axios/axios/releases">axios's releases</a>.</em></p> <blockquote> <h2>v1.18.0 — June 13, 2026</h2> <p>This release hardens redirect and URL handling, improves the validateStatus configuration semantics, and includes updates to documentation, dependencies, and release metadata.</p> <h2>🔒 Security Fixes</h2> <ul> <li> <p><strong>Redirect Header Safety:</strong> Added Node HTTP adapter support for stripping caller-specified sensitive headers on cross-origin redirects, helping prevent custom auth headers such as API keys from leaking to another origin. (<strong><a href="https://redirect.github.com/axios/axios/issues/10892">#10892</a></strong>)</p> </li> <li> <p><strong>URL And Request Hardening:</strong> Rejects malformed <code>http:</code> and <code>https:</code> URLs that omit <code>//</code> with <code>ERR_INVALID_URL</code>, while tightening prototype-pollution-safe config reads, stream size limits, FormData depth handling, data URL sizing, and local <code>NO_PROXY</code> matching. (<strong><a href="https://redirect.github.com/axios/axios/issues/11000">#11000</a></strong>)</p> </li> </ul> <h2>🐛 Bug Fixes</h2> <ul> <li><strong>Status Validation:</strong> Added <code>transitional.validateStatusUndefinedResolves</code> so applications can opt in to treating <code>validateStatus: undefined</code> like the option was omitted, while <code>validateStatus: null</code> remains the explicit way to accept every status. (<strong><a href="https://redirect.github.com/axios/axios/issues/10899">#10899</a></strong>)</li> </ul> <h2>🔧 Maintenance & Chores</h2> <ul> <li> <p><strong>Documentation:</strong> Published the v1.17.0 release notes, fixed a changelog typo, clarified the package update PR policy, and marked the <code>proxy</code> request config as Node.js-only in the advanced docs. (<strong><a href="https://redirect.github.com/axios/axios/issues/10984">#10984</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10988">#10988</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10992">#10992</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10995">#10995</a></strong>)</p> </li> <li> <p><strong>Dependencies:</strong> Bumped <code>@babel/core</code>, <code>@babel/preset-env</code>, <code>@commitlint/cli</code>, <code>@commitlint/config-conventional</code>, <code>@rollup/plugin-babel</code>, <code>@rollup/plugin-commonjs</code>, <code>@vitest/browser</code>, <code>@vitest/browser-playwright</code>, <code>eslint</code>, <code>lint-staged</code>, <code>rollup</code>, <code>vitest</code>, and <code>actions/checkout</code>. (<strong><a href="https://redirect.github.com/axios/axios/issues/10989">#10989</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10996">#10996</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10997">#10997</a></strong>)</p> </li> <li> <p><strong>Release Metadata:</strong> Prepared the 1.18.0 release by updating package metadata and the runtime <code>VERSION</code> value. (<strong><a href="https://redirect.github.com/axios/axios/issues/11003">#11003</a></strong>)</p> </li> </ul> <h2>🌟 New Contributors</h2> <p>We are thrilled to welcome our new contributors. Thank you for helping improve axios:</p> <ul> <li><strong><a href="https://github.com/drori12"><code>@drori12</code></a></strong> (<strong><a href="https://redirect.github.com/axios/axios/issues/10984">#10984</a></strong>)</li> <li><strong><a href="https://github.com/eyupcanakman"><code>@eyupcanakman</code></a></strong> (<strong><a href="https://redirect.github.com/axios/axios/issues/10899">#10899</a></strong>)</li> <li><strong><a href="https://github.com/Adi-Beker"><code>@Adi-Beker</code></a></strong> (<strong><a href="https://redirect.github.com/axios/axios/issues/10995">#10995</a></strong>)</li> </ul> <p><a href="https://github.com/axios/axios/compare/v1.17.0...v1.18.0">Full Changelog</a></p> <h2>v1.17.0 — June 1, 2026</h2> <p>This release adds Node HTTP zstd decompression, hardens config and release workflows, and fixes authentication, header, proxy, and type-handling regressions.</p> <h2>🔒 Security Fixes</h2> <ul> <li><strong>Config Hardening:</strong> Guarded <code>socketPath</code>, <code>params</code>, and <code>paramsSerializer</code> reads with own-property checks to prevent inherited prototype values from affecting request behavior, including SSRF-sensitive paths. (<strong><a href="https://redirect.github.com/axios/axios/issues/10901">#10901</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10922">#10922</a></strong>)</li> <li><strong>Release Publishing:</strong> Switched the publish workflow to npm staged publishing for safer, auditable package releases with provenance. (<strong><a href="https://redirect.github.com/axios/axios/issues/10926">#10926</a></strong>)</li> </ul> <h2>🚀 New Features</h2> <ul> <li><strong>HTTP Compression:</strong> Added Node HTTP adapter support for zstd response decompression, with <code>transitional.advertiseZstdAcceptEncoding</code> controlling whether <code>zstd</code> is advertised in <code>Accept-Encoding</code>. (<strong><a href="https://redirect.github.com/axios/axios/issues/6792">#6792</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10920">#10920</a></strong>)</li> </ul> <h2>🐛 Bug Fixes</h2> <ul> <li><strong>Authentication Handling:</strong> Restored Basic auth on same-origin Node redirects while continuing to strip credentials cross-origin, and aligned the fetch adapter with HTTP adapter behavior for URL-embedded Basic auth. (<strong><a href="https://redirect.github.com/axios/axios/issues/10929">#10929</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10896">#10896</a></strong>)</li> <li><strong>Proxy TLS:</strong> Preserved user <code>httpsAgent</code> TLS options when tunneling HTTPS requests through HTTP CONNECT proxies. (<strong><a href="https://redirect.github.com/axios/axios/issues/10957">#10957</a></strong>)</li> <li><strong>React Native FormData:</strong> Cleared default <code>Content-Type</code> for React Native <code>FormData</code> so multipart boundaries can be generated correctly. (<strong><a href="https://redirect.github.com/axios/axios/issues/10898">#10898</a></strong>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/axios/axios/blob/v1.x/CHANGELOG.md">axios's changelog</a>.</em></p> <blockquote> <h2>v1.18.0 — June 13, 2026</h2> <p>This release hardens redirect and URL handling, improves the validateStatus configuration semantics, and includes updates to documentation, dependencies, and release metadata.</p> <h2>🔒 Security Fixes</h2> <ul> <li> <p><strong>Redirect Header Safety:</strong> Added Node HTTP adapter support for stripping caller-specified sensitive headers on cross-origin redirects, helping prevent custom auth headers such as API keys from leaking to another origin. (<strong><a href="https://redirect.github.com/axios/axios/issues/10892">#10892</a></strong>)</p> </li> <li> <p><strong>URL And Request Hardening:</strong> Rejects malformed <code>http:</code> and <code>https:</code> URLs that omit <code>//</code> with <code>ERR_INVALID_URL</code>, while tightening prototype-pollution-safe config reads, stream size limits, FormData depth handling, data URL sizing, and local <code>NO_PROXY</code> matching. (<strong><a href="https://redirect.github.com/axios/axios/issues/11000">#11000</a></strong>)</p> </li> </ul> <h2>🐛 Bug Fixes</h2> <ul> <li><strong>Status Validation:</strong> Added <code>transitional.validateStatusUndefinedResolves</code> so applications can opt in to treating <code>validateStatus: undefined</code> like the option was omitted, while <code>validateStatus: null</code> remains the explicit way to accept every status. (<strong><a href="https://redirect.github.com/axios/axios/issues/10899">#10899</a></strong>)</li> </ul> <h2>🔧 Maintenance & Chores</h2> <ul> <li> <p><strong>Documentation:</strong> Published the v1.17.0 release notes, fixed a changelog typo, clarified the package update PR policy, and marked the <code>proxy</code> request config as Node.js-only in the advanced docs. (<strong><a href="https://redirect.github.com/axios/axios/issues/10984">#10984</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10988">#10988</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10992">#10992</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10995">#10995</a></strong>)</p> </li> <li> <p><strong>Dependencies:</strong> Bumped <code>@babel/core</code>, <code>@babel/preset-env</code>, <code>@commitlint/cli</code>, <code>@commitlint/config-conventional</code>, <code>@rollup/plugin-babel</code>, <code>@rollup/plugin-commonjs</code>, <code>@vitest/browser</code>, <code>@vitest/browser-playwright</code>, <code>eslint</code>, <code>lint-staged</code>, <code>rollup</code>, <code>vitest</code>, and <code>actions/checkout</code>. (<strong><a href="https://redirect.github.com/axios/axios/issues/10989">#10989</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10996">#10996</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10997">#10997</a></strong>)</p> </li> <li> <p><strong>Release Metadata:</strong> Prepared the 1.18.0 release by updating package metadata and the runtime <code>VERSION</code> value. (<strong><a href="https://redirect.github.com/axios/axios/issues/11003">#11003</a></strong>)</p> </li> </ul> <h2>🌟 New Contributors</h2> <p>We are thrilled to welcome our new contributors. Thank you for helping improve axios:</p> <ul> <li><strong><a href="https://github.com/drori12"><code>@drori12</code></a></strong> (<strong><a href="https://redirect.github.com/axios/axios/issues/10984">#10984</a></strong>)</li> <li><strong><a href="https://github.com/eyupcanakman"><code>@eyupcanakman</code></a></strong> (<strong><a href="https://redirect.github.com/axios/axios/issues/10899">#10899</a></strong>)</li> <li><strong><a href="https://github.com/Adi-Beker"><code>@Adi-Beker</code></a></strong> (<strong><a href="https://redirect.github.com/axios/axios/issues/10995">#10995</a></strong>)</li> </ul> <p><a href="https://github.com/axios/axios/compare/v1.17.0...v1.18.0">Full Changelog</a></p> <h2>v1.17.0 — June 1, 2026</h2> <p>This release adds Node HTTP zstd decompression, hardens config and release workflows, and fixes authentication, header, proxy, and type-handling regressions.</p> <h2>🔒 Security Fixes</h2> <ul> <li><strong>Config Hardening:</strong> Guarded <code>socketPath</code>, <code>params</code>, and <code>paramsSerializer</code> reads with own-property checks to prevent inherited prototype values from affecting request behavior, including SSRF-sensitive paths. (<strong><a href="https://redirect.github.com/axios/axios/issues/10901">#10901</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10922">#10922</a></strong>)</li> <li><strong>Release Publishing:</strong> Switched the publish workflow to npm staged publishing for safer, auditable package releases with provenance. (<strong><a href="https://redirect.github.com/axios/axios/issues/10926">#10926</a></strong>)</li> </ul> <h2>🚀 New Features</h2> <ul> <li><strong>HTTP Compression:</strong> Added Node HTTP adapter support for zstd response decompression, with <code>transitional.advertiseZstdAcceptEncoding</code> controlling whether <code>zstd</code> is advertised in <code>Accept-Encoding</code>. (<strong><a href="https://redirect.github.com/axios/axios/issues/6792">#6792</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10920">#10920</a></strong>)</li> </ul> <h2>🐛 Bug Fixes</h2> <ul> <li><strong>Authentication Handling:</strong> Restored Basic auth on same-origin Node redirects while continuing to strip credentials cross-origin, and aligned the fetch adapter with HTTP adapter behavior for URL-embedded Basic auth. (<strong><a href="https://redirect.github.com/axios/axios/issues/10929">#10929</a></strong>, <strong><a href="https://redirect.github.com/axios/axios/issues/10896">#10896</a></strong>)</li> <li><strong>Proxy TLS:</strong> Preserved user <code>httpsAgent</code> TLS options when tunneling HTTPS requests through HTTP CONNECT proxies. (<strong><a href="https://redirect.github.com/axios/axios/issues/10957">#10957</a></strong>)</li> <li><strong>React Native FormData:</strong> Cleared default <code>Content-Type</code> for React Native <code>FormData</code> so multipart boundaries can be generated correctly. (<strong><a href="https://redirect.github.com/axios/axios/issues/10898">#10898</a></strong>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/axios/axios/commit/2d06f96e8602c2db13b65a26340ee4a1bbc0b61f"><code>2d06f96</code></a> chore(release): prepare release 1.18.0 (<a href="https://redirect.github.com/axios/axios/issues/11003">#11003</a>)</li> <li><a href="https://github.com/axios/axios/commit/32fc489632377d214db55bfa4e2c48486a7d7ce2"><code>32fc489</code></a> fix: malformed http urls (<a href="https://redirect.github.com/axios/axios/issues/11000">#11000</a>)</li> <li><a href="https://github.com/axios/axios/commit/b40ce498abfa10d90b873b4fd08f520afa5d2545"><code>b40ce49</code></a> chore(deps-dev): bump the development_dependencies group with 10 updates (<a href="https://redirect.github.com/axios/axios/issues/10">#10</a>...</li> <li><a href="https://github.com/axios/axios/commit/fe964f960ecb52c3e1155b0daf7be77541956b01"><code>fe964f9</code></a> docs: mark proxy config as Node.js only (<a href="https://redirect.github.com/axios/axios/issues/10995">#10995</a>)</li> <li><a href="https://github.com/axios/axios/commit/5f229d2d1f018d1db3dab6bbe034dbf3f9041b99"><code>5f229d2</code></a> chore(deps): bump actions/checkout from 6.0.2 to 6.0.3 in the github-actions ...</li> <li><a href="https://github.com/axios/axios/commit/fae9d4e7db6a858c407c75e607a071c533c5c4f6"><code>fae9d4e</code></a> docs: clarify package update PR policy (<a href="https://redirect.github.com/axios/axios/issues/10992">#10992</a>)</li> <li><a href="https://github.com/axios/axios/commit/28ab2ced820e55192806c53472ab3eb0cbb68dc2"><code>28ab2ce</code></a> chore(deps-dev): bump the development_dependencies group with 2 updates (<a href="https://redirect.github.com/axios/axios/issues/10989">#10989</a>)</li> <li><a href="https://github.com/axios/axios/commit/a8e4f13aeecc45a3b8fab3ecfd9ddb5d70fb772b"><code>a8e4f13</code></a> fix(core): keep default validateStatus when request passes undefined (<a href="https://redirect.github.com/axios/axios/issues/10899">#10899</a>)</li> <li><a href="https://github.com/axios/axios/commit/614f4552a17de757d4171ad7c3bd38c9c1025fd8"><code>614f455</code></a> docs: publish v1.17.0 release notes (<a href="https://redirect.github.com/axios/axios/issues/10988">#10988</a>)</li> <li><a href="https://github.com/axios/axios/commit/6bb12c191f5380fad321322fb90216ae0dc36985"><code>6bb12c1</code></a> fix: custom auth headers not stripped on cross-origin redirects (<a href="https://redirect.github.com/axios/axios/issues/10892">#10892</a>)</li> <li>Additional commits viewable in <a href="https://github.com/axios/axios/compare/v1.16.1...v1.18.0">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/coder/coder/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
f18c664be2 |
fix(site): stack settings layouts on mobile (#27334)
## Problem On mobile viewports every settings shell renders a fixed 240px sidebar next to the content in a non-responsive flex row, leaving the content almost no width. The MCP Servers page is worst: its fixed-layout table cannot shrink, so the whole page collapses into a single cramped column. ## Changes - `Sidebar` component: full width below the `lg` breakpoint, `w-60` at `lg`+. - Six settings layouts (AI, Deployment, Organization, User, Workspace, Template) stack the nav above the content below `lg` and keep the previous side-by-side spacing at `lg`+. Content wrappers get `min-w-0` so flex children cannot force overflow, and horizontal padding tightens on small screens. - MCP servers table gets `min-w-[640px]` so the existing `overflow-auto` wrapper provides horizontal scrolling instead of colliding column headers. Tailwind class changes only; no component or behavior changes. ## Testing - `pnpm check` and `pnpm run lint:types` pass. - Dogfood UAT on a dev deployment: at 390x844 the MCP Servers, Deployment, Account, and Template settings pages stack nav-above-content with no horizontal body overflow and a scrollable MCP table; boundary verified stacked at 1023px and side-by-side at 1024px; at 1440x900 the layouts are pixel-identical to before (240px sidebar, 112px gap, 40px padding). Closes CODAGT-828. > Created by Mux, an AI agent, on Mike's behalf. |
||
|
|
a9fdf87a2f |
feat: add GET /groups/{group}/members/ai/spend (#27130)
## Description
Adds `GET /api/v2/groups/{group}/members/ai/spend?user_ids=...` (also available org-scoped at `/api/v2/organizations/{org}/groups/{groupName}/members/ai/spend`) to return per-member AI spend attributed to a group, along with each member's effective budget group and the applied spend limit when the queried group is their effective budget source.
In the UI, this endpoint is used alongside the existing `/api/v2/groups/{group}/members` endpoint. AI spend data is kept separate from that endpoint so that:
- Different concepts stay on different endpoints: identity (group members) vs. cost control (spend). Cost control is an additional feature layered on top of groups/orgs.
- Callers that don't need spend information don't pay for its computation.
UI flow:
1. Request `/api/v2/groups/{group}/members` → returns the group's members.
2. Request `/api/v2/groups/{group}/members/ai/spend?user_ids=...` with the IDs from step 1.
**Note:** Only current members of the queried group are returned. `spend_limit_micros` and `limit_source` are populated only when the queried group is the member's effective budget source (its own limit or a user override). `effective_group_id` is null when the member's budget resolves to a group in another organization, since an organization is treated as a tenant boundary.
<img width="2880" height="1904" alt="image" src="https://github.com/user-attachments/assets/33ed395d-d1a3-4b46-bb04-c8d3f41c8886" />
## Changes
- Add `codersdk.GroupMembersAISpend` and `GroupMemberAISpend` types, reusing the shared `AISpendPeriodWindow`.
- Add `GetGroupMembersAISpend` SQL query with a dbauthz per-row filter that mirrors `GET /api/v2/groups/{group}/members`.
- Add handler and routes under `/groups/{group}/members/ai/spend` (and the org-scoped alias) with a required `user_ids` query param (cap 100). Callers with more than 100 members are expected to batch across multiple requests.
- Add codersdk client method.
- Tests: dbauthz, raw SQL, endpoint, and role-access.
Closes https://linear.app/codercom/issue/AIGOV-471/backend-group-members-endpoint-with-members-spend
> [!NOTE]
> Initially generated by Claude Opus 4.7, modified and reviewed by @ssncferreira
|
||
|
|
2adc8f5272 |
feat: add GET /organizations/{org}/groups/ai/spend (#27123)
## Description
Adds `GET /api/v2/organizations/{org}/groups/ai/spend?group_ids=...` to return per-group AI spend and configured limits for a set of groups in an organization.
In the UI, this endpoint is used alongside the existing `/api/v2/organizations/{org}/groups` endpoint. AI spend data is kept separate from that endpoint so that:
- Different concepts stay on different endpoints: identity (groups) vs. cost control (spend). Cost control is an additional feature layered on top of groups/orgs.
- Callers that don't need spend information don't pay for its computation.
UI flow:
1. Request `/api/v2/organizations/{org}/groups` → returns the organization's groups.
2. Request `/api/v2/organizations/{org}/groups/ai/spend?group_ids=...` with the IDs from step 1.
The groups endpoint from 1) is currently not paginated, but if pagination is added later, this design keeps the two responses in sync. This spend endpoint intentionally takes `group_ids` rather than paginating on its own, since it depends on the group set from step 1. Pagination could be added in the future, especially for Cost Control-focused pages.
<img width="2880" height="1460" alt="image" src="https://github.com/user-attachments/assets/ea83b74d-6a4f-45a6-af2f-1024e019da07" />
## Changes
- Add `codersdk.OrganizationGroupsAISpend` and `OrganizationGroupAISpend` types, plus a shared `AISpendPeriodWindow` embedded in the spend response.
- Add `GetOrganizationGroupsAISpend` SQL query with a dbauthz per-row filter that mirrors `GET /organizations/{org}/groups`.
- Add handler and route under `/organizations/{organization}/groups/ai/spend` with a required `group_ids` query param (cap 100). Callers with more than 100 groups are expected to batch across multiple requests.
- Add codersdk client method.
- Tests: dbauthz, raw SQL, endpoint, and role-access.
Closes https://linear.app/codercom/issue/AIGOV-466/backend-organization-groups-endpoint-with-groups-spend
> [!NOTE]
> Initially generated by Claude Opus 4.7, modified and reviewed by @ssncferreira
|
||
|
|
9f4ddea571 |
feat: revoke MCP server OAuth grants at the provider on disconnect (#27300)
Closes [CODAGT-805](https://linear.app/codercom/issue/CODAGT-805/revoke-oauth-grants-at-the-source-for-mcp-servers). The experimental MCP server OAuth2 disconnect endpoint previously deleted only the stored token row, leaving the grant active at the OAuth provider. This PR adds provider-side token revocation while keeping local disconnect independent of provider availability. ## Changes - Add `mcp_server_configs.oauth2_revocation_url` in migration `000547`. The value can be configured manually, discovered from RFC 8414 metadata, and managed through the MCP server settings UI. Non-admin responses redact it with the other OAuth2 fields. - Revoke the refresh token first through the RFC 7009 endpoint, then fall back to the access token only for `unsupported_token_type`. Public clients send `client_id`; confidential clients use `client_secret_basic`. - Delete the local token transactionally before best-effort provider revocation. Callers without a token receive the same response for hidden and nonexistent config IDs, and provider failures return a generic warning without exposing provider response bodies. - Require HTTPS revocation endpoints except for HTTP loopback URLs. Redirects must preserve the POST and remain on the configured origin. Redirect errors omit provider-controlled paths and query strings so reflected token material cannot enter logs. - Treat `200 OK` and `204 No Content` as completed revocations. `202 Accepted` remains a failure because it does not confirm completion. - Prevent an in-flight refresh from recreating a token deleted by disconnect. Refresh persistence now uses an optimistic update keyed by token ID and `updated_at`; only the OAuth callback can create a token row. Refresh conflicts reload the current row or clear in-memory auth when disconnect deleted it. - Return `{token_revoked, token_revocation_error}` from disconnect, while retaining SDK compatibility with the legacy `204` response. The UI surfaces provider revocation failures as warning toasts. - Document revocation endpoint discovery, HTTPS requirements, and best-effort disconnect behavior. No token or no configured revocation URL returns `token_revoked: false` without an error, so disconnect remains idempotent. > Updated by Mux, an AI coding agent, on Mike's behalf. |
||
|
|
9b3af629cd | fix: hide and reject chat models from disabled AI providers (#27070) | ||
|
|
34ed124478 |
fix(site): align React Compiler check scope with vite.config.mts (#27216)
## Stack Context First PR of a 6-PR stack that thins the agent instruction corpus (~4,800 lines down to ~2,800) by removing startup bloat, assigning each procedure one canonical owner, and fixing rules that drifted from reality. Split from #27203 for reviewability. ## Why? `site/vite.config.mts` compiles `src/pages/AIBridgePage/` with the React Compiler, but `site/scripts/check-compiler.mjs` did not include that directory. Compiler regressions in AIBridgePage were invisible to CI: code could silently bail out of compilation with no signal. The two lists had already drifted once, which is exactly how this class of bug recurs. ## What? - Add `src/pages/AIBridgePage/` to the check-compiler scope. Verified all 381 functions in scope compile cleanly. - Cross-reference the two lists with comments so the next person who edits one finds the other. This is the only behavioral (non-docs) change in the stack, which is why it sits at the bottom. > This PR was prepared by Mux (AI agent) on Mike's behalf. |
||
|
|
1ea61b976b |
fix(site): prevent slash menu from flashing at top-left corner when closed (#27326)
Typing `/` in the agent chat input opens the skills slash menu. Pressing Backspace to erase the `/` made the menu flash at the top-left corner of the app for a split second before disappearing. Radix keeps the popover content mounted through its exit animation, but the caret-positioned `PopoverAnchor` was unmounted in the same render that closed the menu. Without an anchor, the popper repositioned the still-visible closing content to the viewport origin. The anchor now stays rendered at the last known caret rect, so the menu holds its position while it animates out. Verified with a frame-by-frame position recorder in the browser: before the fix the closing menu jumped from the caret position to `(0, 4)`; after the fix it stays in place until unmount. Added a `BackspaceClosesMenuWithoutRepositioning` story that fails without the fix. > This PR was created by Mux, an AI coding agent, on Mike's behalf. |
||
|
|
46d1823c0a |
feat: add workspace skills to agent chat slash menu (#25600)
> This Pull Request was updated by Mux working on behalf of Mike. Adds workspace skills to the agent chat slash menu, sourced entirely from the chat's pinned context resources (the single-chat GET response the page already fetches), the same inventory `read_skill` resolves from. No new API endpoint is introduced. Personal entries insert `/name`, or `/personal/name` when the name collides with a workspace skill or the chat's pinned context has not resolved yet; workspace entries insert `/workspace/name`. Qualified aliases stay searchable even when the displayed trigger is bare. Before a chat binds a workspace (new chat form, or a selected but unbound workspace), the menu lists personal skills only. Sending a message invalidates the chat detail query, and chatd broadcasts a context watch event when a first-turn bind pins the chat, so the menu picks up newly pinned context without a reload. Makes `UpdateChatWorkspaceBinding` a no-op when the requested workspace/build/agent binding is unchanged, preserving `updated_at` so chat list ordering and watch events stay stable. Includes regression coverage for the no-op binding guard, pinned-context skill mapping, collision qualification, and skills menu behavior. Refs [CODAGT-474](https://linear.app/codercom/issue/CODAGT-474/ux-improvements-for-coder-agents) (skills autocompleting in the editor). |
||
|
|
36e36e2048 |
fix(site): wrap workspace topbar controls on narrow viewports (#27313)
On mobile-width viewports the workspace page grew to ~1080px wide (390px viewport), pushing the schedule controls, status indicator, and action buttons off-screen. Users had to zoom out or scroll horizontally to reach Stop/Restart/Favorite/Share. The topbar header and the right-side controls group used non-wrapping flex rows, and every child is a `whitespace-nowrap` button, so the row's minimum width (~725px for the controls alone) forced the document wider than the viewport. ## Changes - `WorkspaceTopbar`: allow the topbar header and the right controls group to wrap; right controls stay right-aligned when they wrap onto their own row. - `WorkspaceActions`: allow the button row to wrap. - `TopbarData`: merge a caller-provided `className` (no existing caller passed one); the workspace breadcrumbs use it to wrap on very narrow screens. ## Verification Compared before/after with agent-browser on Storybook stories (`Workspace: Running`, `WorkspaceTopbar: Outdated / WithQuotaWithOrgs / Dormant / ConnectedWithMaxDeadline`): | Viewport | Before `scrollWidth` | After `scrollWidth` | |---|---|---| | 320 | 1080 (overflow) | 305 (fits) | | 390 | 1080 (overflow) | 375 (fits) | | 768 | 1080 (overflow) | 753 (fits) | | 1024 | 1080 (overflow) | 1009 (fits) | | 1440 | 1425 (fits) | 1425, pixel-identical (0% diff) | At widths >= 1280 the layout is unchanged (0% pixel diff at 1440 across the stories above). Between ~1080-1230px the controls now wrap onto a second right-aligned row instead of squeezing label text onto two lines inside a single row. Validation: `biome check`, `tsc --noEmit`, and `pnpm test:storybook` for `Workspace.stories.tsx` + `WorkspaceTopbar.stories.tsx` (36 passed). > This PR was prepared by Mux, an AI coding agent, on Mike's behalf. |
||
|
|
1ac106255b | feat: add Anthropic 1M context window toggle for Agents model configs (#27257) | ||
|
|
2ac2295b1e |
fix: do not send or use stale init dynamic parameter state (#27283)
In summary, we use the init message if we have no autofill params. If we do, then we ignore the init message, send another message with the autofilled values, and then when we get *that* response, finally we render the form since we know we have good state. This eliminates the possibility of temporarily rendering with stale state. This is the same fix that was applied to the edit page, but on the create page this time. The only difference is that the create page does not need to wait on a build parameters query, instead it has to wait on the first message from the socket (to get defaults). This also makes one change where we would send the defaults in the init message. The server already knows the defaults so there is no need to send them. The advantage here is that we no longer need to wait for the first message, and it also fixes an issue where fields with blank values were getting validation errors because they were not filled out, before the user had a chance to actually fill them out. |
||
|
|
1453b4b1fc |
docs: document Bedrock mantle protocol (#27296)
Implements: https://linear.app/codercom/issue/AIGOV-518/add-docs-for-bedrock-mantle Follow-up to: https://github.com/coder/coder/pull/26745 |
||
|
|
3dd9265fa6 |
feat: add UI option to disconnect OAuth2 MCP credentials (#27299)
Closes [CODAGT-804](https://linear.app/codercom/issue/CODAGT-804/add-ui-option-to-revoke-oauth-mcp-credentials). Users could authenticate with an OAuth2 MCP server from the chat input, but there was no UI to disconnect those per-user credentials. The backend endpoint (`DELETE /api/experimental/mcp/servers/{id}/oauth2/disconnect`) already existed. ## Changes - Connected OAuth2 MCP rows in the chat input plus menu now show a disconnect icon button next to the enable switch. It opens a confirmation dialog; confirming calls the disconnect endpoint, shows a toast, and refetches MCP configs so the row reverts to the `Auth` button without a reload. - New `disconnectMCPServerOAuth2` API client method and react-query mutation that invalidates `mcp-server-configs`. - Storybook interaction tests: control visibility per auth state, cancel makes no API call, confirm calls the endpoint once, failed disconnect keeps the dialog open. - Hardened `TestMCPServerConfigsOAuth2Disconnect`: seeded tokens flip `auth_connected`, disconnect only removes the calling user's token, and repeat disconnect stays idempotent. The endpoint removes the token stored in Coder; it does not revoke the upstream OAuth grant, so the UI copy says "disconnect" rather than "revoke". Validated with the targeted Go test, Storybook tests (51 passed), tsc, biome, the react-compiler check, and a manual dogfood run (seeded token, disconnect/cancel/reconnect flows verified in the UI). > This PR was authored by Mux, an AI coding agent, on Mike's behalf. |
||
|
|
9862f10484 |
feat(site): add Bedrock mantle protocol selector to provider form (#27156)
Implements: https://linear.app/codercom/issue/AIGOV-517/add-ui-for-bedrock-mantle Follow-up to https://github.com/coder/coder/pull/26745, which added AWS Bedrock **mantle** support to the backend and modeled it as a `protocol` field on the Bedrock provider settings. ## What changed - Adds a **Protocol** selector to the Bedrock provider form: InvokeModel (default) or Mantle. - The form is now protocol-aware: - **Model** / **Small-fast model** fields are shown only for InvokeModel. Mantle is a passthrough (the client sends the model at request time), so the fields are hidden and omitted from the saved settings. - **Endpoint** validation, placeholder, and hint switch per protocol. Mantle requires a `https://bedrock-mantle.{region}.api.aws/anthropic` URL; InvokeModel keeps the `https://bedrock-runtime.{region}.amazonaws.com` shape. The `/anthropic` suffix is required for mantle because the SDK appends `/v1/messages` to the base URL. ## Manual Testing Tested the following scenarios: 1. Creating a new Mantle provider — works. 2. Creating a new InvokeModel provider — works. 3. Verifying that an existing InvokeModel provider continues to work. 4. Upgrading an existing InvokeModel provider to Mantle — works. ## Screenshots ### InvokeModel <img width="1085" height="474" alt="image" src="https://github.com/user-attachments/assets/4c36b9b0-0eb8-4b17-80b7-e2112325f8d1" /> ### Mantle <img width="1082" height="357" alt="image" src="https://github.com/user-attachments/assets/e8caef26-83d1-4b7e-8f96-79079949e8f1" /> --------- Co-authored-by: Jake Howell <jake@hwll.me> |
||
|
|
b3ff4baeb9 |
fix: smooth compose loader to files page transition (#27277)
## Summary During the template builder compose flow, the transition into the template files page briefly flashed the wizard form again before the files page settled. Root cause: the loader was gated on `createMutation.isPending`. When the compose POST resolved, `isPending` flipped to `false` in the same commit that `onSuccess` navigated to the files page, so `TemplateBuilderPageView` repainted the wizard form for a frame before the route change committed and unmounted it. Fix: keep the loader mounted while the mutation is pending **or** succeeded (`createMutation.isPending || createMutation.isSuccess`). Since `onSuccess` always navigates away, the loader stays until the component unmounts, so the form never reflashes. The error path is unaffected (`isSuccess` stays false). Resolves DEVEX-561. https://github.com/user-attachments/assets/6d5ec04e-9f97-4864-bd18-e1e75055f079 ## Scope Targets the wizard form reflash only. Two adjacent items were identified during investigation and intentionally left out: - The destination files page briefly shows its own `<Loader />` while it fetches template files. Smoothing that requires prefetching before navigation and is a larger change. - The `justCreated` "Awesome, you just created a template!" alert is cleared by a mount effect, so it renders one frame then disappears. Arguably its own bug. Happy to follow up on either if wanted. ## Testing - Biome clean on the changed file. - Manual: build a template through the wizard and confirm the loader holds straight through to the files page with no form flash. ## Stack Stacked on top of #27276 (DEVEX-593). --- Generated by Coder Agents. |
||
|
|
3ddf7d3baa |
fix: stop the template builder build progress bar from looping (#27276)
## Summary The template builder's "Building your template" loader had a progress bar that animated 0→100% every 5s with an infinite repeat, so it visibly restarted over and over while a template built. It looked broken and was frustrating to watch. This replaces the looping fill with a single ease-out fill that decelerates toward 90% and holds until the request resolves and the loader unmounts. Since the loader is intentionally indeterminate and no progress is streamed to the browser, this also removes the now-dead `onUpdate` callback plumbing from the backend `waitForProvisionerJob` (its only caller passed `nil`). Resolves DEVEX-593. https://github.com/user-attachments/assets/6d5ec04e-9f97-4864-bd18-e1e75055f079 ## Commits - `refactor(coderd): drop unused onUpdate callback from waitForProvisionerJob` - `fix(site/src/pages/TemplateBuilder): stop build progress bar from looping` ## Testing - `go build ./coderd/` passes with the reduced `waitForProvisionerJob` signature. - Biome clean on the changed frontend file. - Storybook: `pages/TemplateBuilder/BuildingTemplateLoader` shows the bar fill once and hold, with no restart. <details> <summary>Implementation plan</summary> # DEVEX-593: Stop the build progress bar from looping repeatedly ## Problem While the template builder composes and imports a template, the FE shows `BuildingTemplateLoader`. Its progress bar animates from 0% to 100% over 5s with `repeat: Number.POSITIVE_INFINITY`, so it visibly restarts over and over. Users report this looks broken and is frustrating to watch while waiting. ## Decision (scope) Minimal fix only: **stop the loop**, plus remove the now-dead `onUpdate` plumbing from the backend. Since the UI is intentionally indeterminate and no progress signal is streamed, the callback serves no purpose and should be deleted rather than left as dead code. ### Why not "real sync" now - `POST /api/v2/templatebuilder/compose/template` is a single blocking request. It composes, bundles, inserts the provisioner job, then calls `waitForProvisionerJob(jobCtx, provisionerJob.ID, nil)` and only responds once the job completes. - The `onUpdate` callback runs server-side only. Nothing is streamed to the browser during the wait, so the FE has no progress signal to bind to. - A provisioner job exposes no numeric percentage. Only status transitions (`pending -> running -> succeeded`) and coarse log stages (`init/plan/graph/apply`) exist. Real sync would require converting the endpoint to a streaming protocol (SSE/WebSocket) plus FE rework, which is disproportionate for this 1-point ticket. ### Keep polling (do not switch to pubsub-block) The wait could technically block instead of poll: on completion `CompleteJob` publishes `ProvisionerJobLogsNotifyMessage{EndOfLogs: true}` on the job logs notify channel, so we could subscribe and wait for that message with the context timeout as a fallback. We deliberately do not do that here: correctness would require subscribe-before-completion plus an initial DB completion check to avoid a race, and Postgres LISTEN/NOTIFY is at-most-once (can drop under load), so a poll fallback would still be needed. The existing backoff poll (100ms -> 200ms -> 500ms -> 1s) is simple and robust for a short-lived synchronous request. ## Approach Replace the looping fill with a single, non-repeating ease-out fill that decelerates and approaches (but never reaches) ~90%, holding there until the request resolves and the loader unmounts. This reads as continuous forward progress for an unknown-duration operation and never restarts. The floating-icon animation is intentional ambient motion and is not in scope. ## Out of scope - Any behavioral change to how the endpoint waits (it still blocks on the job). - Streaming real job progress to the browser. - Changes to the floating-icon animation. </details> --- Generated by Coder Agents. |
||
|
|
529b2ead78 |
feat(site/src/pages/AgentsPage): show "Archived chats" sidebar heading when viewing archived chats (#26926)
In the agents sidebar, show "Archived chats" instead of "Chats" when the archive filter is set to `archived`. The heading reads the existing `sidebarFilters.archiveStatus` state, the same condition already used for the archived empty-state message. --- _This PR was opened by [Coder Agents](https://coder.com/) on behalf of @tracyjohnsonux._ --------- Co-authored-by: Coder Agents <noreply@coder.com> |
||
|
|
213f5ce606 | fix(site): redesign provider tri-state controls (#27288) | ||
|
|
457fa5afa3 | fix(site): move thinking settings to provider configuration (#27287) | ||
|
|
9d1e881093 | refactor(site/src/pages/AgentsPage): use model selector for personal overrides (#27229) | ||
|
|
baf4dfae4d |
fix(site/src/pages/TemplateBuilder): display TemplateCard/ModuleCard's official badge inline (#27036)
closes DEVEX-575 There are some screen widths / base template names where the official badge will break lines by itself as an orphan (see Google Compute Engine (Linux) in screenshot below). However, I personally prefer this over the current flex layout (compare with the screenshot in original issue) <img width="1840" height="1191" alt="image" src="https://github.com/user-attachments/assets/d5bee310-0202-4d45-aef7-767e457be051" /> Unfortunately ` ` only works if the entities on either side are both text--not text on the left + image on the right, which is what we have here. ^One alternative to prevent orphan badges is to split the base template name by words, then wrap the last word + the official badge in a span with `white-space: nowrap;`. But that feels a little overwrought to me; I like the clarity of continuing to just show `{name}` in the JSX. What do you guys think? |
||
|
|
0caaac5d27 |
fix: prebuild coderd before Playwright startup for e2e tests (#27136)
The test-e2e job could flake while Playwright waited for its webServer to become ready. CI already built site/e2e/bin/coder, but that binary was built before pnpm build and without the embed tag, so Playwright ignored it and started coderd with go run -tags embed instead. That put Go compilation, including frontend asset embedding, inside Playwright's webServer timeout. Local runs had a similar ordering trap. pnpm playwright:test invoked Playwright directly, and Playwright starts webServer before globalSetup, so the existing preflight build could not guarantee a binary existed before webServer startup. Build the E2E coder binary with the embed tag and make it depend on site/out/index.html. In CI, build the frontend first, then build the E2E binary, then run Playwright. For local runs, have pnpm playwright:test and pnpm playwright:test-ui run make site/e2e/bin/coder before invoking Playwright. Playwright now starts the prebuilt site/e2e/bin/coder binary and waits on the public /healthz endpoint instead of an authenticated API endpoint. This keeps compilation outside the webServer readiness timeout and makes the readiness probe quieter and more direct. I moved to /healtz because the existing endpoint was returning 401, which still means “server is up,” but it is a strange readiness signal. /healthz is explicitly public and returns 200 OK once the HTTP server is accepting requests. Caveat: running pnpm exec playwright test --config=e2e/playwright.config.ts directly bypasses the package script and therefore bypasses the prebuild. Use pnpm playwright:test or make test-e2e for the supported local flow. Because the site package scripts now call make, add make to knip's ignored system binaries. Tests: - pnpm lint:types - pnpm exec playwright test --config=e2e/playwright.config.ts --list - PATH="/opt/homebrew/opt/make/libexec/gnubin:/opt/homebrew/opt/gnu-getopt/bin:$PATH" make gen/mark-fresh - PATH="/opt/homebrew/opt/make/libexec/gnubin:/opt/homebrew/opt/gnu-getopt/bin:$PATH" pnpm playwright:test --list <!-- If you have used AI to produce some or all of this PR, please ensure you have read our [AI Contribution guidelines](https://coder.com/docs/about/contributing/AI_CONTRIBUTING) before submitting. --> |
||
|
|
cc11c8a536 |
feat: surface model content-filter refusals as a blocked chat error (#27118)
Blocked turns from a provider's content filter (Anthropic's `refusal` stop reason with empty content) previously ended silently on the "Thinking" spinner. They now end as a terminal `content_filter` error that renders as a "Response blocked" message with the provider's category and explanation. <img width="888" height="335" alt="image" src="https://github.com/user-attachments/assets/cef85a59-4091-4e62-9d45-1eb06748db48" /> Closes CODAGT-611 Follow-ups will involve implementing fallbacks, but this alone is pretty important |
||
|
|
8eaf4f507b |
feat: generate the known-models catalog and aigateway prices (#27146)
- Regenerates `prices.json` from models.dev. The seeder only upserts, so existing deployments keep delisted models. - Generate the frontend known-models catalog instead of hand-writing it. `make gen/aibridge-prices` fetches models.dev once - Moved patches to model definitions to separate `overrides.jq` which handles both `claude-sonnet-4-5` 200k context and 'aliasing' Fable 5 as Mythos 5. - Editorial choices of selection, order, aliases, and reasoning defaults live in `curation.json`. - Adds golden join tests with one error case per validation, a no-network drift test comparing curation to the checked-in artifact, and pinned invariants for the Anthropic thinking-mode split (the wrong side returns HTTP 400) and the sonnet-4-5 context pin. Adding a model is now one `curation.json` entry plus `make gen/aibridge-prices`, assuming it is present on models.dev. > This PR was authored by Coder Agents on Cian's behalf. --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
b377bec5f4 | fix(site): replace ansi-to-html in the log viewer (#27206) | ||
|
|
61e52532c0 |
docs: wrap placeholder syntax in backticks in CLI help and swagger annotations (#27194)
## Problem
Generated reference docs (`docs/reference/cli/*`,
`docs/reference/api/*`) contained raw placeholder and JSON syntax that
came straight from Go CLI help strings and swagger annotations. HTML
renderers treat the angle-bracket tokens (`<team-slug>`, `<uuid>`,
`<KEY>`, etc.) as unknown tags and drop them, so readers see
broken/half-missing text today. The same strings also break MDX parsing.
## Fix
Wrap the placeholder/JSON syntax in backticks **at the source** (Go help
strings and swagger annotation comments), then `make gen`. Rendered docs
now show the placeholders as inline code instead of dropping them.
### Source changes
| File | Placeholder wrapped | Surfaces in |
|------|--------------------|-------------|
| `codersdk/deployment.go` | `` `<organization-name>/<team-slug>` `` |
`cli/server.md`, `coder --help`, settings UI |
| `codersdk/deployment.go` | `` `CODER_AI_GATEWAY_PROVIDER_<N>_*` ``, ``
`CODER_AI_GATEWAY_PROVIDER_<N>_<KEY>` `` | `api/schemas.md` |
| `cli/tokens.go` | `` `<type>:<uuid>` `` | `cli/tokens_create.md`,
`coder --help` |
| `coderd/aitasks.go` | `` `owner:<…>` ``, `` `organization:<…>` ``, ``
`status:<status>` `` | `api/tasks.md` |
| `coderd/exp_chats.go` | `` `pr_status:<…>` `` and sibling filter
tokens | `api/chats.md` |
| `coderd/provisionerdaemons.go`, `coderd/provisionerjobs.go` | ``
`{'tag1':'value1','tag2':'value2'}` `` | `api/organizations.md`,
`api/provisioning.md` |
Everything else in the diff (`coderd/apidoc/*`, `docs/reference/**`,
`*.golden`, `site/src/api/typesGenerated.ts`) is `make gen` output.
## Reviewer notes (the "considered pass" from the ticket)
- **Product-visible:** this changes `coder server --help` and `coder
tokens create --help` output, and the `server-config.yaml` reference
comment. Backticks in terminal help are literal but read fine as
placeholder markers.
- **Settings UI:** the `deployment.go` `Description` also renders in the
deployment settings page. If that field is not Markdown-rendered,
literal backticks will show there. Happy to drop the `deployment.go`
change if you'd rather keep the UI text clean and fix `server.md`
another way.
- **Out of scope here:** `docs/reference/cli/agent-firewall.md`
(`<host>`/`<glob>`) is generated from the external
`github.com/coder/boundary` module, not this repo. It needs an upstream
fix + module bump; not included in this PR.
<details>
<summary>Implementation notes / decision log</summary>
- Scope taken from DOCS-551: source-level backtick pass for generated
reference docs only. Hand-written Markdown fixes are tracked separately
(companion ticket).
- Swagger `@Param` descriptions are Go comments, so the existing `\|`
pipe-escaping in the chats `q` filter is preserved inside the new
backticks (still required for the Markdown table cell to render `|`).
- Verified after `make gen`: generated docs render placeholders as code
spans, table pipes intact; `gofmt` clean; changed Go packages build; no
emdash/endash introduced.
- Deliberately left the `AIProviderConfig` type-level doc comment
untouched because it does not surface in any generated doc (kept the
diff to doc-feeding comments).
</details>
Linear: DOCS-551
---
_Opened by Coder Agents on behalf of @nickvigilante._
---
## Evidence: placeholders dropped on the live docs site
Verified **2026-07-14** against the live site (`coder.com/docs`, i.e.
`main`, pre-merge) by loading each affected page in headless Chrome and
reading the post-hydration DOM (confirmed identical in the raw page
payload). Each simple `<token>` placeholder is parsed as an **empty
custom HTML element**, so the browser renders nothing for it and the
placeholder text disappears from the page.
### What readers see today (before this PR)
| Page (live) | Source Markdown | Rendered on the live site |
|-------------|-----------------|---------------------------|
| [`cli/server`](https://coder.com/docs/reference/cli/server) — OAuth2
GitHub Allowed Teams | `Structured as: <organization-name>/<team-slug>.`
| `Structured as: /.` |
|
[`cli/tokens_create`](https://coder.com/docs/reference/cli/tokens_create)
— `--allow` | `Repeatable allow-list entry (<type>:<uuid>, e.g.
workspace:1234-...).` | `Repeatable allow-list entry (:, e.g.
workspace:1234-...).` |
| [`api/tasks`](https://coder.com/docs/reference/api/tasks) — `q` | `...
status:<status>` | `... status:` (nothing after the colon) |
| [`api/schemas`](https://coder.com/docs/reference/api/schemas) —
AIBridgeConfig (`anthropic`/`bedrock`/`openai`) |
`CODER_AI_GATEWAY_PROVIDER_<N>_*` | `CODER_AI_GATEWAY_PROVIDER__*` |
| [`api/schemas`](https://coder.com/docs/reference/api/schemas) —
AIBridgeConfig (`providers`) | `CODER_AI_GATEWAY_PROVIDER_<N>_<KEY>` |
`CODER_AI_GATEWAY_PROVIDER__` |
[`api/chats`](https://coder.com/docs/reference/api/chats) (`q`) drops
five tokens the same way — `title:<substring>`, `diff_url:<url>`,
`pr:<number>`, `pr_title:<text>`, and the trailing `title:<value>`. The
live parameter description reads (note the dangling `title:`,
`diff_url:`, `pr:`, `pr_title:`):
```text
Search query. Supports title: (case-insensitive, quote multi-word values), archived:bool, has_unread:bool, pr_status:<draft|open|merged|closed> as repeated or comma-separated values, source:<created_by_me|shared_with_me>, diff_url: (quote values containing colons), pr: (exact PR number match), repo:<owner/repo> (case-insensitive substring match against git remote origin or URL), pr_title: (case-insensitive PR title substring). Bare terms are not supported; use title: for title filtering.
```
<details>
<summary>Raw rendered DOM from the live site (headless Chrome,
post-hydration)</summary>
```html
<!-- reference/cli/server -->
Structured as: <organization-name>/<team-slug>.</team-slug></organization-name>
<!-- reference/cli/tokens_create -->
Repeatable allow-list entry (<type>:<uuid>, e.g. workspace:1234-...).</uuid></type>
<!-- reference/api/tasks : only status:<status> drops; the /-containing tokens are escaped and survive -->
Search query for filtering tasks. Supports: owner:<username/uuid/me>, organization:<org-name/uuid>, status:<status></status>
<!-- reference/api/schemas : anthropic / bedrock / openai rows -->
Deprecated: Use Providers with indexed CODER_AI_GATEWAY_PROVIDER_<n>_* env vars instead.</n>
<!-- reference/api/schemas : providers row -->
Providers holds provider instances populated from CODER_AI_GATEWAY_PROVIDER_<n>_<key> env vars and/or the deprecated LegacyOpenAI/LegacyAnthropic/LegacyBedrock fields above.</key></n>
```
The parser auto-inserts closing tags
(`</team-slug></organization-name>`) and lowercases the tag name (`<N>`
becomes `<n>`), leaving `__` where `<N>_` used to be. Every wrapped
placeholder renders correctly as inline code on the [docs preview for
this
branch](https://coder.com/docs/@vigilante%2Fdocs-551-backtick-placeholder-syntax-in-generated-reference-docs-cli/reference/cli/server).
</details>
### Accuracy note — cases that do *not* drop on live
These render fine today, so they are **not** evidence of dropping (the
PR still wraps them for consistency / MDX-safety):
-
[`api/organizations`](https://coder.com/docs/reference/api/organizations)
and
[`api/provisioning`](https://coder.com/docs/reference/api/provisioning):
`{'tag1':'value1','tag2':'value2'}` renders verbatim — curly braces are
not an HTML tag.
- Tokens containing `/` or `|` are escaped by the renderer and stay
visible (as literal `<...>`): `<username/uuid/me>`, `<org-name/uuid>`,
`<owner/repo>`, `<draft|open|merged|closed>`,
`<created_by_me|shared_with_me>`. Backticks still improve their
readability, but they were never dropped.
|
||
|
|
3126306598 |
feat: add --aigateway-proxy-target flag (#27122)
Adds `--aigateway-proxy-target` option to `deploymentGroupAIGatewayProxy` that defines URL to which intercepted requests should be forwarded to. Forward URL used to be hardcoded to `coderAPI.AccessURL` pointing to embedded Gateway. With addition of standalone AI Gateway this needs to be configurable. Renamed `aibridgeproxyd.Server.coderAccessURL` and `coderAccessPort` -> `gatewayURL` and `gatewayPort` + option to better reflect reality. |
||
|
|
a567f6a89f | feat: allow admins to override the chat compaction model (#27151) | ||
|
|
bf57da58e7 | chore(site): replace CircularProgress with Spinner component (#24276) | ||
|
|
57852112a6 |
chore: unify admin settings menu items (#27209)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell. ## Problem #27191 fixed the mobile menu missing the **AI** / **AI sessions** items, but did so by duplicating the item list. The desktop `DeploymentDropdown` and mobile `MobileMenu` each hardcode the same Admin settings links and permission gates. That duplication is exactly why the two drifted out of sync in the first place, and it will happen again the next time an item is added. ## Fix Extract a single source of truth in `adminSettings.ts`: - `AdminSettingsPermissions` type shared by both surfaces. - `getAdminSettingsItems(permissions)` builds the ordered item list using conditional spreads, e.g. ```ts ...(canViewAISettings ? [{ label: "AI", to: "/ai/settings" }] : []), ``` - `canViewAdminSettings(permissions)` for the desktop visibility gate. `DeploymentDropdown` and `MobileMenu` now just `.map()` over the shared list, so adding or changing an item is a one-line edit in one place. No backend, permission, routing, or user-visible behavior changes. Item labels, links, and order match the current desktop dropdown (mobile now inherits the same `linkToAuditing` constant instead of a hardcoded `/audit`, same value). <details> <summary>Rationale / approach</summary> Following Larry Wall's virtues: laziness (one list to maintain, not two), impatience (kill the class of bug where the two menus silently diverge), and hubris (leave a shared module nobody has to apologize for). Kept `canViewOrganizations` in the permission type and visibility gate even though Organizations always renders, preserving prior behavior rather than changing it as part of a refactor. Validated with `biome check` and `tsc --noEmit`; existing `MobileMenu.stories.tsx` args already cover the Admin / Auditor / OrgAdmin / Member permission matrices. </details> |
||
|
|
bff7ec7624 |
refactor(site): de-emotion the DERP health page (#27208)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell.
## What
Removes the last `@emotion/react` usage from the DERP health page
(`site/src/pages/HealthPage/DERPPage.tsx`).
- Drops `useTheme` from `@emotion/react`; the page no longer reads the
Emotion theme.
- Replaces the region pin's `style={{ color: healthyColor(theme,
severity) }}` with a Tailwind class derived from severity, matching the
existing pattern in sibling components (`HealthIcon`, `HealthyDot`,
`StatusIcon` in `Content.tsx`).
- Deletes `healthyColor.ts`, which was only consumed by this page and
itself depended on `@emotion/react`.
## Why
The page was already almost entirely Tailwind-based; the theme lookup
was the only Emotion holdout. Aligning it with the surrounding
components keeps the severity colours consistent and removes dead code.
<details>
<summary>Notes</summary>
Severity → class mapping mirrors `Content.tsx`:
| Severity | Class |
| --- | --- |
| `ok` | `text-content-success` |
| `warning` | `text-content-warning` |
| `error` | `text-content-destructive` |
Note: the old helper used `theme.roles.*.fill.solid` tokens, whereas the
surrounding components use the `content-*` tokens — these can differ
slightly in shade. I opted for consistency with the neighbouring health
components. Happy to swap to a dedicated `fill`-equivalent token if
you'd prefer an exact colour match.
</details>
|
||
|
|
3060a40285 |
refactor(site/src/pages/UserSettingsPage/TokensPage): de-MUI TokensPageView (#27212)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell.
Removes the remaining MUI/Emotion dependency from `TokensPageView.tsx`.
## Changes
- Removed `useTheme` from `@emotion/react` and the `const theme =
useTheme()` call.
- Replaced all `style={{ color: theme.palette.text.secondary }}` inline
styles with the `text-content-secondary` Tailwind token, matching
sibling components (`Table.tsx`, other UserSettings pages).
- Preserved `data-pixel="ignore"` and all other attributes/behavior.
## Validation
- `tsc --noEmit`: no errors for the file.
- `biome check`: clean.
|
||
|
|
f2181572cc |
fix(site): support browser back and forward in template builder wizard (#27104)
Browser back/forward controls did not work in the template builder wizard. Using browser navigation sent the user out of the wizard entirely instead of moving between steps. The wizard's current step is now driven by a `?step=` search param. Step transitions push history entries so browser back/forward walks the steps. Steps that are invalid, skipped, or unreachable given the wizard state are clamped and the URL is rewritten with a replace, keeping URL and state in sync in both directions. `?base=` is accepted as the only entry search param and deep-links to a preselected base template (superseding #26808). The page container resolves it against the available bases, holds the wizard behind a loader until it is consumed and removed from the URL, then mounts the wizard starting on the first step after base selection. Closes https://linear.app/codercom/issue/DEVEX-594 > Generated with [Coder](https://coder.com) by @jeremyruppel |
||
|
|
0f55c283f1 | fix: use backend-selected chat agent for desktop, git, terminal (#26959) | ||
|
|
55b06f14a3 | feat: allow overriding advisor reasoning effort (#27196) | ||
|
|
63ec93a7ce |
feat: add AWS Bedrock mantle endpoint to AI Gateway (#26745)
Implements https://linear.app/codercom/issue/AIGOV-213/add-bedrock-provider # AWS Bedrock mantle support in AI Gateway ## Summary Add support for the AWS Bedrock **mantle** endpoint (`bedrock-mantle.{region}.api.aws/anthropic/v1/messages`) to AI Gateway. Mantle serves Claude through the native Anthropic Messages API. We model it as a `protocol` field on the existing Bedrock provider settings (`invoke-model` default, or `mantle`) rather than as a new provider type, and we treat mantle as a pure passthrough: SigV4-sign and forward, no body translation. ## Background Claude on AWS Bedrock is reachable through two endpoints, each speaking exactly one wire protocol: 1. **InvokeModel** (existing): `bedrock-runtime.{region}.amazonaws.com`. Model id in the URL path, request translated into Bedrock's InvokeModel format, responses returned as a binary AWS eventstream. This is what AI Gateway already supported for Bedrock. 2. **Mantle** (this doc): `bedrock-mantle.{region}.api.aws/anthropic/v1/messages`. Native Anthropic Messages API: model in the body, plain SSE streaming. ## Why a `protocol` field, not a new provider type The alternative is to model mantle as its own `ai_provider_type` (`bedrock-mantle`) alongside `bedrock`. I chose the `protocol` field instead for two reasons: 1. Mantle reads more like a protocol of Bedrock than a separate provider. It is the same AWS account, credentials, region, and IAM, reached over a different wire protocol and host. One Bedrock provider with two protocols (`invoke-model` default and `mantle`) models that more organically than two provider types. 2. It avoids a database migration. The `protocol` field lives in the settings JSON blob (empty resolves to `invoke-model`, so existing providers are unaffected), whereas a new type means an enum value and the `ALTER TYPE ... ADD VALUE` migration that goes with it. ## Why passthrough, not translation The client already emits Bedrock-legal requests in mantle mode: ```sh export CLAUDE_CODE_USE_MANTLE=1 export CLAUDE_CODE_SKIP_MANTLE_AUTH=1 export ANTHROPIC_BEDROCK_MANTLE_BASE_URL=https://<coder>/api/v2/aibridge/<provider-name> ``` So the gateway just forwards the body and SigV4-signs it (service `bedrock-mantle`), and skips all the InvokeModel body-translation (model remap, thinking conversion, beta-flag allowlist, field stripping). This keeps the mantle path thin and avoids a second copy of translation logic to maintain. ## Consequences - Protocol-dependent fields: `model` / `small_fast_model` are used by InvokeModel but ignored by mantle (the client sends the model), and `base_url` is required for mantle but optional for InvokeModel. Validation is protocol-aware. - No central model control on mantle: because it is a passthrough, the operator cannot pin the model. - `region` and the `base_url` host must name the same region (the SigV4 scope must match the endpoint); a mismatch surfaces as `Credential should be scoped to a valid region`. ## Draft UI <img width="1100" height="579" alt="image" src="https://github.com/user-attachments/assets/37bab46d-8958-4a96-9f47-1fef3493e1b6" /> ## Follow-up PRs: - https://github.com/coder/coder/pull/27156 |
||
|
|
043d367cfe |
fix(site): show AI settings and AI Sessions in mobile admin menu (#27191)
## Problem The desktop `DeploymentDropdown` surfaces **AI** and **AI sessions** items under Admin settings (behind `canViewAISettings` / `canViewAIBridge`), but the mobile `MobileMenu` was never updated to match — its `AdminSettingsSub` only knows about Deployment, Organizations, Audit logs, Connection logs, and Healthcheck. This is a leftover from #25582 ("promote AI settings to a top-level section"), which threaded `canViewAISettings` through `Navbar` / `NavbarView` / `DeploymentDropdown` but did not touch `MobileMenu.tsx`. `canViewAIBridge` has the same oversight. ## Fix - Extend `MobileMenuPermissions` with `canViewAIBridge` and `canViewAISettings`. - Render **AI** (→ `/ai/settings`) and **AI Sessions** (→ `/ai-gateway/sessions`) in the mobile Admin settings collapsible, in the same order as the desktop dropdown. - Thread the two flags through `NavbarView` into `MobileMenu`. - Cover the new args in `MobileMenu.stories.tsx` (Admin story now shows the AI items; Auditor / OrgAdmin / Member keep them hidden). No backend, permission, or routing changes. > 🤖 This PR was drafted by Coder Agents on behalf of @tracyjohnsonux and needs a human review. |
||
|
|
5334cc80b6 |
fix(site): pass all properties of a multi-select dynamic parameter option to MultiSelectCombobox defaultOptions (#27145)
fixes DEVEX-463 Previously, a dynamic parameter of `form_type = "multi-select"` with default options selected would only pass in these 3 properties for each option fed into `MultiSelectCombobox`'s `defaultOptions`: - `value` - `label` - `disable` `defaultOptions` are used as the initial value of `MultiSelectCombobox`'s `selected` array of `Option`s. If the `icon` property is missing from a selected option, then no icon is shown: https://github.com/coder/coder/blob/e59a67d63fd522d1e95b42e57d4fbfe7d2bc5fef/site/src/components/MultiSelectCombobox/MultiSelectCombobox.tsx#L501-L502 Now `icon` and `description` are included among those properties passed to default selected options, when a default option's value can be found among the parameter's available options in the Terraform template. This fixes the bug where icons wouldn't display for default selected options. If no corresponding option is found, then we fall back to the old partial option object (`{ value, label, disable }`). <img width="1840" height="1191" alt="Screenshot 2026-07-09 at 10 08 54 PM" src="https://github.com/user-attachments/assets/91be4aaf-9016-46d6-871b-344c8f2504cb" /> |
||
|
|
15fd7b746a |
fix: use fake timers in edit workspace test (#27141)
Fixes an issue where the debounce delay plus edit delay exceeds the wait timeout. Also remove the mocked rich parameters call; it is not used. |
||
|
|
6f6d7539c8 |
feat: remove unused chat statuses pending, paused, and completed (#27064)
The chatd state machine only recognizes `waiting`, `running`, `error`, `requires_action`, and `interrupting`. Remove the unused `pending`, `paused`, and `completed` values from the database enum, backend, SDK, frontend, generated queries, and API docs. Migration `000543_chat_status_remove_unused` remaps existing `pending` rows to `running`, remaps `paused` and `completed` rows to `waiting`, drops the obsolete `idx_chats_pending` index, and recreates `chats_expanded` around the enum swap. It also removes the dead `AcquireChats` query and all remaining query literals for the deleted statuses. **NOTE**: The enum swap can break chat queries from older replicas during a mixed-version rollout because they still reference `'pending'::chat_status`. Chats are experimental, so this PR accepts that limited rollout window instead of adding a two-release expand and contract sequence. > This PR was authored by Mux (AI agent) on Mike's behalf. |
||
|
|
e0b57f3154 |
chore: remove mui from <IconsPage /> (#27201)
This pull-request removes the MUI specific components from `<IconPage />`. |
||
|
|
aee528e044 |
fix: remove @emotion/react from <LastSeen /> (#27199)
This removes the manual `@emotion/react` we had from the theme being
injected in `<LastSeen />`. This now is relying on Tailwind 🙂
|
||
|
|
ad29777cb2 | feat: NATS mTLS pubsub implementation (#26902) | ||
|
|
010d96c3cd |
chore: remove useTheme from <OAuth2AppsSettingsPageView /> (#27198)
This wasn't used, removing 🙂
|
||
|
|
d5e5b10ff1 |
feat(site): polish AI budget members table (#26805)
Finishing touches for the AI cost control group members table.
- Spend stays primary-colored until near the budget limit, via a new
AIBudgetAmount component
- "AI budget period" label shows the current spend window in local
time, next to the members tab
- Budget tooltip notes the reset date and the group's default limit
- "Budget type" renamed to "Budget group", with a badge for the
governing group or override
- Distinguishes $0 budget ("None") from no budget ("Unlimited")
- Unattributed spend from another group shows a note instead of a dash
- "Manage AI budget" disabled only when another named group governs
- Replaces UserAISpend with generated UserAISpendStatus, fixing
limit_source
Closes #26401
|