UNPKG

agents

Version:

A home for your AI agents

481 lines (480 loc) • 18.1 kB
import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-DZBYAB34.js"; import { t as _classPrivateMethodInitSpec } from "./classPrivateMethodInitSpec-qMjJ6sHQ.js"; import { f as parseHostMessage, l as chunkEntries, t as CLOSE_REPLACED, u as inputText } from "./protocol-cOklVBBD.js"; //#region src/harness/container/daemon-core.ts /** * The harness daemon's core: everything about running an agent inside a * container that does not depend on which agent it is. * * A daemon serves any number of sessions. For each one it keeps a queue of * operations, runs them one at a time through an adapter, numbers every * frame it produces, and keeps frames until the Durable Object acknowledges * them, so a reconnecting object replays exactly what it missed. The * adapter is the only agent-specific part: it opens a session (resuming it * from state it persisted earlier, possibly in another container), runs one * turn at a time, and reports what happens as `ContainerEvent`s. * * Nothing here touches Node, a socket library or a model SDK. The transport * hands the daemon a `DaemonSocket` per connection and feeds it messages; * `./runtime` does that over HTTP in a container, and the tests do it over * a `WebSocketPair` in Workers. * * Modelled on the AI SDK's harness bridge (`runBridge`): the runtime owns * the transport, sequencing and replay, and an adapter owns only the agent. * * @experimental The API may change before it stabilizes. */ /** Settled operations remembered per session, for `hello`. */ const SETTLED_KEPT = 1e3; var _adapter = /* @__PURE__ */ new WeakMap(); var _runtimeId = /* @__PURE__ */ new WeakMap(); var _maxKeptFrames = /* @__PURE__ */ new WeakMap(); var _sessions = /* @__PURE__ */ new WeakMap(); /** * The daemon core. One per container process. * * @experimental The API may change before it stabilizes. */ var ContainerDaemon = class { /** * @param options - The adapter and this container's id. */ constructor(options) { _classPrivateFieldInitSpec(this, _adapter, void 0); _classPrivateFieldInitSpec(this, _runtimeId, void 0); _classPrivateFieldInitSpec(this, _maxKeptFrames, void 0); _classPrivateFieldInitSpec(this, _sessions, /* @__PURE__ */ new Map()); _classPrivateFieldSet2(_adapter, this, options.adapter); _classPrivateFieldSet2(_runtimeId, this, options.runtimeId); _classPrivateFieldSet2(_maxKeptFrames, this, options.maxKeptFrames ?? 1e4); } /** * Attach a connection for a session. A newer connection replaces an older * one, which is closed with `CLOSE_REPLACED`. The daemon sends `hello` * at once. * * @param session - The harness session id. * @param socket - The send side. * @returns The receive side, for the transport to drive. */ connect(session, socket) { let state = _classPrivateFieldGet2(_sessions, this).get(session); if (!state) { state = new DaemonSession(session, _classPrivateFieldGet2(_adapter, this), _classPrivateFieldGet2(_runtimeId, this), _classPrivateFieldGet2(_maxKeptFrames, this)); _classPrivateFieldGet2(_sessions, this).set(session, state); } return state.attach(socket); } /** Close every adapter session, as the container shuts down. */ async close() { await Promise.all([..._classPrivateFieldGet2(_sessions, this).values()].map((s) => s.shutdown())); } }; var _id = /* @__PURE__ */ new WeakMap(); var _adapter2 = /* @__PURE__ */ new WeakMap(); var _runtimeId2 = /* @__PURE__ */ new WeakMap(); var _maxKeptFrames2 = /* @__PURE__ */ new WeakMap(); var _seq = /* @__PURE__ */ new WeakMap(); var _kept = /* @__PURE__ */ new WeakMap(); var _operations = /* @__PURE__ */ new WeakMap(); var _queue = /* @__PURE__ */ new WeakMap(); var _running = /* @__PURE__ */ new WeakMap(); var _opened = /* @__PURE__ */ new WeakMap(); var _restoring = /* @__PURE__ */ new WeakMap(); var _socket = /* @__PURE__ */ new WeakMap(); var _live = /* @__PURE__ */ new WeakMap(); var _inbox = /* @__PURE__ */ new WeakMap(); var _DaemonSession_brand = /* @__PURE__ */ new WeakSet(); var DaemonSession = class { constructor(id, adapter, runtimeId, maxKeptFrames) { _classPrivateMethodInitSpec(this, _DaemonSession_brand); _classPrivateFieldInitSpec(this, _id, void 0); _classPrivateFieldInitSpec(this, _adapter2, void 0); _classPrivateFieldInitSpec(this, _runtimeId2, void 0); _classPrivateFieldInitSpec(this, _maxKeptFrames2, void 0); _classPrivateFieldInitSpec(this, _seq, 0); _classPrivateFieldInitSpec(this, _kept, []); _classPrivateFieldInitSpec(this, _operations, /* @__PURE__ */ new Map()); _classPrivateFieldInitSpec(this, _queue, []); _classPrivateFieldInitSpec(this, _running, void 0); _classPrivateFieldInitSpec(this, _opened, void 0); _classPrivateFieldInitSpec(this, _restoring, void 0); _classPrivateFieldInitSpec(this, _socket, void 0); _classPrivateFieldInitSpec(this, _live, false); _classPrivateFieldInitSpec(this, _inbox, Promise.resolve()); _classPrivateFieldSet2(_id, this, id); _classPrivateFieldSet2(_adapter2, this, adapter); _classPrivateFieldSet2(_runtimeId2, this, runtimeId); _classPrivateFieldSet2(_maxKeptFrames2, this, maxKeptFrames); } attach(socket) { const previous = _classPrivateFieldGet2(_socket, this); _classPrivateFieldSet2(_socket, this, socket); _classPrivateFieldSet2(_live, this, false); previous?.close(CLOSE_REPLACED, "replaced by a newer connection"); _assertClassBrand(_DaemonSession_brand, this, _send).call(this, socket, _assertClassBrand(_DaemonSession_brand, this, _hello).call(this)); return { receive: (text) => { if (_classPrivateFieldGet2(_socket, this) !== socket) return; const message = parseHostMessage(text); if (!message) { _assertClassBrand(_DaemonSession_brand, this, _send).call(this, socket, { type: "error", message: "unparseable message" }); return; } _classPrivateFieldSet2(_inbox, this, _classPrivateFieldGet2(_inbox, this).then(() => _assertClassBrand(_DaemonSession_brand, this, _handle).call(this, message)).catch((error) => { _assertClassBrand(_DaemonSession_brand, this, _send).call(this, socket, { type: "error", message: errorText(error) }); })); }, closed: () => { if (_classPrivateFieldGet2(_socket, this) !== socket) return; _classPrivateFieldSet2(_socket, this, void 0); _classPrivateFieldSet2(_live, this, false); } }; } async shutdown() { _classPrivateFieldGet2(_running, this)?.controller.abort(); const opened = _classPrivateFieldGet2(_opened, this); _classPrivateFieldSet2(_opened, this, void 0); await opened?.session.close().catch(() => void 0); } }; function _hello() { const operations = []; for (const operation of _classPrivateFieldGet2(_operations, this).values()) { const state = operation.state; operations.push(state.tag === "settled" ? { operationId: operation.id, status: "settled", outcome: state.outcome } : { operationId: operation.id, status: state.tag }); } return { type: "hello", protocol: 1, runtimeId: _classPrivateFieldGet2(_runtimeId2, this), session: _classPrivateFieldGet2(_id, this), adapter: { id: _classPrivateFieldGet2(_adapter2, this).id, version: _classPrivateFieldGet2(_adapter2, this).version, capabilities: [..._classPrivateFieldGet2(_adapter2, this).capabilities ?? []] }, open: _classPrivateFieldGet2(_opened, this)?.generation ?? null, lastSeq: _classPrivateFieldGet2(_seq, this), operations }; } async function _handle(message) { switch (message.type) { case "restore": if (_classPrivateFieldGet2(_restoring, this)?.generation !== message.generation) _classPrivateFieldSet2(_restoring, this, { generation: message.generation, entries: [] }); _classPrivateFieldGet2(_restoring, this).entries.push(...message.entries); return; case "open": await _assertClassBrand(_DaemonSession_brand, this, _open).call(this, message); return; case "replay": _assertClassBrand(_DaemonSession_brand, this, _replay).call(this, message.after); return; case "prompt": await _assertClassBrand(_DaemonSession_brand, this, _prompt).call(this, message.operationId, message.input, message.whenBusy); return; case "abort": _assertClassBrand(_DaemonSession_brand, this, _abort).call(this, message.operationId); return; case "configure": await _classPrivateFieldGet2(_opened, this)?.session.configure?.(message.settings); return; case "ack": _classPrivateFieldSet2(_kept, this, _classPrivateFieldGet2(_kept, this).filter((kept) => kept.seq > message.seq)); return; } } async function _open(message) { const restoring = _classPrivateFieldGet2(_restoring, this); _classPrivateFieldSet2(_restoring, this, void 0); if (_classPrivateFieldGet2(_opened, this)?.generation === message.generation) return; const restore = restoring?.generation === message.generation ? [...restoring.entries, ...message.restore] : message.restore; if (_classPrivateFieldGet2(_opened, this)) { _classPrivateFieldGet2(_running, this)?.controller.abort(); await _classPrivateFieldGet2(_opened, this).session.close().catch(() => void 0); _classPrivateFieldSet2(_opened, this, void 0); } const session = await _classPrivateFieldGet2(_adapter2, this).open({ session: _classPrivateFieldGet2(_id, this), settings: message.settings, restore, emit: (event) => _assertClassBrand(_DaemonSession_brand, this, _emit).call(this, { kind: "event", operationId: _classPrivateFieldGet2(_running, this)?.id ?? null, event }), persist: (entries) => { for (const group of chunkEntries(entries)) _assertClassBrand(_DaemonSession_brand, this, _emit).call(this, { kind: "persist", entries: group }); }, log: (level, text) => _assertClassBrand(_DaemonSession_brand, this, _emit).call(this, { kind: "event", operationId: _classPrivateFieldGet2(_running, this)?.id ?? null, event: { type: "log", level, message: text } }) }); _classPrivateFieldSet2(_opened, this, { generation: message.generation, session }); _assertClassBrand(_DaemonSession_brand, this, _pump).call(this); } function _replay(after) { const socket = _classPrivateFieldGet2(_socket, this); if (!socket) return; for (const kept of _classPrivateFieldGet2(_kept, this)) if (kept.seq > after) _assertClassBrand(_DaemonSession_brand, this, _send).call(this, socket, { type: "frame", seq: kept.seq, frame: kept.frame }); _assertClassBrand(_DaemonSession_brand, this, _send).call(this, socket, { type: "caught-up", lastSeq: _classPrivateFieldGet2(_seq, this) }); _classPrivateFieldSet2(_live, this, true); } async function _prompt(id, input, whenBusy) { if (_classPrivateFieldGet2(_operations, this).has(id)) return; const operation = { id, input, whenBusy, state: { tag: "queued" } }; _classPrivateFieldGet2(_operations, this).set(id, operation); _assertClassBrand(_DaemonSession_brand, this, _forgetOldSettled).call(this); const running = _classPrivateFieldGet2(_running, this); const steer = _classPrivateFieldGet2(_opened, this)?.session.steer; if (whenBusy === "steer" && running && steer) { if (await steer.call(_classPrivateFieldGet2(_opened, this)?.session, input) && _classPrivateFieldGet2(_running, this) === running) { operation.state = { tag: "running" }; running.folded.push(id); _assertClassBrand(_DaemonSession_brand, this, _emit).call(this, { kind: "start", operationId: id }); return; } } _classPrivateFieldGet2(_queue, this).push(id); _assertClassBrand(_DaemonSession_brand, this, _pump).call(this); } function _abort(id) { const ids = id === void 0 ? [..._classPrivateFieldGet2(_operations, this).keys()] : _classPrivateFieldGet2(_operations, this).has(id) ? [id] : []; for (const each of ids) { const operation = _classPrivateFieldGet2(_operations, this).get(each); if (!operation) continue; if (operation.state.tag === "queued") { const at = _classPrivateFieldGet2(_queue, this).indexOf(each); if (at >= 0) _classPrivateFieldGet2(_queue, this).splice(at, 1); _assertClassBrand(_DaemonSession_brand, this, _settle).call(this, operation, { status: "unanswered", reason: "aborted" }); } else if (operation.state.tag === "running") _classPrivateFieldGet2(_running, this)?.controller.abort(); } } /** Start the next queued operation, if the session is open and idle. */ function _pump() { const opened = _classPrivateFieldGet2(_opened, this); if (_classPrivateFieldGet2(_running, this) || !opened) return; const id = _classPrivateFieldGet2(_queue, this).shift(); if (id === void 0) return; const operation = _classPrivateFieldGet2(_operations, this).get(id); if (!operation || operation.state.tag !== "queued") { _assertClassBrand(_DaemonSession_brand, this, _pump).call(this); return; } const running = { id, folded: [], controller: new AbortController() }; _classPrivateFieldSet2(_running, this, running); operation.state = { tag: "running" }; _assertClassBrand(_DaemonSession_brand, this, _emit).call(this, { kind: "start", operationId: id }); _assertClassBrand(_DaemonSession_brand, this, _run).call(this, opened, operation, running); } async function _run(opened, operation, running) { let outcome; try { outcome = await opened.session.run({ operationId: operation.id, input: operation.input, signal: running.controller.signal }); if (running.controller.signal.aborted && outcome.status === "done") outcome = { status: "unanswered", reason: "aborted" }; } catch (error) { outcome = { status: "unanswered", reason: running.controller.signal.aborted ? "aborted" : errorText(error) }; } if (_classPrivateFieldGet2(_running, this) === running) _classPrivateFieldSet2(_running, this, void 0); _assertClassBrand(_DaemonSession_brand, this, _settle).call(this, operation, outcome); for (const folded of running.folded) { const each = _classPrivateFieldGet2(_operations, this).get(folded); if (each) _assertClassBrand(_DaemonSession_brand, this, _settle).call(this, each, outcome); } _assertClassBrand(_DaemonSession_brand, this, _pump).call(this); } function _settle(operation, outcome) { if (operation.state.tag === "settled") return; operation.state = { tag: "settled", outcome }; _assertClassBrand(_DaemonSession_brand, this, _emit).call(this, { kind: "settle", operationId: operation.id, outcome }); } function _emit(frame) { _classPrivateFieldSet2(_seq, this, _classPrivateFieldGet2(_seq, this) + 1); const seq = _classPrivateFieldGet2(_seq, this); _classPrivateFieldGet2(_kept, this).push({ seq, frame }); if (_classPrivateFieldGet2(_kept, this).length > _classPrivateFieldGet2(_maxKeptFrames2, this)) _classPrivateFieldGet2(_kept, this).splice(0, _classPrivateFieldGet2(_kept, this).length - _classPrivateFieldGet2(_maxKeptFrames2, this)); const socket = _classPrivateFieldGet2(_socket, this); if (socket && _classPrivateFieldGet2(_live, this)) _assertClassBrand(_DaemonSession_brand, this, _send).call(this, socket, { type: "frame", seq, frame }); } function _send(socket, message) { try { socket.send(JSON.stringify(message)); } catch {} } function _forgetOldSettled() { if (_classPrivateFieldGet2(_operations, this).size <= SETTLED_KEPT) return; for (const [id, operation] of _classPrivateFieldGet2(_operations, this)) { if (_classPrivateFieldGet2(_operations, this).size <= SETTLED_KEPT) return; if (operation.state.tag === "settled") _classPrivateFieldGet2(_operations, this).delete(id); } } function errorText(error) { return error instanceof Error ? error.message : String(error); } /** * A reference adapter that answers `echo: <text>` and needs no model or * credentials. Use it for keyless smoke deploys of the whole path and in * tests. It persists one entry per turn and counts them back after a * restore, so a resumed session visibly remembers its history: * * - `slow <ms> <text>` waits `ms` before answering, and stops on abort. * - `fail <reason>` settles the operation unanswered with `reason`. * - anything else is echoed with the turn number: `echo: hi (turn 3)`. * * @experimental The API may change before it stabilizes. */ const echoAdapter = { id: "echo", version: "1", capabilities: ["steer"], open(context) { let turns = context.restore.length; const steered = []; return { async run(turn) { const text = inputText(turn.input); const slow = /^slow (\d+) ?(.*)$/s.exec(text); if (slow) await sleep(Number(slow[1]), turn.signal); const failure = /^fail ?(.*)$/s.exec(text); if (failure) return { status: "unanswered", reason: failure[1] || "failed" }; turns += 1; const body = slow ? slow[2] ?? "" : text; const answer = `echo: ${body}${steered.splice(0).map((s) => ` + ${s}`).join("")} (turn ${turns})`; const messageId = `${turn.operationId}:assistant`; context.emit({ type: "text-delta", messageId, delta: answer }); context.emit({ type: "message", message: { id: messageId, role: "assistant", parts: [{ type: "text", text: answer }], operationId: turn.operationId, createdAt: Date.now() } }); context.persist([{ turn: turns, text: body }]); return { status: "done", text: answer }; }, steer(input) { steered.push(inputText(input)); return true; }, async close() {} }; } }; function sleep(ms, signal) { return new Promise((resolve, reject) => { if (signal.aborted) { reject(/* @__PURE__ */ new Error("aborted")); return; } const timer = setTimeout(() => { signal.removeEventListener("abort", onAbort); resolve(); }, ms); const onAbort = () => { clearTimeout(timer); reject(/* @__PURE__ */ new Error("aborted")); }; signal.addEventListener("abort", onAbort, { once: true }); }); } //#endregion export { echoAdapter as n, ContainerDaemon as t }; //# sourceMappingURL=daemon-core-Buubj-y1.js.map