Repository navigation
feat(agents): header with New Drive/Agent/Session CTAs on Agents list - #2300
Conversation
…list The Agents console's past-conversations list had no header — it started immediately below the tab bar with no way to start something new from inside it. New Session lived only in the sidebar, New Drive only on the Drives page, and there was no dedicated New Agent affordance anywhere. Adds AgentsListHeader above the list with all three CTAs: - New Drive reuses the existing CreateDriveDialog as-is. - New Session extracts the sidebar's spawn flow (spawn(), SpawnSessionPalette, related state) into a shared useSpawnSession hook so the header and sidebar don't duplicate the two-step spawn logic. AgentsSidebar.tsx is refactored to use the same hook with no behavior change. - New Agent reuses the existing Quick Create palette. On the global (driveless) Agents page, New Session/New Agent open a new DrivePickerDialog first, since neither creation path has a drive to act on without one.
|
Warning Review limit reached
Next review available in: 7 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThe PR adds shared session-spawn orchestration, drive selection, and Agents creation controls. It integrates the controls into the Agents surface and replaces sidebar-specific spawning logic with the shared hook. ChangesAgents session controls
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant AgentUser
participant AgentsListHeader
participant DrivePickerDialog
participant useSpawnSession
participant SessionAPI
participant Router
AgentUser->>AgentsListHeader: choose New Session
AgentsListHeader->>DrivePickerDialog: open picker for global action
DrivePickerDialog-->>AgentsListHeader: return selected drive
AgentsListHeader->>useSpawnSession: select session target
useSpawnSession->>SessionAPI: create session
SessionAPI-->>useSpawnSession: return created session
useSpawnSession->>Router: open conversation or shell workspace
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (1)
apps/web/src/components/agents/useSpawnSession.tsx (1)
235-265: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a
CommandEmptyto the target list.If the search text matches no agent,
Global Assistant, orShell, the list renders with no rows and no message.DrivePickerDialogin this same PR renders aCommandEmptyfor the same situation. Match that behavior.♻️ Proposed change
<CommandInput placeholder="Search agents…" autoFocus /> <CommandList> + <CommandEmpty>No matches.</CommandEmpty> <CommandGroup>Add
CommandEmptyto the import at lines 7-13.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/src/components/agents/useSpawnSession.tsx` around lines 235 - 265, Add CommandEmpty to the imports and render it inside the target CommandList alongside the existing CommandGroup, so searches matching no agent, Global Assistant, or Shell display the standard empty-state message consistent with DrivePickerDialog.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/src/components/agents/AgentsListHeader.tsx`:
- Around line 71-84: Gate the “New Session” button in AgentsListHeader using the
same useAuth admin/loading state as AgentsSidebar, such as canSpawn = isAdmin &&
!authLoading. Hide or disable the control for non-admin users while preserving
handleNewSession for authorized users.
- Line 30: Update the useSpawnSession call in AgentsListHeader to provide an
onSpawned callback that revalidates the sidebar’s /api/agent-sessions SWR key.
Reuse the existing session-change invalidation behavior from AgentsSidebar’s
onChanged callback so newly spawned sessions appear immediately.
- Around line 53-66: The handleDrivePicked flow must wait for the dashboard
route change before opening Quick Create. Update the pickerFor === 'agent'
branch to retain the selected drive and trigger openQuickCreate(null) only after
router.push commits and QuickCreatePalette receives the new params.driveId,
avoiding resolution against the previous or global Agents route.
In `@apps/web/src/components/agents/DrivePickerDialog.tsx`:
- Line 42: Update the CommandEmpty text in DrivePickerDialog so it describes an
empty search result rather than implying the user has no drives. Keep the
existing empty-state rendering and only adjust the displayed message to
accurately cover filtered searches.
- Line 45: Update the CommandItem in DrivePickerDialog to use a value derived
from the unique drive.id rather than drive.name, ensuring cmdk distinguishes
drives with duplicate names while preserving the existing onPick arguments.
In `@apps/web/src/components/agents/useSpawnSession.tsx`:
- Around line 218-230: Add an accessible name to the session-name input in the
name-entry flow by associating it with a visible label or adding a descriptive
aria-label. Keep the existing value, submission, placeholder, and disabled
behavior unchanged.
---
Nitpick comments:
In `@apps/web/src/components/agents/useSpawnSession.tsx`:
- Around line 235-265: Add CommandEmpty to the imports and render it inside the
target CommandList alongside the existing CommandGroup, so searches matching no
agent, Global Assistant, or Shell display the standard empty-state message
consistent with DrivePickerDialog.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 203a37dc-0f88-4c45-b9ad-b2f77b5bc593
📒 Files selected for processing (5)
apps/web/src/components/agents/AgentsListHeader.tsxapps/web/src/components/agents/AgentsSurface.tsxapps/web/src/components/agents/DrivePickerDialog.tsxapps/web/src/components/agents/useSpawnSession.tsxapps/web/src/components/layout/left-sidebar/AgentsSidebar.tsx
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2aff4d693a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| <Plus className="h-4 w-4 mr-1" /> | ||
| New Agent | ||
| </Button> | ||
| <Button size="sm" onClick={handleNewSession}> |
There was a problem hiding this comment.
Gate New Session on sandbox permissions
In production, non-admin users can open this past-conversations surface, but this button is rendered unconditionally even though sandbox spawning is rejected by the centralized canRunCode check with app_admin_required; the existing sidebar avoids this dead-end by exposing spawn controls only when isAdmin && !authLoading. Gate this CTA with the same authorization state so these users are not led through both dialogs only to receive a 403.
AGENTS.md reference: AGENTS.md:L119-L123
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
This was already fixed in b2f69ce (pushed before this comment landed): "New Session" is now gated behind the same isAdmin && !authLoading check AgentsSidebar uses (canSpawn), and hidden entirely for non-admins. Leaving this thread open for your own verification per policy rather than resolving it myself.
| router.push(`/dashboard/${pickedDriveId}/agents`); | ||
| openQuickCreate(null); |
There was a problem hiding this comment.
Wait for the drive route before opening Quick Create
On the global Agents page, especially during a slow or uncached navigation, openQuickCreate runs synchronously while QuickCreatePalette still sees the old route with no driveId. A fast user can select a type and submit before router.push completes, at which point handleCreate returns immediately on !driveId without feedback. Open the palette only after the selected drive is available to it, or pass the picked drive explicitly instead of relying on asynchronously updated route params.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Also already fixed in b2f69ce: "New Agent" on the global page now tracks a pendingAgentDriveId and only calls openQuickCreate once this component's own driveId prop (sourced from the same route QuickCreatePalette reads via useParams()) actually matches the picked drive — no more opening in the same tick as router.push. Leaving this thread open for your own verification per policy rather than resolving it myself.
Self-review pass on PR #2300 surfaced two real gaps: - "New Session" was rendered unconditionally, but session spawning is admin-only everywhere else in this console (AgentsSidebar hides its entire spawn affordance behind `isAdmin`, and GET /api/agent-sessions 403s non-admins). The header showing it to everyone was an inconsistent UI promise. Gated behind the same isAdmin check, and disabled the agents fetch for non-admins since it's spawn-only data. - "New Agent" on the global page called router.push() then openQuickCreate() in the same tick — QuickCreatePalette resolves its driveId from useParams(), so this could open Quick Create before the navigation's params actually landed, silently no-opping Create if the user was fast. Now waits for this component's own driveId prop to reflect the picked drive before opening Quick Create. Also adds AgentsListHeader.test.tsx — the three new files this PR introduced had zero dedicated test coverage.
3 findings (1 blocker, 1 major, 1 minor), all fixed in b2f69ce.
- AgentsListHeader: pass an onSpawned callback into useSpawnSession
that revalidates every /api/agent-sessions SWR key, so a session
spawned from the header shows up in the sidebar immediately instead
of waiting for its 20s poll.
- DrivePickerDialog: CommandItem value keyed by drive.id (not just
drive.name) — two drives sharing a name would otherwise collide in
cmdk's filtering/selection. Also fixed the empty-state copy ("No
drives found." instead of "No drives yet.", which was wrong when the
search text just matched nothing).
- useSpawnSession: added aria-label="Session name" to the naming
step's input — it had no accessible name.
Summary
AgentsListHeader) above the Agents console's past-conversations list, which previously started with no title or actions directly below the tab bar.CreateDriveDialog), New Session, New Agent (reuses the Quick Create palette).spawn,SpawnSessionPalette, related state) out ofAgentsSidebar.tsxinto a shareduseSpawnSessionhook so the new header and the sidebar don't duplicate that logic.AgentsSidebar.tsxnow consumes the same hook with no behavior change./dashboard/agentspage, New Session/New Agent open a newDrivePickerDialogfirst, since neither creation path has a drive to act on without one.AgentsSidebar's own admin-only gate for spawning sandboxes.Review
Self-reviewed and addressed CodeRabbit + chatgpt-codex-connector feedback across two rounds (7 findings fixed — admin gating, a driveId navigation race, missing SWR revalidation on spawn, a cmdk duplicate-value bug, empty-state copy, and an accessibility gap). Full findings log:
tasks/reviews/pu-header-for-agents-page.md.Test plan
bun run --filter web typecheck— cleanbun run --filter web lint— clean, no new warningsbun run --filter web test -- src/components/agents/__tests__/AgentsSurface.test.tsx src/components/agents/__tests__/AgentsListHeader.test.tsx src/components/layout/left-sidebar/__tests__/AgentsSidebar.test.tsx— 89/89 passing🤖 Generated with Claude Code
https://claude.ai/code/session_01FkHfnA78K8SA5ffNGguhuC
Summary by CodeRabbit