Spaces:
Configuration error
Configuration error
| import { MODEL_ID, createPiAgent } from "./piAgent.js"; | |
| import { createSandbox } from "./sandbox.js"; | |
| import "./styles.css"; | |
| const nodes = { | |
| status: document.querySelector("#status"), | |
| modelStatus: document.querySelector("#model-status"), | |
| sandboxStatus: document.querySelector("#sandbox-status"), | |
| transcript: document.querySelector("#transcript"), | |
| eventLog: document.querySelector("#event-log"), | |
| files: document.querySelector("#files"), | |
| prompt: document.querySelector("#prompt"), | |
| run: document.querySelector("#run"), | |
| boot: document.querySelector("#boot-sandbox"), | |
| reset: document.querySelector("#reset-sandbox"), | |
| demo: document.querySelector("#demo-prompt"), | |
| mode: document.querySelector("#mode"), | |
| device: document.querySelector("#device"), | |
| maxTokens: document.querySelector("#max-new-tokens"), | |
| temperature: document.querySelector("#temperature"), | |
| modelLabel: document.querySelector("#model-label"), | |
| }; | |
| nodes.modelLabel.textContent = MODEL_ID; | |
| if (!navigator.gpu) nodes.device.value = "wasm"; | |
| const params = new URLSearchParams(window.location.search); | |
| if (params.get("mode") === "mock") nodes.mode.value = "mock"; | |
| if (params.get("device")) nodes.device.value = params.get("device"); | |
| const sandbox = createSandbox({ | |
| onStatus: (text) => setSandboxStatus(text), | |
| onLog: (text) => logEvent("sandbox", text), | |
| }); | |
| let agent = createAgent(); | |
| function textFromContent(content) { | |
| if (typeof content === "string") return content; | |
| if (!Array.isArray(content)) return ""; | |
| return content | |
| .filter((part) => part.type === "text") | |
| .map((part) => part.text) | |
| .join("\n"); | |
| } | |
| function setStatus(text) { | |
| nodes.status.textContent = text; | |
| } | |
| function setSandboxStatus(text) { | |
| nodes.sandboxStatus.textContent = text; | |
| } | |
| function setModelStatus(text) { | |
| nodes.modelStatus.textContent = text; | |
| } | |
| function logEvent(kind, text) { | |
| const line = `[${new Date().toLocaleTimeString()}] ${kind}: ${text}`; | |
| nodes.eventLog.textContent = `${nodes.eventLog.textContent}${line}\n`; | |
| nodes.eventLog.scrollTop = nodes.eventLog.scrollHeight; | |
| } | |
| function createAgent() { | |
| const next = createPiAgent({ | |
| sandbox, | |
| modelMode: () => nodes.mode.value, | |
| device: () => nodes.device.value, | |
| maxTokens: () => nodes.maxTokens.value, | |
| temperature: () => nodes.temperature.value, | |
| onModelStatus: setModelStatus, | |
| }); | |
| next.subscribe((event) => { | |
| switch (event.type) { | |
| case "agent_start": | |
| setStatus("Agent running"); | |
| logEvent("agent", "start"); | |
| break; | |
| case "message_end": | |
| renderTranscript(); | |
| break; | |
| case "tool_execution_start": | |
| logEvent("tool", `${event.toolName} started`); | |
| break; | |
| case "tool_execution_end": | |
| logEvent("tool", `${event.toolName} finished`); | |
| break; | |
| case "agent_end": | |
| setStatus("Ready"); | |
| renderTranscript(); | |
| refreshFiles().catch((error) => logEvent("files", error.message)); | |
| break; | |
| default: | |
| break; | |
| } | |
| }); | |
| return next; | |
| } | |
| function resetAgent() { | |
| agent.abort(); | |
| agent = createAgent(); | |
| renderTranscript(); | |
| } | |
| function renderTranscript() { | |
| const rendered = agent.state.messages | |
| .map((message) => { | |
| if (message.role === "toolResult") { | |
| return `TOOL ${message.toolName}${message.isError ? " ERROR" : ""}\n${textFromContent(message.content)}`; | |
| } | |
| const heading = message.role.toUpperCase(); | |
| const toolCalls = | |
| message.role === "assistant" | |
| ? message.content | |
| .filter((part) => part.type === "toolCall") | |
| .map((part) => `\nTOOL CALL ${part.name} ${JSON.stringify(part.arguments)}`) | |
| .join("") | |
| : ""; | |
| return `${heading}\n${textFromContent(message.content)}${toolCalls}`; | |
| }) | |
| .join("\n\n"); | |
| nodes.transcript.textContent = rendered || "No messages yet."; | |
| nodes.transcript.scrollTop = nodes.transcript.scrollHeight; | |
| } | |
| async function refreshFiles() { | |
| if (!sandbox.isReady) { | |
| nodes.files.textContent = "Sandbox not booted."; | |
| return; | |
| } | |
| nodes.files.textContent = await sandbox.listFiles("."); | |
| } | |
| async function bootSandbox() { | |
| nodes.boot.disabled = true; | |
| try { | |
| await sandbox.boot(); | |
| await refreshFiles(); | |
| } catch (error) { | |
| setSandboxStatus("Sandbox error"); | |
| logEvent("sandbox", error.stack || error.message || String(error)); | |
| } finally { | |
| nodes.boot.disabled = false; | |
| } | |
| } | |
| nodes.boot.addEventListener("click", bootSandbox); | |
| nodes.reset.addEventListener("click", async () => { | |
| nodes.reset.disabled = true; | |
| try { | |
| await sandbox.reset(); | |
| resetAgent(); | |
| await refreshFiles(); | |
| } catch (error) { | |
| logEvent("reset", error.stack || error.message || String(error)); | |
| } finally { | |
| nodes.reset.disabled = false; | |
| } | |
| }); | |
| nodes.demo.addEventListener("click", () => { | |
| nodes.prompt.value = | |
| "Create hello.js that prints the result of 21 * 2, run it with Node, and tell me the command output."; | |
| }); | |
| nodes.run.addEventListener("click", async () => { | |
| nodes.run.disabled = true; | |
| try { | |
| await bootSandbox(); | |
| await agent.prompt(nodes.prompt.value); | |
| } catch (error) { | |
| setStatus("Error"); | |
| logEvent("agent", error.stack || error.message || String(error)); | |
| } finally { | |
| nodes.run.disabled = false; | |
| } | |
| }); | |
| nodes.mode.addEventListener("change", () => { | |
| resetAgent(); | |
| setModelStatus(nodes.mode.value === "mock" ? "Deterministic test model" : "Model idle"); | |
| }); | |
| setStatus("Ready"); | |
| setSandboxStatus("Not booted"); | |
| setModelStatus(nodes.mode.value === "mock" ? "Deterministic test model" : "Model idle"); | |
| renderTranscript(); | |
| refreshFiles().catch(() => {}); | |