Commit Graph
13456 Commits
Author SHA1 Message Date
Ethan 5cba59af79 fix(coderd): unarchive child chats with parents (#23761)
Unarchiving a root chat now restores descendant chats in the database
and emits lifecycle events for every affected chat so passive sessions
converge without a full refetch.

This keeps archive and unarchive symmetric at both the data and
watch-stream layers by returning the affected chat family from the
database, using those post-update rows for chatd pubsub fanout, and
covering descendant lifecycle delivery with a watch-level regression
test.

Closes #23666
2026-04-01 15:30:25 +11:00
Jeremy RuppelandJake Howell 1d16ff1ca6 fix(site): sessions list and timeline polish (#23885)
- Prompt table was collapsing and sizing improperly, fixed 
- Make pretty much everything `text-sm` and `font-normal`
- Add model filter
- Back button on session threads page now navigates back instead of
going straight to `/aibridge/sessions`

---------

Co-authored-by: Jake Howell <jake@hwll.me>
2026-04-01 14:42:08 +11:00
Ethan b86161e0a6 test: fix TestServer_X11_EvictionLRU hang on fish shell (#23838)
`TestServer_X11_EvictionLRU` hangs forever when the developer's login
shell is `fish`. This is the only test in the repo that breaks on fish,
and it meant I couldn't run `make test` or similar without it blocking
indefinitely.

The test uses `sess.Shell()` to start interactive shell sessions, which
causes the SSH server to run the user's login shell directly (`fish
-l`). Fish buffers all piped stdin to EOF before executing any of it, so
the test's `echo ready-0\n` write never gets processed — fish sits
waiting for the pipe to close, and the test sits waiting for the echo
response.

The fix is a one-line change: `sess.Shell()` → `sess.Start("sh")`. The
test is exercising X11 LRU eviction, not shell behavior, so using `sh`
explicitly is both correct and shell-agnostic. The DISPLAY environment
variable is set identically either way since the x11-req handler runs
before `sessionStart`.
2026-04-01 12:31:22 +11:00
Cian Johnston a164d508cf fix(coderd/x/chatd): gate control subscriber to ignore stale pubsub notifications (#23865)
Fixes flaky `TestOpenAIReasoningWithWebSearchRoundTripStoreFalse` and
`TestOpenAIReasoningWithWebSearchRoundTrip`.

## Changes

- Gate the `processChat` control subscriber's cancel callback behind a
`chan struct{}` that is closed after publishing `"running"` status
- Add `TestGatedControlCancel` with 4 subtests exercising the gate logic

<details>
<summary>Root cause analysis</summary>

`SendMessage` publishes a `"pending"` notification on
`chat:stream:<chatID>` via PostgreSQL `NOTIFY`. `processChat` subscribes
to the same channel for control signals. Due to async NOTIFY delivery,
the `"pending"` notification can arrive at the control subscriber
**after** it registers its queue — even though it was published
**before**. `shouldCancelChatFromControlNotification("pending")` returns
`true`, immediately self-interrupting the processor before it does any
work.

The fix gates the cancel callback behind a closed channel. The channel
is closed after `processChat` publishes `"running"` status, so stale
notifications from before initialization are harmlessly ignored.
`close()` provides a happens-before guarantee in the Go memory model.
</details>

> 🤖 Written by a Coder Agent. Reviewed by a human.
2026-03-31 22:55:20 +01:00
Kayla はな b9f140e53e chore: remove Language objects (#23866) 2026-03-31 15:26:59 -06:00
Jeremy RuppelandJake Howell 7f7b13f0ab fix(site): share AI Bridge entitlement/permissions logic (#23834)
Introduces a new `getAIBridgePermissions` method that all AI Bridge
pages can use to restrict access/paywall. Also adds the paywall and
alert to the session threads page bc I totes forgot.

---------

Co-authored-by: Jake Howell <jacob@coder.com>
2026-03-31 17:19:46 -04:00
Michael Suchacz e2bbd12137 test(coderd/x/chatd): remove flaky OpenAI round-trip tests (#23877) 2026-03-31 17:04:56 -04:00
Danielle Maywood e769d1bd7d fix(site): update story play functions after HelpTooltip→HelpPopover migration (#23876) 2026-03-31 21:50:05 +01:00
Jeremy Ruppel cccb680ec2 chore: remove shared workspaces beta badge (#23873) 2026-03-31 16:25:42 -04:00
Danielle Maywood e8fb418820 fix(site): delay desktop VNC connection until tab is selected (#23861) 2026-03-31 18:42:36 +01:00
Kyle Carberry 2c5e003c91 refactor(site): use hover popover for context indicator with nested skill tooltips (#23870)
Replaces the tooltip-inside-tooltip approach for the context usage
indicator with a hover-based Popover. Skill descriptions now appear as
nested tooltips to the right, matching the ModelSelector pattern.

**Before**: Tooltip with inline skill descriptions (truncated, janky
nested tooltips)
**After**: Popover opens on hover, skill names listed cleanly,
descriptions appear to the right on hover

- Popover opens on `mouseEnter`, closes after 150ms delay on
`mouseLeave`
- `onOpenAutoFocus` prevented to avoid stealing chat input focus
- Mobile keeps tap-to-toggle Popover behavior
- Skill rows get subtle `hover:bg-surface-tertiary` highlight
- `TooltipProvider` with `delayDuration={300}` wraps skill items (same
as ModelSelector)
2026-03-31 13:40:26 -04:00
code-qtzl f44a8994da fix(site): improve keyboard navigation in help popovers (#23374) 2026-03-31 11:10:33 -06:00
Yevhenii Shcherbina 84b94a8376 feat: add chatgpt support for aibridge proxy (#23826)
Add ChatGPT support for AIBridgeProxy
2026-03-31 12:54:38 -04:00
Cian Johnston 2a990ce758 feat: show friendly alert for missing agents-access role (#23831)
Replaces the generic red `ErrorAlert` ("Forbidden.") with a proactive
permission check and friendly info alert when a user lacks the
`agents-access` role.

- Add `createChat` permission check to `permissions.json` using
`owner_id: "me"`
- Handle `"me"` owner substitution in `renderPermissions` (SSR path)
- Pass `canCreateChat` from `useAuthenticated().permissions` into
`AgentCreateForm`
- Show `ChatAccessDeniedAlert` and disable input immediately (no need to
trigger a 403 first)
- Also catch 403 errors as a fallback in case permissions aren't yet
loaded
- Add `ForbiddenNoAgentsRole` Storybook story with `play` assertions
- Add `TestRenderPermissionsResolvesMe` Go test to pin the `"me"`
sentinel substitution

<details><summary>Implementation plan & decision log</summary>

- Uses the existing `permissions.json` + `checkAuthorization` system
rather than a separate API call
- `owner_id: "me"` is resolved to the actor's ID by both the auth-check
API endpoint and the SSR `renderPermissions` function
- Go test uses a real `rbac.StrictCachingAuthorizer` (not a mock) so it
verifies both the sentinel substitution and the RBAC role evaluation
end-to-end
- Alert follows the exact same `Alert` pattern as the 409 usage-limit
block
- Uses `severity="info"` and links to the getting-started docs Step 3
- Textarea is disabled proactively so the user never sees the scary
generic error

</details>

> 🤖 Created by a Coder Agent and will be reviewed by a human.
2026-03-31 17:26:58 +01:00
Danny Kopping c86f1288f1 chore: update aibridge with latest changes (#23863)
https://github.com/coder/aibridge/compare/519b082ad666...a011104f377d

Includes https://github.com/coder/aibridge/pull/242 and
https://github.com/coder/aibridge/pull/229

Signed-off-by: Danny Kopping <danny@coder.com>
2026-03-31 16:11:50 +00:00
Yevhenii Shcherbina 9440adf435 feat: add chatgpt support for aibridge (#23822)
Registers a new aibridge provider for ChatGPT by reusing the existing
OpenAI provider with a different `Name` and `BaseURL`
(https://chatgpt.com/backend-api/codex). The ChatGPT backend API is
OpenAI-compatible, so no new provider type is needed.
ChatGPT authenticates exclusively via per-user OAuth JWTs (BYOK mode) —
no centralized API key is configured. The OpenAI provider already
handles this: when no key is set, it falls through to the bearer token
from the request's Authorization header.
  
  Depends on #23811
2026-03-31 12:08:45 -04:00
Kayla はな 755e8be5ad chore: migrate some emotion styles to tailwind (#23817) 2026-03-31 10:07:33 -06:00
Danielle Maywood c9e335c453 refactor: redesign compaction settings to table layout with batch save (#23844) 2026-03-31 17:06:12 +01:00
Jeremy RuppelandJake Howell 2d1f35f8a6 feat(site): session timeline design feedback (#23836)
- Remove `border-surface-secondary` from all line art and use the
default border color
- Use `text-sm` for all timeline elements and tables *(except the
`Thinking...` mono font, that's `text-xs`)

---------

Co-authored-by: Jake Howell <jacob@coder.com>
2026-03-31 12:02:19 -04:00
Susana Ferreira b0036af57b feat: register multiple Copilot providers for business and enterprise upstreams (#23811)
## Description

Adds support for multiple Copilot provider instances to route requests to different Copilot upstreams (individual, business, enterprise). Each instance has its own name and base URL, enabling per-upstream metrics, logs, circuit breakers, API dump, and routing.

## Changes

* Add Copilot business and enterprise provider names and host constants
* Register three Copilot provider instances in aibridged (default, business, enterprise)
* Update `defaultAIBridgeProvider` in `aibridgeproxy` to route new Copilot hosts to their corresponding providers

## Related

* Depends on: https://github.com/coder/aibridge/pull/240
* Closes: https://github.com/coder/aibridge/issues/152

Note: documentation changes will be added in a follow-up PR.

_Disclaimer: initially produced by Claude Opus 4.6, heavily modified and reviewed by @ssncferreira ._
2026-03-31 16:00:37 +01:00
Kyle Carberry 2953245862 feat(site): display loaded context files and skills in context indicator tooltip (#23853)
Renders the `last_injected_context` data (AGENTS.md files and skills)
from the Chat API in the `ContextUsageIndicator` hover tooltip. On
hover, users now see:

- **Context files**: basename with full path on title hover, truncation
indicator
- **Skills**: name and optional description

Separated from the existing token usage info by a border divider when
both sections are present. Added `max-w-72` to prevent the tooltip from
getting too wide.

<img width="970" height="598" alt="image"
src="https://github.com/user-attachments/assets/5bc25cb2-1d92-41d2-ab1a-63e5e49f667a"
/>

<details>
<summary>Data flow</summary>

```
chatQuery.data.last_injected_context
  → AgentChatPage (AgentChatPageView prop)
    → AgentChatPageView (ChatPageInput prop)
      → ChatPageInput (spread into latestContextUsage)
        → AgentChatInput (contextUsage prop)
          → ContextUsageIndicator (usage.lastInjectedContext)
```

</details>

<details>
<summary>Files changed</summary>

| File | Change |
|---|---|
| `ContextUsageIndicator.tsx` | Add `lastInjectedContext` to interface,
render context files and skills sections in tooltip |
| `ChatPageContent.tsx` | Thread `lastInjectedContext` prop, spread into
context usage object |
| `AgentChatPageView.tsx` | Thread `lastInjectedContext` prop to
`ChatPageInput` |
| `AgentChatPage.tsx` | Pass `chatQuery.data?.last_injected_context`
down |

</details>
2026-03-31 14:43:32 +00:00
Danny Kopping 5d07014f9f chore: update aibridge lib (#23849)
https://github.com/coder/aibridge/pull/230 has been merged, update the
dependency to match.

Includes other changes as well:
https://github.com/coder/aibridge/compare/dd8c239e5566...77d597aa123b
(cc @evgeniy-scherbina, @pawbana)

Signed-off-by: Danny Kopping <danny@coder.com>
2026-03-31 16:11:40 +02:00
Jeremy Ruppel 002e88fefc fix(site): use mock client model in sessions list view (#23851)
Missed this lil guy when adding the `<ClientFilter />` in #23733
2026-03-31 10:00:21 -04:00
Ethan bbf3fbc830 fix(coderd/x/chatd): archive chat hard-interrupts active stream (#23758)
Archiving a chat now transitions pending or running chats to waiting
before setting the archived flag. This publishes a status notification
on `ChatStreamNotifyChannel` so `subscribeChatControl` cancels the
active `processChat` context via `ErrInterrupted` — the same codepath
used by the stop button.

The `processChat` cleanup also skips queued-message auto-promotion when
the chat is archived, so archiving behaves like a hard stop rather than
interrupt-and-continue.

Relates to https://github.com/coder/coder/issues/23666
2026-04-01 00:23:52 +11:00
Danny Kopping 9fa103929a perf: make ListAIBridgeSessions 10x faster (#23774)
_Disclaimer: produced using Claude Opus 4.6, reviewed by me, and
validated against Dogfood dataset._

The `ListAIBridgeSessions` query materialized and aggregated all
matching interceptions before paginating, then ran expensive
token/prompt lookups across the full dataset. For a page of 25 sessions
against ~200k interceptions (our dogfood dataset), this meant:
- Three CTEs scanning all rows (filtered_interceptions, session_tokens,
session_root)
  - ARRAY_AGG(fi.id) collecting every interception ID per session
- Lateral prompt lookup via ANY(array_of_all_ids) running for every
session, not just the page
  - ~90MB of disk sorts and JIT compilation kicking in

The improvement is to restructure to paginate first and enrich after: a
single CTE groups interceptions into sessions with only cheap aggregates
(MIN, MAX, COUNT), applies cursor pagination and LIMIT, then lateral
joins fetch metadata, tokens, and prompts for just the ~25-row page.

  Measured against 220k interceptions / 160k sessions:

  | Metric             | Before | After |
  |--------------------|--------|-------|
  | Execution time     | 1800ms | 185ms |
  | Shared buffer hits | 737k   | 2.6k  |
  | Disk sort spill    | 86MB   | 16MB  |
  | Lateral loops      | 160k   | 25    |

https://grafana.dev.coder.com/goto/fbODPGtvR?orgId=1 the results are
identical, just _much_ faster.

--- 

Also includes some additional tests which I added prior to refactoring
the query to ensure no regressions on edge-cases.

---------

Signed-off-by: Danny Kopping <danny@coder.com>
2026-03-31 14:42:23 +02:00
Lukasz acd2ff63a7 chore: bump Go toolchain to 1.25.8 (#23772)
Bump the repository Go toolchain from 1.25.7 to 1.25.8.

Updates `go.mod`, the shared `setup-go` action default, and the dogfood
image checksum so local, CI, and dogfood builds stay aligned.
2026-03-31 14:04:58 +02:00
Atif Ali e3e17e15f7 fix(site): show accurate message and warning color for startup script failures in agent row (#23654)
The agent row tooltip showed "Error starting the agent" / "Something
went wrong during the agent startup" with a red border when a startup
script fails. This is misleading — the agent is started and functional,
only the startup script exited with a non-zero code.

Extracts shared message constants (`agentLifecycleMessages`,
`agentStatusMessages`) from `health.ts` so both the workspace-level
health classification and the per-agent-row tooltips reference the same
single source of truth. No more duplicated wording that can drift.

Changes:
- **`health.ts`**: Exports `agentLifecycleMessages` and
`agentStatusMessages` maps; `getAgentHealthIssue` now references them
instead of inline strings.
- **`AgentStatus.tsx`**: All lifecycle/status tooltip components
(`StartErrorLifecycle`, `StartTimeoutLifecycle`,
`ShutdownTimeoutLifecycle`, `ShutdownErrorLifecycle`, `TimeoutStatus`)
now import and render from the shared message constants.
`StartErrorLifecycle` icon changed from red (`errorWarning`) to orange
(`timeoutWarning`).
- **`AgentRow.tsx`**: `start_error` border changed from
`border-border-destructive` (red) to `border-border-warning` (orange).

Closes #23652
Refs #21389

> 🤖 This PR was created with the help of Coder Agents, and has been
reviewed by my human. 🧑‍💻
2026-03-31 12:04:51 +00:00
Michael Suchacz af678606fc fix(coderd/x/chatd): stabilize flaky request-count assertion in round-trip test (#23843)
The flaky test assumed the second streamed OpenAI request had already
been captured when the chat status event arrived. In practice, the
capture server can record that second request slightly later, which
intermittently left `streamRequestCount` at `1`.

This change waits for the second captured request before asserting on
the follow-up payload and relaxes the count check to a sanity check. The
test still verifies the `store=false` round-trip behavior without
depending on that timing race.

Fixes coder/internal#1433
2026-03-31 13:09:11 +02:00
Cian JohnstonandCopilot 3190406de3 fix(site): stop workspace deletes playing hide-and-seek (#23641)
- Fix workspaces list invalidation after kebab-menu delete and add
Storybook coverage for the immediate `Deleting` state.

> 🤖 This PR was made by Coder Agents and read by me.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-31 11:36:47 +01:00
Cian Johnston 3ce82bb885 feat: add chat-access site-wide role to gate chat creation (#23724)
- Add `chat-access` built-in role granting chat CRUD at User scope
- Exclude `ResourceChat` from member, org member, and org service
account `allPermsExcept` calls
- Allow system, owner, and user-admin to assign the new role
- Migration auto-assigns role to users who have ever created a chat
- Update RBAC test matrix: `memberMe` denied, `chatAccessUser` allowed

**Breaking change**: Members without `chat-access` lose chat creation
ability. Migration covers existing chat creators. Members who have never
created a chat do not get this role automatically applied.

> 🤖 This PR was created by a Coder Agent and reviewed by me.
2026-03-31 10:07:21 +01:00
Ethan 348a3bd693 fix(site): show archived filter on agents page when chat list is empty (#23793)
While running scaletests I noticed the archived filter button on the
agents sidebar would disappear when the current filter had zero results.
This made it impossible to switch between active and archived views once
one side was empty.

The filter dropdown was only rendered inside the Pinned or first
time-group section header. When `visibleRootIDs` was empty, neither
header existed, so the filter had nowhere to attach.

This keeps the original dropdown placement on section headers when chats
exist. When the list is empty, the empty-state box itself now provides a
"View archived →" or "← Back to active" link so users can always switch
filters without needing the dropdown.

<img width="322" height="191" alt="image"
src="https://github.com/user-attachments/assets/7fd9ca09-5f72-4796-a925-7fab570fdff5"
/>

<img width="320" height="184" alt="image"
src="https://github.com/user-attachments/assets/2f856088-c2dc-4e34-9ece-84144a1adf79"
/>

Both archived & unarchived look the same when there's at least one
agent:

<img width="322" height="194" alt="image"
src="https://github.com/user-attachments/assets/42c4d54b-e500-45b1-b045-c126144c35bd"
/>
2026-03-31 12:57:46 +11:00
Jeremy Ruppel 75f1503b41 feat(site): various Session Timeline fixes (#23791)
- Use Tooltip instead of Popover for AI Gov tooltip
- Fix Agentic Loop tool call summing
- Collapse all expandable sections by default
- Add solid background to "Show More" button
- Remove "Sort by" dropdown for v1
2026-03-30 19:25:03 -04:00
Danielle Maywood c33cd19a05 fix(site/scripts): guard check-compiler main block from test imports (#23825) 2026-03-30 22:11:15 +01:00
Danielle Maywood adcea865c7 fix(site): improve check-compiler.mjs quality and fix bugs (#23812) 2026-03-30 20:41:41 +00:00
Matt Vollmer 5e3bccd96c docs: fix tool tables and model option errors in agent docs (#23821)
Fixes factual errors found during a review of all pages under
`/docs/ai-coder/agents/`.

## Tool tables (`index.md`, `architecture.md`)

Both pages had incomplete tool tables. Added:

- `process_output`, `process_list`, `process_signal` — core workspace
tools always registered alongside `execute`, missing from both pages
- `propose_plan` — platform tool (root chats only), missing from both
pages
- `spawn_computer_use_agent` — orchestration tool (conditional), missing
from architecture.md

Also fixed the architecture.md claim that the agent is "restricted to
the tool set defined in this section" — it now mentions skills and MCP
tools with links to the relevant pages.

## Model options (`models.md`)

- **OpenAI / OpenRouter Reasoning Effort**: docs listed `low`, `medium`,
`high` — code has `none`, `minimal`, `low`, `medium`, `high`, `xhigh`.
Fixed both.
- **Removed hidden fields** that never appear in the admin UI:
  - Google: Safety Settings (`hidden:"true"`)
- OpenRouter: Provider Order, Allow Fallbacks (parent struct
`hidden:"true"`)
  - Vercel: Provider Options (`hidden:"true"`)

---

*PR generated with Coder Agents*
2026-03-30 16:24:45 -04:00
Mathias Fredriksson 3950947c58 fix(site): prevent scroll handler from killing autoScroll during pin convergence (#23818)
WebKit internally adjusts scrollTop during layout when content
above the viewport changes height, even with overflow-anchor:none.
These phantom adjustments fire scroll events where isNearBottom
returns false. The scroll handler was setting autoScrollRef =
nearBottom on every such event, permanently killing follow mode.

The scroll handler now only enables follow mode, never disables
it. When follow mode is active, the user is not wheel/touch
scrolling, and isNearBottom is false, this indicates a
browser-initiated scroll adjustment. Re-pin immediately and
set the restore guard so the pin's own scroll event is suppressed.

Disabling follow mode is exclusive to user-interaction handlers
(wheel, touch, scrollbar pointerdown) via handleUserInterrupt.

Guard-clear callbacks also check isNearBottom before dropping
the restoration flag, re-pinning if content grew between the
pin and the clear.
2026-03-30 22:45:58 +03:00
Kyle Carberry b3d5b8d13c fix: stabilize flaky chatd subscribe/promote queued tests (#23816)
## Summary

Fixes three flaky chatd tests that intermittently fail due to timing
races with the background run loop.

Closes coder/internal#1428

## Root Cause

`CreateChat` and `PromoteQueued` call `signalWake()` which writes to
`wakeCh`, triggering `processOnce` immediately. Even though
`newTestServer` sets `PendingChatAcquireInterval: testutil.WaitLong` to
prevent ticker-based polling, the wake channel bypasses this. This
causes `processOnce` to acquire and process the chat concurrently with
the test's manual DB updates and assertions.

### Failing tests

| Test | Failure | Cause |
|------|---------|-------|
| `TestPromoteQueuedAllowsAlreadyQueuedMessageWhenUsageLimitReached` |
`expected: "pending", actual: "running"` | Wake from `CreateChat` races
with manual `UpdateChatStatus`; wake from `PromoteQueued` acquires the
chat before the status assertion |
| `TestSendMessageInterruptBehaviorQueuesAndInterruptsWhenBusy` |
`should have 1 item(s), but has 2` | Wake from `CreateChat` triggers
`processChat` which auto-promotes a queued message, adding an extra row
to `chat_messages` |
| `TestSubscribeNoPubsubNoDuplicateMessageParts` | `Condition satisfied`
(duplicate events) | Pre-existing `WaitGroup.Add/Wait` race in the
`Eventually` + `WaitUntilIdleForTest` pattern |

## Fix

Introduces a `waitForChatProcessed` helper that:
1. Polls until the chat reaches a **terminal state** (not pending AND
not running)
2. Then calls `WaitUntilIdleForTest` to wait for the inflight
`WaitGroup`

Waiting for a terminal state (not just "not pending") avoids a
`sync.WaitGroup` `Add/Wait` race: `AcquireChats` updates the DB status
to `running` **before** `processOnce` calls `inflight.Add(1)`. Checking
only `status != pending` could return while `Add(1)` hasn't happened
yet, causing `Wait()` to return prematurely.

### Per-test changes

- **`TestSendMessageInterruptBehaviorQueuesAndInterruptsWhenBusy`**:
Call `waitForChatProcessed` after `CreateChat` before manually setting
running status
-
**`TestPromoteQueuedAllowsAlreadyQueuedMessageWhenUsageLimitReached`**:
Call `waitForChatProcessed` after `CreateChat`; remove the inherently
racy `status == pending` assertion after `PromoteQueued` (the wake
immediately acquires the chat). Key assertions on promoted message,
queue state, and message count remain.
- **`TestSubscribeNoPubsubNoDuplicateMessageParts`**: Replace inline
`Eventually` with the safer `waitForChatProcessed` helper

## Verification

All three tests pass 150 consecutive executions with `-race -count=10`
across 15 runs (0 failures).
2026-03-30 18:23:47 +00:00
blinkagent[bot]andblink-so[bot] a00afe4b5a chore(site): update proxy menu dialog text (#23765)
Updates the descriptive text in the proxy selection dropdown menu to be
clearer and more concise.

**Before:**
> Workspace proxies improve terminal and web app connections to
workspaces. This does not apply to CLI connections. A region must be
manually selected, otherwise the default primary region will be used.

**After:**
> Workspace proxies improve terminal and web app connections. CLI
connections are unaffected. If no region is selected, the primary region
will be used.

---------

Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
2026-03-30 11:20:05 -07:00
Kyle Carberry a5cc579453 feat: add last_injected_context column to chats table (#23798)
Adds a nullable JSONB column `last_injected_context` to the `chats`
table that stores the most recently persisted injected context parts
(AGENTS.md context-file and skill message parts). The column is updated
only when `persistInstructionFiles()` runs — on first workspace attach
or when the agent changes — so there are no redundant writes on
subsequent turns.

Internal fields (`ContextFileContent`, `ContextFileOS`,
`ContextFileDirectory`, `SkillDir`) are stripped at write time so the
column only holds small metadata. No stripping needed on the read path.

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

- New migration `000456` adds nullable `last_injected_context JSONB`
column.
- New SQL query `UpdateChatLastInjectedContext` writes the column
without touching `updated_at`.
- `persistInstructionFiles()` strips internal fields from parts via
`StripInternal()` before persisting.
- Sentinel path (no AGENTS.md) persists skill-only parts when skills
exist.
- `codersdk.Chat` exposes `LastInjectedContext []ChatMessagePart`
(omitempty).
- `db2sdk.Chat()` passes through the already-clean data.

</details>
2026-03-30 14:11:30 -04:00
Spike Curtis ef3aade647 chore: support agent updates in tunneler (#23730)
<!--

If you have used AI to produce some or all of this PR, please ensure you have read our [AI Contribution guidelines](https://coder.com/docs/about/contributing/AI_CONTRIBUTING) before submitting.

-->

relates to GRU-18

Adds support for agent updates to the Tunneler
2026-03-30 13:50:06 -04:00
dependabot[bot] 3cc31de57a chore: bump github.com/go-git/go-git/v5 from 5.17.0 to 5.17.1 (#23813)
Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git)
from 5.17.0 to 5.17.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/go-git/go-git/releases">github.com/go-git/go-git/v5's
releases</a>.</em></p>
<blockquote>
<h2>v5.17.1</h2>
<h2>What's Changed</h2>
<ul>
<li>build: Update module github.com/cloudflare/circl to v1.6.3
[SECURITY] (releases/v5.x) by <a
href="https://github.com/go-git-renovate"><code>@​go-git-renovate</code></a>[bot]
in <a
href="https://redirect.github.com/go-git/go-git/pull/1930">go-git/go-git#1930</a></li>
<li>[v5] plumbing: format/index, Improve v4 entry name validation by <a
href="https://github.com/pjbgf"><code>@​pjbgf</code></a> in <a
href="https://redirect.github.com/go-git/go-git/pull/1935">go-git/go-git#1935</a></li>
<li>[v5] plumbing: format/idxfile, Fix version and fanout checks by <a
href="https://github.com/pjbgf"><code>@​pjbgf</code></a> in <a
href="https://redirect.github.com/go-git/go-git/pull/1937">go-git/go-git#1937</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/go-git/go-git/compare/v5.17.0...v5.17.1">https://github.com/go-git/go-git/compare/v5.17.0...v5.17.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/go-git/go-git/commit/5e23dfd02db92644dc4a3358ceb297fce875b772"><code>5e23dfd</code></a>
Merge pull request <a
href="https://redirect.github.com/go-git/go-git/issues/1937">#1937</a>
from pjbgf/idx-v5</li>
<li><a
href="https://github.com/go-git/go-git/commit/6b38a326816b80f64c20cc0e6113958b65c05a1c"><code>6b38a32</code></a>
Merge pull request <a
href="https://redirect.github.com/go-git/go-git/issues/1935">#1935</a>
from pjbgf/index-v5</li>
<li><a
href="https://github.com/go-git/go-git/commit/cd757fcb856a2dcc5fff6c110320a8ff62e99513"><code>cd757fc</code></a>
plumbing: format/idxfile, Fix version and fanout checks</li>
<li><a
href="https://github.com/go-git/go-git/commit/3ec0d70cb687ae1da5f4d18faa4229bd971a8710"><code>3ec0d70</code></a>
plumbing: format/index, Fix tree extension invalidated entry
parsing</li>
<li><a
href="https://github.com/go-git/go-git/commit/dbe10b6b425a2a4ea92a9d98e20cd68e15aede01"><code>dbe10b6</code></a>
plumbing: format/index, Align V2/V3 long name and V4 prefix encoding
with Git</li>
<li><a
href="https://github.com/go-git/go-git/commit/e9b65df44cb97faeba148b47523a362beaecddf9"><code>e9b65df</code></a>
plumbing: format/index, Improve v4 entry name validation</li>
<li><a
href="https://github.com/go-git/go-git/commit/adad18daabddee04c5a889f0230035e74bca32c0"><code>adad18d</code></a>
Merge pull request <a
href="https://redirect.github.com/go-git/go-git/issues/1930">#1930</a>
from go-git/renovate/releases/v5.x-go-github.com-clo...</li>
<li><a
href="https://github.com/go-git/go-git/commit/29470bd1d862c6e902996b8e8ff8eb7a0515a9be"><code>29470bd</code></a>
build: Update module github.com/cloudflare/circl to v1.6.3
[SECURITY]</li>
<li>See full diff in <a
href="https://github.com/go-git/go-git/compare/v5.17.0...v5.17.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/go-git/go-git/v5&package-manager=go_modules&previous-version=5.17.0&new-version=5.17.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/coder/coder/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 17:27:38 +00:00
Mathias Fredriksson d2c308e481 fix(site/src/pages/AgentsPage): unify scroll restore-guard lifecycle in ScrollAnchoredContainer (#23809)
Two ResizeObserver effects (content and container) each had their own
local restoreGuardRafId but both wrote to the shared
isRestoringScrollRef. Either observer's guard-clear RAF could fire
while the other's pin chain was in-flight, leaving isRestoringScrollRef
prematurely false.

scrollTranscriptToBottom also set isRestoringScrollRef without
cancelling any pending guard-clear, so a stale clear could drop
the flag mid-smooth-scroll animation.

Promote restoreGuardRafId to a single shared ref so all write
paths coordinate through one cancellation point.
2026-03-30 20:17:44 +03:00
Kyle Carberry 953c3bdc0f fix(site): prevent spurious startup warning during pending status (#23805)
## Problem

The `/agents` page frequently shows "Response startup is taking longer
than expected" even while the agent is actively working and messages are
appearing in the transcript.

## Root Cause

There's an inconsistency between `isActiveChatStatus` and
`shouldApplyMessagePart` during `"pending"` status (the state between
agent tool-call turns):

| Component | Treats `"pending"` as... |
|---|---|
| `isActiveChatStatus` | **active** — includes both `"running"` and
`"pending"` |
| `shouldApplyMessagePart` | **inactive** — drops all `message_part`
events during `"pending"` |
| Status handler | clears `streamState` to `null` on `"pending"` |

This creates a dead state during multi-turn tool-call cycles:

1. Agent finishes a turn → status = `"pending"` → `streamState` cleared
to `null`
2. `selectIsAwaitingFirstStreamChunk` returns `true` (status is
"active", stream is null, latest message isn't assistant)
3. Phase = `"starting"` → 15s timer starts
4. Stream parts from the server are **silently dropped**
(`shouldApplyMessagePart()` returns `false` for `"pending"`)
5. `streamState` stays `null` — phase is stuck at `"starting"`
6. Meanwhile, durable messages (tool calls, tool results) appear
normally in the transcript
7. After 15s → "Response startup is taking longer than expected" fires

## Fix

Narrow `selectIsAwaitingFirstStreamChunk` to only check `chatStatus ===
"running"` instead of `isActiveChatStatus(chatStatus)`. `"running"` is
the only status where the transport actually accepts stream parts, so
it's the only status where we should be showing the "starting"
indicator.

`isActiveChatStatus` is left unchanged since its other caller
(`shouldSurfaceReconnectState`) correctly needs to include `"pending"`.
2026-03-30 12:46:51 -04:00
Matt Vollmer ca879ffae6 docs: add extending-agents, mcp-servers, and usage-insights pages (#23810)
Adds three new documentation pages for major shipped features that had
no docs, and updates the platform controls index to reflect current
state.

## New pages

### Extending Agents (`extending-agents.md`)

Covers two workspace-level extension mechanisms:
- **Skills** — `.agents/skills/<name>/SKILL.md` directory structure,
frontmatter format, auto-discovery, `read_skill`/`read_skill_file`
tools, size limits, lazy loading
- **Workspace MCP tools** — `.mcp.json` format, stdio and HTTP
transports, tool name prefixing, discovery lifecycle and caching

### MCP Servers (`platform-controls/mcp-servers.md`)

Admin MCP server configuration:
- CRUD via **Agents** > **Settings** > **MCP Servers**
- Four auth modes: none, OAuth2 (with auto-discovery), API key, custom
headers
- Availability policies: `force_on`, `default_on`, `default_off`
- Tool governance via allow/deny lists
- Permission model and secret redaction

### Usage & Insights (`platform-controls/usage-insights.md`)

Three admin dashboards:
- **Usage limits** — spend caps with per-user and per-group overrides,
priority hierarchy, enforcement behavior
- **Cost tracking** — per-user rollup with token breakdowns, date
filtering, per-model and per-chat drill-down

## Updated files

- **`platform-controls/index.md`** — Moved MCP servers, usage limits,
and analytics from "Where we are headed" into "What platform teams
control today" with links to the new pages. Removed the tool
customization roadmap section (now covered by MCP servers page).
- **`manifest.json`** — Added nav entries for all three new pages.

## Resulting nav hierarchy

```
Coder Agents
├── Getting Started
├── Early Access
├── Architecture
├── Models
├── Platform Controls
│   ├── Template Optimization
│   ├── MCP Servers              ← NEW
│   └── Usage & Insights         ← NEW
├── Extending Agents             ← NEW
└── Chats API
```

---

*PR generated with Coder Agents*
2026-03-30 12:46:34 -04:00
Cian Johnston 0880a4685b ci: fix pnpm not found in check-docs job (#23807)
- Enable corepack before the linkspector step so `pnpm` shim is in PATH
- `action-linkspector@v1.4.1` internally calls `actions/setup-node@v5`,
which now defaults `package-manager-cache: true` — it detects
`pnpm-lock.yaml` and tries to resolve the `pnpm` binary, but it's not
installed on the runner
- Add TODO to remove the workaround when upstream is fixed

Upstream: https://github.com/UmbrellaDocs/action-linkspector/issues/54

> 🤖 Cian asked a Coder Agent to make this PR and then reviewed the
change.
2026-03-30 21:28:51 +05:00
Danielle Maywood 3f8e3007d8 fix(site): write WebSocket messages to React Query cache (#23618) 2026-03-30 15:56:08 +01:00
Matt Vollmer 8e57498a87 docs: update Chats API and platform controls docs to match current state (#23803)
The Chats API docs and platform controls docs had fallen behind the
implementation. This brings them up to date.

## Chats API docs (`chats-api.md`)

### Breaking: archive/unarchive endpoints removed

The old `POST /{chat}/archive` and `POST /{chat}/unarchive` endpoints no
longer exist. Replaced with the `PATCH /{chat}` update endpoint
(`{"archived": true/false}`).

### Chat object updated

Added all new fields to the example response and a new reference table:
- `build_id`, `agent_id` — workspace agent binding
- `parent_chat_id`, `root_chat_id` — delegated/child chat lineage
- `pin_order` — pinned chats
- `labels` — general-purpose key-value labels
- `mcp_server_ids` — MCP server bindings
- `has_unread` — read/unread tracking
- `diff_status` — PR/diff metadata

### New endpoints documented

- `PATCH /{chat}` — update chat (title, archived, pin_order, labels)
- `PATCH /{chat}/messages/{message}` — edit a user message
- `GET /watch` — watch all chats via WebSocket
- `POST /{chat}/title/regenerate` — regenerate title
- `GET /{chat}/diff` — get diff/PR status
- `DELETE /{chat}/queue/{id}` / `POST /{chat}/queue/{id}/promote` —
queue management

### Updated existing endpoint docs

- Create chat: added `mcp_server_ids` and `labels` fields
- Send message: added `mcp_server_ids` field
- List chats: added `q` and `label` query parameters
- Stream: noted read cursor behavior on connect/disconnect

## Platform controls docs

### Template allowlist (`platform-controls/index.md`)

- Updated the "Template routing" section to document the template
allowlist setting (**Agents** > **Settings** > **Templates**)
- Removed the "Template scoping for agents" bullet from "Where we are
headed" since it shipped

### Template optimization (`template-optimization.md`)

- Added "Restrict available templates" section documenting the allowlist
UI, behavior, and scope (agents only, not manual workspace creation)

---

*PR generated with Coder Agents*
2026-03-30 10:28:15 -04:00
Susana Ferreira 0fb3e5cba5 feat: extract, log, and strip aibridgeproxy request ID header in aibridged (#23731)
## Problem

`aibridgeproxyd` sends `X-AI-Bridge-Request-Id` on every MITM request to
`aibridged` for cross-service log correlation, but aibridged never reads
it. The header is silently forwarded to upstream LLM providers.

## Changes

* Renamed the header to `X-Coder-AI-Governance-Request-Id` to match the
existing `X-Coder-AI-Governance-*` convention.
* `aibridged` now extracts the header, logs it and strips it before
forwarding upstream.
* Added `TestServeHTTP_StripInternalHeaders` to verify no `X-Coder-*`
headers leak to upstream
2026-03-30 15:21:30 +01:00
Mathias Fredriksson 7fb93dbf0e build: lock provider version in provisioner/terraform/testdata (#23776)
The terraform testdata fixtures silently drift when the coder provider
releases a new version. The .terraform.lock.hcl files are gitignored,
.tf files use loose constraints (>= 2.0.0), and generate.sh always
runs terraform init -upgrade. The Makefile only re-runs generate.sh
when the terraform CLI version changes, not the provider version.

Track a canonical lockfile and provider-version.txt in git. Change
generate.sh to respect the lockfile by default (terraform init without
-upgrade). Add --upgrade flag for intentional provider bumps, --check
for cheap staleness detection in the Makefile, and a new
update-terraform-testdata make target.
2026-03-30 16:37:25 +03:00
Michael Suchacz cf500b95b9 chore: move docker-chat-sandbox under templates/x (#23777)
Adds the experimental `docker-chat-sandbox` example template under
`examples/templates/x/`. It provisions a regular dev agent plus a
chat-designated agent that runs inside bubblewrap with a read-only root,
writable `/home/coder`, and outbound TCP restricted to the Coder
control-plane endpoint via `iptables`.

The chat agent still appears in dashboard and API responses, but the
template reserves it for chatd-managed sessions rather than normal user
interaction. `lint/examples` now walks nested template directories, so
experimental templates can live under `examples/templates/x/` without
treating `x/` itself as a template.
2026-03-30 15:17:55 +02:00