Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/vibe-coding-platform/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).

This project integrates [Workflow DevKit](https://useworkflow.dev/) to support a durable and reliable AI agent with automatic retries and state management.

## Getting Started

First, run the development server:
Expand Down
2 changes: 2 additions & 0 deletions apps/vibe-coding-platform/ai/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { type GatewayModelId } from '@ai-sdk/gateway'
export enum Models {
AmazonNovaPro = 'amazon/nova-pro',
AnthropicClaude4Sonnet = 'anthropic/claude-4-sonnet',
AnthropicClaude45Haiku = 'anthropic/claude-haiku-4.5',
Copy link
Member Author

Choose a reason for hiding this comment

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

Added Haiku while I was at it

AnthropicClaude45Sonnet = 'anthropic/claude-sonnet-4.5',
GoogleGeminiFlash = 'google/gemini-2.5-flash',
MoonshotKimiK2 = 'moonshotai/kimi-k2',
Expand All @@ -15,6 +16,7 @@ export const DEFAULT_MODEL = Models.AnthropicClaude45Sonnet
export const SUPPORTED_MODELS: GatewayModelId[] = [
Models.AmazonNovaPro,
Models.AnthropicClaude4Sonnet,
Models.AnthropicClaude45Haiku,
Models.AnthropicClaude45Sonnet,
Models.GoogleGeminiFlash,
Models.MoonshotKimiK2,
Expand Down
3 changes: 2 additions & 1 deletion apps/vibe-coding-platform/ai/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ export function getModelOptions(

if (
modelId === Models.AnthropicClaude4Sonnet ||
modelId === Models.AnthropicClaude45Sonnet
modelId === Models.AnthropicClaude45Sonnet ||
modelId === Models.AnthropicClaude45Haiku
) {
return {
model: gateway(modelId),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Use this tool to create a new Vercel Sandbox — an ephemeral, isolated Linux container that serves as your development environment for the current session. This sandbox provides a secure workspace where you can upload files, install dependencies, run commands, start development servers, and preview web apps. Each sandbox is uniquely identified and must be referenced for all subsequent operations (e.g., file generation, command execution, or URL access).
export default `Use this tool to create a new Vercel Sandbox — an ephemeral, isolated Linux container that serves as your development environment for the current session. This sandbox provides a secure workspace where you can upload files, install dependencies, run commands, start development servers, and preview web apps. Each sandbox is uniquely identified and must be referenced for all subsequent operations (e.g., file generation, command execution, or URL access).
Copy link
Member Author

Choose a reason for hiding this comment

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

Markdown files aren't supported by workflow compiler plugin, so we had to rename all of the prompts to typescript files


## When to Use This Tool

Expand All @@ -13,17 +13,17 @@ Use this tool **once per session** when:

After creation, the sandbox allows you to:

- Upload and manage files via `Generate Files`
- Execute shell commands with `Run Command` and `Wait Command`
- Access running servers through public URLs using `Get Sandbox URL`
- Upload and manage files via \`Generate Files\`
- Execute shell commands with \`Run Command\` and \`Wait Command\`
- Access running servers through public URLs using \`Get Sandbox URL\`

Each sandbox mimics a real-world development environment and supports rapid iteration and testing without polluting the local system. The base system is Amazon Linux 2023 with the following additional packages:

```
\`\`\`
bind-utils bzip2 findutils git gzip iputils libicu libjpeg libpng ncurses-libs openssl openssl-libs pnpm procps tar unzip which whois zstd
```
\`\`\`

You can install additional packages using the `dnf` package manager. You can NEVER use port 8080 as it is reserved for internal applications. When requested, you need to use a different port.
You can install additional packages using the \`dnf\` package manager. You can NEVER use port 8080 as it is reserved for internal applications. When requested, you need to use a different port.

## Best Practices

Expand All @@ -36,7 +36,7 @@ You can install additional packages using the `dnf` package manager. You can NEV

<example>
User: Can we start fresh? I want to rebuild the project from scratch.
Assistant: Got it — Ill create a new sandbox so we can start clean.
Assistant: Got it — I'll create a new sandbox so we can start clean.
*Calls Create Sandbox*
</example>

Expand All @@ -48,8 +48,9 @@ Skip using this tool when:
2. You only need to upload files (use Generate Files)
3. You want to execute or wait for a command (use Run Command / Wait Command)
4. You want to preview the application (use Get Sandbox URL)
5. The user hasnt asked to reset the environment
5. The user hasn't asked to reset the environment

## Summary

Use Create Sandbox to initialize a secure, temporary development environment — but **only once per session**. Treat the sandbox as the core workspace for all follow-up actions unless the user explicitly asks to discard and start anew.
`
132 changes: 70 additions & 62 deletions apps/vibe-coding-platform/ai/tools/create-sandbox.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,83 @@
import type { UIMessageStreamWriter, UIMessage } from 'ai'
import type { UIMessageChunk } from 'ai'
import type { DataPart } from '../messages/data-parts'
import { Sandbox } from '@vercel/sandbox'
import { getRichError } from './get-rich-error'
import { tool } from 'ai'
import description from './create-sandbox.md'
import description from './create-sandbox.prompt'
import z from 'zod/v3'
import { getWritable } from 'workflow'

interface Params {
writer: UIMessageStreamWriter<UIMessage<never, DataPart>>
}
const inputSchema = z.object({
timeout: z
.number()
.min(600000)
.max(2700000)
.optional()
.describe(
'Maximum time in milliseconds the Vercel Sandbox will remain active before automatically shutting down. Minimum 600000ms (10 minutes), maximum 2700000ms (45 minutes). Defaults to 600000ms (10 minutes). The sandbox will terminate all running processes when this timeout is reached.'
),
ports: z
.array(z.number())
.max(2)
.optional()
.describe(
'Array of network ports to expose and make accessible from outside the Vercel Sandbox. These ports allow web servers, APIs, or other services running inside the Vercel Sandbox to be reached externally. Common ports include 3000 (Next.js), 8000 (Python servers), 5000 (Flask), etc.'
),
})

export const createSandbox = ({ writer }: Params) =>
tool({
description,
inputSchema: z.object({
timeout: z
.number()
.min(600000)
.max(2700000)
.optional()
.describe(
'Maximum time in milliseconds the Vercel Sandbox will remain active before automatically shutting down. Minimum 600000ms (10 minutes), maximum 2700000ms (45 minutes). Defaults to 600000ms (10 minutes). The sandbox will terminate all running processes when this timeout is reached.'
),
ports: z
.array(z.number())
.max(2)
.optional()
.describe(
'Array of network ports to expose and make accessible from outside the Vercel Sandbox. These ports allow web servers, APIs, or other services running inside the Vercel Sandbox to be reached externally. Common ports include 3000 (Next.js), 8000 (Python servers), 5000 (Flask), etc.'
),
}),
execute: async ({ timeout, ports }, { toolCallId }) => {
writer.write({
id: toolCallId,
type: 'data-create-sandbox',
data: { status: 'loading' },
})
async function executeCreateSandbox(
{ timeout, ports }: z.infer<typeof inputSchema>,
{ toolCallId }: { toolCallId: string }
) {
'use step'

const writeable = getWritable<UIMessageChunk<never, DataPart>>()
const writer = writeable.getWriter()
writer.write({
id: toolCallId,
type: 'data-create-sandbox',
data: { status: 'loading' },
})

try {
const sandbox = await Sandbox.create({
timeout: timeout ?? 600000,
ports,
})
try {
const sandbox = await Sandbox.create({
timeout: timeout ?? 600000,
ports,
})

writer.write({
id: toolCallId,
type: 'data-create-sandbox',
data: { sandboxId: sandbox.sandboxId, status: 'done' },
})
writer.write({
id: toolCallId,
type: 'data-create-sandbox',
data: { sandboxId: sandbox.sandboxId, status: 'done' },
})

return (
`Sandbox created with ID: ${sandbox.sandboxId}.` +
`\nYou can now upload files, run commands, and access services on the exposed ports.`
)
} catch (error) {
const richError = getRichError({
action: 'Creating Sandbox',
error,
})
return (
`Sandbox created with ID: ${sandbox.sandboxId}.` +
`\nYou can now upload files, run commands, and access services on the exposed ports.`
)
} catch (error) {
const richError = getRichError({
action: 'Creating Sandbox',
error,
})

writer.write({
id: toolCallId,
type: 'data-create-sandbox',
data: {
error: { message: richError.error.message },
status: 'error',
},
})
writer.write({
id: toolCallId,
type: 'data-create-sandbox',
data: {
error: { message: richError.error.message },
status: 'error',
},
})

console.log('Error creating Sandbox:', richError.error)
return richError.message
}
},
console.log('Error creating Sandbox:', richError.error)
return richError.message
}
}

export const createSandbox = () =>
tool({
description,
inputSchema,
execute: executeCreateSandbox,
})
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Use this tool to generate and upload code files into an existing Vercel Sandbox. It leverages an LLM to create file contents based on the current conversation context and user intent, then writes them directly into the sandbox file system.
export default `Use this tool to generate and upload code files into an existing Vercel Sandbox. It leverages an LLM to create file contents based on the current conversation context and user intent, then writes them directly into the sandbox file system.
The generated files should be considered correct on first iteration and suitable for immediate use in the sandbox environment. This tool is essential for scaffolding applications, adding new features, writing configuration files, or fixing missing components.
All file paths must be relative to the sandbox root (e.g., `src/index.ts`, `package.json`, `components/Button.tsx`).
All file paths must be relative to the sandbox root (e.g., \`src/index.ts\`, \`package.json\`, \`components/Button.tsx\`).
## When to Use This Tool
Expand All @@ -11,48 +11,48 @@ Use Generate Files when:
1. You need to create one or more new files as part of a feature, scaffold, or fix
2. The user requests code that implies file creation (e.g., new routes, APIs, components, services)
3. You need to bootstrap a new application structure inside a sandbox
4. Youre completing a multi-step task that involves generating or updating source code
4. You're completing a multi-step task that involves generating or updating source code
5. A prior command failed due to a missing file, and you need to supply it
## File Generation Guidelines
- Every file must be complete, valid, and runnable where applicable
- File contents must reflect the users intent and the overall session context
- File contents must reflect the user's intent and the overall session context
- File paths must be well-structured and use consistent naming conventions
- Generated files should assume compatibility with other existing files in the sandbox
## Best Practices
- Avoid redundant file generation if the file already exists and is unchanged
- Use conventional file/folder structures for the tech stack in use
- If replacing an existing file, ensure the update fully satisfies the users request
- If replacing an existing file, ensure the update fully satisfies the user's request
## Examples of When to Use This Tool
<example>
User: Add a `NavBar.tsx` component and include it in `App.tsx`
Assistant: Ill generate the `NavBar.tsx` file and update `App.tsx` to include it.
User: Add a \`NavBar.tsx\` component and include it in \`App.tsx\`
Assistant: I'll generate the \`NavBar.tsx\` file and update \`App.tsx\` to include it.
*Uses Generate Files to create:*
- `components/NavBar.tsx`
- Modified `App.tsx` with import and usage of `NavBar`
- \`components/NavBar.tsx\`
- Modified \`App.tsx\` with import and usage of \`NavBar\`
</example>
<example>
User: Lets scaffold a simple Express server with a `/ping` route.
Assistant: Ill generate the necessary files to start the Express app.
User: Let's scaffold a simple Express server with a \`/ping\` route.
Assistant: I'll generate the necessary files to start the Express app.
*Uses Generate Files to create:*
- `package.json` with Express as a dependency
- `index.js` with basic server and `/ping` route
- \`package.json\` with Express as a dependency
- \`index.js\` with basic server and \`/ping\` route
</example>
## When NOT to Use This Tool
Avoid using this tool when:
1. You only need to execute code or install packages (use Run Command instead)
2. Youre waiting for a command to finish (use Wait Command)
2. You're waiting for a command to finish (use Wait Command)
3. You want to preview a running server or UI (use Get Sandbox URL)
4. You havent created a sandbox yet (use Create Sandbox first)
4. You haven't created a sandbox yet (use Create Sandbox first)
## Output Behavior
Expand All @@ -61,3 +61,4 @@ After generation, the tool will return a list of the files created, including th
## Summary
Use Generate Files to programmatically create or update files in your Vercel Sandbox. It enables fast iteration, contextual coding, and dynamic file management — all driven by user intent and conversation context.
`
Loading