Commit Graph
13931 Commits
Author SHA1 Message Date
Cian Johnston b5a625549e feat: migrate agents-access to org-scoped system role for proper chat RBAC (#24438)
The agents-access role previously granted chat permissions at user
scope, but chats are org-scoped objects. Rego skips user-level perms
when org_owner is set, making the grants invisible. Handler-level
band-aids used synthetic non-org-scoped objects as a workaround.

  - Migrates agents-access from users.rbac_roles (site-level) to
    organization_members.roles (org-scoped) via DB migration
  - Redefines agents-access as a predefined org-scoped builtin role
    alongside organization-admin, organization-auditor, etc., with
    Member permissions granting chat create/read/update
  - Excludes ResourceChat from OrgMemberPermissions so org membership
    alone no longer grants chat access
  - Fixes handler Authorize checks to use org-scoped objects with
semantically correct actions (ActionUpdate for message/tool operations)
  - Grants org admins the ability to assign agents-access

Closes #24250
Fixes CODAGT-174

Note: this does not update the "Usage" endpoints. Tracked by CODAGT-161.
> 🤖
2026-04-23 17:59:42 +01:00
Cian Johnston 7efccfa996 fix(site): fix OpensAdminSubPanelOnMobile story on mobile viewport (#24678)
`OpensAdminSubPanelOnMobile` story has been failing due to not finding a
role="link" with name "Settings".

Agent investigated and claimed the Settings icon gets hidden in mobile
view.
Suggested fix is to start the story directly at `/agents/settings`.

> Generated with [Coder Agents](https://coder.com/agents)
2026-04-23 16:41:31 +00:00
Hugo Dutka c56061a09d fix(site): focus agents terminal on tab switch (#24677)
Fixes
[CODAGT-221](https://linear.app/codercom/issue/CODAGT-221/terminal-selection-in-side-panel-does-not-focus-input).
Verified manually that the fix automatically focuses the terminal input
when the terminal tab is selected.
2026-04-23 18:36:46 +02:00
Mathias Fredriksson f8fe5d680b fix(coderd): reject API operations on archived chats (#24633)
Archived chats accept mutations (messages, edits, queued-message
promotions, tool-result submissions) via the API, causing them to
re-enter the processing pipeline. This violates the hard-stop
design intent from PR #23758.

Add archived checks at three layers:

- HTTP handlers (postChatMessages, patchChatMessage,
  promoteChatQueuedMessage, postChatToolResults): return 400
  after auth so callers get a clear error.
- Daemon functions (SendMessage, EditMessage, PromoteQueued,
  SubmitToolResults): return ErrChatArchived after row lock,
  guarding against future callers that bypass the handler.
- AcquireChats SQL: filter out archived chats so they are never
  acquired for processing.

Fixes CODAGT-245
2026-04-23 19:03:33 +03:00
Cian Johnston a13f7f18e5 fix(site): remove last-checked label from git diff panel (#24675)
Removes `LastCheckedLabel.tsx` component and all related plumbing.

Note: chromatic is failing on main, seems to be pre-existing.

> 🤖
2026-04-23 16:45:05 +01:00
TJ e56b409873 fix(site): use highlight-orange for warning badge text and border (#24674)
## Summary

Fixes the warning badge color in light mode by switching text and border
tokens from `content-warning`/`border-warning` to `highlight-orange`.

## What changed

The `warning` variant in `Badge` was the only colored badge variant not
using the `highlight-*` token pattern:

| Variant | Before | After |
|---|---|---|
| warning (text) | `text-content-warning` | `text-highlight-orange` |
| warning (border) | `border-border-warning` | `border-highlight-orange`
|

In light mode, `content-warning` (HSL 27 96% 61%) produced a washed-out
orange. `highlight-orange` (HSL 30 100% 32%) gives a darker, more
legible result that matches the screenshot in the issue.

> [!NOTE]
> This PR was authored by Coder Agents.
2026-04-23 08:41:59 -07:00
david-fraleyandJaayden Halko 50dbb3d2cb feat(site/src/pages/AgentsPage/components): allow disengaging plan mode from Planning badge (#24651)
Adds an inline `X` button to the "Planning" indicator so users can
disengage plan mode directly from the chat input, without reopening the
`+` menu. Reuses the same pattern that already ships on the
attached-workspace and MCP-server badges.

- When `onPlanModeToggle` is provided and plan mode is on, the pill
renders a dismiss `X` next to the label; clicking it calls
`onPlanModeToggle(false)`.
- When no toggle handler is passed, no `X` renders (matches the other
badges).
- Extracts `BadgeDismissButton` inside `AgentChatInput.tsx` now that the
dismiss pattern lives in three places, collapsing ~24 lines of
duplicated markup.
- Storybook coverage: tightened `PlanningIndicator`, new
`DisablePlanModeFromBadge` (click fires `onPlanModeToggle(false)`), new
`PlanningIndicatorWithoutToggle` (no handler, no `X`).

### Demo

![Demo: open + menu, enable Plan first, click X on the Planning pill to
disengage](https://github.com/david-fraley/coder/raw/pr-24651-media/plan-mode-dismiss.gif)

<sub>Higher-quality
[MP4](https://github.com/david-fraley/coder/raw/pr-24651-media/plan-mode-dismiss.mp4)
also available.</sub>

<details>
<summary>Implementation plan</summary>

### Red / Green / Refactor

1. **Red**: Extended `AgentChatInput.stories.tsx` to assert the `X`
button exists in the Planning pill, clicking it fires
`onPlanModeToggle(false)`, and no `X` renders when `onPlanModeToggle` is
absent. Two stories failed as expected.
2. **Green**: Added an inline `<button aria-label="Disable plan mode">`
with `XIcon` to the Planning pill, gated on `onPlanModeToggle`, reusing
the existing `handlePlanModeToggle` handler. All 35 stories pass.
3. **Refactor**: Rule-of-three met with three duplicated dismiss-button
sites (workspace, MCP, planning). Extracted `BadgeDismissButton` with
`onClick` + `ariaLabel` props and replaced all three copies. Stories
still pass.

### Design notes

- `aria-label` is `"Disable plan mode"` (mode toggle, not item removal)
rather than `"Remove planning"` which would be misleading.
- Planning pill stays outside the `badgeContainerRef` overflow container
by design so it never collapses into the `+N` popover.
- No changes to the `Plan first` menu item in the `+` popover or its
behavior.

</details>

---

_This PR was opened by a Coder agent on behalf of @david-fraley._

---------

Co-authored-by: Jaayden Halko <jaayden@coder.com>
2026-04-23 15:19:24 +01:00
david-fraleyandJaayden Halko f96f7b992f fix: promote MCP server display name to a required form field (#24652)
A customer reported that on the `/agents` MCP server create form, the
Create button stays disabled even after filling in Slug and Server URL.
The form also requires a non-empty display name, but the display name
was rendered as a placeholder-style inline title, so it looked optional.

Addressing [Tracy's
feedback](https://github.com/coder/coder/pull/24652#issuecomment-4301473164),
this PR promotes the display name to a proper labeled form field,
matching Slug and Server URL.

## Changes

- Remove the inline editable title input and pencil icon from the
header.
- Header now shows a static server name (or `New MCP server` when
creating).
- Add a labeled `Display name` field as the first field in the form,
with the same required marker treatment used by Slug and Server URL.
- Update the `CreateServer` story to match (no longer asserts the
removed pencil icon).

## Screenshot

![MCP server create form with Display name as a proper labeled field
above
Slug](https://raw.githubusercontent.com/david-fraley/coder/pr-24652-screenshots/mcp-server-required-display-name.png)

Reported via Support for a Netflix user on the MCP server admin panel.

---

_Filed on behalf of the user by Coder Agents._

---------

Co-authored-by: Jaayden Halko <jaayden@coder.com>
2026-04-23 14:51:25 +01:00
Atif Ali 1e21b288b9 ci: add permissions section to backport.yaml (#24654) 2026-04-23 18:41:03 +05:00
Danny Kopping a8613b2209 chore: deprecate /api/v2/aibridge/interceptions endpoint (#24670)
*Disclaimer: implemented by a Coder Agent using Claude Opus 4.6*

Marks the `GET /api/v2/aibridge/interceptions` endpoint as deprecated in
favor of `/aibridge/sessions`, which provides richer session-level
aggregation including threads and agentic actions.

Changes:
- Add `@Deprecated` Swagger annotation to the endpoint handler
- Add deprecation notice to the
`codersdk.Client.AIBridgeListInterceptions` method
- Regenerated OpenAPI spec with `"deprecated": true` flag

The endpoint remains fully functional.

Fixes https://github.com/coder/internal/issues/1339
2026-04-23 15:33:40 +02:00
Jaayden Halko e17da2f648 fix(site): fix action bar hidden after null-returning assistant messages (#24566)
closes CODAGT-121

When an invisible assistant message (e.g. a `provider_executed`
tool-result with no text content) appeared between a visible assistant
message and the next user message, the visible assistant's action bar
was incorrectly hidden. The chain logic computed `isLastInChain` from
the raw `parsedMessages` array, which includes entries that
`ChatMessageItem` returns `null` for.

Extract a shared `isTimelineMessageVisible` helper that encodes the
three null-return conditions (`provider_executed` tool-result-only,
all-provider-executed parts, metadata-only) in one place. Use it both to
guard the early return in `ChatMessageItem` and to skip invisible
entries when computing `isLastInChain`, so chain boundaries are based on
the next *rendered* message.
2026-04-23 14:31:46 +01:00
Cian Johnston ca14aa37c4 fix: stabilize git tab during edit_files (#24648)
- feat(agent/agentgit): shorten fallback poll to 5s
- fix(site/AgentsPage): keep git tab visible after reverting to clean
- feat(site/AgentsPage): show last-checked time in git tab

> 🤖
2026-04-23 14:02:47 +01:00
Hugo Dutka 397c9fb76a fix(agent/x/agentdesktop): flaky TestPortableDesktop_StopRecording_WithThumbnail (#24671)
Fixes https://github.com/coder/internal/issues/1462
2026-04-23 14:54:05 +02:00
TJandJaayden Halko 95386f526a fix(site): improve agents page mobile view (#24508)
closes DES-22030

## Summary

Mobile view cleanup for the agents page — all changes are behind the
`md:` breakpoint so desktop is unchanged.

**Dropdowns:** Full-width on mobile with dynamic positioning via a
`--mobile-dropdown-bottom` CSS custom property set by a `ResizeObserver`
on the chat input box. Three position variants: `-bottom` (above chat
input), `-top` (below header), `-top-below-header` (below sidebar
header). Viewport branching uses a new `isBelowMdViewport()` helper (`<
768px`) so 640–767 px landscape phones pick the mobile branch instead of
the desktop flyout.

**Layout:** On the main agents page, mobile ordering is header → chat
list → chat input using CSS `order` and `contents` on the content
wrapper. The chat input aligns to the bottom of available space. The
sidebar list uses a top/bottom fade mask on mobile to hint at scrollable
content.

**Header:** Settings, Analytics, sound, and notification icons
consolidated into a single meatball menu dropdown on mobile.
Sound/notification toggles use `e.preventDefault()` to keep the menu
open for state feedback. Chime and notification state is lifted into
`AgentCreatePage` and passed down, so the mobile meatball menu and the
desktop `ChimeButton`/`WebPushButton` stay in sync.

**Workspace pill:** Icon-only on mobile (`size-7` round button with
`StatusIcon`), full pill on desktop. Tooltip hidden on mobile to prevent
ghost tooltip after dropdown close.

**Plus menu:** Workspace picker replaces the flyout with an inline
sub-panel on mobile (back button + search list). Desktop flyout
unchanged. `modal={false}` prevents double-tap when switching between
dropdowns.

**Model selector:** Truncated via `shrink` + `min-w-0` on mobile
(flex-based, no fixed max-width), inline provider/context subtext per
item, tooltip hidden on mobile. Added `open` / `onOpenChange` /
`onTriggerTouchStart` props for external control.

**Consistency:** All back/close buttons normalized to `ArrowLeftIcon`.
Right panel, sidebar settings, header `mobileBack`, and workspace
sub-panel all match the chat top bar pattern.

**Misc polish:** Chat tree nodes use `select-none` +
`-webkit-touch-callout:none` on coarse pointers to suppress the
long-press selection/callout on mobile.

<details>
<summary>Files changed (18)</summary>

- `site/src/index.css` — mobile dropdown CSS with 3 position variants
- `site/src/utils/mobile.ts` — new `isBelowMdViewport()` helper
(`<768px`)
- `site/src/pages/AgentsPage/AgentChatPageView.tsx` — bottom padding
`pb-3`
- `site/src/pages/AgentsPage/AgentCreatePage.tsx` — lift chime + webpush
state; pass handlers to header and buttons
- `site/src/pages/AgentsPage/AgentsPageView.tsx` — `contents` wrapper +
sidebar `border-b`
- `site/src/pages/AgentsPage/components/AgentChatInput.tsx` —
`ResizeObserver` composer ref, `plusMenuView` state, inline workspace
picker, `modal={false}`, mobile branching via `isBelowMdViewport`, bg
- `site/src/pages/AgentsPage/components/AgentCreateForm.tsx` —
`order-last` + `items-end` on mobile
- `site/src/pages/AgentsPage/components/AgentPageHeader.tsx` — meatball
menu (controlled chime/webpush props), `ArrowLeftIcon`, `order-first`,
padding, desktop/mobile branching via `matchMedia`
- `site/src/pages/AgentsPage/components/AgentPageHeader.stories.tsx` —
new Storybook coverage + `play` assertions that toggle state stays in
sync across breakpoints
- `site/src/pages/AgentsPage/components/ChimeButton.tsx` — optional
controlled `enabled` / `onToggle` props
- `site/src/pages/AgentsPage/components/WebPushButton.tsx` — optional
controlled `webPush` / `onToggle` props
-
`site/src/pages/AgentsPage/components/ChatElements/CompactOrgSelector.tsx`
— full-width dropdown class
- `site/src/pages/AgentsPage/components/ChatElements/ModelSelector.tsx`
— truncation, inline subtext, tooltip hidden on mobile, new props
(`open`, `onOpenChange`, `onTriggerTouchStart`)
- `site/src/pages/AgentsPage/components/ChatTopBar.tsx` — full-width
dropdown class
- `site/src/pages/AgentsPage/components/ContextUsageIndicator.tsx` —
full-width dropdown class (mobile branch)
- `site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.tsx` —
`ArrowLeftIcon`, filter dropdown class, top/bottom fade mask on scroll
area, `select-none` on tree nodes
- `site/src/pages/AgentsPage/components/Sidebar/SidebarTabView.tsx` —
`ArrowLeftIcon`, padding, back button placement
- `site/src/pages/AgentsPage/components/WorkspacePill.tsx` — compact
icon trigger, tooltip hidden on mobile, full-width dropdown class

</details>

> 🤖 Generated by Coder Agents

---------

Co-authored-by: Jaayden Halko <jaayden@coder.com>
2026-04-23 13:41:44 +01:00
Jake Howell 537e35dd94 chore: de-css <UserSettingsPage /> children (#24647)
This is a cleanup for some leftover `css={}` props within our
`site/src/pages/UserSettingsPage/...` pages.
2026-04-23 22:19:34 +10:00
Cian Johnston 2e5c7d99c2 fix(coderd/x/chatd): fix flaky TestSpawnComputerUseAgentInheritsContext (#24666)
Fixes flaky `TestSpawnComputerUseAgentInheritsContext`.

- The test inserts an Anthropic provider directly into the DB after
`CreateChat` has already been called
- The server's background goroutine may have already cached the provider
list (OpenAI only) via `configCache.EnabledProviders()` with a 10s TTL
- The direct DB insert bypasses the pubsub event that production uses to
invalidate the cache
- `isAnthropicConfigured()` returns the stale cached result, making
`computer_use` appear unavailable
- Fix: call `server.configCache.InvalidateProviders()` after the insert,
mirroring what production does via pubsub

CI failure:
https://github.com/coder/coder/actions/runs/24829197096/job/72673070101?pr=24648

> 🤖
2026-04-23 13:18:18 +01:00
Danielle Maywood 6edb49dcfa fix(site): prevent sticky message cycling when submitting edited message (#24292) 2026-04-23 12:09:54 +01:00
Cian Johnston be011b210b fix(cli): fix flaky TestExpAgentsE2E/ExistingChatHistory (#24661)
- Remove racy sequential `expect("esc")` after `expect("direct open
seed")`
- Both strings appear in the same initial PTY render; their byte-stream
order depends on async title generation timing
- The seed text alone proves we are in the chat view; pressing esc +
expecting `enter: open` confirms list navigation

> 🤖
2026-04-23 11:25:24 +01:00
Cian Johnston d9e3e206cc fix(enterprise/coderd/x/chatd): deflake relay drain test for multiple timers (#24609)
Fixes https://github.com/coder/internal/issues/1474.

PR #24549 introduced a `quartz.NewMock` clock +
`Trap().NewTimer("drain")` to
remove the wall-clock race. However, the trap consumed only **one**
`NewTimer("drain")` call via `MustWait/MustRelease`.

The merge loop has two code paths that create drain timers with the same
tag:
- Relay result handler (`drainAndClose` path in `relayReadyCh` case):
when an async dial completes after `drainAndClose` was set.
- Status notification handler (`relayParts != nil` branch in
`statusNotifications` case): when `status!=running` arrives while an
active relay exists.

Depending on goroutine scheduling, one or both paths fire. When two
calls hit
the trap, the second blocks the merge loop in `matchCallLocked` (quartz
waits
for all traps to release). Since the test already moved past `MustWait`,
nobody
reads the second call from the trap channel, deadlocking the test.

- Replace the single `MustWait/MustRelease/Advance` with a goroutine
that
loops over `trapDrain.Wait`, releasing and advancing for every drain
timer.
- No production code changes.

> 🤖
2026-04-23 11:13:41 +01:00
Mathias Fredriksson 7e29a67b50 chore(dogfood): add CODER_AGENT_EXP_MCP_CONFIG_FILES env var (#24664)
Set CODER_AGENT_EXP_MCP_CONFIG_FILES to ~/.mcp.json,.mcp.json so the
Coder agent reads both the harness-managed global MCP config and any
project-local .mcp.json. The agent resolves .mcp.json relative to its
manifest Directory (~/coder), so without this env var, a ~/.mcp.json
written by a user harness would be invisible to the agent.

Multiple files are merged by Manager.Connect; first file wins on name
conflicts. Missing files are silently skipped.
2026-04-23 13:07:20 +03:00
Danny Kopping 135ab29aa8 docs: add v2.32 to release calendar (#24589)
*Disclaimer: implemented by a Coder Agent using Claude Opus 4.6*

The [release calendar](https://coder.com/docs/install/releases) was
missing a link and details for v2.32, which was released on April 14,
2026.

Changes:
- Add v2.32 as Mainline with changelog link and release date
- Add v2.33 as the next upcoming (Not Released) entry
- Update latest patch versions: v2.29.10, v2.30.7, v2.31.9
2026-04-23 10:42:31 +02:00
Jiachen JiangandDanny Kopping fb26b39780 docs(docs/admin/infrastructure): add Governance Layer section to architecture page (#24587)
Adds a new "Governance Layer" section to the architecture page with
short descriptions of AI Gateway and Agent Firewall, linking to their
dedicated reference pages.

> Generated by Coder Agents

---------

Co-authored-by: Danny Kopping <danny@coder.com>
2026-04-23 08:41:00 +00:00
Jakub Domeracki 9f02fec3a9 ci(.github/workflows/contrib): skip community label for dependabot (#24660) 2026-04-23 10:25:46 +02:00
Cian Johnston f5ccf68e53 feat: add lima incus example (#24640)
Depends on https://github.com/coder/coder/pull/24616

Adds a sample Lima configuration for Coder+Incus.
2026-04-23 08:24:03 +01:00
edd5d83280 ci: bump the github-actions group with 12 updates (#24558)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Lukasz <CommanderK5@users.noreply.github.com>
Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
2026-04-23 10:31:55 +05:00
Atif Ali ff1308c0b1 docs: update MCP Server description for clarity (#24655) 2026-04-23 05:10:09 +00:00
Lukasz 06d7fc5200 feat: add dependabot security backport labels (#24484)
Dependabot security update PRs should be backported with the workflow
added in #24025, but today they still rely on someone noticing and
adding the backport label manually.

This updates the dependabot workflow to add the existing backport label
automatically when a newly opened Dependabot PR looks like a security
fix, and it adjusts the Slack notification text so those PRs are called
out explicitly.
2026-04-23 08:58:53 +05:00
Michael Suchacz 73857222ab fix(site/src): remove agent settings insights menu link (#24644)
> Mux created this PR on behalf of Mike.

This removes the Insights entry from the Coder Agents settings menu.

The underlying page and route stay in place. This PR only stops linking
to that page from the sidebar.
2026-04-22 22:35:25 +02:00
Jake Howell 4caa52844d chore!: remove api.ts unnecessary calls (#22168)
> [!WARNING]  
> The change of the status code from `404` to `204` could break peoples
code downstream. Adding this as a breaking change incase.

Theres a whole ton of noise around failed requests, these are all
unrelated to the actual thing that is broken at hand (and are
confusing).

* Change `/api/v2/organizations/.../templates/.../versions/.../previous`
to return `204` instead of `404` (actually makes more sense because the
content doesn't exist, but the route is found.
* Remove unnecessary calls to `/api/v2/users/me/appearance` when the
user isn't logged in.
* Remove unnecessary calls to `/api/v2/deployment/stats` when the
deployment stats aren't allowed to be seen.
* Various changes to `workspace-sharing` so we don't make unnecessary
calls.

Whats left:

* `/api/v2/users/me` still `401`s on the login page. This persists as
when the user is logged in but tries to reach the sign-in page they
should be redirected to the app, not sign in again.
* `monaco-editor` is still upset... we theoretically could inject an
environment that can serve workers... but eh.

#### Old

```sh
% pnpm playwright:test -g "create workspace with default and required parameters"

> coder-v2@ playwright:test /home/coder/coder/site
> playwright test --config=e2e/playwright.config.ts -g 'create workspace with default and required parameters'

...

Running 2 tests using 1 worker

  ✓  1 …e/setup/addUsersAndLicense.spec.ts:7:5 › setup deployment (8.2s)
     2 ….ts:79:5 › create workspace with default and required parameters
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[response] url=http://localhost:3111/api/v2/users/me/appearance status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[response] url=http://localhost:3111/api/v2/users/me status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[console][error] Failed to load resource: the server responded with a status of 403 (Forbidden)
[response] url=http://localhost:3111/api/v2/deployment/stats status=403 body={"message":"Forbidden.","detail":"You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials."}
[console][error] Failed to load resource: the server responded with a status of 403 (Forbidden)
[response] url=http://localhost:3111/api/v2/deployment/stats status=403 body={"message":"Forbidden.","detail":"You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials."}
[console][error] Failed to load resource: the server responded with a status of 404 (Not Found)
[response] url=http://localhost:3111/api/v2/organizations//provisionerdaemons status=404 body={"message":"Resource not found or you do not have access to this resource"}
[console][error] Failed to load resource: the server responded with a status of 404 (Not Found)
[response] url=http://localhost:3111/api/v2/organizations/default/templates/a4e8096d/versions/agreeable_glenn33/previous status=404 body={"message":"No previous template version found for \"agreeable_glenn33\"."}
[console][warning] Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/microsoft/monaco-editor#faq
[console][warning] You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[response] url=http://localhost:3111/api/v2/users/me/appearance status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[response] url=http://localhost:3111/api/v2/users/me status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[console][error] Failed to load resource: the server responded with a status of 403 (Forbidden)
[response] url=http://localhost:3111/api/v2/deployment/stats status=403 body={"message":"Forbidden.","detail":"You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials."}
  ✓  2 …5 › create workspace with default and required parameters (7.0s)atus of 403 (Forbidden)
[response] url=http://localhost:3111/api/v2/deployment/stats status=403 body={"message":"Forbidden.","detail":"You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials."}
[console][error] Failed to load resource: the server responded with a status of 403 (Forbidden)
[response] url=http://localhost:3111/api/v2/deployment/stats status=403 body={"message":"Forbidden.","detail":"You don't have permission to view this content. If you believe this is a mistake, please contact your administrator or try signing in with different credentials."}

  2 passed (56.1s)
```

`23 LOL` (Lines of logs)

#### New

```sh
% pnpm playwright:test -g "create workspace with default and required parameters"

> coder-v2@ playwright:test /home/coder/coder/site
> playwright test --config=e2e/playwright.config.ts -g 'create workspace with default and required parameters'

...

Running 2 tests using 1 worker

  ✓  1 …e/setup/addUsersAndLicense.spec.ts:7:5 › setup deployment (8.7s)
     2 ….ts:79:5 › create workspace with default and required parameters
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[response] url=http://localhost:3111/api/v2/users/me/appearance status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[response] url=http://localhost:3111/api/v2/users/me status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[console][warning] Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/microsoft/monaco-editor#faq
[console][warning] You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker
  ✓  2 …5 › create workspace with default and required parameters (7.1s)atus of 401 (Unauthorized)
[console][error] Failed to load resource: the server responded with a status of 401 (Unauthorized)
[response] url=http://localhost:3111/api/v2/users/me/appearance status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}
[response] url=http://localhost:3111/api/v2/users/me status=401 body={"message":"You are signed out or your session has expired. Please sign in again to continue.","detail":"Cookie \"coder_session_token\" or query parameter must be provided."}

  2 passed (32.0s)
```

`9 LOL` (Lines of logs)
2026-04-23 06:20:35 +10:00
Callum Styan 7d044fa598 fix(scaletest/prebuilds): fix Runner.Cleanup() to delete workspaces (#23627) 2026-04-22 13:11:42 -07:00
Callum Styan b714fe8e71 fix(scaletest/prebuilds): make measureDeletion more reliable/less brittle (#23614) 2026-04-22 13:10:34 -07:00
Cian Johnston be1256c418 fix(coderd): fix TestListChats/PinnedOnFirstPage race timeout (#24641)
- Insert filler chats directly into the database with `completed` status
instead of creating them via the API
- Removes the `testutil.Eventually` polling loop that waited for all 52
chats to reach terminal status
- Avoids spawning 52 background chat processors that each time out on
title generation under `-race`, exceeding the 25s `WaitLong` timeout
- Test now completes in ~1s instead of timing out at 30s+

Flake:
https://github.com/coder/coder/actions/runs/24789695935/job/72543519963?pr=24438

> 🤖
2026-04-22 20:37:06 +01:00
Cian Johnston 68508e1fd3 chore(examples): update incus template (#24616)
- Decoupled provisioner from Incus host by passing agent token/URL via
Incus Guest API
- Added a config watcher service to detect token updates and restart the
agent automatically.
- Updates for compatibility with Incus provider 1.x
2026-04-22 20:06:21 +01:00
Mathias Fredriksson 1ace519c6e fix(coderd/x/chatd): remove cache-miss check blocking agent recovery (#24634)
The cache-miss isAgentUnreachable check added in #24336 runs before
dialWithLazyValidation, preventing the existing switch mechanism from
discovering the new agent after a workspace rebuild. The chat's stale
agent binding is never repaired, causing an infinite loop of
'agent is disconnected' errors.

Remove the cache-miss check. The cache-hit check remains (it verifies
the agent behind an established connection). The dial timeout and
dialWithLazyValidation already bound the cache-miss failure path.

Closes CODAGT-248
2026-04-22 21:49:10 +03:00
Jeremy Ruppel 514b4994c6 fix(site): fix workspace unhealthy dialog stories (#24637)
#24536 changed the behavior of the ⚠️ from a tooltip (hover) to a
popover (click). this is better for a11y, particularly keyboard
navigation. this PR updates the storybook interaction tests to match



https://github.com/user-attachments/assets/94677b77-4925-4652-ae88-322ed087983b
2026-04-22 14:47:02 -04:00
code-qtzl 075face3cb fix(site/src/pages/WorkspacePage/WorkspaceNotifications): make workspace notification pills keyboard accessible (#24536)
Description:

The workspace notification pills were implemented using Tooltip, which
is hover-only and not reachable via keyboard navigation.

Replace Tooltip/TooltipProvider/TooltipTrigger with
Popover/PopoverContent/PopoverTrigger, and change the trigger element
from a non-interactive div to a button. This makes the notification
pills fully keyboard accessible.


Screenshot:
**Issue**
<img width="640" height="211" alt="not-working"
src="https://github.com/user-attachments/assets/3cb12fdf-704b-41a2-ab9c-c198d03158a7"
/>


**Fix**
<img width="640" height="211" alt="working"
src="https://github.com/user-attachments/assets/25807a6b-7065-4753-b55e-d8db103ba501"
/>
2026-04-22 14:01:33 -04:00
Danny Kopping 8aa3294f06 fix(aibridge): track Charm Crush client and session ID (#24630)
*Disclaimer: implemented by a Coder Agent using Claude Opus 4.6*

Porting https://github.com/coder/aibridge/pull/277 to coder/coder after
the [aibridge code move](https://github.com/coder/coder/pull/24190).

## Summary

Fixes client detection and session ID tracking for the [Charm
Crush](https://github.com/charmbracelet/crush) AI coding client.

## Changes

### Bug fix: User-Agent matching

The actual Crush user-agent is `Charm-Crush/{version}
(https://charm.land/crush)` (hyphenated), but `GuessClient` only checked
for `charm crush/` (space-separated). After lowercasing,
`Charm-Crush/0.2.0` becomes `charm-crush/0.2.0`, which did not match the
`charm crush/` prefix.

Now matches both formats for backwards compatibility.

### Session ID tracking

Adds an explicit `ClientCrush` case to `GuessSessionID`. Crush does not
currently send a session ID header to upstream AI providers, so this
returns `nil` (consistent with how `ClientZed`, `ClientRoo`, and
`ClientCursor` are handled).

### Tests

- Added `charm_crush_hyphen` test case for `GuessClient` using the real
user-agent format.
- Added `crush_returns_empty` test case for `GuessSessionID`.
2026-04-22 19:02:31 +02:00
Jaayden Halko e421c2f747 perf: fix DiffViewer scroll performance (#24300)
## Problem

The GitPanel's DiffViewer had several performance and correctness issues
that
manifested as CPU spikes and scrollbar jank, especially on Safari with
large
diffs:

1. The `onScroll` handler called `getBoundingClientRect()` on every file
   wrapper per scroll tick (O(N) forced layouts per frame).
2. `setActiveFile()` re-rendered the entire DiffViewer tree on every
active
   file change.
3. `parsePatchFiles()` ran on every render in `LocalDiffPanel`,
   `RemoteDiffPanel`, and `GitPanel`.
4. File header `rootMargin` used a percentage, which resolves against
the
   root's width (not height), collapsing the observation strip in wide
   viewports.
5. The IntersectionObserver effect didn't re-run when the viewport
mounted
   after an initial empty state, or when the viewport was resized.

## Fix

### Scroll tracking
Replaced the `getBoundingClientRect` scroll handler with an
`IntersectionObserver` watching a narrow strip at the top of the
viewport.
The observation strip is a pixel value derived from
`viewport.clientHeight`
(the previous `-95%` margin was broken in wide viewports because CSS
margin
percentages resolve against width). A `ResizeObserver` tracks viewport
height so the strip adapts to layout changes, and the effect keys off a
stable `fileListKey` string so scroll-driven re-renders don't tear down
the
observer.

### Memoization: React Compiler
`src/pages/AgentsPage/` is opted into the React Compiler via
`site/vite.config.mts`. The compiler automatically memoizes values,
callbacks, and JSX at build time. This PR removed the manual `useMemo` /
`useCallback` wrappers that were added earlier in the review cycle and
lets the compiler handle memoization.

`React.memo()` is retained on `FileTreeNodeView` and `LazyFileDiff` —
the
documented list-item exception from `site/AGENTS.md`. Their `memo()`
effectiveness depends on the compiler stabilizing prop references;
moving
these components outside the compiler scope without adding manual
memoization would silently regress scroll performance.

`useParsedDiff` uses explicit `useMemo` as a documented exception: the
compiler cannot prove purity of the external `parsePatchFiles` function
from `@pierre/diffs`, so without `useMemo` the parser would run on every
render even when inputs are unchanged.

### `activeCommentBoxRef` (stable annotation handler)
`CommentableDiffViewer` wraps `activeCommentBox` in a ref that's synced
in event handlers (not during render). This gives `renderAnnotation`,
`handleSubmitComment`, and the annotation getters stable identities via
the compiler, so comment-box toggles no longer force every
`LazyFileDiff`
to re-render.

### CSS containment for Safari
Added `will-change: transform` on the scroll container and
`contain: layout style` on each file wrapper. Programmatic
`scrollIntoView` / `scrollBy` calls use `behavior: "instant"` to avoid
fighting Safari's scroll compositor.

### Hook extraction
Extracted `useActiveFileTracking` (observer setup, viewport sizing,
scroll-to-file) and `useParsedDiff` (shared diff parsing with
memoization) to keep `DiffViewer` focused on layout and eliminate
duplication between `LocalDiffPanel` and `RemoteDiffPanel`.

### Testing
Added a `LargeDiff` Storybook story (40 files × 60+ context lines,
~2,400 diff lines) with `isExpanded: true` so the observer code path is
exercised, plus a `play` function that scrolls the viewport and asserts
the sidebar highlight updates.

## Expected impact
- Scroll handler: O(N) `getBoundingClientRect` calls per frame → 0
- Re-renders on scroll: full DiffViewer tree → sidebar only
- Diff parsing: on every render → only when `diffString` changes
2026-04-22 17:47:18 +01:00
Cian Johnston 72e3ae9c5f feat: add chatd tool call error metrics and logging (#24559)
- Add `coderd_chatd_tool_errors_total` prometheus counter (labels:
provider, model, tool_name)
- Log tool call errors at warn level with correlation fields: chat_id,
owner_id, organization_id, workspace_id, agent_id, parent_chat_id,
trigger_message_id, tool_name, tool_call_id, provider, model
- Thread enriched logger from chatd.go into chatloop via
`RunOptions.Logger`
- Remove squashing of all MCP tool calls to the `mcp` bucket

> 🤖
2026-04-22 16:19:56 +00:00
Michael Suchacz 7904bed947 fix: fall back to local git watcher for chat diff drawer (#24512)
The Ctrl+D diff drawer in `coder exp agents` only rendered PR-backed
diffs returned by `/api/experimental/chats/{id}/diff`. Local working
tree changes in a chat's workspace returned an empty diff, so the
drawer showed "No diff contents" with no file summary.

Centralise diff loading behind a single `fetchChatDiffContents` helper
that first hits `/diff`, then falls back to the chat git watcher
WebSocket (`/stream/git`) when the remote diff is empty. Aggregate the
agent's `WorkspaceAgentRepoChanges` into a `ChatDiffContents` value so
the drawer can derive the file summary and styled body from the local
unified diff. Missing workspaces, missing agents, and watcher timeouts
are treated as graceful fallbacks that render the empty-diff
placeholder instead of a hard error.

> Mux is opening this PR on Mike's behalf.
2026-04-22 18:08:02 +02:00
Jeremy RuppelandClaude Sonnet 4.6 c23abc691f feat: sort AI sessions by last prompt time (#24440)
Previously, the sessions list sorted by `MIN(started_at)` across
interceptions, so sessions with old start times but recent activity
would sink to the bottom of the list regardless of how recently they
were used.

`ListAIBridgeSessions` now sorts by `COALESCE(MAX(prompt.created_at),
MIN(started_at)) DESC`, exposed as the non-nullable `last_active_at`
field. Sessions with prompts surface by last activity; sessions with no
prompts fall back to their start time.

The original implementation used two separate columns (`last_active_at`
as a nullable prompt timestamp and `sort_at` as the non-nullable cursor
key). This revision collapses them into a single `last_active_at` that
is always set — simplifying the SQL, the Go conversion, the API type,
and the frontend.

🤖 Generated with [Claude Code](https://claude.ai/claude-code)

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 12:06:49 -04:00
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