Skip to content

feat: make command parameter optional for POST /api/sandboxes - #204

Closed
sweetmantech wants to merge 1 commit into
testfrom
sweetmantech/myc-4138-docs-post-apisandboxes-commands-optional-to-simply-create-a
Closed

feat: make command parameter optional for POST /api/sandboxes#204
sweetmantech wants to merge 1 commit into
testfrom
sweetmantech/myc-4138-docs-post-apisandboxes-commands-optional-to-simply-create-a

Conversation

@sweetmantech

@sweetmantechsweetmantech commented Feb 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Make the command parameter optional in POST /api/sandboxes
  • When command is omitted, sandbox is created without triggering the run-sandbox-command task
  • The runId field is only included in the response when a command was provided

Test plan

  • Call POST /api/sandboxes without command - verify sandbox is created, no runId returned
  • Call POST /api/sandboxes with command - verify sandbox is created with runId
  • Verify no regression in existing functionality

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Command parameter is now optional when creating sandboxes; you can create a sandbox without executing a command initially, enabling more flexible initialization workflows.

Allow creating a sandbox without providing a command, which skips
triggering the run-sandbox-command task. This enables users to simply
create a sandbox environment without executing any commands.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel

vercelBot commented Feb 4, 2026

Copy link
Copy Markdown
Contributor

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

ProjectDeploymentActionsUpdated (UTC)
recoup-apiReadyReadyPreviewFeb 4, 2026 3:04pm

@coderabbitai

coderabbitaiBot commented Feb 4, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The changes make the command field optional when creating sandboxes, allowing sandbox creation without immediately executing a command. The API documentation, request validation schema, and handler logic are updated to reflect this new behavior, with runId only returned when a command is provided.

Changes

Cohort / File(s)Summary
API Documentation & Response Schema
app/api/sandboxes/route.ts
Updated POST /api/sandboxes documentation to indicate command is optional. Made runId optional in response schema and clarified it only appears when a command was provided.
Request Validation
lib/sandbox/validateSandboxBody.ts
Changed command field from required to optional while maintaining minimum length validation (.min(1)) when present.
Execution Handler
lib/sandbox/createSandboxPostHandler.ts
Updated handler to conditionally trigger run-sandbox-command task only when command is provided; sandbox is created regardless, but runId is only captured and returned when command execution occurs.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • Recoupable-com/Recoup-API#195: Modifies the same sandbox creation flow including route, request schema, and handler logic for conditional command execution and runId handling.

Poem

🏗️ Sandboxes now waltz with newfound grace,
Commands become optional in this flexible space,
Create without rushing, let tasks unfold slow,
Run when you're ready, or let them just flow,
Conditional whispers of code made more kind! ✨

🚥 Pre-merge checks | ❌ 1
❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Solid & Clean Code⚠️ WarningError handling violates SRP by conflating 'no command' and 'command failed' into identical responses, hiding execution failures from clients.Return explicit 502 error response when triggerRunSandboxCommand fails to distinguish command failures from missing commands.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sweetmantech/myc-4138-docs-post-apisandboxes-commands-optional-to-simply-create-a

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.

@github-actions

github-actionsBot commented Feb 4, 2026

Copy link
Copy Markdown

Braintrust eval report

Catalog Opportunity Analysis Evaluation (HEAD-1770217418)

ScoreAverageImprovementsRegressions
Catalog_availability41% (+1pp)1 🟢-
Llm_calls0 (+0)--
Tool_calls0 (+0)--
Errors0 (+0)--
Llm_errors0 (+0)--
Tool_errors0 (+0)--
Prompt_tokens0tok (+0tok)--
Prompt_cached_tokens0tok (+0tok)--
Prompt_cache_creation_tokens0tok (+0tok)--
Completion_tokens0tok (+0tok)--
Completion_reasoning_tokens0tok (+0tok)--
Total_tokens0tok (+0tok)--
Duration33.19s (-1.9s)4 🟢1 🔴

Catalog Songs Count Evaluation (HEAD-1770217418)

ScoreAverageImprovementsRegressions
Llm_calls4 (+0)--
Tool_calls0 (+0)--
Errors3 (+0)--
Llm_errors1 (+0)--
Tool_errors0 (+0)--
Prompt_tokens0tok (+0tok)--
Prompt_cached_tokens0tok (+0tok)--
Prompt_cache_creation_tokens0tok (+0tok)--
Completion_tokens0tok (+0tok)--
Completion_reasoning_tokens0tok (+0tok)--
Total_tokens0tok (+0tok)--
Duration10.65s (-5.99s)3 🟢-

First Week Album Sales Evaluation (HEAD-1770217418)

ScoreAverageImprovementsRegressions
Llm_calls1 (+0)--
Tool_calls0 (+0)--
Errors1 (+0)--
Llm_errors0 (+0)--
Tool_errors0 (+0)--
Prompt_tokens0tok (+0tok)--
Prompt_cached_tokens0tok (+0tok)--
Prompt_cache_creation_tokens0tok (+0tok)--
Completion_tokens0tok (+0tok)--
Completion_reasoning_tokens0tok (+0tok)--
Total_tokens0tok (+0tok)--
Duration13.74s (-1.92s)3 🟢1 🔴

Memory & Storage Tools Evaluation (HEAD-1770217418)

ScoreAverageImprovementsRegressions
Tools_called0% (+0pp)--
Llm_calls0 (+0)--
Tool_calls0 (+0)--
Errors0 (+0)--
Llm_errors0 (+0)--
Tool_errors0 (+0)--
Prompt_tokens0tok (+0tok)--
Prompt_cached_tokens0tok (+0tok)--
Prompt_cache_creation_tokens0tok (+0tok)--
Completion_tokens0tok (+0tok)--
Completion_reasoning_tokens0tok (+0tok)--
Total_tokens0tok (+0tok)--
Duration17.84s (-42.22s)1 🟢-

Monthly Listeners Tracking Evaluation (HEAD-1770217418)

ScoreAverageImprovementsRegressions
Llm_calls2 (+0)--
Tool_calls0 (+0)--
Errors2 (+0)--
Llm_errors1 (+0)--
Tool_errors0 (+0)--
Prompt_tokens0tok (+0tok)--
Prompt_cached_tokens0tok (+0tok)--
Prompt_cache_creation_tokens0tok (+0tok)--
Completion_tokens0tok (+0tok)--
Completion_reasoning_tokens0tok (+0tok)--
Total_tokens0tok (+0tok)--
Duration11.56s (-1.51s)3 🟢2 🔴

Search Web Tool Evaluation (HEAD-1770217418)

ScoreAverageImprovementsRegressions
Llm_calls2.73 (-0.27)-1 🔴
Tool_calls0 (+0)--
Errors1.82 (-0.18)1 🟢-
Llm_errors0.91 (-0.09)1 🟢-
Tool_errors0 (+0)--
Prompt_tokens0tok (+0tok)--
Prompt_cached_tokens0tok (+0tok)--
Prompt_cache_creation_tokens0tok (+0tok)--
Completion_tokens0tok (+0tok)--
Completion_reasoning_tokens0tok (+0tok)--
Total_tokens0tok (+0tok)--
Duration21.6s (-3.25s)7 🟢3 🔴

Social Scraping Evaluation (HEAD-1770217418)

ScoreAverageImprovementsRegressions
Tools_called0% (+0pp)--
Llm_calls0 (+0)--
Tool_calls0 (+0)--
Errors0 (+0)--
Llm_errors0 (+0)--
Tool_errors0 (+0)--
Prompt_tokens0tok (+0tok)--
Prompt_cached_tokens0tok (+0tok)--
Prompt_cache_creation_tokens0tok (+0tok)--
Completion_tokens0tok (+0tok)--
Completion_reasoning_tokens0tok (+0tok)--
Total_tokens0tok (+0tok)--
Duration30.63s (+3.39s)2 🟢4 🔴

Spotify Followers Evaluation (HEAD-1770217418)

ScoreAverageImprovementsRegressions
Llm_calls3 (+0)--
Tool_calls0 (+0)--
Errors3 (+0)--
Llm_errors2 (+0)--
Tool_errors0 (+0)--
Prompt_tokens0tok (+0tok)--
Prompt_cached_tokens0tok (+0tok)--
Prompt_cache_creation_tokens0tok (+0tok)--
Completion_tokens0tok (+0tok)--
Completion_reasoning_tokens0tok (+0tok)--
Total_tokens0tok (+0tok)--
Duration15.21s (+0.09s)2 🟢3 🔴

Spotify Tools Evaluation (HEAD-1770217418)

ScoreAverageImprovementsRegressions
Llm_calls0 (+0)--
Tool_calls0 (+0)--
Errors0 (+0)--
Llm_errors0 (+0)--
Tool_errors0 (+0)--
Prompt_tokens0tok (+0tok)--
Prompt_cached_tokens0tok (+0tok)--
Prompt_cache_creation_tokens0tok (+0tok)--
Completion_tokens0tok (+0tok)--
Completion_reasoning_tokens0tok (+0tok)--
Total_tokens0tok (+0tok)--

TikTok Analytics Questions Evaluation (HEAD-1770217418)

ScoreAverageImprovementsRegressions
Question_answered0% (+0pp)--
Llm_calls0 (+0)--
Tool_calls0 (+0)--
Errors0 (+0)--
Llm_errors0 (+0)--
Tool_errors0 (+0)--
Prompt_tokens0tok (+0tok)--
Prompt_cached_tokens0tok (+0tok)--
Prompt_cache_creation_tokens0tok (+0tok)--
Completion_tokens0tok (+0tok)--
Completion_reasoning_tokens0tok (+0tok)--
Total_tokens0tok (+0tok)--
Duration13.42s (-1.05s)1 🟢1 🔴

@coderabbitaicoderabbitaiBot 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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@lib/sandbox/createSandboxPostHandler.ts`:
- Around line 43-57: The current catch in createSandboxPostHandler swallows
triggerRunSandboxCommand failures, making a missing runId indistinguishable from
"no command provided"; change the catch in the block that calls
triggerRunSandboxCommand to propagate a proper error response instead of just
logging: when triggerRunSandboxCommand({ command: validated.command, args:
validated.args, cwd: validated.cwd, sandboxId: result.sandboxId, accountId:
validated.accountId }) throws, rethrow or return a 4xx/5xx error (include the
original error message) so the handler returns failure to the client rather than
a success without runId; update any callers/response flow that rely on runId
accordingly.
🧹 Nitpick comments (1)
lib/sandbox/validateSandboxBody.ts (1)

8-10: Harden command validation against whitespace-only values.

min(1) still allows " ". Consider trimming before validation to avoid “empty but non-empty” commands.

♻️ Suggested change
- command: z.string().min(1, "command cannot be empty").optional(),+ command: z.string().trim().min(1, "command cannot be empty").optional(),

Comment on lines +43 to +57
// Trigger the command execution task only if a command was provided
let runId: string | undefined;
try {
const handle = await triggerRunSandboxCommand({
command: validated.command,
args: validated.args,
cwd: validated.cwd,
sandboxId: result.sandboxId,
accountId: validated.accountId,
});
runId = handle.id;
} catch (triggerError) {
console.error("Failed to trigger run-sandbox-command task:", triggerError);
if (validated.command) {
try {
const handle = await triggerRunSandboxCommand({
command: validated.command,
args: validated.args,
cwd: validated.cwd,
sandboxId: result.sandboxId,
accountId: validated.accountId,
});
runId = handle.id;
} catch (triggerError) {
console.error("Failed to trigger run-sandbox-command task:", triggerError);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Return an error when a requested command fails to trigger.

Right now a client can send command and still get a success response without runId if the trigger fails. That’s indistinguishable from “no command provided” and hides execution failures.

🐛 Suggested change
 if (validated.command) {
try {
const handle = await triggerRunSandboxCommand({
command: validated.command,
args: validated.args,
cwd: validated.cwd,
sandboxId: result.sandboxId,
accountId: validated.accountId,
});
runId = handle.id;
} catch (triggerError) {
console.error("Failed to trigger run-sandbox-command task:", triggerError);
+ return NextResponse.json(+ { status: "error", error: "Failed to run command in sandbox" },+ { status: 502, headers: getCorsHeaders() },+ );
}
}
🤖 Prompt for AI Agents
In `@lib/sandbox/createSandboxPostHandler.ts` around lines 43 - 57, The current
catch in createSandboxPostHandler swallows triggerRunSandboxCommand failures,
making a missing runId indistinguishable from "no command provided"; change the
catch in the block that calls triggerRunSandboxCommand to propagate a proper
error response instead of just logging: when triggerRunSandboxCommand({ command:
validated.command, args: validated.args, cwd: validated.cwd, sandboxId:
result.sandboxId, accountId: validated.accountId }) throws, rethrow or return a
4xx/5xx error (include the original error message) so the handler returns
failure to the client rather than a success without runId; update any
callers/response flow that rely on runId accordingly.

Sign up for freeto 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

@sweetmantech