chore: Initial GHA workflow by bryphe-coder · Pull Request #1 · coder/coder
added 5 commits
kylecarbs added a commit that referenced this pull request
- 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
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
… 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
… 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
…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
…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
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
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
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