Commit Graph
13890 Commits
Author SHA1 Message Date
Michael Suchacz 60186b2489 refactor(site/src): split Agent Settings Behavior into focused destinations (#24574)
Reorganizes Agents Settings navigation. Previously a flat sidebar with
admin items gated by a role check; now a two-level drill-down with user
settings at the top and admin destinations nested under a "Manage
Agents" sub-panel.

**Top Settings panel** (all users, sidebar title "Settings"):

| Destination | Route |
| --- | --- |
| General | `/agents/settings/general` |
| Compaction | `/agents/settings/compaction` |
| Secrets (API keys) | `/agents/settings/api-keys` |
| Manage Agents › (admin only) | drills into the admin sub-panel |

**Manage Agents sub-panel** (admin only, sidebar title "Manage Agents"):

| Destination | Route |
| --- | --- |
| Agents | `/agents/settings/agents` |
| Providers | `/agents/settings/providers` |
| Models | `/agents/settings/models` |
| MCP Servers | `/agents/settings/mcp-servers` |
| Templates | `/agents/settings/templates` |
| Spend | `/agents/settings/spend` |
| Instructions | `/agents/settings/instructions` |
| Experiments | `/agents/settings/experiments` |
| Lifecycle | `/agents/settings/lifecycle` |
| Insights | `/agents/settings/insights` |

On mobile, tapping "Manage Agents" lands on `/agents/settings/admin`, an
admin sub-panel index URL that shows the admin nav in the sidebar (so
admins can still reach every admin destination without desktop-width
viewports).

Key changes:

- **Split the monolithic Behavior page into five focused destinations**
(General, Compaction, Instructions, Experiments, Lifecycle) so non-admin
users no longer trigger deployment-scoped queries like
`chatSystemPrompt`, `chatDesktopEnabled`, or `chatWorkspaceTTL`.
Admin-only pages gate both route (via `RequirePermission`) and query
`enabled` flags.
- **Split chat debug logging into audience-specific components** so no
admin-gated controls remain in user-facing pages.
`AdminChatDebugLoggingSettings` (admin "Let users record chat debug
logs") now lives in the Experiments tab; `UserChatDebugLoggingSettings`
("Record debug logs for my chats") stays in General and only renders
when the admin has allowed user-level toggling.
- **Nested admin sub-panel** in the sidebar. `SidebarView` gains a
`"settings-admin"` panel; `sidebarViewFromPath` routes admin sections
into it. The slide animation and back button behavior extend cleanly. A
small `isSettingsView` helper was extracted alongside to avoid
duplicating the panel-membership check.
- **Renamed `/agents/settings/system-instructions` to
`/agents/settings/instructions`**. Sidebar label is "Instructions". Page
files renamed to `AgentSettingsInstructionsPage(View)` to match the
route slug (the other split pages all do).
- **Renamed "API Keys" to "Secrets (API keys)"** in the sidebar and page
header.
- **Added MCP Servers** entry to the sidebar (route already existed).
- **Added "Manage Coder Agents"** link at the bottom of the Deployment
settings sidebar (gated by `editDeploymentConfig`, matches the existing
`Groups ↗` external-link style).
- **Updated icons** across the sidebar: General uses `UserIcon`,
Compaction `ShrinkIcon`, Secrets `KeyIcon`, Manage Agents
`Settings2Icon`, Providers `PlugIcon`, MCP Servers `ServerIcon`, Spend
`CoinsIcon`, Instructions `ReceiptTextIcon`, Lifecycle `RefreshCwIcon`,
Insights `SparklesIcon`.
- **Storybook interaction coverage** restored and extended for the split
views: user-prompt save flow, invisible-Unicode warning detection,
system-prompt default toggle, workspace-TTL validation, virtual-desktop
toggle, compaction threshold save/reset/validation, retention
toggle/save-error/load-error parity, plan-mode instructions save, and a
mobile story verifying the admin sub-panel remains reachable after the
"Manage Agents" tap.
- **Unit tests** added for `sidebarViewFromPath` and `isSettingsView`
(17 cases covering chats, analytics, user sections, admin sections, the
new `/admin` index, non-admin fallthrough, and defaults).

> Mux opened this PR on behalf of Mike.
2026-04-22 17:45:29 +02:00
Paweł Banaszewski e00e85765b chore: move aibridge library code into coder repo (#24190)
This PR merges code from `coder/aibridge` repository into `coder/coder`.
It was split into 4 PRs for easier review but stacked PRs will need to
be merged into this PR so all checks pass.

* https://github.com/coder/coder/pull/24190 -> raw code copy (this PR,
before merging PRs on top of it, it was just 1 commit:
https://github.com/coder/coder/commit/70d33f33200c7e77df910957595715f81f9bec24)
* https://github.com/coder/coder/pull/24570 -> update imports in
`coder/coder` to use copied code
* https://github.com/coder/coder/pull/24586 -> linter fixes and CI
integration (also added README.md)
* https://github.com/coder/coder/pull/24571 -> added exclude to
scripts/check_emdash.sh check

Original PR message (before PR squash):
Moves coder/aibridge code into coder/coder repository.

Omitted files:

- `go.mod`, `go.sum`, `.gitignore`, `.github/workflows/ci.yml,`
`Makefile`, `LICENSE`, `README.md` (modified README.md is added later)
- `.github`, `example`, `buildinfo,` `scripts` directories

Simple verification script (will list omitted files)

```
tmp=$(mktemp -d)
echo "$tmp"
git clone --depth=1 https://github.com/coder/aibridge "$tmp/aibridge"
git clone --depth=1 --branch pb/aibridge-code-move https://github.com/coder/coder "$tmp/coder"
diff -rq --exclude=.git "$tmp/aibridge" "$tmp/coder/aibridge"
# rm -rf "$tmp"
```
2026-04-22 17:01:01 +02:00
Marcin Tojek ec91ac5427 fix: grant AsAIBridged ResourceSystem.ActionCreate for UpsertAISeatState (#24603)
Related coder/internal#1444
2026-04-22 16:38:57 +02:00
Ehab Younes 3362b5ae7e fix: infer workspace from env in coder support bundle (#24617)
When running `coder support bundle` inside a workspace without arguments, the command now infers the workspace and agent from the `CODER_WORKSPACE_NAME`, `CODER_WORKSPACE_OWNER_NAME`, and `CODER_WORKSPACE_AGENT_NAME` environment variables set by the workspace agent.

Previously, running without arguments inside a workspace produced an incomplete bundle with no workspace info, agent logs, or connection diagnostics, despite the environment having all the information needed to resolve the current workspace.

Also updates the usage string from `<workspace>` to `[<workspace>]` to reflect that the argument has always been optional.

Closes #24615
v2.33.0-rc.3
2026-04-22 17:21:28 +03:00
Michael Suchacz 9b5d09ebdc test(coderd/x/chatd): seed anthropic provider for computer_use tests (#24611)
`TestSubagentLifecycleToolsIncludePersistedSubagentTypeAcrossVariants/ComputerUse`
and two adjacent positive tests passed a static Anthropic key into
`newInternalTestServer`, but `seedInternalChatDeps` only inserts an
OpenAI
provider. At runtime, `Server.resolveUserProviderAPIKeys` calls
`chatprovider.PruneDisabledProviderKeys`, which clears `keys.Anthropic`
because Anthropic is not in the enabled DB provider set, so the
`computer_use` execution path loses its key.

Add a focused test helper `seedEnabledAnthropicProvider` and use it only
in
the positive tests that actually drive a `computer_use` spawn through
the
runtime key-resolution path (the `computer_use` branch of
`TestSubagentLifecycleToolsIncludePersistedSubagentTypeAcrossVariants`,
`TestSpawnAgent_ComputerUseUsesComputerUseModelNotParent`, and
`TestSpawnAgent_ComputerUseInheritsMCPServerIDs`).
`seedInternalChatDeps`
stays unchanged, so the negative availability tests continue to model
the
"Anthropic unavailable" fixture. No production code is modified.

Closes https://github.com/coder/internal/issues/1486

> This PR was opened by Mux working on Mike's behalf.
2026-04-22 15:54:17 +02:00
Thomas Kosiewski 5c316d4252 test(site/src/pages/AgentsPage): add Debug panel Storybook stories (#23921)
## Summary

Add comprehensive Storybook stories covering the Debug panel in various states: loading, empty, single/multiple runs, expanded steps, tool calls, error states, and streaming indicators.

This is PR 9/9 in the chat debug logging stack.

### Changes

- **DebugPanel stories** (`site/src/pages/AgentsPage/components/RightPanel/DebugPanel/DebugPanel.stories.tsx`): Storybook stories with `play` functions for interaction testing, covering:
  - Loading state
  - Empty / disabled state
  - Single-step successful run
  - Multi-step run with tool calls
  - Error state with redacted headers
  - Compaction and title generation run kind badges
  - Long raw request/response payload rendering
  - Streaming / in-progress indicators

### Stack overview

1. Database schema & SDK types
2. Types, context, and model normalization
3. Recorder, transport, and redaction
4. Service and summary aggregation
5. Chat lifecycle wiring
6. HTTP handlers and API docs
7. Frontend API layer and panel utilities
8. Debug panel components and settings
9. **→ Storybook stories** (this PR)

---
_Generated with [`mux`](https://github.com/coder/mux) • Model: `anthropic:claude-opus-4-6` • Thinking: `xhigh`_
2026-04-22 15:44:32 +02:00
Thomas Kosiewski 249b71b96a feat(site): add Debug panel components and settings (#23920)
## Summary

Add the Debug panel UI components: run list, run cards, step cards with transcript and tool-call rendering, attempt accordions, and shared primitives. Wire the panel into the AgentChatPage sidebar and add the per-chat debug logging toggle in the behavior settings page.

This is PR 8/9 in the chat debug logging stack.

### Screenshots

Settings Page

<img width="4608" height="2348" alt="CleanShot 2026-04-21 at 21 19 36@2x" src="https://github.com/user-attachments/assets/69391465-4c56-468a-9923-59576d326963" />

Conditional Debug tab

<img width="4608" height="2348" alt="CleanShot 2026-04-21 at 21 19 58@2x" src="https://github.com/user-attachments/assets/bc1e07cb-21d9-40e7-8928-6fd9a7ec7f57" />

Last request's tools and schema 

<img width="4608" height="2348" alt="CleanShot 2026-04-21 at 21 20 03@2x" src="https://github.com/user-attachments/assets/401f26af-98ce-443f-a586-424d3636d98b" />

"Raw" JSON request bodies

<img width="4608" height="2348" alt="CleanShot 2026-04-21 at 21 20 35@2x" src="https://github.com/user-attachments/assets/3605a373-9e29-4183-89e7-8b2704ff9333" />


### Changes

- **DebugPanel** (`site/src/pages/AgentsPage/components/RightPanel/DebugPanel/DebugPanel.tsx`): top-level panel component owning data fetching and subscription lifecycle.
- **DebugRunCard**: compact single-row header with capitalized provider name, status badge, compact duration (`1.3s`), and token summary (`3→5 tok`). Expandable to show child step cards.
- **DebugStepCard**: step inspector with normalized transcript rendering — system prompts, assistant text with 160-char clamping + independent "see more/less" toggle, tool calls with fully-expanded JSON payloads in `CopyableCodeBlock`.
- **DebugAttemptAccordion**: nested accordion for HTTP-level attempt details showing request/response headers and bodies.
- **Shared primitives**: `CopyableCodeBlock`, `MessageRow`, `ToolPayloadDisclosure`, `StatusBadge`.
- **Sidebar wiring** (`AgentChatPageView.tsx`): adds the Debug tab to the right panel when debug logging is enabled.
- **Behavior settings**: deployment-wide and per-user debug logging toggles on the settings page.

### Stack overview

1. Database schema & SDK types
2. Types, context, and model normalization
3. Recorder, transport, and redaction
4. Service and summary aggregation
5. Chat lifecycle wiring
6. HTTP handlers and API docs
7. Frontend API layer and panel utilities
8. **→ Debug panel components and settings** (this PR)
9. Storybook stories

---
_Generated with [`mux`](https://github.com/coder/mux) • Model: `anthropic:claude-opus-4-6` • Thinking: `xhigh`_
2026-04-22 15:34:32 +02:00
Thomas Kosiewski 8c0fe6d5f2 feat(site): add chat debug API layer and panel utilities (#23919)
## Summary

Add API client methods, React Query builders, and unit tests for the chat debug endpoints. Add `debugPanelUtils` with coercion helpers that transform raw debug step data into structured display models for the Debug panel, and wire debug run streaming into the chat store.

This is PR 7/9 in the chat debug logging stack.

### Changes

- **API client** (`site/src/api/api.ts`): typed methods for all debug endpoints — list runs, list steps, get/set deployment logging, get/set user logging, set per-chat override.
- **React Query builders** (`site/src/api/queries/chats.ts`): `chatDebugRuns`, `chatDebugSteps`, `chatDebugLoggingConfig`, `userDebugLoggingConfig` query/mutation factories with `refetchInterval: 5000` for live polling.
- **Debug panel utilities** (`site/src/pages/AgentsPage/components/RightPanel/DebugPanel/debugPanelUtils.ts`): `coerceStepRequest` / `coerceStepResponse` that recursively parse nested JSONB into `StepRequestViewModel` / `StepResponseViewModel` with `MessagePart`, `ToolDef`, and `ToolCallPart` types. Includes `formatTokenSummary` (compact `3→5 tok` notation) and `compactDuration` helpers.
- **Unit tests**: coverage for coercion edge cases and formatting utilities.

### Stack overview

1. Database schema & SDK types
2. Types, context, and model normalization
3. Recorder, transport, and redaction
4. Service and summary aggregation
5. Chat lifecycle wiring
6. HTTP handlers and API docs
7. **→ Frontend API layer and panel utilities** (this PR)
8. Debug panel components and settings
9. Storybook stories

---
_Generated with [`mux`](https://github.com/coder/mux) • Model: `anthropic:claude-opus-4-6` • Thinking: `xhigh`_
2026-04-22 15:24:32 +02:00
Thomas Kosiewski b7c2c59931 fix(coderd/x/chatd/chatdebug): allow Anthropic per-modality ratelimit headers (#24592)
Previously, Anthropic's per-modality, Priority Tier, and fast-mode rate-limit headers (`Anthropic-Ratelimit-Input-Tokens-*`, `Anthropic-Ratelimit-Output-Tokens-*`, `Anthropic-Priority-Input-Tokens-*`, `Anthropic-Priority-Output-Tokens-*`, `Anthropic-Fast-Input-Tokens-*`, and `Anthropic-Fast-Output-Tokens-*`) were shown as `[REDACTED]` in the Debug panel because they contain `"token"` in the name and fell through the generic credential filter.

Add them to the allowlist in `coderd/x/chatd/chatdebug/redaction.go` alongside the existing `Anthropic-Ratelimit-Tokens-*` entries so the limits/remaining/reset values surface in the raw response view.
2026-04-22 15:14:31 +02:00
Thomas Kosiewski 26b64fa523 fix(coderd/x/chatd/chatdebug): record SSE attempts on EOF (#24565)
`chat_turn` debug steps persist with `attempts: []` even when the
streaming call to Anthropic completes successfully. Fantasy's
Anthropic SSE adapter iterates the response to EOF via
`for stream.Next()` and abandons the body without calling `Close()`,
so `RecordingTransport`'s Close-only recording path never fires and
the attempt is lost. Non-streaming runs (`quickgen`,
`title_generation`) go through `model.Generate(...)` and are
unaffected.

Record on `io.EOF` for `text/event-stream` bodies specifically.
Non-SSE responses stay on the Close-only path so JSON integrity,
content-length validation, and inner-`Close()` error semantics are
preserved. `record()` is already `sync.Once`-guarded, so a later
`Close()` is a no-op for recording.
2026-04-22 15:02:02 +02:00
Michael Suchacz 9634739aed fix: support Bedrock ambient AWS credentials for Agents providers (#24397)
> This PR was authored by Mux on behalf of Mike.

Adds AWS Bedrock ambient credential support to the Agents provider path.
Bedrock providers can now be saved without a stored API key and
authenticated via the standard AWS SDK credential chain on the Coder
server (IAM roles, `AWS_ACCESS_KEY_ID`, etc.). Also fixes missing `Base
URL` forwarding for Bedrock.

## Changes

**Backend runtime** (`coderd/x/chatd/chatprovider/chatprovider.go`):
- New `ProviderAllowsAmbientCredentials(provider)` helper. Currently
returns true only for Bedrock.
- `ModelFromConfig` no longer errors on an empty API key when the
provider is in the ambient-allowed set AND was explicitly resolved via
`ByProvider`. This preserves the policy gate: unresolvable providers
(disabled central key, user-key-required without a user key) still
error.
- `setResolvedProviderAPIKey` internalizes the ambient-credentials
contract via `ProviderAllowsAmbientCredentials`, so a
resolved-but-keyless Bedrock provider is represented as an empty
`ByProvider` entry rather than a post-hoc sentinel patch in the caller.
- `WithAPIKey` is only appended when a token is present.
- `WithBaseURL(baseURL)` is now forwarded for Bedrock (was previously
missing).

**Backend admin API** (`coderd/exp_chats.go`):
- `validateChatProviderCentralAPIKey` exempts Bedrock from requiring a
stored API key when central credentials are enabled.
- AI Gateway separation (`ChatProviderAPIKeysFromDeploymentValues`) is
unchanged. No silent reuse of `CODER_AIBRIDGE_BEDROCK_*` flags.

**Frontend**
(`site/src/pages/AgentsPage/components/ChatModelAdminPanel/*`):
- API Key field is optional for Bedrock when central credentials are
enabled.
- Bedrock-specific descriptions on API Key and Base URL fields
(bearer-token vs ambient modes, `AWS_REGION` guidance).
- Right-aligned "Clear stored token" action switches an existing Bedrock
provider back to ambient mode.
- `hasEffectiveAPIKey` treats Bedrock with central credentials enabled
as configured, so the provider list shows the correct status icon.
- Three new stories: `ProviderFormBedrockAmbientCredentials`,
`ProviderFormBedrockBearerToken`, `ProviderFormBedrockClearBearerToken`.

**Docs** (`docs/ai-coder/agents/models.md`,
`docs/ai-coder/ai-gateway/setup.md`):
- New "Configuring AWS Bedrock" section covering both credential modes,
region resolution, and the Base URL override.
- Explicit note that the `us-east-1` region fallback only applies to
bearer-token mode; ambient credentials require a region from the
standard AWS SDK chain.
- Cross-reference in AI Gateway docs clarifying that
`CODER_AIBRIDGE_BEDROCK_*` flags are a separate configuration path from
Agents.

## Not in scope

- Reusing AI Gateway Bedrock flags as an implicit Agents fallback.
- Per-provider AWS access key, secret, or region fields (would need a
migration and audit-table review).
- IMDS or network-backed credential probes in admin/listing request
paths.

## Related

Dogfood deployment integration:
https://github.com/coder/dogfood/pull/324
2026-04-22 14:20:23 +02:00
Mathias Fredriksson 78d9a220cf fix(coderd/x/chatd): detect disconnected agents in getWorkspaceConn (#24336)
Add agent status check and dial timeout to getWorkspaceConn to
prevent tool calls from hanging when a workspace agent disconnects.

Status check: call isAgentUnreachable on every getWorkspaceConn
call. On cache miss, check the freshly fetched agent row. On
cache hit, re-fetch the agent row by PK for a fresh heartbeat
timestamp. Disconnected and timed-out agents return a sentinel
immediately; connecting agents proceed to dial.

Dial timeout: wrap dialWithLazyValidation in a 30s
context.WithTimeoutCause (matching 8 other server-side AgentConn
callers). Parent context cancellation propagates unchanged so
the chatloop can detect ErrInterrupted.

Both sentinels tell the LLM the agent is unreachable and the
workspace may need restarting from the dashboard.

Closes CODAGT-149
2026-04-22 12:10:32 +00:00
Jakub Domeracki e3a1fb0c89 ci: pass github.repository through env var (#24605)
*Disclaimer: implemented by a Coder Agent using Claude Opus 4.*

---

Move `github.repository` from direct `${{ }}` interpolation in the
`run:`
block to an `env:` var, consistent with how `BRANCH` and `PR_NUMBER` are
already handled. This eliminates a `zizmor` template-injection finding.

Follows up on #24283.
2026-04-22 12:57:22 +02:00
Cian Johnston 38f5d3f0b2 test: add regression guard for chat title masking (#24584)
Follow-up to #24564 addressing unresolved review findings.

- **DEREM-1**: Add `Test_diff/Chat/TitleMasked` to
`enterprise/audit/diff_internal_test.go` so flipping `title` back to
`ActionTrack` fails loudly. Verified: the case passes today, fails with
a clear diff after flipping to `ActionTrack`, passes again after
reverting.
- **DEREM-4**: Inline comment at `coderd/audit/request.go:138`
explaining why `ResourceTarget` for `database.Chat` returns a UUID
prefix instead of the title.
- **DEREM-5**: Trailing comment on `enterprise/audit/table.go` `title`
entry, matching the surrounding `ActionSecret` comment style.

Won't-fix, with rationale (per user):

- **DEREM-2** (8-char prefix collision risk): `resource_target` is a
display hint, not an identifier; the full UUID lives in `resource_id`.
- **DEREM-3** (named constant for `[:8]`): single call site; extracting
would be ceremony.
- **DEREM-6** (PR title misleading): merged PR title is immutable.
- **DEREM-7** (historical log redaction): the offending version only
shipped to dogfood for a couple of hours and not to customers.

> 🤖
2026-04-22 10:52:52 +00:00
Jakub Domeracki 86b2db60b2 fix(coderd): enforce ActionSSH in MCP HTTP agent connection path (#24607) 2026-04-22 12:34:17 +02:00
Ethan cc4e04afde feat(site): display file attachments in chat UI (#24281)
Renders the durable file attachments introduced in #24280 in the chat
interface. Without this, attachments were stored and served correctly
but the UI showed raw file parts with no previews or download UX.

Every attachment gets a download affordance, split into three rendering
tiers:

- **Images** — thumbnail with a hover/focus overlay containing a
download link. `onFocusCapture`/`onBlurCapture` with
`contains(relatedTarget)` keeps the overlay open while tabbing between
the image and its download link.
- **Text-like files** (`text/*`, `application/json`) — expandable
preview button with loading + error-with-retry states and the same
download overlay. Preview fetches throw a typed
`FetchTextAttachmentError` with a `.status` field instead of a
stringly-typed error.
- **Everything else** — compact `FileCard` with extension badge,
filename, and download link.

User-side and assistant-side rendering now share `AttachmentBlocks.tsx`
(`AttachmentPreviewFrame`, `TextAttachmentButton`,
`ImageAttachmentButton`, `FileCard`, plus
`getAttachmentHref`/`getAttachmentName`) instead of two near-duplicate
implementations. The text-attachment overlay anchors to the preview
surface so the download button stays pinned even when a loading/error
status line widens the row below.

`ComputerRenderer` detects when a screenshot was stored as a durable
attachment (`attachment_file_id`) and suppresses the stale base64
rendering — the screenshot appears as a proper file part instead.
`ToolLabel` shows the attached filename for `attach_file` tool calls.

Storybook coverage in `ConversationTimeline.stories.tsx` was expanded to
cover every tier (single/multiple images, inline + file-id text, JSON,
download-only files, fetch-failure retry, mixed attachments + file
references) with play-function assertions.

<img width="811" height="150" alt="image"
src="https://github.com/user-attachments/assets/27c71081-3502-4e80-92a7-d8adf1ff9323"
/>



## Cleanup

Per Mathias' post-merge suggestion on #24280, this PR also relocates
`coderd/chatfiles` → `coderd/x/chatfiles` so the durable-attachment
helpers live beside the rest of the `chatd` experimental surface.

Closes CODAGT-91
2026-04-22 20:11:53 +10:00
Ethan ad1906589d fix(coderd): allow deleting chat providers used in historical chats (#24568)
Drop the `chat_model_configs.provider -> chat_providers.provider`
foreign key and soft-delete model configs when their provider is
removed. The provider row is now hard-deleted inside a transaction that
also tombstones its model configs and promotes a replacement default
when needed.

Historical chats and messages keep pointing at the soft-deleted model
config rows, which are hidden from live/admin queries but still resolve
for read. The runtime chat path already falls back to the default model
config when a soft-deleted config is looked up.

Replaces the lost FK validation in the create/update model-config
handlers with an explicit provider lookup that returns the existing
`Chat provider is not configured.` 400.

## UX

**Admin deleting a chat provider that has historical usage**

- Before: blocked with 400 `Provider models are still referenced by
existing chats.` Admins had no in-product way to remove a provider that
had ever been used.
- After: delete succeeds (204). Any model configs under that provider
are soft-deleted. If the removed provider owned the default model
config, one of the remaining live configs is auto-promoted to the new
default. The promotion is deterministic (`ensureDefaultChatModelConfig`
picks the first live config by `provider ASC, model ASC, updated_at
DESC, id DESC`); there is no picker, and no toast or response detail
names which config became the new default.

**End users with chats that used a deleted provider's model**

- Old chats still open and their history still renders unchanged.
- Sending a new turn in such a chat silently falls back to the current
default model. No banner or warning tells the user the original model is
gone.
- The model picker no longer lists the deleted model.
- If no default model config exists at all after the delete, sending a
new turn fails with `no default chat model config is available`.

**Admin creating or updating a model config against a provider that is
not configured**

- Same as before: 400 `Chat provider is not configured.` Only the
detection mechanism changed (explicit `FOR UPDATE` lookup inside the
transaction, which also serializes against a concurrent provider
delete).

**Admin updating a model config whose row disappears mid-transaction**

- Now returns the standard 404 `Resource not found or you do not have
access to this resource` instead of the previous 500 that leaked `sql:
no rows in result set` in the detail. Unrelated internal races (for
example a race on the promoted default candidate) are still reported as
500 so they are not misclassified as "your target is gone".

Closes CODAGT-23
2026-04-22 19:34:34 +10:00
Cian Johnston 360e119b43 fix(coderd): use waitChatSettled in remaining title tests (#24585)
- Replace inline `require.Eventually` blocks in `PreservesUpdatedAt` and
`NoOpWhenTitleUnchanged` with the shared `waitChatSettled` helper
- These were the last two title subtests still using direct DB polling
instead of the API-based helper

> 🤖
2026-04-22 09:14:25 +01:00
christin 5cce3ee5f4 refactor(site): rename border-hover token to border-secondary (#24553)
Renames the `--border-hover` design token to `--border-secondary` and
updates the color values to work well on `surface-secondary`
backgrounds, preparing for the template creation flow.

- Light theme: `240 5% 65%` (`#A1A1AA`)
- Dark theme: `240 5% 26%` (`#3F3F46`)

All 7 component usages updated to use the new token name.

<details>
<summary>Context</summary>

The previous `border-hover` token used a single value (`#52525B`) for
both themes, which didn't provide enough contrast on `surface-secondary`
backgrounds. The rename to `border-secondary` better reflects its
semantic role as a secondary border color rather than a hover-specific
one, and the updated values give proper contrast in both light and dark
themes. This change is a prerequisite for the upcoming template creation
flow work.

</details>

> 🤖 Generated by Coder Agents
2026-04-22 09:54:28 +02:00
Danny Kopping d3cc23d8ba ci: post docs preview link on PRs that change docs (#24283)
*Disclaimer: implemented by a Coder Agent using Claude Opus 4.6*

---

Adds a lightweight workflow that posts a docs preview link as a PR
comment
whenever a pull request touches files under `docs/`. The preview is
served
by coder.com's branch-preview feature at `/docs/@<branch>`.

The branch name is URL-encoded so names with slashes (e.g.
`user/feature`) produce correct links like
`/docs/@user%2Ffeature` instead of broken paths.

The comment is created on open and updated in-place on subsequent pushes
using the `peter-evans/find-comment` + `create-or-update-comment`
pattern
already used by the `pr-deploy` workflow.

---

Depends on https://github.com/coder/coder.com/pull/708
2026-04-22 09:46:00 +02:00
Jaayden Halko b62881eb85 fix(site): add bottom spacing for no-renderable assistant fallback messages (#24551)
closes CODAGT-125

Assistant messages that show only the fallback text ("Message has no
renderable content.") were missing bottom spacing before the next user
bubble, because `needsAssistantBottomSpacer` only covered reasoning-only
and sources-only cases.

Extend the spacer predicate to also trigger when
`!hasRenderableContent`, and add a `data-testid` to the spacer element
for testability. A new Storybook story
(`NoRenderableContentFallbackSpacing`) covers this regression.
2026-04-22 08:04:55 +01:00
Ethan 353e522614 fix: handle expired chat file attachments in replay and UI (#24518)
Closes CODAGT-216

## Problem

`dbpurge` deletes `chat_files` rows after the deployment's configured
retention window, but `chat_messages.content` can still contain
`file_id` references to those files. On replay, that left the Anthropic
provider with an empty file payload and a `400 image cannot be empty`
error. In the UI, the same missing file showed up as a broken image.

## Fix

- Backend: when replay hits a `file_id` whose bytes are gone, replace it
with a short text placeholder instead of emitting an empty file part. We
could also drop the missing attachment entirely, but that would silently
remove context from the replay and make the conversation harder for the
model to interpret. The placeholder keeps the request valid while still
telling the model that a file used to be there and is no longer
available.
- Frontend: classify chat image failures instead of treating every
broken image the same.
- `404` file fetches render `Image expired`, with a tooltip explaining
that chat attachments are deleted after the retention window set for the
deployment.
- Other remote failures render `Image failed to load`, with a tooltip
that surfaces server/network detail when available.
- Invalid inline image data still renders `Image failed to load` without
a probe.
2026-04-22 14:10:51 +10:00
david-fraley f77827e84a feat: rebucket "Number of developers" onboarding options (#24573) 2026-04-21 15:11:50 -05:00
blinkagent[bot] 79a9f437d7 feat(coderd/x/chatd/chattool): add description tags to tool parameter structs (#24394) 2026-04-21 11:37:29 -07:00
Danielle Maywood 7f4127bc61 feat(site/src/pages/AgentsPage): show MCP settings and hide insights in sidebar (#24428) 2026-04-21 17:53:17 +01:00
Jaayden Halko 148e56b5d9 fix(coderd): fix TestPatchChat/Title flake by waiting for chat to settle (#24572)
## Problem

`TestPatchChat/Title/Rename` and `TestPatchChat/Title/TrimsWhitespace`
fail intermittently on `test-go-pg` with:

```
PATCH .../api/experimental/chats/<id>: unexpected status code 409:
Title regeneration already in progress for this chat.
```

`createChat` persists a chat with `ChatStatusPending` and signals the
daemon wake loop. If the `UpdateChat` PATCH arrives before the daemon
transitions the chat past `Pending`/`Running`, the handler's
`acquireManualTitleLock` returns a 409. Whether the PATCH wins the race
is timing-dependent under PG + `-parallel` load.

Sibling subtests `PreservesUpdatedAt` and `NoOpWhenTitleUnchanged`
already wait for the chat to leave `Pending`/`Running` before renaming,
which is why they do not flake.

## Fix

Add a `waitChatSettled` helper closure in `TestPatchChat` that polls
`client.GetChat` until the chat status leaves `Pending`/`Running`.
Call it in the 4 subtests that issue a valid rename immediately after
`createChat`:

- `Title/Rename` (originally reported flake)
- `Title/TrimsWhitespace` (originally reported flake)
- `Title/LengthBoundaries` (latent flake in valid-rename cases)
- `Title/PublishesWatchEvent` (latent flake, goroutine silently 409s)

No handler, daemon, or SDK changes. The 409 is intentional production
behavior; this is a pure test-side timing fix.

Refs coder/internal#1480
2026-04-21 17:10:00 +01:00
Lukasz 869168b316 chore: bump gomarkdown to patched revision (#24567)
Updates `github.com/gomarkdown/markdown` from
`v0.0.0-20240930133441-72d49d9543d8` to
`v0.0.0-20260411013819-759bbc3e3207`.

This pulls in the patched upstream revision for the markdown dependency.
2026-04-21 14:46:32 +00:00
Jeremy RuppelandClaude Sonnet 4.6 b4eb0e20e5 fix(site): show startup script failure message without restart suggestion (#24449)
When a workspace agent's startup script fails, restarting the workspace
will not resolve the issue since the script will keep failing.
Previously all unhealthy workspaces showed the same generic notification
with a Restart button regardless of cause.

Now, when every failing agent has `lifecycle_state=start_error`, the
workspace-level notification shows "A startup script has failed" and
guides the user to contact their template admin instead of offering a
Restart action.

> Code written by Claude 🤖 reviewed by yours truly

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 10:40:32 -04:00
Ethan ef2b3a7263 fix: rebuild modeloptionsgen when codersdk changes (#24543)
`_gen/bin/modeloptionsgen` reflects over `codersdk` struct tags, but
reflection doesn't read source — Go struct tags are compile-time string
literals folded into the type descriptor and emitted into the binary's
`.rodata` section. `reflect.TypeOf(...).Field(i).Tag.Get("enum")` reads
from that baked-in table; the generator cannot consult
`codersdk/chats.go` on disk even if it wanted to.

That means the binary has to be rebuilt whenever those tags change. The
existing Makefile rule only depends on `scripts/modeloptionsgen/*.go`,
and the JSON target lists the binary as an order-only prereq, so `make
gen` happily runs the stale binary after edits to `codersdk/chats.go`
and writes outdated enum values.

Fix: add `$(wildcard codersdk/*.go)` to the binary's prereqs, matching
`clidocgen`. The whole-package wildcard is deliberate — a narrower
prereq would break if someone splits `chats.go`. Cost is negligible:
Go's per-package build cache means unrelated edits recompile one package
and re-link, and the JSON target's own prereqs are unchanged so it
doesn't regenerate.
2026-04-22 00:11:09 +10:00
Ethan c1421b4ead test(coderd/x/chatd): deflake stale control notification test (#24545)
Previously, `TestProcessChat_IgnoresStaleControlNotification` could
return as soon as `UpdateChatStatus` ran, even though `processChat`
still re-read chat state and finished deferred cleanup afterward. That
let gomock and quartz teardown race the tail of cleanup and
intermittently fail the test.

Wait for `processChat` itself to return before asserting the final
status, while keeping the existing strict mock expectations intact.

Closes https://github.com/coder/internal/issues/1479
2026-04-22 00:08:34 +10:00
Ethan 2295e9d5be feat: surface upstream provider error details in chat callout (#24546)
Anthropic HTTP 400 responses (e.g. "image exceeds 5 MB maximum") were
collapsed in the chat UI to the generic headline "Anthropic returned an
unexpected error (HTTP 400)." with no actionable detail — the upstream
message survived to the processor log but was dropped before reaching
the client.

Add a new optional `Detail` field on `codersdk.ChatStreamError` that
carries the upstream provider message alongside the existing normalized
headline. The backend extracts `error.message` from
`fantasy.ProviderError.ResponseBody` (the JSON envelope shared by
Anthropic and OpenAI), falls back to the trimmed provider message when
the body is absent or unparseable, and caps the result at 500 runes. The
frontend threads `Detail` through `useChatStore`, `liveStatusModel`, and
`ChatStatusCallout`, rendering it as a muted secondary line inside the
existing `AlertDescription`.

Before:

<img width="1552" height="185" alt="image"
src="https://github.com/user-attachments/assets/524b588e-3cee-4fad-bc15-6bf3aec0899d"
/>

After:

<img width="814" height="173" alt="image"
src="https://github.com/user-attachments/assets/eae82a89-3ac1-4a33-8d18-ef9f77263d89"
/>

## Persistence

`Detail` is **not** persisted — it disappears on refresh. Persisting it
would require a DB change (today `chats.last_error` is a single nullable
`TEXT` column), and the shape of persisted chat errors is worth a more
deliberate rethink — e.g. promoting `last_error` to `JSONB` so we can
also retain structured fields like `kind`, `statusCode`, `provider`, and
`retryable` instead of only the normalized headline string. That's a
bigger design discussion than this PR should carry.

In the meantime, seeing the upstream error reason *immediately on
failure* is already a large UX improvement over the status quo, and this
PR gets us there without prejudicing the eventual persistence design.
Tracking persistence in CODAGT-239.

Closes CODAGT-235
2026-04-22 00:05:27 +10:00
Jake Howell 2b8a2c9c5d fix(site/e2e): wait for file upload before submitting create template form (#24548)
> 🤖 This PR was written by Coder Agent on behalf of Jake Howell

Fixes https://github.com/coder/internal/issues/1419

The `createTemplate` e2e helper clicks Save immediately after
`setInputFiles`, but the file upload API call is fire-and-forget through
the React component chain (`FileUpload.onChange` →
`CreateTemplateForm.onUpload` → `UploadTemplateView.onUpload` — none of
which `await` the returned promise up the chain).

If the upload mutation has not settled when the form submits,
`uploadedFile` (`uploadFileMutation.data`) is still `undefined`, and the
`uploadedFile!.hash` non-null assertion throws a `TypeError`. Formik
silently swallows the rejected promise, so the page stays on
`/templates/new` and the URL assertion times out.

The fix waits for the "Remove file" button to appear after
`setInputFiles`. That button only renders when `!isPending && variables`
— i.e. the upload mutation has succeeded and the hash is available.
2026-04-21 23:34:10 +10:00
Cian Johnston 4d45b69b03 fix: stop tracking chat title in audit logs (#24564)
Chat titles can contain sensitive information (secrets, internal project
names, etc.) and should not be visible in audit logs.

- Use truncated chat UUID (first 8 chars) as `resource_target` instead
of the title
- Mark the `title` field as `ActionSecret` so diffs render as `••••••••`

<details><summary>Implementation notes</summary>

Two changes:
1. `coderd/audit/request.go`: `ResourceTarget` for Chat returns
`typed.ID.String()[:8]` instead of `typed.Title`
2. `enterprise/audit/table.go`: Chat `title` field tracking changed from
`ActionTrack` to `ActionSecret`

No frontend changes needed. The frontend already handles `secret: true`
fields.

</details>

> 🤖
2026-04-21 14:26:22 +01:00
Jake Howell a62c0c1afc fix(site): fix flaky TemplateVariablesPage submit test (#24459) 2026-04-21 23:24:27 +10:00
Michael Suchacz f073323c89 refactor: unify subagent spawn behind spawn_subagent (#24535)
Unify the three subagent spawn tools (`spawn_agent`,
`spawn_explore_agent`, `spawn_computer_use_agent`) behind a single
`spawn_subagent` tool keyed by a `subagent_type` discriminant
(`general`, `explore`, `computer_use`). Mirrors the single-entry-point
pattern already used by `task` in mux while keeping `wait_agent`,
`message_agent`, and `close_agent` as separate lifecycle tools.

A new backend subagent definition catalog
(`coderd/x/chatd/subagent_catalog.go`) is the source of truth for tool
description, prompt guidance, availability rules (plan mode,
desktop/Anthropic gating), and child-chat option building.
`spawn_subagent` advertises only the types available in the current
context and validates `subagent_type` server-side; context inheritance
still flows through the existing `createChildSubagentChatWithOptions`
path. `wait_agent`, `message_agent`, and `close_agent` responses now
include a server-derived `subagent_type` so the UI stops inferring
lifecycle state from tool names.

The frontend gets a shared normalization helper
(`site/src/pages/AgentsPage/components/ChatElements/tools/subagentDescriptor.ts`)
that maps either legacy tool names or new `spawn_subagent` args into a
common descriptor (action, variant, icon, fallback copy). Legacy
transcripts still render identically; `Tool.tsx`, `SubagentTool.tsx`,
`ToolLabel.tsx`, `ToolIcon.tsx`, and `messageParsing.ts` now key off the
descriptor instead of hard-coded names. Existing UI copy is preserved
(`Spawning Explore agent...`, `Using the computer...`, computer-use
monitor icon and Open Desktop affordance).

> This PR was opened by Mux working on Mike's behalf.
2026-04-21 14:01:32 +02:00
Cian Johnston f56adf5731 fix(enterprise/coderd/x/chatd): deflake TestSubscribeRelayDrainWithinGraceLeavesBufferRetained (#24549)
Fixes the flake reported in
https://github.com/coder/internal/issues/1474.

- Use a `quartz.NewMock` clock for the subscriber with a drain timer
trap, so the 200ms relay drain fires only when explicitly advanced —
fully deterministic, no wall-clock race
- Give each `testutil.Eventually` call its own context so one slow
assertion cannot starve subsequent ones of their shared 25s deadline

> 🤖
2026-04-21 11:20:32 +00:00
Michael Suchacz cb67e71835 fix(coderd/database): renumber duplicate MCP migration (#24552)
## Summary
- rename the `allow_in_plan_mode` migration pair from `000472` to
`000473`
- rename the matching fixture file and update its comment
- remove the duplicate migration version that broke containerized
database startup

## Testing
- `go test ./coderd/database/migrations -run '^TestMigrate$' -count=1
-timeout 15m`
- validated `iofs.New` for `coderd/database/migrations` and
`coderd/database/migrations/testdata/fixtures`

Closes coder/internal#1483

> Mux opened this PR on Mike's behalf.
2026-04-21 11:10:17 +00:00
Mathias Fredriksson 623e72d72d chore: add no-emdash/endash rule to agent instructions and CI lint (#24375)
Add a lint check that prevents introduction of Unicode emdash (U+2014)
and endash (U+2013) characters. These are almost exclusively introduced
by AI agents and conflict with the project writing style.

The lint script (scripts/check_emdash.sh) checks only added lines in
the current diff by default, so existing violations do not block CI.
Pass --all to scan the entire repo for auditing.

Agent instructions in AGENTS.md, site/AGENTS.md, and the docs style
guide now explicitly ban emdash, endash, and " -- " as punctuation,
with guidance to use commas, semicolons, or periods instead.
2026-04-21 13:55:24 +03:00
Michael Suchacz 9d0469fc4c feat: allow approved external MCP tools in root plan mode (#24509)
## Summary

Allow root plan-mode chats to use MCP tools from external servers that
an admin has explicitly approved for plan mode. Workspace MCP and
plan-mode subagents remain blocked.

## Problem

`chatd.go` excluded every MCP tool when `isPlanModeTurn` was true, so
planning had no access to tools like docs search, ticketing, etc.
Lifting that guard wholesale was unsafe: `mcp_server_configs` already
has centralized admin governance, but workspace-local MCP (discovered
from agent `.mcp.json`) does not, and subagents use a narrower trust
boundary.

## Fix

Add an admin-controlled per-server `allow_in_plan_mode` flag (default
`false`) and gate plan-mode MCP access on it.

### Backend / schema
- New migration `000472_mcp_server_allow_in_plan_mode.{up,down}.sql` and
matching fixture update.
- `mcpserverconfigs.sql` + generated code: persist and read the new
column.
- `codersdk/mcp.go`: thread the field through `MCPServerConfig`,
`Create*`, and `Update*` request types.
- `coderd/mcp.go`: validate, persist, and return the flag in
get/list/create/update handlers.

### chatd
- `coderd/x/chatd/chatd.go`: pre-filter selected external MCP configs by
`AllowInPlanMode` before calling `mcpclient.ConnectAll` on plan-mode
root turns. Workspace MCP discovery is skipped entirely on plan-mode
turns.
- Single helper decides whether a tool is available in plan mode, used
both at construction and for active-tool filtering (defense in depth).
Plan-mode subagents, dynamic tools, provider-native tools, computer-use,
and workspace MCP stay unchanged.
- `coderd/x/chatd/prompt.go`: update the root plan-mode overlay text to
match the new boundary.

### UI
- `MCPServerAdminPanel.tsx`: add an explicit toggle ("Allow all tools
from this MCP server in root plan mode") next to the existing governance
controls.
- Regenerated `site/src/api/typesGenerated.ts`.

### Docs
- `docs/ai-coder/agents/architecture.md`: replace the blanket "MCP is
unavailable in plan mode" note with the new root-only, external-only,
admin-approved policy. Explicitly call out that workspace MCP and
plan-mode subagents are still excluded.

### Tests
- Plan-mode visibility (approved vs non-approved external server).
- Plan-mode invocation of an approved external MCP tool.
- End-to-end plan-mode workflow that uses an approved MCP tool and then
reaches `propose_plan`.
- Regressions: workspace MCP still excluded in plan mode; plan-mode
subagents still on the restricted tool boundary; existing tool
allow/deny list filtering still applies.

## Policy precedence

`allow_in_plan_mode` is an **additional** requirement on top of existing
`enabled`, availability, chat-selected / forced server IDs, and tool
allow/deny lists. It approves **all tools on that server** for root plan
mode; a per-tool plan allowlist is deliberately deferred.

## Follow-ups (explicitly out of scope)

- Whether plan-mode subagents should inherit approved external MCP
tools.
- Workspace-local MCP safety model (agent-side `.mcp.json` schema vs. a
coderd-managed workspace MCP config).

## Validation

- `go vet ./coderd/x/chatd/...`
- `go test ./coderd/x/chatd -run 'TestPlan.*|TestMCP.*' -count=1`
- `go test ./coderd/x/chatd -count=1 -timeout 5m` (full chatd suite)
- `make fmt` (no diff)

> Mux opened this PR on Mike's behalf.
2026-04-21 12:26:12 +02:00
Cian Johnston c968a1f3a3 feat: make database.Chat auditable (#24485)
Wire database.Chat into the audit system so chat lifecycle events
(creation, patches, etc.) produce audit log entries.

Part of CODAGT-200.

> 🤖
2026-04-21 11:11:56 +01:00
Cian Johnston 5f3effd839 fix(coderd/x/chatd): add chattest.OpenAI() default fake server (#24540)
- Add `chattest.OpenAI(t)` convenience wrapper around `NewOpenAI` with
sensible defaults (JSON title response for non-streaming, text chunk for
streaming)
- Update `seedChatDependencies` to use it instead of an empty base URL,
preventing title generation from hitting real `api.openai.com` with a
fake key:

```
    t.go:111: 2026-04-20 19:23:31.885 [debu]  coderd.chatd.processor: title model candidate failed  chat_id=edb43454-f23d-4163-9974-d101b8091de6  chat_id=edb43454-f23d-4163-9974-d101b8091de6 ...
        error= generate structured title:
                   github.com/coder/coder/v2/coderd/x/chatd.generateStructuredTitleWithUsage
                       /home/coder/src/coder/coder/coderd/x/chatd/quickgen.go:443
                 - unauthorized: Incorrect API key provided: test-api-key. You can find your API key at https://platform.openai.com/account/api-keys.
```

> 🤖
2026-04-21 10:26:20 +01:00
Ethan bd3ed18fb1 chore: bump hashicorp/hc-install to v0.9.4 and drop coder fork replace (#24547)
Upstream `github.com/hashicorp/hc-install` v0.9.4 ships the refreshed
HashiCorp release-signing key (hashicorp/hc-install#355 +
hashicorp/hc-install#372), so the `coder/hc-install` fork replace
directive added in #24516 is no longer needed.

Relates to https://github.com/coder/internal/issues/1476

Closes ENG-2496
2026-04-21 15:21:12 +10:00
Jake Howell 3466806a66 fix(site): implement agent logs improvements (#24455)
Polishes the agent logs panel in the workspace resources UI: consistent
padding, clearer behavior when switching log source tabs, and a more
usable download menu for long source lists.

- Use symmetric vertical padding on the logs container (`py-4` instead
of top-only padding).
- Add optional `showSourceIcons` on `AgentLogs` (defaults on);
`AgentRow` turns it off unless the **All** tab is active so filtered
tabs are not cluttered with redundant source icons.
- Anchor the download-logs dropdown below the trigger and cap menu
height to 6 items with scrolling so many sources do not overflow the
viewport.
2026-04-21 03:49:50 +00:00
Jake Howell ac6c9452c0 chore(site): decss the <WorkspaceBuild* /> pages (#24530)
This removes the CSS props of various components found in our workspaces
pages. Eventually, we'd like to remove the MUI-specific components in
here, but its a good start!
2026-04-21 03:48:36 +00:00
Jake Howell 67c57abb63 chore: tighten .vscode IDE and typescript configuration (#24537)
This branch tightens import hygiene and editor guidance to reduce
accidental use of legacy or discouraged patterns.
It also updates consumers too, by propagating the new `lucide-react`
import convention across the existing UI surfaces that reference those
icons.

- Updated `.vscode/settings.json` to prefer non-relative imports and
improve TypeScript auto-import behavior.
- Re-enabled and expanded Biome restricted-import enforcement in
`biome.jsonc` for migration guardrails.
- Added/used `lucide-react` `-Icon` naming conventions for clarity and
consistency.
- Updated consumers too across components, modules, and pages so the new
import rules are applied end-to-end.
2026-04-21 13:45:08 +10:00
Jake Howell e186dc3222 chore(site): replace inline add member form with dialog on <OrganizationMembersPage /> (#24429)
> 🤖 This PR was written by Coder Agent on behalf of Jake Howell

Replace the single-select inline UserAutocomplete form with a
multi-select Dialog (matching the GroupMembersPage pattern from #24287).

Changes:
- Replace AddOrganizationMember inline form with AddUsersDialog using
MultiUserSelect for multi-user selection in a modal
- Batch-add multiple users via Promise.all in the page callback
- Remove isAddingMember prop (dialog manages its own loading state)
- Update stories to match new interface
2026-04-21 13:43:20 +10:00
Jake HowellandJeremy Ruppel 9324c16c97 chore(site): demui <CodeExample /> (#24528)
This pull-request takes our `<CodeExample />` component and removes the
MUI specific styles.

---------

Co-authored-by: Jeremy Ruppel <jeremyruppel@users.noreply.github.com>
2026-04-21 13:40:37 +10:00
Ethan 181e103201 fix: reuse shared tailnet for coderd-hosted MCP workspace tools (#24460)
## Problem

Coderd can expose an MCP server at `/api/experimental/mcp/http` (we have
this enabled on dogfood). Its workspace tools dialed agents through a
per-call client-side tailnet stack. Every tool call re-created a
WireGuard device, netstack, magicsock + UDP sockets, DERP connection,
coordinator websocket, and their goroutines — in a process that already
runs a long-lived shared tailnet. The duplicate stacks drove up resource
usage under load.

## Fix

Route this server's tool calls through the existing shared tailnet, so
none of those transports are reconstructed per call. Closing an
`AgentConn` now releases a tunnel reference instead of tearing down a
transport.

## Potential follow-up

`coder exp mcp server` still builds a fresh tailnet per call. It pays
per-call latency and causes coordinator/DERP churn. A shared CLI tailnet
is more involved — unlike coderd, the CLI has no existing shared tailnet
to reuse, so it would need a new long-lived client-side tailnet with
reconnect, sleep/wake, and idle-destination handling. There's less
motivation to optimize this, given the client-side MCP does not compete
for resources with coderd.

Closes CODAGT-199

> Generated by mux, but reviewed by a human
2026-04-21 11:37:10 +10:00
Ethan 1203f625b7 feat(coderd): accept parameters in start_workspace tool (#24434)
When the chat `start_workspace` tool triggers an active-version upgrade
that introduces new required parameters, the build fails with a
parameter validation error. Previously this returned a message telling
the user to update from the UI — a dead end for the model.

This PR lets the model recover inside the chat by:

1. Accepting an optional `parameters` map on `start_workspace` (same
schema as `create_workspace`), forwarded as `RichParameterValues`.
2. Returning structured JSON error responses that preserve validation
details and the workspace's `template_id`, so the model can call
`read_template` to discover what changed.
3. Replacing the UI-only guidance in `exp_chats.go` with
model-actionable retry instructions.

The expected model flow on an active-version parameter failure is now:

```
start_workspace → fails (structured error with template_id + validations)
read_template   → discovers new required parameters
start_workspace → retries with parameters map → workspace starts
```
<img width="846" height="511" alt="image"
src="https://github.com/user-attachments/assets/d18b6864-5970-4225-8da0-0f2ab134ccb4"
/>
2026-04-21 11:36:20 +10:00
TJ 3b0cd5bb12 fix(site): polish table alignment for workspace proxies (#24538)
Fixes alignment issues in the workspace proxies table.

## Changes

- **Status column alignment**: Removed `text-right` from the Status
column header and the `justify-end` flex wrapper from status cells.
Status indicator dots now align consistently across rows regardless of
text width ("Healthy" vs "Not reachable").
- **Error/warning text alignment**: Changed padding from `px-12` (48px)
to `px-14` (56px) so error/warning messages align with proxy name text,
which starts after cell padding (12px) + avatar (32px) + gap (12px) =
56px.
- **colSpan fix**: Corrected `colSpan={4}` to `colSpan={3}` to match the
actual number of table columns.

Relates to DES-22000

> 🤖 Generated by Coder Agents
2026-04-20 13:05:53 -07:00