Skip to content

feat(agents): header with New Drive/Agent/Session CTAs on Agents list - #2300

Merged
2witstudios merged 5 commits into
masterfrom
pu/header-for-agents-page
Aug 1, 2026
Merged

2witstudios merged 5 commits into
masterfrom
pu/header-for-agents-page

Conversation

@2witstudios

@2witstudios 2witstudios commented Aug 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Adds a header (AgentsListHeader) above the Agents console's past-conversations list, which previously started with no title or actions directly below the tab bar.
  • Three CTAs: New Drive (reuses CreateDriveDialog), New Session, New Agent (reuses the Quick Create palette).
  • Extracts the sidebar's session-spawn flow (spawn, SpawnSessionPalette, related state) out of AgentsSidebar.tsx into a shared useSpawnSession hook so the new header and the sidebar don't duplicate that logic. AgentsSidebar.tsx now consumes the same hook with no behavior change.
  • On the global (driveless) /dashboard/agents page, New Session/New Agent open a new DrivePickerDialog first, since neither creation path has a drive to act on without one.
  • "New Session" is hidden for non-admins, matching 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 — clean
  • bun run --filter web lint — clean, no new warnings
  • bun 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
  • CI: Lint & TypeScript Check, Unit Tests, CodeRabbit — all green
  • Manual click-through: drive-scoped Agents page header renders + all three CTAs work; global Agents page header renders + drive-picker flow works for New Session/New Agent

🤖 Generated with Claude Code

https://claude.ai/code/session_01FkHfnA78K8SA5ffNGguhuC

Summary by CodeRabbit

  • New Features
    • Added Agents console controls for creating drives, agents, and sessions.
    • Added searchable drive selection for launching sessions and creating agents.
    • Added support for starting agent, shell, and assistant sessions.
    • Added session naming and direct navigation to newly created conversations or workspaces.
  • Improvements
    • Centralized session creation across the Agents console and sidebar.
    • Added loading safeguards, refresh handling, and error notifications during session creation.

…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.
@coderabbitai

coderabbitai Bot commented Aug 1, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@2witstudios, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 570067ec-d826-4649-b0b7-ec1ed5d6d514

📥 Commits

Reviewing files that changed from the base of the PR and between 2aff4d6 and 10ab84f.

📒 Files selected for processing (5)
  • apps/web/src/components/agents/AgentsListHeader.tsx
  • apps/web/src/components/agents/DrivePickerDialog.tsx
  • apps/web/src/components/agents/__tests__/AgentsListHeader.test.tsx
  • apps/web/src/components/agents/useSpawnSession.tsx
  • tasks/reviews/pu-header-for-agents-page.md
📝 Walkthrough

Walkthrough

The 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.

Changes

Agents session controls

Layer / File(s) Summary
Shared session spawning
apps/web/src/components/agents/useSpawnSession.tsx, apps/web/src/components/layout/left-sidebar/AgentsSidebar.tsx
useSpawnSession manages target selection, session creation, navigation, loading state, cache callbacks, and errors. AgentsSidebar uses the shared palette and handlers.
Agents header actions
apps/web/src/components/agents/DrivePickerDialog.tsx, apps/web/src/components/agents/AgentsListHeader.tsx
DrivePickerDialog selects searchable non-trashed drives. AgentsListHeader adds drive, agent, and session creation flows for scoped and global actions.
Agents surface layout
apps/web/src/components/agents/AgentsSurface.tsx
The surface places AgentsListHeader above the drive-keyed past-conversations list in a full-height flex layout.

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
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding New Drive, New Agent, and New Session CTAs to the Agents list.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pu/header-for-agents-page

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
apps/web/src/components/agents/useSpawnSession.tsx (1)

235-265: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a CommandEmpty to the target list.

If the search text matches no agent, Global Assistant, or Shell, the list renders with no rows and no message. DrivePickerDialog in this same PR renders a CommandEmpty for the same situation. Match that behavior.

♻️ Proposed change
           <CommandInput placeholder="Search agents…" autoFocus />
           <CommandList>
+            <CommandEmpty>No matches.</CommandEmpty>
             <CommandGroup>

Add CommandEmpty to 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

📥 Commits

Reviewing files that changed from the base of the PR and between c11fe84 and 2aff4d6.

📒 Files selected for processing (5)
  • apps/web/src/components/agents/AgentsListHeader.tsx
  • apps/web/src/components/agents/AgentsSurface.tsx
  • apps/web/src/components/agents/DrivePickerDialog.tsx
  • apps/web/src/components/agents/useSpawnSession.tsx
  • apps/web/src/components/layout/left-sidebar/AgentsSidebar.tsx

Comment thread apps/web/src/components/agents/AgentsListHeader.tsx Outdated
Comment thread apps/web/src/components/agents/AgentsListHeader.tsx
Comment thread apps/web/src/components/agents/AgentsListHeader.tsx
Comment thread apps/web/src/components/agents/DrivePickerDialog.tsx Outdated
Comment thread apps/web/src/components/agents/DrivePickerDialog.tsx Outdated
Comment thread apps/web/src/components/agents/useSpawnSession.tsx

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +63 to +64
router.push(`/dashboard/${pickedDriveId}/agents`);
openQuickCreate(null);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@2witstudios
2witstudios merged commit 2b5616b into master Aug 1, 2026
3 checks passed
@2witstudios
2witstudios deleted the pu/header-for-agents-page branch August 1, 2026 20:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant