Skip to content

Conversation

@rossmanko
Copy link
Contributor

@rossmanko rossmanko commented Aug 15, 2025

Summary by CodeRabbit

  • New Features

    • Selectable execution mode (local or sandbox) with local as default.
    • Added file tools: delete, search/replace, and multi-edit.
    • Sidebar auto-opens to display files read/written during streaming.
    • Terminal now indicates when commands run in the background.
  • Improvements

    • Refined desktop responsiveness; adjusted sidebar visibility and chat layout.
    • Updated tool icons and sizing; consistent link styling and theme link color.
    • Enhanced assistant behavior with current-date context.
  • Documentation

    • Reorganized env setup with clearer sections.
    • Added required OPENROUTER_API_KEY and sandbox configuration guidance.

- Add TERMINAL_EXECUTION_MODE environment variable (local/sandbox)
- Create local terminal execution utilities using Node.js child_process
- Update terminal command tool to support dual execution modes
- Set local mode as default for better user experience
- Maintain backward compatibility with existing sandbox mode
@vercel
Copy link

vercel bot commented Aug 15, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
hackerai Ready Ready Preview Comment Aug 15, 2025 4:38pm

@coderabbitai
Copy link

coderabbitai bot commented Aug 15, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Introduces an ExecutionMode (“local” | “sandbox”) across backend tools and system prompt; adds new file-edit tools; implements local filesystem and terminal execution utilities; updates chat route to pass executionMode; enhances UI with sidebar auto-open, background terminal indicator, link styling, and desktop breakpoint; reorganizes environment config and README accordingly.

Changes

Cohort / File(s) Summary
Env & Docs
/.env.local.example, /README.md
Reorganized env sections; added OPENROUTER_API_KEY and TERMINAL_EXECUTION_MODE; made E2B_API_KEY optional; clarified WorkOS settings. README updated to reflect required config, local vs sandbox execution, and sandbox snippet.
API, Prompt, Types, Tool Factory
/app/api/chat/route.ts, /lib/system-prompt.ts, /types/*, /lib/ai/tools/index.ts
Threaded ExecutionMode from env to tools and prompt; updated systemPrompt signature/content (date, sandbox block, comms guidelines); expanded types (ExecutionMode, ToolContext); createTools now accepts ChatMode and ExecutionMode; added new tools to the factory.
AI Tools – File Ops & Terminal
/lib/ai/tools/read-file.ts, /lib/ai/tools/write-file.ts, /lib/ai/tools/delete-file.ts, /lib/ai/tools/search-replace.ts, /lib/ai/tools/multi-edit.ts, /lib/ai/tools/run-terminal-cmd.ts, /lib/ai/tools/utils/local-file-operations.ts, /lib/ai/tools/utils/local-terminal.ts, /lib/ai/tools/utils/sandbox-manager.ts, /lib/ai/tools/utils/sandbox-utils.ts
Added local-mode support for read/write/run; introduced delete-file, search-replace, multi-edit tools; implemented local FS and terminal utilities; updated imports to aliased types; sandbox paths preserved for non-local.
UI Components
/app/components/MessagePartHandler.tsx, /app/components/TerminalCodeBlock.tsx, /app/components/ComputerSidebar.tsx, /components/ui/tool-block.tsx, /app/components/MemoizedMarkdown.tsx
Added renderers for delete/searchReplace/multiEdit; improved read/write interactions and icons; passed isBackground to TerminalCodeBlock (new prop renders background indicator); switched breakpoint classes to desktop; standardized icon sizing; styled Markdown links.
Hooks & Page Wiring
/app/hooks/useSidebarAutoOpen.ts, /app/components/Messages.tsx, /app/page.tsx
New hook auto-opens sidebar on assistant outputs; Messages exposes resetSidebarAutoOpen via ref; page wires reset on submit; layout breakpoints moved to desktop.
Styles
/app/globals.css
Added desktop custom variant (min-width: 950px); introduced --link-color and theme alias; mirrored color in dark mode.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Client
  participant API as POST /api/chat
  participant Tools as createTools
  participant Prompt as systemPrompt
  participant Exec as Tool (read/write/delete/searchReplace/multiEdit/run)

  User->>Client: Submit message
  Client->>API: Request with model
  API->>Prompt: systemPrompt(model, executionMode)
  API->>Tools: createTools(userID, writer, mode, executionMode)
  API->>Exec: Invoke tool(s)
  alt executionMode == local
    Exec->>Exec: Use local-file-operations / local-terminal
  else executionMode == sandbox
    Exec->>Exec: Use sandbox manager/files/commands
  end
  Exec-->>API: Stream outputs
  API-->>Client: Stream assistant + tool parts
Loading
sequenceDiagram
  participant Client
  participant Messages
  participant Hook as useSidebarAutoOpen
  participant Sidebar as GlobalState.openFileInSidebar

  Client->>Messages: Render(messages, status, lastIdx, resetRef)
  Messages->>Hook: useSidebarAutoOpen(messages, lastIdx, status)
  Hook->>Hook: Detect read/write tool output
  alt width >= 950px and streaming
    Hook->>Sidebar: openFileInSidebar(file, content, range)
  end
  Hook-->>Messages: resetSidebarFlag via ref
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

A rabbit taps keys in the moon’s soft glow,
“Local or sandbox? Now I know!”
Files dance, edits prance, terminals hum,
Sidebars pop open—here they come.
Links gleam blue, code sings along—
Hippity-hop, the tools grow strong. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 093af6b and dc77e28.

📒 Files selected for processing (23)
  • .env.local.example (1 hunks)
  • app/api/chat/route.ts (3 hunks)
  • app/components/MemoizedMarkdown.tsx (1 hunks)
  • app/components/MessagePartHandler.tsx (10 hunks)
  • app/components/Messages.tsx (4 hunks)
  • app/components/TerminalCodeBlock.tsx (2 hunks)
  • app/globals.css (4 hunks)
  • app/hooks/useSidebarAutoOpen.ts (1 hunks)
  • app/page.tsx (7 hunks)
  • lib/ai/tools/delete-file.ts (1 hunks)
  • lib/ai/tools/index.ts (2 hunks)
  • lib/ai/tools/multi-edit.ts (1 hunks)
  • lib/ai/tools/read-file.ts (2 hunks)
  • lib/ai/tools/run-terminal-cmd.ts (2 hunks)
  • lib/ai/tools/search-replace.ts (1 hunks)
  • lib/ai/tools/utils/local-file-operations.ts (1 hunks)
  • lib/ai/tools/utils/local-terminal.ts (1 hunks)
  • lib/ai/tools/utils/sandbox-manager.ts (1 hunks)
  • lib/ai/tools/utils/sandbox-utils.ts (1 hunks)
  • lib/ai/tools/write-file.ts (2 hunks)
  • lib/system-prompt.ts (5 hunks)
  • types/agent.ts (1 hunks)
  • types/index.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/local-terminal-execution

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

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: 13

🔭 Outside diff range comments (3)
lib/ai/tools/write-file.ts (1)

10-17: Align tool reference naming in write-file.ts

We confirmed via lib/ai/tools/index.ts that the read‐file tool is registered under the key readFile (camelCase), not read_file. To avoid confusion for the model and end users, update the description in lib/ai/tools/write-file.ts to either reference the actual ID or use generic wording.

• File: lib/ai/tools/write-file.ts
• Line: 14

Suggested diff:

-    - If this is an existing file, you MUST use the read_file tool first to read the file's contents.
+    - If this is an existing file, you MUST use the read file tool first to read the file's contents.
lib/ai/tools/read-file.ts (2)

24-36: Guard against invalid offset/limit (offset <= 0 or negative limit yields incorrect slices)

Currently, offset can be 0 or negative, which causes lines.slice(offset - 1) to slice from the end. Similarly, a negative limit will slice from the end. Add Zod constraints to prevent invalid values.

Apply this diff:

-      offset: z
-        .number()
-        .optional()
+      offset: z
+        .number()
+        .int()
+        .min(1)
+        .optional()
         .describe(
           "The line number to start reading from. Only provide if the file is too large to read at once.",
         ),
-      limit: z
-        .number()
-        .optional()
+      limit: z
+        .number()
+        .int()
+        .positive()
+        .optional()
         .describe(
           "The number of lines to read. Only provide if the file is too large to read at once.",
         ),

22-23: Clarify sandbox vs. local absolute‐path semantics

The current description (“you can use either a relative path in the workspace or an absolute path … preserved as is”) is misleading: sandbox.files.read() only accepts paths rooted inside the sandbox (i.e. /… refers to the sandbox’s root, not your host filesystem). Host‐absolute paths (e.g. /Users/me/file.txt on your machine) will fail unless that exact path was already written into the sandbox. In local mode you can use host‐absolute paths via readLocalFile(), but for sandbox reads you must:

  • Provide workspace‐relative paths (e.g. ./foo.txt), or
  • Provide sandbox‐rooted paths starting with / (e.g. /data/foo.txt), and
  • If you need to read a host file into the sandbox, first read it locally then sandbox.files.write('/desired/sandbox/path', content).

Please update the descriptions at lines 22–23 (and similarly at 47–80) to reflect this distinction.

♻️ Duplicate comments (1)
lib/ai/tools/utils/local-terminal.ts (1)

113-113: Duplicate code: Same shell injection vulnerability

This line has the same security issue as Line 65 - using sh -c with unsanitized command input.

🧹 Nitpick comments (25)
components/ui/tool-block.tsx (1)

41-41: Consistent icon sizing: nice touch; consider minor a11y + button semantics tweaks

The SVG sizing variant ensures consistent icon dimensions in tool blocks. Two small follow-ups:

  • Decorative icons: hide from AT if they don’t convey meaning.
  • Buttons: set non-submit intent explicitly and disable when not clickable to avoid accidental submissions and improve keyboard behavior.

Apply this diff for the icon container (decorative case):

-        <div className="w-[21px] inline-flex items-center flex-shrink-0 text-foreground [&>svg]:h-4 [&>svg]:w-4">
+        <div
+          className="w-[21px] inline-flex items-center flex-shrink-0 text-foreground [&>svg]:h-4 [&>svg]:w-4"
+          aria-hidden="true"
+        >

Outside the selected lines, consider:

<button
  type="button"
  className={`${baseClasses} ${clickableClasses}`}
  onClick={isClickable ? onClick : undefined}
  onKeyDown={isClickable ? onKeyDown : undefined}
  tabIndex={isClickable ? 0 : -1}
  disabled={!isClickable}
  aria-label={isClickable && target ? `Open ${target} in sidebar` : undefined}
/>
app/globals.css (1)

5-5: Custom desktop variant added — aligns with the PR’s responsive updates

Defining @custom-variant desktop (@media (min-width: 950px)); is a clean way to standardize desktop-specific styles across components. Consider documenting “desktop” in a brief README/style guide note so contributors know when to use desktop: vs legacy breakpoints.

.env.local.example (1)

41-41: Fix dotenv linter warning: ensure trailing newline at EOF

The dotenv linter flags a missing blank line at the end of file. Add a trailing newline to keep CI linting happy.

Apply this minimal diff at EOF:

-# NEXT_PUBLIC_WORKOS_REDIRECT_URI="http://localhost:3000/callback"
+# NEXT_PUBLIC_WORKOS_REDIRECT_URI="http://localhost:3000/callback"
+
lib/system-prompt.ts (2)

22-22: Compute current date at call time to avoid stale prompts

currentDateTime is computed once at module load. In a long-lived server, this can become stale. Prefer computing within systemPrompt or pass the date/time as a param.

Example adjustment:

export const systemPrompt = (model: string, executionMode?: ExecutionMode) => {
  const currentDateTime = new Date().toLocaleDateString("en-US", {
    weekday: "long",
    year: "numeric",
    month: "long",
    day: "numeric",
  });
  return `... The current date is ${currentDateTime}. ...`;
}

65-86: Sandbox environment block: verify accuracy and make it resilient to drift

Two concerns:

  • Potential mismatch: “User: root” with home “/home/user” is unlikely; root’s home is typically /root.
  • Hard-coded versions and details are prone to drift; the prompt may become misleading over time.

You can either verify and correct the specifics or generalize the language to avoid brittleness. Suggested edit:

 <sandbox_environment>
 System Environment:
-- OS: Debian GNU/Linux 12 linux/amd64 (with internet access)
-- User: `root` (with sudo privileges)
-- Home directory: /home/user
+- OS: Debian GNU/Linux (linux/amd64), with internet access
+- A default user with sudo privileges is available
+- Home directory: the user's home (e.g., /home/user)
 - VPN connectivity is not available due to missing TUN/TAP device support in the sandbox environment
 
 Development Environment:
-- Python 3.12.10 (commands: python3, pip3)
-- Node.js 20.19.2 (commands: node, npm)
-- Golang 1.24.2 (commands: go)
+- Python (commands: python3, pip3)
+- Node.js (commands: node, npm)
+- Golang (commands: go)
 
 Pre-installed Tools:
 - curl, wget, nmap, iputils-ping, whois, traceroute, dnsutils, whatweb, wafw00f, subfinder, gobuster
-- SecLists is pre-installed in /home/user and should be used by default for any fuzzing or wordlist needs
+- SecLists is available under the user's home; use it by default for fuzzing/wordlists (verify exact path with \`ls\`)
 </sandbox_environment>

Additionally, consider adding a brief “local environment” block (for local mode) with guardrails: confirm before destructive actions (delete, chmod, mass search-replace), avoid touching dotfiles and OS directories unless explicitly requested, and prefer operating within the workspace root.

lib/ai/tools/utils/local-terminal.ts (1)

10-10: Unused parameter in interface

The user parameter in LocalTerminalOptions is defined but never used in the implementation.

Either implement user switching functionality or remove the unused parameter:

 export interface LocalTerminalOptions {
   cwd?: string;
-  user?: string;
   onStdout?: (output: string) => void;
   onStderr?: (output: string) => void;
   background?: boolean;
 }
lib/ai/tools/utils/local-file-operations.ts (1)

70-71: Line count calculation may be incorrect for empty files

An empty string will return a line count of 1 when split by newline, which may not be the intended behavior.

Consider handling empty content specially:

-    const lineCount = contents.split("\n").length;
+    const lineCount = contents ? contents.split("\n").length : 0;
README.md (3)

30-34: Add language to fenced code block for env snippet

Markdown lint flagged missing language. Use a language hint for better readability and to appease MD040.

Apply this diff:

-  ```
+  ```bash
     # OpenRouter API key (Required)
     # Get your API key at: https://openrouter.ai/
     OPENROUTER_API_KEY=your_openrouter_api_key_here

---

`38-45`: **Add language to fenced code block for sandbox snippet**

Same MD040 issue here. Add a language hint.



Apply this diff:

```diff
-  ```
+  ```bash
   # Switch to sandbox mode (optional)
   TERMINAL_EXECUTION_MODE=sandbox

   # E2B API key for sandbox execution
   # Get your API key at: https://e2b.dev/
   E2B_API_KEY=your_e2b_api_key_here

---

`36-36`: **Minor grammar: “in a sandbox”**

Improve readability with an article.



Apply this diff:

```diff
-   HackerAI can execute terminal commands locally (default) or in sandbox. For sandbox mode, you'll need an E2B API key:
+   HackerAI can execute terminal commands locally (default) or in a sandbox. For sandbox mode, you'll need an E2B API key:
lib/ai/tools/delete-file.ts (2)

14-25: Input field “explanation” is not used

You accept an explanation but never use it. Either log it (e.g., via the writer) for traceability or drop it from the schema to reduce noise.


18-19: Path semantics: align description with other tools (absolute vs relative)

This tool says “relative to the workspace root,” while read/write allow absolute paths. For consistency, either:

  • Allow absolute paths here as well (and enforce/normalize in local/sandbox modes), or
  • Update read/write descriptions to state relative-only if the underlying APIs don’t accept absolute paths.
lib/ai/tools/index.ts (1)

40-42: Expose new tools in ask-mode only if read-only (currently OK)

ask mode remains read-only (only readFile exposed). That’s consistent with principle of least privilege. If you later want to surface non-destructive utilities (e.g., search-only), ensure you don’t leak write/delete in this mode.

If you want the UI to auto-open after search-replace edits, consider emitting a follow-up readFile (or enhancing the Messages auto-open hook) so users immediately see the updated file.

lib/ai/tools/search-replace.ts (1)

32-33: Typo in schema description: “occurrences”

Minor typo in the input schema description.

Apply:

-        .describe("Replace all occurences of old_string (default false)"),
+        .describe("Replace all occurrences of old_string (default false)"),
lib/ai/tools/run-terminal-cmd.ts (2)

27-37: Make is_background optional with a default

Schema currently requires is_background. Defaulting to false simplifies most calls.

-      is_background: z
-        .boolean()
-        .describe("Whether the command should be run in the background."),
+      is_background: z
+        .boolean()
+        .optional()
+        .default(false)
+        .describe("Whether the command should be run in the background."),

15-27: Minor copy edit in guidance text

“Dont” -> “Don't”

-7. Dont include any newlines in the command.`,
+7. Don't include any newlines in the command.`,
app/hooks/useSidebarAutoOpen.ts (1)

53-65: Optional: support auto-open after search/replace

After a successful search-replace, consider auto-reading and opening the file to show updated content. You could detect tool-searchReplace with a success message and then queue a readFile tool call.

I can draft an enhancement to detect tool-searchReplace and trigger a follow-up readFile for the same path if you want to include it in this PR.

app/components/MessagePartHandler.tsx (8)

6-6: Icon import changes look good; watch for default sizing changes.

Switching to lucide-react defaults (without explicit size classes) can slightly change layout. Please spot-check common breakpoints for any visual regressions.


39-47: Make range computation resilient to falsy values and support offset-only/limit-only cases.

Truthiness checks will fail when offset=0 or limit=0, and offset-only is not represented. Recommend explicit number checks and handling offset-only and limit-only consistently.

Apply this diff:

-    const getFileRange = () => {
-      if (readInput.offset && readInput.limit) {
-        return ` L${readInput.offset}-${readInput.offset + readInput.limit - 1}`;
-      }
-      if (!readInput.offset && readInput.limit) {
-        return ` L1-${readInput.limit}`;
-      }
-      return "";
-    };
+    const getFileRange = () => {
+      const hasOffset = typeof readInput.offset === "number";
+      const hasLimit = typeof readInput.limit === "number";
+      if (hasLimit) {
+        const start = hasOffset ? (readInput.offset as number) : 1;
+        const end = start + (readInput.limit as number) - 1;
+        return ` L${start}-${end}`;
+      }
+      if (hasOffset) {
+        return ` L${readInput.offset}-`;
+      }
+      return "";
+    };

72-88: Align sidebar range with the displayed “Lx-y” label when only limit is provided.

Currently, the sidebar range is only set if both offset and limit are present. If only limit is provided, the label shows L1-limit but the sidebar gets no range. Also harden against falsy 0/undefined values.

Apply this diff:

-        const handleOpenInSidebar = () => {
-          const cleanContent = readOutput.result.replace(/^\s*\d+\|/gm, "");
-          const range =
-            readInput.offset && readInput.limit
-              ? {
-                  start: readInput.offset,
-                  end: readInput.offset + readInput.limit - 1,
-                }
-              : undefined;
+        const handleOpenInSidebar = () => {
+          const cleanContent = readOutput.result.replace(/^\s*\d+\|/gm, "");
+          const hasOffset = typeof readInput.offset === "number";
+          const hasLimit = typeof readInput.limit === "number";
+          const range = hasLimit
+            ? {
+                start: hasOffset ? (readInput.offset as number) : 1,
+                end:
+                  (hasOffset ? (readInput.offset as number) : 1) +
+                  (readInput.limit as number) -
+                  1,
+              }
+            : undefined;

97-107: Add explicit button semantics for accessibility (if ToolBlock doesn’t already).

If ToolBlock doesn’t set role="button" and tabIndex={0} when isClickable, consider adding them to ensure screen-reader and keyboard accessibility.


141-167: Differentiate success vs failure on write and gate clickability accordingly.

Right now, the UI always claims success and allows opening the file. Consider deriving isSuccess from output and adjusting label/clickability. This also avoids opening a non-existent/unchanged file on failure.

Apply this diff:

-      case "output-available":
-        return (
+      case "output-available": {
+        const writeOutput = output as { result?: string; error?: string };
+        const isSuccess =
+          !writeOutput?.error &&
+          /success/i.test(writeOutput?.result ?? ""); // fallback heuristic
+        return (
           <ToolBlock
             key={toolCallId}
-            icon={<FilePlus />}
-            action="Successfully wrote"
+            icon={<FilePlus />}
+            action={isSuccess ? "Successfully wrote" : "Failed to write"}
             target={writeInput.file_path}
-            isClickable={true}
+            isClickable={isSuccess}
             onClick={() => {
-              openFileInSidebar({
-                path: writeInput.file_path,
-                content: writeInput.contents,
-                action: "writing",
-              });
+              if (isSuccess) {
+                openFileInSidebar({
+                  path: writeInput.file_path,
+                  content: writeInput.contents,
+                  action: "writing",
+                });
+              }
             }}
             onKeyDown={(e) => {
               if (e.key === "Enter" || e.key === " ") {
                 e.preventDefault();
-                openFileInSidebar({
-                  path: writeInput.file_path,
-                  content: writeInput.contents,
-                  action: "writing",
-                });
+                if (isSuccess) {
+                  openFileInSidebar({
+                    path: writeInput.file_path,
+                    content: writeInput.contents,
+                    action: "writing",
+                  });
+                }
               }
             }}
           />
         );
+      }

175-178: Unused “explanation” input field.

You parse explanation but don’t display or otherwise use it. Either surface it (tooltip/expanded details) or drop it from the local input type to avoid confusion.


201-209: Make success detection resilient to casing and minor phrasing changes.

String includes with exact casing is brittle. Prefer a case-insensitive regex.

Apply this diff:

-        const isSuccess = deleteOutput.result.includes("Successfully deleted");
+        const isSuccess = /successfully deleted/i.test(deleteOutput.result ?? "");

10-15: Type the “part” parameter to avoid pervasive casts.

part: any forces many unsafe casts. Consider a discriminated union keyed by part.type aligned with lib/ai/tools/types.ts for compile-time safety across input/output shapes and states.

Also applies to: 12-12

📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f2441d6 and 093af6b.

📒 Files selected for processing (21)
  • .env.local.example (1 hunks)
  • README.md (1 hunks)
  • app/api/chat/route.ts (3 hunks)
  • app/components/ComputerSidebar.tsx (1 hunks)
  • app/components/MessagePartHandler.tsx (8 hunks)
  • app/components/Messages.tsx (4 hunks)
  • app/globals.css (1 hunks)
  • app/hooks/useSidebarAutoOpen.ts (1 hunks)
  • app/page.tsx (7 hunks)
  • components/ui/tool-block.tsx (1 hunks)
  • lib/ai/tools/delete-file.ts (1 hunks)
  • lib/ai/tools/execution-types.ts (1 hunks)
  • lib/ai/tools/index.ts (2 hunks)
  • lib/ai/tools/read-file.ts (2 hunks)
  • lib/ai/tools/run-terminal-cmd.ts (2 hunks)
  • lib/ai/tools/search-replace.ts (1 hunks)
  • lib/ai/tools/types.ts (2 hunks)
  • lib/ai/tools/utils/local-file-operations.ts (1 hunks)
  • lib/ai/tools/utils/local-terminal.ts (1 hunks)
  • lib/ai/tools/write-file.ts (2 hunks)
  • lib/system-prompt.ts (4 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (11)
lib/ai/tools/types.ts (1)
lib/ai/tools/execution-types.ts (1)
  • ExecutionMode (1-1)
lib/ai/tools/delete-file.ts (2)
lib/ai/tools/types.ts (1)
  • ToolContext (15-19)
lib/ai/tools/utils/local-file-operations.ts (1)
  • deleteLocalFile (95-121)
app/hooks/useSidebarAutoOpen.ts (2)
types/chat.ts (1)
  • SidebarFile (3-12)
app/contexts/GlobalState.tsx (1)
  • useGlobalState (92-98)
lib/ai/tools/search-replace.ts (2)
lib/ai/tools/types.ts (1)
  • ToolContext (15-19)
lib/ai/tools/utils/local-file-operations.ts (1)
  • searchReplaceLocalFile (123-184)
app/api/chat/route.ts (4)
lib/ai/tools/execution-types.ts (1)
  • ExecutionMode (1-1)
lib/token-utils.ts (1)
  • truncateMessagesToTokenLimit (24-44)
lib/ai/tools/index.ts (1)
  • createTools (13-50)
lib/system-prompt.ts (1)
  • systemPrompt (9-86)
lib/ai/tools/run-terminal-cmd.ts (2)
lib/ai/tools/types.ts (1)
  • ToolContext (15-19)
lib/ai/tools/utils/local-terminal.ts (2)
  • createLocalTerminalHandlers (147-170)
  • executeLocalCommand (23-54)
lib/ai/tools/read-file.ts (2)
lib/ai/tools/types.ts (1)
  • ToolContext (15-19)
lib/ai/tools/utils/local-file-operations.ts (1)
  • readLocalFile (10-57)
app/components/Messages.tsx (1)
app/hooks/useSidebarAutoOpen.ts (1)
  • useSidebarAutoOpen (72-103)
lib/ai/tools/index.ts (6)
lib/ai/tools/execution-types.ts (1)
  • ExecutionMode (1-1)
lib/ai/tools/run-terminal-cmd.ts (1)
  • createRunTerminalCmd (11-106)
lib/ai/tools/read-file.ts (1)
  • createReadFile (6-88)
lib/ai/tools/write-file.ts (1)
  • createWriteFile (6-54)
lib/ai/tools/delete-file.ts (1)
  • createDeleteFile (6-70)
lib/ai/tools/search-replace.ts (1)
  • createSearchReplace (6-117)
lib/ai/tools/write-file.ts (2)
lib/ai/tools/types.ts (1)
  • ToolContext (15-19)
lib/ai/tools/utils/local-file-operations.ts (1)
  • writeLocalFile (59-81)
app/page.tsx (1)
app/components/ComputerSidebar.tsx (1)
  • ComputerSidebar (13-196)
🪛 LanguageTool
README.md

[grammar] ~36-~36: There might be a mistake here.
Context: ... terminal commands locally (default) or in sandbox. For sandbox mode, you'll need ...

(QB_NEW_EN)

🪛 markdownlint-cli2 (0.17.2)
README.md

30-30: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


38-38: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 dotenv-linter (3.3.0)
.env.local.example

[warning] 41-41: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

🔇 Additional comments (25)
lib/ai/tools/execution-types.ts (1)

1-1: Single source of truth for execution mode looks good

The union type is clear and concise. This is a good central type to thread through tools and prompts.

.env.local.example (1)

10-18: Good addition of terminal execution settings with sane defaults

Clear separation of sections and defaulting to local makes onboarding easier. The commented E2B_API_KEY for sandbox mode is a nice touch.

lib/ai/tools/utils/local-file-operations.ts (3)

157-157: Regex special character escaping is correct

The regex escaping implementation properly handles all special regex characters to prevent unintended pattern matching.


163-165: Good user experience design

Excellent error message that provides clear guidance when multiple occurrences are found, helping users understand how to resolve the ambiguity.


33-34: Ignore the off-by-one error suggestion in offset calculation

The implementation correctly treats the caller’s offset as a 1-based line number:

  • lines.slice(offset - 1) converts that 1-based value to a 0-based array index.
  • startLineNumber = offset || 1 ensures numbering also starts at the provided offset (or 1 when undefined).

No changes are needed here.

Likely an incorrect or invalid review comment.

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

18-18: Good design: ExecutionMode integration

The addition of executionMode to ToolContext properly enables tools to adapt their behavior based on the execution environment (local vs sandbox).


7-7: Verified setSandbox Implementation
The DefaultSandboxManager in lib/ai/tools/utils/sandbox-manager.ts (lines 39–42) correctly implements the new setSandbox(sandbox: Sandbox): void method. No further action needed.

app/components/ComputerSidebar.tsx (1)

89-89: Responsive design improvement with custom breakpoint

The change from md: to desktop: breakpoints aligns with the new custom responsive variant defined in the PR. This provides more precise control over the layout transition point.

app/api/chat/route.ts (1)

56-61: Proper propagation of execution mode

The execution mode is correctly passed through to both the tools creation and system prompt, ensuring consistent behavior across the application.

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

21-22: No changes needed: Absolute and relative paths are both supported
Verified via the E2B TypeScript SDK docs that sandbox.files.read/write/remove accept both absolute paths (e.g. '/path/to/file') and relative (workspace-/cwd-relative) paths. The current description (“You can use either a relative path in the workspace or an absolute path.”) is accurate.

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

32-33: Context wiring looks good

Passing executionMode into ToolContext cleanly threads mode to all tools. No concerns.

lib/ai/tools/search-replace.ts (3)

46-55: Local path and error handling are solid

Local execution correctly delegates to the shared helper and returns a uniform result. Good parity with the sandbox path, consistent error shape.


80-85: Escape of old_string and counting matches are correct

The escape before building the global regex prevents special-char pitfalls. Counting via match(regex) ensures accurate replacement stats.


85-95: Single-replacement guard is user-friendly

Returning a guidance message when multiple occurrences exist (without replace_all) is a good UX choice to avoid unintended mass edits.

app/page.tsx (3)

43-57: Clean reset mechanism for sidebar auto-open

Using a ref the child fills to reset the auto-open guard is a neat, low-friction pattern. The reset on new submissions is well-timed.


188-191: Mobile overlay gating aligns with desktop breakpoint

Switch from md:hidden to desktop:hidden matches the new breakpoint semantics. LGTM.


118-125: Messages correctly wires resetSidebarAutoOpen
Verified that in app/components/Messages.tsx, a useEffect runs on mount and whenever resetSidebarFlag (or the ref itself) changes, assigning resetSidebarOpen.current = resetSidebarFlag. No further changes are needed here.

app/hooks/useSidebarAutoOpen.ts (3)

26-51: Good detection of actionable tool outputs (read/write)

  • Stripping ^\s*\d+\| handles line-numbered content from sandbox reads without affecting local mode.
  • Returning an explicit action (“reading”/“writing”) provides nice context for the sidebar.

91-95: Desktop gating matches page/layout behavior

Using matchMedia for min-width 950px aligns with the new “desktop” breakpoint. Good consistency with the page styles.


37-41: Range semantics are correct

The read-file tool uses 1-based indexing (it slices at offset – 1 and numbers lines starting from the provided offset), so computing range as

{ start: offset, end: offset + limit - 1 }

accurately reflects the first and last line returned. No changes required.

app/components/MessagePartHandler.tsx (5)

54-57: LGTM on read-file tool icon and interaction updates.

Using FileText, shimmer states during streaming, and click/keyboard open-in-sidebar affordances read clearly and are consistent.

Also applies to: 62-67, 100-106


126-129: LGTM on write-file tool visual states.

Switch to FilePlus and shimmer during “Creating/Writing to” reads well.

Also applies to: 135-139


218-247: LGTM on search/replace tool states.

Shimmering “Editing file”, clear “Editing” vs “Replacing all in” labels, and the FilePen icon all make sense.


332-337: LGTM on wiring new tool types into the main switch.

New cases are correctly routed to their renderers.


39-47: All read-file offset semantics and search-replace messaging verified—no changes required

Offset is confirmed to be 1-based and limit-only reads start at line 1, matching both the tool implementation and the getFileRange labels. The search-replace tool indeed emits “Successfully made …”, so the existing logic is correct.

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