// Fake model drives AgentHarness through 2 whitelisted tools; streams events. import { createModels, fauxProvider } from "@earendil-works/pi-ai"; import { AgentHarness, BACKGROUND_CONTEXT, MemorySessionRepo } from "@earendil-works/pi-agent-core"; import { downloadSubmit, inventoryQuery, script, submitted } from "./common.ts"; const faux = fauxProvider({ provider: "umt-fake" }); const models = createModels(); models.setProvider(faux.provider); faux.setResponses(script); const repo = new MemorySessionRepo(); const session = await repo.create({ id: "spike-1" }, BACKGROUND_CONTEXT); const { harness } = await AgentHarness.create({ session, models, model: faux.getModel(), systemPrompt: "你是媒体库自动化助手,只能使用提供的工具。", tools: [inventoryQuery, downloadSubmit], // explicit whitelist; no discovery toolContext: { actorId: "user:1", grants: ["download.submit"] }, thinkingLevel: "off", compaction: { enabled: true, reserveTokens: 4096, keepRecentTokens: 8000 }, retry: { enabled: true, maxRetries: 2, baseDelayMs: 100 }, toolExecution: "sequential", }, BACKGROUND_CONTEXT); // Server-side authorization gate in addition to the whitelist. harness.hooks.on("before_tool", (ev) => { console.log(` [hook before_tool] ${ev.toolName} args=${JSON.stringify(ev.args)}`); return undefined; }); const types = ["run_start", "turn_start", "message_update", "tool_start", "tool_update", "tool_end", "turn_end", "run_end", "usage", "fault", "handler_error"] as const; for (const t of types) harness.events.on(t as any, (e: any) => { if (e.type === "message_update") { if (e.event.type === "text_delta") process.stdout.write(` [text_delta] ${JSON.stringify(e.event.delta)}\n`); else if (e.event.type === "toolcall_end") console.log(` [toolcall_end] ${e.event.toolCall.name}`); return; } if (e.type === "tool_end") return console.log(`[tool_end] ${e.toolName} isError=${e.isError} -> ${JSON.stringify(e.result.content[0]?.text)}`); if (e.type === "tool_start") return console.log(`[tool_start] ${e.toolName} ${JSON.stringify(e.args)}`); if (e.type === "usage") return console.log(`[usage] in=${e.row?.usage?.input ?? "?"} totals.input=${e.totals.input} output=${e.totals.output}`); if (e.type === "run_end") return console.log(`[run_end] status=${e.status}${e.error ? " error=" + JSON.stringify(e.error) : ""}`); console.log(`[${e.type}]${e.lane ? " lane=" + e.lane : ""}`); }); const lane = await harness.lane("main", BACKGROUND_CONTEXT); const result = await lane.prompt("把《Dune》1080p 收进来", undefined, BACKGROUND_CONTEXT); console.log("RESULT", JSON.stringify(result)); console.log("SUBMITTED", JSON.stringify(submitted), "fake calls:", faux.state.callCount); const entries = await lane.findEntries(undefined, BACKGROUND_CONTEXT); console.log("TRANSCRIPT roles:", entries.map((e: any) => e.type === "message" ? e.message.role : e.type).join(",")); await harness.close(BACKGROUND_CONTEXT);