mukaddamzaid commited on
Commit
67c6e06
·
1 Parent(s): 3a61a4f

feat: implement sandbox management and MCP client integration

Browse files

- Added functionality to start and stop sandboxes for executing commands in isolated environments.
- Integrated MCP client management for handling server connections and tool initialization.
- Enhanced the chat route to generate titles for new chats and manage server states.
- Updated the MCP server manager component to include server control actions and status indicators.
- Introduced a new context for managing MCP server states and sandbox references.
- Improved error handling and logging for better debugging and user feedback.

app/actions.ts CHANGED
@@ -3,6 +3,11 @@
3
  import { openai } from "@ai-sdk/openai";
4
  import { generateObject } from "ai";
5
  import { z } from "zod";
 
 
 
 
 
6
 
7
  // Helper to extract text content from a message regardless of format
8
  function getMessageText(message: any): string {
@@ -64,3 +69,96 @@ export async function generateTitle(messages: any[]) {
64
 
65
  return object.title;
66
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import { openai } from "@ai-sdk/openai";
4
  import { generateObject } from "ai";
5
  import { z } from "zod";
6
+ import { startMcpSandbox } from '@/lib/mcp-sandbox';
7
+
8
+ // Use a global map to store active sandbox instances across requests
9
+ const activeSandboxes = (global as any).activeSandboxes || new Map();
10
+ (global as any).activeSandboxes = activeSandboxes;
11
 
12
  // Helper to extract text content from a message regardless of format
13
  function getMessageText(message: any): string {
 
69
 
70
  return object.title;
71
  }
72
+
73
+ export interface KeyValuePair {
74
+ key: string;
75
+ value: string;
76
+ }
77
+
78
+ /**
79
+ * Server action to start a sandbox
80
+ */
81
+ export async function startSandbox(params: {
82
+ id: string;
83
+ command: string;
84
+ args: string[];
85
+ env?: KeyValuePair[];
86
+ }): Promise<{ url: string }> {
87
+ const { id, command, args, env } = params;
88
+
89
+ // Validate required fields
90
+ if (!id || !command || !args) {
91
+ throw new Error('Missing required fields');
92
+ }
93
+
94
+ // Check if we already have a sandbox for this ID
95
+ if (activeSandboxes.has(id)) {
96
+ // If we do, get the URL and return it without creating a new sandbox
97
+ const existingSandbox = activeSandboxes.get(id);
98
+ return { url: existingSandbox.url };
99
+ }
100
+
101
+ // Build the command string
102
+ let cmd: string;
103
+
104
+ // Prepare the command based on the type of executable
105
+ if (command === 'uvx') {
106
+ // For uvx, use the direct format
107
+ const toolName = args[0];
108
+ cmd = `uvx ${toolName} ${args.slice(1).join(' ')}`;
109
+ } else if (command.includes('python')) {
110
+ // For python commands
111
+ cmd = `${command} ${args.join(' ')}`;
112
+ } else {
113
+ // For node or other commands
114
+ cmd = `${command} ${args.join(' ')}`;
115
+ }
116
+
117
+ // Convert env array to object if needed
118
+ const envs: Record<string, string> = {};
119
+ if (env && env.length > 0) {
120
+ env.forEach((envVar) => {
121
+ if (envVar.key) envs[envVar.key] = envVar.value || '';
122
+ });
123
+ }
124
+
125
+ // Start the sandbox
126
+ console.log(`Starting sandbox for ${id} with command: ${cmd}`);
127
+ const sandbox = await startMcpSandbox({ cmd, envs });
128
+ const url = await sandbox.getUrl();
129
+
130
+ // Store the sandbox in our map
131
+ activeSandboxes.set(id, { sandbox, url });
132
+
133
+ return { url };
134
+ }
135
+
136
+ /**
137
+ * Server action to stop a sandbox
138
+ */
139
+ export async function stopSandbox(id: string): Promise<{ success: boolean }> {
140
+ if (!id) {
141
+ throw new Error('Missing sandbox ID');
142
+ }
143
+
144
+ // Check if we have a sandbox with this ID
145
+ if (!activeSandboxes.has(id)) {
146
+ throw new Error(`No active sandbox found with ID: ${id}`);
147
+ }
148
+
149
+ // Stop the sandbox
150
+ const { sandbox } = activeSandboxes.get(id);
151
+
152
+ try {
153
+ await sandbox.stop();
154
+ console.log(`Stopped sandbox with ID: ${id}`);
155
+ } catch (stopError) {
156
+ console.error(`Error stopping sandbox ${id}:`, stopError);
157
+ // Continue to remove from the map even if stop fails
158
+ }
159
+
160
+ // Remove from our map
161
+ activeSandboxes.delete(id);
162
+
163
+ return { success: true };
164
+ }
app/api/chat/route.ts CHANGED
@@ -1,32 +1,20 @@
1
  import { model, type modelID } from "@/ai/providers";
2
- import { streamText, type UIMessage } from "ai";
3
  import { appendResponseMessages } from 'ai';
4
  import { saveChat, saveMessages, convertToDBMessages } from '@/lib/chat-store';
5
  import { nanoid } from 'nanoid';
6
  import { db } from '@/lib/db';
7
  import { chats } from '@/lib/db/schema';
8
  import { eq, and } from 'drizzle-orm';
 
 
9
 
10
- import { experimental_createMCPClient as createMCPClient, MCPTransport } from 'ai';
11
- import { Experimental_StdioMCPTransport as StdioMCPTransport } from 'ai/mcp-stdio';
12
- import { spawn } from "child_process";
13
 
14
  // Allow streaming responses up to 30 seconds
15
  export const maxDuration = 120;
16
 
17
- interface KeyValuePair {
18
- key: string;
19
- value: string;
20
- }
21
-
22
- interface MCPServerConfig {
23
- url: string;
24
- type: 'sse' | 'stdio';
25
- command?: string;
26
- args?: string[];
27
- env?: KeyValuePair[];
28
- headers?: KeyValuePair[];
29
- }
30
 
31
  export async function POST(req: Request) {
32
  const {
@@ -53,7 +41,7 @@ export async function POST(req: Request) {
53
  const id = chatId || nanoid();
54
 
55
  // Check if chat already exists for the given ID
56
- // If not, we'll create it in onFinish
57
  let isNewChat = false;
58
  if (chatId) {
59
  try {
@@ -66,7 +54,6 @@ export async function POST(req: Request) {
66
  isNewChat = !existingChat;
67
  } catch (error) {
68
  console.error("Error checking for existing chat:", error);
69
- // Continue anyway, we'll create the chat in onFinish
70
  isNewChat = true;
71
  }
72
  } else {
@@ -74,125 +61,44 @@ export async function POST(req: Request) {
74
  isNewChat = true;
75
  }
76
 
77
- // Initialize tools
78
- let tools = {};
79
- const mcpClients: any[] = [];
80
-
81
- // Process each MCP server configuration
82
- for (const mcpServer of mcpServers) {
83
  try {
84
- // Create appropriate transport based on type
85
- let transport: MCPTransport | { type: 'sse', url: string, headers?: Record<string, string> };
86
-
87
- if (mcpServer.type === 'sse') {
88
- // Convert headers array to object for SSE transport
89
- const headers: Record<string, string> = {};
90
- if (mcpServer.headers && mcpServer.headers.length > 0) {
91
- mcpServer.headers.forEach(header => {
92
- if (header.key) headers[header.key] = header.value || '';
93
- });
94
- }
95
-
96
- transport = {
97
- type: 'sse' as const,
98
- url: mcpServer.url,
99
- headers: Object.keys(headers).length > 0 ? headers : undefined
100
- };
101
- } else if (mcpServer.type === 'stdio') {
102
- // For stdio transport, we need command and args
103
- if (!mcpServer.command || !mcpServer.args || mcpServer.args.length === 0) {
104
- console.warn("Skipping stdio MCP server due to missing command or args");
105
- continue;
106
- }
107
-
108
- // Convert env array to object for stdio transport
109
- const env: Record<string, string> = {};
110
- if (mcpServer.env && mcpServer.env.length > 0) {
111
- mcpServer.env.forEach(envVar => {
112
- if (envVar.key) env[envVar.key] = envVar.value || '';
113
- });
114
- }
115
-
116
- // Check for uvx pattern and transform to python3 -m uv run
117
- if (mcpServer.command === 'uvx') {
118
- // install uv
119
- const subprocess = spawn('pip3', ['install', 'uv']);
120
- subprocess.on('close', (code: number) => {
121
- if (code !== 0) {
122
- console.error(`Failed to install uv: ${code}`);
123
- }
124
- });
125
- // wait for the subprocess to finish
126
- await new Promise((resolve) => {
127
- subprocess.on('close', resolve);
128
- console.log("installed uv");
129
- });
130
- console.log("Detected uvx pattern, transforming to python3 -m uv run");
131
- mcpServer.command = 'python3';
132
- // Get the tool name (first argument)
133
- const toolName = mcpServer.args[0];
134
- // Replace args with the new pattern
135
- mcpServer.args = ['-m', 'uv', 'run', toolName, ...mcpServer.args.slice(1)];
136
- }
137
- // if python is passed in the command, install the python package mentioned in args after -m with subprocess or use regex to find the package name
138
- else if (mcpServer.command.includes('python3')) {
139
- const packageName = mcpServer.args[mcpServer.args.indexOf('-m') + 1];
140
- console.log("installing python package", packageName);
141
- const subprocess = spawn('pip3', ['install', packageName]);
142
- subprocess.on('close', (code: number) => {
143
- if (code !== 0) {
144
- console.error(`Failed to install python package: ${code}`);
145
- }
146
- });
147
- // wait for the subprocess to finish
148
- await new Promise((resolve) => {
149
- subprocess.on('close', resolve);
150
- console.log("installed python package", packageName);
151
- });
152
  }
153
-
154
- transport = new StdioMCPTransport({
155
- command: mcpServer.command,
156
- args: mcpServer.args,
157
- env: Object.keys(env).length > 0 ? env : undefined
158
- });
159
- } else {
160
- console.warn(`Skipping MCP server with unsupported transport type: ${mcpServer.type}`);
161
- continue;
162
  }
163
-
164
- const mcpClient = await createMCPClient({ transport });
165
- mcpClients.push(mcpClient);
166
-
167
- const mcptools = await mcpClient.tools();
168
-
169
- console.log(`MCP tools from ${mcpServer.type} transport:`, Object.keys(mcptools));
170
-
171
- // Add MCP tools to tools object
172
- tools = { ...tools, ...mcptools };
173
  } catch (error) {
174
- console.error("Failed to initialize MCP client:", error);
175
- // Continue with other servers instead of failing the entire request
176
  }
177
  }
178
 
179
- // Register cleanup for all clients
180
- if (mcpClients.length > 0) {
181
- req.signal.addEventListener('abort', async () => {
182
- for (const client of mcpClients) {
183
- try {
184
- await client.close();
185
- } catch (error) {
186
- console.error("Error closing MCP client:", error);
187
- }
188
- }
189
- });
190
- }
191
 
192
  console.log("messages", messages);
193
  console.log("parts", messages.map(m => m.parts.map(p => p)));
194
 
195
- // If there was an error setting up MCP clients but we at least have composio tools, continue
 
 
196
  const result = streamText({
197
  model: model.languageModel(selectedModel),
198
  system: `You are a helpful assistant with access to a variety of tools.
@@ -233,10 +139,15 @@ export async function POST(req: Request) {
233
  },
234
  }
235
  },
 
 
 
 
236
  onError: (error) => {
237
  console.error(JSON.stringify(error, null, 2));
238
  },
239
  async onFinish({ response }) {
 
240
  const allMessages = appendResponseMessages({
241
  messages,
242
  responseMessages: response.messages,
@@ -250,16 +161,32 @@ export async function POST(req: Request) {
250
 
251
  const dbMessages = convertToDBMessages(allMessages, id);
252
  await saveMessages({ messages: dbMessages });
253
- // close all mcp clients
254
- // for (const client of mcpClients) {
255
- // await client.close();
256
- // }
 
 
 
 
 
 
 
 
 
 
 
 
257
  }
258
  });
259
 
260
  result.consumeStream()
 
261
  return result.toDataStreamResponse({
262
  sendReasoning: true,
 
 
 
263
  getErrorMessage: (error) => {
264
  if (error instanceof Error) {
265
  if (error.message.includes("Rate limit")) {
@@ -270,4 +197,4 @@ export async function POST(req: Request) {
270
  return "An error occurred.";
271
  },
272
  });
273
- }
 
1
  import { model, type modelID } from "@/ai/providers";
2
+ import { smoothStream, streamText, type UIMessage } from "ai";
3
  import { appendResponseMessages } from 'ai';
4
  import { saveChat, saveMessages, convertToDBMessages } from '@/lib/chat-store';
5
  import { nanoid } from 'nanoid';
6
  import { db } from '@/lib/db';
7
  import { chats } from '@/lib/db/schema';
8
  import { eq, and } from 'drizzle-orm';
9
+ import { initializeMCPClients, type MCPServerConfig } from '@/lib/mcp-client';
10
+ import { generateTitle } from '@/app/actions';
11
 
12
+ export const runtime = 'nodejs';
 
 
13
 
14
  // Allow streaming responses up to 30 seconds
15
  export const maxDuration = 120;
16
 
17
+ export const dynamic = 'force-dynamic';
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  export async function POST(req: Request) {
20
  const {
 
41
  const id = chatId || nanoid();
42
 
43
  // Check if chat already exists for the given ID
44
+ // If not, create it now
45
  let isNewChat = false;
46
  if (chatId) {
47
  try {
 
54
  isNewChat = !existingChat;
55
  } catch (error) {
56
  console.error("Error checking for existing chat:", error);
 
57
  isNewChat = true;
58
  }
59
  } else {
 
61
  isNewChat = true;
62
  }
63
 
64
+ // If it's a new chat, save it immediately
65
+ if (isNewChat && messages.length > 0) {
 
 
 
 
66
  try {
67
+ // Generate a title based on first user message
68
+ const userMessage = messages.find(m => m.role === 'user');
69
+ let title = 'New Chat';
70
+
71
+ if (userMessage) {
72
+ try {
73
+ title = await generateTitle([userMessage]);
74
+ } catch (error) {
75
+ console.error("Error generating title:", error);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  }
 
 
 
 
 
 
 
 
 
77
  }
78
+
79
+ // Save the chat immediately so it appears in the sidebar
80
+ await saveChat({
81
+ id,
82
+ userId,
83
+ title,
84
+ messages: [],
85
+ });
 
 
86
  } catch (error) {
87
+ console.error("Error saving new chat:", error);
 
88
  }
89
  }
90
 
91
+ // Initialize MCP clients using the already running persistent SSE servers
92
+ // mcpServers now only contains SSE configurations since stdio servers
93
+ // have been converted to SSE in the MCP context
94
+ const { tools, cleanup } = await initializeMCPClients(mcpServers, req.signal);
 
 
 
 
 
 
 
 
95
 
96
  console.log("messages", messages);
97
  console.log("parts", messages.map(m => m.parts.map(p => p)));
98
 
99
+ // Track if the response has completed
100
+ let responseCompleted = false;
101
+
102
  const result = streamText({
103
  model: model.languageModel(selectedModel),
104
  system: `You are a helpful assistant with access to a variety of tools.
 
139
  },
140
  }
141
  },
142
+ experimental_transform: smoothStream({
143
+ delayInMs: 5, // optional: defaults to 10ms
144
+ chunking: 'line', // optional: defaults to 'word'
145
+ }),
146
  onError: (error) => {
147
  console.error(JSON.stringify(error, null, 2));
148
  },
149
  async onFinish({ response }) {
150
+ responseCompleted = true;
151
  const allMessages = appendResponseMessages({
152
  messages,
153
  responseMessages: response.messages,
 
161
 
162
  const dbMessages = convertToDBMessages(allMessages, id);
163
  await saveMessages({ messages: dbMessages });
164
+
165
+ // Clean up resources - now this just closes the client connections
166
+ // not the actual servers which persist in the MCP context
167
+ await cleanup();
168
+ }
169
+ });
170
+
171
+ // Ensure cleanup happens if the request is terminated early
172
+ req.signal.addEventListener('abort', async () => {
173
+ if (!responseCompleted) {
174
+ console.log("Request aborted, cleaning up resources");
175
+ try {
176
+ await cleanup();
177
+ } catch (error) {
178
+ console.error("Error during cleanup on abort:", error);
179
+ }
180
  }
181
  });
182
 
183
  result.consumeStream()
184
+ // Add chat ID to response headers so client can know which chat was created
185
  return result.toDataStreamResponse({
186
  sendReasoning: true,
187
+ headers: {
188
+ 'X-Chat-ID': id
189
+ },
190
  getErrorMessage: (error) => {
191
  if (error instanceof Error) {
192
  if (error.message.includes("Rate limit")) {
 
197
  return "An error occurred.";
198
  },
199
  });
200
+ }
components/mcp-server-manager.tsx CHANGED
@@ -24,7 +24,10 @@ import {
24
  Cog,
25
  Edit2,
26
  Eye,
27
- EyeOff
 
 
 
28
  } from "lucide-react";
29
  import { toast } from "sonner";
30
  import {
@@ -33,7 +36,7 @@ import {
33
  AccordionItem,
34
  AccordionTrigger
35
  } from "./ui/accordion";
36
- import { KeyValuePair, MCPServer } from "@/lib/context/mcp-context";
37
 
38
  // Default template for a new MCP server
39
  const INITIAL_NEW_SERVER: Omit<MCPServer, 'id'> = {
@@ -76,6 +79,44 @@ const maskValue = (value: string): string => {
76
  return value.substring(0, 3) + '•'.repeat(Math.min(10, value.length - 4)) + value.substring(value.length - 1);
77
  };
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  export const MCPServerManager = ({
80
  servers,
81
  onServersChange,
@@ -95,6 +136,9 @@ export const MCPServerManager = ({
95
  const [editingHeaderIndex, setEditingHeaderIndex] = useState<number | null>(null);
96
  const [editedEnvValue, setEditedEnvValue] = useState<string>('');
97
  const [editedHeaderValue, setEditedHeaderValue] = useState<string>('');
 
 
 
98
 
99
  const resetAndClose = () => {
100
  setView('list');
@@ -356,6 +400,57 @@ export const MCPServerManager = ({
356
  setShowSensitiveHeaderValues({});
357
  };
358
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
359
  return (
360
  <Dialog open={open} onOpenChange={onOpenChange}>
361
  <DialogContent className="sm:max-w-[480px] max-h-[85vh] overflow-hidden flex flex-col">
@@ -396,6 +491,8 @@ export const MCPServerManager = ({
396
  })
397
  .map((server) => {
398
  const isActive = selectedServers.includes(server.id);
 
 
399
  return (
400
  <div
401
  key={server.id}
@@ -406,7 +503,7 @@ export const MCPServerManager = ({
406
  : 'border-border hover:border-primary/30 hover:bg-primary/5'}
407
  `}
408
  >
409
- {/* Server Header with Type Badge and Delete Button */}
410
  <div className="flex items-center justify-between mb-2">
411
  <div className="flex items-center gap-2">
412
  {server.type === 'sse' ? (
@@ -414,7 +511,7 @@ export const MCPServerManager = ({
414
  ) : (
415
  <Terminal className={`h-4 w-4 ${isActive ? 'text-primary' : 'text-muted-foreground'} flex-shrink-0`} />
416
  )}
417
- <h4 className="text-sm font-medium truncate max-w-[220px]">{server.name}</h4>
418
  {hasAdvancedConfig(server) && (
419
  <span className="flex-shrink-0">
420
  <Cog className="h-3 w-3 text-muted-foreground" />
@@ -425,20 +522,52 @@ export const MCPServerManager = ({
425
  <span className="text-xs px-2 py-0.5 rounded-full bg-secondary text-secondary-foreground">
426
  {server.type.toUpperCase()}
427
  </span>
428
- <button
429
- onClick={(e) => removeServer(server.id, e)}
430
- className="p-1 rounded-full hover:bg-muted/70"
431
- aria-label="Remove server"
432
- >
433
- <Trash2 className="h-3.5 w-3.5 text-muted-foreground" />
434
- </button>
435
- <button
436
- onClick={() => startEditing(server)}
437
- className="p-1 rounded-full hover:bg-muted/50"
438
- aria-label="Edit server"
439
- >
440
- <Edit2 className="h-3.5 w-3.5 text-muted-foreground" />
441
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442
  </div>
443
  </div>
444
 
 
24
  Cog,
25
  Edit2,
26
  Eye,
27
+ EyeOff,
28
+ AlertTriangle,
29
+ RefreshCw,
30
+ Power
31
  } from "lucide-react";
32
  import { toast } from "sonner";
33
  import {
 
36
  AccordionItem,
37
  AccordionTrigger
38
  } from "./ui/accordion";
39
+ import { KeyValuePair, MCPServer, ServerStatus, useMCP } from "@/lib/context/mcp-context";
40
 
41
  // Default template for a new MCP server
42
  const INITIAL_NEW_SERVER: Omit<MCPServer, 'id'> = {
 
79
  return value.substring(0, 3) + '•'.repeat(Math.min(10, value.length - 4)) + value.substring(value.length - 1);
80
  };
81
 
82
+ const StatusIndicator = ({ status, onClick }: { status?: ServerStatus, onClick?: () => void }) => {
83
+ const isClickable = !!onClick;
84
+
85
+ const className = `flex-shrink-0 flex items-center gap-1 ${isClickable ? 'cursor-pointer hover:underline' : ''}`;
86
+
87
+ switch (status) {
88
+ case 'connected':
89
+ return (
90
+ <div className={className} onClick={onClick}>
91
+ <div className="w-2 h-2 rounded-full bg-green-500 animate-pulse" />
92
+ <span className="text-xs text-green-500">Connected</span>
93
+ </div>
94
+ );
95
+ case 'connecting':
96
+ return (
97
+ <div className={className} onClick={onClick}>
98
+ <RefreshCw className="w-3 h-3 text-amber-500 animate-spin" />
99
+ <span className="text-xs text-amber-500">Connecting</span>
100
+ </div>
101
+ );
102
+ case 'error':
103
+ return (
104
+ <div className={className} onClick={onClick}>
105
+ <AlertTriangle className="w-3 h-3 text-red-500" />
106
+ <span className="text-xs text-red-500">Error</span>
107
+ </div>
108
+ );
109
+ case 'disconnected':
110
+ default:
111
+ return (
112
+ <div className={className} onClick={onClick}>
113
+ <div className="w-2 h-2 rounded-full bg-gray-400" />
114
+ <span className="text-xs text-muted-foreground">Disconnected</span>
115
+ </div>
116
+ );
117
+ }
118
+ };
119
+
120
  export const MCPServerManager = ({
121
  servers,
122
  onServersChange,
 
136
  const [editingHeaderIndex, setEditingHeaderIndex] = useState<number | null>(null);
137
  const [editedEnvValue, setEditedEnvValue] = useState<string>('');
138
  const [editedHeaderValue, setEditedHeaderValue] = useState<string>('');
139
+
140
+ // Add access to the MCP context for server control
141
+ const { startServer, stopServer, updateServerStatus } = useMCP();
142
 
143
  const resetAndClose = () => {
144
  setView('list');
 
400
  setShowSensitiveHeaderValues({});
401
  };
402
 
403
+ // Add functions to control servers
404
+ const toggleServerStatus = async (server: MCPServer, e: React.MouseEvent) => {
405
+ e.stopPropagation();
406
+
407
+ if (!server.status || server.status === 'disconnected' || server.status === 'error') {
408
+ // Start the server
409
+ try {
410
+ const success = await startServer(server.id);
411
+ if (success) {
412
+ toast.success(`Started server: ${server.name}`);
413
+ } else {
414
+ toast.error(`Failed to start server: ${server.name}`);
415
+ }
416
+ } catch (error) {
417
+ toast.error(`Error starting server: ${error instanceof Error ? error.message : String(error)}`);
418
+ }
419
+ } else {
420
+ // Stop the server
421
+ try {
422
+ await stopServer(server.id);
423
+ toast.success(`Stopped server: ${server.name}`);
424
+ } catch (error) {
425
+ toast.error(`Error stopping server: ${error instanceof Error ? error.message : String(error)}`);
426
+ }
427
+ }
428
+ };
429
+
430
+ // Add function to restart a server
431
+ const restartServer = async (server: MCPServer, e: React.MouseEvent) => {
432
+ e.stopPropagation();
433
+
434
+ try {
435
+ // First stop it if it's running
436
+ if (server.status === 'connected' || server.status === 'connecting') {
437
+ await stopServer(server.id);
438
+ }
439
+
440
+ // Then start it again
441
+ updateServerStatus(server.id, 'connecting');
442
+ const success = await startServer(server.id);
443
+
444
+ if (success) {
445
+ toast.success(`Restarted server: ${server.name}`);
446
+ } else {
447
+ toast.error(`Failed to restart server: ${server.name}`);
448
+ }
449
+ } catch (error) {
450
+ toast.error(`Error restarting server: ${error instanceof Error ? error.message : String(error)}`);
451
+ }
452
+ };
453
+
454
  return (
455
  <Dialog open={open} onOpenChange={onOpenChange}>
456
  <DialogContent className="sm:max-w-[480px] max-h-[85vh] overflow-hidden flex flex-col">
 
491
  })
492
  .map((server) => {
493
  const isActive = selectedServers.includes(server.id);
494
+ const isRunning = server.status === 'connected' || server.status === 'connecting';
495
+
496
  return (
497
  <div
498
  key={server.id}
 
503
  : 'border-border hover:border-primary/30 hover:bg-primary/5'}
504
  `}
505
  >
506
+ {/* Server Header with Type Badge and Actions */}
507
  <div className="flex items-center justify-between mb-2">
508
  <div className="flex items-center gap-2">
509
  {server.type === 'sse' ? (
 
511
  ) : (
512
  <Terminal className={`h-4 w-4 ${isActive ? 'text-primary' : 'text-muted-foreground'} flex-shrink-0`} />
513
  )}
514
+ <h4 className="text-sm font-medium truncate max-w-[160px]">{server.name}</h4>
515
  {hasAdvancedConfig(server) && (
516
  <span className="flex-shrink-0">
517
  <Cog className="h-3 w-3 text-muted-foreground" />
 
522
  <span className="text-xs px-2 py-0.5 rounded-full bg-secondary text-secondary-foreground">
523
  {server.type.toUpperCase()}
524
  </span>
525
+
526
+ {/* Status indicator */}
527
+ <StatusIndicator
528
+ status={server.status}
529
+ onClick={() => server.errorMessage && toast.error(server.errorMessage)}
530
+ />
531
+
532
+ {/* Server actions */}
533
+ <div className="flex items-center">
534
+ <button
535
+ onClick={(e) => toggleServerStatus(server, e)}
536
+ className="p-1 rounded-full hover:bg-muted/70"
537
+ aria-label={isRunning ? "Stop server" : "Start server"}
538
+ title={isRunning ? "Stop server" : "Start server"}
539
+ >
540
+ <Power className={`h-3.5 w-3.5 ${isRunning ? 'text-red-500' : 'text-green-500'}`} />
541
+ </button>
542
+
543
+ <button
544
+ onClick={(e) => restartServer(server, e)}
545
+ className="p-1 rounded-full hover:bg-muted/70"
546
+ aria-label="Restart server"
547
+ title="Restart server"
548
+ disabled={server.status === 'connecting'}
549
+ >
550
+ <RefreshCw className={`h-3.5 w-3.5 text-muted-foreground ${server.status === 'connecting' ? 'opacity-50' : ''}`} />
551
+ </button>
552
+
553
+ <button
554
+ onClick={(e) => removeServer(server.id, e)}
555
+ className="p-1 rounded-full hover:bg-muted/70"
556
+ aria-label="Remove server"
557
+ title="Remove server"
558
+ >
559
+ <Trash2 className="h-3.5 w-3.5 text-muted-foreground" />
560
+ </button>
561
+
562
+ <button
563
+ onClick={() => startEditing(server)}
564
+ className="p-1 rounded-full hover:bg-muted/50"
565
+ aria-label="Edit server"
566
+ title="Edit server"
567
+ >
568
+ <Edit2 className="h-3.5 w-3.5 text-muted-foreground" />
569
+ </button>
570
+ </div>
571
  </div>
572
  </div>
573
 
lib/context/mcp-context.tsx CHANGED
@@ -1,8 +1,9 @@
1
  "use client";
2
 
3
- import React, { createContext, useContext, useEffect, useState } from "react";
4
  import { useLocalStorage } from "@/lib/hooks/use-local-storage";
5
  import { STORAGE_KEYS } from "@/lib/constants";
 
6
 
7
  // Define types for MCP server
8
  export interface KeyValuePair {
@@ -10,6 +11,8 @@ export interface KeyValuePair {
10
  value: string;
11
  }
12
 
 
 
13
  export interface MCPServer {
14
  id: string;
15
  name: string;
@@ -20,28 +23,54 @@ export interface MCPServer {
20
  env?: KeyValuePair[];
21
  headers?: KeyValuePair[];
22
  description?: string;
 
 
23
  }
24
 
25
  // Type for processed MCP server config for API
26
  export interface MCPServerApi {
27
- type: 'sse' | 'stdio';
28
  url: string;
29
- command?: string;
30
- args?: string[];
31
- env?: KeyValuePair[];
32
  headers?: KeyValuePair[];
33
  }
34
 
 
 
 
 
 
35
  interface MCPContextType {
36
  mcpServers: MCPServer[];
37
  setMcpServers: (servers: MCPServer[]) => void;
38
  selectedMcpServers: string[];
39
  setSelectedMcpServers: (serverIds: string[]) => void;
40
  mcpServersForApi: MCPServerApi[];
 
 
 
41
  }
42
 
43
  const MCPContext = createContext<MCPContextType | undefined>(undefined);
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  export function MCPProvider(props: { children: React.ReactNode }) {
46
  const { children } = props;
47
  const [mcpServers, setMcpServers] = useLocalStorage<MCPServer[]>(
@@ -53,6 +82,157 @@ export function MCPProvider(props: { children: React.ReactNode }) {
53
  []
54
  );
55
  const [mcpServersForApi, setMcpServersForApi] = useState<MCPServerApi[]>([]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
  // Process MCP servers for API consumption whenever server data changes
58
  useEffect(() => {
@@ -65,11 +245,9 @@ export function MCPProvider(props: { children: React.ReactNode }) {
65
  .map(id => mcpServers.find(server => server.id === id))
66
  .filter((server): server is MCPServer => Boolean(server))
67
  .map(server => ({
68
- type: server.type,
 
69
  url: server.url,
70
- command: server.command,
71
- args: server.args,
72
- env: server.env,
73
  headers: server.headers
74
  }));
75
 
@@ -83,7 +261,10 @@ export function MCPProvider(props: { children: React.ReactNode }) {
83
  setMcpServers,
84
  selectedMcpServers,
85
  setSelectedMcpServers,
86
- mcpServersForApi
 
 
 
87
  }}
88
  >
89
  {children}
 
1
  "use client";
2
 
3
+ import React, { createContext, useContext, useEffect, useState, useRef } from "react";
4
  import { useLocalStorage } from "@/lib/hooks/use-local-storage";
5
  import { STORAGE_KEYS } from "@/lib/constants";
6
+ import { startSandbox, stopSandbox } from "@/app/actions";
7
 
8
  // Define types for MCP server
9
  export interface KeyValuePair {
 
11
  value: string;
12
  }
13
 
14
+ export type ServerStatus = 'disconnected' | 'connecting' | 'connected' | 'error';
15
+
16
  export interface MCPServer {
17
  id: string;
18
  name: string;
 
23
  env?: KeyValuePair[];
24
  headers?: KeyValuePair[];
25
  description?: string;
26
+ status?: ServerStatus;
27
+ errorMessage?: string;
28
  }
29
 
30
  // Type for processed MCP server config for API
31
  export interface MCPServerApi {
32
+ type: 'sse';
33
  url: string;
 
 
 
34
  headers?: KeyValuePair[];
35
  }
36
 
37
+ interface SandboxInfo {
38
+ id: string;
39
+ url: string;
40
+ }
41
+
42
  interface MCPContextType {
43
  mcpServers: MCPServer[];
44
  setMcpServers: (servers: MCPServer[]) => void;
45
  selectedMcpServers: string[];
46
  setSelectedMcpServers: (serverIds: string[]) => void;
47
  mcpServersForApi: MCPServerApi[];
48
+ startServer: (serverId: string) => Promise<boolean>;
49
+ stopServer: (serverId: string) => Promise<void>;
50
+ updateServerStatus: (serverId: string, status: ServerStatus, errorMessage?: string) => void;
51
  }
52
 
53
  const MCPContext = createContext<MCPContextType | undefined>(undefined);
54
 
55
+ // Helper function to wait for server readiness
56
+ async function waitForServerReady(url: string, maxAttempts = 15) {
57
+ for (let i = 0; i < maxAttempts; i++) {
58
+ try {
59
+ const response = await fetch(url);
60
+ if (response.status === 200) {
61
+ console.log(`Server ready at ${url} after ${i + 1} attempts`);
62
+ return true;
63
+ }
64
+ console.log(`Server not ready yet (attempt ${i + 1}), status: ${response.status}`);
65
+ } catch {
66
+ console.log(`Server connection failed (attempt ${i + 1})`);
67
+ }
68
+ // Wait between attempts
69
+ await new Promise(resolve => setTimeout(resolve, 6000));
70
+ }
71
+ return false;
72
+ }
73
+
74
  export function MCPProvider(props: { children: React.ReactNode }) {
75
  const { children } = props;
76
  const [mcpServers, setMcpServers] = useLocalStorage<MCPServer[]>(
 
82
  []
83
  );
84
  const [mcpServersForApi, setMcpServersForApi] = useState<MCPServerApi[]>([]);
85
+
86
+ // Keep a ref to active sandboxes (only their IDs and URLs)
87
+ const sandboxesRef = useRef<SandboxInfo[]>([]);
88
+
89
+ // Update server status
90
+ const updateServerStatus = (serverId: string, status: ServerStatus, errorMessage?: string) => {
91
+ setMcpServers(current =>
92
+ current.map(server =>
93
+ server.id === serverId
94
+ ? { ...server, status, errorMessage: errorMessage || undefined }
95
+ : server
96
+ )
97
+ );
98
+ };
99
+
100
+ // Start a server (if it's stdio type) using server actions
101
+ const startServer = async (serverId: string): Promise<boolean> => {
102
+ const server = mcpServers.find(s => s.id === serverId);
103
+ if (!server) return false;
104
+
105
+ // If it's already an SSE server, just update the status
106
+ if (server.type === 'sse') {
107
+ updateServerStatus(serverId, 'connecting');
108
+
109
+ try {
110
+ const isReady = await waitForServerReady(server.url);
111
+ updateServerStatus(serverId, isReady ? 'connected' : 'error',
112
+ isReady ? undefined : 'Could not connect to server');
113
+ return isReady;
114
+ } catch (error) {
115
+ updateServerStatus(serverId, 'error', `Connection error: ${error instanceof Error ? error.message : String(error)}`);
116
+ return false;
117
+ }
118
+ }
119
+
120
+ // For stdio type, start a sandbox via the server action
121
+ if (server.type === 'stdio' && server.command && server.args?.length) {
122
+ updateServerStatus(serverId, 'connecting');
123
+
124
+ try {
125
+ // Check if we already have a sandbox for this server
126
+ const existingSandbox = sandboxesRef.current.find(s => s.id === serverId);
127
+ if (existingSandbox) {
128
+ try {
129
+ // Test if the existing sandbox is still responsive
130
+ const isReady = await waitForServerReady(existingSandbox.url);
131
+ if (isReady) {
132
+ updateServerStatus(serverId, 'connected');
133
+ return true;
134
+ }
135
+ // If not responsive, we'll create a new one below
136
+ } catch {
137
+ // Sandbox wasn't responsive, continue to create a new one
138
+ }
139
+ }
140
+
141
+ // Call the server action to create a sandbox
142
+ const { url } = await startSandbox({
143
+ id: serverId,
144
+ command: server.command,
145
+ args: server.args,
146
+ env: server.env,
147
+ });
148
+
149
+ // Wait for the server to become ready
150
+ const isReady = await waitForServerReady(url);
151
+ if (!isReady) {
152
+ updateServerStatus(serverId, 'error', 'Server failed to start in time');
153
+
154
+ // Attempt to stop the sandbox since it's not working correctly
155
+ try {
156
+ await stopSandbox(serverId);
157
+ } catch (stopError) {
158
+ console.error('Failed to stop non-responsive sandbox:', stopError);
159
+ }
160
+
161
+ return false;
162
+ }
163
+
164
+ // Store the sandbox reference
165
+ // Remove any existing sandbox for this server first
166
+ sandboxesRef.current = sandboxesRef.current.filter(s => s.id !== serverId);
167
+ sandboxesRef.current.push({ id: serverId, url });
168
+
169
+ // Update the server URL to point to the sandbox SSE URL
170
+ setMcpServers(current =>
171
+ current.map(s =>
172
+ s.id === serverId
173
+ ? { ...s, status: 'connected', errorMessage: undefined, url }
174
+ : s
175
+ )
176
+ );
177
+
178
+ return true;
179
+ } catch (error) {
180
+ console.error('Error starting server:', error);
181
+ updateServerStatus(serverId, 'error', `Startup error: ${error instanceof Error ? error.message : String(error)}`);
182
+ return false;
183
+ }
184
+ }
185
+
186
+ return false;
187
+ };
188
+
189
+ // Stop a server using the server action
190
+ const stopServer = async (serverId: string): Promise<void> => {
191
+ // Find the sandbox for this server
192
+ const sandboxIndex = sandboxesRef.current.findIndex(s => s.id === serverId);
193
+ if (sandboxIndex >= 0) {
194
+ try {
195
+ // Call server action to stop the sandbox
196
+ await stopSandbox(serverId);
197
+ console.log(`Stopped sandbox for server ${serverId}`);
198
+ } catch (error) {
199
+ console.error(`Error stopping sandbox for server ${serverId}:`, error);
200
+ }
201
+
202
+ // Remove from our tracking
203
+ sandboxesRef.current.splice(sandboxIndex, 1);
204
+ }
205
+
206
+ // Update server status
207
+ updateServerStatus(serverId, 'disconnected');
208
+ };
209
+
210
+ // Auto-start selected servers when they're added to the selection
211
+ useEffect(() => {
212
+ const startSelectedServers = async () => {
213
+ for (const serverId of selectedMcpServers) {
214
+ const server = mcpServers.find(s => s.id === serverId);
215
+ if (server && (!server.status || server.status === 'disconnected')) {
216
+ await startServer(serverId);
217
+ }
218
+ }
219
+ };
220
+
221
+ startSelectedServers();
222
+
223
+ // Cleanup on unmount
224
+ return () => {
225
+ // Stop all running sandboxes
226
+ sandboxesRef.current.forEach(async ({ id }) => {
227
+ try {
228
+ await stopSandbox(id);
229
+ } catch (error) {
230
+ console.error('Error stopping sandbox during cleanup:', error);
231
+ }
232
+ });
233
+ sandboxesRef.current = [];
234
+ };
235
+ }, [selectedMcpServers]);
236
 
237
  // Process MCP servers for API consumption whenever server data changes
238
  useEffect(() => {
 
245
  .map(id => mcpServers.find(server => server.id === id))
246
  .filter((server): server is MCPServer => Boolean(server))
247
  .map(server => ({
248
+ // All servers are exposed as SSE type to the API
249
+ type: 'sse',
250
  url: server.url,
 
 
 
251
  headers: server.headers
252
  }));
253
 
 
261
  setMcpServers,
262
  selectedMcpServers,
263
  setSelectedMcpServers,
264
+ mcpServersForApi,
265
+ startServer,
266
+ stopServer,
267
+ updateServerStatus
268
  }}
269
  >
270
  {children}
lib/mcp-client.ts ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { experimental_createMCPClient as createMCPClient } from 'ai';
2
+
3
+
4
+ export interface KeyValuePair {
5
+ key: string;
6
+ value: string;
7
+ }
8
+
9
+ export interface MCPServerConfig {
10
+ url: string;
11
+ type: 'sse' | 'stdio';
12
+ command?: string;
13
+ args?: string[];
14
+ env?: KeyValuePair[];
15
+ headers?: KeyValuePair[];
16
+ }
17
+
18
+ export interface MCPClientManager {
19
+ tools: Record<string, any>;
20
+ clients: any[];
21
+ cleanup: () => Promise<void>;
22
+ }
23
+
24
+ async function waitForServerReady(url: string, maxAttempts = 5) {
25
+ for (let i = 0; i < maxAttempts; i++) {
26
+ try {
27
+ const response = await fetch(url)
28
+ if (response.status === 200) {
29
+ console.log(`Server ready at ${url} after ${i + 1} attempts`)
30
+ return true
31
+ }
32
+ console.log(`Server not ready yet (attempt ${i + 1}), status: ${response.status}`)
33
+ } catch {
34
+ console.log(`Server connection failed (attempt ${i + 1})`)
35
+ }
36
+ // Wait 6 seconds between attempts
37
+ await new Promise(resolve => setTimeout(resolve, 6000))
38
+ }
39
+ return false
40
+ }
41
+
42
+ /**
43
+ * Initialize MCP clients for API calls
44
+ * This uses the already running persistent SSE servers
45
+ */
46
+ export async function initializeMCPClients(
47
+ mcpServers: MCPServerConfig[] = [],
48
+ abortSignal?: AbortSignal
49
+ ): Promise<MCPClientManager> {
50
+ // Initialize tools
51
+ let tools = {};
52
+ const mcpClients: any[] = [];
53
+
54
+ // Process each MCP server configuration
55
+ for (const mcpServer of mcpServers) {
56
+ try {
57
+ // All servers are handled as SSE
58
+ const transport = {
59
+ type: 'sse' as const,
60
+ url: mcpServer.url,
61
+ headers: mcpServer.headers?.reduce((acc, header) => {
62
+ if (header.key) acc[header.key] = header.value || '';
63
+ return acc;
64
+ }, {} as Record<string, string>)
65
+ };
66
+
67
+ const mcpClient = await createMCPClient({ transport });
68
+ mcpClients.push(mcpClient);
69
+
70
+ const mcptools = await mcpClient.tools();
71
+
72
+ console.log(`MCP tools from ${mcpServer.url}:`, Object.keys(mcptools));
73
+
74
+ // Add MCP tools to tools object
75
+ tools = { ...tools, ...mcptools };
76
+ } catch (error) {
77
+ console.error("Failed to initialize MCP client:", error);
78
+ // Continue with other servers instead of failing the entire request
79
+ }
80
+ }
81
+
82
+ // Register cleanup for all clients if an abort signal is provided
83
+ if (abortSignal && mcpClients.length > 0) {
84
+ abortSignal.addEventListener('abort', async () => {
85
+ await cleanupMCPClients(mcpClients);
86
+ });
87
+ }
88
+
89
+ return {
90
+ tools,
91
+ clients: mcpClients,
92
+ cleanup: async () => await cleanupMCPClients(mcpClients)
93
+ };
94
+ }
95
+
96
+ async function cleanupMCPClients(clients: any[]): Promise<void> {
97
+ // Clean up the MCP clients
98
+ for (const client of clients) {
99
+ try {
100
+ await client.close();
101
+ } catch (error) {
102
+ console.error("Error closing MCP client:", error);
103
+ }
104
+ }
105
+ }
lib/mcp-sandbox.ts ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // import Sandbox from "@e2b/code-interpreter";
2
+ import { Daytona, Sandbox, SandboxTargetRegion } from "@daytonaio/sdk";
3
+
4
+ export const startMcpSandbox = async ({
5
+ cmd,
6
+ envs = {},
7
+ }: {
8
+ cmd: string
9
+ envs?: Record<string, string>
10
+ }) => {
11
+ console.log("Creating sandbox...");
12
+ const daytona = new Daytona();
13
+ const sandbox = await daytona.create({
14
+ resources: {
15
+ cpu: 2,
16
+ memory: 4,
17
+ disk: 5,
18
+ },
19
+ public: true,
20
+ autoStopInterval: 0, // 24 hours
21
+ timeout: 1000 * 300, // 5 minutes
22
+ envVars: {
23
+ ...envs,
24
+ },
25
+ });
26
+
27
+ const host = await sandbox.getPreviewLink(3000);
28
+ const url = host.url;
29
+ const token = host.token;
30
+ console.log("url", url);
31
+ console.log("token", token);
32
+
33
+ const sessionId = Math.random().toString(36).substring(2, 30);
34
+ await sandbox.process.createSession(sessionId);
35
+ // python -m mcp_server_time --local-timezone=Asia/Kolkata
36
+ const isPythonCommand = cmd.startsWith('python') || cmd.startsWith('python3');
37
+ let installResult = null;
38
+
39
+ if (isPythonCommand) {
40
+ const packageName = cmd.split("-m ")[1]?.split(" ")[0] || "";
41
+ if (packageName) {
42
+ console.log(`Installing Python package: ${packageName}`);
43
+ const installUv = await sandbox.process.executeSessionCommand(sessionId, {
44
+ // Install python package from the command after -m in the command
45
+ command: `pip install ${packageName}`,
46
+ runAsync: true,
47
+ },
48
+ 1000 * 300 // 5 minutes
49
+ );
50
+ console.log("install result", installUv.output);
51
+ if (installUv.exitCode !== 0) {
52
+ console.error("Failed to install package");
53
+ }
54
+ installResult = installUv;
55
+ }
56
+ }
57
+
58
+ console.log("Starting mcp server...");
59
+ // generate a session with random id
60
+ const mcpServer = await sandbox.process.executeSessionCommand(sessionId,
61
+ {
62
+ command: `npx -y supergateway --base-url ${url} --header "x-daytona-preview-token: ${token}" --port 3000 --cors --stdio "${cmd}"`,
63
+ runAsync: true,
64
+ },
65
+ 1000 * 300 // 5 minutes
66
+ );
67
+ console.log("mcp server result", mcpServer.output);
68
+ const session = await sandbox.process.getSession(sessionId);
69
+ console.log(`Session ${sessionId}:`);
70
+ for (const command of session.commands || []) {
71
+ console.log(`Command: ${command.command}, Exit Code: ${command.exitCode}`);
72
+ }
73
+ if (mcpServer.exitCode !== 0) {
74
+ console.error("Failed to start mcp server. Exit code:", mcpServer.exitCode);
75
+ }
76
+
77
+ console.log("MCP server started at:", url + "/sse");
78
+ return new McpSandbox(sandbox);
79
+ }
80
+
81
+ class McpSandbox {
82
+ public sandbox: Sandbox;
83
+
84
+ constructor(sandbox: Sandbox) {
85
+ this.sandbox = sandbox;
86
+ }
87
+
88
+ async getUrl(): Promise<string> {
89
+ if (!this.sandbox) {
90
+ throw new Error("Sandbox not initialized");
91
+ }
92
+ const host = await this.sandbox.getPreviewLink(3000);
93
+ return `${host.url}/sse`;
94
+ }
95
+
96
+ async stop(): Promise<void> {
97
+ await this.sandbox.delete();
98
+ }
99
+ }
100
+
101
+ export type { McpSandbox };
package.json CHANGED
@@ -13,13 +13,14 @@
13
  "db:studio": "drizzle-kit studio"
14
  },
15
  "dependencies": {
16
- "@ai-sdk/anthropic": "^1.2.10",
17
- "@ai-sdk/cohere": "^1.2.9",
18
- "@ai-sdk/google": "^1.2.12",
19
- "@ai-sdk/groq": "^1.2.8",
20
- "@ai-sdk/openai": "^1.3.16",
21
- "@ai-sdk/react": "^1.2.9",
22
- "@ai-sdk/xai": "^1.2.14",
 
23
  "@neondatabase/serverless": "^1.0.0",
24
  "@radix-ui/react-accordion": "^1.2.7",
25
  "@radix-ui/react-avatar": "^1.1.6",
 
13
  "db:studio": "drizzle-kit studio"
14
  },
15
  "dependencies": {
16
+ "@ai-sdk/anthropic": "^1.2.11",
17
+ "@ai-sdk/google": "^1.2.17",
18
+ "@ai-sdk/groq": "^1.2.9",
19
+ "@ai-sdk/openai": "^1.3.22",
20
+ "@ai-sdk/react": "^1.2.12",
21
+ "@ai-sdk/xai": "^1.2.16",
22
+ "@daytonaio/sdk": "^0.17.0",
23
+ "@e2b/code-interpreter": "^1.5.0",
24
  "@neondatabase/serverless": "^1.0.0",
25
  "@radix-ui/react-accordion": "^1.2.7",
26
  "@radix-ui/react-avatar": "^1.1.6",
pnpm-lock.yaml CHANGED
@@ -9,26 +9,29 @@ importers:
9
  .:
10
  dependencies:
11
  '@ai-sdk/anthropic':
12
- specifier: ^1.2.10
13
- version: 1.2.10([email protected])
14
- '@ai-sdk/cohere':
15
- specifier: ^1.2.9
16
- version: 1.2.9([email protected])
17
  '@ai-sdk/google':
18
- specifier: ^1.2.12
19
- version: 1.2.12([email protected])
20
  '@ai-sdk/groq':
21
- specifier: ^1.2.8
22
- version: 1.2.8([email protected])
23
  '@ai-sdk/openai':
24
- specifier: ^1.3.16
25
- version: 1.3.16([email protected])
26
  '@ai-sdk/react':
27
- specifier: ^1.2.9
28
29
  '@ai-sdk/xai':
30
- specifier: ^1.2.14
31
- version: 1.2.14([email protected])
 
 
 
 
 
 
32
  '@neondatabase/serverless':
33
  specifier: ^1.0.0
34
  version: 1.0.0
@@ -186,44 +189,44 @@ importers:
186
 
187
  packages:
188
 
189
- '@ai-sdk/[email protected].10':
190
- resolution: {integrity: sha512-PyE7EC2fPjs9DnzRAHDrPQmcnI2m2Eojr8pfhckOejOlDEh2w7NnSJr1W3qe5hUWzKr+6d7NG1ZKR9fhmpDdEQ==}
191
  engines: {node: '>=18'}
192
  peerDependencies:
193
  zod: ^3.0.0
194
 
195
- '@ai-sdk/cohere@1.2.9':
196
- resolution: {integrity: sha512-ENbQT2bDt1FN+DOLkoFT9n+cojLv7zdN5GCaDtkaqJUuRa+6lHqNO4tRvB79Jg8DY03mhDermty9EhJW2zHoTA==}
197
  engines: {node: '>=18'}
198
  peerDependencies:
199
  zod: ^3.0.0
200
 
201
- '@ai-sdk/google@1.2.12':
202
- resolution: {integrity: sha512-A8AYqCmBs9SJFiAOP6AX0YEDHWTDrCaUDiRY2cdMSKjJiEknvwnPrAAKf3idgVqYaM2kS0qWz5v9v4pBzXDx+w==}
203
  engines: {node: '>=18'}
204
  peerDependencies:
205
  zod: ^3.0.0
206
 
207
- '@ai-sdk/groq@1.2.8':
208
- resolution: {integrity: sha512-DRq0b4twVUh52DFnIhVC4F14Po8w+76sCdigMRRIcAiSmGRr9I3Vyot36tun1q4tBZMYSvQUss60W3eiaoa6mg==}
209
  engines: {node: '>=18'}
210
  peerDependencies:
211
  zod: ^3.0.0
212
 
213
- '@ai-sdk/openai-compatible@0.2.12':
214
- resolution: {integrity: sha512-WGk3hTYMOkExgKqBZPWgow/2lp8JLYeJiiO/T/SxBa1NolxNcV+fPaZVvIyqeHGV0/AIXHqNtqI95CFblM47iA==}
215
  engines: {node: '>=18'}
216
  peerDependencies:
217
  zod: ^3.0.0
218
 
219
- '@ai-sdk/openai@1.3.16':
220
- resolution: {integrity: sha512-pjtiBKt1GgaSKZryTbM3tqgoegJwgAUlp1+X5uN6T+VPnI4FLSymV65tyloWzDlyqZmi9HXnnSRPu76VoL5D5g==}
221
  engines: {node: '>=18'}
222
  peerDependencies:
223
- zod: ^3.0.0
224
 
225
- '@ai-sdk/[email protected].7':
226
- resolution: {integrity: sha512-kM0xS3GWg3aMChh9zfeM+80vEZfXzR3JEUBdycZLtbRZ2TRT8xOj3WodGHPb06sUK5yD7pAXC/P7ctsi2fvUGQ==}
227
  engines: {node: '>=18'}
228
  peerDependencies:
229
  zod: ^3.23.8
@@ -232,6 +235,16 @@ packages:
232
  resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==}
233
  engines: {node: '>=18'}
234
 
 
 
 
 
 
 
 
 
 
 
235
  '@ai-sdk/[email protected]':
236
  resolution: {integrity: sha512-/VYm8xifyngaqFDLXACk/1czDRCefNCdALUyp+kIX6DUIYUWTM93ISoZ+qJ8+3E+FiJAKBQz61o8lIIl+vYtzg==}
237
  engines: {node: '>=18'}
@@ -242,14 +255,20 @@ packages:
242
  zod:
243
  optional: true
244
 
 
 
 
 
 
 
245
  '@ai-sdk/[email protected]':
246
  resolution: {integrity: sha512-nls/IJCY+ks3Uj6G/agNhXqQeLVqhNfoJbuNgCny+nX2veY5ADB91EcZUqVeQ/ionul2SeUswPY6Q/DxteY29Q==}
247
  engines: {node: '>=18'}
248
  peerDependencies:
249
  zod: ^3.23.8
250
 
251
- '@ai-sdk/[email protected].14':
252
- resolution: {integrity: sha512-ZxGjI/D1heIOX6XqyAwrqyBSkICP2mge2La7qHmr5RRcqw9+vWU+2cAg2y1FqCw8FpN/pGFZI81Dm473cYwlpg==}
253
  engines: {node: '>=18'}
254
  peerDependencies:
255
  zod: ^3.0.0
@@ -262,12 +281,46 @@ packages:
262
  resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==}
263
  engines: {node: '>=6.9.0'}
264
 
 
 
 
265
  '@cloudflare/[email protected]':
266
  resolution: {integrity: sha512-uu8gZ8P6teFsyfJOIXBrNC4ZsjLWPUEMeDqbQCdJ8OA6Rs/8QoUYD7ZSLW2kxsO/6upcbZir1WGrWp8088aVWg==}
267
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  '@drizzle-team/[email protected]':
269
  resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==}
270
 
 
 
 
 
 
 
 
 
 
 
271
  '@emnapi/[email protected]':
272
  resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==}
273
 
@@ -815,6 +868,18 @@ packages:
815
  cpu: [x64]
816
  os: [win32]
817
 
 
 
 
 
 
 
 
 
 
 
 
 
818
  '@nodelib/[email protected]':
819
  resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
820
  engines: {node: '>= 8'}
@@ -1827,6 +1892,9 @@ packages:
1827
  resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==}
1828
  engines: {node: '>=4'}
1829
 
 
 
 
1830
1831
  resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
1832
  engines: {node: '>= 0.4'}
@@ -1927,6 +1995,13 @@ packages:
1927
1928
  resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
1929
 
 
 
 
 
 
 
 
1930
1931
  resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
1932
 
@@ -2113,6 +2188,14 @@ packages:
2113
  resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
2114
  engines: {node: '>= 0.4'}
2115
 
 
 
 
 
 
 
 
 
2116
2117
  resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
2118
 
@@ -2298,6 +2381,10 @@ packages:
2298
  resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
2299
  engines: {node: '>=6'}
2300
 
 
 
 
 
2301
2302
  resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
2303
 
@@ -2348,6 +2435,15 @@ packages:
2348
2349
  resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
2350
 
 
 
 
 
 
 
 
 
 
2351
2352
  resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
2353
  engines: {node: '>= 0.4'}
@@ -2399,6 +2495,10 @@ packages:
2399
  resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
2400
  engines: {node: '>= 0.4'}
2401
 
 
 
 
 
2402
2403
  resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
2404
  engines: {node: '>= 0.4'}
@@ -2471,6 +2571,10 @@ packages:
2471
2472
  resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==}
2473
 
 
 
 
 
2474
2475
  resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
2476
 
@@ -2587,6 +2691,10 @@ packages:
2587
  resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
2588
  engines: {node: '>= 0.4'}
2589
 
 
 
 
 
2590
2591
  resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
2592
  engines: {node: '>= 0.4'}
@@ -2617,6 +2725,10 @@ packages:
2617
2618
  resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
2619
 
 
 
 
 
2620
2621
  resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==}
2622
  engines: {node: '>= 0.4'}
@@ -2813,6 +2925,9 @@ packages:
2813
2814
  resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
2815
 
 
 
 
2816
2817
  resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
2818
  engines: {node: '>= 8'}
@@ -2913,6 +3028,10 @@ packages:
2913
  resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
2914
  engines: {node: '>= 0.6'}
2915
 
 
 
 
 
2916
2917
  resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
2918
 
@@ -3013,6 +3132,10 @@ packages:
3013
  encoding:
3014
  optional: true
3015
 
 
 
 
 
3016
3017
  resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==}
3018
 
@@ -3032,6 +3155,10 @@ packages:
3032
  resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
3033
  engines: {node: '>= 0.4'}
3034
 
 
 
 
 
3035
3036
  resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
3037
  engines: {node: '>= 0.4'}
@@ -3059,6 +3186,16 @@ packages:
3059
  resolution: {integrity: sha512-y0W+X7Ppo7oZX6eovsRkuzcSM40Bicg2JEJkDJ4irIt1wsYAP5MLSNv+QAogO8xivMffw/9OvV3um1pxXgt1uA==}
3060
  engines: {node: ^10.13.0 || >=12.0.0}
3061
 
 
 
 
 
 
 
 
 
 
 
3062
3063
  resolution: {integrity: sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==}
3064
 
@@ -3152,6 +3289,9 @@ packages:
3152
  resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
3153
  engines: {node: '>=12'}
3154
 
 
 
 
3155
3156
  resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
3157
  engines: {node: '>= 0.4'}
@@ -3220,6 +3360,9 @@ packages:
3220
3221
  resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==}
3222
 
 
 
 
3223
3224
  resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
3225
  engines: {node: '>=6'}
@@ -3388,6 +3531,9 @@ packages:
3388
  resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
3389
  engines: {node: '>= 0.4'}
3390
 
 
 
 
3391
3392
  resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
3393
 
@@ -3452,6 +3598,10 @@ packages:
3452
  resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
3453
  engines: {node: '>=4'}
3454
 
 
 
 
 
3455
3456
  resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
3457
  engines: {node: '>=8'}
@@ -3620,6 +3770,10 @@ packages:
3620
  peerDependencies:
3621
  react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
3622
 
 
 
 
 
3623
3624
  resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
3625
  hasBin: true
@@ -3661,6 +3815,11 @@ packages:
3661
  engines: {node: '>= 8'}
3662
  hasBin: true
3663
 
 
 
 
 
 
3664
3665
  resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
3666
  engines: {node: '>=0.10.0'}
@@ -3689,43 +3848,44 @@ packages:
3689
 
3690
  snapshots:
3691
 
3692
3693
  dependencies:
3694
  '@ai-sdk/provider': 1.1.3
3695
- '@ai-sdk/provider-utils': 2.2.7([email protected])
3696
  zod: 3.24.2
3697
 
3698
- '@ai-sdk/cohere@1.2.9([email protected])':
3699
  dependencies:
3700
  '@ai-sdk/provider': 1.1.3
3701
- '@ai-sdk/provider-utils': 2.2.7([email protected])
3702
  zod: 3.24.2
3703
 
3704
- '@ai-sdk/google@1.2.12([email protected])':
3705
  dependencies:
3706
  '@ai-sdk/provider': 1.1.3
3707
- '@ai-sdk/provider-utils': 2.2.7([email protected])
3708
  zod: 3.24.2
3709
 
3710
- '@ai-sdk/groq@1.2.8([email protected])':
3711
  dependencies:
3712
  '@ai-sdk/provider': 1.1.3
3713
- '@ai-sdk/provider-utils': 2.2.7([email protected])
3714
  zod: 3.24.2
3715
 
3716
- '@ai-sdk/openai-compatible@0.2.12([email protected])':
3717
  dependencies:
3718
  '@ai-sdk/provider': 1.1.3
3719
- '@ai-sdk/provider-utils': 2.2.7([email protected])
3720
  zod: 3.24.2
3721
 
3722
- '@ai-sdk/openai@1.3.16([email protected])':
3723
  dependencies:
3724
  '@ai-sdk/provider': 1.1.3
3725
- '@ai-sdk/provider-utils': 2.2.7(zod@3.24.2)
 
3726
  zod: 3.24.2
3727
 
3728
3729
  dependencies:
3730
  '@ai-sdk/provider': 1.1.3
3731
  nanoid: 3.3.11
@@ -3736,6 +3896,16 @@ snapshots:
3736
  dependencies:
3737
  json-schema: 0.4.0
3738
 
 
 
 
 
 
 
 
 
 
 
3739
3740
  dependencies:
3741
  '@ai-sdk/provider-utils': 2.2.7([email protected])
@@ -3746,6 +3916,13 @@ snapshots:
3746
  optionalDependencies:
3747
  zod: 3.24.2
3748
 
 
 
 
 
 
 
 
3749
3750
  dependencies:
3751
  '@ai-sdk/provider': 1.1.3
@@ -3753,11 +3930,11 @@ snapshots:
3753
  zod: 3.24.2
3754
  zod-to-json-schema: 3.24.5([email protected])
3755
 
3756
3757
  dependencies:
3758
- '@ai-sdk/openai-compatible': 0.2.12([email protected])
3759
  '@ai-sdk/provider': 1.1.3
3760
- '@ai-sdk/provider-utils': 2.2.7([email protected])
3761
  zod: 3.24.2
3762
 
3763
  '@alloc/[email protected]': {}
@@ -3766,11 +3943,57 @@ snapshots:
3766
  dependencies:
3767
  regenerator-runtime: 0.14.1
3768
 
 
 
3769
  '@cloudflare/[email protected]':
3770
  optional: true
3771
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3772
  '@drizzle-team/[email protected]': {}
3773
 
 
 
 
 
 
 
 
 
3774
  '@emnapi/[email protected]':
3775
  dependencies:
3776
  '@emnapi/wasi-threads': 1.0.2
@@ -4136,6 +4359,14 @@ snapshots:
4136
  '@next/[email protected]':
4137
  optional: true
4138
 
 
 
 
 
 
 
 
 
4139
  '@nodelib/[email protected]':
4140
  dependencies:
4141
  '@nodelib/fs.stat': 2.0.5
@@ -5133,6 +5364,14 @@ snapshots:
5133
 
5134
5135
 
 
 
 
 
 
 
 
 
5136
5137
 
5138
@@ -5228,6 +5467,10 @@ snapshots:
5228
 
5229
5230
 
 
 
 
 
5231
5232
 
5233
@@ -5329,6 +5572,22 @@ snapshots:
5329
  es-errors: 1.3.0
5330
  gopd: 1.2.0
5331
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5332
5333
 
5334
@@ -5699,6 +5958,18 @@ snapshots:
5699
 
5700
5701
 
 
 
 
 
 
 
 
 
 
 
 
 
5702
5703
 
5704
@@ -5751,6 +6022,8 @@ snapshots:
5751
 
5752
5753
 
 
 
5754
5755
  dependencies:
5756
  is-callable: 1.2.7
@@ -5811,6 +6084,8 @@ snapshots:
5811
  dunder-proto: 1.0.1
5812
  es-object-atoms: 1.1.1
5813
 
 
 
5814
5815
  dependencies:
5816
  call-bound: 1.0.4
@@ -5902,6 +6177,8 @@ snapshots:
5902
 
5903
5904
 
 
 
5905
5906
  dependencies:
5907
  ms: 2.1.3
@@ -6022,6 +6299,8 @@ snapshots:
6022
  dependencies:
6023
  call-bound: 1.0.4
6024
 
 
 
6025
6026
  dependencies:
6027
  call-bound: 1.0.4
@@ -6052,6 +6331,8 @@ snapshots:
6052
 
6053
6054
 
 
 
6055
6056
  dependencies:
6057
  define-data-property: 1.1.4
@@ -6333,6 +6614,8 @@ snapshots:
6333
  dependencies:
6334
  '@types/mdast': 4.0.4
6335
 
 
 
6336
6337
 
6338
@@ -6537,6 +6820,8 @@ snapshots:
6537
  dependencies:
6538
  mime-db: 1.52.0
6539
 
 
 
6540
6541
  dependencies:
6542
  brace-expansion: 1.1.11
@@ -6621,6 +6906,10 @@ snapshots:
6621
  dependencies:
6622
  whatwg-url: 5.0.0
6623
 
 
 
 
 
6624
6625
 
6626
@@ -6631,6 +6920,8 @@ snapshots:
6631
 
6632
6633
 
 
 
6634
6635
  dependencies:
6636
  call-bind: 1.0.8
@@ -6671,6 +6962,16 @@ snapshots:
6671
 
6672
6673
 
 
 
 
 
 
 
 
 
 
 
6674
6675
  dependencies:
6676
  jose: 4.15.9
@@ -6776,6 +7077,8 @@ snapshots:
6776
 
6777
6778
 
 
 
6779
6780
 
6781
@@ -6831,6 +7134,8 @@ snapshots:
6831
 
6832
6833
 
 
 
6834
6835
 
6836
@@ -7078,6 +7383,8 @@ snapshots:
7078
  side-channel-map: 1.0.1
7079
  side-channel-weakmap: 1.0.2
7080
 
 
 
7081
7082
  dependencies:
7083
  is-arrayish: 0.3.2
@@ -7162,6 +7469,8 @@ snapshots:
7162
 
7163
7164
 
 
 
7165
7166
 
7167
@@ -7354,6 +7663,8 @@ snapshots:
7354
  dependencies:
7355
  react: 19.1.0
7356
 
 
 
7357
7358
 
7359
@@ -7420,6 +7731,10 @@ snapshots:
7420
  dependencies:
7421
  isexe: 2.0.0
7422
 
 
 
 
 
7423
7424
 
7425
 
9
  .:
10
  dependencies:
11
  '@ai-sdk/anthropic':
12
+ specifier: ^1.2.11
13
+ version: 1.2.11([email protected])
 
 
 
14
  '@ai-sdk/google':
15
+ specifier: ^1.2.17
16
+ version: 1.2.17([email protected])
17
  '@ai-sdk/groq':
18
+ specifier: ^1.2.9
19
+ version: 1.2.9([email protected])
20
  '@ai-sdk/openai':
21
+ specifier: ^1.3.22
22
+ version: 1.3.22([email protected])
23
  '@ai-sdk/react':
24
+ specifier: ^1.2.12
25
26
  '@ai-sdk/xai':
27
+ specifier: ^1.2.16
28
+ version: 1.2.16([email protected])
29
+ '@daytonaio/sdk':
30
+ specifier: ^0.17.0
31
+ version: 0.17.0
32
+ '@e2b/code-interpreter':
33
+ specifier: ^1.5.0
34
+ version: 1.5.0
35
  '@neondatabase/serverless':
36
  specifier: ^1.0.0
37
  version: 1.0.0
 
189
 
190
  packages:
191
 
192
+ '@ai-sdk/[email protected].11':
193
+ resolution: {integrity: sha512-lZLcEMh8MXY4NVSrN/7DyI2rnid8k7cn/30nMmd3bwJrnIsOuIuuFvY8f0nj+pFcTi6AYK7ujLdqW5dQVz1YQw==}
194
  engines: {node: '>=18'}
195
  peerDependencies:
196
  zod: ^3.0.0
197
 
198
+ '@ai-sdk/google@1.2.17':
199
+ resolution: {integrity: sha512-mLFLDMCJaDK+j1nvoqeNszazSZIyeSMPi5X+fs5Wh3xWZljGGE0WmFg32RNkFujRB+UnM63EnhPG70WdqOx/MA==}
200
  engines: {node: '>=18'}
201
  peerDependencies:
202
  zod: ^3.0.0
203
 
204
+ '@ai-sdk/groq@1.2.9':
205
+ resolution: {integrity: sha512-7MoDaxm8yWtiRbD1LipYZG0kBl+Xe0sv/EeyxnHnGPZappXdlgtdOgTZVjjXkT3nWP30jjZi9A45zoVrBMb3Xg==}
206
  engines: {node: '>=18'}
207
  peerDependencies:
208
  zod: ^3.0.0
209
 
210
+ '@ai-sdk/openai-compatible@0.2.14':
211
+ resolution: {integrity: sha512-icjObfMCHKSIbywijaoLdZ1nSnuRnWgMEMLgwoxPJgxsUHMx0aVORnsLUid4SPtdhHI3X2masrt6iaEQLvOSFw==}
212
  engines: {node: '>=18'}
213
  peerDependencies:
214
  zod: ^3.0.0
215
 
216
+ '@ai-sdk/openai@1.3.22':
217
+ resolution: {integrity: sha512-QwA+2EkG0QyjVR+7h6FE7iOu2ivNqAVMm9UJZkVxxTk5OIq5fFJDTEI/zICEMuHImTTXR2JjsL6EirJ28Jc4cw==}
218
  engines: {node: '>=18'}
219
  peerDependencies:
220
  zod: ^3.0.0
221
 
222
+ '@ai-sdk/provider-utils@2.2.7':
223
+ resolution: {integrity: sha512-kM0xS3GWg3aMChh9zfeM+80vEZfXzR3JEUBdycZLtbRZ2TRT8xOj3WodGHPb06sUK5yD7pAXC/P7ctsi2fvUGQ==}
224
  engines: {node: '>=18'}
225
  peerDependencies:
226
+ zod: ^3.23.8
227
 
228
+ '@ai-sdk/[email protected].8':
229
+ resolution: {integrity: sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==}
230
  engines: {node: '>=18'}
231
  peerDependencies:
232
  zod: ^3.23.8
 
235
  resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==}
236
  engines: {node: '>=18'}
237
 
238
+ '@ai-sdk/[email protected]':
239
+ resolution: {integrity: sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==}
240
+ engines: {node: '>=18'}
241
+ peerDependencies:
242
+ react: ^18 || ^19 || ^19.0.0-rc
243
+ zod: ^3.23.8
244
+ peerDependenciesMeta:
245
+ zod:
246
+ optional: true
247
+
248
  '@ai-sdk/[email protected]':
249
  resolution: {integrity: sha512-/VYm8xifyngaqFDLXACk/1czDRCefNCdALUyp+kIX6DUIYUWTM93ISoZ+qJ8+3E+FiJAKBQz61o8lIIl+vYtzg==}
250
  engines: {node: '>=18'}
 
255
  zod:
256
  optional: true
257
 
258
+ '@ai-sdk/[email protected]':
259
+ resolution: {integrity: sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==}
260
+ engines: {node: '>=18'}
261
+ peerDependencies:
262
+ zod: ^3.23.8
263
+
264
  '@ai-sdk/[email protected]':
265
  resolution: {integrity: sha512-nls/IJCY+ks3Uj6G/agNhXqQeLVqhNfoJbuNgCny+nX2veY5ADB91EcZUqVeQ/ionul2SeUswPY6Q/DxteY29Q==}
266
  engines: {node: '>=18'}
267
  peerDependencies:
268
  zod: ^3.23.8
269
 
270
+ '@ai-sdk/[email protected].16':
271
+ resolution: {integrity: sha512-UOZT8td9PWwMi2dF9a0U44t/Oltmf6QmIJdSvrOcLG4mvpRc1UJn6YJaR0HtXs3YnW6SvY1zRdIDrW4GFpv4NA==}
272
  engines: {node: '>=18'}
273
  peerDependencies:
274
  zod: ^3.0.0
 
281
  resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==}
282
  engines: {node: '>=6.9.0'}
283
 
284
+ '@bufbuild/[email protected]':
285
+ resolution: {integrity: sha512-WK6zH4MtBp/uesX8KGCnwDDRVnEVHUvwjsigKXcSR57Oo8Oyv1vRS9qyUlSP+6KWRl5z8tNAU5qpf3QodeVYxA==}
286
+
287
  '@cloudflare/[email protected]':
288
  resolution: {integrity: sha512-uu8gZ8P6teFsyfJOIXBrNC4ZsjLWPUEMeDqbQCdJ8OA6Rs/8QoUYD7ZSLW2kxsO/6upcbZir1WGrWp8088aVWg==}
289
 
290
+ '@connectrpc/[email protected]':
291
+ resolution: {integrity: sha512-w88P8Lsn5CCsA7MFRl2e6oLY4J/5toiNtJns/YJrlyQaWOy3RO8pDgkz+iIkG98RPMhj2thuBvsd3Cn4DKKCkw==}
292
+ peerDependencies:
293
+ '@bufbuild/protobuf': ^2.2.0
294
+ '@connectrpc/connect': 2.0.0-rc.3
295
+
296
+ '@connectrpc/[email protected]':
297
+ resolution: {integrity: sha512-ARBt64yEyKbanyRETTjcjJuHr2YXorzQo0etyS5+P6oSeW8xEuzajA9g+zDnMcj1hlX2dQE93foIWQGfpru7gQ==}
298
+ peerDependencies:
299
+ '@bufbuild/protobuf': ^2.2.0
300
+
301
+ '@daytonaio/[email protected]':
302
+ resolution: {integrity: sha512-XvnvZkS/i207CxvVR8LuyUkmsCj0Z202l6SD/G9TnUl15PJsmu3OuOQcUJ/PjS1bhaGzKDvEOlHJGZHMwCDAVg==}
303
+
304
+ '@daytonaio/[email protected]':
305
+ resolution: {integrity: sha512-1tolkjpAsW0Byqvf6C0SYMr6yEM/v4MkEjrcIK3w13J1c2zM9ubRtzNC6/b9zWnLapX19SaWsMIzVLFfOjRmsg==}
306
+
307
+ '@dotenvx/[email protected]':
308
+ resolution: {integrity: sha512-Z8XjM75aWZ/ekUzBjlr/OqQsLWtJY4nVtruxopAt+FlYHfY0/gKl85nD16aEqbTkU53kJcm5psID0L2/sQMmuw==}
309
+ hasBin: true
310
+
311
  '@drizzle-team/[email protected]':
312
  resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==}
313
 
314
+ '@e2b/[email protected]':
315
+ resolution: {integrity: sha512-9uO8Q5Hfhi6f2rSt0lcshLyhNF6pfh+36StE1dO8RrcMwi3F7MNSyWhKm0/KV9AJjviLZ8lSFFlwXi5/iKyLEA==}
316
+ engines: {node: '>=18'}
317
+
318
+ '@ecies/[email protected]':
319
+ resolution: {integrity: sha512-tapn6XhOueMwht3E2UzY0ZZjYokdaw9XtL9kEyjhQ/Fb9vL9xTFbOaI+fV0AWvTpYu4BNloC6getKW6NtSg4mA==}
320
+ engines: {bun: '>=1', deno: '>=2', node: '>=16'}
321
+ peerDependencies:
322
+ '@noble/ciphers': ^1.0.0
323
+
324
  '@emnapi/[email protected]':
325
  resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==}
326
 
 
868
  cpu: [x64]
869
  os: [win32]
870
 
871
+ '@noble/[email protected]':
872
+ resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==}
873
+ engines: {node: ^14.21.3 || >=16}
874
+
875
+ '@noble/[email protected]':
876
+ resolution: {integrity: sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==}
877
+ engines: {node: ^14.21.3 || >=16}
878
+
879
+ '@noble/[email protected]':
880
+ resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==}
881
+ engines: {node: ^14.21.3 || >=16}
882
+
883
  '@nodelib/[email protected]':
884
  resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
885
  engines: {node: '>= 8'}
 
1892
  resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==}
1893
  engines: {node: '>=4'}
1894
 
1895
1896
+ resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==}
1897
+
1898
1899
  resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
1900
  engines: {node: '>= 0.4'}
 
1995
1996
  resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
1997
 
1998
1999
+ resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
2000
+ engines: {node: '>=16'}
2001
+
2002
2003
+ resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==}
2004
+
2005
2006
  resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
2007
 
 
2188
  resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
2189
  engines: {node: '>= 0.4'}
2190
 
2191
2192
+ resolution: {integrity: sha512-KGe5F5UI+1PZ82OBjPHsYqpbw33ck7j0xgcJRSS56mAOWMX/Z6xllXqbZj66Xg6kkO32GmSGXjCAZL4FMSfyug==}
2193
+ engines: {node: '>=18'}
2194
+
2195
2196
+ resolution: {integrity: sha512-eJAgf9pdv214Hn98FlUzclRMYWF7WfoLlkS9nWMTm1qcCwn6Ad4EGD9lr9HXMBfSrZhYQujRE+p0adPRkctC6A==}
2197
+ engines: {bun: '>=1', deno: '>=2', node: '>=16'}
2198
+
2199
2200
  resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
2201
 
 
2381
  resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
2382
  engines: {node: '>=6'}
2383
 
2384
2385
+ resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
2386
+ engines: {node: '>=10'}
2387
+
2388
2389
  resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
2390
 
 
2435
2436
  resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
2437
 
2438
2439
+ resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
2440
+ engines: {node: '>=4.0'}
2441
+ peerDependencies:
2442
+ debug: '*'
2443
+ peerDependenciesMeta:
2444
+ debug:
2445
+ optional: true
2446
+
2447
2448
  resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
2449
  engines: {node: '>= 0.4'}
 
2495
  resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
2496
  engines: {node: '>= 0.4'}
2497
 
2498
2499
+ resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
2500
+ engines: {node: '>=10'}
2501
+
2502
2503
  resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}
2504
  engines: {node: '>= 0.4'}
 
2571
2572
  resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==}
2573
 
2574
2575
+ resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
2576
+ engines: {node: '>=10.17.0'}
2577
+
2578
2579
  resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
2580
 
 
2691
  resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
2692
  engines: {node: '>= 0.4'}
2693
 
2694
2695
+ resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
2696
+ engines: {node: '>=8'}
2697
+
2698
2699
  resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
2700
  engines: {node: '>= 0.4'}
 
2725
2726
  resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
2727
 
2728
2729
+ resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==}
2730
+ engines: {node: '>=16'}
2731
+
2732
2733
  resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==}
2734
  engines: {node: '>= 0.4'}
 
2925
2926
  resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
2927
 
2928
2929
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
2930
+
2931
2932
  resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
2933
  engines: {node: '>= 8'}
 
3028
  resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
3029
  engines: {node: '>= 0.6'}
3030
 
3031
3032
+ resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
3033
+ engines: {node: '>=6'}
3034
+
3035
3036
  resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
3037
 
 
3132
  encoding:
3133
  optional: true
3134
 
3135
3136
+ resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
3137
+ engines: {node: '>=8'}
3138
+
3139
3140
  resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==}
3141
 
 
3155
  resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
3156
  engines: {node: '>= 0.4'}
3157
 
3158
3159
+ resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==}
3160
+ engines: {node: '>= 10'}
3161
+
3162
3163
  resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}
3164
  engines: {node: '>= 0.4'}
 
3186
  resolution: {integrity: sha512-y0W+X7Ppo7oZX6eovsRkuzcSM40Bicg2JEJkDJ4irIt1wsYAP5MLSNv+QAogO8xivMffw/9OvV3um1pxXgt1uA==}
3187
  engines: {node: ^10.13.0 || >=12.0.0}
3188
 
3189
3190
+ resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
3191
+ engines: {node: '>=6'}
3192
+
3193
3194
+ resolution: {integrity: sha512-zM6elH0EZStD/gSiNlcPrzXcVQ/pZo3BDvC6CDwRDUt1dDzxlshpmQnpD6cZaJ39THaSmwVCxxRrPKNM1hHrDg==}
3195
+
3196
3197
+ resolution: {integrity: sha512-1eNjQtbfNi5Z/kFhagDIaIRj6qqDzhjNJKz8cmMW0CVdGwT6e1GLbAfgI0d28VTJa1A8jz82jm/4dG8qNoNS8g==}
3198
+
3199
3200
  resolution: {integrity: sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==}
3201
 
 
3289
  resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
3290
  engines: {node: '>=12'}
3291
 
3292
3293
+ resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==}
3294
+
3295
3296
  resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
3297
  engines: {node: '>= 0.4'}
 
3360
3361
  resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==}
3362
 
3363
3364
+ resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
3365
+
3366
3367
  resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
3368
  engines: {node: '>=6'}
 
3531
  resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
3532
  engines: {node: '>= 0.4'}
3533
 
3534
3535
+ resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
3536
+
3537
3538
  resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
3539
 
 
3598
  resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
3599
  engines: {node: '>=4'}
3600
 
3601
3602
+ resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
3603
+ engines: {node: '>=6'}
3604
+
3605
3606
  resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
3607
  engines: {node: '>=8'}
 
3770
  peerDependencies:
3771
  react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
3772
 
3773
3774
+ resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==}
3775
+ hasBin: true
3776
+
3777
3778
  resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
3779
  hasBin: true
 
3815
  engines: {node: '>= 8'}
3816
  hasBin: true
3817
 
3818
3819
+ resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==}
3820
+ engines: {node: ^16.13.0 || >=18.0.0}
3821
+ hasBin: true
3822
+
3823
3824
  resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
3825
  engines: {node: '>=0.10.0'}
 
3848
 
3849
  snapshots:
3850
 
3851
3852
  dependencies:
3853
  '@ai-sdk/provider': 1.1.3
3854
+ '@ai-sdk/provider-utils': 2.2.8([email protected])
3855
  zod: 3.24.2
3856
 
3857
+ '@ai-sdk/google@1.2.17([email protected])':
3858
  dependencies:
3859
  '@ai-sdk/provider': 1.1.3
3860
+ '@ai-sdk/provider-utils': 2.2.8([email protected])
3861
  zod: 3.24.2
3862
 
3863
+ '@ai-sdk/groq@1.2.9([email protected])':
3864
  dependencies:
3865
  '@ai-sdk/provider': 1.1.3
3866
+ '@ai-sdk/provider-utils': 2.2.8([email protected])
3867
  zod: 3.24.2
3868
 
3869
+ '@ai-sdk/openai-compatible@0.2.14([email protected])':
3870
  dependencies:
3871
  '@ai-sdk/provider': 1.1.3
3872
+ '@ai-sdk/provider-utils': 2.2.8([email protected])
3873
  zod: 3.24.2
3874
 
3875
+ '@ai-sdk/openai@1.3.22([email protected])':
3876
  dependencies:
3877
  '@ai-sdk/provider': 1.1.3
3878
+ '@ai-sdk/provider-utils': 2.2.8([email protected])
3879
  zod: 3.24.2
3880
 
3881
+ '@ai-sdk/provider-utils@2.2.7([email protected])':
3882
  dependencies:
3883
  '@ai-sdk/provider': 1.1.3
3884
+ nanoid: 3.3.11
3885
+ secure-json-parse: 2.7.0
3886
  zod: 3.24.2
3887
 
3888
3889
  dependencies:
3890
  '@ai-sdk/provider': 1.1.3
3891
  nanoid: 3.3.11
 
3896
  dependencies:
3897
  json-schema: 0.4.0
3898
 
3899
3900
+ dependencies:
3901
+ '@ai-sdk/provider-utils': 2.2.8([email protected])
3902
+ '@ai-sdk/ui-utils': 1.2.11([email protected])
3903
+ react: 19.1.0
3904
+ swr: 2.3.3([email protected])
3905
+ throttleit: 2.1.0
3906
+ optionalDependencies:
3907
+ zod: 3.24.2
3908
+
3909
3910
  dependencies:
3911
  '@ai-sdk/provider-utils': 2.2.7([email protected])
 
3916
  optionalDependencies:
3917
  zod: 3.24.2
3918
 
3919
3920
+ dependencies:
3921
+ '@ai-sdk/provider': 1.1.3
3922
+ '@ai-sdk/provider-utils': 2.2.8([email protected])
3923
+ zod: 3.24.2
3924
+ zod-to-json-schema: 3.24.5([email protected])
3925
+
3926
3927
  dependencies:
3928
  '@ai-sdk/provider': 1.1.3
 
3930
  zod: 3.24.2
3931
  zod-to-json-schema: 3.24.5([email protected])
3932
 
3933
3934
  dependencies:
3935
+ '@ai-sdk/openai-compatible': 0.2.14([email protected])
3936
  '@ai-sdk/provider': 1.1.3
3937
+ '@ai-sdk/provider-utils': 2.2.8([email protected])
3938
  zod: 3.24.2
3939
 
3940
  '@alloc/[email protected]': {}
 
3943
  dependencies:
3944
  regenerator-runtime: 0.14.1
3945
 
3946
+ '@bufbuild/[email protected]': {}
3947
+
3948
  '@cloudflare/[email protected]':
3949
  optional: true
3950
 
3951
+ '@connectrpc/[email protected](@bufbuild/[email protected])(@connectrpc/[email protected](@bufbuild/[email protected]))':
3952
+ dependencies:
3953
+ '@bufbuild/protobuf': 2.3.0
3954
+ '@connectrpc/connect': 2.0.0-rc.3(@bufbuild/[email protected])
3955
+
3956
+ '@connectrpc/[email protected](@bufbuild/[email protected])':
3957
+ dependencies:
3958
+ '@bufbuild/protobuf': 2.3.0
3959
+
3960
+ '@daytonaio/[email protected]':
3961
+ dependencies:
3962
+ axios: 1.9.0
3963
+ transitivePeerDependencies:
3964
+ - debug
3965
+
3966
+ '@daytonaio/[email protected]':
3967
+ dependencies:
3968
+ '@daytonaio/api-client': 0.18.1
3969
+ '@dotenvx/dotenvx': 1.43.0
3970
+ axios: 1.9.0
3971
+ uuid: 11.1.0
3972
+ transitivePeerDependencies:
3973
+ - debug
3974
+
3975
+ '@dotenvx/[email protected]':
3976
+ dependencies:
3977
+ commander: 11.1.0
3978
+ dotenv: 16.5.0
3979
+ eciesjs: 0.4.14
3980
+ execa: 5.1.1
3981
+ fdir: 6.4.3([email protected])
3982
+ ignore: 5.3.2
3983
+ object-treeify: 1.1.33
3984
+ picomatch: 4.0.2
3985
+ which: 4.0.0
3986
+
3987
  '@drizzle-team/[email protected]': {}
3988
 
3989
+ '@e2b/[email protected]':
3990
+ dependencies:
3991
+ e2b: 1.4.0
3992
+
3993
3994
+ dependencies:
3995
+ '@noble/ciphers': 1.3.0
3996
+
3997
  '@emnapi/[email protected]':
3998
  dependencies:
3999
  '@emnapi/wasi-threads': 1.0.2
 
4359
  '@next/[email protected]':
4360
  optional: true
4361
 
4362
+ '@noble/[email protected]': {}
4363
+
4364
+ '@noble/[email protected]':
4365
+ dependencies:
4366
+ '@noble/hashes': 1.8.0
4367
+
4368
+ '@noble/[email protected]': {}
4369
+
4370
  '@nodelib/[email protected]':
4371
  dependencies:
4372
  '@nodelib/fs.stat': 2.0.5
 
5364
 
5365
5366
 
5367
5368
+ dependencies:
5369
+ follow-redirects: 1.15.9
5370
+ form-data: 4.0.2
5371
+ proxy-from-env: 1.1.0
5372
+ transitivePeerDependencies:
5373
+ - debug
5374
+
5375
5376
 
5377
 
5467
 
5468
5469
 
5470
5471
+
5472
5473
+
5474
5475
 
5476
 
5572
  es-errors: 1.3.0
5573
  gopd: 1.2.0
5574
 
5575
5576
+ dependencies:
5577
+ '@bufbuild/protobuf': 2.3.0
5578
+ '@connectrpc/connect': 2.0.0-rc.3(@bufbuild/[email protected])
5579
+ '@connectrpc/connect-web': 2.0.0-rc.3(@bufbuild/[email protected])(@connectrpc/[email protected](@bufbuild/[email protected]))
5580
+ compare-versions: 6.1.1
5581
+ openapi-fetch: 0.9.8
5582
+ platform: 1.3.6
5583
+
5584
5585
+ dependencies:
5586
+ '@ecies/ciphers': 0.2.3(@noble/[email protected])
5587
+ '@noble/ciphers': 1.3.0
5588
+ '@noble/curves': 1.9.0
5589
+ '@noble/hashes': 1.8.0
5590
+
5591
5592
 
5593
 
5958
 
5959
5960
 
5961
5962
+ dependencies:
5963
+ cross-spawn: 7.0.6
5964
+ get-stream: 6.0.1
5965
+ human-signals: 2.1.0
5966
+ is-stream: 2.0.1
5967
+ merge-stream: 2.0.0
5968
+ npm-run-path: 4.0.1
5969
+ onetime: 5.1.2
5970
+ signal-exit: 3.0.7
5971
+ strip-final-newline: 2.0.0
5972
+
5973
5974
 
5975
 
6022
 
6023
6024
 
6025
6026
+
6027
6028
  dependencies:
6029
  is-callable: 1.2.7
 
6084
  dunder-proto: 1.0.1
6085
  es-object-atoms: 1.1.1
6086
 
6087
6088
+
6089
6090
  dependencies:
6091
  call-bound: 1.0.4
 
6177
 
6178
6179
 
6180
6181
+
6182
6183
  dependencies:
6184
  ms: 2.1.3
 
6299
  dependencies:
6300
  call-bound: 1.0.4
6301
 
6302
6303
+
6304
6305
  dependencies:
6306
  call-bound: 1.0.4
 
6331
 
6332
6333
 
6334
6335
+
6336
6337
  dependencies:
6338
  define-data-property: 1.1.4
 
6614
  dependencies:
6615
  '@types/mdast': 4.0.4
6616
 
6617
6618
+
6619
6620
 
6621
 
6820
  dependencies:
6821
  mime-db: 1.52.0
6822
 
6823
6824
+
6825
6826
  dependencies:
6827
  brace-expansion: 1.1.11
 
6906
  dependencies:
6907
  whatwg-url: 5.0.0
6908
 
6909
6910
+ dependencies:
6911
+ path-key: 3.1.1
6912
+
6913
6914
 
6915
 
6920
 
6921
6922
 
6923
6924
+
6925
6926
  dependencies:
6927
  call-bind: 1.0.8
 
6962
 
6963
6964
 
6965
6966
+ dependencies:
6967
+ mimic-fn: 2.1.0
6968
+
6969
6970
+ dependencies:
6971
+ openapi-typescript-helpers: 0.0.8
6972
+
6973
6974
+
6975
6976
  dependencies:
6977
  jose: 4.15.9
 
7077
 
7078
7079
 
7080
7081
+
7082
7083
 
7084
 
7134
 
7135
7136
 
7137
7138
+
7139
7140
 
7141
 
7383
  side-channel-map: 1.0.1
7384
  side-channel-weakmap: 1.0.2
7385
 
7386
7387
+
7388
7389
  dependencies:
7390
  is-arrayish: 0.3.2
 
7469
 
7470
7471
 
7472
7473
+
7474
7475
 
7476
 
7663
  dependencies:
7664
  react: 19.1.0
7665
 
7666
7667
+
7668
7669
 
7670
 
7731
  dependencies:
7732
  isexe: 2.0.0
7733
 
7734
7735
+ dependencies:
7736
+ isexe: 3.1.1
7737
+
7738
7739
 
7740