diff --git a/.csbignore b/.csbignore new file mode 100644 index 00000000..46167bdd --- /dev/null +++ b/.csbignore @@ -0,0 +1,4 @@ +node_modules +dist +.vscode +*.log \ No newline at end of file diff --git a/.devcontainer/Dockerfile.claude b/.devcontainer/Dockerfile.claude new file mode 100644 index 00000000..f331658d --- /dev/null +++ b/.devcontainer/Dockerfile.claude @@ -0,0 +1,14 @@ +#Use Ubuntu 22.04 as the base image +FROM ubuntu:22.04 + +# Install curl and git, update package list +RUN apt-get update && apt-get install -y curl git ripgrep + +# Install Node.js 24.x +RUN curl -sL https://deb.nodesource.com/setup_24.x | bash - && apt-get install -y nodejs + +# Confirm installations +RUN node -v && npm -v && git --version + +# Install Claude Code globalliy +RUN npm install -g @anthropic-ai/claude-code \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..b7e9b403 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,4 @@ +{ + "name": "vibekit-claude-code", + "build": { "dockerfile": "Dockerfile.claude" }, +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5bd7124c..16a3edff 100644 --- a/.gitignore +++ b/.gitignore @@ -42,5 +42,6 @@ test-daytona.ts test-package.ts test-envs.ts test-run-tests.ts +test-togetherai.ts .cluso/config.json .inngest/main.db diff --git a/package-lock.json b/package-lock.json index d023c485..e1d249c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { "name": "@vibe-kit/sdk", - "version": "0.0.20", + "version": "0.0.23", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@vibe-kit/sdk", - "version": "0.0.20", + "version": "0.0.23", "dependencies": { "@ai-sdk/anthropic": "^1.2.12", "@ai-sdk/openai": "^1.3.22", + "@codesandbox/sdk": "^1.1.6", "@daytonaio/sdk": "^0.20.2", "@e2b/code-interpreter": "1.2.0-beta.4", "@opentelemetry/api": "^1.9.0", @@ -2508,6 +2509,19 @@ "integrity": "sha512-foZ7qr0IsUBjzWIq+SuBLfdQCpJ1j8cTuNNT4owngTHoN5KsJb8L9t65fzz7SCeSWzescoOil/0ldqiL041ABg==", "license": "(Apache-2.0 AND BSD-3-Clause)" }, + "node_modules/@codesandbox/sdk": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@codesandbox/sdk/-/sdk-1.1.6.tgz", + "integrity": "sha512-65k6TZSr1c0u8xYjBsz32xhMEq1TwHbqRONJ8h6e3re01qylZ5BDtAU6Nnxr9GQmmhOA0wl+3c4h4zY3/HdHHg==", + "license": "MIT", + "dependencies": { + "ora": "^8.2.0", + "readline": "^1.3.0" + }, + "bin": { + "csb": "dist/bin/codesandbox.cjs" + } + }, "node_modules/@connectrpc/connect": { "version": "2.0.0-rc.3", "resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-2.0.0-rc.3.tgz", @@ -6438,7 +6452,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -6791,6 +6804,33 @@ "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", "license": "MIT" }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -7580,6 +7620,18 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -7872,6 +7924,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -7893,6 +7957,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", @@ -8109,6 +8185,34 @@ "dev": true, "license": "MIT" }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/long": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", @@ -8290,6 +8394,18 @@ "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -8499,6 +8615,52 @@ "integrity": "sha512-1eNjQtbfNi5Z/kFhagDIaIRj6qqDzhjNJKz8cmMW0CVdGwT6e1GLbAfgI0d28VTJa1A8jz82jm/4dG8qNoNS8g==", "license": "MIT" }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "license": "MIT" + }, + "node_modules/ora/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -8867,6 +9029,12 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/readline": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", + "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==", + "license": "BSD" + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -8985,6 +9153,49 @@ "node": ">=8" } }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -9218,6 +9429,18 @@ "dev": true, "license": "MIT" }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/stream-browserify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", @@ -9305,7 +9528,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" diff --git a/package.json b/package.json index 28506dc4..ad1106e8 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "dependencies": { "@ai-sdk/anthropic": "^1.2.12", "@ai-sdk/openai": "^1.3.22", + "@codesandbox/sdk": "^1.1.6", "@daytonaio/sdk": "^0.20.2", "@e2b/code-interpreter": "1.2.0-beta.4", "@opentelemetry/api": "^1.9.0", diff --git a/src/index.ts b/src/index.ts index 4a030d71..9e050b38 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,6 +16,7 @@ export type { ModelProvider, E2BConfig, DaytonaConfig, + TogetherAIConfig, EnvironmentConfig, GithubConfig, TelemetryConfig, diff --git a/src/services/sandbox.ts b/src/services/sandbox.ts index 250dd1e2..6046ebcc 100644 --- a/src/services/sandbox.ts +++ b/src/services/sandbox.ts @@ -1,5 +1,6 @@ import { Sandbox as E2BSandbox } from "@e2b/code-interpreter"; import { Daytona, DaytonaConfig } from "@daytonaio/sdk"; +import { CodeSandbox } from "@codesandbox/sdk"; import { SandboxInstance, @@ -212,15 +213,142 @@ export class DaytonaSandboxProvider implements SandboxProvider { } } +// TogetherAI implementation +class TogetherAISandboxInstance implements SandboxInstance { + constructor( + private session: any, // TogetherAI session object + private sandbox: any, // TogetherAI sandbox object + public sandboxId: string + ) {} + + get commands(): SandboxCommands { + return { + run: async (command: string, options?: SandboxCommandOptions) => { + try { + // Execute command using TogetherAI's session API + const response = await this.session.commands.run(command); + + // Handle streaming callbacks if provided + if (options?.onStdout && response.stdout) { + options.onStdout(response.stdout); + } + if (options?.onStderr && response.stderr) { + options.onStderr(response.stderr); + } + + // TogetherAI returns: { exitCode, stdout, stderr } + return { + exitCode: response.exitCode || 0, + stdout: response.stdout || "", + stderr: response.stderr || "", + }; + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : String(error); + if (options?.onStderr) { + options.onStderr(errorMessage); + } + return { + exitCode: 1, + stdout: "", + stderr: errorMessage, + }; + } + }, + }; + } + + async kill(): Promise { + if (this.sandbox) { + await this.sandbox.kill(); + } + } + + async pause(): Promise { + // TogetherAI doesn't have a direct pause equivalent + console.log( + "Pause not directly supported for TogetherAI sandboxes - sandbox remains active" + ); + } +} + +export class TogetherAISandboxProvider implements SandboxProvider { + async create( + config: SandboxConfig, + envs?: Record, + agentType?: "codex" | "claude" + ): Promise { + try { + const sdk = new CodeSandbox(config.apiKey); + + // Create sandbox - the SDK might handle environment variables differently + const sandbox = await sdk.sandboxes.create(); + + // Connect to the sandbox to get a session + const session = await sandbox.connect(); + console.log("Session connected"); + + // Set environment variables if provided (may need to be done after connection) + if (envs && Object.keys(envs).length > 0) { + for (const [key, value] of Object.entries(envs)) { + await session.commands.run(`export ${key}="${value}"`); + } + } + + return new TogetherAISandboxInstance(session, sandbox, sandbox.id); + } catch (error) { + if ( + error instanceof Error && + error.message.includes("Cannot resolve module") + ) { + throw new Error( + "TogetherAI SDK not found. Please install @codesandbox/sdk: npm install @codesandbox/sdk" + ); + } + throw new Error( + `Failed to create TogetherAI sandbox: ${ + error instanceof Error ? error.message : String(error) + }` + ); + } + } + + async resume( + sandboxId: string, + config: SandboxConfig + ): Promise { + try { + const sdk = new CodeSandbox(config.apiKey); + + // Resume existing sandbox by ID - assuming the SDK provides this functionality + // If not available, we might need to store sandbox references differently + const sandbox = await sdk.sandboxes.resume(sandboxId); + + // Connect to the sandbox to get a session + const session = await sandbox.connect(); + + return new TogetherAISandboxInstance(session, sandbox, sandboxId); + } catch (error) { + throw new Error( + `Failed to resume TogetherAI sandbox: ${ + error instanceof Error ? error.message : String(error) + }` + ); + } + } +} + // Factory function to create appropriate sandbox provider export function createSandboxProvider( - type: "e2b" | "daytona" + type: "e2b" | "daytona" | "togetherai" ): SandboxProvider { switch (type) { case "e2b": return new E2BSandboxProvider(); case "daytona": return new DaytonaSandboxProvider(); + case "togetherai": + return new TogetherAISandboxProvider(); default: throw new Error(`Unsupported sandbox type: ${type}`); } @@ -231,7 +359,16 @@ export function createSandboxConfigFromEnvironment( environment: any, agentType?: "codex" | "claude" ): SandboxConfig { - // Try Daytona first if configured + // Try TogetherAI first if configured + if (environment.togetherai) { + return { + type: "togetherai", + apiKey: environment.togetherai.apiKey, + templateId: environment.togetherai.templateId, + }; + } + + // Try Daytona if configured if (environment.daytona) { // Determine default image based on agent type let defaultImage = "ubuntu:22.04"; // fallback diff --git a/src/types.ts b/src/types.ts index 2339ece8..6c2df26e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -33,9 +33,15 @@ export type DaytonaConfig = { serverUrl?: string; }; +export type TogetherAIConfig = { + apiKey: string; + templateId?: string; +}; + export type EnvironmentConfig = { e2b?: E2BConfig; daytona?: DaytonaConfig; + togetherai?: TogetherAIConfig; }; export type GithubConfig = { @@ -178,9 +184,9 @@ export interface SandboxInstance { } export interface SandboxConfig { - type: "e2b" | "daytona"; + type: "e2b" | "daytona" | "togetherai"; apiKey: string; - templateId?: string; // for E2B + templateId?: string; // for E2B and TogetherAI image?: string; // for Daytona serverUrl?: string; // for Daytona }