agents 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -9
- package/dist/{agent-routing-0DR0Tk2v.d.ts → agent-routing-Bhdbvf7s.d.ts} +13 -8
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-YrATZJu2.d.ts → agent-tools-bJZwBMfq.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/ai-sdk-OoGkFy3s.js +2444 -0
- package/dist/ai-sdk-OoGkFy3s.js.map +1 -0
- package/dist/apply-chunks-1FheRb9W.js +99 -0
- package/dist/apply-chunks-1FheRb9W.js.map +1 -0
- package/dist/broadcast-state-CEyI4uAK.js +69 -0
- package/dist/broadcast-state-CEyI4uAK.js.map +1 -0
- package/dist/browser/ai-sdk.d.ts +1 -1
- package/dist/browser/ai-sdk.js +2 -2
- package/dist/browser/ai-sdk.js.map +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/tanstack-ai.d.ts +1 -1
- package/dist/browser/tanstack-ai.js +1 -1
- package/dist/{browser-DE3d-RLk.d.ts → browser-tmkcAAI3.d.ts} +2 -2
- package/dist/{browser-tool-DuNdlwZ9.d.ts → browser-tool-Bn-nzJQI.d.ts} +3 -3
- package/dist/{browser-tool-CQ10e6Kj.js → browser-tool-CBqs6hqa.js} +58 -18
- package/dist/browser-tool-CBqs6hqa.js.map +1 -0
- package/dist/capability-B4WbF81e.js.map +1 -1
- package/dist/{capability-runner-DBAnGr6L.d.ts → capability-runner-O5VbQzqg.d.ts} +9 -1
- package/dist/channel-Bak_6zDP.d.ts +333 -0
- package/dist/chat/index.d.ts +11 -9
- package/dist/chat/index.js +5 -194
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react.d.ts +2 -4
- package/dist/chat/react.js +3 -1
- package/dist/chat/react.js.map +1 -1
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/chat-sdk/index.js +1 -1
- package/dist/cli.js +144 -0
- package/dist/{client-fyQrLGkD.js → client-1tEQ1Oqz.js} +27 -2
- package/dist/{client-fyQrLGkD.js.map → client-1tEQ1Oqz.js.map} +1 -1
- package/dist/{client-je3koD9Z.d.ts → client-DS3Dz9l0.d.ts} +2 -2
- package/dist/client-tools-aIBO0Fk7.d.ts +53 -0
- package/dist/client.d.ts +1 -1
- package/dist/conversations-DH0ut_8n.d.ts +192 -0
- package/dist/{current-agent-vAk_5JMt.d.ts → current-agent-C07C5o5Y.d.ts} +3 -3
- package/dist/daemon-core-Buubj-y1.js +481 -0
- package/dist/daemon-core-Buubj-y1.js.map +1 -0
- package/dist/daemon-core-CbohVPAu.d.ts +132 -0
- package/dist/{do-oauth-client-provider-Tmf1vgKz.d.ts → do-oauth-client-provider-DfsUcpc3.d.ts} +7 -1
- package/dist/{durable-object-lifecycle-HhgOMWq9.d.ts → durable-object-lifecycle-DRqp475_.d.ts} +2 -2
- package/dist/{channels/email.d.ts → experimental/channels/email/index.d.ts} +25 -12
- package/dist/{channels/email.js → experimental/channels/email/index.js} +13 -35
- package/dist/experimental/channels/email/index.js.map +1 -0
- package/dist/experimental/channels/index.d.ts +270 -0
- package/dist/experimental/channels/index.js +1186 -0
- package/dist/experimental/channels/index.js.map +1 -0
- package/dist/{channels/slack.d.ts → experimental/channels/slack/index.d.ts} +19 -9
- package/dist/experimental/channels/slack/index.js +267 -0
- package/dist/experimental/channels/slack/index.js.map +1 -0
- package/dist/{channels/telegram.d.ts → experimental/channels/telegram/index.d.ts} +19 -9
- package/dist/experimental/channels/telegram/index.js +198 -0
- package/dist/experimental/channels/telegram/index.js.map +1 -0
- package/dist/experimental/channels/web/ai-sdk.d.ts +55 -0
- package/dist/experimental/channels/web/ai-sdk.js +266 -0
- package/dist/experimental/channels/web/ai-sdk.js.map +1 -0
- package/dist/experimental/channels/web/client.d.ts +97 -0
- package/dist/experimental/channels/web/client.js +349 -0
- package/dist/experimental/channels/web/client.js.map +1 -0
- package/dist/experimental/channels/web/index.d.ts +189 -0
- package/dist/experimental/channels/web/index.js +332 -0
- package/dist/experimental/channels/web/index.js.map +1 -0
- package/dist/gateway-BDC07gYO.d.ts +100 -0
- package/dist/handle-zAzh0UW2.d.ts +460 -0
- package/dist/harness/ai-sdk/index.d.ts +175 -0
- package/dist/harness/ai-sdk/index.js +605 -0
- package/dist/harness/ai-sdk/index.js.map +1 -0
- package/dist/harness/container/daemon/index.d.ts +76 -0
- package/dist/harness/container/daemon/index.js +3 -0
- package/dist/harness/container/index.d.ts +740 -0
- package/dist/harness/container/index.js +2152 -0
- package/dist/harness/container/index.js.map +1 -0
- package/dist/harness/container/runtime/index.d.ts +144 -0
- package/dist/harness/container/runtime/index.js +1082 -0
- package/dist/harness/container/runtime/index.js.map +1 -0
- package/dist/harness/opencode/index.d.ts +369 -0
- package/dist/harness/opencode/index.js +1072 -0
- package/dist/harness/opencode/index.js.map +1 -0
- package/dist/harness/pi/index.d.ts +2 -1
- package/dist/harness/store/index.d.ts +24 -0
- package/dist/harness/store/index.js +2 -0
- package/dist/harness/think/index.d.ts +821 -0
- package/dist/harness/think/index.js +2529 -0
- package/dist/harness/think/index.js.map +1 -0
- package/dist/harness-B6B9S3rb.d.ts +203 -0
- package/dist/{images-iiTDSyRu.js → images-Ce9SCu3X.js} +2 -248
- package/dist/images-Ce9SCu3X.js.map +1 -0
- package/dist/{index-BreL0YrQ.d.ts → index-D0A5tbWu.d.ts} +2 -2
- package/dist/index-Ib_4dwOo.d.ts +200 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +2 -2
- package/dist/ingress-EFbrS547.js +9 -0
- package/dist/ingress-EFbrS547.js.map +1 -0
- package/dist/input-schema-DNrpTu49.js +23 -0
- package/dist/input-schema-DNrpTu49.js.map +1 -0
- package/dist/internal-kmw70xwR.js +46 -0
- package/dist/internal-kmw70xwR.js.map +1 -0
- package/dist/internal_context.d.ts +1 -1
- package/dist/lifecycle/index.d.ts +3 -3
- package/dist/mcp/client/do-oauth-client-provider.d.ts +1 -1
- package/dist/mcp/client/do-oauth-client-provider.js +9 -0
- package/dist/mcp/client/do-oauth-client-provider.js.map +1 -1
- package/dist/mcp/client/index.d.ts +1 -1
- package/dist/mcp/client/index.js +1 -1
- package/dist/mcp/client/x402.d.ts +35 -4
- package/dist/mcp/client/x402.js +24 -3
- package/dist/mcp/client/x402.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +2 -2
- package/dist/models/ai-sdk/index.d.ts +16 -14
- package/dist/models/ai-sdk/index.js +1 -2442
- package/dist/models/opencode/index.d.ts +65 -0
- package/dist/models/opencode/index.js +285 -0
- package/dist/models/opencode/index.js.map +1 -0
- package/dist/models/pi-ai/index.d.ts +9 -7
- package/dist/models/pi-ai/index.js +2 -1
- package/dist/models/pi-ai/index.js.map +1 -1
- package/dist/options-pwTNq9z6.d.ts +134 -0
- package/dist/protocol-BEgrJYC5.d.ts +331 -0
- package/dist/protocol-CukuI73M.d.ts +386 -0
- package/dist/protocol-cOklVBBD.js +227 -0
- package/dist/protocol-cOklVBBD.js.map +1 -0
- package/dist/{protocol-kHsr-f0X.js → protocol-eXeJxhgu.js} +2 -67
- package/dist/protocol-eXeJxhgu.js.map +1 -0
- package/dist/protocol-y2sSY584.js +148 -0
- package/dist/protocol-y2sSY584.js.map +1 -0
- package/dist/queue/index.d.ts +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/routing/index.d.ts +2 -2
- package/dist/{scheduler-RdACNXDP.d.ts → scheduler-CrFCnv_J.d.ts} +2 -2
- package/dist/schedules/index.d.ts +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/sessions/index.d.ts +11 -434
- package/dist/sessions/index.js +1 -2271
- package/dist/sessions-B9pNuxdT.js +2272 -0
- package/dist/sessions-B9pNuxdT.js.map +1 -0
- package/dist/settings-C45hDliX.js +253 -0
- package/dist/settings-C45hDliX.js.map +1 -0
- package/dist/{transport-PfFnt-Ld.d.ts → settings-NgGwF7Qt.d.ts} +14 -208
- package/dist/{src-BZeu-SCD.js → src-DgCbZtIR.js} +4 -4
- package/dist/{src-BZeu-SCD.js.map → src-DgCbZtIR.js.map} +1 -1
- package/dist/stall-watchdog-BpRF2uwG.js +195 -0
- package/dist/stall-watchdog-BpRF2uwG.js.map +1 -0
- package/dist/state/index.d.ts +1 -1
- package/dist/store-DLeqKuj3.d.ts +310 -0
- package/dist/store-vgcPYo8K.js +432 -0
- package/dist/store-vgcPYo8K.js.map +1 -0
- package/dist/streams/index.d.ts +1 -1
- package/dist/streams/index.js +1 -1
- package/dist/{streams-DW-UCOUc.js → streams-CITClVer.js} +16 -3
- package/dist/streams-CITClVer.js.map +1 -0
- package/dist/{streams-Cmkj9QfW.d.ts → streams-fbG61qM8.d.ts} +2 -2
- package/dist/sub-routing.d.ts +1 -1
- package/dist/tasks/index.d.ts +1 -1
- package/dist/tasks/index.js +1 -1
- package/dist/{tasks-68DESxf0.js → tasks-CkTZNaV1.js} +2 -1
- package/dist/tasks-CkTZNaV1.js.map +1 -0
- package/dist/{tasks-9YxYtByh.d.ts → tasks-PtlB4Uyn.d.ts} +2 -2
- package/dist/tool-3PA8xjB_.js +421 -0
- package/dist/tool-3PA8xjB_.js.map +1 -0
- package/dist/tool-BPJEbwaX.d.ts +278 -0
- package/dist/transport-k2mFrtL8.d.ts +200 -0
- package/dist/turns-DCV3ycDl.js +317 -0
- package/dist/turns-DCV3ycDl.js.map +1 -0
- package/dist/voice/client.js +1 -1
- package/dist/voice/index.d.ts +2 -2
- package/dist/voice/index.js +1 -1
- package/dist/websearch/index.d.ts +58 -0
- package/dist/websearch/index.js +2 -0
- package/dist/websearch/tools/ai-sdk.d.ts +77 -0
- package/dist/websearch/tools/ai-sdk.js +46 -0
- package/dist/websearch/tools/ai-sdk.js.map +1 -0
- package/dist/websearch/tools/pi.d.ts +82 -0
- package/dist/websearch/tools/pi.js +89 -0
- package/dist/websearch/tools/pi.js.map +1 -0
- package/dist/websearch/tools/tanstack-ai.d.ts +71 -0
- package/dist/websearch/tools/tanstack-ai.js +46 -0
- package/dist/websearch/tools/tanstack-ai.js.map +1 -0
- package/dist/websockets/index.d.ts +12 -296
- package/dist/websockets/index.js +1 -1
- package/dist/{websockets-Ci-LZFHH.js → websockets-CmENGb-Z.js} +18 -4
- package/dist/websockets-CmENGb-Z.js.map +1 -0
- package/dist/{wire-types-CrjKvDyi.d.ts → wire-types-Cv0iwjk5.d.ts} +3 -51
- package/dist/workflow-types.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/dist/workflows.js +1 -1
- package/docs/browse-the-web.md +3 -0
- package/docs/harnesses/think.md +215 -0
- package/docs/index.md +2 -1
- package/docs/lifecycle.md +40 -0
- package/docs/search-the-web.md +133 -0
- package/package.json +117 -38
- package/dist/browser-tool-CQ10e6Kj.js.map +0 -1
- package/dist/channel-Bnm4S7T2.d.ts +0 -491
- package/dist/channels/ai-sdk.d.ts +0 -46
- package/dist/channels/ai-sdk.js +0 -120
- package/dist/channels/ai-sdk.js.map +0 -1
- package/dist/channels/email.js.map +0 -1
- package/dist/channels/index.d.ts +0 -233
- package/dist/channels/index.js +0 -608
- package/dist/channels/index.js.map +0 -1
- package/dist/channels/slack.js +0 -614
- package/dist/channels/slack.js.map +0 -1
- package/dist/channels/tanstack-ai.d.ts +0 -39
- package/dist/channels/tanstack-ai.js +0 -17
- package/dist/channels/tanstack-ai.js.map +0 -1
- package/dist/channels/telegram.js +0 -427
- package/dist/channels/telegram.js.map +0 -1
- package/dist/channels/voice.d.ts +0 -45
- package/dist/channels/voice.js +0 -122
- package/dist/channels/voice.js.map +0 -1
- package/dist/images-iiTDSyRu.js.map +0 -1
- package/dist/index-BB0kqhIz.d.ts +0 -101
- package/dist/ingress-BfetZbMO.js +0 -83
- package/dist/ingress-BfetZbMO.js.map +0 -1
- package/dist/internal-CYlgHl1l.js +0 -59
- package/dist/internal-CYlgHl1l.js.map +0 -1
- package/dist/models/ai-sdk/index.js.map +0 -1
- package/dist/protocol-kHsr-f0X.js.map +0 -1
- package/dist/sessions/index.js.map +0 -1
- package/dist/streams-DW-UCOUc.js.map +0 -1
- package/dist/surface-bZZJqBka.js +0 -17
- package/dist/surface-bZZJqBka.js.map +0 -1
- package/dist/tasks-68DESxf0.js.map +0 -1
- package/dist/tool-schema-CBjGPrsQ.js +0 -31
- package/dist/tool-schema-CBjGPrsQ.js.map +0 -1
- package/dist/websockets-Ci-LZFHH.js.map +0 -1
- package/docs/channels.md +0 -323
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["parseOptions","parseLine"],"sources":["../../../../src/harness/container/runtime/websocket.ts","../../../../src/harness/container/runtime/server.ts","../../../../src/harness/container/runtime/json.ts","../../../../src/harness/container/runtime/file-mirror.ts","../../../../src/harness/container/runtime/cli-adapter.ts","../../../../src/harness/container/runtime/presets/claude-code-events.ts","../../../../src/harness/container/runtime/presets/claude-code.ts","../../../../src/harness/container/runtime/presets/codex.ts"],"sourcesContent":["/**\n * The server half of RFC 6455, for one kind of peer: the Durable Object,\n * which sends text messages and closes cleanly. Enough of the protocol for\n * that (handshake, masked client frames, fragmentation, ping, close) and\n * nothing else, so the daemon needs no dependencies and runs on the plain\n * Node in `cloudflare/debian-trixie`.\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { IncomingMessage } from \"node:http\";\nimport type { Duplex } from \"node:stream\";\n\nconst GUID = \"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\";\n/** Largest message accepted. Restore messages are chunked well below this. */\nconst MAX_MESSAGE_BYTES = 64 * 1024 * 1024;\n\nconst OP_CONTINUATION = 0x0;\nconst OP_TEXT = 0x1;\nconst OP_BINARY = 0x2;\nconst OP_CLOSE = 0x8;\nconst OP_PING = 0x9;\nconst OP_PONG = 0xa;\n\n/** One accepted WebSocket connection. */\nexport type ServerSocket = {\n send(text: string): void;\n close(code: number, reason: string): void;\n};\n\n/** What the server reports for a connection. */\nexport type ServerSocketHandlers = {\n message(text: string): void;\n /** The connection ended, from either side. Called once. */\n closed(): void;\n};\n\nfunction frame(opcode: number, payload: Buffer): Buffer {\n const length = payload.length;\n const header =\n length < 126\n ? Buffer.from([0x80 | opcode, length])\n : length < 65_536\n ? Buffer.from([0x80 | opcode, 126, length >> 8, length & 0xff])\n : Buffer.concat([\n Buffer.from([0x80 | opcode, 127]),\n (() => {\n const size = Buffer.alloc(8);\n size.writeBigUInt64BE(BigInt(length));\n return size;\n })()\n ]);\n return Buffer.concat([header, payload]);\n}\n\n/**\n * Complete the upgrade handshake and serve the connection.\n *\n * @param request - The upgrade request.\n * @param socket - The raw socket.\n * @param head - Bytes read past the request head.\n * @param handlers - Called for each message and on close.\n * @returns The connection, or undefined when the request was not a valid\n * upgrade (the socket is destroyed).\n */\nexport function acceptWebSocket(\n request: IncomingMessage,\n socket: Duplex,\n head: Buffer,\n handlers: ServerSocketHandlers\n): ServerSocket | undefined {\n const key = request.headers[\"sec-websocket-key\"];\n if (\n typeof key !== \"string\" ||\n request.headers.upgrade?.toLowerCase() !== \"websocket\"\n ) {\n socket.destroy();\n return undefined;\n }\n const accept = createHash(\"sha1\")\n .update(key + GUID)\n .digest(\"base64\");\n socket.write(\n \"HTTP/1.1 101 Switching Protocols\\r\\n\" +\n \"Upgrade: websocket\\r\\n\" +\n \"Connection: Upgrade\\r\\n\" +\n `Sec-WebSocket-Accept: ${accept}\\r\\n\\r\\n`\n );\n\n let open = true;\n let ended = false;\n const end = () => {\n if (ended) return;\n ended = true;\n open = false;\n handlers.closed();\n };\n const write = (opcode: number, payload: Buffer) => {\n if (!open) return;\n socket.write(frame(opcode, payload));\n };\n const connection: ServerSocket = {\n send: (text) => write(OP_TEXT, Buffer.from(text, \"utf8\")),\n close: (code, reason) => {\n if (!open) return;\n const payload = Buffer.alloc(2 + Buffer.byteLength(reason));\n payload.writeUInt16BE(code);\n payload.write(reason, 2);\n write(OP_CLOSE, payload);\n open = false;\n socket.end();\n }\n };\n\n let buffered: Buffer = head.length > 0 ? Buffer.from(head) : Buffer.alloc(0);\n let fragments: Buffer[] = [];\n let fragmentBytes = 0;\n\n const drain = () => {\n for (;;) {\n if (buffered.length < 2) return;\n const first = buffered[0] ?? 0;\n const second = buffered[1] ?? 0;\n const fin = (first & 0x80) !== 0;\n const opcode = first & 0x0f;\n const masked = (second & 0x80) !== 0;\n let length = second & 0x7f;\n let offset = 2;\n if (length === 126) {\n if (buffered.length < 4) return;\n length = buffered.readUInt16BE(2);\n offset = 4;\n } else if (length === 127) {\n if (buffered.length < 10) return;\n const big = buffered.readBigUInt64BE(2);\n if (big > BigInt(MAX_MESSAGE_BYTES)) {\n connection.close(1009, \"message too big\");\n return;\n }\n length = Number(big);\n offset = 10;\n }\n const maskOffset = offset;\n if (masked) offset += 4;\n if (buffered.length < offset + length) return;\n const payload = Buffer.from(buffered.subarray(offset, offset + length));\n if (masked) {\n for (let i = 0; i < payload.length; i++) {\n payload[i] =\n (payload[i] ?? 0) ^ (buffered[maskOffset + (i % 4)] ?? 0);\n }\n }\n buffered = buffered.subarray(offset + length);\n\n switch (opcode) {\n case OP_TEXT:\n case OP_BINARY:\n case OP_CONTINUATION: {\n fragments.push(payload);\n fragmentBytes += payload.length;\n if (fragmentBytes > MAX_MESSAGE_BYTES) {\n connection.close(1009, \"message too big\");\n return;\n }\n if (fin) {\n const message = Buffer.concat(fragments).toString(\"utf8\");\n fragments = [];\n fragmentBytes = 0;\n handlers.message(message);\n }\n break;\n }\n case OP_PING:\n write(OP_PONG, payload);\n break;\n case OP_PONG:\n break;\n case OP_CLOSE:\n if (open) {\n write(OP_CLOSE, payload.subarray(0, 2));\n open = false;\n }\n socket.end();\n end();\n return;\n default:\n connection.close(1002, \"unsupported opcode\");\n return;\n }\n }\n };\n\n socket.on(\"data\", (chunk: Buffer) => {\n buffered = buffered.length === 0 ? chunk : Buffer.concat([buffered, chunk]);\n drain();\n });\n socket.on(\"close\", end);\n socket.on(\"error\", end);\n if (buffered.length > 0) queueMicrotask(drain);\n return connection;\n}\n","/**\n * The daemon's transport: an HTTP server that answers the health check and\n * upgrades `/sessions/<id>` to a WebSocket for the daemon core. The Durable\n * Object reaches it through `ctx.container.getTcpPort(port)`.\n *\n * Every request except the health check must carry the token the object\n * started the container with. The health check stays open so that a wrong\n * token looks different from a dead container.\n */\n\nimport { timingSafeEqual } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type Server } from \"node:http\";\nimport type { Duplex } from \"node:stream\";\nimport {\n CLOSE_UNAUTHORIZED,\n CONTAINER_ENV,\n CONTAINER_HEALTH_PATH,\n CONTAINER_SESSION_PATH,\n CONTAINER_TOKEN_HEADER\n} from \"../protocol\";\nimport { ContainerDaemon, type ContainerAdapter } from \"../daemon-core\";\nimport { acceptWebSocket, type ServerSocket } from \"./websocket\";\n\n/** `serve`'s options. */\nexport type ServeOptions = {\n readonly adapter: ContainerAdapter;\n /** This container's id, from `CF_HARNESS_RUNTIME_ID`. */\n readonly runtimeId: string;\n /** The shared secret, from `CF_HARNESS_TOKEN`. */\n readonly token: string;\n /** Port to listen on; 0 picks one. */\n readonly port: number;\n /** Interface to bind. Default all interfaces. */\n readonly host?: string;\n};\n\n/** A running daemon. */\nexport type DaemonServer = {\n /** The port it listens on. */\n readonly port: number;\n /** Stop accepting connections and close every adapter session. */\n close(): Promise<void>;\n};\n\nfunction tokenMatches(expected: string, given: string | undefined): boolean {\n if (given === undefined) return false;\n const a = Buffer.from(expected);\n const b = Buffer.from(given);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n\n/**\n * Start the daemon.\n *\n * @param options - The adapter, identity, secret, and port.\n * @returns The running server, once it listens.\n *\n * @experimental The API may change before it stabilizes.\n */\nexport async function serve(options: ServeOptions): Promise<DaemonServer> {\n const daemon = new ContainerDaemon({\n adapter: options.adapter,\n runtimeId: options.runtimeId\n });\n const sockets = new Set<ServerSocket>();\n const server: Server = createServer((request, response) => {\n if (request.url === CONTAINER_HEALTH_PATH) {\n response.writeHead(200, { \"content-type\": \"text/plain\" });\n response.end(\"ok\");\n return;\n }\n response.writeHead(404);\n response.end();\n });\n\n server.on(\n \"upgrade\",\n (request: IncomingMessage, socket: Duplex, head: Buffer) => {\n const url = new URL(request.url ?? \"/\", \"http://container\");\n if (!url.pathname.startsWith(CONTAINER_SESSION_PATH)) {\n socket.destroy();\n return;\n }\n const session = decodeURIComponent(\n url.pathname.slice(CONTAINER_SESSION_PATH.length)\n );\n const header = request.headers[CONTAINER_TOKEN_HEADER];\n const authorized = tokenMatches(\n options.token,\n Array.isArray(header) ? header[0] : header\n );\n if (!authorized || session.length === 0) {\n const refused = acceptWebSocket(request, socket, head, {\n message: () => {},\n closed: () => {}\n });\n refused?.close(CLOSE_UNAUTHORIZED, \"unauthorized\");\n return;\n }\n // Turns can be silent for many minutes while a tool runs; a quiet\n // socket is never dropped.\n let connection: ReturnType<ContainerDaemon[\"connect\"]> | undefined;\n const ws = acceptWebSocket(request, socket, head, {\n message: (text) => connection?.receive(text),\n closed: () => {\n if (ws) sockets.delete(ws);\n connection?.closed();\n }\n });\n if (!ws) return;\n sockets.add(ws);\n connection = daemon.connect(session, ws);\n }\n );\n\n await new Promise<void>((resolve) => {\n server.listen(options.port, options.host ?? \"0.0.0.0\", resolve);\n });\n const address = server.address();\n const port = typeof address === \"object\" && address ? address.port : 0;\n return {\n port,\n async close() {\n for (const client of sockets) client.close(1001, \"shutting down\");\n await new Promise<void>((resolve) => server.close(() => resolve()));\n await daemon.close();\n }\n };\n}\n\n/**\n * Start the daemon with the identity, secret, and port the Durable Object\n * started the container with, and stop it on SIGTERM. The entrypoint of an\n * image: `serveFromEnv(cliAdapter({ ... }))`.\n *\n * @param adapter - The agent to run.\n * @param env - The environment. Default `process.env`.\n * @returns The running server.\n *\n * @experimental The API may change before it stabilizes.\n */\nexport async function serveFromEnv(\n adapter: ContainerAdapter,\n env: NodeJS.ProcessEnv = process.env\n): Promise<DaemonServer> {\n const token = env[CONTAINER_ENV.token];\n const runtimeId = env[CONTAINER_ENV.runtimeId];\n const port = Number(env[CONTAINER_ENV.port] ?? \"8080\");\n if (!token || !runtimeId || !Number.isInteger(port) || port <= 0) {\n throw new Error(\n `${CONTAINER_ENV.token}, ${CONTAINER_ENV.runtimeId} and ${CONTAINER_ENV.port} must be set; ContainerHarness sets them`\n );\n }\n // The agent's tools run arbitrary commands; they need not see the token.\n delete env[CONTAINER_ENV.token];\n const server = await serve({ adapter, runtimeId, token, port });\n console.log(`harness-daemon: ${adapter.id} on ${server.port} (${runtimeId})`);\n const stop = () => {\n void server.close().finally(() => process.exit(0));\n };\n process.once(\"SIGTERM\", stop);\n process.once(\"SIGINT\", stop);\n return server;\n}\n","import type { JsonValue } from \"../protocol\";\n\n/** A JSON object. */\nexport type JsonObject = { readonly [key: string]: JsonValue };\n\n/**\n * Whether a JSON value is an object (not an array or a primitive).\n *\n * @param value - The value, or undefined for a missing field.\n * @returns True for an object.\n */\nexport function isJsonObject(\n value: JsonValue | undefined\n): value is JsonObject {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * The strings of a JSON array field.\n *\n * @param value - The field.\n * @returns Its string elements, or undefined when it is not an array.\n */\nexport function stringsOf(value: JsonValue | undefined): string[] | undefined {\n if (!Array.isArray(value)) return undefined;\n return value.filter((each): each is string => typeof each === \"string\");\n}\n","/**\n * Mirrors a CLI's state directories into the Durable Object and back.\n *\n * Agent CLIs keep their sessions as files: Claude Code under\n * `~/.claude/projects`, Codex under `~/.codex/sessions`. A container's disk\n * does not outlive the container, so the mirror ships every change to\n * those files out as persisted entries, and writes them back, in order,\n * when the session opens in a new container. The CLI then resumes its own\n * session from its own files and never knows it moved.\n *\n * Session files are append-only logs, so a file that grew ships only the\n * bytes it gained. A file that shrank, or changed without growing, ships\n * whole. Data travels base64-encoded in pieces small enough for one\n * WebSocket message.\n */\n\nimport { mkdir, open, readdir, rm, stat } from \"node:fs/promises\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport type { JsonValue } from \"../protocol\";\nimport { isJsonObject } from \"./json\";\n\n/** Most bytes of one file in one entry. */\nconst PIECE_BYTES = 128 * 1024;\n\n/** Bytes of `path` from `offset` on; `offset` 0 replaces the file. */\ntype FileEntry = {\n readonly kind: \"file\";\n readonly path: string;\n readonly offset: number;\n readonly data: string;\n};\n\ntype Seen = { readonly size: number; readonly mtimeMs: number };\n\nfunction isFileEntry(value: JsonValue): value is FileEntry {\n return (\n isJsonObject(value) &&\n value.kind === \"file\" &&\n typeof value.path === \"string\" &&\n typeof value.offset === \"number\" &&\n typeof value.data === \"string\"\n );\n}\n\n/** One session's mirrored directories, under the session's home. */\nexport class FileMirror {\n readonly #root: string;\n readonly #dirs: readonly string[];\n readonly #seen = new Map<string, Seen>();\n\n /**\n * @param root - The session's home directory.\n * @param dirs - Directories to mirror, relative to `root`.\n */\n constructor(root: string, dirs: readonly string[]) {\n this.#root = resolve(root);\n this.#dirs = dirs;\n }\n\n /**\n * Replace the mirrored directories with the persisted entries, applied in\n * order. Entries that are not file entries are skipped. Whatever the\n * directories held before (a reset session's old files, say) is removed.\n *\n * @param entries - Everything persisted for the session, oldest first.\n */\n async restore(entries: readonly JsonValue[]): Promise<void> {\n for (const dir of this.#dirs) {\n const path = this.#inside(dir);\n if (path !== undefined && path !== this.#root) {\n await rm(path, { recursive: true, force: true });\n }\n }\n for (const entry of entries) {\n if (!isFileEntry(entry)) continue;\n const path = this.#inside(entry.path);\n if (path === undefined) continue;\n await mkdir(dirname(path), { recursive: true });\n const handle =\n entry.offset === 0\n ? await open(path, \"w\")\n : await open(path, \"r+\").catch(() => open(path, \"w\"));\n try {\n if (entry.offset > 0) await handle.truncate(entry.offset);\n await handle.write(\n Buffer.from(entry.data, \"base64\"),\n 0,\n undefined,\n entry.offset\n );\n } finally {\n await handle.close();\n }\n }\n // What was restored is already persisted: only later changes ship.\n for (const file of await this.#files()) {\n const info = await stat(file);\n this.#seen.set(file, { size: info.size, mtimeMs: info.mtimeMs });\n }\n }\n\n /**\n * The changes since the last call (or the restore), as entries to persist.\n *\n * @returns File entries, in the order they must be applied.\n */\n async collect(): Promise<FileEntry[]> {\n const entries: FileEntry[] = [];\n for (const file of await this.#files()) {\n const info = await stat(file).catch(() => undefined);\n if (!info) continue;\n const seen = this.#seen.get(file);\n if (seen && seen.size === info.size && seen.mtimeMs === info.mtimeMs) {\n continue;\n }\n // Grown: ship the new bytes. New, shrunk, or rewritten: ship it whole.\n const from = seen && info.size > seen.size ? seen.size : 0;\n const bytes = await this.#read(file, from, info.size);\n const pieces: Buffer[] = [];\n for (let at = 0; at < bytes.length; at += PIECE_BYTES) {\n pieces.push(bytes.subarray(at, at + PIECE_BYTES));\n }\n if (pieces.length === 0) pieces.push(bytes);\n pieces.forEach((piece, index) => {\n entries.push(this.#entry(file, from + index * PIECE_BYTES, piece));\n });\n this.#seen.set(file, {\n size: from + bytes.length,\n mtimeMs: info.mtimeMs\n });\n }\n return entries;\n }\n\n #entry(file: string, offset: number, data: Buffer): FileEntry {\n return {\n kind: \"file\",\n path: relative(this.#root, file).split(sep).join(\"/\"),\n offset,\n data: data.toString(\"base64\")\n };\n }\n\n async #read(file: string, from: number, to: number): Promise<Buffer> {\n const handle = await open(file, \"r\");\n try {\n const buffer = Buffer.alloc(Math.max(0, to - from));\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, from);\n return buffer.subarray(0, bytesRead);\n } finally {\n await handle.close();\n }\n }\n\n async #files(): Promise<string[]> {\n const files: string[] = [];\n const walk = async (dir: string): Promise<void> => {\n const entries = await readdir(dir, { withFileTypes: true }).catch(\n () => []\n );\n for (const entry of entries) {\n const path = join(dir, entry.name);\n if (entry.isDirectory()) await walk(path);\n else if (entry.isFile()) files.push(path);\n }\n };\n for (const dir of this.#dirs) {\n const path = this.#inside(dir);\n if (path !== undefined) await walk(path);\n }\n return files.sort();\n }\n\n /** `path` under the root, or undefined if it would escape it. */\n #inside(path: string): string | undefined {\n const full = resolve(this.#root, path);\n return full === this.#root || full.startsWith(this.#root + sep)\n ? full\n : undefined;\n }\n}\n","/**\n * An adapter for any agent CLI that runs one turn per process and prints\n * JSON lines: Claude Code (`claude -p --output-format stream-json`), Codex\n * (`codex exec --json`), or your own.\n *\n * A CLI is described by three things:\n *\n * - `command`: the argv (and stdin) for one turn, given the prompt, the\n * session's settings, and the state earlier turns reported, such as the\n * CLI's own session id to resume.\n * - `parser`: turns each stdout line into `ContainerEvent`s, state updates,\n * and the turn's outcome.\n * - `stateDirs`: where the CLI keeps its sessions, relative to `$HOME`.\n *\n * Each harness session gets its own `$HOME`, so sessions sharing a\n * container never see each other's CLI state. The working directory is\n * shared. Everything the CLI writes under `stateDirs`, and every state\n * update, is persisted to the Durable Object while the turn runs; in a new\n * container both are restored before the first turn, so the CLI resumes\n * its own session. Forks need nothing special: a fork's home starts as a\n * copy of its parent's.\n */\n\nimport { spawn } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { constants } from \"node:fs\";\nimport {\n chown,\n copyFile,\n mkdir,\n readdir,\n readlink,\n symlink\n} from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join, resolve, sep } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport {\n inputText,\n type ContainerEvent,\n type ContainerOutcome,\n type ContainerSettings,\n type JsonValue\n} from \"../protocol\";\nimport {\n type AdapterContext,\n type AdapterSession,\n type AdapterTurn,\n type ContainerAdapter\n} from \"../daemon-core\";\nimport { FileMirror } from \"./file-mirror\";\nimport { isJsonObject } from \"./json\";\n\n/** String values a CLI reported in earlier turns, such as its session id. */\nexport type CliState = { readonly [key: string]: string };\n\n/** What a command and a parser are given for one turn. */\nexport type CliTurn = {\n readonly operationId: string;\n /** The prompt's text. Image parts are not passed to CLIs. */\n readonly prompt: string;\n readonly settings: ContainerSettings;\n readonly state: CliState;\n};\n\n/** How to start one turn. */\nexport type CliCommand = {\n readonly argv: readonly string[];\n /** Written to the process's stdin, which is then closed. */\n readonly stdin?: string;\n /** Added to the environment. */\n readonly env?: { readonly [name: string]: string };\n};\n\n/** What one stdout line meant. */\nexport type CliUpdate = {\n readonly events?: readonly ContainerEvent[];\n /** Merged into the session's state and persisted. */\n readonly state?: CliState;\n /** The turn's outcome, when the line reports it. */\n readonly outcome?: ContainerOutcome;\n};\n\n/** Reads one turn's output. */\nexport type CliParser = {\n line(text: string): CliUpdate;\n /** The outcome when no line reported one, from how the process exited. */\n end(exit: {\n readonly code: number | null;\n readonly stderr: string;\n }): ContainerOutcome;\n};\n\n/** `cliAdapter`'s options. */\nexport type CliAdapterOptions = {\n /** Reported in `hello`, such as `\"codex\"`. */\n readonly id: string;\n readonly version?: string;\n readonly command: (turn: CliTurn) => CliCommand;\n readonly parser: (turn: CliTurn) => CliParser;\n /** Directories under `$HOME` where the CLI keeps its sessions. */\n readonly stateDirs?: readonly string[];\n /** Working directory. Default `/workspace`. */\n readonly cwd?: string;\n /** Where session homes are created. Default `~/.harness/sessions`. */\n readonly homes?: string;\n /** How often a running turn's state is persisted. Default 5 seconds. */\n readonly syncIntervalMs?: number;\n /**\n * A home to start every session home from: whatever setup installed\n * there (plugins, mods, settings, skills) is in each session's home. The\n * session files under `stateDirs` are then restored on top. Default: none.\n */\n readonly skeleton?: string;\n /**\n * Run the CLI as this user, and give it its home. For a daemon running\n * as root: Claude Code, for one, refuses to skip permission prompts as\n * root. Default: the daemon's own user.\n */\n readonly user?: { readonly uid: number; readonly gid: number };\n};\n\n/** How long a CLI has to exit after an interrupt before it is killed. */\nconst KILL_AFTER_MS = 5_000;\n/** How much stderr is kept for an error message. */\nconst STDERR_KEPT = 4_096;\n\n/** The session state folded from persisted `{ kind: \"state\" }` entries. */\nfunction foldState(entries: readonly JsonValue[]): CliState {\n const state: Record<string, string> = {};\n for (const entry of entries) {\n if (!isJsonObject(entry) || entry.kind !== \"state\") continue;\n const values = entry.values;\n if (!isJsonObject(values)) continue;\n for (const [key, value] of Object.entries(values)) {\n if (typeof value === \"string\") state[key] = value;\n }\n }\n return state;\n}\n\n/** Give a directory tree to a user. */\nasync function chownTree(\n path: string,\n user: { readonly uid: number; readonly gid: number }\n): Promise<void> {\n await chown(path, user.uid, user.gid);\n const entries = await readdir(path, { withFileTypes: true }).catch(() => []);\n for (const entry of entries) {\n const child = join(path, entry.name);\n if (entry.isDirectory()) await chownTree(child, user);\n else await chown(child, user.uid, user.gid).catch(() => undefined);\n }\n}\n\n/**\n * Copy a skeleton home into a session home, keeping what is already there\n * and leaving out the session homes themselves when they live inside it.\n * (`fs.cp` refuses to copy a directory into its own subdirectory, filter\n * or not, so this walks the tree itself.)\n */\nasync function seed(\n skeleton: string,\n home: string,\n homes: string\n): Promise<void> {\n const excluded = resolve(homes);\n const walk = async (from: string, to: string): Promise<void> => {\n const entries = await readdir(from, { withFileTypes: true }).catch(\n () => []\n );\n for (const entry of entries) {\n const source = join(from, entry.name);\n const path = resolve(source);\n if (path === excluded || path.startsWith(excluded + sep)) continue;\n const target = join(to, entry.name);\n if (entry.isDirectory()) {\n await mkdir(target, { recursive: true });\n await walk(source, target);\n } else if (entry.isSymbolicLink()) {\n await symlink(await readlink(source), target).catch(() => undefined);\n } else if (entry.isFile()) {\n await copyFile(source, target, constants.COPYFILE_EXCL).catch(\n () => undefined\n );\n }\n }\n };\n await walk(resolve(skeleton), home);\n}\n\nfunction homeFor(root: string, session: string): string {\n // Hashed: session ids are arbitrary strings, directory names are not.\n return join(\n root,\n createHash(\"sha256\").update(session).digest(\"hex\").slice(0, 32)\n );\n}\n\nclass CliSession implements AdapterSession {\n readonly #options: CliAdapterOptions;\n readonly #context: AdapterContext;\n readonly #home: string;\n readonly #mirror: FileMirror;\n #state: CliState;\n #settings: ContainerSettings;\n /** Mirror syncs run one at a time. */\n #syncing: Promise<void> = Promise.resolve();\n\n constructor(\n options: CliAdapterOptions,\n context: AdapterContext,\n home: string,\n mirror: FileMirror\n ) {\n this.#options = options;\n this.#context = context;\n this.#home = home;\n this.#mirror = mirror;\n this.#state = foldState(context.restore);\n this.#settings = context.settings;\n }\n\n async run(turn: AdapterTurn): Promise<ContainerOutcome> {\n const cliTurn: CliTurn = {\n operationId: turn.operationId,\n prompt: inputText(turn.input),\n settings: this.#settings,\n state: this.#state\n };\n const command = this.#options.command(cliTurn);\n const parser = this.#options.parser(cliTurn);\n const [file, ...args] = command.argv;\n if (file === undefined) throw new Error(\"The CLI command is empty\");\n\n const user = this.#options.user;\n const child = spawn(file, args, {\n cwd: this.#options.cwd ?? \"/workspace\",\n env: { ...process.env, ...command.env, HOME: this.#home },\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n ...(user ? { uid: user.uid, gid: user.gid } : {})\n });\n child.stdin.on(\"error\", () => undefined);\n child.stdin.end(command.stdin ?? \"\");\n\n let stderr = \"\";\n child.stderr.setEncoding(\"utf8\");\n child.stderr.on(\"data\", (chunk: string) => {\n stderr = (stderr + chunk).slice(-STDERR_KEPT);\n });\n\n let outcome: ContainerOutcome | undefined;\n const lines = createInterface({ input: child.stdout });\n lines.on(\"line\", (text) => {\n if (text.trim() === \"\") return;\n let update: CliUpdate;\n try {\n update = parser.line(text);\n } catch (error) {\n this.#context.log(\"warn\", `unreadable CLI output: ${String(error)}`);\n return;\n }\n for (const event of update.events ?? []) this.#context.emit(event);\n if (update.state) this.#remember(update.state);\n if (update.outcome) outcome = update.outcome;\n });\n\n const onAbort = () => {\n child.kill(\"SIGINT\");\n setTimeout(() => child.kill(\"SIGKILL\"), KILL_AFTER_MS).unref();\n };\n turn.signal.addEventListener(\"abort\", onAbort, { once: true });\n const sync = setInterval(\n () => void this.#sync(),\n this.#options.syncIntervalMs ?? 5_000\n );\n\n const code = await new Promise<number | null>((resolve) => {\n child.on(\"error\", (error) => {\n stderr += `\\n${error.message}`;\n resolve(null);\n });\n child.on(\"close\", (exitCode) => resolve(exitCode));\n });\n clearInterval(sync);\n turn.signal.removeEventListener(\"abort\", onAbort);\n // Everything the turn wrote is persisted before it settles.\n await this.#sync();\n\n if (turn.signal.aborted) return { status: \"unanswered\", reason: \"aborted\" };\n return outcome ?? parser.end({ code, stderr });\n }\n\n configure(settings: ContainerSettings): void {\n this.#settings = settings;\n }\n\n async close(): Promise<void> {\n await this.#syncing;\n }\n\n #remember(update: CliState): void {\n const changed = Object.entries(update).some(\n ([key, value]) => this.#state[key] !== value\n );\n if (!changed) return;\n this.#state = { ...this.#state, ...update };\n this.#context.persist([{ kind: \"state\", values: { ...update } }]);\n }\n\n #sync(): Promise<void> {\n this.#syncing = this.#syncing.then(async () => {\n try {\n const entries = await this.#mirror.collect();\n if (entries.length > 0) this.#context.persist(entries);\n } catch (error) {\n this.#context.log(\"warn\", `state sync failed: ${String(error)}`);\n }\n });\n return this.#syncing;\n }\n}\n\n/**\n * An adapter for an agent CLI.\n *\n * @param options - The CLI's command, parser, and state directories.\n * @returns The adapter.\n *\n * @experimental The API may change before it stabilizes.\n */\nexport function cliAdapter(options: CliAdapterOptions): ContainerAdapter {\n const homes = options.homes ?? join(homedir(), \".harness\", \"sessions\");\n return {\n id: options.id,\n version: options.version ?? \"1\",\n capabilities: [\"resume\", \"fork\", \"model\"],\n async open(context) {\n const home = homeFor(homes, context.session);\n await mkdir(home, { recursive: true });\n if (options.skeleton) await seed(options.skeleton, home, homes);\n const mirror = new FileMirror(home, options.stateDirs ?? []);\n await mirror.restore(context.restore);\n if (options.user) await chownTree(home, options.user);\n return new CliSession(options, context, home, mirror);\n }\n };\n}\n","/**\n * Claude Code's `stream-json` output, projected into `ContainerEvent`s.\n * Each line is an Agent SDK message.\n *\n * Pure and SDK-free: it reads only the fields it needs, structurally, so it\n * can be tested with plain fixtures and survives fields it does not know. Subagent traffic (`parent_tool_use_id` set) is left out of the\n * transcript; the top-level tool call that started the subagent carries its\n * result.\n */\n\nimport type {\n ContainerEvent,\n ContainerMessage,\n ContainerOutcome,\n ContainerPart,\n JsonValue\n} from \"../../protocol\";\n\ntype Block = {\n readonly type: string;\n readonly text?: string;\n readonly thinking?: string;\n readonly id?: string;\n readonly name?: string;\n readonly input?: unknown;\n readonly tool_use_id?: string;\n readonly content?: unknown;\n readonly is_error?: boolean;\n};\n\n/** The subset of an SDK message the projection reads. */\nexport type SdkMessageLike = {\n readonly type: string;\n readonly subtype?: string;\n readonly uuid?: string;\n readonly session_id?: string;\n readonly parent_tool_use_id?: string | null;\n readonly message?: {\n readonly id?: string;\n readonly content?: string | readonly Block[];\n };\n readonly event?: {\n readonly type: string;\n readonly message?: { readonly id?: string };\n readonly delta?: {\n readonly type: string;\n readonly text?: string;\n readonly thinking?: string;\n };\n };\n readonly result?: string;\n readonly is_error?: boolean;\n readonly errors?: readonly string[];\n readonly total_cost_usd?: number;\n readonly usage?: {\n readonly input_tokens?: number;\n readonly output_tokens?: number;\n };\n};\n\ntype Draft = {\n readonly id: string;\n readonly operationId: string | undefined;\n readonly createdAt: number;\n parts: ContainerPart[];\n};\n\nfunction json(value: unknown): JsonValue {\n if (value === undefined) return null;\n try {\n // SAFETY: a JSON round trip yields plain JSON.\n return JSON.parse(JSON.stringify(value)) as JsonValue;\n } catch {\n return String(value);\n }\n}\n\nfunction toolOutput(content: unknown): JsonValue {\n if (typeof content === \"string\") return content;\n if (Array.isArray(content)) {\n const texts = content\n .map((block: unknown) =>\n typeof block === \"object\" &&\n block !== null &&\n \"type\" in block &&\n block.type === \"text\" &&\n \"text\" in block &&\n typeof block.text === \"string\"\n ? block.text\n : undefined\n )\n .filter((text): text is string => text !== undefined);\n if (texts.length === content.length) return texts.join(\"\\n\");\n }\n return json(content);\n}\n\n/** The projection state of one adapter session. */\nexport class ClaudeProjection {\n readonly #drafts = new Map<string, Draft>();\n readonly #toolOwners = new Map<string, string>();\n readonly #seen = new Set<string>();\n #streaming: string | undefined;\n #now: () => number;\n\n /**\n * @param now - The clock, for message timestamps.\n */\n constructor(now: () => number = Date.now) {\n this.#now = now;\n }\n\n /**\n * The events one SDK message produces.\n *\n * @param message - The SDK message.\n * @param operationId - The operation it belongs to.\n * @returns The events, in order.\n */\n project(\n message: SdkMessageLike,\n operationId: string | undefined\n ): ContainerEvent[] {\n if (message.parent_tool_use_id) return [];\n switch (message.type) {\n case \"stream_event\":\n return this.#stream(message);\n case \"assistant\":\n return this.#assistant(message, operationId);\n case \"user\":\n return this.#toolResults(message);\n case \"result\":\n return this.#usage(message);\n default:\n return [];\n }\n }\n\n /**\n * How a turn ended, from its `result` message.\n *\n * @param message - The result message.\n * @param aborted - Whether the turn was interrupted.\n * @returns The outcome.\n */\n outcome(message: SdkMessageLike, aborted: boolean): ContainerOutcome {\n if (aborted) return { status: \"unanswered\", reason: \"aborted\" };\n if (message.subtype === \"success\" && message.is_error !== true) {\n return { status: \"done\", text: message.result ?? \"\" };\n }\n const detail = message.errors?.join(\"; \") || message.result;\n const subtype =\n message.subtype && message.subtype !== \"success\" ? message.subtype : \"\";\n return {\n status: \"unanswered\",\n reason: [subtype, detail].filter((part) => part).join(\": \") || \"error\"\n };\n }\n\n #stream(message: SdkMessageLike): ContainerEvent[] {\n const event = message.event;\n if (!event) return [];\n if (event.type === \"message_start\") {\n this.#streaming = event.message?.id;\n return [];\n }\n const messageId = this.#streaming;\n if (event.type !== \"content_block_delta\" || !messageId || !event.delta) {\n return [];\n }\n if (event.delta.type === \"text_delta\" && event.delta.text) {\n return [{ type: \"text-delta\", messageId, delta: event.delta.text }];\n }\n if (event.delta.type === \"thinking_delta\" && event.delta.thinking) {\n return [\n { type: \"reasoning-delta\", messageId, delta: event.delta.thinking }\n ];\n }\n return [];\n }\n\n #assistant(\n message: SdkMessageLike,\n operationId: string | undefined\n ): ContainerEvent[] {\n const id = message.message?.id;\n const content = message.message?.content;\n if (!id || !Array.isArray(content)) return [];\n // The SDK delivers one content block per message, all under the API\n // message's id; a replayed SDK message (same uuid) adds nothing.\n if (message.uuid !== undefined) {\n if (this.#seen.has(message.uuid)) return [];\n this.#seen.add(message.uuid);\n }\n let draft = this.#drafts.get(id);\n if (!draft) {\n draft = { id, operationId, createdAt: this.#now(), parts: [] };\n this.#drafts.set(id, draft);\n }\n for (const block of content) {\n if (block.type === \"text\" && block.text) {\n draft.parts.push({ type: \"text\", text: block.text });\n } else if (block.type === \"thinking\" && block.thinking) {\n draft.parts.push({ type: \"reasoning\", text: block.thinking });\n } else if (block.type === \"tool_use\" && block.id) {\n draft.parts.push({\n type: \"tool\",\n toolCallId: block.id,\n toolName: block.name ?? \"tool\",\n input: json(block.input),\n state: \"running\"\n });\n this.#toolOwners.set(block.id, id);\n }\n }\n return [{ type: \"message\", message: this.#message(draft) }];\n }\n\n #toolResults(message: SdkMessageLike): ContainerEvent[] {\n const content = message.message?.content;\n if (!Array.isArray(content)) return [];\n const changed = new Set<Draft>();\n for (const block of content) {\n if (block.type !== \"tool_result\" || !block.tool_use_id) continue;\n const owner = this.#toolOwners.get(block.tool_use_id);\n const draft = owner === undefined ? undefined : this.#drafts.get(owner);\n if (!draft) continue;\n draft.parts = draft.parts.map((part) =>\n part.type === \"tool\" && part.toolCallId === block.tool_use_id\n ? {\n ...part,\n state: block.is_error ? \"error\" : \"done\",\n output: toolOutput(block.content)\n }\n : part\n );\n changed.add(draft);\n }\n return [...changed].map((draft) => ({\n type: \"message\",\n message: this.#message(draft)\n }));\n }\n\n #usage(message: SdkMessageLike): ContainerEvent[] {\n return [\n {\n type: \"usage\",\n ...(message.usage?.input_tokens === undefined\n ? {}\n : { inputTokens: message.usage.input_tokens }),\n ...(message.usage?.output_tokens === undefined\n ? {}\n : { outputTokens: message.usage.output_tokens }),\n ...(message.total_cost_usd === undefined\n ? {}\n : { costUsd: message.total_cost_usd })\n }\n ];\n }\n\n #message(draft: Draft): ContainerMessage {\n return {\n id: draft.id,\n role: \"assistant\",\n parts: [...draft.parts],\n ...(draft.operationId === undefined\n ? {}\n : { operationId: draft.operationId }),\n createdAt: draft.createdAt\n };\n }\n}\n","/**\n * Claude Code as a CLI preset: `claude -p` with `stream-json` output, one\n * process per turn, resuming its own session by id. Transcripts live under\n * `~/.claude/projects`, which the adapter mirrors.\n *\n * Credentials come from the container's environment: `ANTHROPIC_API_KEY`,\n * and `ANTHROPIC_BASE_URL` to go through AI Gateway (where the gateway\n * token is the key).\n */\n\nimport type { JsonValue } from \"../../protocol\";\nimport type { CliAdapterOptions } from \"../cli-adapter\";\nimport { isJsonObject, stringsOf } from \"../json\";\nimport { ClaudeProjection, type SdkMessageLike } from \"./claude-code-events\";\n\n/** Claude Code settings, from the harness's `defaults.options`. */\nexport type ClaudeCodeOptions = {\n readonly appendSystemPrompt?: string;\n readonly allowedTools?: readonly string[];\n readonly disallowedTools?: readonly string[];\n readonly maxTurns?: number;\n};\n\nfunction parseOptions(value: JsonValue | undefined): ClaudeCodeOptions {\n if (!isJsonObject(value)) return {};\n const allowed = stringsOf(value.allowedTools);\n const disallowed = stringsOf(value.disallowedTools);\n return {\n ...(typeof value.appendSystemPrompt === \"string\"\n ? { appendSystemPrompt: value.appendSystemPrompt }\n : {}),\n ...(allowed ? { allowedTools: allowed } : {}),\n ...(disallowed ? { disallowedTools: disallowed } : {}),\n ...(typeof value.maxTurns === \"number\" ? { maxTurns: value.maxTurns } : {})\n };\n}\n\nfunction parseLine(text: string): SdkMessageLike | undefined {\n const value: unknown = JSON.parse(text);\n if (typeof value !== \"object\" || value === null || !(\"type\" in value)) {\n return undefined;\n }\n // SAFETY: a stream-json line is an SDK message; `SdkMessageLike` names\n // only fields the projection checks before it uses them.\n return value as SdkMessageLike;\n}\n\n/** The Claude Code preset's description, for `cliAdapter`. */\nexport const claudeCodeCli: CliAdapterOptions = {\n id: \"claude-code\",\n stateDirs: [\".claude/projects\"],\n command(turn) {\n const options = parseOptions(turn.settings.options);\n const argv = [\n \"claude\",\n \"-p\",\n \"--output-format\",\n \"stream-json\",\n \"--verbose\",\n \"--include-partial-messages\",\n // The container is the sandbox.\n \"--dangerously-skip-permissions\"\n ];\n if (turn.settings.model) argv.push(\"--model\", turn.settings.model);\n if (turn.state.sessionId) argv.push(\"--resume\", turn.state.sessionId);\n if (options.appendSystemPrompt) {\n argv.push(\"--append-system-prompt\", options.appendSystemPrompt);\n }\n if (options.allowedTools?.length) {\n argv.push(\"--allowedTools\", options.allowedTools.join(\",\"));\n }\n if (options.disallowedTools?.length) {\n argv.push(\"--disallowedTools\", options.disallowedTools.join(\",\"));\n }\n if (options.maxTurns !== undefined) {\n argv.push(\"--max-turns\", String(options.maxTurns));\n }\n return { argv, stdin: turn.prompt, env: { DISABLE_AUTOUPDATER: \"1\" } };\n },\n parser(turn) {\n const projection = new ClaudeProjection();\n return {\n line(text) {\n const message = parseLine(text);\n if (!message) return {};\n return {\n events: projection.project(message, turn.operationId),\n ...(message.session_id\n ? { state: { sessionId: message.session_id } }\n : {}),\n ...(message.type === \"result\"\n ? { outcome: projection.outcome(message, false) }\n : {})\n };\n },\n end({ code, stderr }) {\n return {\n status: \"unanswered\",\n reason: `claude exited with ${code ?? \"a signal\"}: ${stderr.trim() || \"no output\"}`\n };\n }\n };\n }\n};\n","/**\n * Codex as a CLI preset: `codex exec --json`, one process per turn,\n * resuming its own thread with `codex exec resume <thread>`. Rollouts live\n * under `~/.codex/sessions`, which the adapter mirrors.\n *\n * Credentials come from the container's environment: `OPENAI_API_KEY`,\n * and `OPENAI_BASE_URL` to go through AI Gateway (where the gateway token\n * is the key). Codex does not read `OPENAI_BASE_URL` itself, so the preset\n * passes it as a model provider.\n */\n\nimport type {\n ContainerEvent,\n ContainerMessage,\n ContainerPart,\n JsonValue\n} from \"../../protocol\";\nimport type { CliAdapterOptions } from \"../cli-adapter\";\nimport { isJsonObject, stringsOf } from \"../json\";\n\ntype Item = {\n readonly id?: string;\n readonly type?: string;\n readonly text?: string;\n readonly message?: string;\n readonly command?: string;\n readonly aggregated_output?: string;\n readonly exit_code?: number | null;\n readonly status?: string;\n readonly changes?: JsonValue;\n readonly server?: string;\n readonly tool?: string;\n readonly arguments?: JsonValue;\n readonly result?: JsonValue;\n readonly error?: JsonValue;\n readonly query?: string;\n readonly items?: JsonValue;\n};\n\ntype CodexLine = {\n readonly type?: string;\n readonly thread_id?: string;\n readonly item?: Item;\n readonly usage?: {\n readonly input_tokens?: number;\n readonly output_tokens?: number;\n };\n readonly error?: { readonly message?: string };\n readonly message?: string;\n};\n\nfunction parseLine(text: string): CodexLine | undefined {\n const value: unknown = JSON.parse(text);\n if (typeof value !== \"object\" || value === null) return undefined;\n // SAFETY: a `codex exec --json` line is one of its events; `CodexLine`\n // names only optional fields the projection checks before use.\n return value as CodexLine;\n}\n\nfunction toolState(status: string | undefined): \"running\" | \"done\" | \"error\" {\n if (status === \"completed\") return \"done\";\n if (status === \"failed\" || status === \"declined\") return \"error\";\n return \"running\";\n}\n\n/** One item as a transcript part, or undefined for items that are not. */\nfunction partOf(item: Item): ContainerPart | undefined {\n const id = item.id ?? \"item\";\n const state = toolState(item.status);\n switch (item.type) {\n case \"agent_message\":\n return { type: \"text\", text: item.text ?? \"\" };\n case \"reasoning\":\n return { type: \"reasoning\", text: item.text ?? \"\" };\n case \"command_execution\":\n return {\n type: \"tool\",\n toolCallId: id,\n toolName: \"shell\",\n input: { command: item.command ?? \"\" },\n state:\n state === \"done\" && item.exit_code !== 0 && item.exit_code != null\n ? \"error\"\n : state,\n ...(item.aggregated_output ? { output: item.aggregated_output } : {})\n };\n case \"file_change\":\n return {\n type: \"tool\",\n toolCallId: id,\n toolName: \"file_change\",\n input: item.changes ?? null,\n state\n };\n case \"mcp_tool_call\":\n return {\n type: \"tool\",\n toolCallId: id,\n toolName: `${item.server ?? \"mcp\"}.${item.tool ?? \"tool\"}`,\n input: item.arguments ?? null,\n state,\n ...(item.result !== undefined || item.error !== undefined\n ? { output: item.result ?? item.error ?? null }\n : {})\n };\n case \"web_search\":\n return {\n type: \"tool\",\n toolCallId: id,\n toolName: \"web_search\",\n input: { query: item.query ?? \"\" },\n state\n };\n case \"todo_list\":\n return {\n type: \"tool\",\n toolCallId: id,\n toolName: \"todo_list\",\n input: item.items ?? null,\n state\n };\n default:\n return undefined;\n }\n}\n\n/** Codex settings, from the harness's `defaults.options`. */\nexport type CodexOptions = {\n /** Extra `-c key=value` config overrides. */\n readonly config?: readonly string[];\n};\n\nfunction parseOptions(value: JsonValue | undefined): CodexOptions {\n if (!isJsonObject(value)) return {};\n const config = stringsOf(value.config);\n return config ? { config } : {};\n}\n\n/** The Codex preset's description, for `cliAdapter`. */\nexport const codexCli: CliAdapterOptions = {\n id: \"codex\",\n stateDirs: [\".codex/sessions\"],\n command(turn) {\n const argv = [\"codex\", \"exec\"];\n if (turn.state.threadId) argv.push(\"resume\", turn.state.threadId);\n argv.push(\n \"--json\",\n \"--skip-git-repo-check\",\n // The container is the sandbox.\n \"--dangerously-bypass-approvals-and-sandbox\"\n );\n const baseUrl = process.env.OPENAI_BASE_URL;\n if (baseUrl) {\n argv.push(\n \"-c\",\n \"model_provider=gateway\",\n \"-c\",\n `model_providers.gateway={name=\"AI Gateway\",base_url=${JSON.stringify(baseUrl)},env_key=\"OPENAI_API_KEY\",wire_api=\"responses\"}`\n );\n }\n for (const config of parseOptions(turn.settings.options).config ?? []) {\n argv.push(\"-c\", config);\n }\n if (turn.settings.model) argv.push(\"-m\", turn.settings.model);\n // `-` reads the prompt from stdin.\n argv.push(\"-\");\n return { argv, stdin: turn.prompt };\n },\n parser(turn) {\n // One assistant message per turn, its parts in item order.\n const messageId = `${turn.operationId}:assistant`;\n const createdAt = Date.now();\n const parts = new Map<string, ContainerPart>();\n let lastText = \"\";\n let failure: string | undefined;\n const message = (): ContainerEvent => {\n const value: ContainerMessage = {\n id: messageId,\n role: \"assistant\",\n parts: [...parts.values()],\n operationId: turn.operationId,\n createdAt\n };\n return { type: \"message\", message: value };\n };\n return {\n line(text) {\n const event = parseLine(text);\n if (!event) return {};\n switch (event.type) {\n case \"thread.started\":\n return event.thread_id\n ? { state: { threadId: event.thread_id } }\n : {};\n case \"item.started\":\n case \"item.updated\":\n case \"item.completed\": {\n const item = event.item;\n if (!item) return {};\n if (item.type === \"error\") {\n return {\n events: [\n {\n type: \"log\",\n level: \"warn\",\n message: item.message ?? \"error\"\n }\n ]\n };\n }\n const part = partOf(item);\n if (!part) return {};\n parts.set(item.id ?? String(parts.size), part);\n if (part.type === \"text\" && event.type === \"item.completed\") {\n lastText = part.text;\n }\n return { events: [message()] };\n }\n case \"turn.completed\":\n return {\n events: [\n {\n type: \"usage\",\n ...(event.usage?.input_tokens === undefined\n ? {}\n : { inputTokens: event.usage.input_tokens }),\n ...(event.usage?.output_tokens === undefined\n ? {}\n : { outputTokens: event.usage.output_tokens })\n }\n ],\n outcome: { status: \"done\", text: lastText }\n };\n case \"turn.failed\":\n return {\n outcome: {\n status: \"unanswered\",\n reason: event.error?.message ?? \"turn failed\"\n }\n };\n case \"error\":\n // Reconnect notices and the like; a fatal one ends in\n // `turn.failed` or a non-zero exit.\n failure = event.message;\n return {\n events: [\n {\n type: \"log\",\n level: \"warn\",\n message: event.message ?? \"error\"\n }\n ]\n };\n default:\n return {};\n }\n },\n end({ code, stderr }) {\n return {\n status: \"unanswered\",\n reason: `codex exited with ${code ?? \"a signal\"}: ${failure ?? (stderr.trim() || \"no output\")}`\n };\n }\n };\n }\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import {
|
|
2
|
+
_ as LifecycleJobContext,
|
|
3
|
+
n as CapabilityStartContext,
|
|
4
|
+
s as LifecycleCapability,
|
|
5
|
+
v as LifecycleJobOutcome
|
|
6
|
+
} from "../../capability-runner-O5VbQzqg.js";
|
|
7
|
+
import { OpenCodeWorkerd } from "@opencode/sdk/workerd";
|
|
8
|
+
|
|
9
|
+
//#region src/harness/opencode/types.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* `OpenCodeHarness`'s own types: how the harness addresses sessions and
|
|
12
|
+
* reports operations. They match `PiHarness`'s, field for field. Anything
|
|
13
|
+
* OpenCode already publishes (prompt content, transcript messages, events)
|
|
14
|
+
* is OpenCode's type, used directly.
|
|
15
|
+
*/
|
|
16
|
+
/** The OpenCode host the factory returns: `OpenCodeWorkerd.create`'s result. */
|
|
17
|
+
type OpenCode = OpenCodeWorkerd.Interface;
|
|
18
|
+
type PromptRequest = Parameters<OpenCode["sessions"]["prompt"]>[0];
|
|
19
|
+
/**
|
|
20
|
+
* What a prompt says: text, or text with OpenCode's attachments (files,
|
|
21
|
+
* agent and skill mentions, metadata).
|
|
22
|
+
*/
|
|
23
|
+
type OpenCodeInput =
|
|
24
|
+
| string
|
|
25
|
+
| Omit<PromptRequest, "sessionID" | "id" | "delivery" | "resume">;
|
|
26
|
+
/**
|
|
27
|
+
* One message of an OpenCode transcript: user, assistant, idle markers,
|
|
28
|
+
* compactions, and the rest of OpenCode's message kinds.
|
|
29
|
+
*/
|
|
30
|
+
type OpenCodeMessage = Awaited<
|
|
31
|
+
ReturnType<OpenCode["sessions"]["context"]>
|
|
32
|
+
>[number];
|
|
33
|
+
/** One of OpenCode's events: durable transcript events and live deltas. */
|
|
34
|
+
type OpenCodeEvent =
|
|
35
|
+
ReturnType<OpenCode["events"]["subscribe"]> extends AsyncIterable<infer E>
|
|
36
|
+
? E
|
|
37
|
+
: never;
|
|
38
|
+
/**
|
|
39
|
+
* One of a session's durable events, as `session.log()` replays them. Each
|
|
40
|
+
* carries its sequence number in `durable.seq`.
|
|
41
|
+
*/
|
|
42
|
+
type OpenCodeLogEvent =
|
|
43
|
+
ReturnType<OpenCode["sessions"]["log"]> extends AsyncIterable<infer E>
|
|
44
|
+
? E
|
|
45
|
+
: never;
|
|
46
|
+
/** An OpenCode session, addressed by its id. The root is `"ses_root"`. */
|
|
47
|
+
type OpenCodeSessionId = string;
|
|
48
|
+
/**
|
|
49
|
+
* What a submission does when the session is already running.
|
|
50
|
+
*
|
|
51
|
+
* - `followUp` (default): answered after the current run, as its own run.
|
|
52
|
+
* - `steer`: joins the running work at its next step.
|
|
53
|
+
*/
|
|
54
|
+
type OpenCodeWhenBusy = "followUp" | "steer";
|
|
55
|
+
/** Options for `submit` and `prompt`. */
|
|
56
|
+
type OpenCodeSubmitOptions = {
|
|
57
|
+
/** Default: the root session. */ readonly session?: OpenCodeSessionId;
|
|
58
|
+
/**
|
|
59
|
+
* Idempotency key. Submitting the same id twice returns the same receipt.
|
|
60
|
+
* Letters, digits, `.`, `_`, `~` and `-`; default a random UUID.
|
|
61
|
+
*/
|
|
62
|
+
readonly operationId?: string;
|
|
63
|
+
readonly whenBusy?: OpenCodeWhenBusy;
|
|
64
|
+
};
|
|
65
|
+
/** Selects a session. */
|
|
66
|
+
type OpenCodeSessionOptions = {
|
|
67
|
+
/** Default: the root session. */ readonly session?: OpenCodeSessionId;
|
|
68
|
+
};
|
|
69
|
+
/** Returned once a submission is durable. It says nothing about the model yet. */
|
|
70
|
+
type OpenCodeReceipt = {
|
|
71
|
+
readonly operationId: string;
|
|
72
|
+
readonly session: OpenCodeSessionId /** False when this operation id was already submitted. */;
|
|
73
|
+
readonly accepted: boolean;
|
|
74
|
+
};
|
|
75
|
+
/** How one operation ended. */
|
|
76
|
+
type OpenCodeOperationResult = {
|
|
77
|
+
readonly operationId: string;
|
|
78
|
+
readonly session: OpenCodeSessionId /** `done`: answered. `unanswered`: failed, interrupted, or withdrawn. */;
|
|
79
|
+
readonly status: "done" | "unanswered";
|
|
80
|
+
/**
|
|
81
|
+
* Why an unanswered operation ended: `failed` (with OpenCode's error
|
|
82
|
+
* message when it has one), `interrupted`, or `not_found`.
|
|
83
|
+
*/
|
|
84
|
+
readonly reason?: string /** The final assistant text, when answered. */;
|
|
85
|
+
readonly text?: string;
|
|
86
|
+
};
|
|
87
|
+
/** An operation's result and the session's transcript after it. */
|
|
88
|
+
type OpenCodePromptResponse = OpenCodeOperationResult & {
|
|
89
|
+
/** The session's active transcript after the operation. */ readonly messages: readonly OpenCodeMessage[];
|
|
90
|
+
};
|
|
91
|
+
/** A submission OpenCode has not settled yet. */
|
|
92
|
+
type OpenCodePendingOperation = {
|
|
93
|
+
readonly operationId: string;
|
|
94
|
+
readonly session: OpenCodeSessionId /** `queued` in OpenCode's inbox, or `running` as part of the current run. */;
|
|
95
|
+
readonly status: "queued" | "running";
|
|
96
|
+
};
|
|
97
|
+
/** One session, as `sessions.list()` reports it. */
|
|
98
|
+
type OpenCodeSessionInfo = {
|
|
99
|
+
readonly id: OpenCodeSessionId /** The session this one was forked from, or the one that spawned it. */;
|
|
100
|
+
readonly parent?: OpenCodeSessionId /** The title OpenCode generated for the session, once it has one. */;
|
|
101
|
+
readonly title?: string /** Running, input waiting, or a turn a restart cut off, about to resume. */;
|
|
102
|
+
readonly busy: boolean;
|
|
103
|
+
};
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/harness/opencode/harness.d.ts
|
|
106
|
+
/** The root session's id. OpenCode session ids start with `ses`. */
|
|
107
|
+
declare const ROOT_SESSION: OpenCodeSessionId;
|
|
108
|
+
/** What the factory is handed: the one thing only the harness can build. */
|
|
109
|
+
type OpenCodeHarnessContext = {
|
|
110
|
+
/**
|
|
111
|
+
* This object's storage, with OpenCode's tables moved under the
|
|
112
|
+
* `opencode_` prefix so they cannot collide with the SDK's or the host's.
|
|
113
|
+
* Pass it as `OpenCodeWorkerd.create({ storage })`.
|
|
114
|
+
*/
|
|
115
|
+
readonly storage: DurableObjectStorage;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Opens OpenCode. The harness adopts what it returns and closes it on
|
|
119
|
+
* `dispose()`.
|
|
120
|
+
*
|
|
121
|
+
* ```ts
|
|
122
|
+
* opencode: ({ storage }) =>
|
|
123
|
+
* OpenCodeWorkerd.create({ storage, plugins: [ai.plugin] })
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
type OpenCodeHarnessFactory = (
|
|
127
|
+
context: OpenCodeHarnessContext
|
|
128
|
+
) => OpenCode | Promise<OpenCode>;
|
|
129
|
+
/** A model, as OpenCode references one; `agents/models/opencode` makes them. */
|
|
130
|
+
type OpenCodeModel = {
|
|
131
|
+
readonly providerID: string;
|
|
132
|
+
readonly id: string;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Applied to a session when the harness creates it. Without a model, a
|
|
136
|
+
* session uses OpenCode's default model, if its config names one.
|
|
137
|
+
*/
|
|
138
|
+
type OpenCodeSessionDefaults = {
|
|
139
|
+
/** Model for new sessions. Change one session's with `session.setModel`. */ readonly model?: OpenCodeModel /** OpenCode agent for new sessions, such as `build`. */;
|
|
140
|
+
readonly agent?: string;
|
|
141
|
+
};
|
|
142
|
+
/** `OpenCodeHarness`'s options. Only `opencode`, which opens it, is required. */
|
|
143
|
+
type OpenCodeHarnessOptions = {
|
|
144
|
+
/** Opens OpenCode over the storage this object prepared. */ readonly opencode: OpenCodeHarnessFactory /** What a new session starts with. */;
|
|
145
|
+
readonly defaults?: OpenCodeSessionDefaults;
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* OpenCode v2 hosted in a Durable Object, behind the same harness interface
|
|
149
|
+
* as `PiHarness`: `harness.prompt()`, `harness.sessions`, `harness.session(id)`.
|
|
150
|
+
* How a session reaches a client (sockets, SSE, RPC) is the host's glue,
|
|
151
|
+
* built on `session.events()` and `session.log()`.
|
|
152
|
+
*
|
|
153
|
+
* OpenCode owns everything about a run: the transcript, the inbox of steers
|
|
154
|
+
* and follow-ups, model and tool steps, retries, and crash recovery. It keeps
|
|
155
|
+
* all of it in its own tables in this object's SQLite database, under the
|
|
156
|
+
* `opencode_` prefix.
|
|
157
|
+
*
|
|
158
|
+
* What OpenCode cannot do on a Durable Object is wake itself: it resumes an
|
|
159
|
+
* interrupted turn when it boots, but an evicted object does not boot until
|
|
160
|
+
* something calls it. The harness is that wake, with one Lifecycle job per
|
|
161
|
+
* session. Input goes to OpenCode once, in `submit()`, after the session's
|
|
162
|
+
* job is scheduled. The job waits while the session runs, rescheduling itself
|
|
163
|
+
* as a heartbeat, and completes when the session is idle with nothing left
|
|
164
|
+
* to do. An eviction mid-run leaves the job due, so its alarm restarts the
|
|
165
|
+
* object, OpenCode boots and resumes the turn, and the job waits again.
|
|
166
|
+
*
|
|
167
|
+
* @experimental The API may change between releases.
|
|
168
|
+
*/
|
|
169
|
+
declare class OpenCodeHarness extends LifecycleCapability {
|
|
170
|
+
#private;
|
|
171
|
+
/** Every session in this object. */
|
|
172
|
+
readonly sessions: OpenCodeSessions;
|
|
173
|
+
/**
|
|
174
|
+
* @param options - How to open OpenCode, and what new sessions start with.
|
|
175
|
+
*/
|
|
176
|
+
constructor(options: OpenCodeHarnessOptions);
|
|
177
|
+
/** Open OpenCode, which resumes interrupted turns, and wake running sessions. */
|
|
178
|
+
onStart(_context: CapabilityStartContext): Promise<void>;
|
|
179
|
+
/** Run one step of a session's wake job. */
|
|
180
|
+
onJob(context: LifecycleJobContext): Promise<LifecycleJobOutcome | void>;
|
|
181
|
+
/** Close OpenCode's in-memory resources. Durable state is untouched. */
|
|
182
|
+
dispose(): Promise<void>;
|
|
183
|
+
/**
|
|
184
|
+
* A handle on one session. No I/O until you call it.
|
|
185
|
+
*
|
|
186
|
+
* @param id - The session; default the root session.
|
|
187
|
+
*/
|
|
188
|
+
session(id?: OpenCodeSessionId): OpenCodeSession;
|
|
189
|
+
/** Submit a prompt and wait for its answer. */
|
|
190
|
+
prompt(
|
|
191
|
+
input: OpenCodeInput,
|
|
192
|
+
options?: OpenCodeSubmitOptions
|
|
193
|
+
): Promise<OpenCodePromptResponse>;
|
|
194
|
+
/** Durably submit a prompt. Resolves before the model runs. */
|
|
195
|
+
submit(
|
|
196
|
+
input: OpenCodeInput,
|
|
197
|
+
options?: OpenCodeSubmitOptions
|
|
198
|
+
): Promise<OpenCodeReceipt>;
|
|
199
|
+
/** Stop one operation, or everything running in a session. */
|
|
200
|
+
abort(
|
|
201
|
+
options?: OpenCodeSessionOptions & {
|
|
202
|
+
readonly operationId?: string;
|
|
203
|
+
}
|
|
204
|
+
): Promise<boolean>;
|
|
205
|
+
/** Wait for an operation to settle. Aborting `signal` stops only the wait. */
|
|
206
|
+
wait(
|
|
207
|
+
operationId: string,
|
|
208
|
+
options?: OpenCodeSessionOptions & {
|
|
209
|
+
readonly signal?: AbortSignal;
|
|
210
|
+
}
|
|
211
|
+
): Promise<OpenCodeOperationResult>;
|
|
212
|
+
/** The session's active transcript, as OpenCode's messages. */
|
|
213
|
+
messages(options?: OpenCodeSessionOptions): Promise<OpenCodeMessage[]>;
|
|
214
|
+
/** Submissions OpenCode has not settled yet, oldest first. */
|
|
215
|
+
pending(
|
|
216
|
+
options?: OpenCodeSessionOptions
|
|
217
|
+
): Promise<OpenCodePendingOperation[]>;
|
|
218
|
+
/**
|
|
219
|
+
* The opened OpenCode host, for anything the interface does not cover.
|
|
220
|
+
* The harness closes an idle host, so call this again each time rather
|
|
221
|
+
* than keeping the result; work done through it does not keep it open.
|
|
222
|
+
*/
|
|
223
|
+
opencode(): Promise<OpenCode>;
|
|
224
|
+
/**
|
|
225
|
+
* @internal Run `call` with OpenCode open. The host is not closed while
|
|
226
|
+
* any call holds it.
|
|
227
|
+
*/
|
|
228
|
+
use<T>(call: (opencode: OpenCode) => Promise<T>): Promise<T>;
|
|
229
|
+
/**
|
|
230
|
+
* @internal Hold OpenCode open until the returned release is called, for
|
|
231
|
+
* work that outlives one call, such as an event stream.
|
|
232
|
+
*/
|
|
233
|
+
lease(): () => Promise<void>;
|
|
234
|
+
/** @internal Admit an input to OpenCode once, behind the session's wake. */
|
|
235
|
+
enqueue(
|
|
236
|
+
session: OpenCodeSessionId,
|
|
237
|
+
input: OpenCodeInput,
|
|
238
|
+
options: OpenCodeSubmitOptions
|
|
239
|
+
): Promise<OpenCodeReceipt>;
|
|
240
|
+
/** @internal Withdraw a queued input, or interrupt the run it joined. */
|
|
241
|
+
withdraw(session: OpenCodeSessionId, operationId: string): Promise<boolean>;
|
|
242
|
+
/** @internal Withdraw every queued input and interrupt the running work. */
|
|
243
|
+
interrupt(session: OpenCodeSessionId): Promise<void>;
|
|
244
|
+
/** @internal Wait for OpenCode to settle an operation, by its id. */
|
|
245
|
+
settled(
|
|
246
|
+
session: OpenCodeSessionId,
|
|
247
|
+
operationId: string,
|
|
248
|
+
signal?: AbortSignal
|
|
249
|
+
): Promise<OpenCodeOperationResult>;
|
|
250
|
+
/** @internal Create a session with the harness defaults. */
|
|
251
|
+
create(options?: {
|
|
252
|
+
readonly id?: OpenCodeSessionId;
|
|
253
|
+
}): Promise<OpenCodeSessionId>;
|
|
254
|
+
}
|
|
255
|
+
/** One OpenCode session, addressed through the harness. */
|
|
256
|
+
declare class OpenCodeSession {
|
|
257
|
+
#private;
|
|
258
|
+
/** The session's id. */
|
|
259
|
+
readonly id: OpenCodeSessionId;
|
|
260
|
+
/**
|
|
261
|
+
* @param harness - The harness that hosts the session.
|
|
262
|
+
* @param id - The session's id.
|
|
263
|
+
*/
|
|
264
|
+
constructor(harness: OpenCodeHarness, id: OpenCodeSessionId);
|
|
265
|
+
/** Durably submit a prompt. Resolves before the model runs. */
|
|
266
|
+
submit(
|
|
267
|
+
input: OpenCodeInput,
|
|
268
|
+
options?: OpenCodeSubmitOptions
|
|
269
|
+
): Promise<OpenCodeReceipt>;
|
|
270
|
+
/** Submit and wait for the answer and the updated transcript. */
|
|
271
|
+
prompt(
|
|
272
|
+
input: OpenCodeInput,
|
|
273
|
+
options?: OpenCodeSubmitOptions
|
|
274
|
+
): Promise<OpenCodePromptResponse>;
|
|
275
|
+
/** Join the running work at its next step. */
|
|
276
|
+
steer(
|
|
277
|
+
input: OpenCodeInput,
|
|
278
|
+
options?: Omit<OpenCodeSubmitOptions, "whenBusy">
|
|
279
|
+
): Promise<OpenCodeReceipt>;
|
|
280
|
+
/** Wait for an operation to settle. Aborting `signal` stops only the wait. */
|
|
281
|
+
wait(
|
|
282
|
+
operationId: string,
|
|
283
|
+
signal?: AbortSignal
|
|
284
|
+
): Promise<OpenCodeOperationResult>;
|
|
285
|
+
/**
|
|
286
|
+
* Withdraw one queued operation (or interrupt the run it joined), or, with
|
|
287
|
+
* no id, abort the session: OpenCode's queued inputs are withdrawn and the
|
|
288
|
+
* running work is interrupted.
|
|
289
|
+
*/
|
|
290
|
+
abort(operationId?: string): Promise<boolean>;
|
|
291
|
+
/** Change this session's model; `agents/models/opencode` makes them. */
|
|
292
|
+
setModel(model: {
|
|
293
|
+
readonly providerID: string;
|
|
294
|
+
readonly id: string;
|
|
295
|
+
}): Promise<void>;
|
|
296
|
+
/** Change this session's OpenCode agent, such as `build` or `plan`. */
|
|
297
|
+
setAgent(agent: string): Promise<void>;
|
|
298
|
+
/** The active transcript: OpenCode's messages since the newest compaction. */
|
|
299
|
+
messages(): Promise<OpenCodeMessage[]>;
|
|
300
|
+
/**
|
|
301
|
+
* The whole transcript, oldest first, compacted messages included.
|
|
302
|
+
* OpenCode compacts a long session on its own; `messages()` is what the
|
|
303
|
+
* model sees after that, this is everything the session has said.
|
|
304
|
+
*/
|
|
305
|
+
history(): Promise<OpenCodeMessage[]>;
|
|
306
|
+
/**
|
|
307
|
+
* OpenCode's events for this session as they happen, durable and live
|
|
308
|
+
* (text deltas, tool input), until `signal` aborts. Read the transcript
|
|
309
|
+
* with `messages()` first for a snapshot; use `log()` to resume from a
|
|
310
|
+
* durable position instead.
|
|
311
|
+
*/
|
|
312
|
+
events(signal?: AbortSignal): AsyncIterable<OpenCodeEvent>;
|
|
313
|
+
/**
|
|
314
|
+
* The session's durable events after sequence number `after` (from the
|
|
315
|
+
* start by default), then, with `follow`, new ones as they are committed,
|
|
316
|
+
* until `signal` aborts.
|
|
317
|
+
*/
|
|
318
|
+
log(options?: {
|
|
319
|
+
readonly after?: number;
|
|
320
|
+
readonly follow?: boolean;
|
|
321
|
+
readonly signal?: AbortSignal;
|
|
322
|
+
}): AsyncIterable<OpenCodeLogEvent>;
|
|
323
|
+
/**
|
|
324
|
+
* Whether the session has work: running, input waiting, or a turn a
|
|
325
|
+
* restart cut off that OpenCode is about to resume.
|
|
326
|
+
*/
|
|
327
|
+
busy(): Promise<boolean>;
|
|
328
|
+
}
|
|
329
|
+
/** Every OpenCode session in this object. */
|
|
330
|
+
declare class OpenCodeSessions {
|
|
331
|
+
#private;
|
|
332
|
+
/** @param harness - The harness that hosts the sessions. */
|
|
333
|
+
constructor(harness: OpenCodeHarness);
|
|
334
|
+
/** A handle on one session. No I/O until you call it. */
|
|
335
|
+
get(id: OpenCodeSessionId): OpenCodeSession;
|
|
336
|
+
/** A new top-level session, configured like the root. */
|
|
337
|
+
create(): Promise<OpenCodeSession>;
|
|
338
|
+
/** A new session that sees `from`'s history up to now. */
|
|
339
|
+
fork(from: OpenCodeSessionId): Promise<OpenCodeSession>;
|
|
340
|
+
/** Every session, including subagent sessions OpenCode spawned. */
|
|
341
|
+
list(): Promise<OpenCodeSessionInfo[]>;
|
|
342
|
+
}
|
|
343
|
+
//#endregion
|
|
344
|
+
export {
|
|
345
|
+
type OpenCode,
|
|
346
|
+
type OpenCodeEvent,
|
|
347
|
+
OpenCodeHarness,
|
|
348
|
+
type OpenCodeHarnessContext,
|
|
349
|
+
type OpenCodeHarnessFactory,
|
|
350
|
+
type OpenCodeHarnessOptions,
|
|
351
|
+
type OpenCodeInput,
|
|
352
|
+
type OpenCodeLogEvent,
|
|
353
|
+
type OpenCodeMessage,
|
|
354
|
+
type OpenCodeModel,
|
|
355
|
+
type OpenCodeOperationResult,
|
|
356
|
+
type OpenCodePendingOperation,
|
|
357
|
+
type OpenCodePromptResponse,
|
|
358
|
+
type OpenCodeReceipt,
|
|
359
|
+
OpenCodeSession,
|
|
360
|
+
type OpenCodeSessionDefaults,
|
|
361
|
+
type OpenCodeSessionId,
|
|
362
|
+
type OpenCodeSessionInfo,
|
|
363
|
+
type OpenCodeSessionOptions,
|
|
364
|
+
OpenCodeSessions,
|
|
365
|
+
type OpenCodeSubmitOptions,
|
|
366
|
+
type OpenCodeWhenBusy,
|
|
367
|
+
ROOT_SESSION
|
|
368
|
+
};
|
|
369
|
+
//# sourceMappingURL=index.d.ts.map
|