Commit Graph
14949 Commits
Author SHA1 Message Date
Jon Ayers 401aa58eeb feat: add schema changes for autostop notification (#26417) 2026-06-22 10:59:43 -05:00
Danny KoppingandNick Vigilante bd893a4504 docs: restore Bedrock static credentials walkthrough (#26563)
## Summary

Restores the step-by-step "Obtaining static Bedrock credentials"
walkthrough that was present on the v2.32.6 `ai-bridge/setup` page but
missing from the current `ai-gateway/providers` page.

The current page mentions static credentials in a single line but no
longer explains how to create the IAM user and access key in the AWS
console. This PR brings back that walkthrough, adapted to the current
database/dashboard-managed provider flow.

## Changes

- Add an `#### Obtaining static Bedrock credentials` subsection under
the Amazon Bedrock provider section in
`docs/ai-coder/ai-gateway/providers.md`.
- Keep the AWS console steps (choose region, generate API keys, create
access key) from v2.32.6.
- Replace the deprecated `CODER_AIBRIDGE_BEDROCK_*` environment-variable
configuration step with guidance to enter the credentials when
adding/editing the provider via the dashboard or AI Providers API,
matching the post-v2.34 database-managed model.

<details>
<summary>Context and decisions</summary>

- Source: [`docs/ai-coder/ai-bridge/setup.md` at
v2.32.6](https://coder.com/docs/@v2.32.6/ai-coder/ai-bridge/setup)
"Obtaining Bedrock credentials" section.
- The old flow set provider config via environment variables, which are
deprecated since v2.34 (providers are now stored in the database and
managed via dashboard/API). The restored content keeps the AWS-side
credential-creation steps but routes the final configuration step
through the current provider management flow rather than env vars.
- Open questions from
[AIGOV-432](https://linear.app/codercom/issue/AIGOV-432/restore-bedrock-static-credentials-docs-from-v2326)
(whether other pages also need this, and whether the content needs
further accuracy updates) are left for review.

</details>

Closes
[AIGOV-432](https://linear.app/codercom/issue/AIGOV-432/restore-bedrock-static-credentials-docs-from-v2326).

> [!NOTE]
> This PR was generated by Coder Agents on behalf of @dannykopping.

---------

Co-authored-by: Nick Vigilante <nickvigilante@users.noreply.github.com>
2026-06-22 15:51:18 +00:00
Nick Vigilante e458692cb8 refactor(docs): convert absolute coder/coder blob/tree/main links to relative (DOCS-351) (#26341)
Closes [DOCS-351](https://linear.app/codercom/issue/DOCS-351).

> [!WARNING]
> **DO NOT MERGE** until
[DOCS-349](https://linear.app/codercom/issue/DOCS-349)
([coder.com#877](https://github.com/coder/coder.com/pull/877)) has
shipped to production and baked for at least one Vercel cycle.
>
> Without DOCS-349, the relative links in this PR resolve to broken
docs-route URLs (`/docs/helm/coder/values.yaml` -> 404) instead of
GitHub URLs tagged with the displayed docs version. DOCS-349 fixes the
rewriter to classify these as GitHub blob/tree URLs with the page's
resolved ref.

## TL;DR

Converts 121 absolute
`https://github.com/coder/coder/(blob|tree)/main/<path>` links across 39
docs markdown files to relative paths. After this lands AND DOCS-349
deploys, every one of these links will follow the displayed docs version
(mainline tag on bare URLs, explicit tag on `/@vX.Y.Z/`, `main` on
`/@main/`) instead of always pointing to `main`.

## Why

Today a reader on `/docs/@v2.30.0/install/docker` follows a
`compose.yaml` link and arrives at `main`'s `compose.yaml`, which
doesn't necessarily match what the docs page describes. Helm values,
Terraform templates, and source-code references in particular drift
across versions. The fix is to let the coder.com rewriter substitute the
page's resolved ref into the URL; that only works on relative links.

## Example payoff (post-DOCS-349)

| URL | Today (absolute, always `main`) | After (relative + rewriter) |
|---|---|---|
| `/docs/install/docker` |
`https://github.com/coder/coder/blob/main/compose.yaml` |
`https://github.com/coder/coder/blob/v2.34.1/compose.yaml` (today's
mainline) |
| `/docs/@v2.30.0/install/docker` | same as above |
`https://github.com/coder/coder/blob/v2.30.0/compose.yaml` |
| `/docs/@main/install/docker` | same as above |
`https://github.com/coder/coder/blob/main/compose.yaml` |

## Scope

- **121 conversions** across **39 files**.
- Verb breakdown: `tree/main` (directories) and `blob/main` (files),
both flipped to relative paths.
- Line anchors (`#L23-L24`) and query strings preserved verbatim.
- Conversion is mechanical: relative path computed from the doc file's
directory to the target via `os.path.relpath`. Any path starting at the
same directory or below gets a `./` prefix; otherwise `../` chains.

## Rebased on main

The branch was rebased onto `main` after the DOCS-350 hotfix
([#26339](https://github.com/coder/coder/pull/26339)) merged. The hotfix
repointed 3 `docs-backend-contrib-guide` refs in `backend.md` to `main`,
which then needed the same `main` -> relative conversion this PR is
doing for the other 121 links. The conflict was resolved by reapplying
the mechanical conversion to `backend.md` after taking the hotfix's
content. Net result: those 3 links land here as relative, same as
everything else. New HEAD `3f501cb622`.

## Inline fix folded in: dead `nix` link

- `docs/about/contributing/CONTRIBUTING.md:7` -> `../../../nix`

The original absolute URL `https://github.com/coder/coder/tree/main/nix`
already returned 404 today. Repointed to `flake.nix` (modern Nix
entrypoint, what the prose "Nix environment" semantically refers to).
Closes [DOCS-357](https://linear.app/codercom/issue/DOCS-357) here since
the `check-docs` Linkspector job surfaced it during rebase; cheaper to
fix inline than in a separate single-line PR.

## Out of scope (filed separately)

- [DOCS-350](https://linear.app/codercom/issue/DOCS-350): 3 dead
`docs-backend-contrib-guide` branch refs in `backend.md`
([#26339](https://github.com/coder/coder/pull/26339), merged).
- [DOCS-352](https://linear.app/codercom/issue/DOCS-352): 10 SHA-pinned
`(blob|tree)/<sha>` links pending intent review.
- [DOCS-355](https://linear.app/codercom/issue/DOCS-355): code-server
analog (4 absolute `(blob|tree)/main` links in `coder/code-server`).
- [DOCS-356](https://linear.app/codercom/issue/DOCS-356): 2 upstream
content bugs in `coder/code-server/docs/CONTRIBUTING.md` (independent of
this PR).


## Not triggering `/coder-agents-review`

Docs-only edit; per `AGENTS.md` the bot review is reserved for
product/CI changes.

## Pre-mortem

| Concern | Mitigation |
|---|---|
| Merging before DOCS-349 deploys regresses ~120 currently-working links
into 404s on coder.com | Clear DO-NOT-MERGE banner; tracked as blocker
in Linear. |
| Relative path computed incorrectly (off-by-one `..`) | Verified all
114 newly-relative non-md/non-image paths resolve to existing files in
the repo (only exception is the pre-existing dead `nix` link above). |
| Line anchors stripped during conversion | Preserved by the
substitution regex; verified `#L<n>-L<m>` cases in `airgap.md` and
`speed-up-templates.md`. |
| Future code reorgs change file locations | Relative links will start
pointing to nothing. Same failure mode as absolute links pointing to
renamed files; can be caught with a future link-checker job. |

## Validation

```
$ grep -rE 'github\.com/coder/coder/(blob|tree)/main' docs --include="*.md" | wc -l
0
$ git diff --stat origin/main | tail -1
39 files changed, 118 insertions(+), 118 deletions(-)
```

114 newly-relative paths verified to resolve to existing repo files
(Python `os.path.exists` check on each computed target).

<details>
<summary>Decision log + planning context</summary>

**Why relative over `(blob|tree)/{{currentDocsVersion}}/...`
templating**: relative paths require zero markdown-system support and
zero upstream churn beyond this one PR. Templating would require a
preprocessor on `coder.com` side AND a convention upstream authors have
to remember; relative paths just work in a plain editor and
`github.com`'s own renderer too.

**Why `./` prefix on same-directory targets**: makes the conversion
grep-able later (`grep -E '\((\.\./|\./)'`).

**Why preserve `#L<n>-L<m>` anchors verbatim**: the anchor is meaningful
to the linked file's content, not to the URL form; keeping it as-is
preserves authorial intent. If the file later changes such that the line
range drifts, that's a different problem the SHA-pin audit
([DOCS-352](https://linear.app/codercom/issue/DOCS-352)) will surface.

</details>

---

*Generated by Coder Agents on @nickvigilante's behalf.*





## Drive-by external link fix folded in

`docs/about/contributing/CONTRIBUTING.md:296` cited
`https://reflectoring.io/meaningful-commit-messages/` which is returning
HTTP 503 (the host appears to be down site-wide right now). `check-docs`
Linkspector flagged it after the rebase. Replaced with
`https://cbea.ms/git-commit/` (Chris Beams' canonical "If applied, this
commit will..." article, confirmed 200), which is the original source of
the rule the prose recites anyway.
2026-06-22 11:39:12 -04:00
Kyle Carberry 46916bf899 feat(coderd/x/chatd): consume the pinned chat context in prompt generation (#26558)
## What

`prepareGeneration` now builds the system-prompt instruction block and
workspace skills from a chat's **pinned context copy**
(`chat_context_resources`, populated in #26438) instead of re-scanning
per-turn history, when the chat has a pinned copy. This is the first
production reader of the pin.

Selection is **presence-based, no experiment**: a chat with pinned rows
builds its prompt from the pin; a chat without them falls back to the
existing per-turn history path. The two paths are mutually exclusive, so
older agents that never report context keep their current behavior and
the per-turn pull stays as the fallback.

## How

- `contextResourcesToPrompt` maps the protojson resource bodies
(instruction files and skills) into the instruction block and skill
metadata, skipping non-OK statuses, non-prompt body kinds, and malformed
bodies (the malformed count is logged so a proto/encoding regression
cannot silently drop context).
- `pinnedWorkspaceContext` reads the pin and reports `ok=false` (history
fallback) when there are no pinned rows; read errors propagate. The
bound agent only decorates the instruction header with OS and directory,
so the pin still resolves when the workspace is unreachable.
- `resolveTurnWorkspaceContext` dispatches between the pinned and
history paths; `prepareGeneration` calls it.

## Testing

- `go test ./coderd/x/chatd/` for `TestContextResourcesToPrompt`,
`TestPinnedWorkspaceContext` (incl. `...FromHydratedPin` against real
Postgres), and `TestResolveTurnWorkspaceContext`: pass.
- `make gen` (no drift), `golangci-lint`, `gofmt`, emdash scan, and `go
build`/`go vet` on `./coderd/x/chatd/...`: all clean.

## Scope

This is the foundational backend slice split from #26466 (the full-stack
staging PR). It changes no API surface, schema, proto, or generated
files. The remaining pieces land as follow-ups in dependency order:

1. `ChatContext` drift/diff API (`resources` + `changes`,
`ContextDetail`). This also extracts the body decoders inlined here so
they are shared with the diff path.
2. Context-ring drift indicator, changes dialog, and refresh (UI).
3. In-workspace `coder exp chat context` source CRUD and `refresh`
(CLI).

<details>
<summary>Why this is the first split</summary>

The coderd hydration, the `PUT /chats/{id}/context` refresh endpoint
(#26389), the `chat_context_resources` table (#26430), and the
copy-into-pin logic (#26438) are already merged, as is the agent-side
push (#26526, #26533). Consuming the pin in prompt building is the step
#26438 explicitly deferred, and it is the bottom of the remaining
dependency stack: the drift/diff API, the UI indicator, and the CLI are
only meaningful once the chat actually builds its prompt from the pin.
Keeping it presence-based means it is independently revertable and
leaves the per-turn pull intact as a fallback, matching the RFC's
Release 3 rollout.

The files are taken verbatim from the reviewed #26466 boundary commit
(before the diff-API work began), so the deep-review feedback already
applied there (CRF-1 through CRF-10) is preserved.

</details>

---

*This PR was created by Coder Agents on behalf of @kylecarbs.* Split
from #26466.
2026-06-22 08:51:57 -06:00
Ehab Younes f5cb2e547e feat: include rotated agent logs in support bundles (#26055)
Support bundles previously captured only the active coder-agent.log, losing
history across agent restarts. Add an optional `after` filter to the agent's
/debug/logs endpoint: without it the endpoint is unchanged (active log only,
10 MiB cap); with it the response includes the active log plus rotated
coder-agent-*.log files modified after the cutoff, newest first. Support
bundles request the last 24h.

Closes #25395
2026-06-22 16:38:18 +03:00
Sas Swart adad5bdd49 feat: surface agent firewall correlation in AI Bridge sessions API (#26416)
Add `agent_firewall_session_id` and `agent_firewall_sequence_number`
fields to `AIBridgeThread` in the `GET
/api/v2/aibridge/sessions/{session_id}` response. These fields link each
thread to its agent firewall confinement session so the frontend can
discover the boundary session and compute sequence ranges for
interleaving firewall events within the thread timeline.

The database columns already exist on `aibridge_interceptions`
(migration 000520) and are already selected by
`ListAIBridgeSessionThreads`. This PR surfaces them through the SDK type
and the `db2sdk` conversion.

Depends on #24814

**Naming note:** The RFC uses `boundary_session_id` /
`boundary_sequence_number`, but the codebase standardized on
`agent_firewall_*` naming in the DB migration. The API fields follow the
existing convention.

</details>

> [!NOTE]
> This PR was authored by Coder Agents.
2026-06-22 15:17:37 +02:00
Sas Swart 335d6bda1b feat: add GET /api/v2/agent-firewall/sessions/{id}/logs endpoint (#24816)
Add a `GET /api/v2/agent-firewall/sessions/{id}/logs` endpoint that
returns agent firewall audit logs for a given session, sorted by
sequence number ascending.

The endpoint supports `seq_after` and `seq_before` (exclusive bounds)
and `limit` query parameters. This enables the frontend to fetch exactly
the firewall events that fall between two AI Bridge interceptions within
a thread, as described in FR 4 of the Boundary/Bridge correlation RFC.

Authorization reuses the `boundary_log` RBAC resource (owner and auditor
can read; members cannot). Returns 404 for unauthorized users to avoid
leaking existence information.

The endpoint is enterprise-only, gated behind `FeatureBoundary`
entitlement, matching the session endpoint from #24814.

Depends on #24814

> [!NOTE]
> This PR was authored by Coder Agents.
2026-06-22 13:56:29 +02:00
Ehab Younes c0b8fa9418 feat(site): add user AI budget override UI (#26402)
Add a per-user AI budget override dialog in the group members menu, scoped to the group's organization.

Refs AIGOV-295
2026-06-22 13:58:53 +03:00
Danny Kopping 4f8acfaeff docs: add Codex WebSocket fallback troubleshooting (#26565)
## Summary

Adds a Troubleshooting section to the Codex CLI AI Gateway client docs
covering the WebSocket-to-HTTPS transport fallback.

Recent Codex CLI versions default to the WebSocket runtime for the
Responses API. AI Gateway does not support WebSocket transport, so each
request attempts a WebSocket connection, fails, and falls back to HTTPS,
surfacing:

```text
Falling back from WebSockets to HTTPS transport.
```

The doc explains the cause and the fix: set `supports_websockets =
false` in the `[model_providers.ai_gateway]` block in
`~/.codex/config.toml` to force HTTPS directly and remove the fallback
delay.

Closes
[AIGOV-453](https://linear.app/codercom/issue/AIGOV-453/document-codex-cli-websocket-fallback-workaround).

<details>
<summary>Note on the config value</summary>

The original request and the Linear issue referenced enabling websocket
support / `support_websockets = false`. The authoritative Codex CLI
[config reference](https://developers.openai.com/codex/config-reference)
confirms:

- The key is `supports_websockets` (trailing "s").
- It declares whether a provider supports the Responses API WebSocket
transport.
- Setting it to `false` is the documented workaround to force HTTPS and
stop the fallback attempts.

Since AI Gateway does not support WebSockets, `supports_websockets =
false` is the correct value. `= true` would assert support that does not
exist and keep the fallback happening.

</details>

---

This PR was generated by Coder Agents on behalf of @dannykopping.
2026-06-22 11:56:58 +02:00
8b970e7ff3 docs: clarify Agents vs Chats API reference pages (#26021)
## Problem

The REST API reference page at
[`/docs/reference/api/agents`](https://coder.com/docs/reference/api/agents)
is confusing: by the name alone, a reader looking for the *AI Coder
Agents* programmatic API would assume this is the right page. In fact,
those endpoints are for the *workspace agent daemon* (the `coder_agent`
Terraform resource / `workspaceagent` daemon). The actual AI Coder
Agents API is documented at
[`/docs/reference/api/chats`](https://coder.com/docs/reference/api/chats).

Both pages compound the confusion by being rendered with a bare `#
Agents` / `# Chats` heading and no descriptive intro. The sidebar
entries are similarly ambiguous (`Agents` and `Chats` with no
descriptions).

## Root cause

The reference pages are generated by `scripts/apidocgen/generate.sh`
(swag → widdershins → postprocess). The widdershins template
(`scripts/apidocgen/markdown-template/main.dot`) already renders
`data.resource.description` directly under each section heading:

```
<!-- APIDOCGEN: BEGIN SECTION -->
{{= data.tags.section }}# {{= r}}

{{? data.resource.description }}{{= data.resource.description}}{{?}}
```

…but the swag annotations in `coderd/coderd.go` never declared
`@tag.name` / `@tag.description` for any tag, so the descriptions were
always empty.

## Changes

- `coderd/coderd.go`: add `@tag.name Agents` / `@tag.description …` and
`@tag.name Chats` / `@tag.description …` annotations next to the
existing `@title` / `@version` block.
- `docs/manifest.json`: rename the sidebar entry `Agents` → `Workspace
Agents` and add `description` fields to both API sidebar entries (every
other top-level section in the manifest has descriptions; the API
children did not).
- Regenerate `coderd/apidoc/swagger.json`, `coderd/apidoc/docs.go`,
`docs/reference/api/agents.md`, and `docs/reference/api/chats.md` via
`scripts/apidocgen/generate.sh` + `pnpm exec markdownlint-cli2 --fix` +
`pnpm exec markdown-table-formatter` + `scripts/biome_format.sh`
(matching the Makefile's `coderd/apidoc/.gen` pipeline).

Resulting diff is intentionally minimal — 6 files, 35 insertions / 3
deletions.

## After this PR

The Agents page will render:

> # Agents
>
> Workspace agent endpoints. These power the workspace agent daemon
defined by the `coder_agent` Terraform resource (sometimes called the
workspace daemon). This API is NOT the AI Coder Agents API. For
programmatic access to AI Coder Agents (formerly Tasks), see the Chats
API.

The Chats page will render:

> # Chats
>
> Programmatic API for Coder AI Agents (the user-facing "Coder Agents" /
"Chats" product). Experimental. Use these endpoints to create, list, and
manage AI coding agent sessions. For background and migration from the
Tasks API, see the AI Coder docs.

And the sidebar entry for the workspace-agent endpoints becomes
`Workspace Agents` instead of `Agents`.

## Out of scope (potential follow-ups)

- `docs/reference/api/chat.md` is a 7-byte stub — likely dead. Could be
deleted in a follow-up.
- Larger rename of the `Agents` Swagger tag (and/or the `coder_agent`
Terraform resource) to something like `Workspace Agents` /
`workspace_daemon` would more thoroughly fix the naming collision, but
that's a much bigger change.

Created on behalf of @mattvollmer.

---------

Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
Co-authored-by: Matt Vollmer <matthewjvollmer@outlook.com>
Co-authored-by: Atif Ali <atif@coder.com>
2026-06-22 07:43:13 +00:00
Ethan bc9cc8cb08 fix(enterprise/coderd): allow deleting external-agent workspaces (#26501)
I stumbled on this while manually testing another workspace change: if a
license expires after an external-agent workspace exists, deleting that
workspace is rejected because `CheckBuildUsage` enforces the
external-agent entitlement for every workspace transition. I assume this
is unintentional from a product POV.

This PR narrows the external-agent entitlement check to start builds.
Creating or rebuilding external-agent workspaces still requires the
feature entitlement, but stop and delete transitions stay available as
cleanup paths.

That matches the managed-agent entitlement precedent (i.e. the usage
billing check) in the same `CheckBuildUsage` path, where license
enforcement is scoped to start transitions instead of trapping users
with resources they can no longer remove.
2026-06-22 12:02:01 +10:00
Kyle Carberry 2f8bba792a feat: push MCP server context and tools from agentcontext (#26533)
## What

Live MCP servers and their tools now flow into the `agentcontext`
snapshot and are pushed to coderd via `PushContextState`, stored
alongside instruction files and skills. Previously the resolver's MCP
seam was unimplemented, so live MCP tool lists never reached the pushed
snapshot.

`agentcontext` is now **fully self-contained** for MCP: it connects to
the MCP servers declared in the `.mcp.json` files its own watcher
already discovers, lists their tools, and emits `KindMCPServer`
resources. It does **not** depend on or modify `agent/x/agentmcp` — that
package is left pristine and keeps serving the agent's MCP HTTP API. The
two MCP paths run independently, which means the legacy package can be
deleted later without touching this code.

## How

- **Self-contained runner** (`agentcontext/mcprunner.go`): a one-shot
MCP client (connect → initialize → list tools → close) with its own
`.mcp.json` parser. A Manager goroutine (`runMCPSync`) reloads it
whenever the discovered `KindMCPConfig` `path:contenthash` set changes,
then re-resolves so the new tools are published. Per-server connects run
in parallel (bounded) with a per-server timeout; a server that fails to
connect is recorded as a failure rather than aborting the batch. Each
connect also force-kills its subprocess on close, because mcp-go's stdio
`Close()` closes stdin and then blocks on `cmd.Wait()` with no kill — a
server that ignores stdin-close would otherwise stall the whole reload
loop.
- **Resource production** (`agentcontext/mcp.go`):
`buildMCPServerResources` turns the runner's non-blocking per-server
snapshot into `KindMCPServer` resources. Connected servers carry their
sorted tools (`StatusOK`); failed servers surface as `StatusUnreadable`
issues instead of vanishing; connected-but-no-tools-yet are skipped
until a later reload. The content hash is tool-set sensitive. The
resolver consumes this through a plain `MCPResources func() []Resource`
field (no `MCPProvider` interface).
- **Tool names**: emitted exactly as the server reports them. Flattening
into a single namespace (e.g. `server__tool`) is left to the control
plane in the next step, since each resource already carries the server
name.
- **Drift**: MCP resources are excluded from the snapshot
aggregate/drift hash (`driftResources`). MCP servers connect
asynchronously after boot; without this, a server finishing its connect
would dirty every hydrated chat even though nothing the user pinned
changed.
- **Wiring** (`agent.go`): the manager is given
`ManagerOptions.MCPExecer`/`MCPUpdateEnv`; `agent/x/agentmcp` is
untouched.
- **Config validation**: a structurally broken `.mcp.json` surfaces as
`StatusInvalid` rather than silently dropping all its servers.

coderd already persists `mcp_server`/`mcp_config` resource bodies
(including tools), so no coderd or proto changes were required.

## Testing

- **Unit**: `buildMCPServerResources` (grouping/sort/skip/failed/hash
sensitivity), MCP resources applied via the resolver seam, MCP exclusion
from the aggregate hash, `.mcp.json` parsing (transport inference, env
expansion), `toolInputSchema`, and `mcpConfigSet` change detection.
- **Proto serialization**
(`TestDRPCPusher_HappyPathSerializesAllFields`): a `KindMCPServer`
resource (tools + input schema) round-trips through `PushContextState`
into the `MCPServerBody` wire form, asserting the server name, tool
name/description, and the decoded `input_schema`.
- **Manager-level, real subprocess**
(`TestManager_MCPServerToolsInSnapshot`): a `.mcp.json` points at a
re-exec'd fake stdio MCP server; the runner connects it and its `echo`
tool surfaces as a `KindMCPServer` resource in the Manager snapshot —
the same snapshot pushed to coderd — exercising `runMCPSync` and the
resolver wiring end to end.
- **Regression** (`TestManager_MCPServerHangingCloseDoesNotStall`): the
fake server ignores stdin-close; the test asserts its tool still
surfaces, proving the runner force-kills the subprocess instead of
stalling the reload. Verified to fail without the fix.
- All pass under `-race`; `go build ./...`, `go vet`, and
`golangci-lint` are clean on the touched packages.

## Scope / follow-ups

This is the agent-side production+push half. The chatd consumer (reading
the pinned MCP resources for prompt/tool injection, including any
server-prefix flattening of tool names) and removing the legacy
`workspaceMCPToolsCache` pull path remain follow-ups, per the RFC
rollout. While both `agent/x/agentmcp` and `agentcontext` exist, stdio
MCP servers are spawned by both; this is intentional and temporary until
`agentmcp` is removed.

<details>
<summary>Implementation plan and decisions</summary>

**Goal:** produce live MCP server resources (with tools) from
`agentcontext` and push them to coderd.

**Starting state (main):** proto (`PushContextState`, `MCPServerBody`,
`MCPTool`), the drpc adapter, coderd storage
(`workspace_agent_context_resources`, body kind `mcp_server`), and the
resolver's MCP seam already existed; nothing implemented the seam or fed
live tools into the snapshot.

**Decision (agentcontext fully separate from agentmcp):** `agentcontext`
starts and lists its own MCP servers using only the connect-and-list
half of an mcp-go client, driven by the `.mcp.json` files its existing
watcher discovers. It shares no state with `agent/x/agentmcp` and does
not import it. Two earlier revisions of this branch were discarded: (1)
relocating `agentmcp` into `agentcontext` (rejected — it duplicates
config parsing and file watching `agentcontext` already does); (2)
reading `agentmcp`'s cached server snapshot via new accessors (rejected
— unnecessary coupling between two packages that should simply run
independently while one is being retired). The temporary double-spawn of
stdio servers is the accepted cost of keeping the two paths cleanly
separated until `agentmcp` is removed.

**Decision (no tool-name prefixing, no MCPProvider interface):** the
agent pushes raw, unflattened data — server name plus verbatim tool
names — and lets the control plane own any `server__tool` flattening.
With a single self-contained producer, the `MCPProvider` interface was
collapsed into a `func() []Resource` field on the resolver.

**Invariants held:** no secrets (env/headers) in pushed resources, only
server/tool metadata; MCP excluded from the drift hash; the seam is
non-blocking so the resolver never stalls on MCP I/O.

</details>

---

*This PR was created by Coder Agents on behalf of @kylecarbs.*
2026-06-21 16:31:05 -06:00
Cian Johnston d5ec26beac chore: replace testing.Testing with flag lookup (#26552)
In our codebase we have an existing convention of using
`flag.Lookup("test.v")` instead of `testing.Testing()`. This avoids
pulling in the entire `testing` package. Another consequence: some of
our custom linters trigger upon import of the `testing` package which
can lead to unexpected linter errors.
2026-06-19 19:59:54 +01:00
Cian Johnston befa1176b9 chore(dogfood): tighten template dormancy settings (#26421)
Tightens dormancy settings for all templates managed in this repo to 30
days / 30 days for time till dormancy and dormancy autodeletion,
respectively.

This was apparently done manually previously but ended up being
automatically reverted.
2026-06-19 15:07:53 +01:00
Danny Kopping 6186532cec fix: negative metric counter increment from token arithmetic (#26547)
_Disclosure: produced using Claude Opus 4.8_

Closes
[AIGOV-452](https://linear.app/codercom/issue/AIGOV-452/prevent-control-plane-panic-on-negative-cached-tokens)

Also addresses a similar shortcoming in
`aibridge/intercept/responses/base.go` and aligns token recording
approach for chatcompletions with other implementations

---------

Signed-off-by: Danny Kopping <danny@coder.com>
2026-06-19 15:44:04 +02:00
Cian Johnston a12b051834 chore: skip failing azureidentity test while under investigation (#26545)
Skips the failing azureidentity test while under investigation.
Ref: https://github.com/coder/internal/issues/1602
2026-06-19 12:49:49 +01:00
Cian Johnston fc83d77189 ci: correct location of redirects.json in weekly-docs workflow (#26542) 2026-06-19 12:03:55 +01:00
Marcin Tojek a2b680ab29 fix: sanitize MCP tool names to satisfy LLM provider constraints (#26539)
Fixes #26325
2026-06-19 11:48:30 +02:00
Susana Ferreira 4aa2482e93 fix: alias coder testutil to resolve import collision (#26540)
PRs https://github.com/coder/coder/pull/26092 and
https://github.com/coder/coder/pull/26519 both landed on main and the
circuit breaker test file ended up importing both
`aibridge/internal/testutil` and `coder/v2/testutil` under the same
name, causing a redeclaration error and breaking `make lint`.

Alias the latter as `codertestutil`, matching the convention already
used in `passthrough_internal_test.go` and `keyfailover_test.go`.
2026-06-19 09:23:18 +00:00
Susana Ferreira b0b698c643 fix(aibridge): increase circuit breaker test timeout to prevent flake (#26519)
`TestCircuitBreaker_FullRecoveryCycle/OpenAI` flaked once on macOS CI.
The most likely cause is that the circuit breaker `Timeout`
(open-to-half-open transition) was too short relative to the time
between test phases. On a slow runner, the breaker could transition to
half-open before the test verified it was still open, so the request
went through as a half-open probe instead of being rejected.

Increases `Timeout` to `testutil.IntervalMedium` (250ms) across all
circuit breaker integration tests.

**Note:** Ideally, these tests would use a mock clock for deterministic
timing, but https://github.com/sony/gobreaker (the library used for
circuit breaker logic) uses real time internally and doesn't expose a
clock interface.

Closes https://linear.app/codercom/issue/AIGOV-438

> Generated with [Coder Agents](https://coder.com/agents) on behalf of
@ssncferreira
2026-06-19 09:23:57 +01:00
Susana Ferreira fec21e1a28 refactor(aibridge): apply key pool failover follow-ups (#26130)
Applies follow-ups from the key pool failover work:

- Add a test verifying key pool state is shared across bridged and passthrough routes.
- Refactor the key failover and passthrough tests to use the shared `MockUpstream` helper.
- Simplify how the request body option is passed through the Anthropic messages interceptor.
- Make `ResponseErrorFromKeyPool` nil-safe and cover it with a test.

Closes: https://linear.app/codercom/issue/AIGOV-398/small-follow-up-cleanups-for-key-failover

> [!NOTE]
> Initially generated by Claude Opus 4.7, modified and reviewed by @ssncferreira
2026-06-19 09:01:39 +01:00
Susana Ferreira 19aa9f5616 refactor: separate aibridge provider and interceptor configs (#26092)
## Description

Separates the aibridge provider configuration from the per-request configuration an interceptor actually needs, and introduces a single `Credential` type that each provider resolves per request. Previously a provider handed its full config to the interceptor (including fields the interceptor didn't use) while other request data was passed as loose arguments, and authentication was spread across config fields and arguments.

## Changes

- Add `intercept.Config`: the per-request, provider-agnostic configuration an interceptor needs (`ProviderName`, `BaseURL`, `APIDumpDir`, `SendActorHeaders`).
- Introduce a single `Credential` interface (`BYOK` and `Centralized`) that each provider resolves per request in `resolveCredential`, and have interceptors route on the credential kind.
- Fail fast with `ErrNoCredential` when a request is neither BYOK nor backed by a centralized key pool.
- Remove unused provider config fields (`Key`, `BYOKBearerToken`, `ExtraHeaders`).

Closes: coder/aibridge#266
Closes: https://linear.app/codercom/issue/AIGOV-221/refactor-separate-provider-and-interceptor-configs

> [!NOTE]
> Initially generated by Claude Opus 4.7, modified and reviewed by @ssncferreira
2026-06-19 08:48:03 +01:00
Andrew Aquino 0d573587e8 feat(site): align ModuleSelection icon with top line when text wraps (#26531)
<img width="1840" height="1191" alt="image"
src="https://github.com/user-attachments/assets/3095d1a7-0f34-4a9a-9dbd-7b9cc524af84"
/>

Do you think we should also top-align the deselect button that displays
on hover?
2026-06-19 00:50:06 +00:00
Hugo Dutka ba860271b0 chore(coderd/x/chatd): clean up the message part buffer comments and implementation (#26508)
Address deferred review feedback for `messagepartbuffer` by documenting
its episode lifecycle, extracting the repeated episode lookup and
finalization helpers, and documenting subscriber channel buffering
decisions.

Addresses these PR #26109 comments:

- https://github.com/coder/coder/pull/26109#discussion_r3379915812
- https://github.com/coder/coder/pull/26109#discussion_r3379988015
- https://github.com/coder/coder/pull/26109#discussion_r3380010948
- https://github.com/coder/coder/pull/26109#discussion_r3380029684
2026-06-18 22:45:01 +02:00
Hugo Dutka 56eb705b8c fix(coderd/x/chatd): reset auto archive ticker after runs (#26512)
Prevents slow chat auto-archive runs from causing a constant archival
loop by resetting the ticker only after each run completes.

Also documents the UTC midnight cutoff used for archive eligibility so
chats with activity on the same UTC calendar date stay eligible or
ineligible for the full day.

Addresses deferred review comments:
- https://github.com/coder/coder/pull/26109#discussion_r3380197310
- https://github.com/coder/coder/pull/26109#discussion_r3380219922

Generated by Coder Agents and closely reviewed by Hugo.
2026-06-18 22:44:02 +02:00
Zach 76fa1d4577 fix(coderd): show correct deletion time in dormancy notification (#26488)
The dormancy notification's "will be automatically deleted in X"
sentence rendered the dormancy threshold instead of the auto-delete
duration. A 30-day threshold rendered as "4 weeks" even when auto-delete
was 90 days; a 60-day threshold rendered as "1 month" with a 7-day
auto-delete. Render the countdown from the auto-delete setting, and skip
the deletion sentence entirely when auto-delete is disabled so the
notification no longer promises a deletion that will never happen.
2026-06-18 20:17:37 +00:00
Kyle Carberry 992b1ffed1 feat(agent): serve context sources over the agent socket (#26526)
## Overview

Split from #26466, scoped to **agent-only** changes. This PR exposes the
agent's context sources and snapshots over the existing agent socket.
There
are no changes outside `agent/`.

## What's included

- **agentsocket**: context source CRUD (`ContextSources`,
`GetContextSource`,
`AddContextSource`, `RemoveContextSource`) plus `GetContextSnapshot` and
`ResyncContext` RPCs, with matching client methods and proto. The server
receives the context `Manager` via `WithContextManager` and returns a
clean
  error when it is absent.
- **agentcontext**: the resync JSON response now carries the
per-resource
  `Name`, keeping the HTTP resync payload in sync with the drpc
  `PushContextState` path in `agentsocket`.
- **agent**: passes the context `Manager` to the socket server via
  `WithContextManager`.

## What's intentionally NOT here

- No MCP wiring. There are no MCP additions in `agent.go` or
`agentcontext`.
MCP ownership will land later in `agentcontext`; this PR does not build
on
  `agent/x/agentmcp`.
- No changes to `agent/x/agentmcp` or the `agentcontext` resolver. The
socket
  serves whatever context resources the `Manager` already resolves.

<details>
<summary>Context for reviewers</summary>

This is one of several PRs split out of #26466. Earlier revisions also
wired
live MCP servers through the socket; that scope was removed so this PR
stays
purely socket + context plumbing inside `agent/`. The agentcontext
resolver,
`agent/x/agentmcp`, and `agent.go` MCP startup behavior are unchanged
from
`main`.
</details>

---
_Created by Coder Agents on behalf of @kylecarbs._
2026-06-18 13:00:28 -07:00
Andrew Aquino 61fa2ab878 fix(site): set external auth provider polling status individually (#26313)
fixes #22420
ref DEVEX-369
ref DEVEX-269

The bug on `CreateWorkspacePage`, where clicking one external auth
provider login button disabled all providers' login buttons, was caused
by providers all sharing a single polling status (`"idle" | "polling" |
"abandoned"`) in the `useExternalAuth` hook.

## changes

- Instead of setting one status across all providers, the polling status
in `useExternalAuth` is now tracked for each provider in a record whose
keys are the providers' IDs.
- The biggest diff is a new Storybook file
CreateWorkspacePage.stories.tsx which reproduces the bug behavior from
the issue.
- Until now we've only had CreateWorkspacePageView.stories.tsx, which
isn't able to model the user interactions / API responses needed to
verify the bugfix. This file is unchanged.
- Also deletes `CreateWorkspacePage`'s `useExternalAuth` hook in favor
of the global `useExternalAuth` hook (see #26310)

(co-written with Coder Agents)
2026-06-18 11:58:38 -07:00
Sas Swart 491a75294e feat: GET /api/v2/agent-firewall/sessions/{id} (#24814)
Add a GET endpoint at `/api/v2/agent-firewall/sessions/{id}` that
returns agent firewall session metadata (`id`, `workspace_id`,
`owner_id`, `confined_process`, `started_at`). The handler authorizes
against the `boundary_log` resource with `ActionRead` via dbauthz.

The endpoint is enterprise-only, gated behind the `FeatureBoundary`
entitlement.

The `GetBoundarySessionByID` SQL query JOINs through `workspace_agents`
→ `workspace_resources` → `workspace_builds` → `workspaces` to return
`workspace_id` and `workspace_owner_id` directly, avoiding a separate
query.

Also adds an `owner_id` column to the `boundary_logs` table (migration
000526) with a FK to `users(id)` and a backfill from
`boundary_sessions`. This enables user-scoped RBAC authorization for
`InsertBoundaryLogs` via `.WithOwner()`, ensuring workspace agents can
only insert logs for their own owner.

Depends on #24810

**RBAC behaviour:**

| Role    | Result |
|---------|--------|
| Owner   | read   |
| Auditor | read   |
| Member  | 404    |

> [!NOTE]
> This PR was authored by Coder Agents.
2026-06-18 20:50:17 +02:00
Jeremy RuppelandAndrew Aquino 20ed45cac7 feat(site/src/pages/TemplateBuilder): add ModuleSettingsStep (#26428)
Implement the module settings wizard step, which renders a
`ModuleConfiguration` card per selected module with variable
configuration fields.

- Map non-sensitive variables to `ConfigurationFieldDefinition` (switch
for bool, text input for string/number)
- Show info notice with `code` tags for sensitive variables that will be
collected from developers at workspace creation
- Disable Continue button until all required non-sensitive variables
across all selected modules have values (`moduleSettingsComplete`
helper)
- Step is automatically skipped when no selected modules have
configurable variables

Relates to [DEVEX-286](https://linear.app/codercom/issue/DEVEX-286).

> [!NOTE]
> This PR was authored with Coder Agents.

---------

Co-authored-by: Andrew Aquino <dawneraq@gmail.com>
2026-06-18 13:47:08 -04:00
Hugo Dutka c0c0d1e353 chore(coderd/x/chatd): improve runner logging (#26522)
Follow up to https://github.com/coder/coder/pull/26412.

- Ensure that each `errTaskExpectedExit` and any other error is joined
with a descriptive reason. This will enable
[`runChatWithRetry`](https://github.com/coder/coder/blob/5601ea18ed650deafa4a2da7286a144f9f382330/coderd/x/chatd/tasks.go#L113)
to log a descriptive message when a task exits.
- Pass additional task information like chat id into `runTaskWithRetry`
so logs can be more descriptive.
2026-06-18 19:02:42 +02:00
Andrew Aquino 023a1c992c fix(site): truncate devcontainer name with ellipsis at all screen sizes (#26359)
ref DEVEX-449

## before

In `AgentDevcontainerCard`, the devcontainer's display name truncated
with an ellipsis--but only when the viewport is <768px (parent has
`md:w-full`), which is also when the display name width gets capped at
320px (`max-w-xs`). At larger screen sizes, the display name overlaps
with the rebuild button to the right.


https://github.com/user-attachments/assets/47af30a2-f446-4b5f-bf63-24afb0532b19

## after

Now, the devcontainer display name fills up as much width as possible at
all screen sizes (not just >=768px), and it also gets truncated with an
ellipsis at all screen sizes.


https://github.com/user-attachments/assets/68579438-6fb5-40ea-93cf-c3814dfaac1a

---

(If we have a way to automate resizing screens in Storybook, lmk!)

The trick is to set a `min-width` on the text we want to truncate, see
this CSS Tricks article: https://css-tricks.com/flexbox-truncated-text/

I changed `max-w-xs` to `min-w-[284px]`. In addition to constraining the
display name's width (see "before" above), the `max-width` caused the
rebuild button to wrap to the next line if the screen is too narrow to
show the display name at that width. This behavior on small screens is
preserved. 🙂 However, since the display name's width isn't constrained
anymore, it's written out fully if possible, which causes the rebuild
button to wrap lines on wider screens if the display name is very long.
2026-06-18 09:15:33 -07:00
Hugo Dutka 61a7b800e2 fix(coderd/x/chatd): always commit a workspace context marker (#26520)
Closes
[CODAGT-629](https://linear.app/codercom/issue/CODAGT-629/agents-can-get-stuck-and-ignore-stop-or-nudge).
A stuck chat had these logs associated with it:

```
1781735334322	2026-06-17T22:28:54.322Z	2026-06-17 22:28:54.322 [debu]  coderd.chatd.processor: workspace context build: workspace agent not resolvable  chat_id=d4524ebb-4494-47df-b258-d933c0248942  owner_id=d96bf761-3f94-46b3-a1da-6316e2e4735d
1781735334298	2026-06-17T22:28:54.298Z	2026-06-17 22:28:54.298 [debu]  coderd.chatd.processor: plan path instruction: agent not reachable  chat_id=d4524ebb-4494-47df-b258-d933c0248942  owner_id=d96bf761-3f94-46b3-a1da-6316e2e4735d  chat_id=d4524ebb-4494-47df-b258-d933c0248942 ...
    error= workspace has no running agent: the workspace is likely stopped. Use the start_workspace tool to start it:
               github.com/coder/coder/v2/coderd/x/chatd.init
                   <autogenerated>:1
```

"workspace agent not resolvable" is printed by
[`fetchContextForBuild`](<https://github.com/coder/coder/blob/fecc991ac9f9d673d7a772b0042ca821d19b6296/coderd/x/chatd/workspace_context_builder.go#L145>).
this causes
[`buildWorkspaceContext`](<https://github.com/coder/coder/blob/fecc991ac9f9d673d7a772b0042ca821d19b6296/coderd/x/chatd/workspace_context_builder.go#L60>)
to exit with a `errWorkspaceContextUnavailable` error. That in turn is
interpreted by
[`persistWorkspaceContext`](<https://github.com/coder/coder/blob/fecc991ac9f9d673d7a772b0042ca821d19b6296/coderd/x/chatd/generation.go#L838>)
as an "expected exit" scenario. That's a bug: because the task exits
without changing the chat state, the runner never issues another task to
process the chat any further. But even if it did, it'd go through the
same code path and exit again. We need to ensure that
`persistWorkspaceContext` commits a marker file even if it cannot reach
the agent.
2026-06-18 16:08:26 +00:00
35C4n0r 9d2c504596 chore(dogfood/coder): bump codex module to 5.2.0 (#26525)
Signed-off-by: 35C4n0r <work.jaykumar@gmail.com>
2026-06-18 21:07:01 +05:00
dependabot[bot] 2f3285ebe7 chore: bump the x group across 1 directory with 2 updates (#26521)
Bumps the x group with 2 updates in the / directory:
[golang.org/x/mod](https://github.com/golang/mod) and
[golang.org/x/tools](https://github.com/golang/tools).

Updates `golang.org/x/mod` from 0.36.0 to 0.37.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/mod/commit/deb1dfcdb7c7fd98fb5afddc3e95dd36d5880874"><code>deb1dfc</code></a>
go.mod: update golang.org/x dependencies</li>
<li><a
href="https://github.com/golang/mod/commit/087f6515dd3ba3e8b06918fa425ffe7732321a7a"><code>087f651</code></a>
modfile: use slices.Backward</li>
<li><a
href="https://github.com/golang/mod/commit/343ee60345a1f2ff0692be9dd068c0778dba985c"><code>343ee60</code></a>
x/mod: allow for aggressively conslidating requires</li>
<li>See full diff in <a
href="https://github.com/golang/mod/compare/v0.36.0...v0.37.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/tools` from 0.45.0 to 0.46.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/tools/commit/3d6f8dfd4853c8b323940b931f1170c6d0df8d23"><code>3d6f8df</code></a>
go/packages: propagate PATH in
TestConfigEnvDoesNotInheritProcessEnv</li>
<li><a
href="https://github.com/golang/tools/commit/47abf61fcbb4abdcf37a986ce23e20dc140fd018"><code>47abf61</code></a>
gopls: move internal/tool into gopls/internal/tool</li>
<li><a
href="https://github.com/golang/tools/commit/19cebc548e6c35b3bf20bd09490e7db258183507"><code>19cebc5</code></a>
go/packages/gopackages: use standard flag package instead of
internal/tool</li>
<li><a
href="https://github.com/golang/tools/commit/e965c10097987837d9805f8069f4a8278de7180f"><code>e965c10</code></a>
gopls/internal/test/marker: update hover test</li>
<li><a
href="https://github.com/golang/tools/commit/96efd3d65c18f9f8d66bc94ec5d709db0b7e72f0"><code>96efd3d</code></a>
gopls/internal/golang/stubmethods: support generic interfaces</li>
<li><a
href="https://github.com/golang/tools/commit/83be7b7739a3e73db55876c5d396c8d891f61a51"><code>83be7b7</code></a>
go.mod: update golang.org/x dependencies</li>
<li><a
href="https://github.com/golang/tools/commit/bf05c11f9ba6f0ed70931bf0a302e9099897d726"><code>bf05c11</code></a>
internal/typesinternal: ForEachElement: test generic methods</li>
<li><a
href="https://github.com/golang/tools/commit/99df0abf1ba525779b731d2f9ef358c1b8a1b633"><code>99df0ab</code></a>
go/callgraph/static: support generic methods</li>
<li><a
href="https://github.com/golang/tools/commit/6942095782f864dadecfb2839bf2371d676bfb48"><code>6942095</code></a>
go/ssa: fix instantiation of generic methods on non-generic
receivers</li>
<li><a
href="https://github.com/golang/tools/commit/070e85daf671b972397e181b13cd7a0be55fa6b0"><code>070e85d</code></a>
go/callgraph/rta: skip generic methods in fingerprinting</li>
<li>Additional commits viewable in <a
href="https://github.com/golang/tools/compare/v0.45.0...v0.46.0">compare
view</a></li>
</ul>
</details>
<br />


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 <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-18 15:13:50 +00:00
Atif Ali 0f4a3df2c6 fix: respect automatic_updates policy when building workspace action list (#26362) 2026-06-18 19:57:55 +05:00
Ethan 0fcd9c2005 chore: bump fantasy to sync from upstream (#26440)
Closes CODAGT-572

## Overview

Bumps `charm.land/fantasy` to the head of `coder_2_33`
(`v0.0.0-20260617050554-2e3ddbca75dd`) and adapts `chatd` to it.

The fantasy bump:
- Syncs upstream `charmbracelet/fantasy` main (v0.31.0) into
`coder_2_33` (coder/fantasy#42).
- Mirrors the request region when prefixing cross-region inference
profiles, so a legacy (un-qualified) Bedrock model ID is prefixed for
the same region the request is actually signed for.

Pulling in the new fantasy version propagates its required transitive
dependency upgrades (aws-sdk-go-v2, OpenTelemetry, google genai,
`golang.org/x/*`, etc.) through MVS, which accounts for the bulk of the
`go.mod`/`go.sum` churn.

## chatd changes

- Thread a per-provider `Region` through `ConfiguredProvider` and
`ProviderAPIKeys` (`RegionByProvider`), and merge/prune/resolve it
alongside API keys and base URLs.
- Source the Bedrock region from AI provider settings in `chatd` and
pass `fantasybedrock.WithRegion` when a region is configured.
- Migrate the runtime Bedrock title-generation model ID to a
fully-qualified `global.anthropic.*` ID.
- Emit a `finish_reason` in the test OpenAI streaming server so streams
close on a terminal event, matching fantasy's fail-closed stream
handling.

## Heads-up: most of this is short-lived

Almost all of the `chatd` code in this PR only executes on the **direct
(non-gateway) routing path** — the branch taken when
`AIGatewayRoutingEnabled` is `false`. That flag was a transition crutch
for AI Gateway routing, and it (plus the entire direct path /
`x/chatd/chatprovider` package that backs it) is slated for removal in
CODAGT-598. Under AI Gateway routing — which is the path every
deployment is expected to run — the Bedrock region is resolved by
aibridge directly from provider settings (`cli/aibridged.go` builds
`aibridge.AWSBedrockConfig{Region: settings.Bedrock.Region}`), so none
of the region plumbing added here is reached.

Concretely, expect the following to be deleted alongside the direct
path:
- The `RegionByProvider` map, the `Region()` accessor, and the region
preservation in merge/resolve plus the region pruning in
`PruneDisabledProviderKeys` (`chatprovider.go`).
- The `fantasybedrock.WithRegion(region)` branch in `ModelFromConfig` —
only reachable on the direct path; the gateway path builds a
`fantasyanthropic` client with no region key.
- Reading `settings.Bedrock.Region` in `aiProviderConfigFromKeys`
(`chatd.go`).
- The region-specific tests in `chatprovider_test.go`, and the
`chattest`/`model_coverage` adjustments that support direct-path
testing.

What survives the cleanup (independent of routing):
- The `charm.land/fantasy` bump and its `go.mod`/`go.sum` transitive
churn.
- The fully-qualified `global.anthropic.*` Bedrock title-generation
model ID in `quickgen.go` (a runtime-valid model identifier, not
direct-path-specific).

We're landing the full change anyway so the direct path stays correct
for the remaining transition window; just don't be surprised when
CODAGT-598 reclaims most of it.

## Notes

Depends on coder/fantasy `coder_2_33` already containing the upstream
sync and Bedrock region fix (merged via coder/fantasy#42 and
coder/fantasy#43).
2026-06-19 00:53:59 +10:00
Jeremy RuppelandAndrew Aquino dca8178f8d feat(site): add ModuleSelectStep (#26427)
Implement the module selection wizard step with multi-select toggle and
conflict warnings.

- Add `getTemplateBuilderModules` API client method with optional `base`
parameter for OS filtering
- Add react-query wrapper with `staleTime: Infinity` to prevent
re-fetches on step navigation
- Render a flat grid of `ModuleCard` components with checkbox-style
multi-select
- Show non-blocking conflict warnings when selected modules declare
`conflicts_with` each other
- Map selections to `TemplateBuilderComposeModule[]` and
`SelectedModuleMeta[]` for wizard state

Relates to [DEVEX-285](https://linear.app/codercom/issue/DEVEX-285).

> [!NOTE]
> This PR was authored with Coder Agents.

---------

Co-authored-by: Andrew Aquino <dawneraq@gmail.com>
2026-06-18 09:42:03 -04:00
Cian Johnston a5a4c49a6f chore(coderd/httpapi): deflake TestWSWatcher (#26495)
Fixes ENG-2930
Fixes coder/internal#1597

Refactors TestWSWatcher to reduce flake occurrences.
The flaky tests were using polling-based assertions which may flake
based on goroutine scheduling.
Fixed by using fake connections and channel synchronization where
appropriate.

Note: No coverage of ProbeCanceled, pre-existing.

> Generated by a human, spot-checked by several robots.
2026-06-18 10:08:29 +01:00
Paweł Banaszewski 0dbe0442f0 feat: add CLI commands to manage AI Gateway keys (#25689)
Adds `coder ai-gateway keys` commands:
* `create <name>` creates key with given name
* `list` lists existing keys (alias `ls`)
* `delete <name | id>` removes key matching by name or key id, name has
priority (alias `rm`)
2026-06-18 09:08:17 +00:00
Hugo Dutka 803daaa8b7 fix(coderd/x/chatd): deflake TestStreamPartsDialerDialsPartsEndpoint (#26504)
Closes https://github.com/coder/internal/issues/1601. Fixes a stream
parts WebSocket close race. If the peer closed first, the session read
loop could close the connection before `StreamPartsSession.Close()` ran,
causing cleanup to return a wrapped `net.ErrClosed`. The fix treats
expected transport close errors as successful cleanup.
2026-06-18 08:28:17 +00:00
Hugo Dutka 91543c391d chore: add chatd ARCHITECTURE.md and mention it in AGENTS.md (#26478)
Closes
[CODAGT-610](https://linear.app/codercom/issue/CODAGT-610/add-an-architecturemd-file-to-chatd).
Adds an ARCHITECTURE.md file which describes the architecture of the
chatd subsystem. It's meant for reading by both humans, who would like
to understand chatd better, and agents. It's an edited version of the
chatd stabilization RFC.
2026-06-18 10:08:48 +02:00
Jaayden Halko bc44cdda75 feat: rank chat workspace templates (#25037)
closes CODAGT-203

## Summary

`list_templates` now returns a ranked shortlist with a recommendation,
so the chat agent can pick the right template the way a colleague would:
prefer what matches the request, what the user already uses, and what
the rest of the organization uses. Instead of teaching the model an enum
protocol in prompts, every result carries a fixed `next_step`
instruction telling the agent what to do.

## How list_templates works

1. **Fetch**: active, non-deprecated templates in the chat's
organization, filtered by the admin template allowlist, authorized as
the chat owner (no system escalation).
2. **Query relevance** (optional `query` argument): each template
receives the highest tier any of its fields matches, and a higher tier
always outranks a lower one regardless of usage:

   | Tier | Match |
   |------|-------|
   | 4 | name or display name equals the query |
   | 3 | name or display name starts with the query |
   | 2 | name or display name contains the query |
| 1 | description contains the query (checked only when no name field
matched) |
   | 0 | no match; the template is excluded |

Matching is case-insensitive and ignores spaces/hyphens/underscores
(`python gpu` matches `python-gpu`).
3. **Usage signals**: a new `GetTemplateRankingSignalsByOwnerID` query
returns, per template, the owner's active and recently-deleted workspace
counts within a 60-day window, the last in-window usage, and the count
of distinct developers with an active workspace (unclaimed prebuilds
excluded).
4. **Affinity score** (computed in Go, per template, from that
template's signals only):

   ```text
affinity = 10 x (active + 0.5 x deleted) x 0.5^(days_since_last_use /
14)
            + ln(1 + active_developers)
   ```

`active`/`deleted` are the owner's in-window workspace counts,
`days_since_last_use` is measured from the most recent in-window usage
(the personal term is zero without in-window usage), and
`active_developers` is the org-wide count. Personal usage carries 10x
the weight of org popularity; the confidence floor is the score of two
active developers (`ln 3`) and the required lead over the runner-up is
`ln 3 - ln 2`.
5. **Rank**: query tier first (when a query is present), then affinity
score, then name/ID for determinism. Results paginate 10 per page with
`next_page` present only when more exist.

## Recommendation contract

The result tells the agent what to do next instead of describing
confidence levels:

- `recommended_template_id` is present only when the top template is a
clear winner: the only available template, a decisive query match, or an
affinity score that clears a floor and leads the runner-up by a derived
margin.
- `next_step` is always present and is one of four fixed sentences: use
the recommendation, ask the user to choose, retry a query that matched
nothing, or report that no templates are available.

Per-template items carry raw evidence (`active_developers`,
`your_workspace_count`, `last_used_by_you`) rather than derived labels.
When signals fail to load, the tool logs and degrades to asking the user
unless the query alone is decisive.

Prompts and the `create_workspace`/`read_template` descriptions
reference the field through the `chattool.NextStepField` constant, so
the instruction lives in one place and cannot drift. `create_workspace`
remains idempotent and allowlist-enforced.

## Authorization

The signals query runs with the chat owner's permissions: reading the
owner's own workspaces plus a template-metadata read for the cross-user
popularity count. dbauthz rejects the call if any requested template is
not readable by the owner (covered by allow and deny method tests).

## Docs

Adds `docs/ai-coder/agents/tools/` explaining how agent tool calls work,
with `list_templates` ranking and the `next_step` contract as the first
documented tools.
2026-06-18 06:41:47 +01:00
Jon Ayers ea1379d42c chore: add nats benchmarking pkg (#26396) 2026-06-17 17:34:02 -05:00
George K e702bfa535 test(enterprise/coderd): deflake TestInvalidateTemplatePrebuilds (#26499)
`TestInvalidateTemplatePrebuilds` assumed a stable ordering from preset
invalidation results, but the underlying `UPDATE ... RETURNING` query
does not guarantee row order. Local WIP schema changes were enough to
surface that latent flake when running tests.

Update the test to compare invalidated presets as a set instead of by
slice position. This keeps the behavior under test the same, while
removing dependence on unspecified database row ordering.
2026-06-17 16:33:46 -06:00
Asher 9b847cc5ab feat: support "me" with shared_with_user filter (#26494) 2026-06-17 13:35:53 -08:00
Zach 2f0bb657e2 docs: note Database Encryption coverage for user secrets (#26435) 2026-06-17 14:52:07 -06:00
Garrett Delfosse e188ee03a4 fix(scripts/check_emdash.sh): skip emdash check when no diff base is available (#26489)
## Problem

`scripts/check_emdash.sh` is a diff gate for pull requests: it resolves
the merge-base against the target branch and only inspects added lines.
When it cannot resolve a base ref, it fell back to scanning **every
tracked file**.

Push builds on release branches hit exactly this case: the `lint` job
checks out with `fetch-depth: 1`, so `origin/main` is absent, and
`GITHUB_BASE_REF` is only set for `pull_request` events. With no base
ref, the whole-tree scan flags the many pre-existing emdash/endash
characters already in the repo and fails `make lint` (`lint/emdash`),
even though the build introduced none of them. Observed on
`release/2.34` CI (run
[27704528068](https://github.com/coder/coder/actions/runs/27704528068/job/81949529546)).

## Fix

When no base ref can be determined (i.e. outside a pull request), skip
the check instead of scanning the entire tree. A full scan remains
available on demand via `scripts/check_emdash.sh --all`.

## Testing

- **No base ref** (release-push simulation, no `GITHUB_BASE_REF`, no
`origin/main`): old script scans all files and fails on a pre-existing
emdash; new script skips and exits 0.
- **PR path** (diff vs merge-base): `OK: no emdash or endash characters
found.`
- **`--all`**: still scans the full tree (flags pre-existing characters
as before).
- `shellcheck` and `shfmt` clean.

## Backports

Backport PRs target `release/2.33` and `release/2.34` (same bug, older
script variant). `release/2.29` and `release/2.32` do **not** contain
`scripts/check_emdash.sh`, so there is nothing to backport there.

<details>
<summary>Decision log</summary>

Considered alternatives to the skip:

1. **Compare against `github.event.before`** on push events. Rejected:
the before-SHA is frequently unreachable in a `fetch-depth: 1` clone,
and wiring it in requires per-workflow env changes that complicate
backports.
2. **Fetch `origin/main` / deepen history** in the release lint job.
Rejected for the same backport-surface reason and because it only masks
the design intent.

The check exists to stop *new* emdashes from landing via PRs; that gate
already ran on the originating PRs. On non-PR builds there is no
meaningful diff base, so skipping is correct and self-contained in the
script (clean to backport). The explicit `--all` mode is preserved for
intentional full-tree audits.

</details>

---
Generated by Coder Agents on behalf of @f0ssel.
2026-06-17 16:30:48 -04:00
Jeremy Ruppel 1546a0a58f feat: add BaseTemplateParametersStep (#26426)
Implement the base template parameters wizard step, which renders a
configuration form for base template variables using the existing
`TemplateConfiguration` and `ConfigurationField` components.

- Map `TemplateBuilderModuleVariable` to `ConfigurationFieldDefinition`
(switch for bool, text input for string/number)
- Read variable definitions from the cached bases query
- Disable Continue button until all required non-sensitive variables
have values (`baseParametersComplete` helper)
- Step is automatically skipped when the selected base has no parameters
(e.g. Docker)
- Update `toComposeRequest` to include `base_variable_values` in the API
payload

Relates to [DEVEX-284](https://linear.app/codercom/issue/DEVEX-284).

> [!NOTE]
> This PR was authored with Coder Agents.
2026-06-17 14:56:52 -04:00
Ben Potter 787392ef16 ci: add docs-path redirect audit to weekly-docs workflow (#26472)
Closes
[DOCS-257](https://linear.app/codercom/issue/DOCS-257/b-vitest-validate-docs-literals-against-docsmanifestjson)

Extends `weekly-docs` with a new `audit-docs-paths` job that
cross-references TS/TSX `docs()` calls against
`coder.com/redirects.json` and fails when any path resolves via a
redirect (i.e. is stale). Also fixes two bugs in the existing
`check-docs` job:

- **Scheduled runs were a no-op** — `github-pr-review` reporter silently
exits 0 without a PR context. Now uses `local` reporter on schedule so
broken links actually fail the job.
- **Slack notification was broken** — payload used `"msg"` (invalid)
instead of `"text"` (the standard Slack webhook field).

Sample Slack output:

![slack-notification-sample](https://i.imgur.com/N6E7d9s.png)

Safe to merge in any order relative to #25740 — the audit job checks for
the script and skips gracefully if not yet available.

---

> Generated by [Coder Agents](https://coder.com) on behalf of @bpmct.
2026-06-17 11:59:35 -05:00