Something went wrong. Try again.
Parametric learning in your code harness.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119import assert from "node:assert/strict";import { mkdtemp, rm, writeFile } from "node:fs/promises";import os from "node:os";import path from "node:path";import { test } from "node:test";import { pathToFileURL } from "node:url";import { interactiveExtensionSource, streamToolCall } from "../src/interactive.ts";
test("the interactive extension sets the prompt, registers tools and commands, and records each exchange", async () => { const received: Array<{ action: string; body: any; auth: string | null }> = []; const server = Bun.serve({ port: 0, hostname: "127.0.0.1", async fetch(req) { received.push({ action: new URL(req.url).pathname.slice(1), body: await req.json(), auth: req.headers.get("authorization") }); return new Response("score 1.00"); }, }); const dir = await mkdtemp(path.join(os.tmpdir(), "machine-ext-")); const env = { MACHINE_PI_CONTROL_URL: process.env.MACHINE_PI_CONTROL_URL, MACHINE_PI_CONTROL_TOKEN: process.env.MACHINE_PI_CONTROL_TOKEN }; try { process.env.MACHINE_PI_CONTROL_URL = `http://127.0.0.1:${server.port}`; process.env.MACHINE_PI_CONTROL_TOKEN = "tok"; const file = path.join(dir, "ext.mjs"); await writeFile(file, interactiveExtensionSource({ systemPrompt: "Be a pirate.", tools: [{ name: "t", description: "d", inputSchema: { type: "object" } }], provider: null })); const handlers: Record<string, Function> = {}; const commands: Record<string, any> = {}; const tools: string[] = []; const notes: string[] = []; const fakePi = { registerProvider() {}, on: (event: string, fn: Function) => void (handlers[event] = fn), registerCommand: (name: string, def: any) => void (commands[name] = def), registerTool: (def: any) => void tools.push(def.name), }; (await import(pathToFileURL(file).href)).default(fakePi); const ctx = { ui: { notify: (text: string) => notes.push(text) } };
assert.deepEqual(handlers.before_agent_start({ prompt: "hi" }), { systemPrompt: "Be a pirate." }); await new Promise((r) => setTimeout(r, 50)); // the announcement is sent without waiting assert.deepEqual(tools, ["t"]); assert.deepEqual(Object.keys(commands).sort(), ["bad", "correct", "good", "machine", "score"]);
const messages = [{ role: "user", content: "hi" }, { role: "assistant", content: [{ type: "text", text: "arr" }] }]; await handlers.agent_end({ messages }, ctx); await commands.correct.handler(" too terse ", ctx); assert.deepEqual(received.map((r) => r.action), ["start", "record", "correct"], "the prompt announces the exchange to the dashboard first"); assert.deepEqual(received[1].body.messages, messages); assert.equal(received[2].body.note, "too terse"); assert.ok(received.every((r) => r.auth === "Bearer tok")); assert.ok(notes.includes("score 1.00")); } finally { for (const [k, v] of Object.entries(env)) { if (v === undefined) delete process.env[k]; else process.env[k] = v; } server.stop(); await rm(dir, { recursive: true, force: true }); }});
test("a tool call streams progress to Pi and returns the result", async () => { const server = Bun.serve({ port: 0, hostname: "127.0.0.1", async fetch(req) { const body = await req.json(); assert.equal(new URL(req.url).pathname, "/tool"); assert.deepEqual(body, { name: "slow", arguments: { n: 1 } }); const lines = [{ progress: "step 1" }, { tick: true }, { progress: "step 2" }, { result: "done" }]; return new Response(lines.map((l) => JSON.stringify(l) + "\n").join("")); }, }); const dir = await mkdtemp(path.join(os.tmpdir(), "machine-ext-")); const saved = { url: process.env.MACHINE_PI_CONTROL_URL, token: process.env.MACHINE_PI_CONTROL_TOKEN }; try { process.env.MACHINE_PI_CONTROL_URL = `http://127.0.0.1:${server.port}`; process.env.MACHINE_PI_CONTROL_TOKEN = "tok"; const file = path.join(dir, "ext.mjs"); await writeFile(file, interactiveExtensionSource({ systemPrompt: "x", tools: [{ name: "slow", description: "d", inputSchema: { type: "object" } }], provider: null })); const tools: any[] = []; (await import(pathToFileURL(file).href)).default({ registerProvider() {}, on() {}, registerCommand() {}, registerTool: (def: any) => void tools.push(def) }); const updates: string[] = []; const result = await tools[0].execute("id", { n: 1 }, undefined, (u: any) => updates.push(u.content[0].text)); assert.deepEqual(updates, ["step 1", "step 1\nstep 2"]); assert.deepEqual(result.content, [{ type: "text", text: "done" }]); } finally { if (saved.url === undefined) delete process.env.MACHINE_PI_CONTROL_URL; else process.env.MACHINE_PI_CONTROL_URL = saved.url; if (saved.token === undefined) delete process.env.MACHINE_PI_CONTROL_TOKEN; else process.env.MACHINE_PI_CONTROL_TOKEN = saved.token; server.stop(); await rm(dir, { recursive: true, force: true }); }});
test("streamToolCall reports progress, ticks while waiting, and the result or error", async () => { const lines: unknown[] = []; const slow = { name: "slow", description: "", inputSchema: {}, async execute(input: { fail?: boolean }, ctx: { progress?: (l: string) => void; interactive?: boolean }) { ctx.progress?.(`interactive=${ctx.interactive}`); await new Promise((r) => setTimeout(r, 30)); if (input.fail) throw new Error("nope"); return { ok: true }; }, }; const ctx = { sandbox: {} as any, interactive: true }; await streamToolCall(slow, {}, ctx, (l) => lines.push(l), { tickMs: 10 }); assert.deepEqual(lines[0], { progress: "interactive=true" }); assert.ok(lines.some((l: any) => l.tick), "ticks while the tool runs"); assert.deepEqual(lines.at(-1), { result: '{"ok":true}' }); lines.length = 0; await streamToolCall(slow, { fail: true }, ctx, (l) => lines.push(l), { tickMs: 1000 }); assert.deepEqual(lines.at(-1), { result: "nope", isError: true });});