◐ Shell
clean mode source ↗

chore: Initial GHA workflow by bryphe-coder · Pull Request #1 · coder/coder

added 5 commits

January 3, 2022 19:17

bryphe-coder

bryphe-coder

@bryphe-coder

kylecarbs

matifali pushed a commit that referenced this pull request

Aug 14, 2023

kylecarbs added a commit that referenced this pull request

Mar 27, 2026
- Hoist createComponents to module scope in response.tsx so every
  Response instance shares stable component references. Previously,
  each render of each Response created a fresh components map,
  forcing Streamdown to discard its cached render tree.

- Wrap StickyUserMessage in memo(). Profiling showed it as the #1
  render bottleneck at 35.7% of component self time. Each instance
  carries IntersectionObserver + ResizeObserver + scroll handlers.

- Wrap ConversationTimeline in memo() to prevent cascade re-renders
  from the parent when props are stable.

- Remove duplicate buildSubagentTitles call from ConversationTimeline.
  It was already computed in AgentDetailTimeline and is now passed
  as a prop instead of recomputed.

kylecarbs added a commit that referenced this pull request

Mar 27, 2026
Addresses chat page rendering performance. Profiling with React Profiler
showed `AgentChat` actual render times of 20–31ms (exceeding the
16ms/60fps
budget), with `StickyUserMessage` as the #1 component bottleneck at
35.7%
of self time.

## Changes

**Hoist `createComponents` to module scope** (`response.tsx`):
Previously every `<Response>` instance called `createComponents()` per
render, creating a fresh components map that forced Streamdown to
discard
its cached render tree. Now both light/dark variants are precomputed
once
at module scope.

**Wrap `StickyUserMessage` in `memo()`** (`ConversationTimeline.tsx`):
Profile-confirmed #1 bottleneck. Each instance carries
IntersectionObserver
+ ResizeObserver + scroll handlers; skipping re-render avoids all that
setup.

**Wrap `ConversationTimeline` in `memo()`**
(`ConversationTimeline.tsx`):
Prevents cascade re-renders from the parent when props haven't changed.

**Remove duplicate `buildSubagentTitles`** (`ConversationTimeline.tsx` →
`AgentDetailContent.tsx`): Was computed in both `AgentDetailTimeline`
and
`ConversationTimeline`. Now computed once and passed as a prop.

<details>
<summary>Profiling data & analysis</summary>

### Profiler Metrics
| Metric | Value |
|--------|-------|
| INP (Interaction to Next Paint) | 82ms |
| Processing duration (event handlers) | 52ms |
| AgentChat actual render | 20–31ms (budget: 16ms) |
| AgentChat base render (no memo) | ~100ms |

### Top Bottleneck Components (self-time %)
| Component | Self Time | % |
|-----------|-----------|---|
| StickyUserMessage | 11.0ms | 35.7% |
| ForwardRef (radix-ui) | 7.4ms | 24.0% |
| Presence (radix-ui) | 2.0ms | 6.5% |
| AgentChatInput | 1.4ms | 4.5% |

### Decision log
- Chose module-scope precomputation over `useMemo` for
`createComponents`
  because there are only two possible theme variants and they're static.
- Did not add virtualization — sticky user messages + scroll anchoring
  make it complex. The memoization fixes should be measured first.
- Did not wrap `BlockList` in `memo()` — the React Compiler (enabled for
  `pages/AgentsPage/`) already auto-memoizes JSX elements inside it.
- Phase 2 (verify React Compiler effectiveness on
`parseMessagesWithMergedTools`)
and Phase 3 (radix-ui Tooltip lazy-mounting) deferred to follow-up PRs.

</details>

kylecarbs added a commit that referenced this pull request

May 7, 2026
… history

Replaces the previous draft of this PR (a backend workspaces.claimed_at
column plus migration plus SDK plumbing) with a frontend-only
heuristic per Cian's review.

The /agents archive-and-delete molly-guard previously compared
workspace.created_at against chat.created_at to decide whether to
require typing the workspace name. ClaimPrebuiltWorkspace never
updates workspace.created_at, so claimed prebuilds always looked
pre-existing and the dialog misfired.

Build history already records the truth: build #1's initiator is the
prebuilds system user iff the workspace was a prebuild, and build #2
is the claim. Compute that in the resolver and compare its created_at
against the chat. From-scratch workspaces fall through to
workspace.created_at as before.

The prebuilds system user UUID is hardcoded on the frontend; it lives
in coderd/database/constants.go on the backend and has not changed
since the prebuild feature shipped. If it ever moves, both sides have
to move together.

🤖 Generated with the help of Coder Agents.

kylecarbs added a commit that referenced this pull request

May 10, 2026
… dialog (#25057)

Closes
[CODAGT-317](https://linear.app/codercom/issue/CODAGT-317/pr-workspaces-sometimes-require-name-confirmation-to-delete).

## Problem

The `/agents` archive-and-delete molly-guard (typing the workspace name)
was firing for chats that had clearly created their own workspace. The
heuristic in `resolveArchiveAndDeleteAction` decides whether
confirmation is needed by comparing the workspace's `created_at` against
the chat's `created_at`:

```ts
return new Date(workspaceCreatedAt) >= new Date(chatCreatedAt);
```

That assumption breaks for **prebuilt workspaces**.
`ClaimPrebuiltWorkspace` rewrites `owner_id`, `name`, `updated_at`,
`last_used_at`, etc., but **never touches `created_at`**, which still
reflects when the prebuild was provisioned by the reconciler, often
hours before the chat exists. Result: every prebuild-claimed workspace
looks pre-existing, so the molly-guard fires.

Concrete example from a real chat:

| Field | Value |
|---|---|
| `chat.created_at` | `2026-05-07T15:12:23Z` |
| `workspace.created_at` (provision) | `2026-05-07T14:22:24Z` |
| `latest_build.created_at` (claim) | `2026-05-07T15:19:09Z` |

`14:22:24 < 15:12:23` so `isWorkspaceAutoCreated` returned false even
though the chat issued the claim.

## Fix (frontend-only)

Derive the moment a workspace was acquired from existing build history
rather than relying on `workspace.created_at`:

- Build #1 initiator = prebuilds system user → workspace was a prebuild
→ use `build_2.created_at` (the claim build) as the acquisition time.
- Build #1 initiator = real user → workspace was created from scratch →
use `workspace.created_at` (unchanged behavior).
- Unclaimed prebuild or no build history → return `null` (force
confirmation; safe degradation for a destructive flow).

The resolver fetches the build list via the existing
`getWorkspaceBuilds` endpoint when the dialog might fire. No new column,
no migration, no schema change. Works retroactively for all existing
claimed prebuilds; no backfill needed.

The prebuilds system user UUID is exposed via
`codersdk.PrebuildsSystemUserID` and typegen'd to `typesGenerated.ts`.
`coderd/database.PrebuildsSystemUserID` parses that constant via
`uuid.MustParse` so the two cannot drift; if the codersdk literal ever
changes, package init fails fast.

## History

The first draft of this PR added a `workspaces.claimed_at` column
populated by `ClaimPrebuiltWorkspace`. After review feedback from
@johnstcn pointing out that the same fact is already implicit in build
history, I pivoted to the frontend-only approach. Subsequent review
notes consolidated the prebuilds system user UUID into a single
typegen'd constant.

## Why not the other open PRs

- **#25055** (`chatKey` cache fallback) only fixes a different
cache-miss path; it explicitly notes it does not address `created_at <
chat.created_at`.
- **#25053** (`chats.workspace_auto_created` boolean) puts the truth on
the wrong side of the schema: "this workspace was claimed at time T" is
a property of the workspace, not the chat. The MCP plumbing it adds is
also unnecessary now that the same answer is available from build
history.

## Test plan

- `pnpm vitest run --project=unit
src/pages/AgentsPage/utils/agentWorkspaceUtils.test.ts` — 40/40 pass;
new cases cover prebuild claim before/after chat, unclaimed prebuild,
missing-build-history fallback, and the fetch-skip when the chat is not
in cache.
- `pnpm lint:types`, `pnpm check`, `make pre-commit`.

<details>
<summary>Disclosure</summary>

Opened on behalf of @kylecarbs by [Coder
Agents](https://coder.com/coder-agents).
</details>

f0ssel added a commit that referenced this pull request

May 13, 2026
…orkspaceBuild

CreateWorkspaceBuild goes through wsbuilder which now calls
SoftDeletePriorWorkspaceAgents, soft-deleting the agent from build #1.
The GetWorkspaceAgentLogs test was using that agent's ID, so it got a
404 after the stop build ran. Move it before CreateWorkspaceBuild so
the agent is still visible.

f0ssel added a commit that referenced this pull request

May 13, 2026
…orkspaceBuild

CreateWorkspaceBuild goes through wsbuilder which now calls
SoftDeletePriorWorkspaceAgents, soft-deleting the agent from build #1.
The GetWorkspaceAgentLogs test was using that agent's ID, so it got a
404 after the stop build ran. Move it before CreateWorkspaceBuild so
the agent is still visible.

f0ssel added a commit that referenced this pull request

May 14, 2026
Prior sub-tests call CreateWorkspaceBuild through the API, which
triggers SoftDeletePriorWorkspaceAgents and soft-deletes the agent
from build #1. Re-fetch the workspace to get the current (non-deleted)
agent ID instead of using the stale one captured at setup time.

f0ssel added a commit that referenced this pull request

May 14, 2026
Prior sub-tests call CreateWorkspaceBuild through the API, which
triggers SoftDeletePriorWorkspaceAgents and soft-deletes the agent
from build #1. Re-fetch the workspace to get the current (non-deleted)
agent ID instead of using the stale one captured at setup time.

f0ssel added a commit that referenced this pull request

May 14, 2026
Prior sub-tests call CreateWorkspaceBuild through the API, which
triggers SoftDeletePriorWorkspaceAgents and soft-deletes the agent
from build #1. Re-fetch the workspace to get the current (non-deleted)
agent ID instead of using the stale one captured at setup time.

This was referenced

May 15, 2026