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.
Files changed (233) hide show
  1. package/README.md +8 -9
  2. package/dist/{agent-routing-0DR0Tk2v.d.ts → agent-routing-Bhdbvf7s.d.ts} +13 -8
  3. package/dist/agent-routing.d.ts +1 -1
  4. package/dist/agent-tool-types.d.ts +1 -1
  5. package/dist/{agent-tools-YrATZJu2.d.ts → agent-tools-bJZwBMfq.d.ts} +2 -2
  6. package/dist/agent-tools.d.ts +1 -1
  7. package/dist/ai-sdk-OoGkFy3s.js +2444 -0
  8. package/dist/ai-sdk-OoGkFy3s.js.map +1 -0
  9. package/dist/apply-chunks-1FheRb9W.js +99 -0
  10. package/dist/apply-chunks-1FheRb9W.js.map +1 -0
  11. package/dist/broadcast-state-CEyI4uAK.js +69 -0
  12. package/dist/broadcast-state-CEyI4uAK.js.map +1 -0
  13. package/dist/browser/ai-sdk.d.ts +1 -1
  14. package/dist/browser/ai-sdk.js +2 -2
  15. package/dist/browser/ai-sdk.js.map +1 -1
  16. package/dist/browser/index.d.ts +1 -1
  17. package/dist/browser/tanstack-ai.d.ts +1 -1
  18. package/dist/browser/tanstack-ai.js +1 -1
  19. package/dist/{browser-DE3d-RLk.d.ts → browser-tmkcAAI3.d.ts} +2 -2
  20. package/dist/{browser-tool-DuNdlwZ9.d.ts → browser-tool-Bn-nzJQI.d.ts} +3 -3
  21. package/dist/{browser-tool-CQ10e6Kj.js → browser-tool-CBqs6hqa.js} +58 -18
  22. package/dist/browser-tool-CBqs6hqa.js.map +1 -0
  23. package/dist/capability-B4WbF81e.js.map +1 -1
  24. package/dist/{capability-runner-DBAnGr6L.d.ts → capability-runner-O5VbQzqg.d.ts} +9 -1
  25. package/dist/channel-Bak_6zDP.d.ts +333 -0
  26. package/dist/chat/index.d.ts +11 -9
  27. package/dist/chat/index.js +5 -194
  28. package/dist/chat/index.js.map +1 -1
  29. package/dist/chat/react.d.ts +2 -4
  30. package/dist/chat/react.js +3 -1
  31. package/dist/chat/react.js.map +1 -1
  32. package/dist/chat-sdk/index.d.ts +1 -1
  33. package/dist/chat-sdk/index.js +1 -1
  34. package/dist/cli.js +144 -0
  35. package/dist/{client-fyQrLGkD.js → client-1tEQ1Oqz.js} +27 -2
  36. package/dist/{client-fyQrLGkD.js.map → client-1tEQ1Oqz.js.map} +1 -1
  37. package/dist/{client-je3koD9Z.d.ts → client-DS3Dz9l0.d.ts} +2 -2
  38. package/dist/client-tools-aIBO0Fk7.d.ts +53 -0
  39. package/dist/client.d.ts +1 -1
  40. package/dist/conversations-DH0ut_8n.d.ts +192 -0
  41. package/dist/{current-agent-vAk_5JMt.d.ts → current-agent-C07C5o5Y.d.ts} +3 -3
  42. package/dist/daemon-core-Buubj-y1.js +481 -0
  43. package/dist/daemon-core-Buubj-y1.js.map +1 -0
  44. package/dist/daemon-core-CbohVPAu.d.ts +132 -0
  45. package/dist/{do-oauth-client-provider-Tmf1vgKz.d.ts → do-oauth-client-provider-DfsUcpc3.d.ts} +7 -1
  46. package/dist/{durable-object-lifecycle-HhgOMWq9.d.ts → durable-object-lifecycle-DRqp475_.d.ts} +2 -2
  47. package/dist/{channels/email.d.ts → experimental/channels/email/index.d.ts} +25 -12
  48. package/dist/{channels/email.js → experimental/channels/email/index.js} +13 -35
  49. package/dist/experimental/channels/email/index.js.map +1 -0
  50. package/dist/experimental/channels/index.d.ts +270 -0
  51. package/dist/experimental/channels/index.js +1186 -0
  52. package/dist/experimental/channels/index.js.map +1 -0
  53. package/dist/{channels/slack.d.ts → experimental/channels/slack/index.d.ts} +19 -9
  54. package/dist/experimental/channels/slack/index.js +267 -0
  55. package/dist/experimental/channels/slack/index.js.map +1 -0
  56. package/dist/{channels/telegram.d.ts → experimental/channels/telegram/index.d.ts} +19 -9
  57. package/dist/experimental/channels/telegram/index.js +198 -0
  58. package/dist/experimental/channels/telegram/index.js.map +1 -0
  59. package/dist/experimental/channels/web/ai-sdk.d.ts +55 -0
  60. package/dist/experimental/channels/web/ai-sdk.js +266 -0
  61. package/dist/experimental/channels/web/ai-sdk.js.map +1 -0
  62. package/dist/experimental/channels/web/client.d.ts +97 -0
  63. package/dist/experimental/channels/web/client.js +349 -0
  64. package/dist/experimental/channels/web/client.js.map +1 -0
  65. package/dist/experimental/channels/web/index.d.ts +189 -0
  66. package/dist/experimental/channels/web/index.js +332 -0
  67. package/dist/experimental/channels/web/index.js.map +1 -0
  68. package/dist/gateway-BDC07gYO.d.ts +100 -0
  69. package/dist/handle-zAzh0UW2.d.ts +460 -0
  70. package/dist/harness/ai-sdk/index.d.ts +175 -0
  71. package/dist/harness/ai-sdk/index.js +605 -0
  72. package/dist/harness/ai-sdk/index.js.map +1 -0
  73. package/dist/harness/container/daemon/index.d.ts +76 -0
  74. package/dist/harness/container/daemon/index.js +3 -0
  75. package/dist/harness/container/index.d.ts +740 -0
  76. package/dist/harness/container/index.js +2152 -0
  77. package/dist/harness/container/index.js.map +1 -0
  78. package/dist/harness/container/runtime/index.d.ts +144 -0
  79. package/dist/harness/container/runtime/index.js +1082 -0
  80. package/dist/harness/container/runtime/index.js.map +1 -0
  81. package/dist/harness/opencode/index.d.ts +369 -0
  82. package/dist/harness/opencode/index.js +1072 -0
  83. package/dist/harness/opencode/index.js.map +1 -0
  84. package/dist/harness/pi/index.d.ts +2 -1
  85. package/dist/harness/store/index.d.ts +24 -0
  86. package/dist/harness/store/index.js +2 -0
  87. package/dist/harness/think/index.d.ts +821 -0
  88. package/dist/harness/think/index.js +2529 -0
  89. package/dist/harness/think/index.js.map +1 -0
  90. package/dist/harness-B6B9S3rb.d.ts +203 -0
  91. package/dist/{images-iiTDSyRu.js → images-Ce9SCu3X.js} +2 -248
  92. package/dist/images-Ce9SCu3X.js.map +1 -0
  93. package/dist/{index-BreL0YrQ.d.ts → index-D0A5tbWu.d.ts} +2 -2
  94. package/dist/index-Ib_4dwOo.d.ts +200 -0
  95. package/dist/index.d.ts +5 -5
  96. package/dist/index.js +2 -2
  97. package/dist/ingress-EFbrS547.js +9 -0
  98. package/dist/ingress-EFbrS547.js.map +1 -0
  99. package/dist/input-schema-DNrpTu49.js +23 -0
  100. package/dist/input-schema-DNrpTu49.js.map +1 -0
  101. package/dist/internal-kmw70xwR.js +46 -0
  102. package/dist/internal-kmw70xwR.js.map +1 -0
  103. package/dist/internal_context.d.ts +1 -1
  104. package/dist/lifecycle/index.d.ts +3 -3
  105. package/dist/mcp/client/do-oauth-client-provider.d.ts +1 -1
  106. package/dist/mcp/client/do-oauth-client-provider.js +9 -0
  107. package/dist/mcp/client/do-oauth-client-provider.js.map +1 -1
  108. package/dist/mcp/client/index.d.ts +1 -1
  109. package/dist/mcp/client/index.js +1 -1
  110. package/dist/mcp/client/x402.d.ts +35 -4
  111. package/dist/mcp/client/x402.js +24 -3
  112. package/dist/mcp/client/x402.js.map +1 -1
  113. package/dist/mcp/index.d.ts +1 -1
  114. package/dist/mcp/index.js +2 -2
  115. package/dist/models/ai-sdk/index.d.ts +16 -14
  116. package/dist/models/ai-sdk/index.js +1 -2442
  117. package/dist/models/opencode/index.d.ts +65 -0
  118. package/dist/models/opencode/index.js +285 -0
  119. package/dist/models/opencode/index.js.map +1 -0
  120. package/dist/models/pi-ai/index.d.ts +9 -7
  121. package/dist/models/pi-ai/index.js +2 -1
  122. package/dist/models/pi-ai/index.js.map +1 -1
  123. package/dist/options-pwTNq9z6.d.ts +134 -0
  124. package/dist/protocol-BEgrJYC5.d.ts +331 -0
  125. package/dist/protocol-CukuI73M.d.ts +386 -0
  126. package/dist/protocol-cOklVBBD.js +227 -0
  127. package/dist/protocol-cOklVBBD.js.map +1 -0
  128. package/dist/{protocol-kHsr-f0X.js → protocol-eXeJxhgu.js} +2 -67
  129. package/dist/protocol-eXeJxhgu.js.map +1 -0
  130. package/dist/protocol-y2sSY584.js +148 -0
  131. package/dist/protocol-y2sSY584.js.map +1 -0
  132. package/dist/queue/index.d.ts +1 -1
  133. package/dist/react.d.ts +2 -2
  134. package/dist/routing/index.d.ts +2 -2
  135. package/dist/{scheduler-RdACNXDP.d.ts → scheduler-CrFCnv_J.d.ts} +2 -2
  136. package/dist/schedules/index.d.ts +1 -1
  137. package/dist/serializable.d.ts +1 -1
  138. package/dist/sessions/index.d.ts +11 -434
  139. package/dist/sessions/index.js +1 -2271
  140. package/dist/sessions-B9pNuxdT.js +2272 -0
  141. package/dist/sessions-B9pNuxdT.js.map +1 -0
  142. package/dist/settings-C45hDliX.js +253 -0
  143. package/dist/settings-C45hDliX.js.map +1 -0
  144. package/dist/{transport-PfFnt-Ld.d.ts → settings-NgGwF7Qt.d.ts} +14 -208
  145. package/dist/{src-BZeu-SCD.js → src-DgCbZtIR.js} +4 -4
  146. package/dist/{src-BZeu-SCD.js.map → src-DgCbZtIR.js.map} +1 -1
  147. package/dist/stall-watchdog-BpRF2uwG.js +195 -0
  148. package/dist/stall-watchdog-BpRF2uwG.js.map +1 -0
  149. package/dist/state/index.d.ts +1 -1
  150. package/dist/store-DLeqKuj3.d.ts +310 -0
  151. package/dist/store-vgcPYo8K.js +432 -0
  152. package/dist/store-vgcPYo8K.js.map +1 -0
  153. package/dist/streams/index.d.ts +1 -1
  154. package/dist/streams/index.js +1 -1
  155. package/dist/{streams-DW-UCOUc.js → streams-CITClVer.js} +16 -3
  156. package/dist/streams-CITClVer.js.map +1 -0
  157. package/dist/{streams-Cmkj9QfW.d.ts → streams-fbG61qM8.d.ts} +2 -2
  158. package/dist/sub-routing.d.ts +1 -1
  159. package/dist/tasks/index.d.ts +1 -1
  160. package/dist/tasks/index.js +1 -1
  161. package/dist/{tasks-68DESxf0.js → tasks-CkTZNaV1.js} +2 -1
  162. package/dist/tasks-CkTZNaV1.js.map +1 -0
  163. package/dist/{tasks-9YxYtByh.d.ts → tasks-PtlB4Uyn.d.ts} +2 -2
  164. package/dist/tool-3PA8xjB_.js +421 -0
  165. package/dist/tool-3PA8xjB_.js.map +1 -0
  166. package/dist/tool-BPJEbwaX.d.ts +278 -0
  167. package/dist/transport-k2mFrtL8.d.ts +200 -0
  168. package/dist/turns-DCV3ycDl.js +317 -0
  169. package/dist/turns-DCV3ycDl.js.map +1 -0
  170. package/dist/voice/client.js +1 -1
  171. package/dist/voice/index.d.ts +2 -2
  172. package/dist/voice/index.js +1 -1
  173. package/dist/websearch/index.d.ts +58 -0
  174. package/dist/websearch/index.js +2 -0
  175. package/dist/websearch/tools/ai-sdk.d.ts +77 -0
  176. package/dist/websearch/tools/ai-sdk.js +46 -0
  177. package/dist/websearch/tools/ai-sdk.js.map +1 -0
  178. package/dist/websearch/tools/pi.d.ts +82 -0
  179. package/dist/websearch/tools/pi.js +89 -0
  180. package/dist/websearch/tools/pi.js.map +1 -0
  181. package/dist/websearch/tools/tanstack-ai.d.ts +71 -0
  182. package/dist/websearch/tools/tanstack-ai.js +46 -0
  183. package/dist/websearch/tools/tanstack-ai.js.map +1 -0
  184. package/dist/websockets/index.d.ts +12 -296
  185. package/dist/websockets/index.js +1 -1
  186. package/dist/{websockets-Ci-LZFHH.js → websockets-CmENGb-Z.js} +18 -4
  187. package/dist/websockets-CmENGb-Z.js.map +1 -0
  188. package/dist/{wire-types-CrjKvDyi.d.ts → wire-types-Cv0iwjk5.d.ts} +3 -51
  189. package/dist/workflow-types.d.ts +1 -1
  190. package/dist/workflows.d.ts +1 -1
  191. package/dist/workflows.js +1 -1
  192. package/docs/browse-the-web.md +3 -0
  193. package/docs/harnesses/think.md +215 -0
  194. package/docs/index.md +2 -1
  195. package/docs/lifecycle.md +40 -0
  196. package/docs/search-the-web.md +133 -0
  197. package/package.json +117 -38
  198. package/dist/browser-tool-CQ10e6Kj.js.map +0 -1
  199. package/dist/channel-Bnm4S7T2.d.ts +0 -491
  200. package/dist/channels/ai-sdk.d.ts +0 -46
  201. package/dist/channels/ai-sdk.js +0 -120
  202. package/dist/channels/ai-sdk.js.map +0 -1
  203. package/dist/channels/email.js.map +0 -1
  204. package/dist/channels/index.d.ts +0 -233
  205. package/dist/channels/index.js +0 -608
  206. package/dist/channels/index.js.map +0 -1
  207. package/dist/channels/slack.js +0 -614
  208. package/dist/channels/slack.js.map +0 -1
  209. package/dist/channels/tanstack-ai.d.ts +0 -39
  210. package/dist/channels/tanstack-ai.js +0 -17
  211. package/dist/channels/tanstack-ai.js.map +0 -1
  212. package/dist/channels/telegram.js +0 -427
  213. package/dist/channels/telegram.js.map +0 -1
  214. package/dist/channels/voice.d.ts +0 -45
  215. package/dist/channels/voice.js +0 -122
  216. package/dist/channels/voice.js.map +0 -1
  217. package/dist/images-iiTDSyRu.js.map +0 -1
  218. package/dist/index-BB0kqhIz.d.ts +0 -101
  219. package/dist/ingress-BfetZbMO.js +0 -83
  220. package/dist/ingress-BfetZbMO.js.map +0 -1
  221. package/dist/internal-CYlgHl1l.js +0 -59
  222. package/dist/internal-CYlgHl1l.js.map +0 -1
  223. package/dist/models/ai-sdk/index.js.map +0 -1
  224. package/dist/protocol-kHsr-f0X.js.map +0 -1
  225. package/dist/sessions/index.js.map +0 -1
  226. package/dist/streams-DW-UCOUc.js.map +0 -1
  227. package/dist/surface-bZZJqBka.js +0 -17
  228. package/dist/surface-bZZJqBka.js.map +0 -1
  229. package/dist/tasks-68DESxf0.js.map +0 -1
  230. package/dist/tool-schema-CBjGPrsQ.js +0 -31
  231. package/dist/tool-schema-CBjGPrsQ.js.map +0 -1
  232. package/dist/websockets-Ci-LZFHH.js.map +0 -1
  233. package/docs/channels.md +0 -323
@@ -0,0 +1,432 @@
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
+ //#region src/harness/store/store.ts
4
+ const DEFAULT_PREFIX = "harness_";
5
+ /**
6
+ * Characters per stored chunk of a JSON value. A Durable Object row holds
7
+ * at most 2 MB and a character is at most 4 bytes of UTF-8, so a quarter of
8
+ * a megabyte of characters always fits with room for the other columns.
9
+ */
10
+ const CHUNK_CHARS = 256 * 1024;
11
+ /**
12
+ * Open the store over this object's SQLite database, creating its tables on
13
+ * first use. Cheap: call it once per isolate and keep the result.
14
+ *
15
+ * @param storage - The Durable Object's storage.
16
+ * @param options - Table prefix.
17
+ * @returns The store.
18
+ */
19
+ function openHarnessStore(storage, options = {}) {
20
+ return new HarnessStore(storage, options);
21
+ }
22
+ function parseJson(text) {
23
+ return JSON.parse(text);
24
+ }
25
+ function isStatus(value) {
26
+ return value === "queued" || value === "running" || value === "done" || value === "unanswered";
27
+ }
28
+ function chunks(text) {
29
+ if (text.length <= CHUNK_CHARS) return [text];
30
+ const parts = [];
31
+ for (let at = 0; at < text.length; at += CHUNK_CHARS) parts.push(text.slice(at, at + CHUNK_CHARS));
32
+ return parts;
33
+ }
34
+ var _storage = /* @__PURE__ */ new WeakMap();
35
+ var _sessions = /* @__PURE__ */ new WeakMap();
36
+ var _operations = /* @__PURE__ */ new WeakMap();
37
+ var _log = /* @__PURE__ */ new WeakMap();
38
+ var _HarnessStore_brand = /* @__PURE__ */ new WeakSet();
39
+ /**
40
+ * The store. Construct it with `openHarnessStore`.
41
+ *
42
+ * @experimental The API may change before it stabilizes.
43
+ */
44
+ var HarnessStore = class {
45
+ /**
46
+ * @param storage - The Durable Object's storage.
47
+ * @param options - Table prefix.
48
+ */
49
+ constructor(storage, options) {
50
+ _classPrivateMethodInitSpec(this, _HarnessStore_brand);
51
+ _classPrivateFieldInitSpec(this, _storage, void 0);
52
+ _classPrivateFieldInitSpec(this, _sessions, void 0);
53
+ _classPrivateFieldInitSpec(this, _operations, void 0);
54
+ _classPrivateFieldInitSpec(this, _log, void 0);
55
+ const prefix = options.prefix ?? DEFAULT_PREFIX;
56
+ if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(prefix)) throw new Error(`Invalid harness store prefix ${JSON.stringify(prefix)}`);
57
+ if (prefix.startsWith("_cf_")) throw new Error("The harness store prefix must not start with _cf_");
58
+ _classPrivateFieldSet2(_storage, this, storage);
59
+ _classPrivateFieldSet2(_sessions, this, `${prefix}sessions`);
60
+ _classPrivateFieldSet2(_operations, this, `${prefix}operations`);
61
+ _classPrivateFieldSet2(_log, this, `${prefix}log`);
62
+ _assertClassBrand(_HarnessStore_brand, this, _migrate).call(this);
63
+ }
64
+ /**
65
+ * Run `fn` in one storage transaction. Writes inside it commit together or
66
+ * not at all.
67
+ *
68
+ * @template T - What `fn` returns.
69
+ * @param fn - Synchronous work against this store.
70
+ * @returns What `fn` returned.
71
+ */
72
+ transaction(fn) {
73
+ return _classPrivateFieldGet2(_storage, this).transactionSync(fn);
74
+ }
75
+ /**
76
+ * Create a session, or return the existing one with this id unchanged.
77
+ *
78
+ * @param input - The id, an optional parent, and the initial state.
79
+ * @returns The stored session.
80
+ */
81
+ createSession(input) {
82
+ const now = Date.now();
83
+ _classPrivateFieldGet2(_storage, this).sql.exec(`INSERT INTO ${_classPrivateFieldGet2(_sessions, this)} (id, parent, state, created_at, updated_at)
84
+ VALUES (?, ?, ?, ?, ?) ON CONFLICT (id) DO NOTHING`, input.id, input.parent ?? null, JSON.stringify(input.state ?? null), now, now);
85
+ const created = this.session(input.id);
86
+ if (!created) throw new Error(`Session ${input.id} was not stored`);
87
+ return created;
88
+ }
89
+ /**
90
+ * Read one session.
91
+ *
92
+ * @param id - The session id.
93
+ * @returns The session, or `undefined` when there is none.
94
+ */
95
+ session(id) {
96
+ const row = _classPrivateFieldGet2(_storage, this).sql.exec(`SELECT * FROM ${_classPrivateFieldGet2(_sessions, this)} WHERE id = ?`, id).toArray()[0];
97
+ return row ? _assertClassBrand(_HarnessStore_brand, this, _sessionOf).call(this, row) : void 0;
98
+ }
99
+ /**
100
+ * Every session, oldest first.
101
+ *
102
+ * @returns The sessions.
103
+ */
104
+ sessions() {
105
+ return _classPrivateFieldGet2(_storage, this).sql.exec(`SELECT * FROM ${_classPrivateFieldGet2(_sessions, this)} ORDER BY created_at, id`).toArray().map((row) => _assertClassBrand(_HarnessStore_brand, this, _sessionOf).call(this, row));
106
+ }
107
+ /**
108
+ * Replace a session's harness-owned state.
109
+ *
110
+ * @param id - The session id.
111
+ * @param state - The new state.
112
+ * @returns False when there is no such session.
113
+ */
114
+ setSessionState(id, state) {
115
+ return _classPrivateFieldGet2(_storage, this).sql.exec(`UPDATE ${_classPrivateFieldGet2(_sessions, this)} SET state = ?, updated_at = ? WHERE id = ?`, JSON.stringify(state), Date.now(), id).rowsWritten > 0;
116
+ }
117
+ /**
118
+ * Delete a session with its operations and logs.
119
+ *
120
+ * @param id - The session id.
121
+ * @returns False when there was no such session.
122
+ */
123
+ deleteSession(id) {
124
+ return this.transaction(() => {
125
+ const sql = _classPrivateFieldGet2(_storage, this).sql;
126
+ sql.exec(`DELETE FROM ${_classPrivateFieldGet2(_operations, this)} WHERE session = ?`, id);
127
+ sql.exec(`DELETE FROM ${_classPrivateFieldGet2(_log, this)} WHERE session = ?`, id);
128
+ return sql.exec(`DELETE FROM ${_classPrivateFieldGet2(_sessions, this)} WHERE id = ?`, id).rowsWritten > 0;
129
+ });
130
+ }
131
+ /**
132
+ * Durably queue an operation. Idempotent on `(session, id)`: a second
133
+ * enqueue with the same id stores nothing and returns the first record.
134
+ *
135
+ * @param input - The session, the idempotency id, the input and options.
136
+ * @returns The stored record, and whether this call created it.
137
+ */
138
+ enqueue(input) {
139
+ return this.transaction(() => {
140
+ const existing = this.operation(input.session, input.id);
141
+ if (existing) return {
142
+ record: existing,
143
+ accepted: false
144
+ };
145
+ const sql = _classPrivateFieldGet2(_storage, this).sql;
146
+ const next = sql.exec(`SELECT MAX(seq) AS seq FROM ${_classPrivateFieldGet2(_operations, this)}`).toArray()[0]?.seq ?? 0;
147
+ sql.exec(`INSERT INTO ${_classPrivateFieldGet2(_operations, this)}
148
+ (session, id, seq, status, input, meta, result, reason, created_at, settled_at)
149
+ VALUES (?, ?, ?, 'queued', ?, ?, 'null', NULL, ?, NULL)`, input.session, input.id, next + 1, JSON.stringify(input.input), JSON.stringify(input.meta ?? null), Date.now());
150
+ const record = this.operation(input.session, input.id);
151
+ if (!record) throw new Error(`Operation ${input.id} was not stored`);
152
+ return {
153
+ record,
154
+ accepted: true
155
+ };
156
+ });
157
+ }
158
+ /**
159
+ * Read one operation.
160
+ *
161
+ * @param session - The session id.
162
+ * @param id - The operation id.
163
+ * @returns The operation, or `undefined` when there is none.
164
+ */
165
+ operation(session, id) {
166
+ const row = _classPrivateFieldGet2(_storage, this).sql.exec(`SELECT * FROM ${_classPrivateFieldGet2(_operations, this)} WHERE session = ? AND id = ?`, session, id).toArray()[0];
167
+ return row ? _assertClassBrand(_HarnessStore_brand, this, _operationOf).call(this, row) : void 0;
168
+ }
169
+ /**
170
+ * Operations in submission order, optionally narrowed to one session and
171
+ * to some statuses.
172
+ *
173
+ * @param filter - The session and statuses to keep. Default: all.
174
+ * @returns The matching operations, oldest first.
175
+ */
176
+ operations(filter = {}) {
177
+ const where = [];
178
+ const params = [];
179
+ if (filter.session !== void 0) {
180
+ where.push("session = ?");
181
+ params.push(filter.session);
182
+ }
183
+ if (filter.status !== void 0) {
184
+ if (filter.status.length === 0) return [];
185
+ where.push(`status IN (${filter.status.map(() => "?").join(", ")})`);
186
+ params.push(...filter.status);
187
+ }
188
+ return _classPrivateFieldGet2(_storage, this).sql.exec(`SELECT * FROM ${_classPrivateFieldGet2(_operations, this)}
189
+ ${where.length > 0 ? `WHERE ${where.join(" AND ")}` : ""}
190
+ ORDER BY seq`, ...params).toArray().map((row) => _assertClassBrand(_HarnessStore_brand, this, _operationOf).call(this, row));
191
+ }
192
+ /**
193
+ * Move a queued operation to `running`.
194
+ *
195
+ * @param session - The session id.
196
+ * @param id - The operation id.
197
+ * @returns False when it was not queued.
198
+ */
199
+ start(session, id) {
200
+ return _assertClassBrand(_HarnessStore_brand, this, _transition).call(this, session, id, ["queued"], "running");
201
+ }
202
+ /**
203
+ * Move a running operation back to `queued`, to run it again.
204
+ *
205
+ * @param session - The session id.
206
+ * @param id - The operation id.
207
+ * @returns False when it was not running.
208
+ */
209
+ requeue(session, id) {
210
+ return _assertClassBrand(_HarnessStore_brand, this, _transition).call(this, session, id, ["running"], "queued");
211
+ }
212
+ /**
213
+ * Settle a queued or running operation.
214
+ *
215
+ * @param session - The session id.
216
+ * @param id - The operation id.
217
+ * @param outcome - How it ended.
218
+ * @returns False when it had already settled or does not exist.
219
+ */
220
+ settle(session, id, outcome) {
221
+ return _classPrivateFieldGet2(_storage, this).sql.exec(`UPDATE ${_classPrivateFieldGet2(_operations, this)}
222
+ SET status = ?, result = ?, reason = ?, settled_at = ?
223
+ WHERE session = ? AND id = ? AND status IN ('queued', 'running')`, outcome.status, JSON.stringify(outcome.status === "done" ? outcome.result : null), outcome.status === "unanswered" ? outcome.reason : null, Date.now(), session, id).rowsWritten > 0;
224
+ }
225
+ /**
226
+ * Replace an operation's harness-owned bookkeeping.
227
+ *
228
+ * @param session - The session id.
229
+ * @param id - The operation id.
230
+ * @param meta - The new value.
231
+ * @returns False when there is no such operation.
232
+ */
233
+ setOperationMeta(session, id, meta) {
234
+ return _classPrivateFieldGet2(_storage, this).sql.exec(`UPDATE ${_classPrivateFieldGet2(_operations, this)} SET meta = ? WHERE session = ? AND id = ?`, JSON.stringify(meta), session, id).rowsWritten > 0;
235
+ }
236
+ /**
237
+ * Append entries to a session's log. An entry with an id that is already
238
+ * in the log replaces that entry in place, keeping its position.
239
+ *
240
+ * @param session - The session id.
241
+ * @param log - The log's name, such as `"messages"`.
242
+ * @param entries - The entries, in order.
243
+ * @returns The position of the last entry written, or of the log's end.
244
+ */
245
+ append(session, log, entries) {
246
+ return this.transaction(() => {
247
+ let end = this.end(session, log);
248
+ for (const entry of entries) {
249
+ const existing = entry.id === void 0 ? void 0 : _assertClassBrand(_HarnessStore_brand, this, _seqOf).call(this, session, log, entry.id);
250
+ if (existing !== void 0) {
251
+ _assertClassBrand(_HarnessStore_brand, this, _write).call(this, session, log, existing, entry);
252
+ continue;
253
+ }
254
+ end += 1;
255
+ _assertClassBrand(_HarnessStore_brand, this, _write).call(this, session, log, end, entry);
256
+ }
257
+ return end;
258
+ });
259
+ }
260
+ /**
261
+ * Read a session's log in order.
262
+ *
263
+ * @param session - The session id.
264
+ * @param log - The log's name.
265
+ * @param range - Entries after position `after` (exclusive), at most `limit`.
266
+ * @returns The entries.
267
+ */
268
+ read(session, log, range = {}) {
269
+ const after = range.after ?? 0;
270
+ const limit = range.limit ?? -1;
271
+ const rows = _classPrivateFieldGet2(_storage, this).sql.exec(`SELECT seq, part, id, data, created_at FROM ${_classPrivateFieldGet2(_log, this)}
272
+ WHERE session = ? AND log = ? AND seq IN (
273
+ SELECT DISTINCT seq FROM ${_classPrivateFieldGet2(_log, this)}
274
+ WHERE session = ? AND log = ? AND seq > ?
275
+ ORDER BY seq LIMIT ?
276
+ )
277
+ ORDER BY seq, part`, session, log, session, log, after, limit).toArray();
278
+ const entries = [];
279
+ let current;
280
+ const flush = () => {
281
+ if (!current) return;
282
+ entries.push({
283
+ seq: current.row.seq,
284
+ id: current.row.id ?? void 0,
285
+ data: parseJson(current.text),
286
+ createdAt: current.row.created_at
287
+ });
288
+ };
289
+ for (const row of rows) {
290
+ if (current && current.row.seq === row.seq) {
291
+ current.text += row.data;
292
+ continue;
293
+ }
294
+ flush();
295
+ current = {
296
+ row,
297
+ text: row.data
298
+ };
299
+ }
300
+ flush();
301
+ return entries;
302
+ }
303
+ /**
304
+ * One entry by id.
305
+ *
306
+ * @param session - The session id.
307
+ * @param log - The log's name.
308
+ * @param id - The entry id.
309
+ * @returns The entry, or `undefined`.
310
+ */
311
+ entry(session, log, id) {
312
+ const seq = _assertClassBrand(_HarnessStore_brand, this, _seqOf).call(this, session, log, id);
313
+ if (seq === void 0) return void 0;
314
+ return this.read(session, log, {
315
+ after: seq - 1,
316
+ limit: 1
317
+ })[0];
318
+ }
319
+ /**
320
+ * The position of a log's last entry.
321
+ *
322
+ * @param session - The session id.
323
+ * @param log - The log's name.
324
+ * @returns The position, or 0 for an empty log.
325
+ */
326
+ end(session, log) {
327
+ return _classPrivateFieldGet2(_storage, this).sql.exec(`SELECT MAX(seq) AS seq FROM ${_classPrivateFieldGet2(_log, this)} WHERE session = ? AND log = ?`, session, log).toArray()[0]?.seq ?? 0;
328
+ }
329
+ /**
330
+ * Empty a session's log.
331
+ *
332
+ * @param session - The session id.
333
+ * @param log - The log's name.
334
+ */
335
+ clear(session, log) {
336
+ _classPrivateFieldGet2(_storage, this).sql.exec(`DELETE FROM ${_classPrivateFieldGet2(_log, this)} WHERE session = ? AND log = ?`, session, log);
337
+ }
338
+ /**
339
+ * Copy one session's log onto the end of another's, keeping entry ids.
340
+ *
341
+ * @param from - The source session.
342
+ * @param to - The target session.
343
+ * @param log - The log's name.
344
+ */
345
+ copy(from, to, log) {
346
+ this.transaction(() => {
347
+ const offset = this.end(to, log);
348
+ _classPrivateFieldGet2(_storage, this).sql.exec(`INSERT INTO ${_classPrivateFieldGet2(_log, this)} (session, log, seq, part, id, data, created_at)
349
+ SELECT ?, log, seq + ?, part, id, data, created_at FROM ${_classPrivateFieldGet2(_log, this)}
350
+ WHERE session = ? AND log = ?`, to, offset, from, log);
351
+ });
352
+ }
353
+ };
354
+ function _migrate() {
355
+ const sql = _classPrivateFieldGet2(_storage, this).sql;
356
+ sql.exec(`CREATE TABLE IF NOT EXISTS ${_classPrivateFieldGet2(_sessions, this)} (
357
+ id TEXT PRIMARY KEY,
358
+ parent TEXT,
359
+ state TEXT NOT NULL,
360
+ created_at INTEGER NOT NULL,
361
+ updated_at INTEGER NOT NULL
362
+ )`);
363
+ sql.exec(`CREATE TABLE IF NOT EXISTS ${_classPrivateFieldGet2(_operations, this)} (
364
+ session TEXT NOT NULL,
365
+ id TEXT NOT NULL,
366
+ seq INTEGER NOT NULL,
367
+ status TEXT NOT NULL,
368
+ input TEXT NOT NULL,
369
+ meta TEXT NOT NULL,
370
+ result TEXT NOT NULL,
371
+ reason TEXT,
372
+ created_at INTEGER NOT NULL,
373
+ settled_at INTEGER,
374
+ PRIMARY KEY (session, id)
375
+ )`);
376
+ sql.exec(`CREATE INDEX IF NOT EXISTS ${_classPrivateFieldGet2(_operations, this)}_open ON ${_classPrivateFieldGet2(_operations, this)} (status, seq)`);
377
+ sql.exec(`CREATE TABLE IF NOT EXISTS ${_classPrivateFieldGet2(_log, this)} (
378
+ session TEXT NOT NULL,
379
+ log TEXT NOT NULL,
380
+ seq INTEGER NOT NULL,
381
+ part INTEGER NOT NULL,
382
+ id TEXT,
383
+ data TEXT NOT NULL,
384
+ created_at INTEGER NOT NULL,
385
+ PRIMARY KEY (session, log, seq, part)
386
+ )`);
387
+ sql.exec(`CREATE INDEX IF NOT EXISTS ${_classPrivateFieldGet2(_log, this)}_id ON ${_classPrivateFieldGet2(_log, this)} (session, log, id) WHERE id IS NOT NULL`);
388
+ }
389
+ function _sessionOf(row) {
390
+ return {
391
+ id: row.id,
392
+ parent: row.parent ?? void 0,
393
+ state: parseJson(row.state),
394
+ createdAt: row.created_at,
395
+ updatedAt: row.updated_at
396
+ };
397
+ }
398
+ function _transition(session, id, from, to) {
399
+ return _classPrivateFieldGet2(_storage, this).sql.exec(`UPDATE ${_classPrivateFieldGet2(_operations, this)} SET status = ?
400
+ WHERE session = ? AND id = ? AND status IN (${from.map(() => "?").join(", ")})`, to, session, id, ...from).rowsWritten > 0;
401
+ }
402
+ function _operationOf(row) {
403
+ if (!isStatus(row.status)) throw new Error(`Unknown operation status ${row.status}`);
404
+ return {
405
+ session: row.session,
406
+ id: row.id,
407
+ seq: row.seq,
408
+ status: row.status,
409
+ input: parseJson(row.input),
410
+ meta: parseJson(row.meta),
411
+ result: parseJson(row.result),
412
+ reason: row.reason ?? void 0,
413
+ createdAt: row.created_at,
414
+ settledAt: row.settled_at ?? void 0
415
+ };
416
+ }
417
+ function _seqOf(session, log, id) {
418
+ return _classPrivateFieldGet2(_storage, this).sql.exec(`SELECT seq FROM ${_classPrivateFieldGet2(_log, this)} WHERE session = ? AND log = ? AND id = ? LIMIT 1`, session, log, id).toArray()[0]?.seq;
419
+ }
420
+ function _write(session, log, seq, entry) {
421
+ const sql = _classPrivateFieldGet2(_storage, this).sql;
422
+ const createdAt = sql.exec(`SELECT created_at FROM ${_classPrivateFieldGet2(_log, this)} WHERE session = ? AND log = ? AND seq = ? LIMIT 1`, session, log, seq).toArray()[0]?.created_at ?? Date.now();
423
+ sql.exec(`DELETE FROM ${_classPrivateFieldGet2(_log, this)} WHERE session = ? AND log = ? AND seq = ?`, session, log, seq);
424
+ chunks(JSON.stringify(entry.data)).forEach((part, index) => {
425
+ sql.exec(`INSERT INTO ${_classPrivateFieldGet2(_log, this)} (session, log, seq, part, id, data, created_at)
426
+ VALUES (?, ?, ?, ?, ?, ?, ?)`, session, log, seq, index, entry.id ?? null, part, createdAt);
427
+ });
428
+ }
429
+ //#endregion
430
+ export { openHarnessStore as n, HarnessStore as t };
431
+
432
+ //# sourceMappingURL=store-vgcPYo8K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-vgcPYo8K.js","names":[],"sources":["../src/harness/store/store.ts"],"sourcesContent":["/**\n * A session store for harnesses, on a Durable Object's SQLite database.\n *\n * Any harness that runs its agent somewhere other than the object (a\n * container, a sandbox, a remote process) needs the same few things kept\n * durably next to it: which sessions exist, which operations were submitted\n * and how each one ended, and the session's history in whatever format the\n * harness speaks. This store keeps those and nothing more. It knows no\n * message format, no event vocabulary and no runtime: inputs, results,\n * session state and log entries are opaque JSON that the harness parses.\n *\n * Three record kinds:\n *\n * - **Sessions**: an id, an optional parent (a fork), and one JSON state\n * value the harness owns (model, cursors, resume handles).\n * - **Operations**: one row per submitted operation, keyed by an\n * idempotency id within its session, moving `queued` → `running` →\n * `done` | `unanswered`. Transitions are guarded in SQL, so a duplicate or\n * late transition is a no-op rather than a regression.\n * - **Logs**: named, append-ordered streams of JSON entries per session\n * (`\"messages\"`, `\"engine\"`, …). An entry may carry an id, and an entry\n * written again under the same id replaces the old one in place. Entries\n * larger than one SQLite row are split across continuation rows.\n *\n * The store is synchronous, like the SQL API under it, so a harness can\n * group several writes in `transaction()` without awaiting.\n *\n * @experimental The API may change before it stabilizes.\n */\n\n/** A JSON value, as the store keeps it. */\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | readonly JsonValue[]\n | { readonly [key: string]: JsonValue };\n\n/** Where an operation is in its life. */\nexport type OperationStatus = \"queued\" | \"running\" | \"done\" | \"unanswered\";\n\n/** A session, as stored. */\nexport type SessionRecord = {\n readonly id: string;\n /** The session this one was forked from. */\n readonly parent: string | undefined;\n /** Harness-owned state. `null` until the harness writes some. */\n readonly state: JsonValue;\n readonly createdAt: number;\n readonly updatedAt: number;\n};\n\n/** One operation, as stored. */\nexport type OperationRecord = {\n readonly session: string;\n /** The idempotency key, unique within the session. */\n readonly id: string;\n /** Submission order within the whole store. */\n readonly seq: number;\n readonly status: OperationStatus;\n /** What was submitted, in the harness's format. */\n readonly input: JsonValue;\n /** Harness-owned submission options and bookkeeping. */\n readonly meta: JsonValue;\n /** The harness's result for a `done` operation, else `null`. */\n readonly result: JsonValue;\n /** Why an `unanswered` operation ended. */\n readonly reason: string | undefined;\n readonly createdAt: number;\n readonly settledAt: number | undefined;\n};\n\n/** One log entry, as stored. */\nexport type LogEntry = {\n /** Position in the log. Stable when the entry is replaced by id. */\n readonly seq: number;\n readonly id: string | undefined;\n readonly data: JsonValue;\n readonly createdAt: number;\n};\n\n/** One entry to append. */\nexport type LogAppend = {\n /** Replace an existing entry with this id in place, instead of appending. */\n readonly id?: string;\n readonly data: JsonValue;\n};\n\n/** How an operation ended. */\nexport type OperationOutcome =\n | { readonly status: \"done\"; readonly result: JsonValue }\n | { readonly status: \"unanswered\"; readonly reason: string };\n\n/** `openHarnessStore`'s options. */\nexport type HarnessStoreOptions = {\n /**\n * Prefix for the store's tables. Two harnesses in one object use two\n * prefixes. Must not start with `_cf_`, which Durable Objects reserve.\n * Default `harness_`.\n */\n readonly prefix?: string;\n};\n\nconst DEFAULT_PREFIX = \"harness_\";\n\n/**\n * Characters per stored chunk of a JSON value. A Durable Object row holds\n * at most 2 MB and a character is at most 4 bytes of UTF-8, so a quarter of\n * a megabyte of characters always fits with room for the other columns.\n */\nconst CHUNK_CHARS = 256 * 1024;\n\n/**\n * Open the store over this object's SQLite database, creating its tables on\n * first use. Cheap: call it once per isolate and keep the result.\n *\n * @param storage - The Durable Object's storage.\n * @param options - Table prefix.\n * @returns The store.\n */\nexport function openHarnessStore(\n storage: DurableObjectStorage,\n options: HarnessStoreOptions = {}\n): HarnessStore {\n return new HarnessStore(storage, options);\n}\n\ntype SessionRow = {\n id: string;\n parent: string | null;\n state: string;\n created_at: number;\n updated_at: number;\n};\n\ntype OperationRow = {\n session: string;\n id: string;\n seq: number;\n status: string;\n input: string;\n meta: string;\n result: string;\n reason: string | null;\n created_at: number;\n settled_at: number | null;\n};\n\ntype LogRow = {\n seq: number;\n part: number;\n id: string | null;\n data: string;\n created_at: number;\n};\n\nfunction parseJson(text: string): JsonValue {\n // SAFETY: every stored value was produced by JSON.stringify of a JsonValue\n // in this module; parsing it back yields the same shape.\n return JSON.parse(text) as JsonValue;\n}\n\nfunction isStatus(value: string): value is OperationStatus {\n return (\n value === \"queued\" ||\n value === \"running\" ||\n value === \"done\" ||\n value === \"unanswered\"\n );\n}\n\nfunction chunks(text: string): string[] {\n if (text.length <= CHUNK_CHARS) return [text];\n const parts: string[] = [];\n for (let at = 0; at < text.length; at += CHUNK_CHARS) {\n parts.push(text.slice(at, at + CHUNK_CHARS));\n }\n return parts;\n}\n\n/**\n * The store. Construct it with `openHarnessStore`.\n *\n * @experimental The API may change before it stabilizes.\n */\nexport class HarnessStore {\n readonly #storage: DurableObjectStorage;\n readonly #sessions: string;\n readonly #operations: string;\n readonly #log: string;\n\n /**\n * @param storage - The Durable Object's storage.\n * @param options - Table prefix.\n */\n constructor(storage: DurableObjectStorage, options: HarnessStoreOptions) {\n const prefix = options.prefix ?? DEFAULT_PREFIX;\n if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(prefix)) {\n throw new Error(`Invalid harness store prefix ${JSON.stringify(prefix)}`);\n }\n if (prefix.startsWith(\"_cf_\")) {\n throw new Error(\"The harness store prefix must not start with _cf_\");\n }\n this.#storage = storage;\n this.#sessions = `${prefix}sessions`;\n this.#operations = `${prefix}operations`;\n this.#log = `${prefix}log`;\n this.#migrate();\n }\n\n #migrate(): void {\n const sql = this.#storage.sql;\n sql.exec(`CREATE TABLE IF NOT EXISTS ${this.#sessions} (\n id TEXT PRIMARY KEY,\n parent TEXT,\n state TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n )`);\n sql.exec(`CREATE TABLE IF NOT EXISTS ${this.#operations} (\n session TEXT NOT NULL,\n id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n status TEXT NOT NULL,\n input TEXT NOT NULL,\n meta TEXT NOT NULL,\n result TEXT NOT NULL,\n reason TEXT,\n created_at INTEGER NOT NULL,\n settled_at INTEGER,\n PRIMARY KEY (session, id)\n )`);\n sql.exec(\n `CREATE INDEX IF NOT EXISTS ${this.#operations}_open ON ${this.#operations} (status, seq)`\n );\n sql.exec(`CREATE TABLE IF NOT EXISTS ${this.#log} (\n session TEXT NOT NULL,\n log TEXT NOT NULL,\n seq INTEGER NOT NULL,\n part INTEGER NOT NULL,\n id TEXT,\n data TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n PRIMARY KEY (session, log, seq, part)\n )`);\n sql.exec(\n `CREATE INDEX IF NOT EXISTS ${this.#log}_id ON ${this.#log} (session, log, id) WHERE id IS NOT NULL`\n );\n }\n\n /**\n * Run `fn` in one storage transaction. Writes inside it commit together or\n * not at all.\n *\n * @template T - What `fn` returns.\n * @param fn - Synchronous work against this store.\n * @returns What `fn` returned.\n */\n transaction<T>(fn: () => T): T {\n return this.#storage.transactionSync(fn);\n }\n\n // ── Sessions ─────────────────────────────────────────────────────────────\n\n /**\n * Create a session, or return the existing one with this id unchanged.\n *\n * @param input - The id, an optional parent, and the initial state.\n * @returns The stored session.\n */\n createSession(input: {\n readonly id: string;\n readonly parent?: string;\n readonly state?: JsonValue;\n }): SessionRecord {\n const now = Date.now();\n this.#storage.sql.exec(\n `INSERT INTO ${this.#sessions} (id, parent, state, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?) ON CONFLICT (id) DO NOTHING`,\n input.id,\n input.parent ?? null,\n JSON.stringify(input.state ?? null),\n now,\n now\n );\n const created = this.session(input.id);\n if (!created) throw new Error(`Session ${input.id} was not stored`);\n return created;\n }\n\n /**\n * Read one session.\n *\n * @param id - The session id.\n * @returns The session, or `undefined` when there is none.\n */\n session(id: string): SessionRecord | undefined {\n const row = this.#storage.sql\n .exec<SessionRow>(`SELECT * FROM ${this.#sessions} WHERE id = ?`, id)\n .toArray()[0];\n return row ? this.#sessionOf(row) : undefined;\n }\n\n /**\n * Every session, oldest first.\n *\n * @returns The sessions.\n */\n sessions(): SessionRecord[] {\n return this.#storage.sql\n .exec<SessionRow>(\n `SELECT * FROM ${this.#sessions} ORDER BY created_at, id`\n )\n .toArray()\n .map((row) => this.#sessionOf(row));\n }\n\n /**\n * Replace a session's harness-owned state.\n *\n * @param id - The session id.\n * @param state - The new state.\n * @returns False when there is no such session.\n */\n setSessionState(id: string, state: JsonValue): boolean {\n return (\n this.#storage.sql.exec(\n `UPDATE ${this.#sessions} SET state = ?, updated_at = ? WHERE id = ?`,\n JSON.stringify(state),\n Date.now(),\n id\n ).rowsWritten > 0\n );\n }\n\n /**\n * Delete a session with its operations and logs.\n *\n * @param id - The session id.\n * @returns False when there was no such session.\n */\n deleteSession(id: string): boolean {\n return this.transaction(() => {\n const sql = this.#storage.sql;\n sql.exec(`DELETE FROM ${this.#operations} WHERE session = ?`, id);\n sql.exec(`DELETE FROM ${this.#log} WHERE session = ?`, id);\n return (\n sql.exec(`DELETE FROM ${this.#sessions} WHERE id = ?`, id).rowsWritten >\n 0\n );\n });\n }\n\n #sessionOf(row: SessionRow): SessionRecord {\n return {\n id: row.id,\n parent: row.parent ?? undefined,\n state: parseJson(row.state),\n createdAt: row.created_at,\n updatedAt: row.updated_at\n };\n }\n\n // ── Operations ───────────────────────────────────────────────────────────\n\n /**\n * Durably queue an operation. Idempotent on `(session, id)`: a second\n * enqueue with the same id stores nothing and returns the first record.\n *\n * @param input - The session, the idempotency id, the input and options.\n * @returns The stored record, and whether this call created it.\n */\n enqueue(input: {\n readonly session: string;\n readonly id: string;\n readonly input: JsonValue;\n readonly meta?: JsonValue;\n }): { readonly record: OperationRecord; readonly accepted: boolean } {\n return this.transaction(() => {\n const existing = this.operation(input.session, input.id);\n if (existing) return { record: existing, accepted: false };\n const sql = this.#storage.sql;\n const next =\n sql\n .exec<{\n seq: number | null;\n }>(`SELECT MAX(seq) AS seq FROM ${this.#operations}`)\n .toArray()[0]?.seq ?? 0;\n sql.exec(\n `INSERT INTO ${this.#operations}\n (session, id, seq, status, input, meta, result, reason, created_at, settled_at)\n VALUES (?, ?, ?, 'queued', ?, ?, 'null', NULL, ?, NULL)`,\n input.session,\n input.id,\n next + 1,\n JSON.stringify(input.input),\n JSON.stringify(input.meta ?? null),\n Date.now()\n );\n const record = this.operation(input.session, input.id);\n if (!record) throw new Error(`Operation ${input.id} was not stored`);\n return { record, accepted: true };\n });\n }\n\n /**\n * Read one operation.\n *\n * @param session - The session id.\n * @param id - The operation id.\n * @returns The operation, or `undefined` when there is none.\n */\n operation(session: string, id: string): OperationRecord | undefined {\n const row = this.#storage.sql\n .exec<OperationRow>(\n `SELECT * FROM ${this.#operations} WHERE session = ? AND id = ?`,\n session,\n id\n )\n .toArray()[0];\n return row ? this.#operationOf(row) : undefined;\n }\n\n /**\n * Operations in submission order, optionally narrowed to one session and\n * to some statuses.\n *\n * @param filter - The session and statuses to keep. Default: all.\n * @returns The matching operations, oldest first.\n */\n operations(\n filter: {\n readonly session?: string;\n readonly status?: readonly OperationStatus[];\n } = {}\n ): OperationRecord[] {\n const where: string[] = [];\n const params: string[] = [];\n if (filter.session !== undefined) {\n where.push(\"session = ?\");\n params.push(filter.session);\n }\n if (filter.status !== undefined) {\n if (filter.status.length === 0) return [];\n where.push(`status IN (${filter.status.map(() => \"?\").join(\", \")})`);\n params.push(...filter.status);\n }\n return this.#storage.sql\n .exec<OperationRow>(\n `SELECT * FROM ${this.#operations}\n ${where.length > 0 ? `WHERE ${where.join(\" AND \")}` : \"\"}\n ORDER BY seq`,\n ...params\n )\n .toArray()\n .map((row) => this.#operationOf(row));\n }\n\n /**\n * Move a queued operation to `running`.\n *\n * @param session - The session id.\n * @param id - The operation id.\n * @returns False when it was not queued.\n */\n start(session: string, id: string): boolean {\n return this.#transition(session, id, [\"queued\"], \"running\");\n }\n\n /**\n * Move a running operation back to `queued`, to run it again.\n *\n * @param session - The session id.\n * @param id - The operation id.\n * @returns False when it was not running.\n */\n requeue(session: string, id: string): boolean {\n return this.#transition(session, id, [\"running\"], \"queued\");\n }\n\n /**\n * Settle a queued or running operation.\n *\n * @param session - The session id.\n * @param id - The operation id.\n * @param outcome - How it ended.\n * @returns False when it had already settled or does not exist.\n */\n settle(session: string, id: string, outcome: OperationOutcome): boolean {\n return (\n this.#storage.sql.exec(\n `UPDATE ${this.#operations}\n SET status = ?, result = ?, reason = ?, settled_at = ?\n WHERE session = ? AND id = ? AND status IN ('queued', 'running')`,\n outcome.status,\n JSON.stringify(outcome.status === \"done\" ? outcome.result : null),\n outcome.status === \"unanswered\" ? outcome.reason : null,\n Date.now(),\n session,\n id\n ).rowsWritten > 0\n );\n }\n\n /**\n * Replace an operation's harness-owned bookkeeping.\n *\n * @param session - The session id.\n * @param id - The operation id.\n * @param meta - The new value.\n * @returns False when there is no such operation.\n */\n setOperationMeta(session: string, id: string, meta: JsonValue): boolean {\n return (\n this.#storage.sql.exec(\n `UPDATE ${this.#operations} SET meta = ? WHERE session = ? AND id = ?`,\n JSON.stringify(meta),\n session,\n id\n ).rowsWritten > 0\n );\n }\n\n #transition(\n session: string,\n id: string,\n from: readonly OperationStatus[],\n to: OperationStatus\n ): boolean {\n return (\n this.#storage.sql.exec(\n `UPDATE ${this.#operations} SET status = ?\n WHERE session = ? AND id = ? AND status IN (${from.map(() => \"?\").join(\", \")})`,\n to,\n session,\n id,\n ...from\n ).rowsWritten > 0\n );\n }\n\n #operationOf(row: OperationRow): OperationRecord {\n if (!isStatus(row.status)) {\n throw new Error(`Unknown operation status ${row.status}`);\n }\n return {\n session: row.session,\n id: row.id,\n seq: row.seq,\n status: row.status,\n input: parseJson(row.input),\n meta: parseJson(row.meta),\n result: parseJson(row.result),\n reason: row.reason ?? undefined,\n createdAt: row.created_at,\n settledAt: row.settled_at ?? undefined\n };\n }\n\n // ── Logs ─────────────────────────────────────────────────────────────────\n\n /**\n * Append entries to a session's log. An entry with an id that is already\n * in the log replaces that entry in place, keeping its position.\n *\n * @param session - The session id.\n * @param log - The log's name, such as `\"messages\"`.\n * @param entries - The entries, in order.\n * @returns The position of the last entry written, or of the log's end.\n */\n append(session: string, log: string, entries: readonly LogAppend[]): number {\n return this.transaction(() => {\n let end = this.end(session, log);\n for (const entry of entries) {\n const existing =\n entry.id === undefined\n ? undefined\n : this.#seqOf(session, log, entry.id);\n if (existing !== undefined) {\n this.#write(session, log, existing, entry);\n continue;\n }\n end += 1;\n this.#write(session, log, end, entry);\n }\n return end;\n });\n }\n\n /**\n * Read a session's log in order.\n *\n * @param session - The session id.\n * @param log - The log's name.\n * @param range - Entries after position `after` (exclusive), at most `limit`.\n * @returns The entries.\n */\n read(\n session: string,\n log: string,\n range: { readonly after?: number; readonly limit?: number } = {}\n ): LogEntry[] {\n const after = range.after ?? 0;\n const limit = range.limit ?? -1;\n const rows = this.#storage.sql\n .exec<LogRow>(\n `SELECT seq, part, id, data, created_at FROM ${this.#log}\n WHERE session = ? AND log = ? AND seq IN (\n SELECT DISTINCT seq FROM ${this.#log}\n WHERE session = ? AND log = ? AND seq > ?\n ORDER BY seq LIMIT ?\n )\n ORDER BY seq, part`,\n session,\n log,\n session,\n log,\n after,\n limit\n )\n .toArray();\n const entries: LogEntry[] = [];\n let current: { row: LogRow; text: string } | undefined;\n const flush = () => {\n if (!current) return;\n entries.push({\n seq: current.row.seq,\n id: current.row.id ?? undefined,\n data: parseJson(current.text),\n createdAt: current.row.created_at\n });\n };\n for (const row of rows) {\n if (current && current.row.seq === row.seq) {\n current.text += row.data;\n continue;\n }\n flush();\n current = { row, text: row.data };\n }\n flush();\n return entries;\n }\n\n /**\n * One entry by id.\n *\n * @param session - The session id.\n * @param log - The log's name.\n * @param id - The entry id.\n * @returns The entry, or `undefined`.\n */\n entry(session: string, log: string, id: string): LogEntry | undefined {\n const seq = this.#seqOf(session, log, id);\n if (seq === undefined) return undefined;\n return this.read(session, log, { after: seq - 1, limit: 1 })[0];\n }\n\n /**\n * The position of a log's last entry.\n *\n * @param session - The session id.\n * @param log - The log's name.\n * @returns The position, or 0 for an empty log.\n */\n end(session: string, log: string): number {\n return (\n this.#storage.sql\n .exec<{ seq: number | null }>(\n `SELECT MAX(seq) AS seq FROM ${this.#log} WHERE session = ? AND log = ?`,\n session,\n log\n )\n .toArray()[0]?.seq ?? 0\n );\n }\n\n /**\n * Empty a session's log.\n *\n * @param session - The session id.\n * @param log - The log's name.\n */\n clear(session: string, log: string): void {\n this.#storage.sql.exec(\n `DELETE FROM ${this.#log} WHERE session = ? AND log = ?`,\n session,\n log\n );\n }\n\n /**\n * Copy one session's log onto the end of another's, keeping entry ids.\n *\n * @param from - The source session.\n * @param to - The target session.\n * @param log - The log's name.\n */\n copy(from: string, to: string, log: string): void {\n this.transaction(() => {\n const offset = this.end(to, log);\n this.#storage.sql.exec(\n `INSERT INTO ${this.#log} (session, log, seq, part, id, data, created_at)\n SELECT ?, log, seq + ?, part, id, data, created_at FROM ${this.#log}\n WHERE session = ? AND log = ?`,\n to,\n offset,\n from,\n log\n );\n });\n }\n\n #seqOf(session: string, log: string, id: string): number | undefined {\n return this.#storage.sql\n .exec<{ seq: number }>(\n `SELECT seq FROM ${this.#log} WHERE session = ? AND log = ? AND id = ? LIMIT 1`,\n session,\n log,\n id\n )\n .toArray()[0]?.seq;\n }\n\n #write(session: string, log: string, seq: number, entry: LogAppend): void {\n const sql = this.#storage.sql;\n const createdAt =\n sql\n .exec<{ created_at: number }>(\n `SELECT created_at FROM ${this.#log} WHERE session = ? AND log = ? AND seq = ? LIMIT 1`,\n session,\n log,\n seq\n )\n .toArray()[0]?.created_at ?? Date.now();\n sql.exec(\n `DELETE FROM ${this.#log} WHERE session = ? AND log = ? AND seq = ?`,\n session,\n log,\n seq\n );\n chunks(JSON.stringify(entry.data)).forEach((part, index) => {\n sql.exec(\n `INSERT INTO ${this.#log} (session, log, seq, part, id, data, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n session,\n log,\n seq,\n index,\n entry.id ?? null,\n part,\n createdAt\n );\n });\n }\n}\n"],"mappings":"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"}
@@ -12,7 +12,7 @@ import {
12
12
  s as StreamOpenOptions,
13
13
  t as DEFAULT_MAX_CHUNK_BYTES,
14
14
  u as StreamSettleOptions
15
- } from "../streams-Cmkj9QfW.js";
15
+ } from "../streams-fbG61qM8.js";
16
16
 
17
17
  //#region src/streams/errors.d.ts
18
18
  /**
@@ -1,4 +1,4 @@
1
- import { a as StreamSerializationError, i as StreamNotFoundError, n as Streams, r as StreamClosedError, t as DEFAULT_MAX_CHUNK_BYTES } from "../streams-DW-UCOUc.js";
1
+ import { a as StreamSerializationError, i as StreamNotFoundError, n as Streams, r as StreamClosedError, t as DEFAULT_MAX_CHUNK_BYTES } from "../streams-CITClVer.js";
2
2
  //#region src/streams/sse.ts
3
3
  const encoder = new TextEncoder();
4
4
  function resumeFrom(options) {
@@ -192,6 +192,7 @@ var Streams = class extends LifecycleCapability {
192
192
  if (rows.length === 0) return;
193
193
  continue;
194
194
  }
195
+ if (rows.length > 0) continue;
195
196
  await _assertClassBrand(_Streams_brand, this, _waitForWakeup).call(this, streamId, signal);
196
197
  }
197
198
  }
@@ -414,7 +415,7 @@ function _deleteRows(streamId) {
414
415
  for (const hook of _classPrivateFieldGet2(_deleteHooks, this)) hook(row, cursor);
415
416
  }
416
417
  }
417
- if (_classPrivateFieldGet2(_legacyChunkTable, this)) {
418
+ if (_assertClassBrand(_Streams_brand, this, _legacyTableLive).call(this)) {
418
419
  _assertClassBrand(_Streams_brand, this, _sql).bind(this)`DELETE FROM cf_agents_stream_chunks WHERE stream_id = ${streamId}`;
419
420
  _assertClassBrand(_Streams_brand, this, _dropLegacyChunkTableIfEmpty).call(this);
420
421
  }
@@ -587,7 +588,7 @@ function _blockTail(streamId) {
587
588
  * per chunk. The table is dropped once the last stream's rows are gone.
588
589
  */
589
590
  function _foldLegacyChunks(streamId) {
590
- if (!_classPrivateFieldGet2(_legacyChunkTable, this)) return;
591
+ if (!_assertClassBrand(_Streams_brand, this, _legacyTableLive).call(this)) return;
591
592
  this.lifecycle.storage.transactionSync(() => {
592
593
  const tail = _assertClassBrand(_Streams_brand, this, _sql).bind(this)`
593
594
  SELECT block, seq_to FROM cf_agents_stream_blocks
@@ -636,6 +637,18 @@ function _foldLegacyChunks(streamId) {
636
637
  _assertClassBrand(_Streams_brand, this, _dropLegacyChunkTableIfEmpty).call(this);
637
638
  });
638
639
  }
640
+ /**
641
+ * Whether the v1 chunk table is still there. The flag is per instance,
642
+ * but the table is per object: another Streams instance on the same
643
+ * storage (a host's own, beside a harness's) may have folded the last v1
644
+ * rows and dropped it. Recheck before use while the flag says it exists.
645
+ */
646
+ function _legacyTableLive() {
647
+ if (!_classPrivateFieldGet2(_legacyChunkTable, this)) return false;
648
+ if (_assertClassBrand(_Streams_brand, this, _hasLegacyChunkTable).call(this)) return true;
649
+ _classPrivateFieldSet2(_legacyChunkTable, this, false);
650
+ return false;
651
+ }
639
652
  function _hasLegacyChunkTable() {
640
653
  return _assertClassBrand(_Streams_brand, this, _sql).bind(this)`
641
654
  SELECT name FROM sqlite_master
@@ -713,4 +726,4 @@ function _emit(type, payload) {
713
726
  //#endregion
714
727
  export { StreamSerializationError as a, StreamNotFoundError as i, Streams as n, StreamClosedError as r, DEFAULT_MAX_CHUNK_BYTES as t };
715
728
 
716
- //# sourceMappingURL=streams-DW-UCOUc.js.map
729
+ //# sourceMappingURL=streams-CITClVer.js.map