Skip to content

Vercel Sandbox Integration#640

Open
ngoiyaeric wants to merge 1 commit into
mainfrom
feature/vercel-sandbox-integration-4831652204283404284
Open

Vercel Sandbox Integration#640
ngoiyaeric wants to merge 1 commit into
mainfrom
feature/vercel-sandbox-integration-4831652204283404284

Conversation

@ngoiyaeric
Copy link
Copy Markdown
Collaborator

This PR integrates Vercel Sandbox into QCX, enabling the AI to execute JavaScript and TypeScript code in isolated microVMs.

Key features:

  • Sandbox Tool: A new tool that allows the AI to run code, install npm dependencies, and host web servers.
  • Log Streaming: Real-time streaming of stdout and stderr from the sandbox to the chat UI.
  • Live Previews: Automatically detects web servers and provides a public preview URL rendered in an iframe.
  • UI Components: Terminal-like log viewer and security-conscious iframe container for previews.
  • Agent Integration: Updated the researcher's system prompt to use the sandbox for data transformations and visualization.

Infrastructure:

  • Added @vercel/sandbox package.
  • Defined Zod schemas and TypeScript types for sandbox operations.
  • Added Vercel credentials to .env.example.
  • Updated app/actions.tsx to handle sandbox tool results in history.

PR created automatically by Jules for task 4831652204283404284 started by @ngoiyaeric

- Add @vercel/sandbox dependency and types
- Implement `sandbox` tool with support for JS/TS and live previews
- Create UI components for streaming logs and iframe previews
- Update researcher agent with code execution capabilities
- Handle tool result reconstruction in message history

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
@google-labs-jules
Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Jun 1, 2026

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

Project Deployment Actions Updated (UTC)
qcx Ready Ready Preview, Comment Jun 1, 2026 3:42pm

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

Warning

Review limit reached

@ngoiyaeric, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 5 minutes and 42 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

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.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ed67760f-2a2e-49b4-952d-68a862bb2f6d

📥 Commits

Reviewing files that changed from the base of the PR and between b110b93 and 58859ab.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • .env.local.example
  • app/actions.tsx
  • components/sandbox-logs.tsx
  • components/sandbox-preview.tsx
  • components/sandbox-section.tsx
  • components/section.tsx
  • lib/agents/researcher.tsx
  • lib/agents/tools/index.tsx
  • lib/agents/tools/sandbox.tsx
  • lib/schema/sandbox.ts
  • lib/types/index.ts
  • package.json
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/vercel-sandbox-integration-4831652204283404284

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 and usage tips.

@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Integrate Vercel Sandbox for code execution and live previews

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Integrates Vercel Sandbox for isolated JavaScript/TypeScript code execution
• Adds real-time log streaming and live preview capabilities for web servers
• Creates UI components for terminal-like log viewer and iframe previews
• Updates researcher agent to support code execution and data transformation
• Adds sandbox tool configuration and environment variables
Diagram
flowchart LR
  A["Researcher Agent"] -->|uses sandbox tool| B["Sandbox Tool"]
  B -->|executes code| C["Vercel Sandbox MicroVM"]
  C -->|streams logs| D["SandboxSection Component"]
  D -->|displays| E["SandboxLogs"]
  C -->|detects server| F["SandboxPreview Component"]
  F -->|renders| G["Live Preview iframe"]

Loading

Grey Divider

File Changes

1. lib/schema/sandbox.ts ⚙️ Configuration changes +30/-0

Define Zod schema for sandbox parameters

lib/schema/sandbox.ts


2. lib/types/index.ts ✨ Enhancement +8/-0

Add SandboxResult type to AIMessage

lib/types/index.ts


3. .env.local.example ⚙️ Configuration changes +6/-0

Add Vercel Sandbox environment variables

.env.local.example


View more (9)
4. app/actions.tsx ✨ Enhancement +17/-0

Handle sandbox tool results in UI state

app/actions.tsx


5. components/sandbox-logs.tsx ✨ Enhancement +52/-0

Create terminal-like log viewer component

components/sandbox-logs.tsx


6. components/sandbox-preview.tsx ✨ Enhancement +51/-0

Create iframe preview component with controls

components/sandbox-preview.tsx


7. components/sandbox-section.tsx ✨ Enhancement +51/-0

Create main sandbox section container component

components/sandbox-section.tsx


8. components/section.tsx ✨ Enhancement +6/-1

Add Terminal icon for Sandbox section

components/section.tsx


9. lib/agents/researcher.tsx 📝 Documentation +11/-4

Update researcher prompt with sandbox tool guidance

lib/agents/researcher.tsx


10. lib/agents/tools/index.tsx ✨ Enhancement +8/-0

Register sandbox tool with environment checks

lib/agents/tools/index.tsx


11. lib/agents/tools/sandbox.tsx ✨ Enhancement +127/-0

Implement sandbox tool with execution and streaming

lib/agents/tools/sandbox.tsx


12. package.json Dependencies +1/-0

Add @vercel/sandbox dependency

package.json


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented Jun 1, 2026

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (0)

Grey Divider


Action required

1. Npm install injection 🐞 Bug ⛨ Security
Description
sandboxTool builds an npm install ... command by string-concatenating dependencies, allowing
command injection in the microVM (extra commands beyond npm). This breaks the tool’s security
boundary and can be used to run arbitrary unintended commands during the install step.
Code

lib/agents/tools/sandbox.tsx[R37-43]

Evidence
The tool passes a template string to runCommand with unescaped, user-controlled dependencies,
which is the classic command-injection pattern.

lib/agents/tools/sandbox.tsx[37-43]
lib/schema/sandbox.ts[8-20]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`sandboxTool` constructs `npm install` as a single shell string using `dependencies.join(' ')`, which enables command injection if any dependency string includes shell metacharacters.

### Issue Context
The tool parameter schema allows arbitrary strings in `dependencies`, and the tool executes them inside the sandbox via `runCommand`.

### Fix Focus Areas
- Replace string command with structured args (no shell parsing).
- Validate/whitelist dependency names (e.g., npm package name grammar) and reject anything else.

### Fix Focus Areas (code locations)
- lib/agents/tools/sandbox.tsx[37-44]
- lib/schema/sandbox.ts[8-20]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Sandbox never stopped 🐞 Bug ☼ Reliability
Description
When isServer is true, the tool detaches the process and returns without ever calling
sandbox.stop(), leaving microVMs running and consuming resources. The /http|express|.../
heuristic is broad enough to misclassify non-server code, increasing the frequency of this leak.
Code

lib/agents/tools/sandbox.tsx[R46-97]

Evidence
The code only calls sandbox.stop() in the non-server branch, while the server branch detaches and
returns immediately; isServer is determined by a broad regex over the code string.

lib/agents/tools/sandbox.tsx[46-97]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
In the server/detached execution path, the sandbox is never stopped, so microVMs can remain alive after the tool returns.

### Issue Context
`sandbox.stop()` is only called in the non-server branch. Server mode is triggered by a regex against the source code, which can produce false positives.

### Fix Focus Areas
- Ensure `sandbox.stop()` is invoked for server runs (e.g., via a `finally` block) or implement a controlled lifecycle/TTL shutdown strategy.
- Avoid heuristic server detection: add an explicit `mode`/`isServer` parameter or detect actual listening port readiness.
- Avoid unhandled background async failures (use `void streamLogs().catch(...)`).

### Fix Focus Areas (code locations)
- lib/agents/tools/sandbox.tsx[46-97]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. TypeScript runner missing 🐞 Bug ≡ Correctness
Description
TypeScript execution uses cmd = 'tsx' but the tool never installs tsx, so a TypeScript run will
fail unless the caller knows to include tsx in dependencies. This makes the advertised
TypeScript support unreliable by default.
Code

lib/agents/tools/sandbox.tsx[R46-53]

Evidence
The code picks tsx when language is typescript, but the install step only installs
user-specified dependencies and does not add tsx automatically, so tsx may be missing at
runtime.

lib/agents/tools/sandbox.tsx[37-53]
lib/schema/sandbox.ts[8-20]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The tool selects `tsx` as the command for TypeScript, but does not guarantee `tsx` exists in the sandbox environment.

### Issue Context
The tool only runs `npm install` when `dependencies` are provided, and it does not add any implicit dependencies based on the selected `language`.

### Fix Focus Areas
- If `language === 'typescript'`, install `tsx` (and typically `typescript`/`@types/node`) automatically before execution.
- Or run through `npx`/a pinned package runner with explicit args.

### Fix Focus Areas (code locations)
- lib/agents/tools/sandbox.tsx[37-53]
- lib/schema/sandbox.ts[8-20]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Server logs not saved 🐞 Bug ☼ Reliability
Description
For server executions, streamLogs() runs asynchronously but the tool returns immediately, so the
persisted tool message stores only the initial snapshot of logs at return time. After a
refresh/rehydration, getUIStateFromAIState will render incomplete/empty logs even if the user saw
more logs streamed live.
Code

lib/agents/tools/sandbox.tsx[R68-97]

Evidence
The sandbox tool returns before the async log-streaming finishes, but the app persists tool results
immediately via JSON.stringify, freezing whatever the logs array contained at return time.

lib/agents/tools/sandbox.tsx[68-97]
app/actions.tsx[478-493]
app/actions.tsx[788-859]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
In server mode, logs are streamed after the tool returns, but the app persists tool output immediately; this loses later log entries in saved chat state.

### Issue Context
`app/actions.tsx` saves tool outputs by `JSON.stringify(output.result)` when the tool returns. In server mode the returned object includes `logs` before streaming completes.

### Fix Focus Areas
- Delay returning until you have captured a meaningful initial log set (or until server readiness), then return that snapshot.
- Alternatively, write logs to a durable store keyed by run ID and persist only the run ID in AI state; hydrate logs from storage on reload.

### Fix Focus Areas (code locations)
- lib/agents/tools/sandbox.tsx[68-97]
- app/actions.tsx[478-493]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +37 to +43
if (dependencies && dependencies.length > 0) {
const installCommand = await sandbox.runCommand(`npm install ${dependencies.join(' ')}`)
for await (const log of installCommand.logs()) {
const logEntry = { type: log.stream as 'stdout' | 'stderr', content: log.data }
logs.push(logEntry)
streamableLogs.update([...logs])
}
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.

Action required

1. Npm install injection 🐞 Bug ⛨ Security

sandboxTool builds an npm install ... command by string-concatenating dependencies, allowing
command injection in the microVM (extra commands beyond npm). This breaks the tool’s security
boundary and can be used to run arbitrary unintended commands during the install step.
Agent Prompt
### Issue description
`sandboxTool` constructs `npm install` as a single shell string using `dependencies.join(' ')`, which enables command injection if any dependency string includes shell metacharacters.

### Issue Context
The tool parameter schema allows arbitrary strings in `dependencies`, and the tool executes them inside the sandbox via `runCommand`.

### Fix Focus Areas
- Replace string command with structured args (no shell parsing).
- Validate/whitelist dependency names (e.g., npm package name grammar) and reject anything else.

### Fix Focus Areas (code locations)
- lib/agents/tools/sandbox.tsx[37-44]
- lib/schema/sandbox.ts[8-20]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +46 to +97
const isServer = /http|express|serve|listen|app\.get|app\.post|createServer/.test(code)
const cmd = language === 'typescript' ? 'tsx' : 'node'

const command = await sandbox.runCommand({
cmd,
args: [filename],
detached: isServer
})

let previewUrl: string | undefined
if (isServer) {
previewUrl = await sandbox.domain(3000)
// Update UI with preview URL
uiStream.update(
<SandboxSection
key={nanoid()}
logs={streamableLogs.value}
previewUrl={previewUrl}
/>
)
}

const streamLogs = async () => {
for await (const log of command.logs()) {
const logEntry = { type: log.stream as 'stdout' | 'stderr', content: log.data }
logs.push(logEntry)
streamableLogs.update([...logs])
}
streamableLogs.done(logs)
}

if (isServer) {
// For servers, stream logs in the background and return immediately
streamLogs()
} else {
// For regular scripts, wait for execution to complete
await streamLogs()
const result = await (command as any).wait()
await sandbox.stop()
return {
logs,
exitCode: result.exitCode,
type: 'sandbox_result'
}
}

return {
logs,
exitCode: 0,
previewUrl,
type: 'sandbox_result'
}
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.

Action required

2. Sandbox never stopped 🐞 Bug ☼ Reliability

When isServer is true, the tool detaches the process and returns without ever calling
sandbox.stop(), leaving microVMs running and consuming resources. The /http|express|.../
heuristic is broad enough to misclassify non-server code, increasing the frequency of this leak.
Agent Prompt
### Issue description
In the server/detached execution path, the sandbox is never stopped, so microVMs can remain alive after the tool returns.

### Issue Context
`sandbox.stop()` is only called in the non-server branch. Server mode is triggered by a regex against the source code, which can produce false positives.

### Fix Focus Areas
- Ensure `sandbox.stop()` is invoked for server runs (e.g., via a `finally` block) or implement a controlled lifecycle/TTL shutdown strategy.
- Avoid heuristic server detection: add an explicit `mode`/`isServer` parameter or detect actual listening port readiness.
- Avoid unhandled background async failures (use `void streamLogs().catch(...)`).

### Fix Focus Areas (code locations)
- lib/agents/tools/sandbox.tsx[46-97]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +46 to +53
const isServer = /http|express|serve|listen|app\.get|app\.post|createServer/.test(code)
const cmd = language === 'typescript' ? 'tsx' : 'node'

const command = await sandbox.runCommand({
cmd,
args: [filename],
detached: isServer
})
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.

Action required

3. Typescript runner missing 🐞 Bug ≡ Correctness

TypeScript execution uses cmd = 'tsx' but the tool never installs tsx, so a TypeScript run will
fail unless the caller knows to include tsx in dependencies. This makes the advertised
TypeScript support unreliable by default.
Agent Prompt
### Issue description
The tool selects `tsx` as the command for TypeScript, but does not guarantee `tsx` exists in the sandbox environment.

### Issue Context
The tool only runs `npm install` when `dependencies` are provided, and it does not add any implicit dependencies based on the selected `language`.

### Fix Focus Areas
- If `language === 'typescript'`, install `tsx` (and typically `typescript`/`@types/node`) automatically before execution.
- Or run through `npx`/a pinned package runner with explicit args.

### Fix Focus Areas (code locations)
- lib/agents/tools/sandbox.tsx[37-53]
- lib/schema/sandbox.ts[8-20]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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