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,481 @@
|
|
|
1
|
+
import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-DZBYAB34.js";
|
|
2
|
+
import { t as _classPrivateMethodInitSpec } from "./classPrivateMethodInitSpec-qMjJ6sHQ.js";
|
|
3
|
+
import { f as parseHostMessage, l as chunkEntries, t as CLOSE_REPLACED, u as inputText } from "./protocol-cOklVBBD.js";
|
|
4
|
+
//#region src/harness/container/daemon-core.ts
|
|
5
|
+
/**
|
|
6
|
+
* The harness daemon's core: everything about running an agent inside a
|
|
7
|
+
* container that does not depend on which agent it is.
|
|
8
|
+
*
|
|
9
|
+
* A daemon serves any number of sessions. For each one it keeps a queue of
|
|
10
|
+
* operations, runs them one at a time through an adapter, numbers every
|
|
11
|
+
* frame it produces, and keeps frames until the Durable Object acknowledges
|
|
12
|
+
* them, so a reconnecting object replays exactly what it missed. The
|
|
13
|
+
* adapter is the only agent-specific part: it opens a session (resuming it
|
|
14
|
+
* from state it persisted earlier, possibly in another container), runs one
|
|
15
|
+
* turn at a time, and reports what happens as `ContainerEvent`s.
|
|
16
|
+
*
|
|
17
|
+
* Nothing here touches Node, a socket library or a model SDK. The transport
|
|
18
|
+
* hands the daemon a `DaemonSocket` per connection and feeds it messages;
|
|
19
|
+
* `./runtime` does that over HTTP in a container, and the tests do it over
|
|
20
|
+
* a `WebSocketPair` in Workers.
|
|
21
|
+
*
|
|
22
|
+
* Modelled on the AI SDK's harness bridge (`runBridge`): the runtime owns
|
|
23
|
+
* the transport, sequencing and replay, and an adapter owns only the agent.
|
|
24
|
+
*
|
|
25
|
+
* @experimental The API may change before it stabilizes.
|
|
26
|
+
*/
|
|
27
|
+
/** Settled operations remembered per session, for `hello`. */
|
|
28
|
+
const SETTLED_KEPT = 1e3;
|
|
29
|
+
var _adapter = /* @__PURE__ */ new WeakMap();
|
|
30
|
+
var _runtimeId = /* @__PURE__ */ new WeakMap();
|
|
31
|
+
var _maxKeptFrames = /* @__PURE__ */ new WeakMap();
|
|
32
|
+
var _sessions = /* @__PURE__ */ new WeakMap();
|
|
33
|
+
/**
|
|
34
|
+
* The daemon core. One per container process.
|
|
35
|
+
*
|
|
36
|
+
* @experimental The API may change before it stabilizes.
|
|
37
|
+
*/
|
|
38
|
+
var ContainerDaemon = class {
|
|
39
|
+
/**
|
|
40
|
+
* @param options - The adapter and this container's id.
|
|
41
|
+
*/
|
|
42
|
+
constructor(options) {
|
|
43
|
+
_classPrivateFieldInitSpec(this, _adapter, void 0);
|
|
44
|
+
_classPrivateFieldInitSpec(this, _runtimeId, void 0);
|
|
45
|
+
_classPrivateFieldInitSpec(this, _maxKeptFrames, void 0);
|
|
46
|
+
_classPrivateFieldInitSpec(this, _sessions, /* @__PURE__ */ new Map());
|
|
47
|
+
_classPrivateFieldSet2(_adapter, this, options.adapter);
|
|
48
|
+
_classPrivateFieldSet2(_runtimeId, this, options.runtimeId);
|
|
49
|
+
_classPrivateFieldSet2(_maxKeptFrames, this, options.maxKeptFrames ?? 1e4);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Attach a connection for a session. A newer connection replaces an older
|
|
53
|
+
* one, which is closed with `CLOSE_REPLACED`. The daemon sends `hello`
|
|
54
|
+
* at once.
|
|
55
|
+
*
|
|
56
|
+
* @param session - The harness session id.
|
|
57
|
+
* @param socket - The send side.
|
|
58
|
+
* @returns The receive side, for the transport to drive.
|
|
59
|
+
*/
|
|
60
|
+
connect(session, socket) {
|
|
61
|
+
let state = _classPrivateFieldGet2(_sessions, this).get(session);
|
|
62
|
+
if (!state) {
|
|
63
|
+
state = new DaemonSession(session, _classPrivateFieldGet2(_adapter, this), _classPrivateFieldGet2(_runtimeId, this), _classPrivateFieldGet2(_maxKeptFrames, this));
|
|
64
|
+
_classPrivateFieldGet2(_sessions, this).set(session, state);
|
|
65
|
+
}
|
|
66
|
+
return state.attach(socket);
|
|
67
|
+
}
|
|
68
|
+
/** Close every adapter session, as the container shuts down. */
|
|
69
|
+
async close() {
|
|
70
|
+
await Promise.all([..._classPrivateFieldGet2(_sessions, this).values()].map((s) => s.shutdown()));
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var _id = /* @__PURE__ */ new WeakMap();
|
|
74
|
+
var _adapter2 = /* @__PURE__ */ new WeakMap();
|
|
75
|
+
var _runtimeId2 = /* @__PURE__ */ new WeakMap();
|
|
76
|
+
var _maxKeptFrames2 = /* @__PURE__ */ new WeakMap();
|
|
77
|
+
var _seq = /* @__PURE__ */ new WeakMap();
|
|
78
|
+
var _kept = /* @__PURE__ */ new WeakMap();
|
|
79
|
+
var _operations = /* @__PURE__ */ new WeakMap();
|
|
80
|
+
var _queue = /* @__PURE__ */ new WeakMap();
|
|
81
|
+
var _running = /* @__PURE__ */ new WeakMap();
|
|
82
|
+
var _opened = /* @__PURE__ */ new WeakMap();
|
|
83
|
+
var _restoring = /* @__PURE__ */ new WeakMap();
|
|
84
|
+
var _socket = /* @__PURE__ */ new WeakMap();
|
|
85
|
+
var _live = /* @__PURE__ */ new WeakMap();
|
|
86
|
+
var _inbox = /* @__PURE__ */ new WeakMap();
|
|
87
|
+
var _DaemonSession_brand = /* @__PURE__ */ new WeakSet();
|
|
88
|
+
var DaemonSession = class {
|
|
89
|
+
constructor(id, adapter, runtimeId, maxKeptFrames) {
|
|
90
|
+
_classPrivateMethodInitSpec(this, _DaemonSession_brand);
|
|
91
|
+
_classPrivateFieldInitSpec(this, _id, void 0);
|
|
92
|
+
_classPrivateFieldInitSpec(this, _adapter2, void 0);
|
|
93
|
+
_classPrivateFieldInitSpec(this, _runtimeId2, void 0);
|
|
94
|
+
_classPrivateFieldInitSpec(this, _maxKeptFrames2, void 0);
|
|
95
|
+
_classPrivateFieldInitSpec(this, _seq, 0);
|
|
96
|
+
_classPrivateFieldInitSpec(this, _kept, []);
|
|
97
|
+
_classPrivateFieldInitSpec(this, _operations, /* @__PURE__ */ new Map());
|
|
98
|
+
_classPrivateFieldInitSpec(this, _queue, []);
|
|
99
|
+
_classPrivateFieldInitSpec(this, _running, void 0);
|
|
100
|
+
_classPrivateFieldInitSpec(this, _opened, void 0);
|
|
101
|
+
_classPrivateFieldInitSpec(this, _restoring, void 0);
|
|
102
|
+
_classPrivateFieldInitSpec(this, _socket, void 0);
|
|
103
|
+
_classPrivateFieldInitSpec(this, _live, false);
|
|
104
|
+
_classPrivateFieldInitSpec(this, _inbox, Promise.resolve());
|
|
105
|
+
_classPrivateFieldSet2(_id, this, id);
|
|
106
|
+
_classPrivateFieldSet2(_adapter2, this, adapter);
|
|
107
|
+
_classPrivateFieldSet2(_runtimeId2, this, runtimeId);
|
|
108
|
+
_classPrivateFieldSet2(_maxKeptFrames2, this, maxKeptFrames);
|
|
109
|
+
}
|
|
110
|
+
attach(socket) {
|
|
111
|
+
const previous = _classPrivateFieldGet2(_socket, this);
|
|
112
|
+
_classPrivateFieldSet2(_socket, this, socket);
|
|
113
|
+
_classPrivateFieldSet2(_live, this, false);
|
|
114
|
+
previous?.close(CLOSE_REPLACED, "replaced by a newer connection");
|
|
115
|
+
_assertClassBrand(_DaemonSession_brand, this, _send).call(this, socket, _assertClassBrand(_DaemonSession_brand, this, _hello).call(this));
|
|
116
|
+
return {
|
|
117
|
+
receive: (text) => {
|
|
118
|
+
if (_classPrivateFieldGet2(_socket, this) !== socket) return;
|
|
119
|
+
const message = parseHostMessage(text);
|
|
120
|
+
if (!message) {
|
|
121
|
+
_assertClassBrand(_DaemonSession_brand, this, _send).call(this, socket, {
|
|
122
|
+
type: "error",
|
|
123
|
+
message: "unparseable message"
|
|
124
|
+
});
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
_classPrivateFieldSet2(_inbox, this, _classPrivateFieldGet2(_inbox, this).then(() => _assertClassBrand(_DaemonSession_brand, this, _handle).call(this, message)).catch((error) => {
|
|
128
|
+
_assertClassBrand(_DaemonSession_brand, this, _send).call(this, socket, {
|
|
129
|
+
type: "error",
|
|
130
|
+
message: errorText(error)
|
|
131
|
+
});
|
|
132
|
+
}));
|
|
133
|
+
},
|
|
134
|
+
closed: () => {
|
|
135
|
+
if (_classPrivateFieldGet2(_socket, this) !== socket) return;
|
|
136
|
+
_classPrivateFieldSet2(_socket, this, void 0);
|
|
137
|
+
_classPrivateFieldSet2(_live, this, false);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
async shutdown() {
|
|
142
|
+
_classPrivateFieldGet2(_running, this)?.controller.abort();
|
|
143
|
+
const opened = _classPrivateFieldGet2(_opened, this);
|
|
144
|
+
_classPrivateFieldSet2(_opened, this, void 0);
|
|
145
|
+
await opened?.session.close().catch(() => void 0);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
function _hello() {
|
|
149
|
+
const operations = [];
|
|
150
|
+
for (const operation of _classPrivateFieldGet2(_operations, this).values()) {
|
|
151
|
+
const state = operation.state;
|
|
152
|
+
operations.push(state.tag === "settled" ? {
|
|
153
|
+
operationId: operation.id,
|
|
154
|
+
status: "settled",
|
|
155
|
+
outcome: state.outcome
|
|
156
|
+
} : {
|
|
157
|
+
operationId: operation.id,
|
|
158
|
+
status: state.tag
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
type: "hello",
|
|
163
|
+
protocol: 1,
|
|
164
|
+
runtimeId: _classPrivateFieldGet2(_runtimeId2, this),
|
|
165
|
+
session: _classPrivateFieldGet2(_id, this),
|
|
166
|
+
adapter: {
|
|
167
|
+
id: _classPrivateFieldGet2(_adapter2, this).id,
|
|
168
|
+
version: _classPrivateFieldGet2(_adapter2, this).version,
|
|
169
|
+
capabilities: [..._classPrivateFieldGet2(_adapter2, this).capabilities ?? []]
|
|
170
|
+
},
|
|
171
|
+
open: _classPrivateFieldGet2(_opened, this)?.generation ?? null,
|
|
172
|
+
lastSeq: _classPrivateFieldGet2(_seq, this),
|
|
173
|
+
operations
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
async function _handle(message) {
|
|
177
|
+
switch (message.type) {
|
|
178
|
+
case "restore":
|
|
179
|
+
if (_classPrivateFieldGet2(_restoring, this)?.generation !== message.generation) _classPrivateFieldSet2(_restoring, this, {
|
|
180
|
+
generation: message.generation,
|
|
181
|
+
entries: []
|
|
182
|
+
});
|
|
183
|
+
_classPrivateFieldGet2(_restoring, this).entries.push(...message.entries);
|
|
184
|
+
return;
|
|
185
|
+
case "open":
|
|
186
|
+
await _assertClassBrand(_DaemonSession_brand, this, _open).call(this, message);
|
|
187
|
+
return;
|
|
188
|
+
case "replay":
|
|
189
|
+
_assertClassBrand(_DaemonSession_brand, this, _replay).call(this, message.after);
|
|
190
|
+
return;
|
|
191
|
+
case "prompt":
|
|
192
|
+
await _assertClassBrand(_DaemonSession_brand, this, _prompt).call(this, message.operationId, message.input, message.whenBusy);
|
|
193
|
+
return;
|
|
194
|
+
case "abort":
|
|
195
|
+
_assertClassBrand(_DaemonSession_brand, this, _abort).call(this, message.operationId);
|
|
196
|
+
return;
|
|
197
|
+
case "configure":
|
|
198
|
+
await _classPrivateFieldGet2(_opened, this)?.session.configure?.(message.settings);
|
|
199
|
+
return;
|
|
200
|
+
case "ack":
|
|
201
|
+
_classPrivateFieldSet2(_kept, this, _classPrivateFieldGet2(_kept, this).filter((kept) => kept.seq > message.seq));
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async function _open(message) {
|
|
206
|
+
const restoring = _classPrivateFieldGet2(_restoring, this);
|
|
207
|
+
_classPrivateFieldSet2(_restoring, this, void 0);
|
|
208
|
+
if (_classPrivateFieldGet2(_opened, this)?.generation === message.generation) return;
|
|
209
|
+
const restore = restoring?.generation === message.generation ? [...restoring.entries, ...message.restore] : message.restore;
|
|
210
|
+
if (_classPrivateFieldGet2(_opened, this)) {
|
|
211
|
+
_classPrivateFieldGet2(_running, this)?.controller.abort();
|
|
212
|
+
await _classPrivateFieldGet2(_opened, this).session.close().catch(() => void 0);
|
|
213
|
+
_classPrivateFieldSet2(_opened, this, void 0);
|
|
214
|
+
}
|
|
215
|
+
const session = await _classPrivateFieldGet2(_adapter2, this).open({
|
|
216
|
+
session: _classPrivateFieldGet2(_id, this),
|
|
217
|
+
settings: message.settings,
|
|
218
|
+
restore,
|
|
219
|
+
emit: (event) => _assertClassBrand(_DaemonSession_brand, this, _emit).call(this, {
|
|
220
|
+
kind: "event",
|
|
221
|
+
operationId: _classPrivateFieldGet2(_running, this)?.id ?? null,
|
|
222
|
+
event
|
|
223
|
+
}),
|
|
224
|
+
persist: (entries) => {
|
|
225
|
+
for (const group of chunkEntries(entries)) _assertClassBrand(_DaemonSession_brand, this, _emit).call(this, {
|
|
226
|
+
kind: "persist",
|
|
227
|
+
entries: group
|
|
228
|
+
});
|
|
229
|
+
},
|
|
230
|
+
log: (level, text) => _assertClassBrand(_DaemonSession_brand, this, _emit).call(this, {
|
|
231
|
+
kind: "event",
|
|
232
|
+
operationId: _classPrivateFieldGet2(_running, this)?.id ?? null,
|
|
233
|
+
event: {
|
|
234
|
+
type: "log",
|
|
235
|
+
level,
|
|
236
|
+
message: text
|
|
237
|
+
}
|
|
238
|
+
})
|
|
239
|
+
});
|
|
240
|
+
_classPrivateFieldSet2(_opened, this, {
|
|
241
|
+
generation: message.generation,
|
|
242
|
+
session
|
|
243
|
+
});
|
|
244
|
+
_assertClassBrand(_DaemonSession_brand, this, _pump).call(this);
|
|
245
|
+
}
|
|
246
|
+
function _replay(after) {
|
|
247
|
+
const socket = _classPrivateFieldGet2(_socket, this);
|
|
248
|
+
if (!socket) return;
|
|
249
|
+
for (const kept of _classPrivateFieldGet2(_kept, this)) if (kept.seq > after) _assertClassBrand(_DaemonSession_brand, this, _send).call(this, socket, {
|
|
250
|
+
type: "frame",
|
|
251
|
+
seq: kept.seq,
|
|
252
|
+
frame: kept.frame
|
|
253
|
+
});
|
|
254
|
+
_assertClassBrand(_DaemonSession_brand, this, _send).call(this, socket, {
|
|
255
|
+
type: "caught-up",
|
|
256
|
+
lastSeq: _classPrivateFieldGet2(_seq, this)
|
|
257
|
+
});
|
|
258
|
+
_classPrivateFieldSet2(_live, this, true);
|
|
259
|
+
}
|
|
260
|
+
async function _prompt(id, input, whenBusy) {
|
|
261
|
+
if (_classPrivateFieldGet2(_operations, this).has(id)) return;
|
|
262
|
+
const operation = {
|
|
263
|
+
id,
|
|
264
|
+
input,
|
|
265
|
+
whenBusy,
|
|
266
|
+
state: { tag: "queued" }
|
|
267
|
+
};
|
|
268
|
+
_classPrivateFieldGet2(_operations, this).set(id, operation);
|
|
269
|
+
_assertClassBrand(_DaemonSession_brand, this, _forgetOldSettled).call(this);
|
|
270
|
+
const running = _classPrivateFieldGet2(_running, this);
|
|
271
|
+
const steer = _classPrivateFieldGet2(_opened, this)?.session.steer;
|
|
272
|
+
if (whenBusy === "steer" && running && steer) {
|
|
273
|
+
if (await steer.call(_classPrivateFieldGet2(_opened, this)?.session, input) && _classPrivateFieldGet2(_running, this) === running) {
|
|
274
|
+
operation.state = { tag: "running" };
|
|
275
|
+
running.folded.push(id);
|
|
276
|
+
_assertClassBrand(_DaemonSession_brand, this, _emit).call(this, {
|
|
277
|
+
kind: "start",
|
|
278
|
+
operationId: id
|
|
279
|
+
});
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
_classPrivateFieldGet2(_queue, this).push(id);
|
|
284
|
+
_assertClassBrand(_DaemonSession_brand, this, _pump).call(this);
|
|
285
|
+
}
|
|
286
|
+
function _abort(id) {
|
|
287
|
+
const ids = id === void 0 ? [..._classPrivateFieldGet2(_operations, this).keys()] : _classPrivateFieldGet2(_operations, this).has(id) ? [id] : [];
|
|
288
|
+
for (const each of ids) {
|
|
289
|
+
const operation = _classPrivateFieldGet2(_operations, this).get(each);
|
|
290
|
+
if (!operation) continue;
|
|
291
|
+
if (operation.state.tag === "queued") {
|
|
292
|
+
const at = _classPrivateFieldGet2(_queue, this).indexOf(each);
|
|
293
|
+
if (at >= 0) _classPrivateFieldGet2(_queue, this).splice(at, 1);
|
|
294
|
+
_assertClassBrand(_DaemonSession_brand, this, _settle).call(this, operation, {
|
|
295
|
+
status: "unanswered",
|
|
296
|
+
reason: "aborted"
|
|
297
|
+
});
|
|
298
|
+
} else if (operation.state.tag === "running") _classPrivateFieldGet2(_running, this)?.controller.abort();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/** Start the next queued operation, if the session is open and idle. */
|
|
302
|
+
function _pump() {
|
|
303
|
+
const opened = _classPrivateFieldGet2(_opened, this);
|
|
304
|
+
if (_classPrivateFieldGet2(_running, this) || !opened) return;
|
|
305
|
+
const id = _classPrivateFieldGet2(_queue, this).shift();
|
|
306
|
+
if (id === void 0) return;
|
|
307
|
+
const operation = _classPrivateFieldGet2(_operations, this).get(id);
|
|
308
|
+
if (!operation || operation.state.tag !== "queued") {
|
|
309
|
+
_assertClassBrand(_DaemonSession_brand, this, _pump).call(this);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const running = {
|
|
313
|
+
id,
|
|
314
|
+
folded: [],
|
|
315
|
+
controller: new AbortController()
|
|
316
|
+
};
|
|
317
|
+
_classPrivateFieldSet2(_running, this, running);
|
|
318
|
+
operation.state = { tag: "running" };
|
|
319
|
+
_assertClassBrand(_DaemonSession_brand, this, _emit).call(this, {
|
|
320
|
+
kind: "start",
|
|
321
|
+
operationId: id
|
|
322
|
+
});
|
|
323
|
+
_assertClassBrand(_DaemonSession_brand, this, _run).call(this, opened, operation, running);
|
|
324
|
+
}
|
|
325
|
+
async function _run(opened, operation, running) {
|
|
326
|
+
let outcome;
|
|
327
|
+
try {
|
|
328
|
+
outcome = await opened.session.run({
|
|
329
|
+
operationId: operation.id,
|
|
330
|
+
input: operation.input,
|
|
331
|
+
signal: running.controller.signal
|
|
332
|
+
});
|
|
333
|
+
if (running.controller.signal.aborted && outcome.status === "done") outcome = {
|
|
334
|
+
status: "unanswered",
|
|
335
|
+
reason: "aborted"
|
|
336
|
+
};
|
|
337
|
+
} catch (error) {
|
|
338
|
+
outcome = {
|
|
339
|
+
status: "unanswered",
|
|
340
|
+
reason: running.controller.signal.aborted ? "aborted" : errorText(error)
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
if (_classPrivateFieldGet2(_running, this) === running) _classPrivateFieldSet2(_running, this, void 0);
|
|
344
|
+
_assertClassBrand(_DaemonSession_brand, this, _settle).call(this, operation, outcome);
|
|
345
|
+
for (const folded of running.folded) {
|
|
346
|
+
const each = _classPrivateFieldGet2(_operations, this).get(folded);
|
|
347
|
+
if (each) _assertClassBrand(_DaemonSession_brand, this, _settle).call(this, each, outcome);
|
|
348
|
+
}
|
|
349
|
+
_assertClassBrand(_DaemonSession_brand, this, _pump).call(this);
|
|
350
|
+
}
|
|
351
|
+
function _settle(operation, outcome) {
|
|
352
|
+
if (operation.state.tag === "settled") return;
|
|
353
|
+
operation.state = {
|
|
354
|
+
tag: "settled",
|
|
355
|
+
outcome
|
|
356
|
+
};
|
|
357
|
+
_assertClassBrand(_DaemonSession_brand, this, _emit).call(this, {
|
|
358
|
+
kind: "settle",
|
|
359
|
+
operationId: operation.id,
|
|
360
|
+
outcome
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
function _emit(frame) {
|
|
364
|
+
_classPrivateFieldSet2(_seq, this, _classPrivateFieldGet2(_seq, this) + 1);
|
|
365
|
+
const seq = _classPrivateFieldGet2(_seq, this);
|
|
366
|
+
_classPrivateFieldGet2(_kept, this).push({
|
|
367
|
+
seq,
|
|
368
|
+
frame
|
|
369
|
+
});
|
|
370
|
+
if (_classPrivateFieldGet2(_kept, this).length > _classPrivateFieldGet2(_maxKeptFrames2, this)) _classPrivateFieldGet2(_kept, this).splice(0, _classPrivateFieldGet2(_kept, this).length - _classPrivateFieldGet2(_maxKeptFrames2, this));
|
|
371
|
+
const socket = _classPrivateFieldGet2(_socket, this);
|
|
372
|
+
if (socket && _classPrivateFieldGet2(_live, this)) _assertClassBrand(_DaemonSession_brand, this, _send).call(this, socket, {
|
|
373
|
+
type: "frame",
|
|
374
|
+
seq,
|
|
375
|
+
frame
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
function _send(socket, message) {
|
|
379
|
+
try {
|
|
380
|
+
socket.send(JSON.stringify(message));
|
|
381
|
+
} catch {}
|
|
382
|
+
}
|
|
383
|
+
function _forgetOldSettled() {
|
|
384
|
+
if (_classPrivateFieldGet2(_operations, this).size <= SETTLED_KEPT) return;
|
|
385
|
+
for (const [id, operation] of _classPrivateFieldGet2(_operations, this)) {
|
|
386
|
+
if (_classPrivateFieldGet2(_operations, this).size <= SETTLED_KEPT) return;
|
|
387
|
+
if (operation.state.tag === "settled") _classPrivateFieldGet2(_operations, this).delete(id);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
function errorText(error) {
|
|
391
|
+
return error instanceof Error ? error.message : String(error);
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* A reference adapter that answers `echo: <text>` and needs no model or
|
|
395
|
+
* credentials. Use it for keyless smoke deploys of the whole path and in
|
|
396
|
+
* tests. It persists one entry per turn and counts them back after a
|
|
397
|
+
* restore, so a resumed session visibly remembers its history:
|
|
398
|
+
*
|
|
399
|
+
* - `slow <ms> <text>` waits `ms` before answering, and stops on abort.
|
|
400
|
+
* - `fail <reason>` settles the operation unanswered with `reason`.
|
|
401
|
+
* - anything else is echoed with the turn number: `echo: hi (turn 3)`.
|
|
402
|
+
*
|
|
403
|
+
* @experimental The API may change before it stabilizes.
|
|
404
|
+
*/
|
|
405
|
+
const echoAdapter = {
|
|
406
|
+
id: "echo",
|
|
407
|
+
version: "1",
|
|
408
|
+
capabilities: ["steer"],
|
|
409
|
+
open(context) {
|
|
410
|
+
let turns = context.restore.length;
|
|
411
|
+
const steered = [];
|
|
412
|
+
return {
|
|
413
|
+
async run(turn) {
|
|
414
|
+
const text = inputText(turn.input);
|
|
415
|
+
const slow = /^slow (\d+) ?(.*)$/s.exec(text);
|
|
416
|
+
if (slow) await sleep(Number(slow[1]), turn.signal);
|
|
417
|
+
const failure = /^fail ?(.*)$/s.exec(text);
|
|
418
|
+
if (failure) return {
|
|
419
|
+
status: "unanswered",
|
|
420
|
+
reason: failure[1] || "failed"
|
|
421
|
+
};
|
|
422
|
+
turns += 1;
|
|
423
|
+
const body = slow ? slow[2] ?? "" : text;
|
|
424
|
+
const answer = `echo: ${body}${steered.splice(0).map((s) => ` + ${s}`).join("")} (turn ${turns})`;
|
|
425
|
+
const messageId = `${turn.operationId}:assistant`;
|
|
426
|
+
context.emit({
|
|
427
|
+
type: "text-delta",
|
|
428
|
+
messageId,
|
|
429
|
+
delta: answer
|
|
430
|
+
});
|
|
431
|
+
context.emit({
|
|
432
|
+
type: "message",
|
|
433
|
+
message: {
|
|
434
|
+
id: messageId,
|
|
435
|
+
role: "assistant",
|
|
436
|
+
parts: [{
|
|
437
|
+
type: "text",
|
|
438
|
+
text: answer
|
|
439
|
+
}],
|
|
440
|
+
operationId: turn.operationId,
|
|
441
|
+
createdAt: Date.now()
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
context.persist([{
|
|
445
|
+
turn: turns,
|
|
446
|
+
text: body
|
|
447
|
+
}]);
|
|
448
|
+
return {
|
|
449
|
+
status: "done",
|
|
450
|
+
text: answer
|
|
451
|
+
};
|
|
452
|
+
},
|
|
453
|
+
steer(input) {
|
|
454
|
+
steered.push(inputText(input));
|
|
455
|
+
return true;
|
|
456
|
+
},
|
|
457
|
+
async close() {}
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
function sleep(ms, signal) {
|
|
462
|
+
return new Promise((resolve, reject) => {
|
|
463
|
+
if (signal.aborted) {
|
|
464
|
+
reject(/* @__PURE__ */ new Error("aborted"));
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
const timer = setTimeout(() => {
|
|
468
|
+
signal.removeEventListener("abort", onAbort);
|
|
469
|
+
resolve();
|
|
470
|
+
}, ms);
|
|
471
|
+
const onAbort = () => {
|
|
472
|
+
clearTimeout(timer);
|
|
473
|
+
reject(/* @__PURE__ */ new Error("aborted"));
|
|
474
|
+
};
|
|
475
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
//#endregion
|
|
479
|
+
export { echoAdapter as n, ContainerDaemon as t };
|
|
480
|
+
|
|
481
|
+
//# sourceMappingURL=daemon-core-Buubj-y1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-core-Buubj-y1.js","names":[],"sources":["../src/harness/container/daemon-core.ts"],"sourcesContent":["/**\n * The harness daemon's core: everything about running an agent inside a\n * container that does not depend on which agent it is.\n *\n * A daemon serves any number of sessions. For each one it keeps a queue of\n * operations, runs them one at a time through an adapter, numbers every\n * frame it produces, and keeps frames until the Durable Object acknowledges\n * them, so a reconnecting object replays exactly what it missed. The\n * adapter is the only agent-specific part: it opens a session (resuming it\n * from state it persisted earlier, possibly in another container), runs one\n * turn at a time, and reports what happens as `ContainerEvent`s.\n *\n * Nothing here touches Node, a socket library or a model SDK. The transport\n * hands the daemon a `DaemonSocket` per connection and feeds it messages;\n * `./runtime` does that over HTTP in a container, and the tests do it over\n * a `WebSocketPair` in Workers.\n *\n * Modelled on the AI SDK's harness bridge (`runBridge`): the runtime owns\n * the transport, sequencing and replay, and an adapter owns only the agent.\n *\n * @experimental The API may change before it stabilizes.\n */\n\nimport {\n chunkEntries,\n CLOSE_REPLACED,\n CONTAINER_PROTOCOL_VERSION,\n inputText,\n parseHostMessage,\n type ContainerEvent,\n type ContainerInput,\n type ContainerOutcome,\n type ContainerSettings,\n type ContainerWhenBusy,\n type DaemonFrame,\n type DaemonMessage,\n type DaemonOperation,\n type HostMessage,\n type JsonValue\n} from \"./protocol\";\n\n/** What an adapter is told when its session opens. */\nexport type AdapterContext = {\n /** The harness session id. */\n readonly session: string;\n readonly settings: ContainerSettings;\n /**\n * Everything this adapter `persist`ed for the session before, possibly in\n * another container, oldest first. Empty for a new session.\n */\n readonly restore: readonly JsonValue[];\n /** Report an event. It belongs to the operation that is running, if any. */\n emit(event: ContainerEvent): void;\n /**\n * Keep resume state. The Durable Object stores the entries and passes all\n * of them back as `restore` when the session opens in a new container.\n */\n persist(entries: readonly JsonValue[]): void;\n /** A diagnostic line, reported as a `log` event. */\n log(level: \"info\" | \"warn\" | \"error\", message: string): void;\n};\n\n/** One turn an adapter runs. */\nexport type AdapterTurn = {\n readonly operationId: string;\n readonly input: ContainerInput;\n /** Aborted when the operation is aborted. Wind down promptly. */\n readonly signal: AbortSignal;\n};\n\n/** An open adapter session. Turns are never run concurrently. */\nexport type AdapterSession = {\n /**\n * Run one turn to completion. A rejection settles the operation\n * `unanswered` with the error's message.\n */\n run(turn: AdapterTurn): Promise<ContainerOutcome>;\n /**\n * Fold input into the running turn. Return false to have it queued as a\n * follow-up instead. Absent when the agent cannot be steered.\n */\n steer?(input: ContainerInput): boolean | Promise<boolean>;\n /** Apply new settings to the open session. */\n configure?(settings: ContainerSettings): void | Promise<void>;\n /** Release the session's resources. */\n close(): Promise<void>;\n};\n\n/** An agent, as the daemon runs it. */\nexport type ContainerAdapter = {\n /** Reported in `hello`, such as `\"claude-code\"`. */\n readonly id: string;\n readonly version: string;\n /** Free-form capability names, reported in `hello`. */\n readonly capabilities?: readonly string[];\n /** Open (or resume) one session. */\n open(context: AdapterContext): AdapterSession | Promise<AdapterSession>;\n};\n\n/** The send side of one connection, supplied by the transport. */\nexport type DaemonSocket = {\n send(text: string): void;\n close(code: number, reason: string): void;\n};\n\n/** The receive side of one connection, driven by the transport. */\nexport type DaemonConnection = {\n /** A message arrived. */\n receive(text: string): void;\n /** The connection closed. */\n closed(): void;\n};\n\n/** `ContainerDaemon`'s options. */\nexport type ContainerDaemonOptions = {\n readonly adapter: ContainerAdapter;\n /** This container's id, from `CONTAINER_ENV.runtimeId`. */\n readonly runtimeId: string;\n /**\n * Most unacknowledged frames kept per session. Older ones are dropped and\n * the object reconciles from `hello` instead. Default 10_000.\n */\n readonly maxKeptFrames?: number;\n};\n\n/** Settled operations remembered per session, for `hello`. */\nconst SETTLED_KEPT = 1_000;\n\ntype Operation = {\n readonly id: string;\n readonly input: ContainerInput;\n readonly whenBusy: ContainerWhenBusy;\n state:\n | { readonly tag: \"queued\" }\n | { readonly tag: \"running\" }\n | { readonly tag: \"settled\"; readonly outcome: ContainerOutcome };\n};\n\ntype Running = {\n readonly id: string;\n /** Operations steered into this turn; they settle with it. */\n readonly folded: string[];\n readonly controller: AbortController;\n};\n\ntype Opened = {\n readonly generation: number;\n readonly session: AdapterSession;\n};\n\n/**\n * The daemon core. One per container process.\n *\n * @experimental The API may change before it stabilizes.\n */\nexport class ContainerDaemon {\n readonly #adapter: ContainerAdapter;\n readonly #runtimeId: string;\n readonly #maxKeptFrames: number;\n readonly #sessions = new Map<string, DaemonSession>();\n\n /**\n * @param options - The adapter and this container's id.\n */\n constructor(options: ContainerDaemonOptions) {\n this.#adapter = options.adapter;\n this.#runtimeId = options.runtimeId;\n this.#maxKeptFrames = options.maxKeptFrames ?? 10_000;\n }\n\n /**\n * Attach a connection for a session. A newer connection replaces an older\n * one, which is closed with `CLOSE_REPLACED`. The daemon sends `hello`\n * at once.\n *\n * @param session - The harness session id.\n * @param socket - The send side.\n * @returns The receive side, for the transport to drive.\n */\n connect(session: string, socket: DaemonSocket): DaemonConnection {\n let state = this.#sessions.get(session);\n if (!state) {\n state = new DaemonSession(\n session,\n this.#adapter,\n this.#runtimeId,\n this.#maxKeptFrames\n );\n this.#sessions.set(session, state);\n }\n return state.attach(socket);\n }\n\n /** Close every adapter session, as the container shuts down. */\n async close(): Promise<void> {\n await Promise.all([...this.#sessions.values()].map((s) => s.shutdown()));\n }\n}\n\nclass DaemonSession {\n readonly #id: string;\n readonly #adapter: ContainerAdapter;\n readonly #runtimeId: string;\n readonly #maxKeptFrames: number;\n #seq = 0;\n #kept: { readonly seq: number; readonly frame: DaemonFrame }[] = [];\n readonly #operations = new Map<string, Operation>();\n readonly #queue: string[] = [];\n #running: Running | undefined;\n #opened: Opened | undefined;\n /** Resume state received for an `open` that has not arrived yet. */\n #restoring: { generation: number; entries: JsonValue[] } | undefined;\n #socket: DaemonSocket | undefined;\n #live = false;\n /** Host messages are handled one at a time, in order. */\n #inbox: Promise<void> = Promise.resolve();\n\n constructor(\n id: string,\n adapter: ContainerAdapter,\n runtimeId: string,\n maxKeptFrames: number\n ) {\n this.#id = id;\n this.#adapter = adapter;\n this.#runtimeId = runtimeId;\n this.#maxKeptFrames = maxKeptFrames;\n }\n\n attach(socket: DaemonSocket): DaemonConnection {\n const previous = this.#socket;\n this.#socket = socket;\n this.#live = false;\n previous?.close(CLOSE_REPLACED, \"replaced by a newer connection\");\n this.#send(socket, this.#hello());\n return {\n receive: (text) => {\n if (this.#socket !== socket) return;\n const message = parseHostMessage(text);\n if (!message) {\n this.#send(socket, { type: \"error\", message: \"unparseable message\" });\n return;\n }\n this.#inbox = this.#inbox\n .then(() => this.#handle(message))\n .catch((error: unknown) => {\n this.#send(socket, { type: \"error\", message: errorText(error) });\n });\n },\n closed: () => {\n if (this.#socket !== socket) return;\n this.#socket = undefined;\n this.#live = false;\n }\n };\n }\n\n async shutdown(): Promise<void> {\n this.#running?.controller.abort();\n const opened = this.#opened;\n this.#opened = undefined;\n await opened?.session.close().catch(() => undefined);\n }\n\n #hello(): DaemonMessage {\n const operations: DaemonOperation[] = [];\n for (const operation of this.#operations.values()) {\n const state = operation.state;\n operations.push(\n state.tag === \"settled\"\n ? {\n operationId: operation.id,\n status: \"settled\",\n outcome: state.outcome\n }\n : { operationId: operation.id, status: state.tag }\n );\n }\n return {\n type: \"hello\",\n protocol: CONTAINER_PROTOCOL_VERSION,\n runtimeId: this.#runtimeId,\n session: this.#id,\n adapter: {\n id: this.#adapter.id,\n version: this.#adapter.version,\n capabilities: [...(this.#adapter.capabilities ?? [])]\n },\n open: this.#opened?.generation ?? null,\n lastSeq: this.#seq,\n operations\n };\n }\n\n async #handle(message: HostMessage): Promise<void> {\n switch (message.type) {\n case \"restore\":\n if (this.#restoring?.generation !== message.generation) {\n this.#restoring = { generation: message.generation, entries: [] };\n }\n this.#restoring.entries.push(...message.entries);\n return;\n case \"open\":\n await this.#open(message);\n return;\n case \"replay\":\n this.#replay(message.after);\n return;\n case \"prompt\":\n await this.#prompt(\n message.operationId,\n message.input,\n message.whenBusy\n );\n return;\n case \"abort\":\n this.#abort(message.operationId);\n return;\n case \"configure\":\n await this.#opened?.session.configure?.(message.settings);\n return;\n case \"ack\":\n this.#kept = this.#kept.filter((kept) => kept.seq > message.seq);\n return;\n }\n }\n\n async #open(message: Extract<HostMessage, { type: \"open\" }>): Promise<void> {\n const restoring = this.#restoring;\n this.#restoring = undefined;\n if (this.#opened?.generation === message.generation) return;\n const restore =\n restoring?.generation === message.generation\n ? [...restoring.entries, ...message.restore]\n : message.restore;\n if (this.#opened) {\n // A new generation (a reset) replaces the\n // open session. The turn running in it cannot continue.\n this.#running?.controller.abort();\n await this.#opened.session.close().catch(() => undefined);\n this.#opened = undefined;\n }\n const session = await this.#adapter.open({\n session: this.#id,\n settings: message.settings,\n restore,\n emit: (event) =>\n this.#emit({\n kind: \"event\",\n operationId: this.#running?.id ?? null,\n event\n }),\n persist: (entries) => {\n for (const group of chunkEntries(entries)) {\n this.#emit({ kind: \"persist\", entries: group });\n }\n },\n log: (level, text) =>\n this.#emit({\n kind: \"event\",\n operationId: this.#running?.id ?? null,\n event: { type: \"log\", level, message: text }\n })\n });\n this.#opened = { generation: message.generation, session };\n this.#pump();\n }\n\n #replay(after: number): void {\n const socket = this.#socket;\n if (!socket) return;\n for (const kept of this.#kept) {\n if (kept.seq > after) {\n this.#send(socket, { type: \"frame\", seq: kept.seq, frame: kept.frame });\n }\n }\n this.#send(socket, { type: \"caught-up\", lastSeq: this.#seq });\n this.#live = true;\n }\n\n async #prompt(\n id: string,\n input: ContainerInput,\n whenBusy: ContainerWhenBusy\n ): Promise<void> {\n if (this.#operations.has(id)) return;\n const operation: Operation = {\n id,\n input,\n whenBusy,\n state: { tag: \"queued\" }\n };\n this.#operations.set(id, operation);\n this.#forgetOldSettled();\n const running = this.#running;\n const steer = this.#opened?.session.steer;\n if (whenBusy === \"steer\" && running && steer) {\n const folded = await steer.call(this.#opened?.session, input);\n if (folded && this.#running === running) {\n operation.state = { tag: \"running\" };\n running.folded.push(id);\n this.#emit({ kind: \"start\", operationId: id });\n return;\n }\n }\n this.#queue.push(id);\n this.#pump();\n }\n\n #abort(id: string | undefined): void {\n const ids =\n id === undefined\n ? [...this.#operations.keys()]\n : this.#operations.has(id)\n ? [id]\n : [];\n for (const each of ids) {\n const operation = this.#operations.get(each);\n if (!operation) continue;\n if (operation.state.tag === \"queued\") {\n const at = this.#queue.indexOf(each);\n if (at >= 0) this.#queue.splice(at, 1);\n this.#settle(operation, { status: \"unanswered\", reason: \"aborted\" });\n } else if (operation.state.tag === \"running\") {\n // A steered operation shares its turn: aborting it aborts the turn.\n this.#running?.controller.abort();\n }\n }\n }\n\n /** Start the next queued operation, if the session is open and idle. */\n #pump(): void {\n const opened = this.#opened;\n if (this.#running || !opened) return;\n const id = this.#queue.shift();\n if (id === undefined) return;\n const operation = this.#operations.get(id);\n if (!operation || operation.state.tag !== \"queued\") {\n this.#pump();\n return;\n }\n const running: Running = {\n id,\n folded: [],\n controller: new AbortController()\n };\n this.#running = running;\n operation.state = { tag: \"running\" };\n this.#emit({ kind: \"start\", operationId: id });\n void this.#run(opened, operation, running);\n }\n\n async #run(\n opened: Opened,\n operation: Operation,\n running: Running\n ): Promise<void> {\n let outcome: ContainerOutcome;\n try {\n outcome = await opened.session.run({\n operationId: operation.id,\n input: operation.input,\n signal: running.controller.signal\n });\n if (running.controller.signal.aborted && outcome.status === \"done\") {\n outcome = { status: \"unanswered\", reason: \"aborted\" };\n }\n } catch (error) {\n outcome = {\n status: \"unanswered\",\n reason: running.controller.signal.aborted ? \"aborted\" : errorText(error)\n };\n }\n if (this.#running === running) this.#running = undefined;\n this.#settle(operation, outcome);\n for (const folded of running.folded) {\n const each = this.#operations.get(folded);\n if (each) this.#settle(each, outcome);\n }\n this.#pump();\n }\n\n #settle(operation: Operation, outcome: ContainerOutcome): void {\n if (operation.state.tag === \"settled\") return;\n operation.state = { tag: \"settled\", outcome };\n this.#emit({ kind: \"settle\", operationId: operation.id, outcome });\n }\n\n #emit(frame: DaemonFrame): void {\n this.#seq += 1;\n const seq = this.#seq;\n this.#kept.push({ seq, frame });\n if (this.#kept.length > this.#maxKeptFrames) {\n this.#kept.splice(0, this.#kept.length - this.#maxKeptFrames);\n }\n const socket = this.#socket;\n if (socket && this.#live) this.#send(socket, { type: \"frame\", seq, frame });\n }\n\n #send(socket: DaemonSocket, message: DaemonMessage): void {\n try {\n socket.send(JSON.stringify(message));\n } catch {\n // The socket closed under us. The frame is kept and replayed.\n }\n }\n\n #forgetOldSettled(): void {\n if (this.#operations.size <= SETTLED_KEPT) return;\n for (const [id, operation] of this.#operations) {\n if (this.#operations.size <= SETTLED_KEPT) return;\n if (operation.state.tag === \"settled\") this.#operations.delete(id);\n }\n }\n}\n\nfunction errorText(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * A reference adapter that answers `echo: <text>` and needs no model or\n * credentials. Use it for keyless smoke deploys of the whole path and in\n * tests. It persists one entry per turn and counts them back after a\n * restore, so a resumed session visibly remembers its history:\n *\n * - `slow <ms> <text>` waits `ms` before answering, and stops on abort.\n * - `fail <reason>` settles the operation unanswered with `reason`.\n * - anything else is echoed with the turn number: `echo: hi (turn 3)`.\n *\n * @experimental The API may change before it stabilizes.\n */\nexport const echoAdapter: ContainerAdapter = {\n id: \"echo\",\n version: \"1\",\n capabilities: [\"steer\"],\n open(context) {\n let turns = context.restore.length;\n const steered: string[] = [];\n return {\n async run(turn) {\n const text = inputText(turn.input);\n const slow = /^slow (\\d+) ?(.*)$/s.exec(text);\n if (slow) {\n await sleep(Number(slow[1]), turn.signal);\n }\n const failure = /^fail ?(.*)$/s.exec(text);\n if (failure) {\n return { status: \"unanswered\", reason: failure[1] || \"failed\" };\n }\n turns += 1;\n const body = slow ? (slow[2] ?? \"\") : text;\n const extra = steered\n .splice(0)\n .map((s) => ` + ${s}`)\n .join(\"\");\n const answer = `echo: ${body}${extra} (turn ${turns})`;\n const messageId = `${turn.operationId}:assistant`;\n context.emit({ type: \"text-delta\", messageId, delta: answer });\n context.emit({\n type: \"message\",\n message: {\n id: messageId,\n role: \"assistant\",\n parts: [{ type: \"text\", text: answer }],\n operationId: turn.operationId,\n createdAt: Date.now()\n }\n });\n context.persist([{ turn: turns, text: body }]);\n return { status: \"done\", text: answer };\n },\n steer(input) {\n steered.push(inputText(input));\n return true;\n },\n async close() {}\n };\n }\n};\n\nfunction sleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal.aborted) {\n reject(new Error(\"aborted\"));\n return;\n }\n const timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(new Error(\"aborted\"));\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
h as ContainerSettings,
|
|
3
|
+
l as ContainerEvent,
|
|
4
|
+
p as ContainerOutcome,
|
|
5
|
+
u as ContainerInput,
|
|
6
|
+
x as JsonValue
|
|
7
|
+
} from "./protocol-BEgrJYC5.js";
|
|
8
|
+
|
|
9
|
+
//#region src/harness/container/daemon-core.d.ts
|
|
10
|
+
/** What an adapter is told when its session opens. */
|
|
11
|
+
type AdapterContext = {
|
|
12
|
+
/** The harness session id. */ readonly session: string;
|
|
13
|
+
readonly settings: ContainerSettings;
|
|
14
|
+
/**
|
|
15
|
+
* Everything this adapter `persist`ed for the session before, possibly in
|
|
16
|
+
* another container, oldest first. Empty for a new session.
|
|
17
|
+
*/
|
|
18
|
+
readonly restore: readonly JsonValue[] /** Report an event. It belongs to the operation that is running, if any. */;
|
|
19
|
+
emit(event: ContainerEvent): void;
|
|
20
|
+
/**
|
|
21
|
+
* Keep resume state. The Durable Object stores the entries and passes all
|
|
22
|
+
* of them back as `restore` when the session opens in a new container.
|
|
23
|
+
*/
|
|
24
|
+
persist(
|
|
25
|
+
entries: readonly JsonValue[]
|
|
26
|
+
): void /** A diagnostic line, reported as a `log` event. */;
|
|
27
|
+
log(level: "info" | "warn" | "error", message: string): void;
|
|
28
|
+
};
|
|
29
|
+
/** One turn an adapter runs. */
|
|
30
|
+
type AdapterTurn = {
|
|
31
|
+
readonly operationId: string;
|
|
32
|
+
readonly input: ContainerInput /** Aborted when the operation is aborted. Wind down promptly. */;
|
|
33
|
+
readonly signal: AbortSignal;
|
|
34
|
+
};
|
|
35
|
+
/** An open adapter session. Turns are never run concurrently. */
|
|
36
|
+
type AdapterSession = {
|
|
37
|
+
/**
|
|
38
|
+
* Run one turn to completion. A rejection settles the operation
|
|
39
|
+
* `unanswered` with the error's message.
|
|
40
|
+
*/
|
|
41
|
+
run(turn: AdapterTurn): Promise<ContainerOutcome>;
|
|
42
|
+
/**
|
|
43
|
+
* Fold input into the running turn. Return false to have it queued as a
|
|
44
|
+
* follow-up instead. Absent when the agent cannot be steered.
|
|
45
|
+
*/
|
|
46
|
+
steer?(
|
|
47
|
+
input: ContainerInput
|
|
48
|
+
): boolean | Promise<boolean> /** Apply new settings to the open session. */;
|
|
49
|
+
configure?(
|
|
50
|
+
settings: ContainerSettings
|
|
51
|
+
): void | Promise<void> /** Release the session's resources. */;
|
|
52
|
+
close(): Promise<void>;
|
|
53
|
+
};
|
|
54
|
+
/** An agent, as the daemon runs it. */
|
|
55
|
+
type ContainerAdapter = {
|
|
56
|
+
/** Reported in `hello`, such as `"claude-code"`. */ readonly id: string;
|
|
57
|
+
readonly version: string /** Free-form capability names, reported in `hello`. */;
|
|
58
|
+
readonly capabilities?: readonly string[] /** Open (or resume) one session. */;
|
|
59
|
+
open(context: AdapterContext): AdapterSession | Promise<AdapterSession>;
|
|
60
|
+
};
|
|
61
|
+
/** The send side of one connection, supplied by the transport. */
|
|
62
|
+
type DaemonSocket = {
|
|
63
|
+
send(text: string): void;
|
|
64
|
+
close(code: number, reason: string): void;
|
|
65
|
+
};
|
|
66
|
+
/** The receive side of one connection, driven by the transport. */
|
|
67
|
+
type DaemonConnection = {
|
|
68
|
+
/** A message arrived. */ receive(
|
|
69
|
+
text: string
|
|
70
|
+
): void /** The connection closed. */;
|
|
71
|
+
closed(): void;
|
|
72
|
+
};
|
|
73
|
+
/** `ContainerDaemon`'s options. */
|
|
74
|
+
type ContainerDaemonOptions = {
|
|
75
|
+
readonly adapter: ContainerAdapter /** This container's id, from `CONTAINER_ENV.runtimeId`. */;
|
|
76
|
+
readonly runtimeId: string;
|
|
77
|
+
/**
|
|
78
|
+
* Most unacknowledged frames kept per session. Older ones are dropped and
|
|
79
|
+
* the object reconciles from `hello` instead. Default 10_000.
|
|
80
|
+
*/
|
|
81
|
+
readonly maxKeptFrames?: number;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* The daemon core. One per container process.
|
|
85
|
+
*
|
|
86
|
+
* @experimental The API may change before it stabilizes.
|
|
87
|
+
*/
|
|
88
|
+
declare class ContainerDaemon {
|
|
89
|
+
#private;
|
|
90
|
+
/**
|
|
91
|
+
* @param options - The adapter and this container's id.
|
|
92
|
+
*/
|
|
93
|
+
constructor(options: ContainerDaemonOptions);
|
|
94
|
+
/**
|
|
95
|
+
* Attach a connection for a session. A newer connection replaces an older
|
|
96
|
+
* one, which is closed with `CLOSE_REPLACED`. The daemon sends `hello`
|
|
97
|
+
* at once.
|
|
98
|
+
*
|
|
99
|
+
* @param session - The harness session id.
|
|
100
|
+
* @param socket - The send side.
|
|
101
|
+
* @returns The receive side, for the transport to drive.
|
|
102
|
+
*/
|
|
103
|
+
connect(session: string, socket: DaemonSocket): DaemonConnection;
|
|
104
|
+
/** Close every adapter session, as the container shuts down. */
|
|
105
|
+
close(): Promise<void>;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* A reference adapter that answers `echo: <text>` and needs no model or
|
|
109
|
+
* credentials. Use it for keyless smoke deploys of the whole path and in
|
|
110
|
+
* tests. It persists one entry per turn and counts them back after a
|
|
111
|
+
* restore, so a resumed session visibly remembers its history:
|
|
112
|
+
*
|
|
113
|
+
* - `slow <ms> <text>` waits `ms` before answering, and stops on abort.
|
|
114
|
+
* - `fail <reason>` settles the operation unanswered with `reason`.
|
|
115
|
+
* - anything else is echoed with the turn number: `echo: hi (turn 3)`.
|
|
116
|
+
*
|
|
117
|
+
* @experimental The API may change before it stabilizes.
|
|
118
|
+
*/
|
|
119
|
+
declare const echoAdapter: ContainerAdapter;
|
|
120
|
+
//#endregion
|
|
121
|
+
export {
|
|
122
|
+
ContainerDaemon as a,
|
|
123
|
+
DaemonSocket as c,
|
|
124
|
+
ContainerAdapter as i,
|
|
125
|
+
echoAdapter as l,
|
|
126
|
+
AdapterSession as n,
|
|
127
|
+
ContainerDaemonOptions as o,
|
|
128
|
+
AdapterTurn as r,
|
|
129
|
+
DaemonConnection as s,
|
|
130
|
+
AdapterContext as t
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=daemon-core-CbohVPAu.d.ts.map
|