Skip to content

Conversation

@rossmanko
Copy link
Contributor

@rossmanko rossmanko commented Aug 12, 2025

Summary by CodeRabbit

  • New Features

    • Chat supports authenticated, user-specific tools with persistent sandbox sessions.
    • File operations in chat: read previews and write confirmations.
    • Unified tool UI for terminal commands, file reads, and writes.
  • Improvements

    • Code block header layout improved for better alignment.
    • Sandboxes are paused automatically after runs; background pause handling added.
  • Chores

    • Environment example comment fixed.
    • Added runtime dependency to enable background task scheduling.

@coderabbitai
Copy link

coderabbitai bot commented Aug 12, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Adds user-scoped tools and persistent sandbox management to the chat API (WorkOS-aware), introduces read/write file tools and a terminal tool factory, centralizes tool UI via ToolHandler, adds sandbox utilities and safe background wait, tweaks a code-highlight header, and adds @vercel/functions dependency. Minor .env comment fix.

Changes

Cohort / File(s) Summary
API Auth & Chat Flow
app/api/chat/route.ts, .env.local.example
Chat POST now uses NextRequest, integrates WorkOS auth with anonymous fallback, calls createTools(userID, mode), streams model with tools, and pauses sandbox on finish. .env.local.example comment fixed.
UI: Tool Rendering & Code Header
app/components/ToolHandler.tsx, app/components/Message.tsx, app/components/CodeHighlight.tsx
Adds ToolHandler component to render runTerminalCmd/readFile/writeFile UIs; Message delegates tool parts to ToolHandler; CodeHighlight header layout adjusted with flexible left wrapper.
Tools Factory & Types
lib/ai/tools/index.ts, lib/ai/tools/types.ts
Adds createTools(userID, mode) factory exposing per-user tools and getSandbox; introduces SandboxManager, SandboxContext, and ToolContext types.
Tool Implementations
lib/ai/tools/run-terminal-cmd.ts, lib/ai/tools/read-file.ts, lib/ai/tools/write-file.ts
Converts terminal tool to createRunTerminalCmd(context) (context-driven sandbox usage) and adds createReadFile / createWriteFile tools with zod schemas for sandbox-backed file I/O.
Sandbox Utilities & Manager
lib/ai/tools/utils/sandbox.ts, lib/ai/tools/utils/sandbox-utils.ts, lib/ai/tools/utils/sandbox-manager.ts
Adds persistent sandbox lifecycle: create/connect/resume/pause/kill logic, ensureSandboxConnection, DefaultSandboxManager implementing lazy init and set/get sandbox, and pauseSandbox helper with background pause.
Background Wait Utility
lib/utils/safe-wait-until.ts
Adds safeWaitUntil wrapper using waitUntil to run Promises in background with error logging.
Dependencies
package.json
Adds dependency @vercel/functions ^2.2.8.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ChatAPI as Chat API (POST /api/chat)
  participant WorkOS as Auth (WorkOS)
  participant Tools as createTools
  participant Manager as SandboxManager
  participant Sandbox
  participant Model as Streaming Model

  Client->>ChatAPI: POST message
  ChatAPI->>WorkOS: get session (if configured)
  WorkOS-->>ChatAPI: userID or error
  ChatAPI->>Tools: createTools(userID, mode)
  Tools->>Manager: init with userID
  ChatAPI->>Model: stream({ tools })
  Model->>Manager: getSandbox()
  Manager->>Sandbox: ensure connect/resume/create
  Sandbox-->>Manager: sandbox handle
  Model-->>ChatAPI: streamed response + tool calls
  ChatAPI-->>Client: streamed response
  ChatAPI->>Sandbox: pauseSandbox (onFinish, background)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

In my burrow I build a mental lab,
Sandboxes hum while I tap the tab.
Read and write, and commands that run,
Streams arrive like carrots—one by one.
I pause, I save, then flop with glee—this rabbit dev is free. 🐇


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b086dd3 and 1c19afb.

📒 Files selected for processing (2)
  • app/components/ToolHandler.tsx (1 hunks)
  • lib/ai/tools/utils/sandbox-utils.ts (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/e2b-persistent-sandbox

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

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

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@vercel
Copy link

vercel bot commented Aug 12, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Project Deployment Preview Comments Updated (UTC)
hackerai Ready Preview Comment Aug 12, 2025 11:43pm

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🧹 Nitpick comments (8)
lib/utils/safe-wait-until.ts (1)

3-9: JSDoc parameter description doesn’t match the actual signature

Docs say “work - The async function…”, but the function currently accepts a Promise. Either update the docs or (preferably) change the API to accept a thunk (() => Promise) so synchronous errors are also captured and execution is deferred until waitUntil schedules it.

Here’s a doc-only fix if you keep the current signature:

- * @param work - The async function to execute in the background
+ * @param promise - The promise to execute in the background
lib/ai/tools/types.ts (3)

3-6: Consider simplifying getSandbox’s return type

Returning an object with a sandbox property adds ceremony without clear benefit. Consider returning the Sandbox directly (or Sandbox | null) to reduce boilerplate and improve ergonomics.

If you go that route:

export interface SandboxManager {
  getSandbox(): Promise<Sandbox | null>;
  setSandbox(sandbox: Sandbox): void;
  // optionally:
  // clearSandbox(): void;
}

This typically simplifies downstream usage and error handling.


8-11: SandboxContext shape may be too minimal for consumers

Exposing only setSandbox without a getter or a current value might force callers to re-fetch. Consider adding either a sandbox?: Sandbox field and/or a getSandbox accessor, or rely solely on SandboxManager to avoid duplicated concepts.


13-15: Document ToolContext to guide implementers

Add a brief JSDoc explaining that ToolContext is passed into tool factories and must be server-only (no client usage), since SandboxManager will touch server resources.

Example:

/**
 * Context passed to tool factories. Must be used server-side only.
 * Provides access to per-user sandbox lifecycle via sandboxManager.
 */
export interface ToolContext {
  sandboxManager: SandboxManager;
}
lib/ai/tools/index.ts (1)

13-21: Potential memory leak in sandbox callback closure.

The callback function (newSandbox) => { sandbox = newSandbox; } captures the local sandbox variable, but the closure may not be properly cleaned up. Consider using a more explicit pattern.

Apply this diff to use a more explicit callback pattern:

-  let sandbox: Sandbox | null = null;
+  let sandbox: Sandbox | null = null;
+
+  const setSandboxCallback = (newSandbox: Sandbox) => {
+    sandbox = newSandbox;
+  };

   const sandboxManager = new DefaultSandboxManager(
     userID,
-    (newSandbox) => {
-      sandbox = newSandbox;
-    },
+    setSandboxCallback,
     sandbox,
   );
lib/ai/tools/utils/sandbox-manager.ts (1)

19-30: Redundant sandbox check after ensureSandboxConnection.

Line 26 passes this.sandbox (which is null at this point) as initialSandbox to ensureSandboxConnection, making this parameter effectively unused. The subsequent null check on line 32 is also redundant since ensureSandboxConnection should always return a valid sandbox or throw.

Apply this diff to simplify the logic:

     if (!this.sandbox) {
       const result = await ensureSandboxConnection(
         {
           userID: this.userID,
           setSandbox: this.setSandboxCallback,
         },
-        {
-          initialSandbox: this.sandbox,
-        },
       );
       this.sandbox = result.sandbox;
     }

-    if (!this.sandbox) {
-      throw new Error("Failed to initialize sandbox");
-    }

     return { sandbox: this.sandbox };
lib/ai/tools/read-file.ts (1)

18-23: Parameter naming consistency with write-file.

This tool uses target_file while write-file uses file_path. Consider unifying to a single name (e.g., file_path) across tools to minimize model confusion and UI branching.

lib/ai/tools/run-terminal-cmd.ts (1)

10-22: Nit: fix contraction in tool description.

Minor copy edit improves polish.

-7. Dont include any newlines in the command.`,
+7. Don't include any newlines in the command.`,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b5d13d4 and b086dd3.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (15)
  • .env.local.example (1 hunks)
  • app/api/chat/route.ts (1 hunks)
  • app/components/CodeHighlight.tsx (1 hunks)
  • app/components/Message.tsx (2 hunks)
  • app/components/ToolHandler.tsx (1 hunks)
  • lib/ai/tools/index.ts (1 hunks)
  • lib/ai/tools/read-file.ts (1 hunks)
  • lib/ai/tools/run-terminal-cmd.ts (2 hunks)
  • lib/ai/tools/types.ts (1 hunks)
  • lib/ai/tools/utils/sandbox-manager.ts (1 hunks)
  • lib/ai/tools/utils/sandbox-utils.ts (1 hunks)
  • lib/ai/tools/utils/sandbox.ts (1 hunks)
  • lib/ai/tools/write-file.ts (1 hunks)
  • lib/utils/safe-wait-until.ts (1 hunks)
  • package.json (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (8)
lib/ai/tools/write-file.ts (1)
lib/ai/tools/types.ts (1)
  • ToolContext (13-15)
lib/ai/tools/utils/sandbox-utils.ts (3)
lib/ai/tools/types.ts (1)
  • SandboxContext (8-11)
lib/ai/tools/utils/sandbox.ts (1)
  • createOrConnectPersistentTerminal (21-135)
lib/ai/tools/utils/sandbox-manager.ts (1)
  • setSandbox (39-42)
app/api/chat/route.ts (3)
lib/ai/tools/index.ts (1)
  • createTools (9-40)
lib/ai/tools/utils/sandbox-manager.ts (1)
  • getSandbox (16-37)
lib/ai/tools/utils/sandbox.ts (1)
  • pauseSandbox (150-167)
lib/ai/tools/utils/sandbox.ts (1)
lib/utils/safe-wait-until.ts (1)
  • safeWaitUntil (10-22)
lib/ai/tools/read-file.ts (1)
lib/ai/tools/types.ts (1)
  • ToolContext (13-15)
lib/ai/tools/utils/sandbox-manager.ts (2)
lib/ai/tools/types.ts (1)
  • SandboxManager (3-6)
lib/ai/tools/utils/sandbox-utils.ts (1)
  • ensureSandboxConnection (8-38)
lib/ai/tools/index.ts (5)
lib/ai/tools/utils/sandbox-manager.ts (2)
  • DefaultSandboxManager (5-43)
  • getSandbox (16-37)
lib/ai/tools/types.ts (1)
  • ToolContext (13-15)
lib/ai/tools/run-terminal-cmd.ts (1)
  • createRunTerminalCmd (6-55)
lib/ai/tools/read-file.ts (1)
  • createReadFile (5-80)
lib/ai/tools/write-file.ts (1)
  • createWriteFile (5-46)
lib/ai/tools/run-terminal-cmd.ts (1)
lib/ai/tools/types.ts (1)
  • ToolContext (13-15)
🪛 Biome (2.1.2)
app/components/ToolHandler.tsx

[error] 38-40: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 87-87: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🔇 Additional comments (15)
package.json (1)

21-21: safeWaitUntil is confined to a Vercel API Route handler

All invocations of waitUntil via safeWaitUntil are wrapped in pauseSandbox and only ever called inside the /app/api/chat/route.ts onFinish handler. No other call sites exist.

• lib/utils/safe-wait-until.ts – defines safeWaitUntil (imports waitUntil)
• lib/ai/tools/utils/sandbox.ts – calls safeWaitUntil in pauseSandbox()
• app/api/chat/route.ts – await pauseSandbox(sandbox) inside the server-side route’s onFinish callback

No usages of safeWaitUntil (or waitUntil) occur outside of a request context.

.env.local.example (1)

14-15: LGTM – comment fix improves clarity

The corrected comment is clearer and aligns with WorkOS dashboard-based configuration.

app/components/CodeHighlight.tsx (1)

99-105: LGTM – layout change keeps actions right-aligned even without a language badge

Wrapping the left header segment with flex-1 ensures consistent spacing and alignment. Good change.

app/components/Message.tsx (2)

5-5: LGTM - Clean centralization of tool handling.

The import of ToolHandler is appropriate and aligns with the centralized tool handling pattern.


50-61: LGTM - Elegant tool handling refactor.

The refactor successfully centralizes tool handling by:

  • Using a consistent pattern to extract toolName from part.type
  • Leveraging part.toolCallId as a stable key for React rendering
  • Delegating all tool-specific UI logic to the ToolHandler component

This approach is extensible and maintains clean separation of concerns.

lib/ai/tools/write-file.ts (1)

31-44: LGTM - Robust error handling and clear feedback.

The implementation provides:

  • Proper async/await usage with the sandbox API
  • Comprehensive error handling with descriptive messages
  • Helpful feedback showing the number of lines written

The error handling correctly distinguishes between Error instances and other types.

lib/ai/tools/index.ts (2)

34-35: LGTM - Appropriate tool filtering based on mode.

The mode-based tool filtering is well-implemented:

  • "ask" mode provides read-only access with just readFile
  • Default "agent" mode provides full tool access
  • Clean object destructuring maintains type safety

37-39: LGTM - Simple and effective sandbox accessor.

The getSandbox function provides a clean way to access the current sandbox state, properly returning null when no sandbox is initialized.

lib/ai/tools/utils/sandbox-manager.ts (1)

39-42: LGTM - Clean sandbox update pattern.

The setSandbox method properly updates both the internal state and notifies the callback, maintaining consistency across the sandbox management system.

lib/ai/tools/utils/sandbox-utils.ts (2)

29-34: LGTM - Comprehensive error handling with context.

The error handling properly:

  • Logs the original error for debugging
  • Provides a descriptive error message
  • Preserves the original error details when available
  • Maintains the error chain for troubleshooting

5-6: Ensure sandbox template name aligns with persistent sandbox and validate timeout

I only see SANDBOX_TEMPLATE defined once (in lib/ai/tools/utils/sandbox-utils.ts) as "temporary-sandbox". If this constant now powers your persistent‐sandbox feature, rename or update it to match the actual template (e.g. "persistent-sandbox"). Also confirm that a 15-minute Bash timeout is sufficient for your use case—or bump it if longer‐lived sessions are expected.

• lib/ai/tools/utils/sandbox-utils.ts:

  • const SANDBOX_TEMPLATE = "temporary-sandbox";
  • const BASH_SANDBOX_TIMEOUT = 15 * 60 * 1000;
app/api/chat/route.ts (2)

22-35: WorkOS-aware user scoping looks solid with safe fallbacks.

Fetching the user ID via authkit(req) only when WorkOS is configured, and falling back to "anonymous" on errors, is a pragmatic and safe approach.


37-48: Good: user-scoped tool provisioning and clean integration with streamText.

Passing tools from createTools(userID, mode) directly into streamText aligns the API with tool lifecycle ownership and keeps the route lean.

lib/ai/tools/run-terminal-cmd.ts (1)

6-8: Good: context-driven sandbox access via SandboxManager.

Refactoring to a factory that pulls the sandbox from sandboxManager keeps lifecycle control in one place. This matches the persistent sandbox architecture introduced in this PR.

app/components/ToolHandler.tsx (1)

15-21: Type narrowing OK; UI mapping matches tool payloads.

The narrowing of input and output for each tool path is sensible, and keys are stable via toolCallId.

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.

2 participants