@lamplitisles/dsh-nanocodex 0.1.0-beta.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 (276) hide show
  1. package/LICENSE +65 -0
  2. package/NOTICE +2 -0
  3. package/README.md +182 -0
  4. package/THIRD_PARTY_NOTICES.md +29 -0
  5. package/cordis.patch.yml +52 -0
  6. package/dist/index.d.ts +435 -0
  7. package/dist/index.js +3405 -0
  8. package/dist/standard-preset.d.ts +7 -0
  9. package/dist/standard-preset.js +25 -0
  10. package/engine-release.json +14 -0
  11. package/package.json +119 -0
  12. package/presets/standard/agent.cordis.yml +6 -0
  13. package/presets/standard/preset.yml +2 -0
  14. package/vendor/nanocodex/README.md +1344 -0
  15. package/vendor/nanocodex/actions/events.d.mts +10 -0
  16. package/vendor/nanocodex/actions/events.mjs +163 -0
  17. package/vendor/nanocodex/actions/index.d.mts +13 -0
  18. package/vendor/nanocodex/actions/index.mjs +35 -0
  19. package/vendor/nanocodex/actions/session.d.mts +66 -0
  20. package/vendor/nanocodex/actions/session.mjs +59 -0
  21. package/vendor/nanocodex/actions/turn.d.mts +59 -0
  22. package/vendor/nanocodex/actions/turn.mjs +37 -0
  23. package/vendor/nanocodex/actions/voice.d.mts +22 -0
  24. package/vendor/nanocodex/actions/voice.mjs +50 -0
  25. package/vendor/nanocodex/browser/Agent.d.mts +55 -0
  26. package/vendor/nanocodex/browser/Agent.mjs +11 -0
  27. package/vendor/nanocodex/browser/ChatGptSubscription.d.mts +7 -0
  28. package/vendor/nanocodex/browser/ChatGptSubscription.mjs +19 -0
  29. package/vendor/nanocodex/browser/InlineAgent.mjs +266 -0
  30. package/vendor/nanocodex/browser/Transport.d.mts +74 -0
  31. package/vendor/nanocodex/browser/Transport.mjs +61 -0
  32. package/vendor/nanocodex/browser/Voice.d.mts +71 -0
  33. package/vendor/nanocodex/browser/Voice.mjs +291 -0
  34. package/vendor/nanocodex/browser/VoiceSession.mjs +688 -0
  35. package/vendor/nanocodex/browser/WorkerAgent.d.mts +65 -0
  36. package/vendor/nanocodex/browser/WorkerAgent.mjs +1472 -0
  37. package/vendor/nanocodex/browser/agent.worker.mjs +3 -0
  38. package/vendor/nanocodex/browser/config.d.mts +36 -0
  39. package/vendor/nanocodex/browser/config.mjs +439 -0
  40. package/vendor/nanocodex/browser/engine.mjs +13 -0
  41. package/vendor/nanocodex/browser/harness.mjs +55 -0
  42. package/vendor/nanocodex/browser/host.d.mts +83 -0
  43. package/vendor/nanocodex/browser/host.mjs +555 -0
  44. package/vendor/nanocodex/browser/hostManagedWebSocket.d.mts +14 -0
  45. package/vendor/nanocodex/browser/hostManagedWebSocket.mjs +110 -0
  46. package/vendor/nanocodex/browser/index.d.mts +92 -0
  47. package/vendor/nanocodex/browser/index.mjs +23 -0
  48. package/vendor/nanocodex/browser/indexeddb-durability-store.mjs +197 -0
  49. package/vendor/nanocodex/browser/workspace.d.mts +16 -0
  50. package/vendor/nanocodex/browser/workspace.mjs +107 -0
  51. package/vendor/nanocodex/cloud/Client.d.mts +83 -0
  52. package/vendor/nanocodex/cloud/Client.mjs +231 -0
  53. package/vendor/nanocodex/cloud/Decorator.d.mts +31 -0
  54. package/vendor/nanocodex/cloud/Decorator.mjs +37 -0
  55. package/vendor/nanocodex/cloud/Dialog.d.mts +113 -0
  56. package/vendor/nanocodex/cloud/Dialog.mjs +366 -0
  57. package/vendor/nanocodex/cloud/Errors.d.mts +22 -0
  58. package/vendor/nanocodex/cloud/Errors.mjs +39 -0
  59. package/vendor/nanocodex/cloud/Principal.d.mts +26 -0
  60. package/vendor/nanocodex/cloud/Principal.mjs +88 -0
  61. package/vendor/nanocodex/cloud/RemoteProvider.mjs +88 -0
  62. package/vendor/nanocodex/cloud/Transport.d.mts +47 -0
  63. package/vendor/nanocodex/cloud/Transport.mjs +454 -0
  64. package/vendor/nanocodex/cloud/actions/account.d.mts +9 -0
  65. package/vendor/nanocodex/cloud/actions/account.mjs +19 -0
  66. package/vendor/nanocodex/cloud/actions/agent.d.mts +18 -0
  67. package/vendor/nanocodex/cloud/actions/agent.mjs +428 -0
  68. package/vendor/nanocodex/cloud/actions/connection.d.mts +133 -0
  69. package/vendor/nanocodex/cloud/actions/connection.mjs +580 -0
  70. package/vendor/nanocodex/cloud/actions/grant.d.mts +10 -0
  71. package/vendor/nanocodex/cloud/actions/grant.mjs +12 -0
  72. package/vendor/nanocodex/cloud/actions/index.d.mts +7 -0
  73. package/vendor/nanocodex/cloud/actions/index.mjs +7 -0
  74. package/vendor/nanocodex/cloud/actions/machineUsd.d.mts +23 -0
  75. package/vendor/nanocodex/cloud/actions/machineUsd.mjs +37 -0
  76. package/vendor/nanocodex/cloud/actions/model.d.mts +12 -0
  77. package/vendor/nanocodex/cloud/actions/model.mjs +50 -0
  78. package/vendor/nanocodex/cloud/actions/mpp.d.mts +28 -0
  79. package/vendor/nanocodex/cloud/actions/mpp.mjs +39 -0
  80. package/vendor/nanocodex/cloud/index.d.mts +30 -0
  81. package/vendor/nanocodex/cloud/index.mjs +9 -0
  82. package/vendor/nanocodex/cloud/internal.mjs +533 -0
  83. package/vendor/nanocodex/cloud/mercator.mjs +108 -0
  84. package/vendor/nanocodex/cloud/server/HostPrincipal.d.mts +34 -0
  85. package/vendor/nanocodex/cloud/server/HostPrincipal.mjs +202 -0
  86. package/vendor/nanocodex/cloud/server/index.d.mts +1 -0
  87. package/vendor/nanocodex/cloud/server/index.mjs +1 -0
  88. package/vendor/nanocodex/cloud/types.d.mts +211 -0
  89. package/vendor/nanocodex/cloudflare/Agent.d.mts +133 -0
  90. package/vendor/nanocodex/cloudflare/Agent.mjs +811 -0
  91. package/vendor/nanocodex/cloudflare/egress-subject.mjs +19 -0
  92. package/vendor/nanocodex/cloudflare/egress.d.mts +41 -0
  93. package/vendor/nanocodex/cloudflare/egress.mjs +119 -0
  94. package/vendor/nanocodex/cloudflare/event-socket.mjs +316 -0
  95. package/vendor/nanocodex/cloudflare/index.d.mts +7 -0
  96. package/vendor/nanocodex/cloudflare/index.mjs +6 -0
  97. package/vendor/nanocodex/host/Agent.d.mts +55 -0
  98. package/vendor/nanocodex/host/Agent.mjs +1 -0
  99. package/vendor/nanocodex/host/index.d.mts +82 -0
  100. package/vendor/nanocodex/host/index.mjs +10 -0
  101. package/vendor/nanocodex/index.d.mts +81 -0
  102. package/vendor/nanocodex/index.mjs +12 -0
  103. package/vendor/nanocodex/internal.mjs +1275 -0
  104. package/vendor/nanocodex/managed/Agent.d.mts +380 -0
  105. package/vendor/nanocodex/managed/Agent.mjs +1694 -0
  106. package/vendor/nanocodex/managed/ManagedError.d.mts +9 -0
  107. package/vendor/nanocodex/managed/ManagedError.mjs +8 -0
  108. package/vendor/nanocodex/managed/README.md +241 -0
  109. package/vendor/nanocodex/managed/Voice.mjs +202 -0
  110. package/vendor/nanocodex/managed/index.d.mts +20 -0
  111. package/vendor/nanocodex/managed/index.mjs +2 -0
  112. package/vendor/nanocodex/managed/internal.mjs +119 -0
  113. package/vendor/nanocodex/node/Agent.d.mts +50 -0
  114. package/vendor/nanocodex/node/Agent.mjs +203 -0
  115. package/vendor/nanocodex/node/ChatGptSubscription.d.mts +9 -0
  116. package/vendor/nanocodex/node/ChatGptSubscription.mjs +17 -0
  117. package/vendor/nanocodex/node/Transport.d.mts +44 -0
  118. package/vendor/nanocodex/node/Transport.mjs +46 -0
  119. package/vendor/nanocodex/node/host.mjs +731 -0
  120. package/vendor/nanocodex/node/index.d.mts +73 -0
  121. package/vendor/nanocodex/node/index.mjs +17 -0
  122. package/vendor/nanocodex/node/workspace.d.mts +10 -0
  123. package/vendor/nanocodex/node/workspace.mjs +198 -0
  124. package/vendor/nanocodex/package.json +200 -0
  125. package/vendor/nanocodex/pkg-node/nanocodex.d.ts +675 -0
  126. package/vendor/nanocodex/pkg-node/nanocodex.js +2628 -0
  127. package/vendor/nanocodex/pkg-node/nanocodex_bg.wasm.d.ts +105 -0
  128. package/vendor/nanocodex/pkg-node/package.json +1 -0
  129. package/vendor/nanocodex/pkg-web/.nanocodex-bindgen-stamp +6 -0
  130. package/vendor/nanocodex/pkg-web/nanocodex-build.json +1 -0
  131. package/vendor/nanocodex/pkg-web/nanocodex.d.ts +805 -0
  132. package/vendor/nanocodex/pkg-web/nanocodex.js +2714 -0
  133. package/vendor/nanocodex/pkg-web/nanocodex_bg.js +2615 -0
  134. package/vendor/nanocodex/pkg-web/nanocodex_bg.wasm +0 -0
  135. package/vendor/nanocodex/pkg-web/nanocodex_bg.wasm.d.ts +105 -0
  136. package/vendor/nanocodex/pkg-web/nanocodex_worker.js +9 -0
  137. package/vendor/nanocodex/pkg-web/package.json +1 -0
  138. package/vendor/nanocodex/runtime/chatgpt-subscription.mjs +212 -0
  139. package/vendor/nanocodex/runtime/cloudflare-durability-store.d.mts +26 -0
  140. package/vendor/nanocodex/runtime/cloudflare-durability-store.mjs +168 -0
  141. package/vendor/nanocodex/runtime/code-evaluator.worker.mjs +137 -0
  142. package/vendor/nanocodex/runtime/code-runtime.mjs +1 -0
  143. package/vendor/nanocodex/runtime/durability-store.d.mts +85 -0
  144. package/vendor/nanocodex/runtime/durability-store.mjs +631 -0
  145. package/vendor/nanocodex/runtime/durability.mjs +153 -0
  146. package/vendor/nanocodex/runtime/managed-transport.mjs +460 -0
  147. package/vendor/nanocodex/runtime/mcp-runtime.mjs +534 -0
  148. package/vendor/nanocodex/runtime/postgres-durability-store.d.mts +64 -0
  149. package/vendor/nanocodex/runtime/postgres-durability-store.mjs +532 -0
  150. package/vendor/nanocodex/runtime/quickjs-evaluator.d.mts +17 -0
  151. package/vendor/nanocodex/runtime/quickjs-evaluator.mjs +236 -0
  152. package/vendor/nanocodex/runtime/responses-transport.mjs +22 -0
  153. package/vendor/nanocodex/runtime/subagents.d.mts +107 -0
  154. package/vendor/nanocodex/runtime/subagents.mjs +54 -0
  155. package/vendor/nanocodex/runtime/subscription-store.d.mts +8 -0
  156. package/vendor/nanocodex/runtime/subscription-store.mjs +42 -0
  157. package/vendor/nanocodex/runtime/tempo-provider.d.mts +125 -0
  158. package/vendor/nanocodex/runtime/tempo-provider.mjs +264 -0
  159. package/vendor/nanocodex/runtime/tool-configuration.mjs +1 -0
  160. package/vendor/nanocodex/runtime/tool-router.mjs +1 -0
  161. package/vendor/nanocodex/runtime/utf8.mjs +1 -0
  162. package/vendor/nanocodex/runtime/worker-evaluator.mjs +162 -0
  163. package/vendor/nanocodex/runtime/workspace.d.mts +1 -0
  164. package/vendor/nanocodex/runtime/workspace.mjs +1 -0
  165. package/vendor/nanocodex/tools/Tools.d.mts +56 -0
  166. package/vendor/nanocodex/tools/Tools.mjs +136 -0
  167. package/vendor/nanocodex/tools/artifact.d.mts +1 -0
  168. package/vendor/nanocodex/tools/artifact.mjs +1 -0
  169. package/vendor/nanocodex/tools/attachment.mjs +1 -0
  170. package/vendor/nanocodex/tools/bash.d.mts +1 -0
  171. package/vendor/nanocodex/tools/bash.mjs +1 -0
  172. package/vendor/nanocodex/tools/browser/accountInfo.mjs +795 -0
  173. package/vendor/nanocodex/tools/browser/browserBuffer.mjs +18 -0
  174. package/vendor/nanocodex/tools/browser/browserCompiler.mjs +155 -0
  175. package/vendor/nanocodex/tools/browser/browserEgress.mjs +161 -0
  176. package/vendor/nanocodex/tools/browser/browserPython.mjs +133 -0
  177. package/vendor/nanocodex/tools/browser/browserShell.mjs +1075 -0
  178. package/vendor/nanocodex/tools/browser/browserSprintf.mjs +4 -0
  179. package/vendor/nanocodex/tools/browser/browserSsh.mjs +201 -0
  180. package/vendor/nanocodex/tools/browser/browserZlib.mjs +136 -0
  181. package/vendor/nanocodex/tools/browser/compiler.worker.mjs +160 -0
  182. package/vendor/nanocodex/tools/browser/devTunnelsSshBrowser.mjs +13 -0
  183. package/vendor/nanocodex/tools/browser/index.d.mts +209 -0
  184. package/vendor/nanocodex/tools/browser/index.mjs +174 -0
  185. package/vendor/nanocodex/tools/browser/opfsGit.mjs +248 -0
  186. package/vendor/nanocodex/tools/browser/python.worker.mjs +114 -0
  187. package/vendor/nanocodex/tools/browser/threadGit.mjs +197 -0
  188. package/vendor/nanocodex/tools/browser/unsupportedNodeRsa.mjs +5 -0
  189. package/vendor/nanocodex/tools/browser/workspace.mjs +83 -0
  190. package/vendor/nanocodex/tools/dataset.d.mts +1 -0
  191. package/vendor/nanocodex/tools/dataset.mjs +1 -0
  192. package/vendor/nanocodex/tools/datasetContract.mjs +1 -0
  193. package/vendor/nanocodex/tools/datasetEngine.mjs +1 -0
  194. package/vendor/nanocodex/tools/hostedCatalog.d.mts +1 -0
  195. package/vendor/nanocodex/tools/hostedCatalog.mjs +1 -0
  196. package/vendor/nanocodex/tools/index.d.mts +49 -0
  197. package/vendor/nanocodex/tools/index.mjs +19 -0
  198. package/vendor/nanocodex/tools/namedTool.mjs +1 -0
  199. package/vendor/nanocodex/tools/repository-workspace.d.mts +1 -0
  200. package/vendor/nanocodex/tools/repository-workspace.mjs +1 -0
  201. package/vendor/nanocodex/tools/ssh.d.mts +1 -0
  202. package/vendor/nanocodex/tools/ssh.mjs +1 -0
  203. package/vendor/nanocodex/tools/standard.mjs +1 -0
  204. package/vendor/nanocodex/tools/standardDescriptions.mjs +1 -0
  205. package/vendor/nanocodex/types.d.mts +663 -0
  206. package/vendor/nanocodex/wasm.d.mts +4 -0
  207. package/vendor/nanocodex/worker/ChatGptSubscription.d.mts +9 -0
  208. package/vendor/nanocodex/worker/ChatGptSubscription.mjs +29 -0
  209. package/vendor/nanocodex/worker/index.d.mts +18 -0
  210. package/vendor/nanocodex/worker/index.mjs +5 -0
  211. package/vendor/nanocodex-tools/README.md +65 -0
  212. package/vendor/nanocodex-tools/dist/hosted/app-tool-catalog.d.ts +7 -0
  213. package/vendor/nanocodex-tools/dist/hosted/app-tool-catalog.js +14 -0
  214. package/vendor/nanocodex-tools/dist/hosted/broker-core.d.ts +172 -0
  215. package/vendor/nanocodex-tools/dist/hosted/broker-core.js +1278 -0
  216. package/vendor/nanocodex-tools/dist/hosted/index.d.ts +3 -0
  217. package/vendor/nanocodex-tools/dist/hosted/index.js +3 -0
  218. package/vendor/nanocodex-tools/dist/hosted/protocol.d.ts +120 -0
  219. package/vendor/nanocodex-tools/dist/hosted/protocol.js +415 -0
  220. package/vendor/nanocodex-tools/dist/index.d.ts +19 -0
  221. package/vendor/nanocodex-tools/dist/index.js +14 -0
  222. package/vendor/nanocodex-tools/dist/memory.d.ts +204 -0
  223. package/vendor/nanocodex-tools/dist/memory.js +411 -0
  224. package/vendor/nanocodex-tools/dist/namespace.d.ts +87 -0
  225. package/vendor/nanocodex-tools/dist/namespace.js +338 -0
  226. package/vendor/nanocodex-tools/dist/repository-archive.d.ts +4 -0
  227. package/vendor/nanocodex-tools/dist/repository-archive.js +104 -0
  228. package/vendor/nanocodex-tools/dist/runtime.d.ts +30 -0
  229. package/vendor/nanocodex-tools/dist/runtime.js +37 -0
  230. package/vendor/nanocodex-tools/dist/session.d.ts +167 -0
  231. package/vendor/nanocodex-tools/dist/session.js +286 -0
  232. package/vendor/nanocodex-tools/dist/shell.d.ts +51 -0
  233. package/vendor/nanocodex-tools/dist/shell.js +553 -0
  234. package/vendor/nanocodex-tools/dist/ssh.d.ts +29 -0
  235. package/vendor/nanocodex-tools/dist/ssh.js +66 -0
  236. package/vendor/nanocodex-tools/dist/workspace.d.ts +45 -0
  237. package/vendor/nanocodex-tools/dist/workspace.js +237 -0
  238. package/vendor/nanocodex-tools/package.json +122 -0
  239. package/vendor/nanocodex-tools/runtime/code-runtime.mjs +817 -0
  240. package/vendor/nanocodex-tools/runtime/tool-configuration.mjs +50 -0
  241. package/vendor/nanocodex-tools/runtime/tool-router.mjs +730 -0
  242. package/vendor/nanocodex-tools/runtime/utf8.d.mts +2 -0
  243. package/vendor/nanocodex-tools/runtime/utf8.mjs +25 -0
  244. package/vendor/nanocodex-tools/tools/artifact.d.mts +69 -0
  245. package/vendor/nanocodex-tools/tools/artifact.mjs +270 -0
  246. package/vendor/nanocodex-tools/tools/attachment.mjs +603 -0
  247. package/vendor/nanocodex-tools/tools/bash.d.mts +90 -0
  248. package/vendor/nanocodex-tools/tools/bash.mjs +742 -0
  249. package/vendor/nanocodex-tools/tools/dataset.d.mts +9 -0
  250. package/vendor/nanocodex-tools/tools/dataset.mjs +47 -0
  251. package/vendor/nanocodex-tools/tools/datasetContract.mjs +54 -0
  252. package/vendor/nanocodex-tools/tools/datasetEngine.mjs +1167 -0
  253. package/vendor/nanocodex-tools/tools/execution-contract.d.mts +5 -0
  254. package/vendor/nanocodex-tools/tools/execution-contract.mjs +63 -0
  255. package/vendor/nanocodex-tools/tools/hostedCatalog.d.mts +20 -0
  256. package/vendor/nanocodex-tools/tools/hostedCatalog.mjs +67 -0
  257. package/vendor/nanocodex-tools/tools/hostedMachine.d.mts +10 -0
  258. package/vendor/nanocodex-tools/tools/hostedMachine.mjs +56 -0
  259. package/vendor/nanocodex-tools/tools/just-bash-browser.d.mts +1 -0
  260. package/vendor/nanocodex-tools/tools/just-bash-browser.mjs +1 -0
  261. package/vendor/nanocodex-tools/tools/namedTool.d.mts +3 -0
  262. package/vendor/nanocodex-tools/tools/namedTool.mjs +3 -0
  263. package/vendor/nanocodex-tools/tools/nodeProcess.d.mts +10 -0
  264. package/vendor/nanocodex-tools/tools/nodeProcess.mjs +314 -0
  265. package/vendor/nanocodex-tools/tools/processOutput.mjs +56 -0
  266. package/vendor/nanocodex-tools/tools/repository-workspace.d.mts +55 -0
  267. package/vendor/nanocodex-tools/tools/repository-workspace.mjs +397 -0
  268. package/vendor/nanocodex-tools/tools/ssh.d.mts +56 -0
  269. package/vendor/nanocodex-tools/tools/ssh.mjs +503 -0
  270. package/vendor/nanocodex-tools/tools/standard.mjs +458 -0
  271. package/vendor/nanocodex-tools/tools/standardDescriptions.mjs +3 -0
  272. package/vendor/nanocodex-tools/tools/types.d.mts +83 -0
  273. package/vendor/nanocodex-tools/tools/workspace.d.mts +25 -0
  274. package/vendor/nanocodex-tools/tools/workspace.mjs +282 -0
  275. package/vendor/nanocodex-tools/tools/x.d.mts +30 -0
  276. package/vendor/nanocodex-tools/tools/x.mjs +91 -0
@@ -0,0 +1,1472 @@
1
+ import { agentActions } from "../actions/index.mjs";
2
+ import {
3
+ createAgentClient,
4
+ createBrowserVoice,
5
+ defineRuntime,
6
+ freezeJson,
7
+ getEncodedTurnSnapshot,
8
+ getEncodedTurnUsage,
9
+ releaseAgentSession,
10
+ reportError,
11
+ reserveAgentSession,
12
+ } from "../internal.mjs";
13
+ import { resolveResponsesTransport } from "../runtime/responses-transport.mjs";
14
+ import { utf8ByteLength } from "../runtime/utf8.mjs";
15
+ import { createIndexedDbDurabilityStore } from "./indexeddb-durability-store.mjs";
16
+
17
+ const DEFAULT_MAX_PENDING_RPCS = 1_024;
18
+ const MAX_RETAINED_RESULTS = 1_024;
19
+ export const WORKER_EVENT_BATCH_MAX_EVENTS = 256;
20
+ export const WORKER_EVENT_BATCH_MAX_BYTES = 256 * 1024;
21
+ export const WORKER_HEARTBEAT_INTERVAL_MS = 10_000;
22
+ export const WORKER_HEARTBEAT_TIMEOUT_MS = 30_000;
23
+ const WORKER_HEARTBEAT_MISSES = 2;
24
+ const PREWARM_TIMEOUT_MS = 15_000;
25
+ const PREWARM_RETENTION_MS = 30_000;
26
+ const PROTOCOL = "nanocodex.worker-agent.v1";
27
+ const eventEncoder = new TextEncoder();
28
+ const eventDecoder = new TextDecoder("utf-8", { fatal: true });
29
+ const recentImages = new Map();
30
+ let prewarmedWorker;
31
+
32
+ /** Creates a DefaultAgent whose owned driver and browser host live in one module Worker. */
33
+ export async function createWorkerAgent(options = {}, workerOptions = {}) {
34
+ workerOptions.signal?.throwIfAborted();
35
+ const config = serializeConfig(options);
36
+ const reservation = config.sessionId === undefined
37
+ ? undefined
38
+ : reserveAgentSession(config.sessionId);
39
+ let worker;
40
+ try {
41
+ const claimed = claimWorker(config.harness, config.module, workerOptions);
42
+ worker = claimed instanceof Promise ? await claimed : claimed;
43
+ } catch (error) {
44
+ releaseAgentSession(reservation);
45
+ throw error;
46
+ }
47
+ let connection;
48
+ try {
49
+ connection = new WorkerConnection(worker, workerOptions);
50
+ } catch (error) {
51
+ const errors = [error];
52
+ try {
53
+ disposeWorker(worker);
54
+ } catch (cleanupError) {
55
+ appendErrors(errors, cleanupError);
56
+ } finally {
57
+ releaseAgentSession(reservation);
58
+ }
59
+ throwErrors(errors, "Worker Agent connection construction and cleanup both failed");
60
+ }
61
+ const stopAbort = listenForAbort(workerOptions.signal, (error) => connection.fail(error));
62
+ try {
63
+ const root = await connection.boot(config);
64
+ workerOptions.signal?.throwIfAborted();
65
+ stopAbort();
66
+ return await connection.createClient(root, reservation);
67
+ } catch (error) {
68
+ stopAbort();
69
+ connection.fail(error);
70
+ releaseAgentSession(reservation);
71
+ throw error;
72
+ }
73
+ }
74
+
75
+ /** Starts the exact module Worker and browser harness consumed by the next Agent.create. */
76
+ export function prepareWorkerAgent(options = {}, workerOptions = {}) {
77
+ workerOptions.signal?.throwIfAborted();
78
+ const harness = options.harness === false ? false : harnessDescriptor(options, true);
79
+ const key = harnessKey(harness);
80
+ const module = options.module;
81
+ if (prewarmedWorker?.key === key && prewarmedWorker.module === module) {
82
+ const entry = prewarmedWorker;
83
+ return entry.prepare(workerOptions.signal);
84
+ }
85
+ prewarmedWorker?.cancel(new Error("Nanocodex Agent Worker prewarm was replaced"));
86
+ const worker = createWorker(workerOptions);
87
+ const channel = randomId();
88
+ let claimed = false;
89
+ let disposed = false;
90
+ let expiryTimer;
91
+ let startupTimer;
92
+ let cancel;
93
+ const preparationAborts = new Set();
94
+ const clearPreparationAborts = () => {
95
+ for (const stopAbort of preparationAborts) stopAbort();
96
+ preparationAborts.clear();
97
+ };
98
+ const ready = new Promise((resolve, reject) => {
99
+ let settled = false;
100
+ cancel = (error) => {
101
+ if (disposed) return;
102
+ disposed = true;
103
+ if (!settled) {
104
+ settled = true;
105
+ reject(error);
106
+ }
107
+ const cleanupErrors = [];
108
+ try { clearPreparationAborts(); } catch (cleanupError) { appendErrors(cleanupErrors, cleanupError); }
109
+ try { clearTimeout(expiryTimer); } catch (cleanupError) { appendErrors(cleanupErrors, cleanupError); }
110
+ try { clearTimeout(startupTimer); } catch (cleanupError) { appendErrors(cleanupErrors, cleanupError); }
111
+ try {
112
+ if (prewarmedWorker?.worker === worker) prewarmedWorker = undefined;
113
+ } catch (cleanupError) {
114
+ appendErrors(cleanupErrors, cleanupError);
115
+ }
116
+ try { disposeWorker(worker); } catch (cleanupError) { appendErrors(cleanupErrors, cleanupError); }
117
+ for (const cleanupError of cleanupErrors) reportError(cleanupError);
118
+ };
119
+ worker.onmessage = ({ data }) => {
120
+ if (data?.protocol !== PROTOCOL || data.channel !== channel) return;
121
+ if (data.type === "prewarmed") {
122
+ if (settled || disposed) return;
123
+ settled = true;
124
+ clearTimeout(startupTimer);
125
+ worker.onmessage = null;
126
+ worker.onerror = null;
127
+ worker.onmessageerror = null;
128
+ if (!claimed) {
129
+ expiryTimer = setTimeout(
130
+ () => cancel(new Error("Nanocodex prepared Agent Worker expired")),
131
+ PREWARM_RETENTION_MS,
132
+ );
133
+ }
134
+ resolve();
135
+ } else if (data.type === "fatal") {
136
+ cancel(decodeError(data.error));
137
+ }
138
+ };
139
+ worker.onerror = (event) => cancel(new Error(event?.message || "Nanocodex Agent Worker prewarm failed"));
140
+ worker.onmessageerror = () => cancel(new Error("Nanocodex Agent Worker returned an unreadable prewarm message"));
141
+ startupTimer = setTimeout(() => cancel(new Error("Nanocodex Agent Worker prewarm timed out")), PREWARM_TIMEOUT_MS);
142
+ try { worker.postMessage({ protocol: PROTOCOL, channel, type: "prewarm", harness, module }); }
143
+ catch (error) { cancel(error); }
144
+ });
145
+ const entry = {
146
+ cancel,
147
+ get claimed() { return claimed; },
148
+ claim(signal) {
149
+ claimed = true;
150
+ clearPreparationAborts();
151
+ clearTimeout(expiryTimer);
152
+ return abortable(ready, signal, (error) => cancel(error)).then(() => {
153
+ if (disposed) throw new Error("Nanocodex prepared Agent Worker was disposed");
154
+ return worker;
155
+ });
156
+ },
157
+ prepare(signal) {
158
+ if (signal !== undefined) {
159
+ let stopAbort = () => {};
160
+ stopAbort = listenForAbort(signal, (error) => {
161
+ preparationAborts.delete(stopAbort);
162
+ if (!claimed) cancel(error);
163
+ });
164
+ if (!signal.aborted) preparationAborts.add(stopAbort);
165
+ }
166
+ return ready;
167
+ },
168
+ key,
169
+ module,
170
+ ready,
171
+ worker,
172
+ };
173
+ if (!disposed) prewarmedWorker = entry;
174
+ return entry.prepare(workerOptions.signal);
175
+ }
176
+
177
+ /**
178
+ * Installs the reusable package RPC runtime in a Worker-like global scope.
179
+ * Tests and advanced integrations may inject the explicitly local Agent creator.
180
+ */
181
+ export function installWorkerAgentRuntime(scope = globalThis, options = {}) {
182
+ if (!scope || typeof scope.postMessage !== "function") {
183
+ throw new TypeError("the Worker Agent runtime requires a Worker-like scope");
184
+ }
185
+ const createAgent = options.createAgent ?? loadAgent;
186
+ const createDurabilityStore = options.createDurabilityStore
187
+ ?? (() => createIndexedDbDurabilityStore());
188
+ const prewarmLocal = options.prewarmLocal ?? prewarmWorkerRuntime;
189
+ const prewarmBoot = options.createAgent === undefined || options.prewarmLocal !== undefined
190
+ ? prewarmLocal
191
+ : undefined;
192
+ let generation = 0;
193
+ let channel;
194
+ let bootPromise;
195
+ let watcher;
196
+ let watcherAgentId;
197
+ let eventsEnabled = false;
198
+ let eventQueue = [];
199
+ let eventQueueBytes = 0;
200
+ let eventFlushScheduled = false;
201
+ let eventDeliveryGeneration = 0;
202
+ let nextAgent = 1;
203
+ let nextResult = 1;
204
+ let nextVoice = 1;
205
+ let nextChunkedEvent = 1;
206
+ const agents = new Map();
207
+ const turns = new Map();
208
+ const results = new Map();
209
+ const voices = new Map();
210
+
211
+ const post = (message, expectedGeneration = generation, transfer) => {
212
+ if (expectedGeneration !== generation) return;
213
+ const envelope = { protocol: PROTOCOL, channel, ...message };
214
+ if (transfer) scope.postMessage(envelope, transfer);
215
+ else scope.postMessage(envelope);
216
+ };
217
+
218
+ const cleanup = () => {
219
+ eventsEnabled = false;
220
+ stopWatching();
221
+ for (const turn of turns.values()) {
222
+ try { turn.dispose(); } catch (error) { reportError(error); }
223
+ }
224
+ for (const agent of agents.values()) {
225
+ try { agent.dispose(); } catch (error) { reportError(error); }
226
+ }
227
+ for (const voice of voices.values()) {
228
+ try { voice.free(); } catch (error) { reportError(error); }
229
+ }
230
+ turns.clear();
231
+ for (const resultId of [...results.keys()]) {
232
+ try { releaseWorkerResult(results, resultId); } catch (error) { reportError(error); }
233
+ }
234
+ agents.clear();
235
+ voices.clear();
236
+ };
237
+
238
+ const boot = async (message) => {
239
+ generation += 1;
240
+ const currentGeneration = generation;
241
+ cleanup();
242
+ channel = message.channel;
243
+ nextAgent = 1;
244
+ nextResult = 1;
245
+ nextVoice = 1;
246
+ try {
247
+ const hydration = hydrateConfig(message.config, createDurabilityStore);
248
+ const preparation = prewarmBoot?.(message.config.harness, {
249
+ module: message.config.module,
250
+ });
251
+ const [config] = await Promise.all([hydration, preparation]);
252
+ const agent = await createAgent(config);
253
+ if (currentGeneration !== generation) {
254
+ agent.dispose();
255
+ return;
256
+ }
257
+ const agentId = `agent-${nextAgent++}`;
258
+ agents.set(agentId, agent);
259
+ post({ type: "ready", root: describeAgent(agentId, agent) }, currentGeneration);
260
+ } catch (error) {
261
+ if (currentGeneration !== generation) return;
262
+ post({ type: "fatal", error: encodeError(error) }, currentGeneration);
263
+ cleanup();
264
+ }
265
+ };
266
+
267
+ const handle = async (message, currentGeneration) => {
268
+ try {
269
+ const value = await dispatch(message, {
270
+ agents,
271
+ turns,
272
+ results,
273
+ voices,
274
+ allocateAgent: (agent) => allocateAgent(agent, currentGeneration),
275
+ allocateResult,
276
+ allocateVoice: (voice) => {
277
+ const id = `voice-${nextVoice++}`;
278
+ voices.set(id, voice);
279
+ return id;
280
+ },
281
+ isCurrent: () => currentGeneration === generation,
282
+ moveWatcherFrom,
283
+ setEventsEnabled,
284
+ });
285
+ if (!message.noReply) post({ type: "resolve", id: message.id, value }, currentGeneration);
286
+ } catch (error) {
287
+ post({ type: "reject", id: message.id, error: encodeError(error) }, currentGeneration);
288
+ }
289
+ };
290
+
291
+ function allocateAgent(agent, expectedGeneration) {
292
+ if (expectedGeneration !== generation) {
293
+ agent.dispose();
294
+ throw new Error("the Worker Agent child belongs to a replaced runtime");
295
+ }
296
+ const id = `agent-${nextAgent++}`;
297
+ agents.set(id, agent);
298
+ if (eventsEnabled && !watcher) watchAgent(id, agent);
299
+ return describeAgent(id, agent);
300
+ }
301
+
302
+ function allocateResult(result) {
303
+ if (results.size >= MAX_RETAINED_RESULTS) {
304
+ result.dispose();
305
+ throw new RangeError(
306
+ `Worker Agent exceeded its bound of ${MAX_RETAINED_RESULTS} retained turn results`,
307
+ );
308
+ }
309
+ const id = `result-${nextResult++}`;
310
+ results.set(id, { active: 0, released: false, result });
311
+ return id;
312
+ }
313
+
314
+ function watchAgent(agentId, agent, expectedGeneration = generation) {
315
+ if (!eventsEnabled || watcher) return;
316
+ watcherAgentId = agentId;
317
+ watcher = agent.events.watch({ includeAllSessions: true });
318
+ watcher.onEvent((event, encodedBytes, encodedEvent) => {
319
+ enqueueEvent(event, encodedBytes, encodedEvent, expectedGeneration);
320
+ });
321
+ }
322
+
323
+ function stopWatching() {
324
+ watcher?.off();
325
+ watcher = undefined;
326
+ watcherAgentId = undefined;
327
+ eventQueue.length = 0;
328
+ eventQueue = [];
329
+ eventQueueBytes = 0;
330
+ eventFlushScheduled = false;
331
+ eventDeliveryGeneration += 1;
332
+ }
333
+
334
+ function setEventsEnabled(enabled) {
335
+ if (typeof enabled !== "boolean") throw new TypeError("Worker Agent event demand must be boolean");
336
+ if (eventsEnabled === enabled) return;
337
+ eventsEnabled = enabled;
338
+ if (!enabled) {
339
+ stopWatching();
340
+ return;
341
+ }
342
+ for (const [agentId, agent] of agents) {
343
+ watchAgent(agentId, agent);
344
+ break;
345
+ }
346
+ }
347
+
348
+ function enqueueEvent(event, encodedBytes, encodedEvent, expectedGeneration) {
349
+ if (!eventsEnabled || expectedGeneration !== generation) return;
350
+ const immutable = freezeJson(event);
351
+ const encoded = typeof encodedEvent === "string" ? encodedEvent : undefined;
352
+ const bytes = Number.isSafeInteger(encodedBytes) && encodedBytes >= 0
353
+ ? encodedBytes
354
+ : eventBytes(immutable, encoded);
355
+ if (
356
+ eventQueue.length
357
+ && (
358
+ eventQueue.length >= WORKER_EVENT_BATCH_MAX_EVENTS
359
+ || eventQueueBytes + bytes > WORKER_EVENT_BATCH_MAX_BYTES
360
+ )
361
+ ) {
362
+ flushEvents(expectedGeneration, eventDeliveryGeneration);
363
+ }
364
+ eventQueue.push({ bytes, encoded, event: immutable });
365
+ eventQueueBytes += bytes;
366
+ if (
367
+ eventQueue.length >= WORKER_EVENT_BATCH_MAX_EVENTS
368
+ || eventQueueBytes >= WORKER_EVENT_BATCH_MAX_BYTES
369
+ ) {
370
+ flushEvents(expectedGeneration, eventDeliveryGeneration);
371
+ return;
372
+ }
373
+ if (eventFlushScheduled) return;
374
+ eventFlushScheduled = true;
375
+ const deliveryGeneration = eventDeliveryGeneration;
376
+ queueMicrotask(() => flushEvents(expectedGeneration, deliveryGeneration));
377
+ }
378
+
379
+ function flushEvents(expectedGeneration, deliveryGeneration) {
380
+ if (
381
+ expectedGeneration !== generation
382
+ || deliveryGeneration !== eventDeliveryGeneration
383
+ || !eventsEnabled
384
+ ) return;
385
+ const pending = eventQueue;
386
+ eventQueue = [];
387
+ eventQueueBytes = 0;
388
+ eventFlushScheduled = false;
389
+ let head = 0;
390
+ while (head < pending.length) {
391
+ const first = pending[head];
392
+ if (first.bytes > WORKER_EVENT_BATCH_MAX_BYTES) {
393
+ postChunkedEvent(first, expectedGeneration);
394
+ head += 1;
395
+ continue;
396
+ }
397
+ const events = [];
398
+ let encodedBytes = 0;
399
+ while (head < pending.length && events.length < WORKER_EVENT_BATCH_MAX_EVENTS) {
400
+ const entry = pending[head];
401
+ if (entry.bytes > WORKER_EVENT_BATCH_MAX_BYTES) break;
402
+ if (events.length && encodedBytes + entry.bytes > WORKER_EVENT_BATCH_MAX_BYTES) break;
403
+ events.push({ encodedBytes: entry.bytes, event: entry.event });
404
+ encodedBytes += entry.bytes;
405
+ head += 1;
406
+ }
407
+ post({ type: "event.batch", encodedBytes, events }, expectedGeneration);
408
+ }
409
+ }
410
+
411
+ function postChunkedEvent(entry, expectedGeneration) {
412
+ const encoded = eventEncoder.encode(entry.encoded ?? JSON.stringify(entry.event));
413
+ const id = `event-${nextChunkedEvent++}`;
414
+ for (let offset = 0, index = 0; offset < encoded.byteLength; index += 1) {
415
+ const end = Math.min(offset + WORKER_EVENT_BATCH_MAX_BYTES, encoded.byteLength);
416
+ const chunk = encoded.slice(offset, end);
417
+ post({
418
+ type: "event.chunk",
419
+ chunk,
420
+ encodedBytes: encoded.byteLength,
421
+ id,
422
+ index,
423
+ last: end === encoded.byteLength,
424
+ }, expectedGeneration, [chunk.buffer]);
425
+ offset = end;
426
+ }
427
+ }
428
+
429
+ function moveWatcherFrom(agentId) {
430
+ if (watcherAgentId !== agentId) return;
431
+ watcher?.off();
432
+ watcher = undefined;
433
+ watcherAgentId = undefined;
434
+ for (const [candidateId, candidate] of agents) {
435
+ if (candidateId !== agentId) {
436
+ watchAgent(candidateId, candidate);
437
+ break;
438
+ }
439
+ }
440
+ }
441
+
442
+ scope.onmessage = ({ data: message }) => {
443
+ if (message?.protocol !== PROTOCOL) return;
444
+ if (message.type === "prewarm") {
445
+ const currentGeneration = generation;
446
+ void Promise.resolve().then(() => prewarmLocal(message.harness, {
447
+ module: message.module,
448
+ })).then(
449
+ () => {
450
+ if (currentGeneration === generation) {
451
+ scope.postMessage({ protocol: PROTOCOL, channel: message.channel, type: "prewarmed" });
452
+ }
453
+ },
454
+ (error) => {
455
+ if (currentGeneration === generation) {
456
+ scope.postMessage({
457
+ protocol: PROTOCOL,
458
+ channel: message.channel,
459
+ type: "fatal",
460
+ error: encodeError(error),
461
+ });
462
+ }
463
+ },
464
+ );
465
+ return;
466
+ }
467
+ if (message.type === "boot") {
468
+ bootPromise = boot(message);
469
+ return;
470
+ }
471
+ if (message.channel !== channel || !bootPromise) return;
472
+ const currentGeneration = generation;
473
+ if (message.type === "liveness.ping") {
474
+ if (Number.isSafeInteger(message.sequence) && message.sequence > 0) {
475
+ post({ type: "liveness.pong", sequence: message.sequence }, currentGeneration);
476
+ }
477
+ return;
478
+ }
479
+ void bootPromise.then(() => handle(message, currentGeneration)).catch((error) => {
480
+ post({ type: "reject", id: message.id, error: encodeError(error) }, currentGeneration);
481
+ });
482
+ };
483
+
484
+ return Object.freeze({ dispose() { generation += 1; cleanup(); scope.onmessage = null; } });
485
+ }
486
+
487
+ async function dispatch(message, state) {
488
+ const { agents, turns, results, voices } = state;
489
+ switch (message.type) {
490
+ case "prompt": {
491
+ const agent = required(agents, message.agentId, "agent");
492
+ const turn = agent.turn.prompt(message.options);
493
+ if (turns.has(message.turnId)) throw new Error(`duplicate Worker Agent turn: ${message.turnId}`);
494
+ turns.set(message.turnId, turn);
495
+ try {
496
+ return await turn.accepted();
497
+ } catch (error) {
498
+ if (turns.get(message.turnId) === turn) turns.delete(message.turnId);
499
+ turn.dispose();
500
+ throw error;
501
+ }
502
+ }
503
+ case "events": {
504
+ state.setEventsEnabled(message.enabled);
505
+ return undefined;
506
+ }
507
+ case "rpc": break;
508
+ default: throw new Error(`unknown Worker Agent message: ${message.type}`);
509
+ }
510
+ const { method, args = [] } = message;
511
+ if (method === "turn.result") {
512
+ const turn = required(turns, args[0], "turn");
513
+ let result;
514
+ try {
515
+ result = await turn.result();
516
+ } finally {
517
+ if (turns.get(args[0]) === turn) turns.delete(args[0]);
518
+ turn.dispose();
519
+ }
520
+ if (!state.isCurrent()) {
521
+ result.dispose();
522
+ throw new Error("the Worker Agent completion belongs to a replaced runtime");
523
+ }
524
+ const resultId = state.allocateResult(result);
525
+ return { finalMessage: result.finalMessage, resultId };
526
+ }
527
+ if (method === "turn.steer") return required(turns, args[0], "turn").steer(args[1]);
528
+ if (method === "turn.cancel") return required(turns, args[0], "turn").cancel();
529
+ if (method === "turn.dispose") {
530
+ const turn = turns.get(args[0]);
531
+ turns.delete(args[0]);
532
+ turn?.dispose();
533
+ return;
534
+ }
535
+ if (method === "result.snapshot") {
536
+ return withWorkerResult(results, args[0], getEncodedTurnSnapshot);
537
+ }
538
+ if (method === "result.usage") {
539
+ return withWorkerResult(results, args[0], getEncodedTurnUsage);
540
+ }
541
+ if (method === "result.dispose") {
542
+ releaseWorkerResult(results, args[0]);
543
+ return;
544
+ }
545
+ if (method === "voice.configure") return required(voices, args[0], "voice").configure(args[1]);
546
+ if (method === "voice.appendSpeech") return required(voices, args[0], "voice").appendSpeech(args[1]);
547
+ if (method === "voice.appendText") return required(voices, args[0], "voice").appendText(args[1], args[2]);
548
+ if (method === "voice.appendContext") return required(voices, args[0], "voice").appendContext(args[1]);
549
+ if (method === "voice.start") return required(voices, args[0], "voice").start();
550
+ if (method === "voice.callBody") return required(voices, args[0], "voice").callBody(args[1]);
551
+ if (method === "voice.completeCall") {
552
+ return required(voices, args[0], "voice").completeCall(args[1], args[2]);
553
+ }
554
+ if (method === "voice.sidebandUrl") {
555
+ return required(voices, args[0], "voice").sidebandUrl(args[1]);
556
+ }
557
+ if (method === "voice.sidebandOpened") {
558
+ return required(voices, args[0], "voice").sidebandOpened();
559
+ }
560
+ if (method === "voice.sidebandClosed") {
561
+ return required(voices, args[0], "voice").sidebandClosed(args[1]);
562
+ }
563
+ if (method === "voice.framesSent") {
564
+ return required(voices, args[0], "voice").framesSent(args[1]);
565
+ }
566
+ if (method === "voice.requiresAgentAdmission") {
567
+ return required(voices, args[0], "voice").requiresAgentAdmission(args[1]);
568
+ }
569
+ if (method === "voice.realtimeMessage") {
570
+ return required(voices, args[0], "voice").realtimeMessage(args[1]);
571
+ }
572
+ if (method === "voice.agentEvent") return required(voices, args[0], "voice").agentEvent(args[1]);
573
+ if (method === "voice.flush") return required(voices, args[0], "voice").flush(args[1]);
574
+ if (method === "voice.stop") return required(voices, args[0], "voice").stop();
575
+ if (method === "voice.cancel") return required(voices, args[0], "voice").cancel();
576
+ if (method === "voice.preferredPhysicalInput") {
577
+ return required(voices, args[0], "voice").preferredPhysicalInput(args[1], args[2]);
578
+ }
579
+ if (method === "voice.dispose") {
580
+ const voice = voices.get(args[0]);
581
+ voices.delete(args[0]);
582
+ voice?.free();
583
+ return;
584
+ }
585
+ const agent = required(agents, args[0], "agent");
586
+ if (method === "agent.voice.create") {
587
+ return state.allocateVoice(await createBrowserVoice(agent, args[1]));
588
+ }
589
+ if (method === "agent.fork") {
590
+ if (args[1] === undefined) return state.allocateAgent(await agent.session.fork());
591
+ return withWorkerResult(results, args[1], async (at) => (
592
+ state.allocateAgent(await agent.session.fork({ at }))
593
+ ));
594
+ }
595
+ if (method === "agent.spawn") return state.allocateAgent(await agent.session.spawn());
596
+ if (method === "agent.compact") return agent.session.compact();
597
+ if (method === "agent.context") return agent.session.context();
598
+ if (method === "agent.snapshot") return agent.session.snapshot();
599
+ if (method === "agent.setModel") return agent.session.setModel(args[1]);
600
+ if (method === "agent.setThinking") return agent.session.setThinking(args[1]);
601
+ if (method === "agent.setFastMode") return agent.session.setFastMode(args[1]);
602
+ if (method === "agent.appendDeveloperMessage") return agent.session.appendDeveloperMessage(args[1]);
603
+ if (method === "agent.realtime.start") return agent.session.realtime.start();
604
+ if (method === "agent.realtime.end") return agent.session.realtime.end();
605
+ if (method === "agent.realtime.delegation") {
606
+ return agent.session.realtime.delegation(args[1], JSON.parse(args[2]));
607
+ }
608
+ if (method === "agent.realtime.tailDelegation") {
609
+ return agent.session.realtime.tailDelegation(JSON.parse(args[1]));
610
+ }
611
+ if (method === "agent.shutdown") {
612
+ state.moveWatcherFrom(args[0]);
613
+ return agent.session.shutdown();
614
+ }
615
+ if (method === "agent.dispose") {
616
+ state.moveWatcherFrom(args[0]);
617
+ agents.delete(args[0]);
618
+ agent.dispose();
619
+ return;
620
+ }
621
+ throw new Error(`unknown Worker Agent RPC method: ${method}`);
622
+ }
623
+
624
+ function required(map, id, kind) {
625
+ const value = map.get(id);
626
+ if (!value) throw new Error(`unknown Worker Agent ${kind}: ${id}`);
627
+ return value;
628
+ }
629
+
630
+ async function withWorkerResult(results, resultId, action) {
631
+ const entry = required(results, resultId, "turn result");
632
+ entry.active += 1;
633
+ try {
634
+ return await action(entry.result);
635
+ } finally {
636
+ entry.active -= 1;
637
+ if (entry.released && entry.active === 0) entry.result.dispose();
638
+ }
639
+ }
640
+
641
+ function releaseWorkerResult(results, resultId) {
642
+ const entry = results.get(resultId);
643
+ if (!entry) return;
644
+ results.delete(resultId);
645
+ entry.released = true;
646
+ if (entry.active === 0) entry.result.dispose();
647
+ }
648
+
649
+ function describeAgent(agentId, agent) {
650
+ return { handleId: agentId, agentId: agent.agentId, sessionId: agent.sessionId };
651
+ }
652
+
653
+ class WorkerConnection {
654
+ constructor(worker, options) {
655
+ this.worker = worker;
656
+ if (options.onFailure !== undefined && typeof options.onFailure !== "function") {
657
+ throw new TypeError("onFailure must be a function");
658
+ }
659
+ this.onFailure = options.onFailure;
660
+ this.channel = randomId();
661
+ this.maxPending = options.maxPendingRpcs === undefined
662
+ ? DEFAULT_MAX_PENDING_RPCS
663
+ : positiveInteger(options.maxPendingRpcs, "maxPendingRpcs");
664
+ this.nextRpc = 1;
665
+ this.nextTurn = 1;
666
+ this.nextHeartbeat = 1;
667
+ this.pending = new Map();
668
+ this.listeners = new Set();
669
+ this.clients = new Set();
670
+ this.clientByRaw = new Map();
671
+ this.constructingAgents = new Set();
672
+ this.rawAgents = new Set();
673
+ this.chunkedEvent = undefined;
674
+ this.agents = 0;
675
+ this.voices = 0;
676
+ this.turns = 0;
677
+ this.results = 0;
678
+ this.operations = 0;
679
+ this.heartbeatMisses = 0;
680
+ this.heartbeatSequence = undefined;
681
+ this.heartbeatTimer = undefined;
682
+ this.closed = false;
683
+ this.closeError = undefined;
684
+ worker.onmessage = ({ data }) => this.receive(data);
685
+ worker.onerror = (event) => this.fail(new Error(event?.message || "Nanocodex Agent Worker failed"));
686
+ worker.onmessageerror = () => this.fail(new Error("Nanocodex Agent Worker returned an unreadable message"));
687
+ this.scheduleHeartbeat();
688
+ }
689
+
690
+ boot(config) {
691
+ const promise = this.pendingCall("boot");
692
+ try { this.send({ type: "boot", config }); }
693
+ catch (error) { this.rejectPending("boot", error); }
694
+ return promise;
695
+ }
696
+
697
+ runtime() {
698
+ return defineRuntime({
699
+ key: "browser-worker-wasm",
700
+ name: "Nanocodex Browser Worker WASM",
701
+ type: "browser",
702
+ create: (descriptor) => this.rawAgent(descriptor),
703
+ adopt: () => this.assertOpen(),
704
+ subscribe: (listener) => this.subscribe(listener),
705
+ release: (raw) => {
706
+ const client = this.clientByRaw.get(raw);
707
+ if (client !== undefined) this.clients.delete(client);
708
+ this.clientByRaw.delete(raw);
709
+ },
710
+ dispose: (raw) => {
711
+ if (!raw.released) {
712
+ raw.released = true;
713
+ this.rawAgents.delete(raw);
714
+ if (!this.constructingAgents.has(raw.handleId)) {
715
+ this.sendBestEffort("agent.dispose", [raw.handleId]);
716
+ }
717
+ this.agents -= 1;
718
+ }
719
+ this.closeIfIdle();
720
+ },
721
+ decorate: (agent, raw) => {
722
+ const decorated = agent.extend(agentActions());
723
+ this.clients.add(decorated);
724
+ this.clientByRaw.set(raw, decorated);
725
+ return decorated;
726
+ },
727
+ });
728
+ }
729
+
730
+ async createClient(root, reservation) {
731
+ const handleId = root?.handleId ?? root?.agentId;
732
+ this.constructingAgents.add(handleId);
733
+ try {
734
+ return await createAgentClient(this.runtime(), root, reservation);
735
+ } catch (error) {
736
+ if (this.closed) throw error;
737
+ try {
738
+ await this.rpc("agent.dispose", [handleId]);
739
+ } catch (rollbackError) {
740
+ throw new AggregateError(
741
+ [error, rollbackError],
742
+ "Worker Agent client construction and boot rollback both failed",
743
+ );
744
+ }
745
+ throw error;
746
+ } finally {
747
+ this.constructingAgents.delete(handleId);
748
+ this.closeIfIdle();
749
+ }
750
+ }
751
+
752
+ rawAgent(descriptor) {
753
+ this.assertOpen();
754
+ this.agents += 1;
755
+ const connection = this;
756
+ const handleId = descriptor.handleId ?? descriptor.agentId;
757
+ const agentId = descriptor.handleId === undefined
758
+ ? descriptor.sessionId
759
+ : descriptor.agentId;
760
+ const raw = {
761
+ handleId,
762
+ agentId,
763
+ sessionId: descriptor.sessionId,
764
+ released: false,
765
+ prompt(input, id) { return connection.prompt(handleId, { input, ...(id === undefined ? {} : { id }) }); },
766
+ promptContent(input, id) { return connection.prompt(handleId, { input: JSON.parse(input), ...(id === undefined ? {} : { id }) }); },
767
+ fork: async () => connection.rawAgent(await connection.rpc("agent.fork", [handleId])),
768
+ forkFrom: async (result) => {
769
+ if (result?.connection !== connection) {
770
+ throw new TypeError("historical forks require a result from the same Worker Agent");
771
+ }
772
+ return connection.rawAgent(await connection.rpc("agent.fork", [handleId, result.resultId]));
773
+ },
774
+ spawn: async () => connection.rawAgent(await connection.rpc("agent.spawn", [handleId])),
775
+ compact: () => connection.rpc("agent.compact", [handleId]),
776
+ context: async () => JSON.stringify(await connection.rpc("agent.context", [handleId])),
777
+ snapshot: async () => JSON.stringify(await connection.rpc("agent.snapshot", [handleId])),
778
+ setModel: (value) => connection.rpc("agent.setModel", [handleId, value]),
779
+ setThinking: (value) => connection.rpc("agent.setThinking", [handleId, value]),
780
+ setFastMode: (value) => connection.rpc("agent.setFastMode", [handleId, value]),
781
+ appendDeveloperMessage: async (text) => JSON.stringify(await connection.rpc("agent.appendDeveloperMessage", [handleId, text])),
782
+ startRealtimeConversation: async () => JSON.stringify(await connection.rpc("agent.realtime.start", [handleId])),
783
+ endRealtimeConversation: async () => JSON.stringify(await connection.rpc("agent.realtime.end", [handleId])),
784
+ realtimeDelegation: (input, transcript) => connection.rpc("agent.realtime.delegation", [handleId, input, transcript]),
785
+ realtimeTailDelegation: (transcript) => connection.rpc("agent.realtime.tailDelegation", [handleId, transcript]),
786
+ browserVoice: async (voice) => connection.rawVoice(
787
+ await connection.rpc("agent.voice.create", [handleId, voice]),
788
+ ),
789
+ shutdown: () => connection.rpc("agent.shutdown", [handleId]),
790
+ free() {},
791
+ };
792
+ this.rawAgents.add(raw);
793
+ return raw;
794
+ }
795
+
796
+ rawVoice(voiceId) {
797
+ this.assertOpen();
798
+ this.voices += 1;
799
+ const connection = this;
800
+ let released = false;
801
+ return {
802
+ configure: (settings) => connection.rpc("voice.configure", [voiceId, settings]),
803
+ appendSpeech: (text) => connection.rpc("voice.appendSpeech", [voiceId, text]),
804
+ appendText: (role, text) => connection.rpc("voice.appendText", [voiceId, role, text]),
805
+ appendContext: (text) => connection.rpc("voice.appendContext", [voiceId, text]),
806
+ start: () => connection.rpc("voice.start", [voiceId]),
807
+ callBody: (sdp) => connection.rpc("voice.callBody", [voiceId, sdp]),
808
+ completeCall: (body, location) => connection.rpc(
809
+ "voice.completeCall",
810
+ [voiceId, body, location],
811
+ ),
812
+ sidebandUrl: (callId) => connection.rpc("voice.sidebandUrl", [voiceId, callId]),
813
+ sidebandOpened: () => connection.rpc("voice.sidebandOpened", [voiceId]),
814
+ sidebandClosed: (connectedMs) => connection.rpc(
815
+ "voice.sidebandClosed",
816
+ [voiceId, connectedMs],
817
+ ),
818
+ framesSent: (count) => connection.rpc("voice.framesSent", [voiceId, count]),
819
+ requiresAgentAdmission: (payload) => connection.rpc(
820
+ "voice.requiresAgentAdmission",
821
+ [voiceId, payload],
822
+ ),
823
+ realtimeMessage: (payload) => connection.rpc("voice.realtimeMessage", [voiceId, payload]),
824
+ agentEvent: (event) => connection.rpc("voice.agentEvent", [voiceId, event]),
825
+ flush: (finalChunk) => connection.rpc("voice.flush", [voiceId, finalChunk]),
826
+ stop: () => connection.rpc("voice.stop", [voiceId]),
827
+ cancel: () => connection.rpc("voice.cancel", [voiceId]),
828
+ preferredPhysicalInput: (current, labels) => connection.rpc(
829
+ "voice.preferredPhysicalInput",
830
+ [voiceId, current, labels],
831
+ ),
832
+ free() {
833
+ if (released) return;
834
+ released = true;
835
+ connection.sendBestEffort("voice.dispose", [voiceId]);
836
+ connection.voices -= 1;
837
+ connection.closeIfIdle();
838
+ },
839
+ };
840
+ }
841
+
842
+ prompt(agentId, options) {
843
+ this.assertOpen();
844
+ const connection = this;
845
+ assertCloneable(options, "turn prompt");
846
+ const turnId = `turn-${this.nextTurn++}`;
847
+ const accepted = this.pendingCall(turnId);
848
+ void accepted.catch(() => {});
849
+ this.turns += 1;
850
+ try { this.send({ type: "prompt", id: turnId, agentId, turnId, options }); }
851
+ catch (error) { this.rejectPending(turnId, error); }
852
+ let result;
853
+ let disposed = false;
854
+ let retained = true;
855
+ return {
856
+ accepted() { return accepted; },
857
+ result() {
858
+ if (disposed && !result) {
859
+ return Promise.reject(new Error("the Nanocodex turn has been disposed"));
860
+ }
861
+ result ||= accepted
862
+ .then(() => connectionResult(thisConnection(), turnId))
863
+ .finally(release);
864
+ return result;
865
+ },
866
+ steer(input) { return accepted.then(() => thisConnection().rpc("turn.steer", [turnId, { input }])); },
867
+ steerContent(input) { return accepted.then(() => thisConnection().rpc("turn.steer", [turnId, { input: JSON.parse(input) }])); },
868
+ cancel() { return accepted.then(() => thisConnection().rpc("turn.cancel", [turnId])); },
869
+ free() {
870
+ if (disposed) return;
871
+ disposed = true;
872
+ if (result) return;
873
+ thisConnection().sendBestEffort("turn.dispose", [turnId]);
874
+ release();
875
+ },
876
+ };
877
+ function thisConnection() { return connection; }
878
+ function release() {
879
+ if (!retained) return;
880
+ retained = false;
881
+ connection.turns -= 1;
882
+ connection.closeIfIdle();
883
+ }
884
+ }
885
+
886
+ rpc(method, args) {
887
+ this.assertOpen();
888
+ assertCloneable(args, method);
889
+ const id = `rpc-${this.nextRpc++}`;
890
+ const promise = this.pendingCall(id);
891
+ this.operations += 1;
892
+ try { this.send({ type: "rpc", id, method, args }); }
893
+ catch (error) { this.rejectPending(id, error); }
894
+ return promise.finally(() => {
895
+ if (this.closed) return;
896
+ this.operations -= 1;
897
+ queueMicrotask(() => queueMicrotask(() => this.closeIfIdle()));
898
+ });
899
+ }
900
+
901
+ sendBestEffort(method, args) {
902
+ if (this.closed) return;
903
+ const id = `rpc-${this.nextRpc++}`;
904
+ try { this.send({ type: "rpc", id, method, args, noReply: true }); } catch {}
905
+ }
906
+
907
+ adoptResult() {
908
+ this.assertOpen();
909
+ this.results += 1;
910
+ }
911
+
912
+ releaseResult(resultId) {
913
+ if (this.results === 0) return;
914
+ this.sendBestEffort("result.dispose", [resultId]);
915
+ this.results -= 1;
916
+ this.closeIfIdle();
917
+ }
918
+
919
+ closeIfIdle() {
920
+ if (
921
+ this.constructingAgents.size === 0
922
+ && this.agents === 0
923
+ && this.voices === 0
924
+ && this.turns === 0
925
+ && this.results === 0
926
+ && this.operations === 0
927
+ ) {
928
+ this.close(new Error("the Nanocodex Agent Worker has been disposed"));
929
+ }
930
+ }
931
+
932
+ subscribe(listener) {
933
+ this.assertOpen();
934
+ const enable = this.listeners.size === 0;
935
+ this.listeners.add(listener);
936
+ if (enable) {
937
+ try { this.send({ type: "events", enabled: true, noReply: true }); }
938
+ catch (error) {
939
+ this.listeners.delete(listener);
940
+ throw error;
941
+ }
942
+ }
943
+ let active = true;
944
+ return () => {
945
+ if (!active) return;
946
+ active = false;
947
+ this.listeners.delete(listener);
948
+ if (this.listeners.size === 0 && !this.closed) {
949
+ try { this.send({ type: "events", enabled: false, noReply: true }); } catch {}
950
+ }
951
+ };
952
+ }
953
+
954
+ pendingCall(id) {
955
+ this.assertOpen();
956
+ if (this.pending.size >= this.maxPending) {
957
+ throw new RangeError(`Worker Agent exceeded its bound of ${this.maxPending} pending RPCs`);
958
+ }
959
+ return new Promise((resolve, reject) => this.pending.set(id, { resolve, reject }));
960
+ }
961
+
962
+ send(message) {
963
+ this.assertOpen();
964
+ this.worker.postMessage({ protocol: PROTOCOL, channel: this.channel, ...message });
965
+ }
966
+
967
+ receive(message) {
968
+ if (this.closed || message?.protocol !== PROTOCOL || message.channel !== this.channel) return;
969
+ if (message.type === "liveness.pong") {
970
+ this.receiveHeartbeat(message.sequence);
971
+ return;
972
+ }
973
+ if (message.type === "event.batch") {
974
+ if (!Array.isArray(message.events)
975
+ || message.events.length > WORKER_EVENT_BATCH_MAX_EVENTS
976
+ || !Number.isSafeInteger(message.encodedBytes)
977
+ || message.encodedBytes < 0
978
+ || message.encodedBytes > WORKER_EVENT_BATCH_MAX_BYTES) {
979
+ this.fail(new Error("Nanocodex Agent Worker returned an invalid event batch"));
980
+ return;
981
+ }
982
+ let encodedBytes = 0;
983
+ for (const entry of message.events) {
984
+ if (
985
+ !Number.isSafeInteger(entry?.encodedBytes)
986
+ || entry.encodedBytes < 0
987
+ || entry.encodedBytes > WORKER_EVENT_BATCH_MAX_BYTES
988
+ ) {
989
+ this.fail(new Error("Nanocodex Agent Worker returned an invalid event size"));
990
+ return;
991
+ }
992
+ encodedBytes += entry.encodedBytes;
993
+ }
994
+ if (encodedBytes !== message.encodedBytes) {
995
+ this.fail(new Error("Nanocodex Agent Worker returned inconsistent event batch bytes"));
996
+ return;
997
+ }
998
+ for (const entry of message.events) this.emitEvent(entry.event, entry.encodedBytes);
999
+ return;
1000
+ }
1001
+ if (message.type === "event.chunk") {
1002
+ this.receiveEventChunk(message);
1003
+ return;
1004
+ }
1005
+ if (message.type === "ready") return this.resolvePending("boot", message.root);
1006
+ if (message.type === "fatal") return this.fail(decodeError(message.error));
1007
+ if (message.type === "resolve") return this.resolvePending(message.id, message.value);
1008
+ if (message.type === "reject") return this.rejectPending(message.id, decodeError(message.error));
1009
+ }
1010
+
1011
+ resolvePending(id, value) {
1012
+ const pending = this.pending.get(id);
1013
+ if (!pending) return;
1014
+ this.pending.delete(id);
1015
+ pending.resolve(value);
1016
+ }
1017
+
1018
+ rejectPending(id, error) {
1019
+ const pending = this.pending.get(id);
1020
+ if (!pending) return;
1021
+ this.pending.delete(id);
1022
+ pending.reject(error);
1023
+ }
1024
+
1025
+ scheduleHeartbeat() {
1026
+ if (this.closed) return;
1027
+ clearTimeout(this.heartbeatTimer);
1028
+ this.heartbeatTimer = setTimeout(
1029
+ () => this.sendHeartbeat(),
1030
+ WORKER_HEARTBEAT_INTERVAL_MS,
1031
+ );
1032
+ }
1033
+
1034
+ sendHeartbeat() {
1035
+ if (this.closed) return;
1036
+ const sequence = this.nextHeartbeat++;
1037
+ this.heartbeatSequence = sequence;
1038
+ this.heartbeatTimer = setTimeout(
1039
+ () => this.missHeartbeat(sequence),
1040
+ WORKER_HEARTBEAT_TIMEOUT_MS,
1041
+ );
1042
+ try {
1043
+ this.send({ type: "liveness.ping", sequence });
1044
+ } catch (error) {
1045
+ this.fail(error);
1046
+ }
1047
+ }
1048
+
1049
+ receiveHeartbeat(sequence) {
1050
+ if (sequence !== this.heartbeatSequence) return;
1051
+ clearTimeout(this.heartbeatTimer);
1052
+ this.heartbeatSequence = undefined;
1053
+ this.heartbeatMisses = 0;
1054
+ this.scheduleHeartbeat();
1055
+ }
1056
+
1057
+ missHeartbeat(sequence) {
1058
+ if (this.closed || sequence !== this.heartbeatSequence) return;
1059
+ this.heartbeatMisses += 1;
1060
+ if (this.heartbeatMisses < WORKER_HEARTBEAT_MISSES) {
1061
+ this.sendHeartbeat();
1062
+ return;
1063
+ }
1064
+ const error = new Error(
1065
+ "Nanocodex Agent Worker stopped responding; retry to start a fresh Worker",
1066
+ );
1067
+ error.code = "worker_unresponsive";
1068
+ this.fail(error);
1069
+ }
1070
+
1071
+ emitEvent(event, encodedBytes) {
1072
+ const immutable = freezeJson(event);
1073
+ for (const listener of this.listeners) listener(immutable, encodedBytes);
1074
+ }
1075
+
1076
+ receiveEventChunk(message) {
1077
+ const chunk = message.chunk instanceof Uint8Array
1078
+ ? message.chunk
1079
+ : message.chunk instanceof ArrayBuffer ? new Uint8Array(message.chunk) : undefined;
1080
+ if (
1081
+ !chunk
1082
+ || chunk.byteLength > WORKER_EVENT_BATCH_MAX_BYTES
1083
+ || !Number.isSafeInteger(message.encodedBytes)
1084
+ || message.encodedBytes <= WORKER_EVENT_BATCH_MAX_BYTES
1085
+ || !Number.isSafeInteger(message.index)
1086
+ || message.index < 0
1087
+ || typeof message.id !== "string"
1088
+ || typeof message.last !== "boolean"
1089
+ ) {
1090
+ this.fail(new Error("Nanocodex Agent Worker returned an invalid chunked event"));
1091
+ return;
1092
+ }
1093
+ let entry = this.chunkedEvent;
1094
+ if (message.index === 0) {
1095
+ if (entry) {
1096
+ this.fail(new Error("Nanocodex Agent Worker interleaved chunked events"));
1097
+ return;
1098
+ }
1099
+ entry = { chunks: [], encodedBytes: message.encodedBytes, id: message.id, receivedBytes: 0 };
1100
+ this.chunkedEvent = entry;
1101
+ }
1102
+ if (
1103
+ !entry
1104
+ || entry.id !== message.id
1105
+ || entry.encodedBytes !== message.encodedBytes
1106
+ || entry.chunks.length !== message.index
1107
+ || entry.receivedBytes + chunk.byteLength > entry.encodedBytes
1108
+ ) {
1109
+ this.fail(new Error("Nanocodex Agent Worker returned an out-of-order chunked event"));
1110
+ return;
1111
+ }
1112
+ entry.chunks.push(chunk);
1113
+ entry.receivedBytes += chunk.byteLength;
1114
+ if (!message.last) return;
1115
+ if (entry.receivedBytes !== entry.encodedBytes) {
1116
+ this.fail(new Error("Nanocodex Agent Worker returned an incomplete chunked event"));
1117
+ return;
1118
+ }
1119
+ const encoded = new Uint8Array(entry.encodedBytes);
1120
+ let offset = 0;
1121
+ for (const part of entry.chunks) {
1122
+ encoded.set(part, offset);
1123
+ offset += part.byteLength;
1124
+ }
1125
+ this.chunkedEvent = undefined;
1126
+ try {
1127
+ this.emitEvent(JSON.parse(eventDecoder.decode(encoded)), entry.encodedBytes);
1128
+ } catch (error) {
1129
+ this.fail(new Error("Nanocodex Agent Worker returned an invalid encoded event", { cause: error }));
1130
+ }
1131
+ }
1132
+
1133
+ assertOpen() {
1134
+ if (this.closed) {
1135
+ throw this.closeError ?? new Error("the Nanocodex Agent Worker has been disposed");
1136
+ }
1137
+ }
1138
+
1139
+ fail(error) {
1140
+ if (this.closed) return;
1141
+ const onFailure = this.onFailure;
1142
+ this.onFailure = undefined;
1143
+ try { this.close(error); } catch (failure) { reportError(failure); }
1144
+ if (onFailure !== undefined) {
1145
+ try { onFailure(error); } catch (failure) { reportError(failure); }
1146
+ }
1147
+ }
1148
+
1149
+ close(error) {
1150
+ if (this.closed) return;
1151
+ this.closed = true;
1152
+ this.closeError = error;
1153
+ clearTimeout(this.heartbeatTimer);
1154
+ this.heartbeatTimer = undefined;
1155
+ this.heartbeatSequence = undefined;
1156
+ const worker = this.worker;
1157
+ for (const raw of this.rawAgents) raw.released = true;
1158
+ this.rawAgents.clear();
1159
+ this.agents = 0;
1160
+ try {
1161
+ disposeWorker(worker);
1162
+ } finally {
1163
+ for (const client of [...this.clients]) {
1164
+ try { client.dispose(); } catch (failure) { reportError(failure); }
1165
+ }
1166
+ this.clients.clear();
1167
+ this.clientByRaw.clear();
1168
+ for (const pending of this.pending.values()) pending.reject(error);
1169
+ this.pending.clear();
1170
+ this.listeners.clear();
1171
+ this.chunkedEvent = undefined;
1172
+ this.onFailure = undefined;
1173
+ }
1174
+ }
1175
+ }
1176
+
1177
+ async function connectionResult(connection, turnId) {
1178
+ const result = await connection.rpc("turn.result", [turnId]);
1179
+ if (!result || typeof result.finalMessage !== "string" || typeof result.resultId !== "string") {
1180
+ if (typeof result?.resultId === "string") {
1181
+ connection.sendBestEffort("result.dispose", [result.resultId]);
1182
+ }
1183
+ throw new TypeError("Nanocodex Agent Worker returned an invalid turn result handle");
1184
+ }
1185
+ let released = false;
1186
+ connection.adoptResult();
1187
+ return {
1188
+ connection,
1189
+ finalMessage: result.finalMessage,
1190
+ resultId: result.resultId,
1191
+ snapshot() {
1192
+ if (released) return Promise.reject(new Error("the Nanocodex turn result has been disposed"));
1193
+ return connection.rpc("result.snapshot", [result.resultId]);
1194
+ },
1195
+ usage() {
1196
+ if (released) return Promise.reject(new Error("the Nanocodex turn result has been disposed"));
1197
+ return connection.rpc("result.usage", [result.resultId]);
1198
+ },
1199
+ free() {
1200
+ if (released) return;
1201
+ released = true;
1202
+ connection.releaseResult(result.resultId);
1203
+ },
1204
+ };
1205
+ }
1206
+
1207
+ function createWorker(options) {
1208
+ const supplied = options.worker ?? options.workerFactory;
1209
+ if (supplied !== undefined) {
1210
+ const worker = typeof supplied === "function" ? supplied() : supplied;
1211
+ if (!worker || typeof worker.postMessage !== "function") throw new TypeError("worker must be Worker-like");
1212
+ return worker;
1213
+ }
1214
+ if (typeof Worker !== "function") throw new Error("this environment does not provide module Workers");
1215
+ return new Worker(new URL("./agent.worker.mjs", import.meta.url), { type: "module", name: "nanocodex-agent" });
1216
+ }
1217
+
1218
+ function claimWorker(harness, module, options) {
1219
+ options.signal?.throwIfAborted();
1220
+ if (options.worker !== undefined || options.workerFactory !== undefined) {
1221
+ return createWorker(options);
1222
+ }
1223
+ const entry = prewarmedWorker;
1224
+ if (
1225
+ !entry
1226
+ || entry.key !== harnessKey(harness)
1227
+ || entry.module !== module
1228
+ ) return createWorker(options);
1229
+ prewarmedWorker = undefined;
1230
+ return entry.claim(options.signal);
1231
+ }
1232
+
1233
+ function disposeWorker(worker) {
1234
+ const errors = [];
1235
+ for (const property of ["onmessage", "onerror", "onmessageerror"]) {
1236
+ try { worker[property] = null; } catch (error) { errors.push(error); }
1237
+ }
1238
+ try { worker.terminate?.(); } catch (error) { errors.push(error); }
1239
+ throwErrors(errors, "Nanocodex Agent Worker cleanup failed");
1240
+ }
1241
+
1242
+ function appendErrors(errors, error) {
1243
+ if (error instanceof AggregateError) errors.push(...error.errors);
1244
+ else errors.push(error);
1245
+ }
1246
+
1247
+ function throwErrors(errors, message) {
1248
+ if (errors.length === 1) throw errors[0];
1249
+ if (errors.length > 1) throw new AggregateError(errors, message);
1250
+ }
1251
+
1252
+ function abortable(promise, signal, abort) {
1253
+ if (signal === undefined) return promise;
1254
+ if (signal.aborted) {
1255
+ abort(signal.reason);
1256
+ return Promise.reject(signal.reason);
1257
+ }
1258
+ return new Promise((resolve, reject) => {
1259
+ let settled = false;
1260
+ let stopAbort = () => {};
1261
+ stopAbort = listenForAbort(signal, (error) => {
1262
+ abort(error);
1263
+ settle(reject, error);
1264
+ });
1265
+ Promise.resolve(promise).then(
1266
+ (value) => settle(resolve, value),
1267
+ (error) => settle(reject, error),
1268
+ );
1269
+
1270
+ function settle(complete, value) {
1271
+ if (settled) return;
1272
+ settled = true;
1273
+ stopAbort();
1274
+ complete(value);
1275
+ }
1276
+ });
1277
+ }
1278
+
1279
+ function listenForAbort(signal, listener) {
1280
+ if (signal === undefined) return () => {};
1281
+ let listening = true;
1282
+ const onAbort = () => {
1283
+ if (!listening) return;
1284
+ listening = false;
1285
+ signal.removeEventListener("abort", onAbort);
1286
+ listener(signal.reason);
1287
+ };
1288
+ if (signal.aborted) onAbort();
1289
+ else signal.addEventListener("abort", onAbort, { once: true });
1290
+ return () => {
1291
+ if (!listening) return;
1292
+ listening = false;
1293
+ signal.removeEventListener("abort", onAbort);
1294
+ };
1295
+ }
1296
+
1297
+ function serializeConfig(options) {
1298
+ const config = { ...options };
1299
+ if (typeof config.resolveCompactionInstruction === "function") {
1300
+ throw new TypeError(
1301
+ "resolveCompactionInstruction is supported in Node and current-isolate WASM hosts, not the default browser Worker API",
1302
+ );
1303
+ }
1304
+ const workerDurability = config.durability !== false;
1305
+ if (!workerDurability) delete config.durability;
1306
+ const stableThreadId = nonEmptyString(options.threadId) ?? nonEmptyString(options.sessionId);
1307
+ const transport = options.transport;
1308
+ if (transport !== undefined) {
1309
+ let setup;
1310
+ try {
1311
+ setup = resolveResponsesTransport(transport);
1312
+ } catch {
1313
+ throw new TypeError("Worker Agent requires a Nanocodex Responses transport");
1314
+ }
1315
+ if (setup.subscription !== undefined || setup.mpp !== undefined) {
1316
+ throw new TypeError("Worker Agent does not support function-backed ChatGPT or MPP transports");
1317
+ }
1318
+ const {
1319
+ apiKey,
1320
+ hostAuth,
1321
+ hostManagedProtocol: _hostManagedProtocol,
1322
+ ...connection
1323
+ } = setup;
1324
+ if (hostAuth === true) {
1325
+ if (typeof connection.createWebSocket === "function"
1326
+ || typeof connection.WebSocketImpl === "function") {
1327
+ throw new TypeError("Worker Agent host-managed transport callbacks must live inside a custom Worker");
1328
+ }
1329
+ config.transport = { kind: "host-managed", options: connection };
1330
+ } else {
1331
+ config.transport = { kind: "openai", options: { apiKey, ...connection } };
1332
+ }
1333
+ }
1334
+ if (config.harness !== false) {
1335
+ config.harness = harnessDescriptor(config);
1336
+ if (
1337
+ workerDurability
1338
+ && stableThreadId !== undefined
1339
+ && config.durability === undefined
1340
+ && config.durabilityId === undefined
1341
+ ) config.workerDurabilityId = stableThreadId;
1342
+ }
1343
+ delete config.accountConnectionRequests;
1344
+ delete config.threadId;
1345
+ assertNoFunctions(config, "Agent options");
1346
+ assertCloneable(config, "Agent options");
1347
+ return config;
1348
+ }
1349
+
1350
+ async function hydrateConfig(config, createDurabilityStore) {
1351
+ const { harness, workerDurabilityId, ...options } = config;
1352
+ const [Transport, harnessRuntime] = await Promise.all([
1353
+ import("./Transport.mjs"),
1354
+ harness === false || harness === undefined
1355
+ ? undefined
1356
+ : import("./harness.mjs").then(({ createBrowserHarness }) => createBrowserHarness({
1357
+ ...harness,
1358
+ web: { headers: { "x-nanocodex-request": "1" } },
1359
+ images: { headers: { "x-nanocodex-request": "1" } },
1360
+ recentImages: (sessionId, count) =>
1361
+ (recentImages.get(sessionId) ?? []).slice(-count),
1362
+ rememberImage: (sessionId, imageUrl) => {
1363
+ const images = recentImages.get(sessionId) ?? [];
1364
+ images.push(imageUrl);
1365
+ if (images.length > 5) images.splice(0, images.length - 5);
1366
+ recentImages.set(sessionId, images);
1367
+ },
1368
+ })),
1369
+ ]);
1370
+ if (options.transport?.kind === "openai") {
1371
+ options.transport = Transport.openAi(options.transport.options);
1372
+ } else if (options.transport?.kind === "host-managed") {
1373
+ options.transport = Transport.hostManaged(options.transport.options);
1374
+ }
1375
+ if (
1376
+ workerDurabilityId !== undefined
1377
+ && options.durability === undefined
1378
+ && options.durabilityId === undefined
1379
+ ) {
1380
+ if (typeof workerDurabilityId !== "string" || !workerDurabilityId) {
1381
+ throw new TypeError("Worker-owned durability requires a stable thread ID");
1382
+ }
1383
+ options.durability = await createDurabilityStore();
1384
+ options.durabilityId = workerDurabilityId;
1385
+ }
1386
+ if (harnessRuntime) {
1387
+ if ((options.model ?? "gpt-6-astra") === "gpt-6-astra" && options.instructions === undefined) {
1388
+ options.additionalInstructions = [
1389
+ harnessRuntime.instructions,
1390
+ options.additionalInstructions,
1391
+ ].filter((instructions) => instructions !== undefined && instructions !== "").join("\n\n");
1392
+ } else {
1393
+ options.instructions ??= harnessRuntime.instructions;
1394
+ }
1395
+ Object.assign(options, {
1396
+ codeEvaluator: harnessRuntime.codeEvaluator,
1397
+ filesystem: harnessRuntime.filesystem,
1398
+ filesystemTools: false,
1399
+ tools: harnessRuntime.tools,
1400
+ executionEnvironment: options.executionEnvironment ?? harnessRuntime.executionEnvironment,
1401
+ });
1402
+ }
1403
+ return options;
1404
+ }
1405
+
1406
+ async function loadAgent(options) {
1407
+ const Agent = await import("./InlineAgent.mjs");
1408
+ if (typeof Agent.create !== "function") {
1409
+ throw new Error("browser/InlineAgent.mjs must expose create(options) for the package Worker entry");
1410
+ }
1411
+ return Agent.create(options);
1412
+ }
1413
+
1414
+ /** @internal Starts independent Worker resources on the same critical path. */
1415
+ export async function prewarmWorkerRuntime(
1416
+ harness,
1417
+ {
1418
+ module,
1419
+ loadAgent = () => import("./InlineAgent.mjs"),
1420
+ loadBrowser = () => import("../tools/browser/index.mjs"),
1421
+ loadEngine = () => import("./engine.mjs"),
1422
+ } = {},
1423
+ ) {
1424
+ const resources = [
1425
+ loadEngine().then(({ initializeBrowserEngine }) => initializeBrowserEngine({ module })),
1426
+ loadAgent(),
1427
+ ];
1428
+ if (harness !== false) {
1429
+ resources.push(loadBrowser().then(({ prepareBrowser }) => prepareBrowser(harness)));
1430
+ }
1431
+ await Promise.all(resources);
1432
+ }
1433
+
1434
+ function assertNoFunctions(value, label, seen = new Set(), path = label) {
1435
+ if (typeof value === "function") throw new TypeError(`${path} cannot contain functions across the Worker boundary`);
1436
+ if (!value || typeof value !== "object" || seen.has(value)) return;
1437
+ if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) return;
1438
+ seen.add(value);
1439
+ for (const key of Reflect.ownKeys(value)) {
1440
+ if (typeof key === "symbol") continue;
1441
+ assertNoFunctions(value[key], label, seen, `${path}.${key}`);
1442
+ }
1443
+ }
1444
+
1445
+ function assertCloneable(value, label) {
1446
+ try { structuredClone(value); }
1447
+ catch (error) { throw new TypeError(`${label} must be structured-clone-safe`, { cause: error }); }
1448
+ }
1449
+
1450
+ function eventBytes(event, encoded) {
1451
+ return utf8ByteLength(encoded ?? JSON.stringify(event));
1452
+ }
1453
+ function positiveInteger(value, label) {
1454
+ if (!Number.isSafeInteger(value) || value <= 0) throw new TypeError(`${label} must be a positive safe integer`);
1455
+ return value;
1456
+ }
1457
+ function randomId() { return globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`; }
1458
+ function nonEmptyString(value) { return typeof value === "string" && value ? value : undefined; }
1459
+ function harnessDescriptor(options = {}, requireIdentity = false) {
1460
+ const threadId = nonEmptyString(options.threadId) ?? nonEmptyString(options.sessionId);
1461
+ if (requireIdentity && threadId === undefined) {
1462
+ throw new TypeError("preparing an Agent Worker requires a stable threadId or sessionId");
1463
+ }
1464
+ return {
1465
+ threadId: threadId ?? randomId(),
1466
+ origin: nonEmptyString(options.origin) ?? globalThis.location?.origin,
1467
+ ...(options.accountConnectionRequests === true ? { accountConnectionRequests: true } : {}),
1468
+ };
1469
+ }
1470
+ function harnessKey(harness) { return `${harness?.origin ?? ""}\n${harness?.threadId ?? ""}`; }
1471
+ function encodeError(error) { return { name: error?.name || "Error", message: error?.message || String(error), stack: error?.stack, ...(typeof error?.code === "string" ? { code: error.code } : {}), ...(typeof error?.blockedBy === "string" ? { blockedBy: error.blockedBy } : {}) }; }
1472
+ function decodeError(encoded = {}) { const error = encoded.name === "RangeError" ? new RangeError(encoded.message) : encoded.name === "TypeError" ? new TypeError(encoded.message) : new Error(encoded.message || "Worker Agent failed"); if (encoded.stack) error.stack = encoded.stack; if (typeof encoded.code === "string") error.code = encoded.code; if (typeof encoded.blockedBy === "string") error.blockedBy = encoded.blockedBy; return error; }