mirror of
https://github.com/coder/coder.git
synced 2026-10-16 14:48:56 +08:00
47345bfc4ee8f4546da0968abe4f9ca1a424f517
16718
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
47345bfc4e | fix: adapt agent docs, skills, and Coder Agents prompts for Claude Opus 5.5 (#29817) | ||
|
|
b55f721f24 |
fix: apply user-supplied AWS Bedrock API keys instead of dropping them (#28724)
## Bug
Under `/agents/settings/api-keys`, a personal API key saved for a
Bedrock provider never took effect. AI Gateway forwarded the saved
value, but the Bedrock interceptors re-signed every request with the
deployment's AWS credentials (SigV4), overwriting the `Authorization`
header. The key was silently dropped, so users were unknowingly still
billed to the administrator's AWS account with no way to bring their own
credentials.
## Fix
Apply the user's Bedrock key instead of discarding it. AWS Bedrock API
keys are bearer tokens (`Authorization: Bearer <key>`), so when a
personal key is present AI Gateway now sends it as a bearer token and
skips SigV4 signing. This covers every Bedrock route:
- **InvokeModel** (`/v1/messages`): applies the same wire transform as
the signed path (`/model/{model}/invoke[-with-response-stream]`,
`anthropic_version`, `anthropic-beta` → body, `model`/`stream`
stripping) but sets a bearer `Authorization` header instead of signing.
- **Mantle** (`/v1/messages`, `/v1/responses`, `/v1/chat/completions`):
passthrough with a bearer `Authorization` header instead of signing.
The bearer paths resolve no deployment AWS credentials, so BYOK works
even where the deployment has none. Requests without a personal key keep
the existing SigV4 behavior.
This also reverts the earlier interim guard that hid the key field and
rejected Bedrock key upserts: the field is shown again and the API
accepts the keys, because they now work.
<details>
<summary>Implementation notes</summary>
**Gateway (`aibridge`)**
- `messages.newMessagesService` detects BYOK on a Bedrock interception
and routes it through bearer-token option builders instead of the SigV4
path.
- `withBedrockInvokeModelBYOKOptions` /
`bedrockInvokeModelBearerMiddleware` reimplement the Anthropic SDK's
`bedrock.WithConfig` wire transform without signing, because that helper
couples the transform with SigV4 and would resolve deployment
credentials a BYOK request must not depend on.
- `bedrocksig.BearerMiddleware` is shared by the Messages, Responses,
and chat-completions interceptors for the Mantle passthrough; each
installs it in place of `SignMiddleware` when the credential is BYOK.
- Streaming decoding is unchanged: the Bedrock event-stream decoder is
registered by the SDK package's `init` and selected by response
content-type, independent of `bedrock.WithConfig`.
**coderd / SDK / frontend / docs**
- Removed the interim guard and `supports_user_api_key` capability flag;
restored the API-key field for Bedrock providers.
- Docs describe the Bedrock personal key as an AWS Bedrock API key
forwarded as a bearer token for every model family Bedrock serves.
**Tests**
- Unit: bearer middleware transform + auth for InvokeModel; shared
bearer middleware; option-builder validation.
- Integration: end-to-end through the bridge for InvokeModel, Mantle
Messages, Mantle Responses, and Mantle chat completions, asserting
`Authorization: Bearer <key>`, no `X-Amz-*` headers, correct upstream
path/model, no `X-Api-Key` leak, and that InvokeModel streaming decodes
real AWS binary event-stream frames.
- coderd: Bedrock key upserts succeed.
</details>
Closes
[CODAGT-699](https://linear.app/codercom/issue/CODAGT-699/bedrock-provider-settings-for-byok-only-expose-one-api-key).
---
*This PR was generated by Coder Agents on behalf of @f0ssel.*
|
||
|
|
99c42af5fc |
fix(site/src): stop delete dialog keys and clicks from activating rows (#29868)
Fixes [DASH-106](https://linear.app/codercom/issue/DASH-106/show-validation-error-for-incorrect-workspace-deletion-confirmation). In the workspaces list, pressing Enter or Space in the delete confirmation input took you to the workspace page. Nothing was deleted and there was no explanation. Review turned up related problems in the same dialog, which this PR also fixes. **Root cause:** React sends events from portaled content (dialogs, menus) up through the component tree to parent components. The delete dialog is rendered inside a clickable workspace row. The row reacted to Enter and Space from the dialog's input as if the row itself had been activated, and it did the same for middle clicks. The actions cell already stopped normal clicks from reaching the row, but not key events or middle clicks. **Changes** - `useClickable` / `useClickableTableRow`: - Enter and Space only activate the row when the row itself has focus. - Clicks, middle-clicks, and double-clicks from portaled content are ignored (`isFromPortal`). A middle-click paste (Linux) into the dialog no longer opens the workspace in a new tab. - A nested native button still sends its own click to the row unless it stops click propagation, as the existing row buttons already do. - New `DeleteConfirmationField` + `useDeleteConfirmation`, shared by `WorkspaceDeleteDialog` and `DeleteDialog`. They previously duplicated this logic. The shared field provides: - Enter with a wrong name shows the error immediately, instead of only after the input loses focus. Screen readers announce it (`role="alert"`). - The typed text is quoted and keeps its whitespace, so a stray space is visible. - `WorkspaceDeleteDialog` clears the typed name, "Orphan Resources", and the error whenever the dialog closes, including after confirm (the parent closes it then). Before, typing the correct name, cancelling, and reopening showed an enabled Delete button, so one click deleted the workspace without retyping. - `DeleteDialog` (shared) clears the typed name whenever its dialog closes, including when the parent closes it, as the organization page does after a failed delete. Before, reopening showed Delete already enabled. Callers that keep the dialog open after a failed delete (templates, users) still keep the typed name so the user can retry. - `WorkspaceOutdatedTooltip`, `ProviderRow`, `ModelRow`: removed key handlers that only worked around the old row behavior, and corrected their comments. **Decisions** - The mismatch error appears below the input without a reserved slot, so the controls below move down when it shows (unchanged from `main`, by design decision). - Enter with an empty input stays silent on purpose. It doesn't confirm or navigate, and the disabled Delete button signals that a name is needed. - Workspace names can't contain spaces, so a typed space leads to the mismatch error. The input doesn't block spaces. **Verification** - Unit tests: - Enter and Space from inline and portaled inputs don't activate a clickable element. - Clicks and middle-clicks from portaled content don't activate the row. - Enter with a wrong name marks the input invalid and announces the error. Editing the name clears it. - A matching name confirms on Enter. - The workspace dialog reopens empty after cancel and after confirm. The shared dialog reopens empty after its parent closes it, and keeps the typed name while it stays open for a retry. - Each new test fails when the code it covers is removed. - Stories: new `FilledWrongSubmitted` (error shown while focused). - Related unit tests and stories pass for every clickable table page and every `DeleteDialog` caller (workspaces, templates, organizations, users, Agents). - Tested by hand by @tracyjohnsonux before the reset, shared-field, and click-guard changes. --- _Generated by Coder Agents on behalf of @tracyjohnsonux._ |
||
|
|
282365b23a | feat: report clicks on the workspace build debug action to telemetry (#29853) | ||
|
|
6f0c4474ee |
feat(site/src): show agent startup logs in start and create tools (#29550)
feat(site/src): show agent startup logs in start and create tools (#29550) start_workspace and create_workspace wait for agent startup after the build, but the row only showed the finished build log. Show the agent startup log below it, using the same Logs components as the build log. Closes CODAGT-166 |
||
|
|
23cf5fcbe7 | ci: remove one-off helm index repair workflow (#29926) | ||
|
|
aa87166c2f | docs: fix step order and values.yaml in Azure App Gateway guide (#29927) | ||
|
|
4b3c2b3ca3 |
docs: remove the User spend page from AI Gateway docs (#29844)
## Description Remove the **User spend** page from the AI Gateway and spend management docs, since the page is hidden from the sidebar and marked experimental for this release. The removed content is commented out with a TODO so it can be restored once the page leaves experimental. Related to [internal Slack thread](https://codercom.slack.com/archives/C04M9CNGHGF/p1790190171687059?thread_ts=1790190121.005749&cid=C04M9CNGHGF). ## Changes - Comment out the **User spend** page in the dashboard visibility table and spend details lists in `cost-controls.md` and `spend-management.md`. > [!NOTE] > Generated by Coder Agents on behalf of @ssncferreira. |
||
|
|
fb8b6dc2fb |
feat: hide the User spend page from the AI settings sidebar (#29843)
## Description Hide the **User spend** page from the AI settings sidebar for this release and mark the page as experimental. The page stays reachable at `/ai/settings/spend`, so nothing else about it is removed. Related to [internal Slack thread](https://codercom.slack.com/archives/C04M9CNGHGF/p1790190171687059?thread_ts=1790190121.005749&cid=C04M9CNGHGF). Screenshot <img width="1186" height="613" alt="Screenshot 2026-09-25 at 13 44 50" src="https://github.com/user-attachments/assets/820058d5-1b88-4fe7-8c95-01b1fe2211cb" /> ## Changes - Remove the sidebar nav item and the spend access lookup that only fed it. - Add an `Experimental` badge next to the page title and a warning alert explaining that reports may load slowly and the page may change or be removed. Docs for the **User spend** page are updated upstack in #29844. > [!NOTE] > Generated by Coder Agents on behalf of @ssncferreira. |
||
|
|
46ccaf3764 |
chore: mark organization AI spend users endpoint as experimental (#29842)
## Description
Move `GET /organizations/{organization}/ai/spend/users` under
`/api/experimental` so the per-user spend report is not part of the
stable API for this release. The endpoint behavior is unchanged.
Related to [internal Slack
thread](https://codercom.slack.com/archives/C04M9CNGHGF/p1790190171687059?thread_ts=1790190121.005749&cid=C04M9CNGHGF).
## Changes
- Register the route on the experimental handler and mark it
`@x-apidocgen {"skip": true}`, which removes it from the generated API
reference.
- Move the Go SDK method to `ExperimentalClient` and the frontend method
to `API.experimental`.
- Drop the docs link to the removed API reference section. The link is
commented out with a TODO so it can be restored later.
User-facing docs for the **User spend** page are updated upstack in
#29844.
> [!NOTE]
> Generated by Coder Agents on behalf of @ssncferreira.
|
||
|
|
9afdea4808 |
docs(docs): document RPM install on RHEL-family Linux (#29295)
## Summary Coder ships `.rpm` assets with every release and `install.sh` routes the RHEL family to `install_rpm()`, but no public page said so. The only page that named RHEL was the uninstall page. This adds an RPM install page for the control plane. New page `docs/install/server/rpm.md`: - Supported distribution matrix for RHEL 8/9/10, Rocky, AlmaLinux, CentOS Stream, Amazon Linux, Fedora, and openSUSE, with the `ID`/`ID_LIKE` detection that makes derivatives work. - Install tabs for the install script, `dnf install`, and `rpm -U`. - What the package lays down: `/usr/bin/coder`, `/etc/coder.d/coder.env`, `coder.service`, `coder-workspace-proxy.service`, and the unprivileged `coder` user. - Configure-then-start ordering, because `coder.service` carries `ConditionFileNotEmpty=/etc/coder.d/coder.env` and won't start against an empty config. - SELinux caveat for Docker/Podman inside workspaces on RHEL nodes, linking the existing guidance instead of duplicating it. - Iron Bank UBI9-minimal pointer for hardened environments, scoped correctly as a container image rather than an RPM path. Supporting edits: manifest entry under "3. Install the control plane" between OpenShift and Cloud Providers, a row in the platform table on `install/server/index.md`, and a pointer from `install/cli.md`. ## Placement The page sits at `docs/install/server/rpm.md`, as a sibling of Docker, Kubernetes, Rancher, and OpenShift, rather than under community install methods: RPMs are officially built and shipped, not an unofficial method. It is a control-plane deployment page, not CLI download content, so it is out of scope for the CLI-retirement work. ## Verification Claims on the page were checked against real RHEL-family images, not just the install script: | Check | Method | Result | |-------|--------|--------| | `ID` and `ID_LIKE` per distribution | `docker run <image> sh -c '. /etc/os-release; ...'` across UBI 8/9/10, Rocky 9, Alma 9/10, CentOS Stream 9/10, Amazon Linux 2/2023, Fedora, openSUSE Leap and Tumbleweed | Every RHEL-family image lists `fedora` in `ID_LIKE`; both openSUSE variants list `opensuse`. Matches the `distro()` branch in `install.sh` | | `dnf install ./coder_*.rpm` | Rocky Linux 9 container | Installs cleanly | | Package contents | `rpm -ql coder` | `/usr/bin/coder`, `/etc/coder.d/coder.env`, `coder.service`, `coder-workspace-proxy.service` | | Service account and start condition | Installed unit file | Runs as `coder:coder`; `ConditionFileNotEmpty=/etc/coder.d/coder.env` | | Architectures | `.github/workflows/release.yaml` | `amd64`, `armv7`, `arm64` | Not verified: `systemctl enable --now coder` against a live database, since the containers used for verification have no init system. The `systemctl is-active` output on the page is standard systemd output, flagged here for the reviewer. Lint: `make lint/markdown`, `make lint/emdash`, and `make lint/prose` all clean on the changed files; `pnpm run format-docs` applied. <details> <summary>Implementation plan and decision log</summary> ### Style guide application The first revision of this page was drafted from sibling install pages rather than from the style guide, and was rewritten against [`docs/.style/content-guidelines.md`](https://github.com/coder/coder/blob/main/docs/.style/content-guidelines.md) and the prose style guide. What changed: one sentence per source line, declared audience and outcome in the opening paragraph, numbered procedures with one instruction per step and conditions stated first, `refer to` instead of `see`, `sh` fences instead of `shell`, H3 tab headings, non-breaking space between number and unit, and `Learn more` instead of `Next steps`. ### Decisions - **No version numbers or FIPS certification claims for Iron Bank.** The tags in `scripts/ironbank/hardening_manifest.yaml` are stale (`0.15.3`); documenting them would re-create the drift. The page links the registry and names the UBI9-minimal base only. - **Iron Bank framed as a container path.** It is a container image, so the page routes readers to Kubernetes/OpenShift rather than implying it is an alternative to the RPM. - **Dropped an unverified SELinux claim.** An earlier draft asserted that the control plane runs under enforcing mode with no policy changes. That was not tested, so it is gone. The section now covers only the workspace container-runtime case, which links to existing verified guidance. - **`ID_LIKE` values kept out of the table.** They vary by version (RHEL 8/9 report `fedora`, RHEL 10 reports `centos fedora`), so the table lists `ID` and the prose states the invariant the install script actually matches on. - **Minimal edit to `install/cli.md`.** That file is slated for deletion in the Install restructure, so it gets a pointer and nothing more. ### Rebase onto the install spine restructure The install spine restructure landed on `main` while this PR was open and removed the install-method tabs on `install/index.md` that the first revision pointed from. The branch was rebased and squashed onto it: the page moved from `docs/install/rpm.md` to `docs/install/server/rpm.md`, every relative link was repointed at the new locations (`../plan/sizing/index.md`, `../prepare/airgap.md`, `../operate/upgrade.md`, `../operate/uninstall.md`, `./kubernetes/index.md`), the install script snippet picked up the standardized `curl -fsSL` flags, and discovery moved from the removed `install/index.md` tabs to the platform table on `install/server/index.md`. The prose is otherwise unchanged. ### Follow-ups tracked elsewhere The install spine has no other bare-host or Linux-package option under platforms; every other entry is a container platform or a cloud VM. Open question recorded on the IA proposal: whether this generalizes to a single "Linux host (system packages)" page covering `.deb` and `.apk` too. </details> --- Linear: [DOCS-886](https://linear.app/codercom/issue/DOCS-886/document-support-for-running-coder-on-red-hat-linux) 🤖 Generated with Coder Agents on behalf of @nickvigilante. |
||
|
|
702b13112d | feat: add Debug with Coder Agents action for failed workspace builds (#29811) | ||
|
|
b3e073b7c2 |
test(coderd/x/chatd): strengthen synthetic key lifecycle coverage (#29885)
Strengthen coverage of existing synthetic Gateway key behavior: check reuse and renewal on both sides of the renewal margin, preserve key identity and unrelated fields during renewal, synchronize concurrent mint callers before they contend for the existing lock, and verify colliding user-created tokens remain untouched. Uses a mock clock and joins workers on failure. No production changes or dependency on model authorization. Independent extraction from #29846. Verified locally: `make pre-commit` and five focused synthetic-key race-test runs passed against unchanged production code. The combined extraction branch also passed the complete Chatd suite. Extracted and verified with AI assistance on behalf of @johnstcn. |
||
|
|
150d366259 | docs: add branch-naming rule to prevent issue-tracker auto-link collisions (#28574) | ||
|
|
5e12a74f38 | fix: run the test recipe under MAKE_TIMED instead of skipping it (#29849) | ||
|
|
f64ccfb836 |
feat: add experimental inline MCP servers (#29546)
Closes CODAGT-1131 Fifth PR in the inline MCP servers stack, on top of #29520. A chat owner can now declare MCP servers by URL and headers on their own chat, and chatd connects to them every turn alongside the org-configured ones. They go in a new `inline_mcp_servers` field on `POST /api/v2/chats` and `POST /api/v2/chats/{chat}/messages`, which replaces the whole set (omit to keep, `[]` to remove). Root chats only. `GET /api/v2/chats/{chat}` returns them, with the URL blanked for non-owners and header values never returned. Subagents only get servers marked `allow_in_subagents`, a root chat in explore mode gets none, and a root chat in plan mode gets all of them. URLs must be `https`, or `http` to an IP literal in `CODER_MCP_ALLOWED_PRIVATE_CIDRS`. Header values have no minimum length, so anything under the redactor's 8 byte floor from #29518 is accepted but not redacted, which the docs call out. Every cap is exported from `codersdk`. It's behind the `chat-inline-mcp-servers` experiment, and the `--disable-chat-caller-supplied-tools` kill switch from #29466 covers it too. With either off, declaring servers gets a 403 and existing chats stop connecting to theirs, but `[]` still works so a client can detach. Load failures show up in the chat debug panel as failed connections, as do org servers with an invalid config. Docs are hand-written in `mcp-servers.md`. |
||
|
|
1c974608b1 |
feat: rotate, decrypt, and delete encrypted chat_mcp_servers headers (#29520)
Relates to #25381 `chat_mcp_servers.headers_key_id` has a foreign key to `dbcrypt_keys(active_key_digest)`, but `dbcrypt rotate`, `decrypt` and `delete` didn't know about the table. `rotate` finishes by revoking every old key, so an encrypted header row would fail that revoke with an FK violation, which is the same class of bug as #25381. This PR adds `chat_mcp_servers` to all three commands. `rotate` re-encrypts under the new key (and encrypts plaintext rows with no key ID, like `gitsshkeys`), `decrypt` writes the plaintext back and clears the key ID, and `delete` removes the encrypted rows outright, like `user_secrets`, since a server without its headers can't authenticate anyway. Rows with `{}` headers are never encrypted, so they're left alone. The org-level `mcp_server_configs` gap is still tracked at #25381. I've stacked this on the `mcpclient` PR, though it only depends on the `chat_mcp_servers` table PR, as `gh stack` is linear. Part of CODAGT-1131 |
||
|
|
016df8cbab |
feat(coderd/x/chatd/mcpclient): add hardened connect path for inline MCP servers (#29518)
Third PR in the inline MCP servers stack, on top of https://github.com/coder/coder/pull/29517. This adds the `mcpclient` side that chatd will use to talk to servers a chat owner declared by value on the chat. Nothing in chatd calls the new functions yet. `mcpclient` now owns its input type. `ConnectAll` and the new `ConnectInline` both take `[]mcpclient.Server`, and `ServerFromConfig` converts an org-configured row at the boundary, so a caller never has to fake a `database.MCPServerConfig` for a server that has no row. The org path behaves as before with two exceptions: `connectAllWithHooks` no longer skips disabled servers (the call site in `generation_preparer.go` filters them), and a `custom_headers` row with malformed JSON or an unknown auth type used to connect without those headers, whereas now conversion fails and the caller skips the server with a warning. Org-configured servers were set up by an admin, so we don't put many limits on them. Inline ones are supplied by whoever created the chat, so `ConnectInline` treats the server as untrusted. HTTP response bodies are capped at 1 MiB, a server can expose at most 64 tools with each definition under 64 KiB and 256 KiB in total, and tool results are capped at 256 KiB. If a server blows the tool caps we skip the whole server rather than hand the model a partial tool set, and an oversized result comes back to the model as a tool error rather than being truncated silently. Everything the server sends that we log or hand to the model (tool names, descriptions, schemas, results, connect errors) has the values in `Server.SensitiveValues` replaced with `[REDACTED]`; chatd sets that to the URL and header values. Header names aren't redacted, as they're public and short enough that redacting them would rewrite ordinary text. For the same reason the redactor ignores anything shorter than `MinSensitiveValueBytes` (8), and #29546 rejects header values that short at the API. The slug is caller-supplied too, so it also goes through the redactor wherever it lands in a tool name, connect summary or log field. `AppendInline` merges the resulting tools into an existing tool list with the existing names winning, so an inline server can't shadow a builtin or org-configured tool. Collisions are logged once per server with the `config_id`. Lastly, every `tools/call` (for both kinds of server) now carries the model's tool call ID in `_meta` under `com.coder/tool_call_id`. It's a correlation ID that's stable across chatd retries of the same call, so a server can use it to dedupe if it wants to. We make no other idempotency promise. Part of CODAGT-1131 |
||
|
|
acebdf5b60 |
feat: add chat_mcp_servers table with encrypted headers (#29517)
This is the second PR in the stack that adds experimental support for attaching MCP servers to a chat; https://github.com/coder/coder/pull/29466 is the first. This one is just the persistence layer, nothing reads from the table yet. It adds a `chat_mcp_servers` table, unique on `(chat_id, slug)` and cascading on chat deletion. Each row stores the server URL, a JSON object of request headers, per-server tool allow and deny lists, and three flags that later PRs in the stack use to decide when the server gets connected: `allow_in_plan_mode` (mirroring the existing column on `mcp_server_configs`), `allow_in_subagents`, and `forward_coder_headers`. All three default to `false`. Headers are the sensitive part, so they're encrypted at rest via `dbcrypt` in the same way `external_auth_links` are: `headers_key_id` records which key was used, and `NULL` means plaintext. Empty or `{}` headers are stored as `{}` with no key, so servers that don't need auth never produce ciphertext. The `dbcrypt` wrappers cover the chat-scoped reads and writes, plus `GetChatMCPServersByChatOwnerID` and `UpdateEncryptedChatMCPServerHeaders`, which follow the per-user shape that `Rotate` and `Decrypt` in `cliutil.go` use. I haven't wired those two into `coder server dbcrypt rotate` and `decrypt` in this PR. For authz, reading a chat's servers requires read on the chat, and upserting or deleting them requires update on the chat. The two owner-scoped queries above are system-only. Part of CODAGT-1131 |
||
|
|
c1af0793e5 |
feat: add caller-supplied tools kill switch for chats (#29466)
This is the first PR in a stack that adds experimental support for attaching MCP servers to a chat when it's created, and then deprecates `unsafe_dynamic_tools` in favour of them. Both are "caller-supplied tools", i.e. tools the client hands to coderd at chat creation rather than tools an admin has configured, so we want a single switch admins can use to turn all of them off. This PR adds that switch: `--disable-chat-caller-supplied-tools` (`CODER_DISABLE_CHAT_CALLER_SUPPLIED_TOOLS`). It follows the existing `disable-*` deployment flag pattern (`--disable-chat-sharing` etc.), so there's no new API route and it's independent of any experiment. When set, `POST /api/v2/chats` returns a `403` if the request includes `unsafe_dynamic_tools`, and chats that already have dynamic tools run without them; a call to one gets a tool error result and the model just continues. Later in the stack, chat-attached MCP servers are gated behind the same flag. It's unset by default, so nothing changes unless you opt in. Part of CODAGT-1131 |
||
|
|
9700db5b53 |
chore: update low-risk dependencies (#29860)
## Summary Updates pinned dependency overrides across three independent pnpm installs: | File | Package | From | To | |------|---------|------|----| | `package.json` (root) | brace-expansion | 1.1.16 | 1.1.18 | | `offlinedocs/package.json` | brace-expansion | 1.1.16 | 1.1.18 | | `scripts/apidocgen/package.json` | form-data | 4.0.4 | 4.0.6 | All pinned via `pnpm.overrides`; each `pnpm-lock.yaml` is regenerated to match. There is no `pnpm-workspace.yaml`, so root, `offlinedocs/`, and `scripts/apidocgen/` are separate installs and each bump is isolated to its own tooling. ## Testing Run locally per install: **Root** - `pnpm install` — resolves/locks `brace-expansion@1.1.18`; no stale references - `pnpm run check-docs` (markdownlint + table formatter, uses js-yaml) — 505 files, 0 errors - `quicktype` JSON→TS + `biome --version` — pass **offlinedocs** - `pnpm install` — resolves/locks `brace-expansion@1.1.18`; no stale references - `pnpm run lint:types` / `format:check` / `build` — pass, 453 pages built **scripts/apidocgen** - `pnpm install` — resolves/locks `form-data@4.0.6`; no stale references - `widdershins --version` + full render of `coderd/apidoc/swagger.json` (exercises form-data) — rendered successfully No behavioral changes; dependency version bumps only. |
||
|
|
2de1f8b111 |
feat: link promoted chat messages to their queue entry (#29859)
Signed-off-by: Thomas Kosiewski <tk@coder.com> |
||
|
|
b0b472de9e | feat(codersdk/toolsdk): add owner_id to the coder_create_chat MCP tool (#29704) | ||
|
|
7c74fa3548 |
feat: add workspace file upload agent API (#27078)
## What Adds a dedicated workspace-agent endpoint, `POST /api/v0/upload-chat-file`, that streams a request body into the chat's upload directory `~/.coder/chats/<chat-id>/files/<name>`, plus the SDK plumbing to call it: - `coderd/x/chatfiles`: upload-name sanitization (`SanitizeWorkspaceUploadName`), collision suffixes (compound extensions such as `.tar.gz` stay intact: `archive_2.tar.gz`), and the shared `~/.coder/chats/<id>/files` path layout. - `agent/agentfiles`: the HTTP handler. On Linux/macOS the directory chain is opened with `openat(O_NOFOLLOW)`, so symlinked path components are rejected. The body streams into a hidden `.<name>.upload-<random>` temp file and is published under its final name only when complete, via `linkat` over the `_2`, `_3`, ... collision sequence, so existing files are never overwritten and a half-written file is never visible under its final name. Filesystems without hard links fall back to an exclusive placeholder plus `renameat`. Other platforms use an afero-based fallback with the same semantics. Stale temp files older than an hour are swept before each upload, and failures are logged with a structured warning. - `codersdk/workspacesdk`: `AgentConn.UploadChatFile` + regenerated `agentconnmock`. ## Why Coder Agents chat can attach images/text/PDF to prompts, but arbitrary files (zips, datasets, binaries) have nowhere to land where the agent's tools can act on them. This is the agent-side foundation; the coderd route that fronts it is stacked on top. Design notes: - There is deliberately no size cap; the resource profile matches existing SSH/WebSocket proxying, and client cancellation aborts the stream (a failed write removes the temp file, so no partial files remain). Because the agent HTTP server uses fixed 20 s read/write timeouts, the handler pushes both deadlines forward on every received chunk, so a slow upload only fails after a 20 s stall. If the connection does not support deadline changes, the agent logs one warning per request. - This endpoint is not gated by `CODER_AGENT_BLOCK_FILE_TRANSFER`. That flag targets SSH-transport file tools (scp/rsync/sftp). Chat uploads are an agent API capability like `write-file` and `edit-files`, which already bypass the flag; the interaction is documented in the FAQ. ## How tested - `go test ./agent/agentfiles ./coderd/x/chatfiles ./codersdk/workspacesdk` (unit + umask/symlink/collision integration tests). - UAT on a dogfood-style deployment (2026-09-21): uploads longer than 20 s went from 502 to 201 once the workspace agent was restarted on this build; a coderd restart alone keeps the old agent running, so the per-chunk deadline extension needs the agent rolled (older agents get the 409 "Restart the workspace" from #27079). Part of CODAGT-211. Stack: agent API (this PR) -> coderd endpoint -> UI. > This PR was authored by Mux (AI) working on Mike's behalf. |
||
|
|
6094c03a90 | docs(coderd/x/chatd): remove compaction TODOs from ARCHITECTURE.md (#29870) | ||
|
|
37295547b8 | feat: add default model picker to Coder Agents settings (#29470) | ||
|
|
5393f9d5f4 |
feat: stream advisor reasoning in tool cards (#29742)
Show the advisor’s live reasoning under **Thinking**, separately from **Advice**, in one tool card with the original question and title. Keep nested reasoning out of the parent assistant’s reasoning and saved chat history. Clear both live channels on retry and remove transient reasoning when the call finishes. Cover streaming, retry, error, and interrupted-output behavior with regression tests, and regenerate the SDK and API schemas. This also changes a shared seam for every tool, not only the advisor: live output for a tool call that is already saved now completes that call's card, and the separate live-row card for it is removed. Remote UAT passed on `a39bbe4c21`: deterministic provider tests covered streamed reasoning, retry, errors, and refresh; a real-provider run confirmed advice streaming and card association. The real model did not emit reasoning. The intermittent, unattributed React console warning is tracked in #29741. <details> <summary>Remote UAT evidence (deterministic provider)</summary>  Streaming, completion, and refresh: https://github.com/user-attachments/assets/dd1f3a24-a365-40c8-a1d9-b78cd17ef4c5 </details> --- <details> <summary>📋 Implementation Plan</summary> # Plan: Stream advisor reasoning in Coder Agents ## Goal and delivery boundary Show nested advisor reasoning as live **Thinking** in its advisor tool card. Keep it separate from live **Advice**, normal parent-assistant reasoning, and the final persisted advisor result. Deliver one focused PR: optional SDK field, nested publisher, transient frontend state, existing card rendering, generated API artifacts, and regression tests. Do not add provider features, persistence, new stream event types, UI redesigns, or unrelated cleanup. The implementation already exists and has been reconciled with current main. The implement-flow implementation phase is an acceptance audit, not a rewrite. Preserve correct behavior and current architecture. Change only demonstrated gaps. A no-op implementation result is valid; do not manufacture an empty commit. ## Current integration points 1. `codersdk/chats.go`: add optional `ReasoningDelta string` with `json:"reasoning_delta,omitempty" variants:"tool-result?"`. Preserve it in `StripInternal` alongside other live fields. Register the same NUL-encoding policy as `ResultDelta` in `chatprompt` so the SDK field coverage and round-trip tests remain complete. Regenerate SDK types and API documentation with `make gen`. 2. `coderd/x/chatd/chatadvisor/runner.go`: route assistant text and reasoning through separate optional callbacks on `RunAdvisorOptions`. Install the publisher if either callback exists. Preserve empty-delta and role guards. Use current `GenerateAssistant` and `chatretry.Retry`. Rename the reset callback to `OnLiveOutputReset` because it clears advice and reasoning. Keep `extractAdvisorText` text-only and existing budget/refund behavior. 3. `coderd/x/chatd/chatadvisor/tool.go`: use the current context-injected `MessagePartPublisherFromContext`; do not reintroduce the old ToolOptions publishing callbacks or chatd.go wiring. Preserve the missing-publisher error and the nonempty tool-call-ID guard. Publish reasoning as role `tool`, part type `tool-result`, tool name `advisor`, matching `tool_call_id`, and `reasoning_delta`. Use existing `result_reset` to reset both live channels on retry. 4. `site/src/pages/AgentsPage/components/ChatConversation/streamState.ts` and `types.ts`: retain a single transient reasoning string. Append deltas exactly as plain text, never JSON-parse or trim them during accumulation. Reasoning makes the tool streaming. An empty `result_delta` must not swallow a nonempty `reasoning_delta`. Reset removes the entry. A final result or `is_error` clears reasoning and streaming state. Pass reasoning through `buildStreamTools` into `MergedTool`. 5. `MessageBlocks.tsx` and `ChatElements/tools/Tool.tsx`: forward reasoning at both current Tool instantiation paths and through AdvisorRenderer. Do not restore the old ConversationTimeline rendering implementation. 6. `AdvisorTool.tsx`: use current `ToolCall.Root`, `ScrollArea`, `Response`, and semantic theme tokens. Display Thinking only when running and trimmed reasoning is nonempty. Display live advice separately when present. Keep completed advice, empty/loading, limit, and error behavior unchanged. Reasoning-only running cards must not show the empty-advice fallback. Do not restore removed MUI dependencies. 7. `messageParsing.ts`, `streamState.ts`, and `ChatPageContent.tsx`: associate live tool results with matching durable tool calls. Preserve the invocation's question, intent, and metadata. A durable final result remains authoritative, including explicit null results. Remove only the overlaid result and its block from the separate live row; keep unrelated results and live call/result pairs unchanged. This closes the durable-call/live-result split found during integration testing. ## Acceptance criteria 1. Nested reasoning reaches the dedicated runner callback and the client as tool-scoped live output for the same advisor call as advice. 2. Advisor reasoning is not parent assistant reasoning, final advice, input to the parent's continuation, or persisted chat history. 3. Retry clears stale reasoning and advice before fresh output. Final success and bare error clear transient reasoning. 4. Raw whitespace and JSON-looking reasoning survive concatenation unchanged. Empty advice deltas do not hide reasoning. 5. Reasoning-only and reasoning-plus-advice states render in exactly one existing advisor card per invocation, retaining its question and intent title when the call is already durable. Completed cards never display transient thinking, even if handed a stale prop. Other tool and normal assistant reasoning behavior is unchanged. 6. Generated artifacts match source. Final candidate passes relevant Go tests, frontend tests, stories, typecheck, lint, and pre-commit checks, or has explicit verified blockers. Old evidence is not final-candidate evidence. ## Phases and quality gates 1. Reconcile existing work onto current main while retaining a recovery snapshot. Remove obsolete workarounds, not current upstream behavior. Gate: no conflicts, focused diff, preserved original work. 2. Audit regressions at the existing runner, tool publisher, parent-chat stream, and frontend state boundaries. Add one missing behavior at a time. Reproduce failures before fixes. Gate: failing tests demonstrate the defect and pass after the smallest fix. 3. Simplify only within this feature. Use one reasoning string and existing publishers/components. Gate: tests remain green, generated diff is scoped, FE1 through FE10 pass. 4. Commit the candidate with repository hooks enabled, then run the packaged implement-flow audit, validation, remote UAT, and polish stages. Gate: readyForPr and verified remote evidence for the exact final candidate. If polish changes HEAD, refresh the UAT evidence for that SHA. 5. Create a reviewable PR and complete green CI plus bounded Codex review on its exact head. Get one fresh independent readiness recommendation. Gate: no unresolved review threads, required evidence recorded, and a justified readiness decision. Do not merge. ## Regression coverage - Runner: reasoning and advice callbacks remain separate; final advice and usage count stay correct. Retain existing retry/refund tests. - Tool: all reasoning/advice events carry role tool, type tool-result, advisor name, and the invocation ID. Without an ID, emit no live output. Retry emits stale reasoning/advice, reset, then fresh reasoning/advice. - Chatd: extend `TestAdvisorHappyPath_RootChat` with deterministic `openai-compat` reasoning chunks. Hold the nested response until the live subscriber captures expected reasoning and advice. Observe the complete relevant event set, assert no parent-assistant reasoning, and check continuation and persisted content contain no advisor reasoning. Extend only the test fixture needed to emit `reasoning_content`; do not change production adapters. - Frontend: extend streamState tests for exact accumulation, whitespace, JSON-looking text, reasoning-only streaming, empty advice delta, reset, final result, and bare error. - Durable/live integration: replay a durable assistant tool call followed by live reasoning and advice results. Assert the durable card receives both channels and the live row no longer owns the same result or block. Preserve unrelated IDs and live calls. Clear the overlay on reset; prefer durable final results, including null. Cover the complete display path with a real-store ChatPageContent story. - Visual stories: running reasoning-only, running reasoning-plus-advice, and completed with stale reasoning. Keep existing limit/error stories. Stories set up visual states without assertions, following current FE1. ## Validation Run targeted checks while iterating, then the broader gates: ```sh umask 022 go test ./coderd/x/chatd/chatadvisor ./coderd/x/chatd ./codersdk -run 'Advisor|ChatMessagePart|ChatStream' -count=1 pnpm -C site exec vitest run --project=unit src/pages/AgentsPage/components/ChatConversation/streamState.test.ts pnpm -C site exec vitest run --project=storybook src/pages/AgentsPage/components/ChatElements/tools/AdvisorTool.stories.tsx make gen make fmt make test RUN='Advisor|ChatMessagePart|ChatStream' pnpm -C site lint:types pnpm -C site check pnpm -C site lint make lint make pre-commit ``` Keep native exit codes and logs. Do not hide a failed check, bypass hooks, or fix unrelated baseline problems in this PR. Stage intentional generated/formatting changes before pre-commit's clean-diff checks. Report exact blockers and risks. ## Remote dogfood UAT Use the coder-agents-uat skill and an independent critical Coder Agent, not a local-only substitute. Push only the named feature branch. Test its exact SHA in an isolated workspace/deployment without changing shared model credentials or configuration. Use an isolated user, chat, and model config. Setup: 1. Read the branch diff and UAT scope. Record the branch and SHA. 2. Start Coder with the repository-supported `./scripts/develop.sh --port-offset` (or `CODER_DEV_PORT_OFFSET=true`). Do not replace it with a manual server launch. Record effective API/UI URLs and wait for readiness. 3. Prefer a deterministic mock OpenAI-compatible provider that emits advisor reasoning and advice separately, and a retry after stale output. Use only isolated configuration. Never print or capture secrets. 4. Start a named agent-browser session. Attempt `agent-browser skills get core`; record the installed version/fallback if unavailable. Record video before the scenario, then install any stream capture since recording may recreate browser context. Scenario: 1. Create a normal advisor-enabled root chat. Do not use Plan Mode: current product behavior excludes the advisor there. 2. Capture the initial state. Prompt the parent to call advisor. 3. While the tool is running, capture reasoning-only and reasoning-plus-advice states. Verify exactly one advisor card per tool-call ID, with its original question and intent title. Verify Thinking and Advice stay separate inside that card and the parent thinking area does not receive nested reasoning. 4. Capture the relevant WebSocket event set. Verify role tool, type tool-result, advisor name, matching tool-call ID, and reasoning_delta. An advisor-filtered subset is insufficient to prove absence of parent reasoning. 5. Let the advisor finish. Verify final advice remains, Thinking disappears, and refresh does not restore transient reasoning. 6. Exercise retry with the deterministic provider if feasible. Verify stale reasoning/advice clears before fresh output. If not exercised, record the omission and remaining test evidence; do not claim it was dogfooded. 7. Capture console errors before and after. Inspect the screenshots and semantic video frames, not only successful media decoding. Required evidence: exact tested SHA; remote chat URL; setup command and effective URLs; non-secret provider/model names; before/thinking/thinking-plus-advice/completed screenshots; a short streaming video; complete relevant stream evidence; refresh and retry observations; console results; explicit omissions; and owned-resource cleanup receipts. Keep evidence under `.mux-uat/round-<n>/`, excluded from source commits. When publishing evidence to GitHub, use native `gh --attach`, not cookie-based uploads or gh-image. Cleanup: stop only owned develop/provider processes and named browser sessions. Do not use unscoped process sweeps, shared database resets, or `agent-browser close --all`. </details> --- _Generated with [`xum`](https://github.com/coder/xum) • Model: `coder:openai/gpt-6-astra` • Thinking: `xhigh`_ --------- Signed-off-by: Thomas Kosiewski <tk@coder.com> |
||
|
|
c931c1a4ef |
fix(site): apply design feedback to the workspace filter combobox (#29111)
Design review follow-ups for the unified workspace search and filter (`FilterCombobox`) on `/workspaces`, continuing #29080. **Search box** - Filter toggle shows a dotted `ListFilterActiveIcon` while at least one chip is applied; it renders 2px larger than the plain icon so both read as the same size. - Chips render the `key:` prefix in content-secondary and the value in content-primary, at 14px with 8px left padding. - Attributes chips display as `attribute:outdated` (etc.) instead of `outdated:true`; the category key is now `attribute` with `attributes` kept as a typed alias. The emitted query is unchanged. - The trailing text input sizes to its content (`field-sizing: content`) and matches chip height, so an empty input no longer forces a second row and the box no longer changes height when the first chip is added. **Dropdown** - Categories are ordered Owner, Status, Attributes, Template, Organization. - Each category row ends with either the labels of its applied chips plus a check mark, or a sample of its options (templates and organizations come from the deployment; Owner shows a fixed `me`). Applied values are content-secondary, the sample is muted; both 12px. - Rows are 34px with 8px horizontal padding, a 24px icon slot (18px lucide icons, 24px avatars), 14px regular text. List padding is 8px; group headers get 16px above except the first. - Attributes uses `TagIcon`; Organization keeps `Building2Icon`. - Result rows inherit the row colour so label and icon highlight together; the workspace result subtitle (and the unused `SearchResult.subtitle` field) is removed. **Table** - Pagination summary is prefixed with `Filtered:` while a query is set; with zero filtered results it reads `No workspaces match your search.` - Filtered empty state uses the same sentence and adds an outline `Clear all` button that resets the query. Stories cover the new states (active icon, wrapped chips, attribute chips, category previews and applied values, filtered summary, empty state, Clear all). `chipDisplay` and `categoryPreview` have unit tests. <details> <summary>Decision log</summary> - "Filter active" for the toggle icon means at least one committed chip; free text alone does not switch it. - The supplied SVG for the active icon was redrawn on lucide's 24px grid with `currentColor` and stroke 2 so it matches `ListFilterIcon` in weight and theming; its shortened top line carries less visual mass, hence the 20px render. - Row spec asked for 34px rows and 8px padding with a 24px icon slot; 24 + 2*8 = 40, so rows use 8px horizontal / 5px vertical padding to hit 34px. - Chips use `text-sm` with `leading-4` so they stay 28px tall and the box height and first-row icon alignment are unchanged. - Chips are now two spans, so story assertions use a `chip(token)` matcher on the chip element's full text instead of `getByText("owner:me")`. - The `field-sizing` input relies on browser support that is now in Chrome, Safari, and Firefox 152; `size={1}` keeps the fallback intrinsic width small elsewhere. - Category previews reuse the empty-query option lookup (`filterComboboxOptions(key, getOptions, "")`), so entering a category hits the react-query cache. `FilterCategory.hint` is a fixed override of the sample; `FilterOption.appliedLabel` lets `owner:me` read as `me` rather than `admin (you)`. - The helper text uses `text-content-disabled` because the theme defines no `content-tertiary` token (the 18 existing `text-content-tertiary` usages under `AgentsPage` generate no CSS). - Free text is still emitted live (debounced) while browsing the dropdown; the backend treats bare terms as workspace-name substrings, so typing `admin` does not match owner `admin`. Left unchanged here; a backend change would be a separate PR. </details> --- This PR was generated by Coder Agents on behalf of @tracyjohnsonux. --------- Co-authored-by: Jake Howell <jacob@coder.com> Co-authored-by: Jake Howell <jake@hwll.me> |
||
|
|
b70702d50d |
docs: split OAuth2 provider page (#29778)
Split the OAuth2 provider documentation into seven focused pages. - Update navigation and inbound links, preserving compatibility anchors for moved headings. - Correct `DELETE /oauth2/tokens` documentation: it revokes only the calling user's tokens and codes, not every user's for the application. - Clarify client authentication and app creation, mention PKCE, and update callback UI references. - Remove contributor-only instructions and the feature-specific example from feature-stage docs; restore release and upgrade guidance in `security.md`. - Standardize formatting and verify internal anchors. Markdown and em-dash linting pass. Refs PLAT-659. |
||
|
|
3d30e201b5 |
docs: move contributor guides out of the published docs into the repo (#29751)
## Merge order Merge first; then republish the docs; then coder/coder.com#1100 (the redirects). ## Summary The nine pages under `docs/about/contributing/` are for people working in this repository, not for Coder users or administrators, so they leave the published documentation. The repository becomes their canonical home. Until now the root `CONTRIBUTING.md` and `CODE_OF_CONDUCT.md` were two-line stubs that only linked to the docs site, so contributors on GitHub were bounced out to read them. A companion PR in `coder/coder.com` adds redirects from every retired `/docs/about/contributing/*` URL to the new GitHub location. It must merge only after this PR has merged and the docs have republished. ## Changes | Old path | New path | | -- | -- | | `docs/about/contributing/CONTRIBUTING.md` | `CONTRIBUTING.md` (replaces the stub) | | `docs/about/contributing/CODE_OF_CONDUCT.md` | `CODE_OF_CONDUCT.md` (replaces the stub) | | `docs/about/contributing/SECURITY.md` | deleted; the root `SECURITY.md` already holds the policy | | `docs/about/contributing/AI_CONTRIBUTING.md` | `contributing/AI_CONTRIBUTING.md` | | `docs/about/contributing/backend.md` | `contributing/backend.md` | | `docs/about/contributing/frontend.md` | `contributing/frontend.md` | | `docs/about/contributing/modules.md` | `contributing/modules.md` | | `docs/about/contributing/templates.md` | `contributing/templates.md` | | `docs/about/contributing/documentation.md` | `contributing/documentation.md` (see note below) | For every moved file: the docs front matter is stripped and its `title` becomes the H1, relative links are rewritten for the new depth (`../../../foo` becomes `./foo` at the root and `../foo` under `contributing/`; the two links into `docs/admin/` become `../docs/admin/...`), and the docs-only `<div class="tabs">` wrapper in `CONTRIBUTING.md` is removed. `CONTRIBUTING.md` gains a short intro that links the code of conduct, the security policy and the area guides, since GitHub only auto-surfaces the root files. `docs/manifest.json` loses the About → Contributing group and `docs/images/icons/contributing.svg`, which only that group used. Inbound references updated: - `README.md`: contribution guide link now points at `CONTRIBUTING.md` on GitHub. - `docs/tutorials/example-guide.md` and `docs/install/releases/feature-stages.md`: link to `contributing/documentation.md` on GitHub, since a docs page cannot link to a repo-only file. - `docs/.style/style-guide/README.md`: the "Relationship to" section names the new location. - `scripts/docshtmlcheck/main.go`: both the package comment and the user-facing error string name `contributing/documentation.md`. - `scripts/docshtmlcheck/README.md`: relative link to the new location. - `coderd/database/migrations/migrate_test.go`: `t.Log` link now points at `contributing/backend.md#database-fixtures-for-testing-migrations`. - `.github/pull_request_template.md`: AI contribution guidelines link. - `.github/workflows/contrib.yaml`: commit-message guidelines link in the PR title check. - `.github/workflows/test-docs-preview-mapper.sh`: the mapper test case that used `docs/about/contributing/CONTRIBUTING.md` now uses `docs/admin/security/audit-logs.md`. - `.claude/docs/{ARCHITECTURE,PR_STYLE_GUIDE,WORKFLOWS,DOCS_STYLE_GUIDE}.md`: links to `CONTRIBUTING.md`. `git grep about/contributing` is empty after this change. `CODEOWNERS` had no entry for the old paths. Note on `documentation.md`: it is docs-authoring guidance and is parked in `contributing/` for now. Folding it into `docs/.style/` is tracked separately and is deliberately not attempted here. ## Testing - `go run ./scripts/docshtmlcheck` over `docs/`, and again over `contributing/`, `CONTRIBUTING.md` and `CODE_OF_CONDUCT.md`: clean. - `go vet ./scripts/docshtmlcheck/...` and `go test ./scripts/docshtmlcheck/...`: 47 tests pass. - `go vet ./coderd/database/migrations/...`: clean. `go test` for that package fails to link on this machine (`tailscale.com/tstime/mono: invalid reference to runtime.nanotime1`) identically on unmodified `main`, so it is a local toolchain issue and not exercised here; the change is a string in a `t.Log`. - `pnpm check-docs` (markdownlint-cli2 and markdown-table-formatter over `docs/`, `.claude/docs/`, root `*.md`): 495 files, 0 errors. The same two tools over `contributing/*.md`: 0 errors. - Every relative link in the eight moved files resolves to an existing path (scripted check). - `bash .github/workflows/test-docs-preview-mapper.sh`: the changed `assert_maps_to` case passes; the six `resolve_ref`/`pages_for_image` failures it reports are identical on unmodified `main` on macOS. Linear: [DOCS-975](https://linear.app/codercom/issue/DOCS-975) --- 🤖 Built with AI assistance. |
||
|
|
d7b6528d7e |
docs: cap the config reference TOC and drop the Dangerous emoji (#29857)
## Merge order Standalone; no dependency on the other DOCS-977 PR (task-list checkboxes). ## Summary Tracy and Ian flagged the mixed checkbox/emoji styling in the docs (Slack thread linked from DOCS-977), including the `⚠️ Dangerous` heading that `scripts/configdocgen` generates from `codersdk.DeploymentValues`. The generated configuration reference also has around 130 `h3` headings, which makes its "On this page" list unreadable. This PR changes only the generator, `scripts/configdocgen`, and regenerates `docs/admin/setup/configuration-reference.md` from it. ## Design or Fix - Emit `toc_depth: 2` frontmatter at the top of the generated page, before the `<!-- DO NOT EDIT -->` comment. docs-engine's sync (`packages/docs-build/src/sync.ts`) reads a page's own frontmatter before stripping it, so this caps the on-page TOC at h2 without any docs-engine change. - Strip any leading emoji or symbol from generated section headings (`stripLeadingSymbol`), so the Dangerous heading reads "Dangerous" instead of "⚠️ Dangerous". `sectionRank`'s "Dangerous last" ordering still keys off the raw serpent group name, so ordering is unaffected. - Render a GitHub `[!CAUTION]` alert directly under the Dangerous heading, using the group's own codersdk description when it has one, otherwise a short fallback ("These options can break your deployment or weaken its security..."). The `⚠️ Dangerous` group name in `codersdk/deployment.go` is unchanged, because the CLI and other output use it. ## Testing - `go test ./scripts/configdocgen/...` — 45 passed (7 new/updated cases: `TestStripLeadingSymbol`, `TestRenderDangerousWithDescription`, and updated `TestRenderPipeline` assertions for the stripped heading, the Caution alert, and its position between the heading and the first option). - `go vet ./scripts/configdocgen/...` and `gofmt -l scripts/configdocgen/*.go` — clean. - `make docs/admin/setup/configuration-reference.md` — regenerated the page (never hand-edited); this also runs `markdownlint-cli2 --fix` and `markdown-table-formatter` as part of the make target, both clean. - `go run ./scripts/docshtmlcheck` — clean. - Verified with a small Node script against docs-engine's built `parseFrontmatter`/`extractTitle` (from `packages/docs-transforms/dist/transform.js`, at the commit that introduced `toc_depth` support) that a page shaped like the regenerated one — `toc_depth: 2` frontmatter followed by the `<!-- DO NOT EDIT -->` comment and then the `# Configuration reference` H1 — parses `toc_depth: 2` and the title correctly. ## QA Confirmed via the docs-engine sync parser directly (see Testing) that `toc_depth: 2` is picked up correctly from this file shape. I did not spin up docs-engine's dev server against this worktree: my local docs-engine checkout is behind `origin/main` by several commits including the one that added `toc_depth` support, so a faithful local preview would first need a docs-engine rebuild against `origin/main`. Given the direct parser verification above already confirms the mechanism, I judged the full dev-server rebuild too heavy for the marginal confidence gained and skipped it. Expected rendering, based on the diff and docs-engine's documented `toc_depth` behavior: - The "On this page" TOC lists only h2 sections (General, Dangerous, and the rest), not the ~130 option h3s. - The Dangerous section renders as a plain "Dangerous" heading, followed immediately by a Caution callout, with no emoji. ## Upstream No. This is Coder product documentation generation (`codersdk`-driven), not a Fumadocs engine change. Linear: [DOCS-977](https://linear.app/codercom/issue/DOCS-977/docs-replace-emoji-checkboxes-and-emoji-headings-with-one-icon-style) --- 🤖 Built with AI assistance. |
||
|
|
b5ce79b9e0 |
fix(coderd): validate GCP instance token audience (#29765)
Google instance identity authentication accepted tokens issued for any audience. A Google-signed token for a registered VM but intended for another service could therefore be exchanged for a Coder agent token. Require `aud=coder` before the exchange. The standard GCP agent already requests this audience. Custom clients requesting another audience will receive 401 and need to update. Add coverage for foreign-audience rejection and the returned agent token. Refs https://linear.app/codercom/issue/PLAT-655/fixcoderdworkspaceresourceauth-validate-audience-on-gcp-instance |
||
|
|
99a3425333 |
fix: advertise install.sh with curl -fsSL everywhere (#29801)
## Summary The install one-liner is advertised as `curl -L` in most docs pages, the README, and the CLI's default version-mismatch hint, while `install.sh` itself and the deployment-local hint use `curl -fsSL`. Without `-f`, curl writes an HTTP error body to stdout, and the one-liner pipes that error page into `sh`. This PR standardizes every `install.sh` invocation on `-fsSL` so a failed download fails closed. ## Changes - Docs: `install/cli.md`, `install/operate/upgrade.md` (twice), `get-started/index.md`, `start/local-deploy.md`, `install/operate/provisioners/index.md`, `admin/templates/managing-templates/change-management.md` (twice), `user-guides/workspace-access/zed.md`, and `README.md`. - CLI: `defaultUpgradeMessage` in `cli/root.go` now prints `curl -fsSL`, matching the deployment-local branch in the same function. - `codersdk/deployment.go`: the `--cli-upgrade-message` description now says `curl -fsSL`; the server help goldens, `server-config.yaml.golden`, `docs/reference/cli/server.md`, and `docs/admin/setup/configuration-reference.md` are regenerated to match. - `install.sh`: the "To run" header comment now matches the script's own usage text. - Style guide: a new "Commands that pipe a download into a shell" rule in `docs/.style/style-guide/formatting.md`, and the tabs example uses `-fsSL`. The coder.com download page already builds its command from `-fsSL` in coder/coder.com#1093, and coder.com `main` has no other `install.sh` one-liners outside test fixtures, so no coder.com change is needed. DatoCMS content and a release verification page are not in this PR. `main` since moved the upgrade and provisioner pages under `docs/install/operate/` and removed the install one-liner from `docs/install/index.md` in #29304, so that page no longer appears in this diff. ## Testing - `TZ=UTC go test ./cli -run='Test(CommandHelp|ServerYAML|ErrorExamples|.*Golden)' -update` and `go test ./enterprise/cli -run=TestEnterpriseCommandHelp -update` pass and produce the committed golden diffs. - `go test ./cli -run 'Test.*Version|TestWrapTransport'` passes, including `Test_wrapTransportWithVersionCheck`. - `go run ./scripts/configdocgen` output contains the new `curl -fsSL` description. - `markdownlint-cli2` on the edited style guide page reports 0 errors. - `git grep` finds no remaining `curl -L …install.sh` outside the style guide's **Don't** example. - After merging `main`: `make pre-commit` passes, and `make test`, `make test-js`, and `make site/out/index.html` pass. Linear: https://linear.app/codercom/issue/DOCS-964/standardize-installsh-curl-flags-on-fssl-across-docs-codercom-and-the --- 🤖 Built with AI assistance. |
||
|
|
6d490f076f |
feat(site/src/pages/WorkspacesPage): open link context menu when right clicking workspace name (#29813)
closes DASH-101 This PR changes `WorkspacesRow`'s workspace name from a `span` into a `Link` (which renders an `a`), enabling right-clicking to open the browser's context menu to perform link-specific actions like opening in a new tab or copying the URL. <img width="1840" height="1191" alt="image" src="https://github.com/user-attachments/assets/1555449b-70cf-4b97-b279-bf43d541d8ba" /> The user who opened the issue is requesting that the row renders an anchor element. However, the entire table row cannot be turned into an anchor, since it contains other interactive elements, including other anchors. Anchors cannot be nested according to the [`<a>` spec](https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element). Within `WorkspacesRow`, we already support opening a workspace in a new tab by clicking the row with the middle mouse button. Adding event handlers to non-interactive HTML elements like `tr` is not an a11y best practice, but it's a workable solution considering the interactive descendant elements contained in each row. |
||
|
|
d5a6047879 |
docs: restructure Install into the five phase deployment spine (#29304)
Restructures the Install section into the five-phase deployment spine, so the reading order matches the order a deployment actually happens: **plan, prepare, install, validate, operate.** Today the first thing a reader sees is a shell command, and architecture and sizing sit downstream in Administration, after the point where they would have been useful. Resolves [DOCS-869](https://linear.app/codercom/issue/DOCS-869). Part of [DOCS-685](https://linear.app/codercom/issue/DOCS-685) and [DOCS-738](https://linear.app/codercom/issue/DOCS-738). > [!IMPORTANT] > **Stacked on [#28960](https://github.com/coder/coder/pull/28960)** (DOCS-871, terminology). Base is that branch, not `main`. Retarget to `main` after it merges. > > **Paired with coder/coder.com [#1077](https://github.com/coder/coder.com/pull/1077)**, which must merge **first**. Without it, every inbound link to a moved page 404s in the gap. ## Deliberately mechanical No prose changes. The only edits inside moved pages are relative link and image path repairs, so the diff reads as renames. That is the point: this is the highest link-breakage change in the project, and it should be reviewable as such. The prose work is [DOCS-868](https://linear.app/codercom/issue/DOCS-868) (phase overview, architecture rewrite, sizing split, actor table) and [DOCS-872](https://linear.app/codercom/issue/DOCS-872) (new pages). ## The new spine ```text Install and deploy Coder /install ├── Coder CLI [unchanged, retired by DOCS-870] ├── 1. Plan your deployment │ ├── Architecture and components [from admin/infrastructure] │ └── Coder Validated Architecture [from admin/infrastructure] │ └── 1k / 2k / 3k / 10k users ├── 2. Prepare prerequisites │ ├── Licensing [from admin/licensing] │ ├── Air-gapped deployments [from install/airgap] │ └── Mirror images and registries [from install/registry-mirror-artifactory] ├── 3. Install the control plane │ ├── Docker / Kubernetes / Rancher / OpenShift │ ├── Cloud marketplace and VM images │ └── Unofficial install methods ├── 4. Validate your deployment │ └── Scale testing [from admin/infrastructure] │ ├── Scale test utility │ └── Scaling best practices └── 5. Operate and maintain ├── External provisioners [from admin/provisioners] ├── Upgrading (+ best practices, ESR guides) └── Uninstall ``` Leaving Install: release channels become `reference/releases`, feature stages become `reference/feature-stages`. `docs/admin/infrastructure/` is gone entirely, which is what DOCS-738 recommended. ## Numbers - 31 pages moved, all as `git mv` renames. - 1 page deleted: `admin/infrastructure/index.md`, whose content was a one-line section blurb. - 5 new placeholder index pages, one per phase, each a sentence of orientation plus `<children></children>`. The nav schema requires a path on every entry, so a phase cannot exist without one. - 265 relative links and asset paths repaired across 57 files. - `docs/manifest.json` restructured. Entry count goes 460 to 464: plus 5 stubs, minus the deleted Infrastructure entry. ## Reviewer attention, please **The redirects PR repairs 19 existing redirects, not just adds new ones.** This was the surprise. `redirects.json` already had entries whose *destinations* pointed at pages this PR moves, so they would have started redirecting to 404s. Examples: `/docs/architecture/architecture`, `/docs/admin/architectures`, `/docs/scaling/scale-testing`, `/docs/licensing`, `/docs/enterprise`, `/docs/install/offline`, `/docs/platforms`, `/docs/install/1-click`, `/docs/admin/upgrade`, `/docs/install/cloud/ec2`, and both `feature-stages` aliases. All 19 are fixed in the paired PR. **This PR touches `scripts/`, so it is not docs-only.** Two release tools write to paths that moved and would have broken silently at release time: - `scripts/update-release-calendar.sh`: `DOCS_FILE` now points at `docs/reference/releases.md`. - `scripts/releaser/docs.go`: `releasesFile`, and also `kubernetesFile` and `rancherFile`, which pointed at `docs/install/kubernetes.md` and `docs/install/rancher.md`. <details> <summary>Deliberate scope decisions</summary> - **Self-managed vs cloud grouping is flattened.** The reconciled IA nested platform pages under a "Self-managed platforms" parent. That would need two more placeholder index pages for groups with no content yet, so the platform pages sit directly under Phase 3 and the grouping lands with the DOCS-868 prose. - **Release-notes URLs left alone.** `scripts/releaser/release.go` and `scripts/release/generate_release_notes.sh` embed `https://coder.com/docs/install/releases` and `/docs/install/upgrade` in release-note templates. The redirects cover them, and changing the strings would require updating Go test fixtures in `scripts/release/main_internal_test.go`. Better as its own change. - **In-product doc links left alone.** Several `site/src` pages link to `coder.com/docs/admin/provisioners` and similar. Those are absolute URLs, so the redirects cover them. Updating them is a frontend change that would pull frontend review into a docs restructure. - **`admin/security/audit-logs.md` line 237** is hand-written prose below the generated table, and its `../licensing/index.md` link had to move with the licensing page. Verified `make gen` does not revert it. - **`reference/feature-stages.md`** has generated blocks whose relative links changed depth with the move. The generator named in its own marker comment (`scripts/release/docs_update_feature_stages.sh`) no longer exists in the repo, so those links were repaired by hand and the file is effectively hand-maintained. Worth its own issue. - **`install/cli.md` keeps its nav slot** here. DOCS-870 retires it. </details> ## Verification | Check | Result | |---|---| | Broken relative link scan | 0 in `install/`, `admin/`, `reference/`. 21 remain, all pre-existing illustrative examples in `docs/.style/style-guide/**` and one malformed URL in `docs/README.md` | | `make gen` | clean, manifest not clobbered, phase structure intact | | `make lint/markdown` | pass, 508 files, 0 errors | | `make lint/emdash` | pass | | `make lint/docs-html` | pass | | `make lint/prose` | pass, 1 intentional demo error, no new findings | | `make pre-commit` | pass, including `lint/go`, `lint/ts`, `lint/shellcheck`, and a slim build | | Manifest audit | every path resolves to a file on disk; entry-by-entry diff shows only the expected moves | Generated with Coder Agents on behalf of @nickvigilante. <details> <summary>CI note: doc-check failure is infrastructure, not this PR</summary> `Analyze PR for Documentation Updates Needed` fails before it reviews anything: the Coder account behind `agents-chat-action` returns `User is not active (status = "suspended")`. It isn't a required check. `check-docs` (linkspector) and every other check pass on `58ed9e3e4b`. _CI note added by Coder Agents on behalf of @nickvigilante._ </details> |
||
|
|
eb893f536d | docs: move section page to index.md (#29858) | ||
|
|
6f22956063 | docs(docs): label MCP Server page early access (#29864) | ||
|
|
dd3963a408 |
ci(.github/workflows): stop doc-check workspaces after each review (#29851)
doc-check creates one `doc-check-pr-<N>` workspace per PR and never stops or deletes it. On docfood.cdr.dev, 54 of them ran at once, and the host's load average reached about 2900, mostly from processes blocked on I/O. This stops the review workspace once the chat reaches a terminal status, starts it again before the next review, and deletes it when the PR merges. A PR closed without merging keeps its workspace, because stale PRs get closed and reopened and the review needs its context back. Runs for the same PR share a concurrency group, so one run cannot stop or delete the workspace while another is reviewing in it. The workspace lookup also now matches the name exactly. The `name:` filter matches substrings (`coderd/database/queries/workspaces.sql`), so `doc-check-pr-12` also matched `doc-check-pr-123`. Depends on #29849, which fixes the pre-push hook crash that blocked pushing this branch. Retarget to `main` after it merges. Refs [DOCS-1007](https://linear.app/codercom/issue/DOCS-1007/doc-check-stop-review-workspace-after-each-run-and-delete-it-on-pr), CODAGT-1025 <details> <summary>Decision log</summary> ### Choices - **Stop only on a terminal chat status** (`waiting`, `completed`, `error`). When the 40-minute wait times out, the chat is still working in the workspace, so the step leaves it running. - **Start in the workflow, not the model.** The next run finds the workspace stopped. The workflow starts it through the REST API and waits up to 3 minutes, rather than relying on the agent to call `start_workspace`. The job timeout goes from 45 to 50 minutes to make room. A failed start only warns, so the agent's existing recovery path still applies. - **Delete on merge only.** Per review feedback, `closed` without `merged` keeps the workspace. Workspaces for PRs that close and never reopen will pile up (stopped, then dormant) until a sweep removes them. - **Serialize per PR** with `cancel-in-progress: false`. Canceling a job does not cancel the Coder chat, so cancellation would not stop the review it interrupts. ### Follow-up Replace per-PR workspaces with one persistent doc-check workspace and a git worktree per PR, pinned through the action's `workspace-id` input. ### Verification - `actionlint` and `zizmor --persona=regular` pass. - The exact-name jq filter picks the right workspace from sample responses, including an empty or null `workspaces` field. - Not exercised end to end against docfood. </details> --- 🤖 Generated by Coder Agents on behalf of @nickvigilante. |
||
|
|
9a4cb3aebd |
refactor(aibridge/intercept): inject actor headers in middleware (#29839)
Move actor-header injection into the shared upstream-header middleware for Messages, Chat Completions, and Responses. Read the authenticated actor from the request context and remove the duplicated SDK-option injection from blocking and streaming paths, completing the TODO from @ssncferreira. Preserve the existing header names and forwarding toggle. This is the first PR in the actor-header stack: #29839 → #29840 (email forwarding) → #29812 (configurable names). Refs https://linear.app/codercom/issue/AIGOV-601 > 🤖 Generated by AI with human input. |
||
|
|
442b08fee5 |
docs: drop duplicated 'the the' in scaletest flag help and OIDC docs (#29107)
Two doubled-word typos: - `cli/exp_scaletest.go`: the `--connect-url` flag description shown by `coder exp scaletest --help` read "inside **the the** workspace over WireGuard" - `docs/admin/users/oidc-auth/index.md`: "as **the the** username" Docs/help text only. |
||
|
|
77763b5aa7 |
chore: own AgentsPage via the agents-frontend team (#29703)
Replaces the solo `@DanielleMaywood` ownership of `site/src/pages/AgentsPage/` with the new `@coder/agents-frontend` team (`@DanielleMaywood`, `@jakehwll`, `@jaaydenh`). `coderd/schedule/autostop.go` (co-owned with `@deansheather`) is intentionally left unchanged since it's not frontend code. --- _Generated by Coder Agents on behalf of @ibetitsmike._ |
||
|
|
c95a87cea7 |
feat: warn before narrowing a self-registered OAuth2 app's scope allowlist (#29777)
- Warn rather than block when admins narrow a self-registered OAuth2 app's scope allowlist. Clients requesting all advertised scopes may receive `invalid_scope` on new authorizations; existing tokens retain their scopes. - Expose `dynamically_registered` in API responses and display registration type on the app page. - Show no warning for widening or clearing allowlists, or for admin-created apps. - Update scope and `invalid_scope` troubleshooting docs and remove the outdated note that the UI cannot set allowlists. Closes PLAT-664. |
||
|
|
9c0c3948c9 |
feat: narrow ssh and bash tool client.Workspace calls with include_related (#29542)
Part of the lite `codersdk.Workspace` work ([GRU-82](https://linear.app/codercom/issue/GRU-82), [RFC](https://app.notion.com/p/coderhq/Lite-Workspace-API-Requests-3aad579be5928060b5e7cc65c539717f)). Stacked on #29541. Narrows the two production `client.Workspace` (get-by-ID) call sites that read only a subset of the returned workspace. - **`cli/ssh.go`** (`notifyCondition`) reads `TTLMillis` and `LatestBuild.Deadline`. `TTLMillis` is computed server-side from the template (`AllowUserAutostop`/`DefaultTTL`), so this requests `template` and `latest_build` (the deadline is on the build itself; no job, resources, or template version needed). - **`codersdk/toolsdk/bash.go`** (`findWorkspaceAndAgent`) refetches after autostart only to locate the first agent, so it requests `latest_build.resources.agents`. Callers read only the agent plus the top-level `Name`/`OwnerName`. The other production by-ID callers were left on the default (full) selection because they need the whole object: `support/support.go` serializes the workspace into the support bundle, `codersdk/toolsdk/chatgpt.go` JSON-marshals it for the model, and `codersdk.ResolveWorkspace` is a generic resolver whose callers expect everything. CLI paths that use `WorkspaceByOwnerAndName` are not touched because that endpoint does not parse `include_related` yet. ### Testing - `TestWorkspaceBash` and `TestWorkspaceBashTimeout` pass; the autostart-refresh branch has no dedicated test, so its selection was verified by tracing the fields read from the returned workspace and agent. - `cli` and `codersdk/toolsdk` build/vet/lint clean; the SSH deadline notifier has no dedicated test, so its selection was verified the same way (and by confirming the server derives `TTLMillis` from the template). --- *Generated by Coder Agents on behalf of @spikecurtis.* |
||
|
|
4def4b480a |
docs(docs/ai-coder/agents/platform-controls): rename sandboxing guide to network isolation (#29847)
Renames the guide added in #29698 from "Sandboxing" to "Network isolation" in both places it appears: the `docs/manifest.json` entry and the `agent-isolation.md` heading. > Generated by Coder Agents on behalf of @bpmct. |
||
|
|
646270a62a |
fix(site/src/pages/AgentsPage): render stop_workspace like start_workspace (#29549)
`stop_workspace` had no renderer and used the generic tool row. The backend already saves the stop build ID on the chat binding, so the `start_workspace` renderer handles stop with its own labels and icon. The build log polling fallback only accepted `pending` and `starting`, so a `stopping` build was never streamed when the binding had not arrived. It now uses `ACTIVE_BUILD_STATUSES`. |
||
|
|
bacb4fc6ed |
feat: expose per-app session counts (#29351)
Track individual applications across deployment statistics, Prometheus, telemetry, and the dashboard instead of exposing only fixed family totals. Preserve existing fields and gauges so current consumers can migrate without breaking. - Add per-app counts with normalized identifiers and registry-backed display names, families, and bundled icons. Unrecognized apps retain their identifiers. - Limit each statistics report to 64 distinct app names, combining excess names into an explicit overflow bucket. - Group dashboard connections by family, including an Other category, with alphabetical per-app tooltips and distinct loading and empty states. - Export app-keyed Prometheus counts separately from current family metadata, allowing queries to enrich historical counts without rewriting stored samples. - Document family queries with unknown fallback, deployment isolation, and replica handling, alongside collection behavior and migration guidance. - Include per-app counts in telemetry, update API schemas and documentation, and add regression coverage across collection, metrics, and dashboard behavior. Closes #27411 |
||
|
|
deafad29cc |
chore: refresh AI model price book (#29835)
## Price book changes 22 models added, 5 models removed, 21 models changed. <details> <summary>Added</summary> - bedrock/global.moonshotai.kimi-k3 - bedrock/global.openai.gpt-6-luna - bedrock/global.openai.gpt-6-sol - bedrock/openai.gpt-6-luna - bedrock/openai.gpt-6-sol - bedrock/us.moonshotai.kimi-k3 - bedrock/us.openai.gpt-6-luna - bedrock/us.openai.gpt-6-sol - copilot/claude-opus-5.5 - copilot/gpt-6-luna - copilot/gpt-6-sol - openrouter/aion-labs/aion-3.5 - openrouter/aion-labs/aion-3.5-mini - openrouter/cohere/command-a-plus - openrouter/fireworks/ember-1 - openrouter/qwen/qwen3.8-max-prime - openrouter/stealth/space-bunny-alpha - openrouter/upstage/solar-mini4 - openrouter/z-ai/glm-5.3-prime - vercel/alibaba/qwen3.8-max-prime - vercel/google/gemini-3.8-flash-lite-tts - vercel/google/gemini-3.8-flash-tts </details> <details> <summary>Removed</summary> - openrouter/inclusionai/ling-3.0-flash-vl:free - openrouter/mistralai/devstral-2512 - openrouter/nex-agi/nex-n2.5-mini - openrouter/nex-agi/nex-n2.5-pro - vercel/inclusionai/ling-3.0-flash-vl-free </details> <details> <summary>Changed</summary> - openrouter/deepseek/deepseek-v4-flash - openrouter/deepseek/deepseek-v4-flash-0731 - openrouter/deepseek/deepseek-v4-pro - openrouter/deepseek/deepseek-v4-pro-0813 - openrouter/deepseek/deepseek-v4.1-flash - openrouter/minimax/minimax-m2 - openrouter/moonshotai/kimi-k2.7-code - openrouter/nvidia/nemotron-3.5-lightning - openrouter/qwen/qwen3-30b-a3b-instruct-2507 - openrouter/qwen/qwen3-next-80b-a3b-instruct - openrouter/tencent/hy3 - openrouter/z-ai/glm-5.3 - openrouter/z-ai/glm-5.3-flashx - openrouter/~deepseek/deepseek-flash-latest - openrouter/~deepseek/deepseek-pro-latest - openrouter/~deepseek/deepseek-v4-flash-latest - openrouter/~moonshotai/kimi-latest - openrouter/~z-ai/glm-flash-latest - openrouter/~z-ai/glm-latest - vercel/inclusionai/ling-3.0-flash-vl - vercel/openai/gpt-oss-120b </details> ## Review notes Regenerated by `make gen/aibridge-prices` from the live [models.dev](https://models.dev) catalog. Both artifacts come from one snapshot, so they ship together: - `coderd/aibridge/prices/data/prices.json` - `site/src/modules/aiModels/knownModels/knownModelsGenerated.json` These are customer-visible cost numbers taken from upstream data, so this PR is never merged automatically. The summary above lists what moved; check the diff for exact figures before approving. Opened automatically by the [aigateway-prices-refresh workflow](https://github.com/coder/coder/actions/runs/35979133021). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Cian Johnston <cian@coder.com> |
||
|
|
59adebc28d |
fix(site/src/pages/AgentsPage): stop remembering the last model in the new chat composer (#29802)
## Problem The new chat composer on `/agents` restored the last model that was actually sent (`localStorage["agents.last-model-config-id"]`, written on every send and on chat creation). Bumping to a more expensive model for one tricky problem silently carried that model into every subsequent new chat, which makes spend unpredictable. ## Change New chat composer only. Model precedence becomes: ``` user click > personal root override (model) > personal root override (chat_default, resolved) > organization default > first available ``` The `last-used` step is removed, along with the `localStorage` key that fed it. The key was written in `AgentCreatePage` and `submitChatTurn`, but `AgentCreateForm` was its only reader, so the writes are removed as dead code. **The composer inside an existing chat is unchanged.** It resolves its model from the chat record (`chats.last_model_config_id`) via `AgentChatPage`, never from `localStorage`, so switching models mid-conversation still sticks for that conversation. ## Stories - `LastUsedModelFallbackWithoutRootOverride` -> `OrganizationDefaultModelWithoutRootOverride`, now asserting the organization default is selected and submitted. - `DelayedAuthorizationPreservesForeignPersistedModel` -> `DelayedAuthorizationResolvesPermittedOrganization`, with the obsolete seeding dropped. ## Validation - `pnpm exec tsc -p . --noEmit` - `pnpm exec vitest run src/pages/AgentsPage/components/ChatConversation/submitChatTurn.test.ts` (14 passed) - `pnpm exec biome check` Storybook interaction tests were not runnable in this environment (no browser runner); CI covers them. Requested by @ibetitsmike. Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com> |
||
|
|
82691e66a1 |
feat(site): add section switcher to agents sidebar header (#29829)
closes CODAGT-1179 <img width="314" height="274" alt="Screenshot 2026-09-24 at 17 10 55" src="https://github.com/user-attachments/assets/c5f510db-324d-405a-8eca-9ad45abf43e6" /> Adds a dropdown to the right of the product logo in the agents sidebar header with **Workspaces**, **Templates**, and **Agents** entries that navigate to the respective pages. The current section (Agents) is marked with a check. The menu items are real links (`DropdownMenuItem asChild` + `Link`, the same pattern as the Admin settings menu) so middle-click and cmd-click open in a new tab and Radix roving focus keeps them keyboard reachable. Navigation is covered in `ChatsSidebar.test.tsx` and the open state by the `SectionSwitcherMenu` story. <details> <summary>Implementation notes</summary> - The switcher lives in a new `chats/SectionSwitcher.tsx` next to `UserSidebarFooter.tsx` rather than inline, since `ChatsPanel.tsx` is already over 600 lines. - `DropdownMenuRadioItem` would give `menuitemradio` semantics for free, but its wrapper renders the indicator as a sibling of `children`, so it cannot be used with `asChild` around a `Link`. Plain `DropdownMenuItem` items with a manual `CheckIcon` and `aria-current="page"` were used instead to keep the items as anchors. - The checked item is hardcoded to Agents because this sidebar only renders under `/agents`. - The logo's existing link to `/workspaces` and the desktop-only (`hidden sm:flex`) header are unchanged. </details> --- Generated by Coder Agents on behalf of @jaaydenh. |
||
|
|
2fcbe1957e |
chore: update low-risk dependencies (#29789)
## Summary Updates two pinned dependency overrides in the root `package.json`: | Package | From | To | |---------|------|----| | brace-expansion | 1.1.12 | 1.1.16 | | js-yaml | 4.1.1 | 4.3.2 | Pinned via the `pnpm.overrides` block; `pnpm-lock.yaml` is regenerated to match. These overrides affect the root tooling install only (docs/codegen tooling); `site/` and `offlinedocs/` have their own lockfiles and are unaffected. ## Testing Run locally at the repo root: - `pnpm install` — resolves/locks both; lockfile has no references to old versions - `pnpm run check-docs` (markdownlint + table formatter, uses js-yaml) — 504 files, 0 errors - `quicktype` version + functional JSON→TS run (depends on js-yaml; used in `make gen`) — pass - `biome` / `markdown-table-formatter` load — pass No behavioral changes; dependency version bumps only. |