Commit Graph
5462 Commits
Author SHA1 Message Date
McKayla はな 1302e78283 ci: remove chromatic (#26777) 2026-06-29 08:57:07 -06:00
TJ 5f42bbcdbf feat(site/src): nest agent pages under a Coder Agents subsection in AI nav (#26667)
Groups the agent-related AI settings pages under a new **Coder Agents**
parent in the sidebar, with a continuous left rule connecting the
children and an active-segment indicator that lights up the rule where
the current sub-item sits.

The new nav order:

- AI Governance
- AI Gateway keys
- Providers
- Coder Agents
  - Models
  - MCP servers
  - Templates
  - Spend
  - Instructions
  - Lifecycle

All target pages already exist on main (Danielle's recent migrations of
Models, MCP servers, Templates, Instructions, Lifecycle, Spend, and
Coder Agents into AI Settings). This PR only changes the sidebar visual
structure: the children move into an indented group with a `border-l
border-l-border` rule, and the active child paints a
`border-l-content-primary` segment over that rule via `-ml-px` so the
rule and indicator share a column instead of stacking.

<details>
<summary>Design notes</summary>

Concept 1 from the earlier exploration: always-expanded with indents,
the parent is its own page. Chosen because it adds no expand/collapse
state, no "which child is the default" question, and no animation work;
the parent reuses the existing nav-item, and the children sit in a
wrapper `div` with a left rule. The site bundle ships without Tailwind's
preflight, so the wrapper and sub-item borders are paired with
`border-solid` to actually paint, matching the pattern already in
`Sidebar.tsx`.

</details>

---

_This PR was prepared by Coder Agents on behalf of @tracyjohnsonux._
2026-06-29 13:46:09 +00:00
Danielle Maywood b4a7b25290 feat(site): move Coder Agents settings to AI settings (#26692) 2026-06-29 12:28:36 +00:00
Danielle Maywood cf1c29b651 feat(site): move spend page to AI settings (#26800) 2026-06-29 12:49:38 +01:00
Danielle Maywood 60a56cf343 fix(site): use large avatar on provider table (#26804) 2026-06-29 11:49:25 +00:00
Danielle Maywood 3d1e41c616 feat(site): add paginated query options (#26802) 2026-06-29 11:45:28 +01:00
Cian Johnston 86a7bc9fb0 fix: resolve model config provider via ai_provider_id (#26660)
-  `site/src/pages/AISettingsPage/ProvidersPage/components/providerFormApiMap.ts`):
`providerFormValuesToCreate` returns `type: "bedrock"` when the form
type is `bedrock`, instead of `type: "anthropic"` with Bedrock settings.
- Updated `providerFormApiMap.test.ts` to expect `type:
"bedrock"` and `MockAIProviderBedrock` fixture in `entities.ts` to
`type: "bedrock"`. Added Bedrock fixtures to `ModelsPageView` stories
asserting the AWS Bedrock icon renders correctly.

Refs: [CODAGT-549](https://linear.app/codercom/issue/CODAGT-549/bedrock-models-use-anthropic-styling-and-icons)

> 🤖
2026-06-29 11:04:58 +01:00
Danielle Maywood 72980d3e65 refactor(site): share confirm delete dialog (#26799) 2026-06-29 11:00:49 +01:00
Ethan 4820cbf7b1 test: migrate CreateUserPage tests to Storybook play stories (#26794)
Migrates the CreateUserPage tests from vitest to Storybook play-function
stories.

The old `CreateUserPage.test.tsx` rendered the full page through
`renderWithAuth` and MSW, which is slow and contributes to `test-js`
timeout flakes. The new stories seed the react-query cache directly and
assert the same behavior in `play` functions, so they run in the
Storybook test lane instead of the vitest `unit` project.

Coverage is preserved: a success story asserts the success toast after
creating a user, and an error story asserts that an API failure surfaces
in the form's error alert.

Relates to CODAGT-686
Relates to https://github.com/coder/internal/issues/1598
2026-06-29 18:24:23 +10:00
Ehab Younes c782cbce77 feat(site/src/pages/GroupsPage): update group AI budget UI (#26659)
Update the group AI budget settings UI to match the unlimited,
no-budget, and finite-budget states. The field now uses a USD input
suffix, the label reads "Monthly limit per member", and unlimited or $0
budgets show explanatory helper text with an info alert.
2026-06-29 00:52:47 +03:00
McKayla はな 9efbcc7601 chore: make dynamic parameters WorkspaceParametersPage the default (#25095) 2026-06-26 17:55:34 -06:00
McKayla はな efd93027ce feat: allow editing user avatars (#26652)
Adds an avatar URL field to the admin **Edit user** page, available only
for users whose login type is `password` or `none`.

For identity-provider login types (`github`, `oidc`) the avatar is
synced from the IdP on every login, so the field is hidden and the API
ignores any submitted avatar to avoid confusing overwrites.

The field reuses the same emoji picker + URL input (`IconField`) already
used for template, group, and organization icons.

A follow-up PR will add the same control to the self-service Account
settings page.

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

**Goal:** Let an admin set/clear a user's avatar from the Edit user
page, gated to `password`/`none` login types.

**Backend**
- Add `avatar_url` to `codersdk.UpdateUserProfileRequest`.
- `putUserProfile` applies the submitted avatar only for
`password`/`none`; otherwise it preserves the existing (IdP-synced)
value.
- Regenerated TS types and API docs via `make gen`.

**Frontend**
- `EditUserForm` renders an `IconField` ("Avatar URL") when the login
type allows it.
- `EditUserPage` passes the avatar value and a `canEditAvatar` flag.
- `AccountPage` round-trips `avatar_url` so the shared request type
doesn't wipe avatars on the self-service path.

**Gating** is enforced in both the UI (field hidden) and the backend
(submitted value ignored for IdP login types).

**Tests/stories:** backend `TestUpdateUserProfile` covers apply
(password) and ignore (SSO); `EditUserForm` stories cover the
shown/hidden states with interaction tests.

</details>

---
> Generated by Coder Agents on behalf of @aslilac.
2026-06-26 16:35:03 -06:00
McKayla はな 7481e1a5a0 fix(site): keep TemplateVersionEditor file tree in sync (#25068) 2026-06-26 14:47:55 -06:00
Andrew Aquino e24bc5b572 refactor(site): use our Link component in Markdown instead of MUI (#26758)
ref DEVEX-517

MUI's `Link` color does not come from our design system, whereas our
`Link`'s does
2026-06-26 12:35:17 -07:00
Andrew Aquino 2ba85d9657 feat(site): give all template builder steps rounded border + padding (#26757)
ref DEVEX-517

Some small preliminary UI spruce-ups to get each step closer to the
design before implementing the main feature for DEVEX-517. See commit
messages for individual changes.

The most prominent change is making it so that every step gets wrapped
in this rounded/bordered/padded container. Previously it was present
only in `ModuleSettingsStep` and `TemplateCustomizationsStep`; but
missing from `BaseInfraSelectStep`, `BaseTemplateParametersStep`, and
`ModuleSelectStep`

<img width="1840" height="1191" alt="image"
src="https://github.com/user-attachments/assets/f143a6b1-abdf-4103-8041-cd6e1431c856"
/>
2026-06-26 12:34:36 -07:00
Paweł Banaszewski c15d483863 chore: rename 'last_used_at' column (#26749)
Renames the `last_used_at` column  to `last_heartbeat_at` in `ai_gateway_keys` table.  
`ai_gateway_keys` table has not been released yet.  
All references updated.
2026-06-26 18:45:37 +02:00
Paweł Banaszewski 6189d6e386 feat: add /api/v2/aibridge/serve endpoint (#26506)
Adds a new enterprise-only `GET /api/v2/ai-gateway/serve` endpoint that standalone AI Gateway replicas use to connect to `coderd` over a DRPC-over-WebSocket transport, mirroring the existing in-memory path used by the embedded AI Bridge daemon.

- The endpoint upgrades the HTTP connection to a WebSocket, multiplexes it with yamux, and finally serves the three DRPC services (Recorder, MCPConfigurator, Authorizer).
- The `X-AI-Governance-Gateway-Key` header is used for authentication.
    - The key is looked up by its hashed secret
    - Missing or revoked keys return `401`.
- API version negotiation is enforced via a new `aibridged/proto` version (`v1.0`).
    - Incompatible versions return `400`.
- `FeatureAIBridge` entitlement is required.
- Key liveness (`last_used_at`) is recorded immediately on connection and refreshed every 60 seconds while the session remains open.
  - When key liveness detects the key was deleted (no rows where updated) session is closed.

#### Small refactors

* The three DRPC service registrations are extracted into `aibridgedserver.Register`, shared by both the in-memory and WebSocket paths.

* The literal `256 * 1024` used as the yamux-aligned WebSocket read limit is replaced with the named constant `drpcsdk.YamuxDefaultStreamWindowSize` in all call sites.
  * as noted in review comment https://github.com/coder/coder/pull/26506#discussion_r3461905223 order of `SetReadLimit` and `WebsocketNetConn` calls was fixed.
2026-06-26 18:27:37 +02:00
Steven Masley ad355aeaa9 feat: add INSECURE oidc email fallback flag for IdP brokers (#26751)
<!-- Authored by Coder Agents on behalf of @Emyrk. -->

Adds an opt-in `CODER_DANGEROUS_OIDC_EMAIL_FALLBACK` flag (alias
`--dangerous-oidc-email-fallback`) for IdP brokers that do not issue a
stable `sub` for the same user across connections.
2026-06-26 11:23:42 -05:00
Paweł Banaszewski 0f1e792f3f feat(coderd/database): add AI Gateway key auth lookup and last-used queries (#26505)
Adds DB methods`GetAIGatewayKeyIDByHashedSecret` and `UpdateAIGatewayKeyLastUsedAt`.
`GetAIGatewayKeyIDByHashedSecret` - returns AI Gateway key ID by hashed secret value.
`UpdateAIGatewayKeyLastUsedAt` - updates last used timestamp for given AI Gateway key. 
Used by standalone AI Gateway for authentication and keeping track of currently used keys.
2026-06-26 18:16:01 +02:00
Spike Curtis 98e1ce133c chore: modify replicasync to handle NATS explicitly (#26666)
relates to GRU-69

Modifies replicasync to handle discovering NATS enabled primary replicas explicitly, and passing that info to the NATS Pubsub.

This PR adds a new deployment value to explicitly represent the host or IP that the replica can be reached on. It isn't wired up to the CLI, but piggybacks on the DERP config for now.

We learn the NATS port directly from NATS at runtime, and propagate it thru replicasync to learn all peers for clustering.
2026-06-26 08:36:32 -04:00
Mathias Fredriksson 59fcc9c0ad feat: improve sub-agent orchestration tools (#26673)
Tool errors caused orchestrators to abandon spawned agents. Bare error
responses and the close_agent name framed delegation as one-shot: one
transient failure or timeout ended the work, and the orchestrator had no
way to recover or reuse agents.

Renames close_agent to interrupt_agent with a hidden backward-compatible
alias. wait_agent and message_agent return structured payloads instead
of bare errors, so the orchestrator can retry after a timeout, recover
from an error status, or redirect an idle agent. Adds list_agents so
orchestrators can rediscover spawned agents. Adds root-only
orchestration guidance for error recovery.
2026-06-26 13:41:43 +03:00
Kyle Carberry a163d43981 fix(site/src/pages/AgentsPage): keep agent chat sticky truncation in sync as the transcript grows (#26714)
## Problem

In `/agents`, the sticky user-message truncation sometimes does not
update as new content arrives. While pinned to the bottom with the
transcript overflowing, several messages (or a streaming response) can
land and the sticky bubble keeps a stale clip height, overflowing and
overlapping the content below it. It only snaps back once you scroll
manually.

## Root cause

`StickyUserMessage` recomputes its clip height (`--clip-h`) and push-up
`top` in an `update()` driven by three triggers: a scroll listener, a
window-resize listener, and a `ResizeObserver` meant to catch the
transcript growing.

The observer watched `scroller.firstElementChild`, but in
`ChatScrollContainer` the scroller's first child is the `flex-1 basis-0`
spacer that pins content to the bottom, not the content wrapper. That
spacer collapses to `0px` the moment the transcript overflows (exactly
when truncation engages) and then never resizes again, so the observer
goes silent.

The other triggers do not cover this case either: in `flex-col-reverse`
the `scrollTop` stays at `0` while pinned to the bottom, so no scroll
event fires as content grows. The result is a stale `--clip-h` until the
next manual scroll.

## Fix

- Observe the real content wrapper instead of the collapsing spacer. The
wrapper is tagged with `data-chat-scroll-content` (it contains both the
committed timeline and the streaming live tail), and the sticky code
resolves it via `sentinel.closest(...)`, falling back to the previous
node only if the marker is absent.
- Recompute the scroller geometry (`scrollerTop`/`scrollerHeight`)
inside `update()` on every tick instead of caching it at effect setup,
so the clip and push-up math cannot drift when the scroller moves or
resizes without a window resize (for example the composer growing). This
also removes the now-redundant `onResize` handler.

No change to the sticky visuals or the rAF throttling.

## Testing

- New story `StickyUserMessageClipUpdatesWhilePinned` grows the
transcript while pinned (no scroll dispatched) and asserts the clip
tracks the new geometry, plus structural guards that the observed node
is the content marker and not the `aria-hidden` spacer.
- Verified as a true regression guard: with the fix reverted the new
story fails; with the fix it passes. The existing
`StickyUserMessagePinsOnScroll` is unaffected.
- `biome check`, `tsc -p .`, React Compiler check, emdash check, and
`vitest --project=storybook` for this stories file all pass (48/48).

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

- Considered centralizing the per-message scroll/resize/observer wiring
into a single coordinator in `ConversationTimeline` (it already
centralizes sentinels) to cut N observers/listeners down to one.
Deferred as a follow-up to keep this PR a surgical, low-risk fix; this
change alone resolves the staleness.
- Chose a semantic `data-chat-scroll-content` marker over reusing the
`chat-timeline-wrapper` test id so runtime behavior does not depend on a
test-only attribute. The marker sits on the wrapper that contains both
the timeline and the live tail, so streaming growth is observed too.
- Kept the `scroller.firstElementChild` fallback so other
`ConversationTimeline` consumers and stories without the marker keep
working.

</details>

---

Filed via Coder Agents on behalf of @kylecarbs.
2026-06-25 17:57:28 -06:00
Andrew Aquino 37d8b5163d feat(site): add search + filter tabs for template builder modules (#26674)
ref DEVEX-491

Adds a `useFuzzySearch` hook based on the logic in IconsPage.tsx, and
Storybook stories for `ModuleSelectStep` to verify filter tab count
behavior.

c16e0d9516 and
b6ee21875c co-written with Claude Code
2026-06-25 13:44:42 -07:00
uzair-coder07 7e509e8fd0 fix(site/src/pages/WorkspacesPage): show only parent agent apps in workspaces table (#26568)
The workspaces table shortcuts row selected `resources[0].agents[0]`, so
a sub-agent that ended up first (for example the Claude/Task sub-agent
created on a workspace) could replace the parent agent's launcher icons,
and which apps showed depended on agent ordering.

Select the parent agent (`parent_id === null`) of the first non-hidden
resource instead, matching the convention already used on the workspace
detail page (`Workspace.tsx`). This keeps the shortcuts row
deterministic and excludes sub-agent apps.

Refs
[DEVEX-459](https://linear.app/codercom/issue/DEVEX-459/aggregate-workspace-table-shortcuts-across-all-agents)

<details>
<summary>Decision context and scope</summary>

Per the discussion on DEVEX-459, this is the agreed short-term fix:

> In the short term, we should display only apps from the parent agent
and make the behavior deterministic, rather than the current reported
behavior of showing apps from the first discovered agent.

Out of scope (tracked as a longer-term backlog item on DEVEX-459):

- Aggregating app shortcuts across multiple agents.
- Changing the 4-slot cap (`WORKSPACE_APPS_SLOTS`).

For workspaces with multiple top-level agents, the first parent agent's
apps are shown. This is deterministic but not aggregated.

A `ParentAgentApps` Storybook story was added (sub-agent listed first)
with a `play` function asserting the parent agent's app renders and the
sub-agent's app does not.

</details>

---

This PR was created by Coder Agents on behalf of @uzair-coder07.
2026-06-25 15:39:27 -05:00
McKayla はな 4c8c496979 fix(site): add bottom padding to create workspace page (#26431) 2026-06-25 13:19:53 -06:00
Andrew Aquino 973056dcf6 feat(site): limit dropdown module config fields to 50% width (#26682)
closes DEVEX-532

## other changes

just cleaning up typographic styles a bit to match Figma better

- create `TemplateBuilderTitle`/`TemplateBuilderSubtitle` components for
h2+p elements at the top of steps
- left-align switch's description with its label
2026-06-25 10:49:46 -07:00
Danielle Maywood b40923d1dd fix(site): hide empty model provider configuration (#26690) 2026-06-25 15:17:04 +01:00
Ehab Younes 75993c2ea0 feat(site): add group member AI budget columns (#26574)
Adds AI budget and Budget type columns to the group members table, shown when
aibridge is enabled and the ai-gateway-cost-control experiment is on. A member's
spend, limit, and source come from an ai_cost_control object embedded in the
group members and groups responses, so no extra request is made.

- Add AI budget and Budget type columns, gated by the aibridge feature and the
  ai-gateway-cost-control experiment
- Read ai_cost_control inline from the group and member lists instead of calling
  a separate spend endpoint
- Share an AIBudgetUsage component (spend vs budget with severity colors) and an
  InfoIconTooltip for the column headers
- When another group governs a member's budget, grey the spend and name that
  group in a tooltip; otherwise render the spend (severity-colored) against a
  white limit
- Resolve a member's effective group in the AI budget override dialog, marking
  only the governing group "(default)" and none when no group governs them
- Defer the override's custom-budget error until the field is touched

Closes AIGOV-291
2026-06-25 15:41:46 +03:00
Danielle Maywood 1ae96fcf8a fix!: prevent AI provider name collision with static settings routes (#26688)
Move the providers routes into a dedicated providers sub-tree: `/ai/settings/providers`, `/ai/settings/providers/add`, and `/ai/settings/providers/:providerId`.

The old `/ai/settings/:providerId` and `/ai/settings/add` URLs are
removed without backward-compatibility redirects. Bookmarked or shared
links to these paths now return a 404. Creating a provider with id `models` (although unlikely) made it impossible to edit it due to a conflict with the static models route.
2026-06-25 11:09:58 +01:00
Danielle Maywood a7f3ea50b7 feat(site): add TableBody size="lg" variant for 72px rows (#26687)
Add a new variant `size="lg"` for the `Table` component, and make use of
it in the new AI settings page. This allows us to ensure each table is
using the same implementation and are consistent.
2026-06-25 11:07:51 +01:00
Yevhenii Shcherbina f66df86aed feat: add Bedrock Role ARN field in UI (#26578)
Adds a Role ARN field for the Bedrock provider in the UI. When set, the
gateway assumes that IAM role (using the base identity) before calling
Bedrock. The field is optional and non-secret, so it round-trips back
into the form on edit and clears when left blank.

<hr/>

Related PR: https://github.com/coder/coder/pull/26527
Related issue:
https://linear.app/codercom/issue/AIGOV-371/support-dynamic-bedrock-assumerole-across-aws-accounts-for-ai-gateway
2026-06-24 21:48:33 -04:00
TJ 0f4731446b fix(site/src/pages/AISettingsPage/ModelsPage): disable Update model until form is dirty (#26684)
The Update model button on `/ai/settings/models/:modelId` was enabled on
mount even when the form had not been edited, so it was possible to
submit an unchanged update. This matches the Provider form behavior
already established in #25551 by gating submit on `form.dirty` when
editing.

### Changes

- `ModelForm.tsx` adds `(!isEditing || form.dirty)` to the `canSubmit`
predicate so Update is disabled until the user changes a field.
Add/duplicate flows are unaffected because their existing
`model.trim().length > 0` requirement already enforces user input.
- `ModelForm.stories.tsx` tightens `EditSaveSubmits` to assert the
disabled-on-mount and enabled-after-edit transitions, and adds
`EditUpdateDisabledUntilDirty` covering the case where the user reverts
an edit back to the original value.

### Verification

- `pnpm exec biome check
src/pages/AISettingsPage/ModelsPage/components/ModelForm.tsx
src/pages/AISettingsPage/ModelsPage/components/ModelForm.stories.tsx`:
clean
- `pnpm exec tsc -p . --noEmit`: clean
- `pnpm test:storybook --project=chromium
src/pages/AISettingsPage/ModelsPage`: 21/21 stories pass (including the
two new dirty-state stories)
- `make pre-commit` via the project git hooks: passed (lint/ts, lint/go,
lint/emdash, lint/agents, lint/check-scopes, build, all green)

> [!NOTE]
> 🤖 This PR was written by Coder Agents on behalf of @tracyjohnsonux
2026-06-25 01:01:56 +00:00
TJ 99c0362b26 fix(site/src/pages/AISettingsPage/ModelsPage): duplicate Add model dropdown in empty state (#26685)
Mirrors the providers page on `/ai/settings/providers`: when the models
table is empty on `/ai/settings/models`, the empty state now renders an
**Add model** dropdown alongside the description so users have an
obvious next step.

## Changes

- `AddModelDropdown` accepts an optional `align` prop (defaults to
`"end"`), so the existing header instance is unchanged.
- The empty state passes a second instance via `TableEmpty`'s `cta` prop
with `align="start"`, matching how `ProvidersPageView` duplicates
`AddProviderDropdown`.
- Updated the `Empty` Storybook story to assert two **Add model**
buttons render (header + empty state).

## Verification

- `pnpm --dir site exec biome check
src/pages/AISettingsPage/ModelsPage/`
- `pnpm --dir site exec tsc -p . --noEmit`
- `pnpm --dir site exec vitest run --project=storybook
src/pages/AISettingsPage/ModelsPage/` (20/20 stories pass, including the
updated `Empty` play)

<details>
<summary>Reference: providers page pattern</summary>

`ProvidersPageView.tsx` already does this with `AddProviderDropdown`:

```tsx
<TableEmpty
  message="No providers configured"
  cta={<AddProviderDropdown align="start" />}
/>
```

This PR brings the models page in line with that pattern.

</details>

---

> [!NOTE]
> Opened by Coder Agents on behalf of @tracyjohnsonux.
2026-06-24 17:58:14 -07:00
Andrew Aquino 612b6d4e95 refactor(site): make optionalFields a prop of ModuleConfiguration instead of children (#26681)
ref: DEVEX-532

During #26627, I think we should've given `ModuleConfiguration` an
`optionalFields` prop in the first place--our one and only usage of
`ModuleConfiguration` doesn't render optional fields in a way that makes
sense as children. Also, `ModuleConfiguration` should be the component
responsible for rendering the collapsible section, not
`ModuleSettingsStep`

This makes Storybook more accurately represent what module config looks
like, since ModuleConfiguration.stories.tsx now shows the optional field
in a collapsible section:

<img width="1840" height="1191" alt="image"
src="https://github.com/user-attachments/assets/2b385ea7-a060-409a-8e84-aa37f0b09c2c"
/>
2026-06-24 14:00:28 -07:00
Andrew Aquino 6a57f4751f feat(site): give SelectionSummary's template/module names secondary text color (#26580)
Figma design:
https://www.figma.com/design/z1qkNiNIya2myaVW4kR6jP/Template-creation-builder?node-id=450-8030&m=dev
2026-06-24 12:13:19 -07:00
Andrew Aquino 63b9388c6c fix(site): open TemplateBuilder template docs in new tab (#26589)
Mainly makes the template builder's external docs/registry links behave
consistently.

Includes some small changes to make copy consistent (sentence casing for
links + period after page header subtitle, sourced from
[Figma](https://www.figma.com/design/z1qkNiNIya2myaVW4kR6jP/Template-creation-builder?node-id=257-906&m=dev))

Also, `noreferrer` has automatically been applied to `target="_blank"`
links in major browsers since 2021 ([source
1](https://frontendmasters.com/blog/bone-up-html-2025/#you-probably-dont-need-noopener-noreferrer-on-links-anymore),
[source 2](https://stackoverflow.com/a/50709724/6432160))
2026-06-24 12:11:53 -07:00
Yevhenii Shcherbina 8bf6f43016 feat: support cross-account Bedrock AssumeRole in AI Bridge (#26527)
# Support IAM role assumption for AWS Bedrock in AI Bridge

## Summary

Implements
https://linear.app/codercom/issue/AIGOV-371/support-dynamic-bedrock-assumerole-across-aws-accounts-for-ai-gateway

A Bedrock provider can now be configured with an IAM role to assume.
Before calling Bedrock, the gateway assumes that role via STS and signs
requests with the resulting temporary credentials. Whether the role
lives in the same account or another one is entirely a matter of the
role's trust policy.

## Problem

Many organizations prohibit long-lived AWS access keys and expect
workloads to authenticate through assumed IAM roles instead. A common
case is an organization that runs Bedrock across several AWS accounts,
one per business unit, and needs each unit's usage billed to its own
account by assuming a role there. AI Bridge previously authenticated a
Bedrock provider only with static keys or the gateway's own ambient AWS
identity, which is shared by every provider, with no way to assume a
role. These deployments had no clean path.

## How it works

When a provider is configured with a role ARN, the gateway uses its base
identity to assume that role via STS and signs Bedrock requests with the
temporary credentials it returns. The base identity is whatever the AWS
default credential chain resolves, IRSA, EKS Pod Identity, EC2 Instance
Profile, or static keys.

Credentials are resolved once when the provider is set up and are then
cached and rotated, so individual requests are served from the cache
rather than triggering a new STS call. A deployment that needs several
roles configures several providers, each pointing at its own role.

## Configuration

The role ARN is part of the Bedrock provider settings and is set through
the AI provider API. It is optional: a provider with no role ARN behaves
exactly as before.

## Scope and trade-offs

- This PR is backend only. The settings UI for the role ARN ships in a
follow-up.
- Configuration is not exposed through environment variables.
Environment-based provider configuration is being phased out in favor of
database-managed providers, so the role ARN is intentionally database
and API only.

Follow-up PR: https://github.com/coder/coder/pull/26578
2026-06-24 12:03:27 -04:00
Danielle Maywood 85652554f9 feat: move MCP servers to AI settings (#26642) 2026-06-24 12:30:15 +01:00
Danielle Maywood 3133a8b9c6 feat: move instructions to AI settings (#26624) 2026-06-24 12:29:58 +01:00
Paweł Banaszewski b11cd07d97 chore: move ai gateway keys link up in ai settings (#26654)
Moves 'AI Gateway Keys' link under 'AI Governance' so it doesn't sit between 'Providers' and 'Models'.
Providers remain page loaded by default.
2026-06-24 11:34:54 +02:00
Danielle Maywood 791b4b6413 feat(site): move lifecycle settings to AI settings (#26625) 2026-06-24 10:15:28 +01:00
Danielle Maywood e569e16682 feat(site): move template allowlist to ai settings (#26615) 2026-06-24 10:00:37 +01:00
Susana Ferreira 0807b3272c feat(site): move frontend routes from /aibridge to /ai-gateway with redirects (#26569)
## Description

Moves frontend routes from `/aibridge` to `/ai-gateway` and adds client-side redirects so existing bookmarks and deep links continue to work.

## Changes

- Move React Router paths from `/aibridge` to `/ai-gateway`
- Add `<Navigate>` redirects from `/aibridge`, `/aibridge/sessions`, and `/aibridge/sessions/:sessionId`
- Update `navigate()` calls and `Link` components to use new paths

Closes https://linear.app/coder/issue/AIGOV-233

> Generated with the assistance of Coder Agents (@ssncferreira)
2026-06-24 09:02:36 +01:00
Susana Ferreira a9c58ab8ef feat: update API URLs from /aibridge to /ai-gateway (#26567)
## Description

Updates frontend and Go SDK client URLs from `/api/v2/aibridge/*` to `/api/v2/ai-gateway/*` to match the new route aliases introduced in #26475.

## Changes

- Update `site/src/api/api.ts` to call `/api/v2/ai-gateway/*` for all AI Gateway endpoints
- Update `codersdk/aibridge.go` type comment to reference the new path
- Regenerate `site/src/api/typesGenerated.ts`

Closes https://linear.app/coder/issue/AIGOV-230

> Generated with the assistance of Coder Agents (@ssncferreira)
2026-06-24 08:52:24 +01:00
Jon Ayers 4cfed1b3ed feat: plumb time_til_autostop_notify template field (#26439) 2026-06-23 17:32:47 -05:00
Jeremy Ruppel 61dfefb991 fix(site/src/pages/TemplateBuilder): block continuing without base template or module selection (#26626)
Fixes DEVEX-520

The Template Builder wizard allowed users to continue past the base
template selection step without selecting a template, and past the
module selection step without selecting any modules.

Adds `canContinue` validation for the `base-infra` and
`module-select` steps in `computeCanContinue()`. The Continue button
is now disabled until a base template is selected on the first step
and at least one module is selected on the module selection step.

> Generated with [Coder Agents](https://coder.com/agents)
2026-06-23 15:20:48 -04:00
Jeremy Ruppel 24f97e86ad feat(site/src/pages/TemplateBuilder): put optional module variables in collapsible section (#26627) 2026-06-23 13:39:01 -04:00
Jeremy Ruppel 47adfb3f28 feat(site): display prerequisites in base template step (#26524)
Display the base template prerequisites in the Template Builder wizard.
Stacked on #26523.

The `base-parameters` wizard step now renders the prerequisites markdown
(served by the backend `prerequisites` field) below the variable
configuration fields using `MemoizedMarkdown`. The step is shown when
the base has parameters **or** prerequisites, so Docker (no parameters,
has prerequisites) now shows this step.

## Changes

- `SelectedBaseMeta` gains `hasPrerequisites` boolean
- `toSelectedBaseMeta()` populates it from `base.prerequisites`
- `base-parameters` step skip logic: show when base has parameters or
prerequisites
- `BaseTemplateParametersStep`: render full prerequisites markdown as-is
(headings intact)
- Updated all test fixtures with the new field

*Generated with the assistance of an AI coding agent. Reviewed by
@jeremyruppel.*

Relates to https://linear.app/codercom/issue/DEVEX-446
2026-06-23 11:57:28 -04:00
Ehab Younes 0aa14c7d45 feat(site): add group AI budget column (#26566)
Adds an AI budget column to the organization Groups list showing each
group's current AI spend against its configured limit, or "unlimited"
when no limit is set.

- Column and its spend request are gated behind `aibridge` visibility
  and the `ai-gateway-cost-control` experiment
- Shows loading placeholders while spend is fetched from
  `/api/v2/organizations/{org}/groups/ai/spend`
- Spend severity thresholds extracted into shared `utils/budget.ts`:
  warning at 85%, destructive at or above the limit
- Response type defined locally with a TODO to replace with the
  generated type once the backend endpoint exists

Closes AIGOV-290
2026-06-23 18:56:54 +03:00
Jeremy Ruppel 10717572ac feat: show template prerequisites in builder UI (#26523)
Surface base template prerequisites to admins before they create a
template in the Template Builder wizard.

Today, template prerequisites (Docker socket setup, Kubernetes auth, AWS
IAM policies) are only visible in the registry README after import.
Admins hit opaque provisioner errors and have to hunt for docs. This
change extracts the prerequisites from the README and serves them via
the API so the frontend can display them inline.

## How it works

Each base template README uses HTML comment markers (`<!--
prerequisites:start -->` / `<!-- prerequisites:end -->`) to delimit the
prerequisites section. At boot time, the base catalog loader reads the
README, extracts the content between markers via `strings.Index`, and
caches both the full README and the prerequisites string.

The prerequisites are served via a new `prerequisites` field on `GET
/api/v2/templatebuilder/bases`. The full README is included in the
composed template tar bundle and stored as the template version readme.

## Changes

- Add `README.md` with prerequisite markers to
`coderd/templatebuilder/bases/{docker,kubernetes,aws-linux}/`
- New `ExtractPrerequisites()` in `prerequisites.go` using literal
string matching
- `bases.go`: load README at boot, fail loudly if missing, extract
prerequisites
- `compose.go`: include README in `ComposeResult` and tar bundle
- `codersdk`: add `Prerequisites` field to `TemplateBuilderBase`
- Handler: populate prerequisites in bases response, set readme on
template version

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

- Prerequisites extraction uses `strings.Index` for exact literal marker
matching; no regex or AST parser needed since we control the markers.
- YAML frontmatter is deliberately retained in the stored README. The
frontend `TemplateDocsPage` already strips it at render time via
`front-matter`.
- The prerequisite markers are HTML comments, invisible in rendered
markdown.
- The `RejectsMissingReadme` test enforces that every base template must
include a README.
- AWS Linux prerequisites span two H2 sections (`## Prerequisites` and
`## Required permissions / policy`), which is why heading-based parsing
was rejected in favor of explicit markers.

*Generated with the assistance of an AI coding agent. Reviewed by
@jeremyruppel.*
</details>

Relates to https://linear.app/codercom/issue/DEVEX-446
2026-06-23 11:36:07 -04:00