Skip to content

Commit 20bbbc7

Browse files
authored
Add vibe-coding-platform project (#1186)
Adds the Vibe Coding Platform example
1 parent 15547f1 commit 20bbbc7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+3945
-3922
lines changed

apps/vibe-coding-platform/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ yarn-error.log*
3939
# typescript
4040
*.tsbuildinfo
4141
next-env.d.ts
42+
.env*.local
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { type GatewayModelId } from '@ai-sdk/gateway'
2+
3+
export const DEFAULT_MODEL: GatewayModelId[number] = 'openai/wagyu-a5'
4+
5+
export const SUPPORTED_MODELS: GatewayModelId[] = [
6+
'amazon/nova-pro',
7+
'anthropic/claude-4-sonnet',
8+
'google/gemini-2.5-flash',
9+
'moonshotai/kimi-k2',
10+
'openai/gpt-4o',
11+
'openai/o4-mini',
12+
'openai/wagyu-a5',
13+
'xai/grok-3-fast',
14+
]
15+
16+
export const TEST_PROMPTS = [
17+
'Generate a Next.js app that allows to list and search Pokemons',
18+
'Create a `golang` server that responds with "Hello World" to any request',
19+
]
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import type { JSONValue } from 'ai'
2+
import type { OpenAIResponsesProviderOptions } from '@ai-sdk/openai'
3+
import { createGatewayProvider, type GatewayModelId } from '@ai-sdk/gateway'
4+
5+
const gateway = createGatewayProvider({
6+
baseURL: process.env.AI_GATEWAY_BASE_URL,
7+
})
8+
9+
interface AvailableModel {
10+
id: GatewayModelId | 'openai/wagyu-a5'
11+
name: string
12+
}
13+
14+
export async function getAvailableModels(): Promise<AvailableModel[]> {
15+
const response = await gateway.getAvailableModels()
16+
return [
17+
...response.models.map(({ id, name }) => ({ id, name })),
18+
{ id: 'openai/wagyu-a5', name: 'GPT-5' },
19+
]
20+
}
21+
22+
interface ModelOptions {
23+
model: string
24+
providerOptions?: Record<string, Record<string, JSONValue>>
25+
headers?: Record<string, string>
26+
}
27+
28+
export function getModelOptions(modelId: string): ModelOptions {
29+
if (modelId === 'openai/o4-mini') {
30+
return {
31+
model: modelId,
32+
providerOptions: {
33+
openai: {
34+
reasoningEffort: 'low',
35+
reasoningSummary: 'detailed',
36+
} satisfies OpenAIResponsesProviderOptions,
37+
},
38+
}
39+
}
40+
41+
if (modelId === 'openai/wagyu-a5') {
42+
return {
43+
model: modelId,
44+
providerOptions: {
45+
openai: {
46+
include: ['reasoning.encrypted_content'],
47+
reasoningEffort: 'low',
48+
reasoningSummary: 'detailed',
49+
} satisfies OpenAIResponsesProviderOptions,
50+
},
51+
}
52+
}
53+
54+
if (modelId === 'anthropic/claude-4-sonnet') {
55+
return {
56+
model: modelId,
57+
headers: { 'anthropic-beta': 'fine-grained-tool-streaming-2025-05-14' },
58+
providerOptions: {
59+
// gateway: { order: ["bedrock", "vertex"] },
60+
anthropic: {
61+
cacheControl: { type: 'ephemeral' },
62+
},
63+
},
64+
}
65+
}
66+
67+
return {
68+
model: modelId,
69+
}
70+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import z from 'zod/v3'
2+
3+
export const dataPartSchema = z.object({
4+
'create-sandbox': z.object({
5+
sandboxId: z.string().optional(),
6+
status: z.enum(['loading', 'done']),
7+
}),
8+
'generating-files': z.object({
9+
paths: z.array(z.string()),
10+
status: z.enum(['generating', 'uploading', 'uploaded', 'done']),
11+
}),
12+
'run-command': z.object({
13+
command: z.string(),
14+
args: z.array(z.string()),
15+
status: z.enum(['loading', 'done']),
16+
commandId: z.string().optional(),
17+
sandboxId: z.string(),
18+
}),
19+
'wait-command': z.object({
20+
sandboxId: z.string(),
21+
commandId: z.string(),
22+
command: z.string(),
23+
args: z.array(z.string()),
24+
exitCode: z.number().optional(),
25+
status: z.enum(['loading', 'done']),
26+
}),
27+
'get-sandbox-url': z.object({
28+
url: z.string().optional(),
29+
status: z.enum(['loading', 'done']),
30+
}),
31+
})
32+
33+
export type DataPart = z.infer<typeof dataPartSchema>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import z from 'zod/v3'
2+
3+
export const metadataSchema = z.object({
4+
model: z.string(),
5+
})
6+
7+
export type Metadata = z.infer<typeof metadataSchema>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
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).
2+
3+
## When to Use This Tool
4+
5+
Use this tool **once per session** when:
6+
7+
1. You begin working on a new user request that requires code execution or file creation
8+
2. No sandbox currently exists for the session
9+
3. The user asks to start a new project, scaffold an application, or test code in a live environment
10+
4. The user requests a fresh or reset environment
11+
12+
## Sandbox Capabilities
13+
14+
After creation, the sandbox allows you to:
15+
16+
- Upload and manage files via `Generate Files`
17+
- Execute shell commands with `Run Command` and `Wait Command`
18+
- Access running servers through public URLs using `Get Sandbox URL`
19+
20+
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:
21+
22+
```
23+
bind-utils bzip2 findutils git gzip iputils libicu libjpeg libpng ncurses-libs openssl openssl-libs pnpm procps tar unzip which whois zstd
24+
```
25+
26+
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.
27+
28+
## Best Practices
29+
30+
- Create the sandbox at the beginning of the session or when the user initiates a coding task
31+
- Track and reuse the sandbox ID throughout the session
32+
- Do not create a second sandbox unless explicitly instructed
33+
- If the user requests an environment reset, you may create a new sandbox **after confirming their intent**
34+
35+
## Examples of When to Use This Tool
36+
37+
<example>
38+
User: Can we start fresh? I want to rebuild the project from scratch.
39+
Assistant: Got it — I’ll create a new sandbox so we can start clean.
40+
*Calls Create Sandbox*
41+
</example>
42+
43+
## When NOT to Use This Tool
44+
45+
Skip using this tool when:
46+
47+
1. A sandbox has already been created for the current session
48+
2. You only need to upload files (use Generate Files)
49+
3. You want to execute or wait for a command (use Run Command / Wait Command)
50+
4. You want to preview the application (use Get Sandbox URL)
51+
5. The user hasn’t asked to reset the environment
52+
53+
## Summary
54+
55+
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.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import type { UIMessageStreamWriter, UIMessage } from 'ai'
2+
import type { DataPart } from '../messages/data-parts'
3+
import { Sandbox } from '@vercel/sandbox'
4+
import { tool } from 'ai'
5+
import description from './create-sandbox.md'
6+
import z from 'zod/v3'
7+
8+
interface Params {
9+
writer: UIMessageStreamWriter<UIMessage<never, DataPart>>
10+
}
11+
12+
export const createSandbox = ({ writer }: Params) =>
13+
tool({
14+
description,
15+
inputSchema: z.object({
16+
timeout: z
17+
.number()
18+
.optional()
19+
.describe(
20+
'Maximum time in milliseconds the Vercel Sandbox will remain active before automatically shutting down. Defaults to 300000ms (5 minutes). The sandbox will terminate all running processes when this timeout is reached.'
21+
),
22+
ports: z
23+
.array(z.number())
24+
.max(2)
25+
.optional()
26+
.describe(
27+
'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.'
28+
),
29+
}),
30+
execute: async ({ timeout, ports }, { toolCallId }) => {
31+
writer.write({
32+
id: toolCallId,
33+
type: 'data-create-sandbox',
34+
data: { status: 'loading' },
35+
})
36+
37+
const sandbox = await Sandbox.create({
38+
timeout,
39+
ports,
40+
})
41+
42+
writer.write({
43+
id: toolCallId,
44+
type: 'data-create-sandbox',
45+
data: { sandboxId: sandbox.sandboxId, status: 'done' },
46+
})
47+
48+
return `Sandbox created with ID: ${sandbox.sandboxId}. You can now upload files, run commands, and access services on the exposed ports.`
49+
},
50+
})
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Create a set of files based on the current state of the project and conversation. Your output will be uploaded directly into a Vercel Sandbox environment, so it must be immediately usable and correct on first iteration. Do not include explanations or markdown. Your output will be parsed programmatically and uploaded to a live environment.
2+
3+
## Instructions
4+
5+
1. Generate only the files that are relevant to the user's request.
6+
2. All file paths must be relative to the sandbox root (e.g., \`src/app.tsx\`, \`package.json\`, \`routes/api.ts\`).
7+
3. Ensure every file is syntactically valid, consistent with the chosen tech stack, and complete.
8+
4. Do not include placeholder comments like “TODO” unless explicitly instructed.
9+
5. Assume any previously generated files already exist in the sandbox — write with compatibility in mind.
10+
6. Favor minimal, functional implementations that demonstrate correctness and are ready to be run, built, or extended.
11+
7. Include configuration, setup, or support files (e.g., \`.env\`, \`tsconfig.json\`, \`vite.config.ts\`) if the task depends on them working.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
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.
2+
3+
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.
4+
5+
All file paths must be relative to the sandbox root (e.g., `src/index.ts`, `package.json`, `components/Button.tsx`).
6+
7+
## When to Use This Tool
8+
9+
Use Generate Files when:
10+
11+
1. You need to create one or more new files as part of a feature, scaffold, or fix
12+
2. The user requests code that implies file creation (e.g., new routes, APIs, components, services)
13+
3. You need to bootstrap a new application structure inside a sandbox
14+
4. You’re completing a multi-step task that involves generating or updating source code
15+
5. A prior command failed due to a missing file, and you need to supply it
16+
17+
## File Generation Guidelines
18+
19+
- Every file must be complete, valid, and runnable where applicable
20+
- File contents must reflect the user’s intent and the overall session context
21+
- File paths must be well-structured and use consistent naming conventions
22+
- Generated files should assume compatibility with other existing files in the sandbox
23+
24+
## Best Practices
25+
26+
- Avoid redundant file generation if the file already exists and is unchanged
27+
- Use conventional file/folder structures for the tech stack in use
28+
- If replacing an existing file, ensure the update fully satisfies the user’s request
29+
30+
## Examples of When to Use This Tool
31+
32+
<example>
33+
User: Add a `NavBar.tsx` component and include it in `App.tsx`
34+
Assistant: I’ll generate the `NavBar.tsx` file and update `App.tsx` to include it.
35+
*Uses Generate Files to create:*
36+
- `components/NavBar.tsx`
37+
- Modified `App.tsx` with import and usage of `NavBar`
38+
</example>
39+
40+
<example>
41+
User: Let’s scaffold a simple Express server with a `/ping` route.
42+
Assistant: I’ll generate the necessary files to start the Express app.
43+
*Uses Generate Files to create:*
44+
- `package.json` with Express as a dependency
45+
- `index.js` with basic server and `/ping` route
46+
</example>
47+
48+
## When NOT to Use This Tool
49+
50+
Avoid using this tool when:
51+
52+
1. You only need to execute code or install packages (use Run Command instead)
53+
2. You’re waiting for a command to finish (use Wait Command)
54+
3. You want to preview a running server or UI (use Get Sandbox URL)
55+
4. You haven’t created a sandbox yet (use Create Sandbox first)
56+
57+
## Output Behavior
58+
59+
After generation, the tool will return a list of the files created, including their paths and contents. These can then be inspected, referenced, or used in subsequent commands.
60+
61+
## Summary
62+
63+
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.

0 commit comments

Comments
 (0)