Commit Graph

5215 Commits

Author SHA1 Message Date
Michael Suchacz 40878eeba4 feat: add AI provider schema expansion (#25412) 2026-05-22 02:16:01 +02:00
Michael Suchacz 1809cfc37f feat(site): show reasoning heading in thinking block (#25594)
> Mux is opening this PR on behalf of Mike.

Updates agent chat thinking disclosures to include the first Markdown
heading or leading header-like reasoning paragraph, rendering titles
like `Thinking about configuring model settings` while preserving
`Thinking` when no heading is present.

Existing chat logs store many thinking section titles as bold standalone
paragraphs, such as `**Checking tool execution**`. This handles that
format too, and removes the displayed heading from the expanded thinking
body so it does not appear twice. Adds focused title/body extraction
coverage and updates the conversation timeline story for the heading
title behavior.
2026-05-22 01:59:09 +02:00
Michael Suchacz fa9eb1ad56 feat(site/src/pages/AgentsPage): add personal skills slash menu (#25386)
> Mux updated this PR on behalf of Mike.

## Context

PR #25066 has merged. This branch is rebased onto `main` and now
contains only the personal skills slash menu UI changes.

## Summary

- Add a `/` slash-trigger menu in the agent chat composer that filters
personal skills by name and description.
- Insert `/<skill-name>` on click, Enter, or Tab selection while
preserving normal composer behavior when the menu is closed.
- Keep Escape dismissal and post-selection suppression scoped to the
current slash trigger, with menu anchor refresh on editor scroll and
resize.
- Share personal skill trigger formatting and parsing helpers with unit
coverage.
- Add Storybook coverage for open, filter, click, keyboard selection,
Escape, error, empty, and filtered-empty states.

## Validation

- pre-commit hook
- `cd site && pnpm exec vitest run --project=unit
src/pages/AgentsPage/components/ChatMessageInput/ChatMessageInput.test.tsx
src/pages/AgentsPage/utils/personalSkills.test.ts`
- `cd site && pnpm lint:types`
- `cd site && pnpm lint:check`
2026-05-22 01:24:26 +02:00
Michael Suchacz 356bccddc2 feat: add personal skills settings UI and docs (#25066)
> Mux updated this PR on behalf of Mike.

## Summary

- Add experimental personal skills API helpers and an Agents settings UI
for listing, creating, editing, deleting, and importing SKILL.md
content.
- Add docs, Storybook coverage, and unit tests for backend-compatible
SKILL.md parsing.
- Address review feedback by simplifying frontmatter scalar parsing,
clarifying the UI parser scope, defaulting personal skill queries to
`me`, and patching React Query caches after create, update, and delete.
- Merge latest `main` and resolve the Agents sidebar refactor conflicts.

## Validation

- pre-commit hook
- `go test ./codersdk/workspacesdk -run TestParseSkillFrontmatter
-count=1`
- `go test ./coderd/x/chatd/chattool -run 'Test' -count=1`
- `cd site && pnpm test --
src/pages/AgentsPage/utils/personalSkills.test.ts
src/api/queries/userSkills.test.ts src/utils/fileSize.test.ts
--runInBand`
- `cd site && pnpm lint:types`
- `cd site && pnpm lint:check`
2026-05-22 00:20:10 +02:00
Zach ddc0e99c69 chore: remove coder_secret Terraform integration (#25512)
Removes the coder_secret Terraform integration: the data.coder_secret
consumption path through provisionerdserver → provisioner.proto →
provisioner/terraform, the dynamic-parameter secret-requirement
validation, and the workspace-update / resolve-autostart surfaces that
depended on it. This is being done due to a product/feature direction
change (see PLAT-243). User-secret CRUD (DB, REST, CLI, UI, telemetry, audit)
and the agent-manifest secret-injection path are untouched.

The provisionerd API is bumped from v1.17 to v1.18 rather than rolled
back: v1.17 shipped in v2.33.x, so user_secrets field numbers are
reserved and the changelog documents both versions.

Generated with assistance from Coder Agents.
2026-05-21 09:19:29 -06:00
Jake Howell 4c91069479 fix: append asChild to <AgentApps /> (#25547)
This pull-request resolves a stupid issue wherein the `<DropdownItem />`
would wrap into an `<AppLink />` causing two hit targets. This now is a
single one and inline with the Figma Coder Kit after the parent merges
onto the child.

| Old | New |
| --- | --- |
| <img width="400" alt="preview-broken-button"
src="https://github.com/user-attachments/assets/b74018a7-9279-4464-b71b-a16901e844c9"
/> | <img width="308" height="141" alt="image"
src="https://github.com/user-attachments/assets/8b4a1371-e1bb-4341-9a6a-033a7b48c31d"
/> |
2026-05-22 00:21:26 +10:00
Jake Howell ef8eeb1f5d fix: resolve badge content color (#25550)
I noticed that the content on our badges for options broke, I've
restored this to using `text-content-primary` so that the content will
always be legible and not inherit from the base body css.

| Old | New |
| --- | --- |
| <img width="718" height="488" alt="CLI_PREVIEW_OLD"
src="https://github.com/user-attachments/assets/98c91591-b8b8-4ed0-bdd5-0bd2fb5f2802"
/> | <img width="718" height="488" alt="CLI_PREVIEW_NEW"
src="https://github.com/user-attachments/assets/5c07a5e0-3fbf-41a0-8454-0e7bd6ee52e8"
/> |
2026-05-22 00:21:02 +10:00
Jake Howell 1fdb8ed9a0 fix: wrap latestVersion?.message with <div /> (#25549)
This pull-request wraps the `latestVersion?.message` in a `<div />` so
that our content is affected by the `flex flex-col` class from the
parent.

| Old | New |
| --- | --- |
| <img width="441" height="363" alt="PREVIEW_1"
src="https://github.com/user-attachments/assets/0693136a-cfcc-4f17-a94d-35c14943c3bd"
/> | <img width="441" height="295" alt="PREVIEW_1_NEW"
src="https://github.com/user-attachments/assets/ce6c1126-6153-4d7f-a4b8-f01a5a98e270"
/> |
| <img width="441" height="396" alt="PREVIEW_2"
src="https://github.com/user-attachments/assets/b26e81b4-09fb-4317-9d25-3ca8b5989c54"
/> | <img width="441" height="294" alt="PREVIEW_2_NEW"
src="https://github.com/user-attachments/assets/241afe85-c278-4593-a985-bcc2400ac52f"
/> |
2026-05-22 00:20:41 +10:00
Jaayden Halko 2a45262fa2 fix: truncate search results (#25566)
1. truncates search results
2. display a loading spinner when retrieving new search results when
existing results are displayed
3. Improve dialog resizing behavior
2026-05-21 14:42:32 +01:00
Danielle Maywood 873aa0da6a fix(site/src/pages/AgentsPage/components/ChatConversation): add min-h-6 to StatusPlaceholder to prevent layout shift (#25560) 2026-05-21 12:58:02 +01:00
Danielle Maywood d9875d8902 fix(site): restore iOS backspace in agent chat input (#25531) 2026-05-21 11:42:20 +01:00
Jaayden Halko 92d67888b8 feat: modal chat search popup (#25535)
closes CODAGT-422

<img width="591" height="404" alt="Screenshot 2026-05-21 at 17 33 26"
src="https://github.com/user-attachments/assets/5ef8134a-aca7-4442-bed7-9a31698dc5d6"
/>
<img width="590" height="499" alt="Screenshot 2026-05-21 at 17 33 46"
src="https://github.com/user-attachments/assets/b8e99e53-793c-4480-8411-d90f97f9bcb6"
/>
<img width="376" height="301" alt="Screenshot 2026-05-21 at 17 36 39"
src="https://github.com/user-attachments/assets/d9c4a45c-9094-40a2-ac88-87415c45b358"
/>

---------

Co-authored-by: Cian Johnston <cian@coder.com>
2026-05-21 11:39:58 +01:00
Paweł Banaszewski 46e93e6325 chore: add ai_gateway options that alias aibridge options (#25061)
Adds options matching new AI Gateway naming.
New options are added as alias for old options. Old options are still
working.
Old options have deprecated message.
No conflict detection was added.

Updated documentation so it mentions only new options. Added note about
old options still working.

> Various AI tools where used to create this PR
2026-05-21 11:14:11 +02:00
Mathias Fredriksson f1b772928d feat: parse execute tool commands and render them in the chat UI (#25478)
When the execute tool runs a chained shell command, the UI previously
rendered the raw string. Long chains like "cd /repo && git pull &&
git add . && git commit -m fix" were hard to scan.

A new ChatMessagePart.ParsedCommands [][]string field on tool-call
parts carries one entry per simple command, parsed in chatd from args
via mvdan.cc/sh/v3/syntax. The frontend renders the joined list ("cd,
git pull, git add, git commit") in place of the raw command, and falls
back to the raw command when the field is absent.

Closes CODAGT-446
2026-05-21 08:12:34 +00:00
Rowan Smith 57ed244de1 chore: update cli install link to use local deployment URL instead of coder.com (#25548)
Updates the connect via SSH menu shown in workspaces to redirect to
`/install` on the local deployment instead of
`https://coder.com/docs/<version>/install`. This ensures consistency
with the user account dropdown menu which also references the local
deployment.

End goal is to ensure the user running install script receives the same
CLI version as is running on the Coder deployment.
2026-05-21 15:12:06 +10:00
Danielle Maywood 889add734e fix(site): use ToolCollapsible for thinking blocks (#25445) 2026-05-20 21:58:19 +01:00
Danielle Maywood e27d917135 feat: enable chat sharing (#24987) 2026-05-20 18:45:44 +01:00
Danielle Maywood e73292fc89 fix(site): recover malformed subagent chat links (#25532) 2026-05-20 13:39:49 +00:00
Jaayden Halko 1ba54e2ca6 chore: cleanup structure of left sidebar (#25528)
This cleanups up the folder structure and breaks up files into a more
atomic structure. No functional changes should exist here.
2026-05-20 14:06:54 +01:00
Atif Ali 7ffeac711c fix: correct web terminal glyph rendering and tmux display (#25059)
The web terminal was rendering Claude Code and Codex incorrectly because
xterm's custom glyph renderer draws block and quadrant characters with
its own geometry. The reconnecting PTY screen backend also exposed
`screen.xterm-256color` to the user's shell, which made tmux rendering
issues harder to reason about.

This PR:

* Disables xterm custom glyph rendering so the selected terminal font
draws block and quadrant glyphs.
* Adds a tiny Powerline-only terminal symbol fallback font so common
prompt separators still render when custom glyphs are disabled.
* Configures the screen backend to keep the inner shell `TERM` aligned
with the browser terminal emulator, including background color erase
behavior.
* Tightens reconnecting PTY tests around prompt synchronization and
`TERM` assertions.

<!-- linear:table-colwidths:200,200 -->
| Before | After |
| -- | -- |
| <img
src="https://uploads.linear.app/e62091d9-44f5-421c-8e5c-df481fc99003/3c45efce-9d7e-43b4-b24f-88d4d23d294a/ba68155e-949e-4961-b0b2-124757cb07bb?signature=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXRoIjoiL2U2MjA5MWQ5LTQ0ZjUtNDIxYy04ZTVjLWRmNDgxZmM5OTAwMy8zYzQ1ZWZjZS05ZDdlLTQzYjQtYjI0Zi04OGQ0ZDIzZDI5NGEvYmE2ODE1NWUtOTQ5ZS00OTYxLWIwYjItMTI0NzU3Y2IwN2JiIiwiaWF0IjoxNzc4MTgxNjUwLCJleHAiOjE4MDk3NTIyMTB9.45f1ZzBpWOF5OCJV0xHfICdpyRQ1UoGMbJjLYPqeAkg
" alt="Before: Claude Code logo rendering is distorted in the web
terminal outside and inside tmux" width="640" /> | <img
src="https://uploads.linear.app/e62091d9-44f5-421c-8e5c-df481fc99003/26b0a109-5e21-4000-b1b5-ddac87c409d4/46a301c2-a815-419a-92d2-c51cecdefe40?signature=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXRoIjoiL2U2MjA5MWQ5LTQ0ZjUtNDIxYy04ZTVjLWRmNDgxZmM5OTAwMy8yNmIwYTEwOS01ZTIxLTQwMDAtYjFiNS1kZGFjODdjNDA5ZDQvNDZhMzAxYzItYTgxNS00MTlhLTkyZDItYzUxY2VjZGVmZTQwIiwiaWF0IjoxNzc4MTgxNjUwLCJleHAiOjE4MDk3NTIyMTB9.SQVwUbtaf2OrpjRJPkRH3uc0nPqad0bNBVvcRyuR6NQ
" alt="After: Claude Code logo renders correctly in the web terminal
outside and inside tmux" width="640" /> |

## Validation

* `go test ./agent -run '^TestAgent_ReconnectingPTY$' -count=1`
* `pnpm --dir site test -- src/theme/constants.test.ts`
* `pnpm --dir site lint:types`
* `pnpm --dir site check`
* `pnpm --dir site build`
* `git commit` pre-commit hook passed
* `git push` pre-push hook ran and printed the repo CI monitoring hint

> Mux worked on this PR on Mike's behalf.

---------

Co-authored-by: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com>
2026-05-20 13:57:50 +02:00
Danielle Maywood 962b6850cf chore(site): update lexical to 0.44.0 (#25524) 2026-05-20 11:52:43 +01:00
Ethan e6fe9916d6 fix: pin chat timestamp chromatic ignore-mask width (#25522)
Follow-up to #25429, which wrapped `shortRelativeTime(chat.updated_at)`
in `<span data-chromatic="ignore">` to stop the chat row timestamp from
drifting `"46m" → "5m" → "now"` across Chromatic runs. Chromatic kept
flagging a sliver of change just to the left of the rendered text, even
though the area looks empty.

[Chromatic's docs](https://www.chromatic.com/docs/ignoring-elements/)
explain why: `data-chromatic="ignore"` masks pixel diffs **inside the
element's bounding rectangle**, but dimension changes of that rectangle
still trigger a diff. The wrapper span has no explicit width, so it
sizes to its text — `"46m"` (≈22px) shrinks to `"now"` (≈19px), the mask
shrinks by ~3px on its left edge, and that exposed strip is what
Chromatic was reporting.

Fix: pin the wrapper to `inline-block w-7 text-right`. `w-7` matches the
surrounding `w-7` column, and `text-right` keeps the trailing edge
anchored so the bounding rect is identical regardless of which
`shortRelativeTime` branch fired. The unread-dot branch is untouched and
keeps its own Chromatic coverage.
2026-05-20 19:55:54 +10:00
Danielle Maywood 96e3c49670 feat: add chat sharing API (#24968) 2026-05-20 10:46:35 +01:00
Danny Kopping dd3223451b feat: add AI providers HTTP CRUD handlers (#24894) 2026-05-20 10:21:36 +02:00
Michael Suchacz 9c2e0aac88 fix(site/src/pages/AgentsPage): widen inline desktop preview to fill chat (#25497) 2026-05-20 08:42:30 +02:00
Ethan 4c362499f2 fix(site): keep workspace quota meter live-updated in Agents chat (#25468)
The workspace quota meter in the Agents chat sidebar previously only
refreshed on a full page reload, while the AI cost-usage meter rendered
next to it already polled every 60 seconds.

This change gives the Agents usage indicator the same 60s
workspace-quota polling and refreshes derived workspace caches
immediately when workspace-affecting chat tools complete.
`create_workspace`, `start_workspace`, and `stop_workspace` now
invalidate the workspace quota and `workspaces` query family, so both
the credit numbers and the workspace-count detail stay in sync.

`create_workspace` still invalidates the chat record to resolve
workspace bindings, and archive-and-delete uses the shared workspace
mutation invalidation helper so deleting an agent workspace refreshes
the same derived workspace data.

Closes CODAGT-444


Tested manually and it works perfectly.
2026-05-20 12:30:28 +10:00
Michael Suchacz 5a8d0016a5 feat: add personal skill storage, API, and SDK (#25363)
> Mux updated this PR on behalf of Mike.

## Stack Context

This PR is the storage, permissions, API, and SDK layer for experimental
personal skills. #25362 has landed on `main`, so this branch is
restacked directly on `main`.

Stack order:
1. #25363 storage, permissions, API, and SDK
2. #25365 API test coverage
3. #25366 chattool and chatd integration
4. #25066 settings UI and docs
5. #25386 personal skills slash menu

## What?

Adds the `user_skills` database table, generated queries, RBAC resources
and scopes, audit resource handling, experimental user-scoped CRUD
endpoints, SDK types, and generated API/site types.

Follow-up review and restack fixes:
- Enforce a bounded personal skill description in parser and database
constraints.
- Return `403 Forbidden` for unauthorized create and update attempts.
- Return explicit conflict responses when soft-deleted users are
targeted.
- Keep user admins out of personal skills, while site owners can read
and delete but not create or update.
- Document trigger-raised constraint names and keep schema constants
covered by tests.
- Reuse `UserSkillMetadata` in the full `UserSkill` SDK response type.
- Generate user skill IDs in Go instead of relying on a database
default.
- Rebase on latest `main` and renumber the user skills migration to
`000502_user_skills`.

## Why?

Personal skills need durable user-owned storage with owner
authorization, limited site-owner moderation, and a hidden API surface
before chatd can consume them.

## Validation

- `make gen`
- `go test ./coderd/database -run '^TestUserSkillSchemaConstants$'
-count=1`
- `go test ./coderd/database/dbauthz -run
'^TestMethodTestSuite/TestUserSkills$' -count=1`
- `go test ./coderd -run '^TestPatchUserSkill$' -count=1`
- `go test ./codersdk ./coderd/database/db2sdk`
- `make lint`
- pre-commit hook on `97fd58108d`
2026-05-20 00:09:09 +02:00
Michael Suchacz 951a8e7237 feat: add intent labels to execute tool (#25482)
> Mux opened this PR on behalf of Mike.

Fixes CODAGT-451

Adds optional `model_intent` metadata to the built-in execute tool
schema so tool calls can carry a short user-facing intent label without
duplicating the command or duration.

The Agents UI now composes that intent with the existing execute command
and duration fields, displaying labels like `Checking repository state
using git fetch origin for 2.3s` while keeping the shell command visible
as the audit-relevant action.

Existing execute calls without an intent keep the previous `Ran
<command>` fallback label, so only intent-bearing calls get the new
composed label.
2026-05-19 18:47:12 +02:00
dylanhuff-at-coder 441854daa8 feat: add user secrets client utilities (#25370)
Add frontend API methods, mocks, and form helpers for user secrets CRUD. The new client methods cover list, get, create, update, and delete requests, including URL encoding for secret names used in route paths.

Add user secret form utilities for create and update payload construction, required create field checks, and structured API validation error mapping back to form fields. User secret name validation now lives in codersdk with tests, and coderd returns field-level validation errors for create, update, and uniqueness conflicts so the frontend can show backend-owned validation results consistently.
2026-05-19 09:30:31 -07:00
Cian Johnston ce7f41f56d fix: bump MaxChatFileIDs from 20 to 50 (#25492)
Fixes CODAGT-456
2026-05-19 16:53:30 +01:00
Steven Masley 1afc6d4fd0 feat: structured disconnect attribution for agent logs (#25191)
Implements
[PLAT-60](https://linear.app/codercom/issue/PLAT-60/enhance-disconnect-logs-with-structured-reason-attribution):
adds structured disconnect attribution to disconnect logs throughout the
agent and tailnet packages.

Every disconnect log site now carries structured slog fields. All
existing logs remain; existing messages are preserved with the fields
added alongside.

New fields on disconnect log lines:

- `connect_type` — which layer disconnected: `server_to_agent`,
`agent_to_client`, or `client_to_server`
- `disconnect_reason` — categorical reason: `graceful`, `network_error`,
`server_shutdown`, etc.
- `disconnect_expected` — whether the disconnect is normal operation
(`true`) or should be investigated (`false`)
- `disconnect_initiator` — who started it: `client`, `agent`, `server`,
or `network` (control-plane sites only)
- `disconnect_detail` — free-form supplemental info (where useful)

## What's covered

**Control plane (`server_to_agent`):** coordination RPC, DERP map
subscriber, agent runLoop, agent Close, `BasicCoordination.Close`,
`Controller.run`.

**Data plane (`agent_to_client`):** SSH sessions, reconnecting PTY,
JetBrains port-forwarding.

<details>
<summary>Control-plane sites</summary>

| Site | Reason | Initiator |
|---|---|---|
| `agent/agent.go` `runLoop` EOF | `network_error` | `network` |
| `agent/agent.go` `runCoordinator` deferred exit | `server_shutdown` /
`graceful` / `network_error` | `agent` / `server` / `network` |
| `agent/agent.go` `runDERPMapSubscriber` deferred exit | same (shared
`classifyCoordinatorRPCExit`) | same |
| `agent/agent.go` `Close` shutdown timeout | `server_shutdown` + detail
| `agent` |
| `agent/agent.go` `Close` clean coord disconnect | `server_shutdown` |
`agent` |
| `tailnet/controllers.go` `BasicCoordination.Close` | `graceful` or
`network_error` | `c.initiator` |
| `tailnet/controllers.go` `Controller.run` `net.ErrClosed` |
`network_error` | `network` |

</details>

<details>
<summary>Data-plane sites</summary>

| Site | Reason | Notes |
|---|---|---|
| `agent/agentssh/agentssh.go` SSH session closed | free-form
(`graceful`, `process exited with error status: N`, etc.) | Also sets
`closeCause("normal exit")` for clean exits so coderd's
`connection_log.DisconnectReason` is no longer empty |
| `agent/reconnectingpty/server.go` PTY closed | `server_shutdown`,
error string, or `graceful` | |
| `agent/agentssh/jetbrainstrack.go` channel closed | `normal close` or
error string | Previously passed empty reason |

</details>

<details>
<summary>Bug fix</summary>

The deferred `disconnected from coordination RPC` log no longer fires
when the initial `Coordinate()` RPC call fails before any connection is
established.

</details>

Refs PLAT-60.

---

_This PR was prepared by Coder Agents on behalf of @Emyrk._
**Manually QA'd a lot of common disconnects**

---------

Co-authored-by: Coder Agents <noreply@coder.com>
2026-05-19 09:47:03 -05:00
Bartek Gatz ba0df64390 chore(site): update Codernauts roster to 47 entries (#25427)
Replace the original 13-person roster with the full 47-person list,
sorted alphabetically by first name.

cc @DanielleMaywood for review

> [!NOTE]
> This PR was authored by Coder Agents.
2026-05-19 12:59:06 +02:00
Danielle Maywood 170a6e1fe9 feat: add chat sharing foundation (#25041) 2026-05-18 22:32:05 +01:00
Yevhenii Shcherbina 2732378da2 feat: audit group AI budget mutations (#25374)
Relates to
https://linear.app/codercom/issue/AIGOV-284/add-group-budgets-table-and-crud-api

Adds audit-log support for `group_ai_budget` mutations. Without it, an
admin could silently lower a spend limit from `$500` to `$50` or delete
a budget entirely, with no record of who performed the action.

Both write (`create-or-update`) and delete actions now produce audit log
entries, including before/after diffs for `spend_limit_micros`.

Depends on #25203.

## Old Version
<img width="1340" height="456" alt="image"
src="https://github.com/user-attachments/assets/e9ff52fb-a905-4aef-a4ee-7cdc58e68b75"
/>

## New Version (see
https://github.com/coder/coder/pull/25374/changes/9d22833de87cc106c24142c1d471a3f71872bf67)
<img width="1347" height="496" alt="image"
src="https://github.com/user-attachments/assets/1b9bbfa1-f86d-48e3-a0b1-266eb76f851f"
/>
2026-05-18 15:17:20 -04:00
Kyle Carberry 385146000b feat: record created_at/completed_at on reasoning ChatMessageParts (#24789)
Records reasoning start and end times on persisted reasoning
`ChatMessagePart`s so reasoning duration can be computed for stored
chats. Backend-only: no SSE changes and no frontend rendering ship in
this PR.

The `created_at` field on `ChatMessagePart` is extended to also be
present on `reasoning` parts (it previously appeared only on `tool-call`
and `tool-result`), and a new `completed_at` field is added for
`reasoning` parts.

### How timestamps are recorded

- `StreamPartTypeReasoningStart`: stamp `startedAt = dbtime.Now()` on
the active reasoning state.
- `StreamPartTypeReasoningEnd`: stamp `completedAt = dbtime.Now()` and
append both into parallel `[]time.Time` slices on `stepResult`.
- Persistence reads the slices in occurrence order (reasoning has no
provider-side ID) and applies them to the matching `ChatMessagePart` via
`buildAssistantPartsForPersist`. The first reasoning block's stamps go
onto the first reasoning part, and so on.
- `flushActiveState` flushes partial reasoning interrupted before
`StreamPartTypeReasoningEnd` with `startedAt` from the active state and
`completedAt = dbtime.Now()` at the interruption.

### Why two fields, not one?

Tool calls and results are point events. The frontend computes their
duration by subtracting the call's `created_at` from the result's
`created_at`. Reasoning is one assistant part that brackets a span, so
we record both endpoints on the part itself.

### Why not stamp in `PartFromContent`?

Same rationale as #24101: `PartFromContent` is called during both SSE
publishing and persistence. Stamping there would yield incorrect
persistence-time timestamps for reasoning blocks that finished much
earlier in the step. Instead we capture in the chatloop and apply during
persistence.

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

- `codersdk/chats.go`: extend `CreatedAt`'s `variants` to include
`reasoning?`; add `CompletedAt *time.Time` with `variants:"reasoning?"`.
- `coderd/x/chatd/chatloop/chatloop.go`: extend `reasoningState` with
`startedAt`; extend `stepResult` and `PersistedStep` with parallel
`[]time.Time` reasoning slices; stamp on
`ReasoningStart`/`ReasoningEnd`; thread the slices through all
`PersistStep` call sites including the interrupt-safe path; record
partial reasoning in `flushActiveState`.
- `coderd/x/chatd/attachments.go`: walk reasoning parts in occurrence
order and apply `step.ReasoningStartedAt[i]` to `part.CreatedAt` and
`step.ReasoningCompletedAt[i]` to `part.CompletedAt`.

### Tests

- `codersdk/chats_test.go` round-trips `created_at` + `completed_at` on
reasoning parts and verifies omission when absent and partial
interrupted parts.
- `coderd/x/chatd/chatprompt/chatprompt_test.go` asserts
`PartFromContent(ReasoningContent{})` does NOT stamp timestamps.
- `coderd/x/chatd/chatloop/chatloop_test.go`
`TestRun_ReasoningTimestamps` drives a stream with two reasoning blocks
and verifies parallel slices, monotonicity, ordering, non-zero values,
and content-block ordering.
`TestRun_InterruptedReasoningFlushesTimestamps` cancels mid-reasoning
and verifies `flushActiveState` records a non-zero pair.
- `coderd/x/chatd/attachments_test.go` covers
`buildAssistantPartsForPersist` for normal interleaved reasoning,
partial (zero `completed_at`), and missing slices.

</details>

> Generated by Coder Agents.

Co-authored-by: Coder Agent <agent@coder.com>
2026-05-18 12:30:30 -04:00
Danielle Maywood 46821525f7 fix(site): refine execute tool transcript UI (#25432) 2026-05-18 14:44:43 +01:00
Danny Kopping c69dd9c5dc feat: widen ai_provider_type enum for chatd providers (#25394) 2026-05-18 15:06:30 +02:00
Danny Kopping 0770428a5c feat: add AIProvider types and client methods (#24893) 2026-05-18 11:10:30 +02:00
Ethan 6a79f5f62e fix: ignore drifting timestamp in stories (#25429)
The `SectionHeadersCollapse` story (and every other
Chromatic-snapshotted story rendering the agents sidebar) was flaky
because each chat row renders `shortRelativeTime(chat.updated_at)` —
`"now"`, `"5m"`, `"7h"`, `"1d"`, etc. The values are computed against
the live wall clock from fixed fixture timestamps, so the rendered text
drifts on every run (e.g. `"7h"` → `"now"` mid-day) and Chromatic diffs
the change.

This wraps the timestamp in `<span data-chromatic="ignore">`, the
dominant codebase convention for time-varying text.
`data-chromatic="ignore"` appears 35 times across 20 files in
`site/src`, including `utils/schedule.tsx:139,153`,
`components/LastSeen/LastSeen.tsx:42`,
`modules/provisioners/Provisioner.tsx:80`,
`pages/OrganizationSettingsPage/.../ProvisionerRow.tsx:119`,
`JobRow.tsx:139`, `ProvisionerKeyRow.tsx:81`,
`pages/AIBridgePage/RequestLogsPage/RequestLogsRow/RequestLogsRow.tsx`
(multiple rows), `pages/HealthPage/WorkspaceProxyPage.tsx:144`, and
`pages/UserSettingsPage/TokensPage/TokensPageView.tsx:117`. By
comparison, only one component (`AppStatuses`) plumbs a reference date
through props, and there is no `Date.now`-stubbing precedent that would
actually stabilize `dayjs()`-based output like `shortRelativeTime`.

The wrap is scoped tightly: only the text node returned by
`shortRelativeTime` is ignored, so the sibling unread-indicator dot and
surrounding layout still participate in snapshots.
2026-05-18 18:21:00 +10:00
Dean Sheather 5cc655806f fix(site/src/pages/AgentsPage): sanitize chat upload filenames client-side (#25421)
Filenames from the OS (e.g. `Screen Shot 2025-01-01 at 10.00.00 AM.png`
or `My Report (final).pdf`) flow unchanged through the chat-attach hooks
into chip labels, the persisted-attachment localStorage records, the
upload `Content-Disposition` header, and downstream LLM prompts.
Characters such as parentheses, brackets, quotes, shell or URL or path
metacharacters, whitespace, and control codes are all valid in HTTP
transport today but tend to break things further down the line (LLM tool
calls that quote the name, audit logs, any future S3/path interpolation,
shell-quoted tooling).

Sanitize at the boundary in `useFileAttachments.handleAttach` and
`useChatDraftAttachments.handleAttach` by mapping each incoming `File`
through a new `renameChatFileForUpload` helper. The helper replaces
`()[]{}<>'\"\`;,:*?|&#$\\/`, whitespace, and control characters with
`_`, collapses adjacent underscores, trims leading or trailing `_`, `.`,
or whitespace, and falls back to `"file"` if the result is empty. ASCII
alphanumerics, `.`, `-`, `_`, and all other Unicode letters and symbols
(CJK, emoji, accented Latin) are preserved so localized names remain
readable. Already-safe names return the same `File` reference; the chat
UI keys preview-URL, upload-state, and text-content Maps on the `File`
object, so identity must be stable.

The server's existing `chatfiles.NormalizeStoredFileName` (control-char
strip plus 255-byte truncate) is untouched. This is a client-only
hardening pass.
2026-05-18 07:07:31 +00:00
Michael Suchacz 3723f7a0c7 feat(site/src/pages/AgentsPage/components/ChatConversation): jump between user prompts via arrow buttons (#25336)
Add prev/next chevron buttons to the action row under each user message
in the agent chat transcript. Clicking jumps the scroll container to the
neighbouring user prompt's sticky sentinel (smooth scroll, no composer
mutation). Arrows disable rather than wrap when at the ends.

## Why

When a chat gets long, scrolling back to a previous prompt to see the
question that produced an answer is annoying. The transcript already has
a stable per-prompt anchor (`data-user-sentinel`) used by the
sticky-message logic, so reusing it for navigation is cheap and
consistent with the existing scroll model.

## Implementation

- `ChatMessageItem` accepts three optional props (`prevUserMessageId`,
`nextUserMessageId`, `onJumpToUserMessage`) and renders the two chevron
buttons inside the existing `message-actions` row when the message is a
user role.
- `StickyUserMessage` forwards the props to both copies of
`ChatMessageItem` (flow + sticky overlay).
- `ConversationTimeline` derives the ordered list of visible user
message IDs using the same `deriveMessageDisplayState` predicate that
controls visibility, builds a neighbour map, and supplies the jump
handler. The handler resolves the target via
`[data-user-sentinel][data-user-message-id="..."]` and smooth-scrolls
the closest `.overflow-y-auto` ancestor by the sentinel's offset
(mirroring the existing edit-flow scroll helper).
- New `data-user-message-id` attribute on the sentinel `div` to make the
lookup direct.
- New Storybook story `UserMessageJumpArrows` covers: arrow counts,
disabled-at-ends, and that clicking Next scrolls the next user sentinel
to the top of the scroller. JSDOM doesn't animate smooth scroll, so the
play function monkey-patches `scrollBy` to apply the requested top
offset synchronously.

No API, DB, or audit-table changes. Frontend only.

## Test

- `pnpm test:storybook
src/pages/AgentsPage/components/ChatConversation/ConversationTimeline.stories.tsx`
— 46 passed (incl. new story).
- `pnpm test:storybook
src/pages/AgentsPage/components/ChatConversation/` — 67 passed.
- `pnpm lint:types`, `pnpm lint:fix`, `pnpm lint:compiler`, `pnpm
format:check` — all clean.
- Local `make pre-commit` ran via the pre-commit hook on commit.

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

Plan lives at
`/home/coder/.coder/plans/PLAN-41b442d8-05bc-4b62-b1ba-155a7cef09bc.md`
in the agent workspace. Summary:

1. Add three optional props (`prevUserMessageId`, `nextUserMessageId`,
`onJumpToUserMessage`) to `ChatMessageItem` and render
`ChevronLeft`/`ChevronRight` buttons inside the existing actions row
when the message is a user role. Disable each button when its neighbour
is undefined.
2. Forward those props through `StickyUserMessage` to both
`ChatMessageItem` instances (flow + sticky overlay).
3. In `ConversationTimeline`, build the ordered list of visible user IDs
using the same `deriveMessageDisplayState` predicate, derive a neighbour
map, and implement `handleJumpToUserMessage` that looks up
`[data-user-sentinel][data-user-message-id="${id}"]`, finds the closest
`.overflow-y-auto` ancestor, and smooth-scrolls by the sentinel's
offset.
4. Add `data-user-message-id` to the sentinel so the lookup is direct.
5. Cover the behaviour with a `UserMessageJumpArrows` Storybook play
function.

</details>

---

*This PR was authored by Coder Agents on behalf of @ibetitsmike.*
2026-05-16 21:47:22 +02:00
Matt Vollmer d9976768db fix(site): copy token value from modal (#25399) 2026-05-15 16:52:55 -04:00
Jaayden Halko 2c18e07e39 feat: add theme mode dropdown (#25183)
## Summary

- Wire the Appearance settings page to the new theme mode dropdown and
sync or single theme selectors.
- Update Appearance page tests and stories for theme mode behavior.
- Update the user settings e2e test to exercise single theme selection.

## Dependencies

- Depends on #25076, #25180, #25181, and #25182.
- This PR targets helper branch `pr25077/05-theme-mode-dropdown-base`,
which contains dependency commits only, so this PR diff stays focused on
final dropdown wiring. Rebase and retarget after the dependency PRs
merge.

## Validation

- `pnpm -C site exec vitest run --project=unit
src/pages/UserSettingsPage/AppearancePage/AppearancePage.test.tsx
src/theme/themeMode.test.ts src/api/queries/users.test.ts`
- `pnpm -C site lint:types`
- `pnpm -C site storybook:ci`
- `pnpm -C site build`
- `pnpm -C site playwright:test -- e2e/tests/users/userSettings.spec.ts`
- Pre-commit hook passed on the branch commit.
2026-05-15 16:15:06 +01:00
Danielle Maywood b94cb38504 style(site): use terminal icon for shell tool (#25392) 2026-05-15 13:39:51 +00:00
Jaayden Halko 8650a2ee22 fix: rollback appearance mutation cache updates (#25182)
## Summary

- Add appearance mutation context so optimistic cache updates can be
rolled back on failure.
- Restore previous appearance settings, or remove the optimistic cache
entry when no previous data exists.
- Merge successful server responses back into the appearance cache while
preserving request fields when responses are partial.

## Dependencies

- Stacked on #25076 because the tests and generated types use the new
appearance theme mode fields.

## Validation

- `pnpm -C site exec vitest run --project=unit
src/api/queries/users.test.ts`
- `pnpm -C site lint:types`
- Pre-commit hook passed on the branch commit.
2026-05-15 10:50:29 +01:00
Jaayden Halko e8cfff40b4 feat(site): add theme mode frontend foundation (#25181)
## Summary

- Add theme mode helpers for legacy migration, active theme resolution,
draft conversion, and mode switching.
- Add `usePreferredColorScheme` and refactor `ThemeProvider` to use the
shared theme mode resolver.
- Add reusable Appearance theme picker components plus isolated
Storybook coverage.

## Dependencies

- Stacked on #25180.

## Validation

- `pnpm -C site exec vitest run --project=unit
src/theme/themeMode.test.ts src/theme/usePreferredColorScheme.test.tsx`
- `pnpm -C site lint:types`
- `pnpm -C site lint:knip`
- Pre-commit hook passed on the branch commit.
2026-05-15 10:04:48 +01:00
Yevhenii Shcherbina 238968cfa0 feat: add per-group AI budget table and endpoints (#25203)
Closes
https://linear.app/codercom/issue/AIGOV-284/add-group-budgets-table-and-crud-api

## Summary

Adds the `group_ai_budgets` table and the following endpoints:

- `GET /api/v2/groups/{group}/ai/budget`
- `PUT /api/v2/groups/{group}/ai/budget`
- `DELETE /api/v2/groups/{group}/ai/budget`

Each group may have at most one budget row. If no row exists, no budget
is enforced.

### Feature gate
  
Added `RequireFeatureMW(FeatureAIBridge)` on the `/ai/budget` sub-route.

## RBAC

Authorization reuses `rbac.ResourceGroup` with the existing
`.InOrganization(...).WithID(...)` scoping model.

The `dbauthz` wrappers load the parent `groups` row and authorize
against it.

No new resource type is introduced. As a result, anyone with
`group:update` permissions (Owner, OrgAdmin, or UserAdmin within the
organization) can manage AI budgets for that group.

## Read access for group members

`database.Group.RBACObject()` grants `policy.ActionRead` to all members
of the group through the group ACL:

```go
func (g Group) RBACObject() rbac.Object {
	return rbac.ResourceGroup.WithID(g.ID).
		InOrg(g.OrganizationID).
		// Group members can read the group.
		WithGroupACL(map[string][]policy.Action{
			g.ID.String(): {
				policy.ActionRead,
			},
		})
}
```

Because the `GET` endpoint authorizes against the same loaded `Group`
object, any group member can call:

```text
GET /api/v2/groups/{group}/ai/budget
```

`PUT` and `DELETE` remain admin-only. The group ACL grants only
`ActionRead`, so write operations continue to require role-based
`group:update` permissions.

## Alternative considered

A dedicated `rbac.ResourceGroupAiBudget` resource would allow budget
management to be separated from general group administration.

We decided not to add that complexity for now.
2026-05-14 15:54:37 -04:00
Tyler d79cfcfe61 fix(site): move docs link to primary header on observability page (#25313)
Move the "Read the docs" button from the Audit Logging subsection up to
the primary Observability header's `actions` prop, matching the layout
pattern used by General, Network, and other deployment settings pages.

Also updates the docs URL from `/admin/security/audit-logs` to
`/admin/monitoring` to reflect the page-level scope.

> Generated by Coder Agents on behalf of @designertyler

---------

Co-authored-by: TJ <tracy@coder.com>
2026-05-14 13:57:01 -05:00
Kayla はな a43690d29b chore: add storybook to .mcp.json (#25352) 2026-05-14 12:40:23 -06:00
Danielle Maywood 68baf84b8c fix: hide empty execute tool calls (#25346) 2026-05-14 18:19:12 +01:00