Spaces:
Running
Running
File size: 5,526 Bytes
5012205 dff2be9 a56be76 5012205 dff2be9 67c6e06 5012205 dff2be9 5012205 dff2be9 5012205 dff2be9 5012205 dff2be9 5012205 dff2be9 5012205 dff2be9 5012205 dff2be9 5012205 dff2be9 5012205 dff2be9 5012205 dff2be9 5012205 dff2be9 a56be76 dff2be9 5012205 dff2be9 5012205 dff2be9 5012205 dff2be9 5012205 67c6e06 dff2be9 0c91a71 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 0c91a71 dff2be9 0c91a71 dff2be9 0c91a71 dff2be9 0c91a71 dff2be9 0c91a71 dff2be9 0c91a71 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 0c91a71 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 dff2be9 67c6e06 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
"use server";
import { openai } from "@/lib/openai-client";
import { hf } from "@/lib/hf-client";
import { z } from "zod";
import { startMcpSandbox } from "@/lib/mcp-sandbox";
// Use a global map to store active sandbox instances across requests
const activeSandboxes = (global as any).activeSandboxes || new Map();
(global as any).activeSandboxes = activeSandboxes;
// Helper to extract text content from a message regardless of format
function getMessageText(message: any): string {
// Check if the message has parts (new format)
if (message.parts && Array.isArray(message.parts)) {
const textParts = message.parts.filter(
(p: any) => p.type === "text" && p.text
);
if (textParts.length > 0) {
return textParts.map((p: any) => p.text).join("\n");
}
}
// Fallback to content (old format)
if (typeof message.content === "string") {
return message.content;
}
// If content is an array (potentially of parts), try to extract text
if (Array.isArray(message.content)) {
const textItems = message.content.filter(
(item: any) =>
typeof item === "string" || (item.type === "text" && item.text)
);
if (textItems.length > 0) {
return textItems
.map((item: any) => (typeof item === "string" ? item : item.text))
.join("\n");
}
}
return "";
}
export async function generateTitle(messages: any[]): Promise<string> {
const normalized = messages.map((m) => ({
role: m.role as "user" | "assistant" | "system",
content: Array.isArray(m.content) ? m.content.join("\n") : m.content,
}));
const response = await hf.chat.completions.create({
model: "meta-llama/Llama-3.1-8B-Instruct",
max_tokens: 30,
temperature: 0.4,
messages: [
{
role: "system",
content:
"You are a helpful assistant that writes very short, unique titles (≤30 characters) for chat conversations.",
},
...normalized,
{ role: "user", content: "Write the title only." },
],
});
const title = response.choices[0]?.message.content?.trim() ?? "New Chat";
// basic schema check
return z.string().min(1).max(100).parse(title);
}
export interface KeyValuePair {
key: string;
value: string;
}
/**
* Server action to start a sandbox
*/
export async function startSandbox(params: {
id: string;
command: string;
args: string[];
env?: KeyValuePair[];
}): Promise<{ url: string }> {
const { id, command, args, env } = params;
console.log(`[startSandbox] Starting sandbox for ID: ${id}`);
// Validate required fields
if (!id || !command || !args) {
throw new Error("Missing required fields");
}
// Check if we already have a sandbox for this ID
if (activeSandboxes.has(id)) {
// If we do, get the URL and return it without creating a new sandbox
const existingSandbox = activeSandboxes.get(id);
console.log(
`[startSandbox] Reusing existing sandbox for ${id}, URL: ${existingSandbox.url}`
);
// Re-fetch the URL to make sure it's current
try {
const freshUrl = await existingSandbox.sandbox.getUrl();
console.log(`[startSandbox] Updated sandbox URL for ${id}: ${freshUrl}`);
// Update the URL in the map
activeSandboxes.set(id, {
sandbox: existingSandbox.sandbox,
url: freshUrl,
});
return { url: freshUrl };
} catch (error) {
console.error(
`[startSandbox] Error refreshing sandbox URL for ${id}:`,
error
);
// Fall through to create a new sandbox if we couldn't refresh the URL
activeSandboxes.delete(id);
console.log(
`[startSandbox] Removed stale sandbox for ${id}, will create a new one`
);
}
}
// Build the command string
let cmd: string;
// Prepare the command based on the type of executable
if (command === "uvx") {
// For uvx, use the direct format
const toolName = args[0];
cmd = `uvx ${toolName} ${args.slice(1).join(" ")}`;
} else if (command.includes("python")) {
// For python commands
cmd = `${command} ${args.join(" ")}`;
} else {
// For node or other commands
cmd = `${command} ${args.join(" ")}`;
}
// Convert env array to object if needed
const envs: Record<string, string> = {};
if (env && env.length > 0) {
env.forEach((envVar) => {
if (envVar.key) envs[envVar.key] = envVar.value || "";
});
}
// Start the sandbox
console.log(
`[startSandbox] Creating new sandbox for ${id} with command: ${cmd}`
);
const sandbox = await startMcpSandbox({ cmd, envs });
const url = await sandbox.getUrl();
console.log(`[startSandbox] Sandbox created for ${id}, URL: ${url}`);
// Store the sandbox in our map
activeSandboxes.set(id, { sandbox, url });
return { url };
}
/**
* Server action to stop a sandbox
*/
export async function stopSandbox(id: string): Promise<{ success: boolean }> {
if (!id) {
throw new Error("Missing sandbox ID");
}
// Check if we have a sandbox with this ID
if (!activeSandboxes.has(id)) {
throw new Error(`No active sandbox found with ID: ${id}`);
}
// Stop the sandbox
const { sandbox } = activeSandboxes.get(id);
try {
await sandbox.stop();
console.log(`Stopped sandbox with ID: ${id}`);
} catch (stopError) {
console.error(`Error stopping sandbox ${id}:`, stopError);
// Continue to remove from the map even if stop fails
}
// Remove from our map
activeSandboxes.delete(id);
return { success: true };
}
|