@swirls/looms 0.0.2 → 0.2.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 (375) hide show
  1. package/CHANGELOG.md +24 -2
  2. package/dist/actor/cell.d.ts +9 -4
  3. package/dist/actor/cell.js +7 -11
  4. package/dist/actor/host.d.ts +7 -3
  5. package/dist/actor/host.js +57 -33
  6. package/dist/actor/index.d.ts +1 -1
  7. package/dist/actor/index.js +1 -1
  8. package/dist/actor/routing.d.ts +12 -1
  9. package/dist/actor/routing.js +57 -51
  10. package/dist/agent/agent-session.d.ts +5 -0
  11. package/dist/agent/agent-session.js +270 -0
  12. package/dist/agent/debugger/agent-chat.d.ts +2 -0
  13. package/dist/agent/debugger/agent-chat.js +176 -0
  14. package/dist/agent/debugger/index.d.ts +5 -0
  15. package/dist/agent/debugger/index.js +19 -0
  16. package/dist/agent/debugger/summarize.d.ts +2 -0
  17. package/dist/agent/debugger/summarize.js +51 -0
  18. package/dist/agent/debugger/token-usage.d.ts +3 -0
  19. package/dist/agent/debugger/token-usage.js +11 -0
  20. package/dist/agent/definitions-store.d.ts +2 -3
  21. package/dist/agent/definitions-store.js +2 -4
  22. package/dist/agent/definitions.d.ts +47 -29
  23. package/dist/agent/definitions.js +39 -12
  24. package/dist/agent/effects.d.ts +359 -2
  25. package/dist/agent/effects.js +60 -34
  26. package/dist/agent/events.d.ts +175 -19
  27. package/dist/agent/events.js +45 -10
  28. package/dist/agent/index.d.ts +1 -0
  29. package/dist/agent/index.js +1 -0
  30. package/dist/agent/llm.d.ts +11 -2
  31. package/dist/agent/llm.js +13 -3
  32. package/dist/agent/module.d.ts +812 -78
  33. package/dist/agent/module.js +16 -4
  34. package/dist/agent/scope.d.ts +174 -18
  35. package/dist/agent/signals.d.ts +26 -1
  36. package/dist/agent/signals.js +79 -0
  37. package/dist/agent/threads.d.ts +3 -33
  38. package/dist/agent/threads.js +20 -25
  39. package/dist/agent/tool-schema.d.ts +1 -17
  40. package/dist/agent/tool-schema.js +3 -43
  41. package/dist/agent/types.d.ts +49 -4
  42. package/dist/agent/types.js +5 -5
  43. package/dist/ai-vercel/index.d.ts +1 -0
  44. package/dist/ai-vercel/index.js +1 -0
  45. package/dist/ai-vercel/messages.js +22 -7
  46. package/dist/ai-vercel/vercel-evaluator.d.ts +36 -0
  47. package/dist/ai-vercel/vercel-evaluator.js +73 -0
  48. package/dist/ai-vercel/vercel-llm.js +64 -44
  49. package/dist/approval/debugger/approvals-view.d.ts +3 -0
  50. package/dist/approval/debugger/approvals-view.js +16 -0
  51. package/dist/approval/debugger/index.d.ts +4 -0
  52. package/dist/approval/debugger/index.js +11 -0
  53. package/dist/approval/debugger/summarize.d.ts +2 -0
  54. package/dist/approval/debugger/summarize.js +17 -0
  55. package/dist/approval/effects.d.ts +89 -0
  56. package/dist/approval/module.d.ts +179 -29
  57. package/dist/approval/projections.d.ts +0 -14
  58. package/dist/approval/projections.js +20 -3
  59. package/dist/approval/signals.d.ts +2 -0
  60. package/dist/approval/signals.js +18 -2
  61. package/dist/cli/cli.js +2 -0
  62. package/dist/cli/commands.js +12 -16
  63. package/dist/client/client.d.ts +1213 -18
  64. package/dist/client/client.js +120 -120
  65. package/dist/client/index.d.ts +1 -1
  66. package/dist/client/index.js +1 -1
  67. package/dist/client/sse.d.ts +13 -0
  68. package/dist/client/sse.js +38 -44
  69. package/dist/cloudflare/alarm-scheduler.d.ts +12 -2
  70. package/dist/cloudflare/alarm-scheduler.js +34 -7
  71. package/dist/cloudflare/durable-object.d.ts +10 -2
  72. package/dist/cloudflare/durable-object.js +59 -28
  73. package/dist/cloudflare/event-store.d.ts +7 -2
  74. package/dist/cloudflare/event-store.js +8 -7
  75. package/dist/cloudflare/index.d.ts +2 -2
  76. package/dist/cloudflare/index.js +2 -2
  77. package/dist/cloudflare/router.d.ts +1 -1
  78. package/dist/cloudflare/router.js +15 -16
  79. package/dist/core/catalog.d.ts +3 -3
  80. package/dist/core/catalog.js +2 -5
  81. package/dist/core/coalesce.js +5 -3
  82. package/dist/core/compose.d.ts +2 -1
  83. package/dist/core/compose.js +19 -2
  84. package/dist/core/debugger-host.d.ts +16 -0
  85. package/dist/core/debugger-host.js +1 -0
  86. package/dist/core/definition-store.d.ts +11 -0
  87. package/dist/core/definition-store.js +6 -0
  88. package/dist/core/effects.d.ts +127 -15
  89. package/dist/core/effects.js +89 -17
  90. package/dist/core/envelope.d.ts +27 -7
  91. package/dist/core/envelope.js +20 -6
  92. package/dist/core/event-codec.d.ts +4 -2
  93. package/dist/core/event-codec.js +10 -5
  94. package/dist/core/event-index.js +1 -3
  95. package/dist/core/fold.d.ts +3 -0
  96. package/dist/core/fold.js +171 -24
  97. package/dist/core/ids.d.ts +5 -0
  98. package/dist/core/ids.js +35 -2
  99. package/dist/core/index.d.ts +7 -1
  100. package/dist/core/index.js +6 -1
  101. package/dist/core/kind.d.ts +22 -0
  102. package/dist/core/kind.js +17 -0
  103. package/dist/core/limits.d.ts +34 -0
  104. package/dist/core/limits.js +46 -0
  105. package/dist/core/match.d.ts +1 -0
  106. package/dist/core/match.js +10 -1
  107. package/dist/core/module-scope.d.ts +22 -20
  108. package/dist/core/module-scope.js +38 -28
  109. package/dist/core/module.d.ts +18 -5
  110. package/dist/core/module.js +4 -0
  111. package/dist/core/projection.d.ts +13 -13
  112. package/dist/core/projection.js +9 -5
  113. package/dist/core/protocol.d.ts +68 -11
  114. package/dist/core/protocol.js +82 -11
  115. package/dist/core/published.d.ts +43 -0
  116. package/dist/core/published.js +44 -0
  117. package/dist/core/replay.d.ts +312 -3
  118. package/dist/core/replay.js +11 -1
  119. package/dist/core/schema.d.ts +11 -20
  120. package/dist/core/schema.js +63 -80
  121. package/dist/core/serialize.js +2 -4
  122. package/dist/core/snapshot-store.d.ts +6 -1
  123. package/dist/core/snapshot-store.js +15 -2
  124. package/dist/core/snapshots.d.ts +5 -1
  125. package/dist/core/snapshots.js +10 -15
  126. package/dist/core/sqlite-store.js +95 -11
  127. package/dist/core/state.d.ts +142 -4
  128. package/dist/core/state.js +78 -0
  129. package/dist/core/store.d.ts +38 -3
  130. package/dist/core/store.js +77 -22
  131. package/dist/core/thread.d.ts +10 -9
  132. package/dist/core/types.d.ts +5 -8
  133. package/dist/core/types.js +28 -24
  134. package/dist/core/validate-event.js +14 -4
  135. package/dist/core/worker-callback.d.ts +17 -0
  136. package/dist/core/worker-callback.js +1 -0
  137. package/dist/debugger/app/assets/index-B3Ah8WAE.css +2 -0
  138. package/dist/debugger/app/assets/index-Qb371t_O.js +22 -0
  139. package/dist/debugger/app/assets/rolldown-runtime-CbXtAM7H.js +1 -0
  140. package/dist/debugger/app/assets/routes-CjtEHgPQ.js +47 -0
  141. package/dist/debugger/app/index.html +14 -0
  142. package/dist/debugger/components/composer.d.ts +17 -0
  143. package/dist/debugger/components/composer.js +25 -0
  144. package/dist/debugger/components/debugger-split.d.ts +2 -1
  145. package/dist/debugger/components/debugger-split.js +2 -2
  146. package/dist/debugger/components/event-inspector.d.ts +2 -1
  147. package/dist/debugger/components/event-inspector.js +25 -16
  148. package/dist/debugger/components/event-stream.d.ts +2 -1
  149. package/dist/debugger/components/event-stream.js +14 -74
  150. package/dist/debugger/components/follow-list.d.ts +19 -0
  151. package/dist/debugger/components/follow-list.js +96 -0
  152. package/dist/debugger/components/json-tree.d.ts +11 -0
  153. package/dist/debugger/components/json-tree.js +120 -0
  154. package/dist/debugger/components/json-view.js +2 -2
  155. package/dist/debugger/components/run-tree.js +53 -20
  156. package/dist/debugger/components/status-dot.d.ts +4 -0
  157. package/dist/debugger/components/status-dot.js +6 -2
  158. package/dist/debugger/context.d.ts +14 -0
  159. package/dist/debugger/context.js +17 -0
  160. package/dist/debugger/contracts.d.ts +7 -4
  161. package/dist/debugger/events/builtin-families.d.ts +3 -0
  162. package/dist/debugger/events/builtin-families.js +9 -0
  163. package/dist/debugger/events/catalog.d.ts +3 -4
  164. package/dist/debugger/events/catalog.js +27 -17
  165. package/dist/debugger/events/protocol-summarize.d.ts +1 -2
  166. package/dist/debugger/events/protocol-summarize.js +42 -24
  167. package/dist/debugger/index.d.ts +20 -6
  168. package/dist/debugger/index.js +19 -5
  169. package/dist/debugger/lib/cn.d.ts +1 -0
  170. package/dist/debugger/lib/cn.js +3 -0
  171. package/dist/debugger/lib/event-meta.d.ts +2 -3
  172. package/dist/debugger/lib/event-meta.js +6 -12
  173. package/dist/debugger/lib/json.d.ts +25 -0
  174. package/dist/debugger/lib/json.js +87 -0
  175. package/dist/debugger/lib/payload.d.ts +7 -0
  176. package/dist/debugger/lib/payload.js +11 -0
  177. package/dist/debugger/lib/time.d.ts +3 -0
  178. package/dist/debugger/lib/time.js +24 -0
  179. package/dist/debugger/plugin.d.ts +36 -0
  180. package/dist/debugger/plugin.js +14 -0
  181. package/dist/debugger/server/index.d.ts +14 -0
  182. package/dist/debugger/server/index.js +114 -0
  183. package/dist/debugger/shell/debugger-shell.d.ts +15 -0
  184. package/dist/debugger/shell/debugger-shell.js +43 -0
  185. package/dist/debugger/shell/definition-key.d.ts +3 -0
  186. package/dist/debugger/shell/definition-key.js +4 -0
  187. package/dist/debugger/shell/events-pane.d.ts +12 -0
  188. package/dist/debugger/shell/events-pane.js +25 -0
  189. package/dist/debugger/shell/projections-panel.d.ts +4 -0
  190. package/dist/debugger/shell/projections-panel.js +59 -0
  191. package/dist/debugger/shell/run-controls.d.ts +4 -0
  192. package/dist/debugger/shell/run-controls.js +72 -0
  193. package/dist/debugger/shell/run-search.d.ts +6 -0
  194. package/dist/debugger/shell/run-search.js +102 -0
  195. package/dist/debugger/shell/run-type-menu.d.ts +6 -0
  196. package/dist/debugger/shell/run-type-menu.js +11 -0
  197. package/dist/debugger/shell/schema-form.d.ts +31 -0
  198. package/dist/debugger/shell/schema-form.js +117 -0
  199. package/dist/debugger/shell/start-form.d.ts +3 -0
  200. package/dist/debugger/shell/start-form.js +75 -0
  201. package/dist/debugger/shell/use-start-run.d.ts +14 -0
  202. package/dist/debugger/shell/use-start-run.js +32 -0
  203. package/dist/debugger/shell/workspace.d.ts +6 -0
  204. package/dist/debugger/shell/workspace.js +15 -0
  205. package/dist/debugger/styles.css +111 -27
  206. package/dist/debugger/ui/button.d.ts +24 -0
  207. package/dist/debugger/ui/button.js +24 -0
  208. package/dist/debugger/ui/command.d.ts +9 -0
  209. package/dist/debugger/ui/command.js +24 -0
  210. package/dist/debugger/ui/dropdown-menu.d.ts +13 -0
  211. package/dist/debugger/ui/dropdown-menu.js +37 -0
  212. package/dist/debugger/ui/panel.d.ts +14 -0
  213. package/dist/debugger/ui/panel.js +16 -0
  214. package/dist/debugger/ui/popover.d.ts +7 -0
  215. package/dist/debugger/ui/popover.js +17 -0
  216. package/dist/debugger/ui/resizable.d.ts +7 -0
  217. package/dist/debugger/ui/resizable.js +14 -0
  218. package/dist/debugger/ui/scroll-area.d.ts +2 -1
  219. package/dist/debugger/ui/scroll-area.js +5 -3
  220. package/dist/debugger/ui/select.d.ts +10 -0
  221. package/dist/debugger/ui/select.js +21 -0
  222. package/dist/debugger/ui/tabs.js +2 -2
  223. package/dist/debugger/ui/textarea.d.ts +3 -0
  224. package/dist/debugger/ui/textarea.js +7 -0
  225. package/dist/evaluator/definitions-store.d.ts +11 -0
  226. package/dist/evaluator/definitions-store.js +8 -0
  227. package/dist/evaluator/definitions.d.ts +18 -0
  228. package/dist/evaluator/definitions.js +4 -0
  229. package/dist/evaluator/effects.d.ts +226 -0
  230. package/dist/evaluator/effects.js +132 -0
  231. package/dist/evaluator/evaluator.d.ts +24 -0
  232. package/dist/evaluator/evaluator.js +67 -0
  233. package/dist/evaluator/events.d.ts +59 -0
  234. package/dist/evaluator/events.js +21 -0
  235. package/dist/evaluator/index.d.ts +11 -0
  236. package/dist/evaluator/index.js +11 -0
  237. package/dist/evaluator/module.d.ts +606 -0
  238. package/dist/evaluator/module.js +25 -0
  239. package/dist/evaluator/projections.d.ts +50 -0
  240. package/dist/evaluator/projections.js +20 -0
  241. package/dist/evaluator/scope.d.ts +59 -0
  242. package/dist/evaluator/scope.js +7 -0
  243. package/dist/evaluator/signals.d.ts +3 -0
  244. package/dist/evaluator/signals.js +17 -0
  245. package/dist/evaluator/threads.d.ts +62 -0
  246. package/dist/evaluator/threads.js +117 -0
  247. package/dist/evaluator/types.d.ts +125 -0
  248. package/dist/evaluator/types.js +51 -0
  249. package/dist/projectors/delivery.d.ts +83 -0
  250. package/dist/projectors/delivery.js +182 -0
  251. package/dist/projectors/index-model.d.ts +1 -1
  252. package/dist/projectors/index-model.js +4 -6
  253. package/dist/projectors/index.d.ts +2 -0
  254. package/dist/projectors/index.js +2 -0
  255. package/dist/projectors/memory.d.ts +1 -1
  256. package/dist/projectors/memory.js +10 -8
  257. package/dist/projectors/postgres.js +44 -58
  258. package/dist/projectors/projector.d.ts +17 -0
  259. package/dist/projectors/projector.js +26 -1
  260. package/dist/projectors/sqlite-delivery.d.ts +4 -0
  261. package/dist/projectors/sqlite-delivery.js +147 -0
  262. package/dist/projectors/sqlite.js +23 -23
  263. package/dist/projectors/with-projectors.d.ts +7 -2
  264. package/dist/projectors/with-projectors.js +27 -28
  265. package/dist/react/notify.js +11 -8
  266. package/dist/react/react.d.ts +2 -3
  267. package/dist/react/react.js +14 -30
  268. package/dist/react/sse.d.ts +1 -1
  269. package/dist/react/sse.js +1 -1
  270. package/dist/react/store.d.ts +3 -3
  271. package/dist/react/store.js +109 -119
  272. package/dist/runtime/cancellation.d.ts +16 -0
  273. package/dist/runtime/cancellation.js +129 -0
  274. package/dist/runtime/deadline-transition-planner.d.ts +31 -0
  275. package/dist/runtime/deadline-transition-planner.js +139 -0
  276. package/dist/runtime/dispatch-effect.d.ts +3 -2
  277. package/dist/runtime/dispatch-effect.js +7 -13
  278. package/dist/runtime/errors.d.ts +51 -0
  279. package/dist/runtime/errors.js +39 -0
  280. package/dist/runtime/{runtime-helpers.d.ts → helpers.d.ts} +24 -4
  281. package/dist/runtime/{runtime-helpers.js → helpers.js} +56 -19
  282. package/dist/runtime/index.d.ts +3 -3
  283. package/dist/runtime/index.js +3 -3
  284. package/dist/runtime/ingress.d.ts +15 -0
  285. package/dist/runtime/ingress.js +42 -0
  286. package/dist/runtime/local-effect-executor.d.ts +21 -0
  287. package/dist/runtime/local-effect-executor.js +137 -0
  288. package/dist/runtime/looms.d.ts +30 -4
  289. package/dist/runtime/looms.js +57 -37
  290. package/dist/runtime/observer.d.ts +45 -0
  291. package/dist/runtime/observer.js +11 -0
  292. package/dist/runtime/repository.d.ts +55 -0
  293. package/dist/runtime/repository.js +293 -0
  294. package/dist/runtime/retry-policy.d.ts +16 -0
  295. package/dist/runtime/retry-policy.js +29 -0
  296. package/dist/runtime/run-execution-context.d.ts +30 -0
  297. package/dist/runtime/run-execution-context.js +56 -0
  298. package/dist/runtime/run-start.d.ts +4 -0
  299. package/dist/runtime/run-start.js +44 -0
  300. package/dist/runtime/runtime.d.ts +6 -87
  301. package/dist/runtime/runtime.js +248 -470
  302. package/dist/runtime/server/auth.d.ts +41 -0
  303. package/dist/runtime/server/auth.js +45 -0
  304. package/dist/runtime/server/debugger-host.d.ts +11 -0
  305. package/dist/runtime/server/debugger-host.js +32 -0
  306. package/dist/runtime/server/fetch-handler.d.ts +18 -0
  307. package/dist/runtime/server/fetch-handler.js +62 -0
  308. package/dist/runtime/server/http.d.ts +38 -0
  309. package/dist/runtime/server/http.js +66 -0
  310. package/dist/runtime/server/route-table.d.ts +55 -0
  311. package/dist/runtime/server/route-table.js +74 -0
  312. package/dist/runtime/server/routes/definitions.d.ts +3 -0
  313. package/dist/runtime/server/routes/definitions.js +20 -0
  314. package/dist/runtime/server/routes/effects.d.ts +3 -0
  315. package/dist/runtime/server/routes/effects.js +59 -0
  316. package/dist/runtime/server/routes/operations.d.ts +3 -0
  317. package/dist/runtime/server/routes/operations.js +14 -0
  318. package/dist/runtime/server/routes/runs.d.ts +3 -0
  319. package/dist/runtime/server/routes/runs.js +199 -0
  320. package/dist/runtime/server.d.ts +4 -8
  321. package/dist/runtime/server.js +6 -211
  322. package/dist/runtime/sse.d.ts +2 -1
  323. package/dist/runtime/sse.js +24 -17
  324. package/dist/runtime/types.d.ts +117 -0
  325. package/dist/runtime/types.js +1 -0
  326. package/dist/runtime/wake-engine.d.ts +20 -0
  327. package/dist/runtime/wake-engine.js +311 -0
  328. package/dist/runtime/wake-scheduler.d.ts +3 -4
  329. package/dist/runtime/wake-scheduler.js +25 -31
  330. package/dist/runtime/worker-callbacks.d.ts +16 -0
  331. package/dist/runtime/worker-callbacks.js +167 -0
  332. package/dist/runtime/worker-effect-dispatch.d.ts +36 -0
  333. package/dist/runtime/worker-effect-dispatch.js +126 -0
  334. package/dist/s2/config.d.ts +1 -1
  335. package/dist/s2/config.js +1 -1
  336. package/dist/s2/lite.js +70 -82
  337. package/dist/s2/pagination.d.ts +15 -0
  338. package/dist/s2/pagination.js +36 -0
  339. package/dist/s2/projector.js +6 -5
  340. package/dist/s2/snapshot-store.js +188 -161
  341. package/dist/s2/store.d.ts +3 -21
  342. package/dist/s2/store.js +71 -165
  343. package/dist/testing/index.d.ts +15 -0
  344. package/dist/testing/index.js +53 -16
  345. package/dist/workflow/debugger/index.d.ts +4 -0
  346. package/dist/workflow/debugger/index.js +11 -0
  347. package/dist/workflow/debugger/nodes-view.d.ts +3 -0
  348. package/dist/workflow/debugger/nodes-view.js +13 -0
  349. package/dist/workflow/debugger/summarize.d.ts +2 -0
  350. package/dist/workflow/debugger/summarize.js +30 -0
  351. package/dist/workflow/definitions-store.d.ts +2 -3
  352. package/dist/workflow/definitions-store.js +2 -2
  353. package/dist/workflow/definitions.d.ts +78 -22
  354. package/dist/workflow/definitions.js +80 -14
  355. package/dist/workflow/effects.d.ts +453 -107
  356. package/dist/workflow/effects.js +214 -115
  357. package/dist/workflow/events.d.ts +149 -5
  358. package/dist/workflow/events.js +27 -5
  359. package/dist/workflow/graph.d.ts +56 -0
  360. package/dist/workflow/graph.js +207 -0
  361. package/dist/workflow/index.d.ts +1 -0
  362. package/dist/workflow/index.js +1 -0
  363. package/dist/workflow/module.d.ts +1047 -266
  364. package/dist/workflow/projections.d.ts +14 -12
  365. package/dist/workflow/projections.js +30 -8
  366. package/dist/workflow/scope.d.ts +146 -4
  367. package/dist/workflow/threads.d.ts +383 -155
  368. package/dist/workflow/threads.js +308 -110
  369. package/package.json +26 -2
  370. package/dist/debugger/events/domain-summarize.d.ts +0 -3
  371. package/dist/debugger/events/domain-summarize.js +0 -107
  372. package/dist/debugger/events/family.d.ts +0 -8
  373. package/dist/debugger/events/family.js +0 -44
  374. package/dist/runtime/events-api.d.ts +0 -4
  375. package/dist/runtime/events-api.js +0 -84
@@ -1,8 +1,7 @@
1
1
  import { Predicate } from 'effect';
2
- import { createWaitId, emit, invoke, isWithdrawnError, parseEffectId, spawn, wait, } from '@swirls/looms/core';
2
+ import { createWaitId, DEFAULT_DEFINITION_VERSION, emit, invoke, isWithdrawnError, parseEffectId, spawn, wait, waitOutcome, } from '@swirls/looms/core';
3
3
  import { callLlmEffect, executeToolEffect } from './effects.js';
4
4
  import { agentModule } from './scope.js';
5
- import { AgentStateSchema } from './types.js';
6
5
  function inputToLine(input) {
7
6
  if (input === null) {
8
7
  return null;
@@ -44,9 +43,9 @@ function attachToolCall(lines, toolCall) {
44
43
  }
45
44
  export const agentThread = agentModule.thread({
46
45
  kind: 'agent',
47
- shape: AgentStateSchema,
48
46
  initialState: (ctx) => ({
49
47
  definitionName: ctx.definitionName,
48
+ definitionVersion: ctx.definitionVersion,
50
49
  lines: [],
51
50
  pendingToolCalls: [],
52
51
  executingToolCalls: [],
@@ -60,12 +59,14 @@ export const agentThread = agentModule.thread({
60
59
  input: ctx.input,
61
60
  output: null,
62
61
  pendingEffectTools: {},
62
+ consumedSteerMessageIds: [],
63
63
  }),
64
64
  step(state, event, ctx) {
65
65
  switch (event.type) {
66
66
  case 'runtime.thread.started': {
67
67
  const payload = event.payload;
68
68
  const defName = payload.definitionName || state.definitionName;
69
+ const defVersion = payload.definitionVersion ?? state.definitionVersion ?? DEFAULT_DEFINITION_VERSION;
69
70
  // SAFETY: event payload input is JSON
70
71
  const input = payload.input !== undefined ? payload.input : state.input;
71
72
  const line = inputToLine(input);
@@ -73,6 +74,7 @@ export const agentThread = agentModule.thread({
73
74
  return {
74
75
  ...state,
75
76
  definitionName: defName,
77
+ definitionVersion: defVersion,
76
78
  input,
77
79
  lines,
78
80
  needsLlmCall: true,
@@ -141,6 +143,10 @@ export const agentThread = agentModule.thread({
141
143
  case 'agent.steered': {
142
144
  const message = event.payload.message;
143
145
  const interrupt = event.payload.interrupt ?? false;
146
+ const messageId = event.payload.messageId;
147
+ const consumedSteerMessageIds = messageId && !state.consumedSteerMessageIds.includes(messageId)
148
+ ? [...state.consumedSteerMessageIds, messageId]
149
+ : state.consumedSteerMessageIds;
144
150
  if (interrupt) {
145
151
  return {
146
152
  ...state,
@@ -152,16 +158,18 @@ export const agentThread = agentModule.thread({
152
158
  pendingEffects: [],
153
159
  pendingEmits: [],
154
160
  needsLlmCall: true,
161
+ consumedSteerMessageIds,
155
162
  };
156
163
  }
157
164
  return {
158
165
  ...state,
159
166
  lines: [...state.lines, message],
160
167
  pendingSteer: message,
168
+ consumedSteerMessageIds,
161
169
  };
162
170
  }
163
171
  case 'agent.spawn.requested': {
164
- const { childThreadId, kind, definitionName, toolCallId, input } = event.payload;
172
+ const { childThreadId, kind, definitionName, definitionVersion, toolCallId, input } = event.payload;
165
173
  return {
166
174
  ...state,
167
175
  executingToolCalls: state.executingToolCalls.filter((item) => item.id !== toolCallId),
@@ -171,6 +179,7 @@ export const agentThread = agentModule.thread({
171
179
  childThreadId,
172
180
  kind,
173
181
  definitionName,
182
+ definitionVersion,
174
183
  toolCallId,
175
184
  // SAFETY: schema-decoded input is JSON
176
185
  input: input ?? null,
@@ -180,10 +189,7 @@ export const agentThread = agentModule.thread({
180
189
  }
181
190
  case 'agent.effects.requested': {
182
191
  const { toolCallId, effects: rawEffects, waitOn } = event.payload;
183
- // SAFETY: handler serialized RuntimeEffect values into the event payload.
184
- const effects = Array.isArray(rawEffects)
185
- ? [...rawEffects]
186
- : [];
192
+ const effects = Array.isArray(rawEffects) ? [...rawEffects] : [];
187
193
  const taggedEffects = effects.map((effect, idx) => {
188
194
  if (!('tag' in effect && Predicate.isString(effect.tag))) {
189
195
  return { ...effect, tag: `${toolCallId}_${effect.type}_${idx}` };
@@ -211,7 +217,6 @@ export const agentThread = agentModule.thread({
211
217
  waitOn: waitOn
212
218
  ? {
213
219
  type: waitOn.type,
214
- // SAFETY: schema-decoded match is JSON
215
220
  match: waitOn.match ?? undefined,
216
221
  }
217
222
  : undefined,
@@ -283,17 +288,9 @@ export const agentThread = agentModule.thread({
283
288
  if (!toolCallId) {
284
289
  return state;
285
290
  }
286
- const embedded = event.payload.event;
287
- const embeddedObj = Predicate.isObject(embedded) && Predicate.isObject(embedded.payload)
288
- ? embedded.payload
289
- : {};
290
291
  const threadId = ctx.threadId;
291
292
  const name = Predicate.isString(tag.name) ? tag.name : 'child';
292
- const error = Predicate.isString(embeddedObj.error) ? embeddedObj.error : null;
293
- // SAFETY: embedded output/payload is JSON
294
- const result = embeddedObj.output ??
295
- (Predicate.isObject(embedded) ? embedded.payload : null) ??
296
- null;
293
+ const { result, error } = waitOutcome(event.payload.event, tag);
297
294
  return {
298
295
  ...state,
299
296
  pendingSpawns: state.pendingSpawns.filter((item) => item.toolCallId !== toolCallId),
@@ -327,14 +324,17 @@ export const agentThread = agentModule.thread({
327
324
  effects.push(invoke(callLlmEffect, {
328
325
  turn: state.turn + 1,
329
326
  definitionName: state.definitionName,
327
+ definitionVersion: state.definitionVersion ?? DEFAULT_DEFINITION_VERSION,
330
328
  messages: state.lines,
331
329
  input: state.input,
330
+ consumedSteerMessageIds: state.consumedSteerMessageIds,
332
331
  }, `llm_turn_${state.turn + 1}`));
333
332
  }
334
333
  for (const toolCall of state.executingToolCalls) {
335
334
  effects.push(invoke(executeToolEffect, {
336
335
  turn: state.turn,
337
336
  definitionName: state.definitionName,
337
+ definitionVersion: state.definitionVersion ?? DEFAULT_DEFINITION_VERSION,
338
338
  toolCall,
339
339
  }, `tool_${toolCall.id}`));
340
340
  }
@@ -344,6 +344,7 @@ export const agentThread = agentModule.thread({
344
344
  childThreadId: spawnReq.childThreadId,
345
345
  kind: spawnReq.kind,
346
346
  definitionName: spawnReq.definitionName,
347
+ definitionVersion: spawnReq.definitionVersion,
347
348
  input: spawnReq.input,
348
349
  }), wait({
349
350
  waitId,
@@ -384,15 +385,9 @@ export function satisfiedToToolResult(event) {
384
385
  if (!toolCallId) {
385
386
  return null;
386
387
  }
387
- const embedded = event.payload.event;
388
- const embeddedPayload = Predicate.isObject(embedded) && Predicate.isObject(embedded.payload) ? embedded.payload : {};
389
388
  const threadId = event.threadId ?? null;
390
389
  const name = Predicate.isString(tag.name) ? tag.name : 'child';
391
- const error = Predicate.isString(embeddedPayload.error) ? embeddedPayload.error : null;
392
- // SAFETY: embedded output/payload is JSON
393
- const result = embeddedPayload.output ??
394
- (Predicate.isObject(embedded) ? embedded.payload : null) ??
395
- null;
390
+ const { result, error } = waitOutcome(event.payload.event, tag);
396
391
  return emit({
397
392
  type: 'agent.tool.result',
398
393
  payload: {
@@ -1,21 +1,5 @@
1
- import { Schema } from 'effect';
2
- import type { JsonValue, SchemaInput } from '@swirls/looms/core';
1
+ import { type JsonValue } from '@swirls/looms/core';
3
2
  import { type AgentToolEntry, type ToolLike } from './definitions';
4
3
  import type { LlmToolSpec } from './llm';
5
- interface StandardJsonSchemaConverter {
6
- readonly input: (options: {
7
- target: string;
8
- }) => JsonValue;
9
- }
10
- interface StandardJsonSchemaHolder {
11
- readonly '~standard': {
12
- readonly jsonSchema?: {
13
- readonly input?: StandardJsonSchemaConverter['input'];
14
- };
15
- };
16
- }
17
- type SchemaCandidate = SchemaInput | StandardJsonSchemaHolder | Schema.Codec<JsonValue>;
18
4
  export declare function toolJsonSchema(tool: ToolLike): JsonValue;
19
5
  export declare function toolSpecs(tools?: ReadonlyArray<AgentToolEntry>): LlmToolSpec[];
20
- export declare function jsonSchemaFromStandard(schema: SchemaCandidate | null | undefined): JsonValue;
21
- export {};
@@ -1,44 +1,7 @@
1
- import { Schema } from 'effect';
1
+ import { jsonSchemaOfInput } from '@swirls/looms/core';
2
2
  import { normalizeTools } from './definitions.js';
3
3
  const EMPTY_OBJECT_SCHEMA = { type: 'object' };
4
- function isStandardJsonSchemaHolder(value) {
5
- return '~standard' in value;
6
- }
7
- function fromStandardJsonSchema(schema) {
8
- if (!isStandardJsonSchemaHolder(schema)) {
9
- return undefined;
10
- }
11
- const input = schema['~standard'].jsonSchema?.input;
12
- if (!input) {
13
- return undefined;
14
- }
15
- try {
16
- return input({ target: 'draft-2020-12' });
17
- }
18
- catch {
19
- return undefined;
20
- }
21
- }
22
- function fromEffectSchema(schema) {
23
- if (!Schema.isSchema(schema)) {
24
- return undefined;
25
- }
26
- try {
27
- // SAFETY: Effect Schema values used as tool input codecs produce Standard JSON Schema.
28
- const standard = Schema.toStandardJSONSchemaV1(schema);
29
- return fromStandardJsonSchema(standard);
30
- }
31
- catch {
32
- return undefined;
33
- }
34
- }
35
- function fromInputCandidate(input) {
36
- if (!input) {
37
- return undefined;
38
- }
39
- return fromStandardJsonSchema(input) ?? fromEffectSchema(input);
40
- }
41
- function toolInputCandidate(tool) {
4
+ function toolInput(tool) {
42
5
  switch (tool.kind) {
43
6
  case 'function':
44
7
  return tool.input;
@@ -53,7 +16,7 @@ function toolInputCandidate(tool) {
53
16
  }
54
17
  }
55
18
  export function toolJsonSchema(tool) {
56
- return tool.inputSchema ?? fromInputCandidate(toolInputCandidate(tool)) ?? EMPTY_OBJECT_SCHEMA;
19
+ return jsonSchemaOfInput(toolInput(tool)) ?? EMPTY_OBJECT_SCHEMA;
57
20
  }
58
21
  export function toolSpecs(tools = []) {
59
22
  return normalizeTools(tools).map((tool) => ({
@@ -62,6 +25,3 @@ export function toolSpecs(tools = []) {
62
25
  inputJsonSchema: toolJsonSchema(tool),
63
26
  }));
64
27
  }
65
- export function jsonSchemaFromStandard(schema) {
66
- return fromInputCandidate(schema ?? undefined) ?? EMPTY_OBJECT_SCHEMA;
67
- }
@@ -1,5 +1,5 @@
1
1
  import { Schema } from 'effect';
2
- import type { EventInput, JsonValue, RuntimeEffect } from '@swirls/looms/core';
2
+ import { type EventInput, type JsonValue, type RuntimeEffect } from '@swirls/looms/core';
3
3
  export declare const ToolCallSchema: Schema.Struct<{
4
4
  readonly id: Schema.String;
5
5
  readonly name: Schema.String;
@@ -35,12 +35,13 @@ export declare const ConversationSchema: Schema.Struct<{
35
35
  }>;
36
36
  export type ConversationState = Schema.Schema.Type<typeof ConversationSchema>;
37
37
  export declare const TokenUsageSchema: Schema.Struct<{
38
- readonly input: Schema.Number;
39
- readonly output: Schema.Number;
38
+ readonly input: Schema.Finite;
39
+ readonly output: Schema.Finite;
40
40
  }>;
41
41
  export type TokenUsage = Schema.Schema.Type<typeof TokenUsageSchema>;
42
42
  export declare const ThreadStartedPayloadSchema: Schema.Struct<{
43
43
  readonly definitionName: Schema.optional<Schema.String>;
44
+ readonly definitionVersion: Schema.withDecodingDefaultKey<Schema.String, never>;
44
45
  readonly input: Schema.optional<Schema.Unknown>;
45
46
  }>;
46
47
  export interface PendingEffectTool {
@@ -51,6 +52,7 @@ export interface AgentPendingSpawn {
51
52
  readonly childThreadId: string;
52
53
  readonly kind: string;
53
54
  readonly definitionName: string;
55
+ readonly definitionVersion: string;
54
56
  readonly toolCallId: string;
55
57
  readonly input: JsonValue;
56
58
  }
@@ -68,6 +70,7 @@ export interface AgentPendingEmit {
68
70
  }
69
71
  export interface AgentState {
70
72
  definitionName?: string;
73
+ definitionVersion?: string;
71
74
  lines: Message[];
72
75
  pendingToolCalls: ToolCall[];
73
76
  executingToolCalls: ToolCall[];
@@ -83,5 +86,47 @@ export interface AgentState {
83
86
  pendingEffectTools: {
84
87
  [causingSeq: string]: PendingEffectTool;
85
88
  };
89
+ consumedSteerMessageIds: string[];
90
+ }
91
+ export type AgentMessageDelivery = 'steer' | 'followUp' | 'nextTurn';
92
+ export type AgentSessionTurnStatus = 'completed' | 'failed' | 'cancelled';
93
+ export interface AgentSessionMessage {
94
+ readonly messageId: string;
95
+ readonly text: string;
96
+ readonly delivery?: AgentMessageDelivery;
97
+ readonly steeredIntoMessageId?: string;
98
+ }
99
+ export interface AgentSessionActiveTurn {
100
+ readonly messageId: string;
101
+ readonly childThreadId: string;
102
+ readonly text: string;
103
+ }
104
+ export interface AgentSessionClosure {
105
+ readonly messageId: string;
106
+ readonly status: AgentSessionTurnStatus;
107
+ readonly error?: string;
108
+ }
109
+ export interface AgentSessionState {
110
+ readonly definitionName: string;
111
+ readonly definitionVersion: string;
112
+ readonly pendingMessages: AgentSessionMessage[];
113
+ readonly nextTurnMessages: AgentSessionMessage[];
114
+ readonly processedMessageIds: string[];
115
+ readonly activeTurn: AgentSessionActiveTurn | null;
116
+ readonly pendingSteerDeliveries: AgentSessionMessage[];
117
+ readonly pendingClosures: AgentSessionClosure[];
118
+ readonly lastSequence: number;
119
+ readonly idleTimeoutMs: number;
120
+ readonly idleDeadlineAt: number | null;
121
+ readonly parked: boolean;
122
+ readonly cancelling: boolean;
123
+ }
124
+ export interface AgentSessionSnapshot {
125
+ readonly activeTurnId: string | null;
126
+ readonly activeChildThreadId: string | null;
127
+ readonly pendingMessageCount: number;
128
+ readonly nextTurnHeldCount: number;
129
+ readonly processedMessageIds: readonly string[];
130
+ readonly lastSequence: number;
131
+ readonly parked: boolean;
86
132
  }
87
- export declare const AgentStateSchema: Schema.Schema<AgentState>;
@@ -1,4 +1,5 @@
1
- import { Schema } from 'effect';
1
+ import { Effect, Schema } from 'effect';
2
+ import { DEFAULT_DEFINITION_VERSION, } from '@swirls/looms/core';
2
3
  export const ToolCallSchema = Schema.Struct({
3
4
  id: Schema.String,
4
5
  name: Schema.String,
@@ -21,12 +22,11 @@ export const ConversationSchema = Schema.Struct({
21
22
  lines: Schema.mutable(Schema.Array(MessageSchema)),
22
23
  });
23
24
  export const TokenUsageSchema = Schema.Struct({
24
- input: Schema.Number,
25
- output: Schema.Number,
25
+ input: Schema.Finite,
26
+ output: Schema.Finite,
26
27
  });
27
28
  export const ThreadStartedPayloadSchema = Schema.Struct({
28
29
  definitionName: Schema.optional(Schema.String),
30
+ definitionVersion: Schema.String.pipe(Schema.withDecodingDefaultKey(Effect.succeed(DEFAULT_DEFINITION_VERSION))),
29
31
  input: Schema.optional(Schema.Unknown),
30
32
  });
31
- // SAFETY: AgentState is folded by reducers; Schema.Unknown is a typed placeholder, not a decoder.
32
- export const AgentStateSchema = Schema.Unknown;
@@ -1,2 +1,3 @@
1
1
  export { vercelLlm, type VercelLlmOptions } from './vercel-llm';
2
+ export { toEvaluatorAnswers, vercelEvaluator, type EvaluationModelProvider, type VercelEvaluatorOptions, } from './vercel-evaluator';
2
3
  export { toLoomsToolCalls, toModelMessages } from './messages';
@@ -1,2 +1,3 @@
1
1
  export { vercelLlm } from './vercel-llm.js';
2
+ export { toEvaluatorAnswers, vercelEvaluator, } from './vercel-evaluator.js';
2
3
  export { toLoomsToolCalls, toModelMessages } from './messages.js';
@@ -1,4 +1,22 @@
1
1
  import {} from 'ai';
2
+ import { Option, Predicate, Schema } from 'effect';
3
+ const decodeJson = Schema.decodeOption(Schema.fromJsonString(Schema.Json));
4
+ function toAiJson(value) {
5
+ if (value === null ||
6
+ Predicate.isString(value) ||
7
+ Predicate.isNumber(value) ||
8
+ Predicate.isBoolean(value)) {
9
+ return value;
10
+ }
11
+ if (Array.isArray(value)) {
12
+ return value.map(toAiJson);
13
+ }
14
+ const converted = {};
15
+ for (const [key, nested] of Object.entries(value)) {
16
+ converted[key] = toAiJson(nested);
17
+ }
18
+ return converted;
19
+ }
2
20
  export function toModelMessages(messages) {
3
21
  const converted = [];
4
22
  for (const message of messages) {
@@ -51,13 +69,10 @@ export function toModelMessages(messages) {
51
69
  return converted;
52
70
  }
53
71
  function parseToolOutput(content) {
54
- try {
55
- // SAFETY: tool message content is parsed JSON from JSON.parse.
56
- return { type: 'json', value: JSON.parse(content) };
57
- }
58
- catch {
59
- return { type: 'text', value: content };
60
- }
72
+ return Option.match(decodeJson(content), {
73
+ onNone: () => ({ type: 'text', value: content }),
74
+ onSome: (value) => ({ type: 'json', value: toAiJson(value) }),
75
+ });
61
76
  }
62
77
  export function toLoomsToolCalls(calls) {
63
78
  return calls.map((call) => ({
@@ -0,0 +1,36 @@
1
+ import { experimental_evaluate } from 'ai';
2
+ import type { EvaluatorAdapter, EvaluatorAnswers, EvaluatorQuestions } from '@swirls/looms/evaluator';
3
+ type EvaluateOptions = Parameters<typeof experimental_evaluate>[0];
4
+ type EvaluationModel = Exclude<EvaluateOptions['model'], string>;
5
+ /** An AI SDK provider with evaluation models, such as `createTypeSafeAi({ apiKey })`. */
6
+ export interface EvaluationModelProvider {
7
+ readonly evaluationModel: (modelId: string) => EvaluationModel;
8
+ }
9
+ interface VercelEvaluatorBaseOptions {
10
+ /** Abort the hosted call after this many milliseconds. Defaults to 2000. */
11
+ readonly timeoutMs?: number;
12
+ /** Defaults to AI Gateway zero data retention when no `provider` is set. */
13
+ readonly providerOptions?: EvaluateOptions['providerOptions'];
14
+ }
15
+ export type VercelEvaluatorOptions = VercelEvaluatorBaseOptions & ({
16
+ /** AI Gateway model id. Defaults to TypeSafe Jev (`typesafe-ai/jev`). */
17
+ readonly model?: string;
18
+ readonly provider?: undefined;
19
+ } | {
20
+ /** Default model id for `provider`. A definition's own `model` takes precedence. */
21
+ readonly model: string;
22
+ /** Resolves model ids with your own provider and key instead of the AI Gateway. */
23
+ readonly provider: EvaluationModelProvider;
24
+ });
25
+ interface EvaluateAnswer {
26
+ readonly type?: 'boolean' | 'choice' | 'score';
27
+ readonly probability?: number;
28
+ readonly choice?: string;
29
+ readonly score?: number;
30
+ }
31
+ /** Map `experimental_evaluate` answers onto evaluator answers. Boolean items only expose probability. */
32
+ export declare function toEvaluatorAnswers(questions: EvaluatorQuestions, raw: {
33
+ readonly [name: string]: EvaluateAnswer | undefined;
34
+ }): EvaluatorAnswers;
35
+ export declare function vercelEvaluator(options?: VercelEvaluatorOptions): EvaluatorAdapter;
36
+ export {};
@@ -0,0 +1,73 @@
1
+ import { experimental_evaluate } from 'ai';
2
+ import { Data, Effect, Predicate } from 'effect';
3
+ const DEFAULT_EVALUATOR_MODEL = 'typesafe-ai/jev';
4
+ class VercelEvaluatorError extends Data.TaggedError('VercelEvaluatorError') {
5
+ constructor(cause) {
6
+ super({
7
+ cause,
8
+ message: cause instanceof Error ? cause.message : String(cause),
9
+ });
10
+ this.name = 'VercelEvaluatorError';
11
+ }
12
+ }
13
+ function abortSignalFor(timeoutMs, parent) {
14
+ const timeout = AbortSignal.timeout(timeoutMs);
15
+ return parent ? AbortSignal.any([parent, timeout]) : timeout;
16
+ }
17
+ /** Map `experimental_evaluate` answers onto evaluator answers. Boolean items only expose probability. */
18
+ export function toEvaluatorAnswers(questions, raw) {
19
+ const answers = {};
20
+ for (const [name, question] of Object.entries(questions)) {
21
+ const item = raw[name];
22
+ if (question.type === 'boolean') {
23
+ const probability = Predicate.isNumber(item?.probability) ? item.probability : 0;
24
+ answers[name] = {
25
+ type: 'boolean',
26
+ value: probability >= 0.5,
27
+ probability,
28
+ };
29
+ continue;
30
+ }
31
+ if (question.type === 'choice') {
32
+ answers[name] = {
33
+ type: 'choice',
34
+ value: Predicate.isString(item?.choice) ? item.choice : '',
35
+ };
36
+ continue;
37
+ }
38
+ answers[name] = {
39
+ type: 'score',
40
+ value: Predicate.isNumber(item?.score) ? item.score : 0,
41
+ };
42
+ }
43
+ return answers;
44
+ }
45
+ export function vercelEvaluator(options = {}) {
46
+ const timeoutMs = options.timeoutMs ?? 2000;
47
+ const providerOptions = options.providerOptions ??
48
+ (options.provider ? undefined : { gateway: { zeroDataRetention: true } });
49
+ function resolveModel(modelId) {
50
+ const id = modelId ?? options.model ?? DEFAULT_EVALUATOR_MODEL;
51
+ return options.provider ? options.provider.evaluationModel(id) : id;
52
+ }
53
+ return {
54
+ evaluate: (args) => Effect.runPromise(Effect.tryPromise({
55
+ try: () => experimental_evaluate({
56
+ model: resolveModel(args.model),
57
+ state: args.state,
58
+ abortSignal: abortSignalFor(timeoutMs, args.signal),
59
+ maxRetries: 0,
60
+ providerOptions,
61
+ questions: args.questions,
62
+ }),
63
+ catch: (cause) => new VercelEvaluatorError(cause),
64
+ }).pipe(Effect.map((result) => ({
65
+ answers: toEvaluatorAnswers(args.questions, result.answers),
66
+ usage: {
67
+ input: result.usage.inputTokens ?? 0,
68
+ output: result.usage.outputTokens ?? 0,
69
+ },
70
+ raw: result,
71
+ })))),
72
+ };
73
+ }
@@ -1,36 +1,51 @@
1
- import { generateText, jsonSchema, streamText, tool } from 'ai';
1
+ import { generateText, jsonSchema, streamText, tool, } from 'ai';
2
+ import { Data, Effect, Option, Predicate, Stream } from 'effect';
3
+ import { asJson } from '@swirls/looms/core';
2
4
  import { toLoomsToolCalls, toModelMessages } from './messages.js';
5
+ class VercelLlmError extends Data.TaggedError('VercelLlmError') {
6
+ constructor(cause) {
7
+ super({
8
+ cause,
9
+ message: cause instanceof Error ? cause.message : String(cause),
10
+ });
11
+ this.name = 'VercelLlmError';
12
+ }
13
+ }
14
+ function isJsonSchema(value) {
15
+ return Predicate.isReadonlyObject(value) && !Array.isArray(value);
16
+ }
3
17
  function toAiTools(specs) {
4
- return Object.fromEntries(specs.map((spec) => [
5
- spec.name,
6
- tool({
7
- description: spec.description,
8
- // SAFETY: LlmToolSpec.inputJsonSchema is JSON Schema produced by toolJsonSchema.
9
- inputSchema: jsonSchema(spec.inputJsonSchema),
10
- }),
11
- ]));
18
+ return Object.fromEntries(specs.map((spec) => {
19
+ if (!isJsonSchema(spec.inputJsonSchema)) {
20
+ throw new VercelLlmError(`Invalid JSON Schema for tool "${spec.name}"`);
21
+ }
22
+ return [
23
+ spec.name,
24
+ tool({
25
+ description: spec.description,
26
+ inputSchema: jsonSchema(spec.inputJsonSchema),
27
+ }),
28
+ ];
29
+ }));
12
30
  }
13
31
  function toolCallInput(call) {
14
32
  const input = 'input' in call ? call.input : {};
15
- // SAFETY: AI SDK tool-call input is JSON produced by the model against our schema.
16
- return (input ?? {});
33
+ return asJson(input ?? {});
17
34
  }
18
35
  export function vercelLlm(options) {
19
36
  const streamEnabled = options.stream !== false;
20
37
  return {
21
- async complete(args) {
38
+ complete: (args) => Effect.runPromise(Effect.gen(function* () {
22
39
  const messages = toModelMessages(args.messages);
23
40
  const tools = args.toolSpecs && args.toolSpecs.length > 0 ? toAiTools(args.toolSpecs) : undefined;
24
- const shouldStream = streamEnabled && args.onTextDelta !== undefined;
25
- if (shouldStream) {
41
+ if (streamEnabled && args.onTextDelta) {
26
42
  const result = tools
27
43
  ? streamText({
28
44
  model: options.model,
29
45
  instructions: args.instructions,
30
46
  messages,
31
47
  abortSignal: args.signal,
32
- // SAFETY: VercelAiTool values are `tool()` instances from the AI SDK.
33
- tools: tools,
48
+ tools,
34
49
  })
35
50
  : streamText({
36
51
  model: options.model,
@@ -38,16 +53,21 @@ export function vercelLlm(options) {
38
53
  messages,
39
54
  abortSignal: args.signal,
40
55
  });
41
- for await (const part of result.fullStream) {
42
- if (part.type === 'text-delta') {
43
- const delta = 'text' in part ? part.text : '';
44
- if (delta) {
45
- await args.onTextDelta?.(delta);
46
- }
47
- }
48
- }
49
- try {
50
- const [text, rawToolCalls] = await Promise.all([result.text, result.toolCalls]);
56
+ yield* Stream.fromAsyncIterable(result.fullStream, (cause) => new VercelLlmError(cause)).pipe(Stream.runForEach((part) => {
57
+ const delta = part.type === 'text-delta' && 'text' in part ? part.text : '';
58
+ return delta
59
+ ? Effect.tryPromise({
60
+ try: () => Promise.resolve(args.onTextDelta?.(delta)),
61
+ catch: (cause) => new VercelLlmError(cause),
62
+ })
63
+ : Effect.void;
64
+ }));
65
+ const streamed = yield* Effect.tryPromise({
66
+ try: () => Promise.all([result.text, result.toolCalls]),
67
+ catch: (cause) => new VercelLlmError(cause),
68
+ }).pipe(Effect.asSome, Effect.catchIf((error) => error.message.includes('No output generated'), () => Effect.succeedNone));
69
+ if (Option.isSome(streamed)) {
70
+ const [text, rawToolCalls] = streamed.value;
51
71
  const toolCalls = toLoomsToolCalls(rawToolCalls.map((call) => ({
52
72
  toolCallId: call.toolCallId,
53
73
  toolName: call.toolName,
@@ -59,26 +79,26 @@ export function vercelLlm(options) {
59
79
  usage: { input: 0, output: text.length },
60
80
  };
61
81
  }
62
- catch (err) {
63
- if (!(err instanceof Error) || !err.message.includes('No output generated')) {
64
- throw err;
65
- }
66
- }
67
82
  }
68
83
  const result = tools
69
- ? await generateText({
70
- model: options.model,
71
- instructions: args.instructions,
72
- messages,
73
- abortSignal: args.signal,
74
- // SAFETY: VercelAiTool values are `tool()` instances from the AI SDK.
75
- tools: tools,
84
+ ? yield* Effect.tryPromise({
85
+ try: () => generateText({
86
+ model: options.model,
87
+ instructions: args.instructions,
88
+ messages,
89
+ abortSignal: args.signal,
90
+ tools,
91
+ }),
92
+ catch: (cause) => new VercelLlmError(cause),
76
93
  })
77
- : await generateText({
78
- model: options.model,
79
- instructions: args.instructions,
80
- messages,
81
- abortSignal: args.signal,
94
+ : yield* Effect.tryPromise({
95
+ try: () => generateText({
96
+ model: options.model,
97
+ instructions: args.instructions,
98
+ messages,
99
+ abortSignal: args.signal,
100
+ }),
101
+ catch: (cause) => new VercelLlmError(cause),
82
102
  });
83
103
  const toolCalls = toLoomsToolCalls(result.toolCalls.map((call) => ({
84
104
  toolCallId: call.toolCallId,
@@ -93,6 +113,6 @@ export function vercelLlm(options) {
93
113
  output: result.usage?.outputTokens ?? result.text.length,
94
114
  },
95
115
  };
96
- },
116
+ })),
97
117
  };
98
118
  }