@xopcai/xopc 0.0.84 → 0.0.85

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 (410) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  3. package/dist/extensions/feishu/src/plugin.d.ts +2 -0
  4. package/dist/extensions/feishu/src/plugin.js +10 -0
  5. package/dist/extensions/feishu/src/plugin.js.map +1 -1
  6. package/dist/extensions/feishu/src/workflow-progress.d.ts +27 -0
  7. package/dist/extensions/feishu/src/workflow-progress.js +99 -0
  8. package/dist/extensions/feishu/src/workflow-progress.js.map +1 -0
  9. package/dist/extensions/telegram/src/plugin.d.ts +2 -0
  10. package/dist/extensions/telegram/src/plugin.js +11 -1
  11. package/dist/extensions/telegram/src/plugin.js.map +1 -1
  12. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  13. package/dist/extensions/telegram/src/workflow-progress.d.ts +24 -0
  14. package/dist/extensions/telegram/src/workflow-progress.js +73 -0
  15. package/dist/extensions/telegram/src/workflow-progress.js.map +1 -0
  16. package/dist/extensions/telegram/xopc.extension.json +1 -1
  17. package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js +158 -0
  18. package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js.map +1 -0
  19. package/dist/extensions/weixin/src/api/api.js +2 -2
  20. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  21. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  22. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  23. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  24. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  25. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  26. package/dist/extensions/weixin/src/plugin.d.ts +2 -0
  27. package/dist/extensions/weixin/src/plugin.js +11 -1
  28. package/dist/extensions/weixin/src/plugin.js.map +1 -1
  29. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  30. package/dist/extensions/weixin/src/workflow-progress.d.ts +26 -0
  31. package/dist/extensions/weixin/src/workflow-progress.js +99 -0
  32. package/dist/extensions/weixin/src/workflow-progress.js.map +1 -0
  33. package/dist/gateway/static/root/assets/agents-D3_-kNlZ.js +222 -0
  34. package/dist/gateway/static/root/assets/apps-page-D7v7649T.js +1 -0
  35. package/dist/gateway/static/root/assets/channels-settings-nCaMb0a7.js +1 -0
  36. package/dist/gateway/static/root/assets/channels-status-swr-C1gZBcJV.js +8 -0
  37. package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +1 -0
  38. package/dist/gateway/static/root/assets/cron-api-CoYK0hlm.js +1 -0
  39. package/dist/gateway/static/root/assets/cron-page-DeGo-Vjc.js +1 -0
  40. package/dist/gateway/static/root/assets/dist-BTWC-BTN.js +45 -0
  41. package/dist/gateway/static/root/assets/{dist-CqNMNhJM.js → dist-DaK4dsss.js} +1 -1
  42. package/dist/gateway/static/root/assets/{extension-debug-page-gf2L0kY_.js → extension-debug-page-BZngZWbO.js} +1 -1
  43. package/dist/gateway/static/root/assets/extension-page-D6JSyV27.js +1 -0
  44. package/dist/gateway/static/root/assets/extension-settings-page-8PZcmWI7.js +1 -0
  45. package/dist/gateway/static/root/assets/fetch-B2MYHbWg.js +1 -0
  46. package/dist/gateway/static/root/assets/{field-primitives-DTtlp-l8.js → field-primitives-Zzl22MvN.js} +1 -1
  47. package/dist/gateway/static/root/assets/heartbeat-config-api-BtIcpG0O.js +1 -0
  48. package/dist/gateway/static/root/assets/index-D4vM3-P7.js +4700 -0
  49. package/dist/gateway/static/root/assets/index-ew_2L2We.css +1 -0
  50. package/dist/gateway/static/root/assets/logs-page-_d4UJ-qQ.js +1 -0
  51. package/dist/gateway/static/root/assets/sessions-page-5N4aF2Wk.js +1 -0
  52. package/dist/gateway/static/root/assets/settings-form-section-D_tgb8r2.js +1 -0
  53. package/dist/gateway/static/root/assets/settings-page-C18xBt4X.js +3 -0
  54. package/dist/gateway/static/root/assets/share-preview-page-D4EG_vM1.js +2 -0
  55. package/dist/gateway/static/root/assets/skills-page-sPAXhh8w.js +2 -0
  56. package/dist/gateway/static/root/assets/theme-store-DryYl3qD.js +1 -0
  57. package/dist/gateway/static/root/assets/url-BwNL6Rgk.js +3 -0
  58. package/dist/gateway/static/root/assets/utils-CYO9eTCM.js +1 -0
  59. package/dist/gateway/static/root/assets/voice-api-key-field-Ds51havm.js +1 -0
  60. package/dist/gateway/static/root/index.html +7 -6
  61. package/dist/package.js +1 -1
  62. package/dist/src/agent/agent-manager.js +7 -7
  63. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  64. package/dist/src/agent/context/workspace-seed.js +3 -3
  65. package/dist/src/agent/embedded/map-stream-events.js +6 -0
  66. package/dist/src/agent/embedded/map-stream-events.js.map +1 -1
  67. package/dist/src/agent/embedded/subscribe-session.js +24 -0
  68. package/dist/src/agent/embedded/subscribe-session.js.map +1 -1
  69. package/dist/src/agent/embedded/types.d.ts +19 -0
  70. package/dist/src/agent/goals/goal-locale.js +2 -2
  71. package/dist/src/agent/goals/goal-run-store.js +4 -4
  72. package/dist/src/agent/goals/persistent-goal-service.js +1 -1
  73. package/dist/src/agent/goals/post-turn.js +2 -2
  74. package/dist/src/agent/image/load-image-media.js +2 -2
  75. package/dist/src/agent/ipc/bus.js +1 -1
  76. package/dist/src/agent/ipc/inbox.js +2 -2
  77. package/dist/src/agent/ipc/socket.js +1 -1
  78. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  79. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  80. package/dist/src/agent/memory/dreaming/events.js +1 -1
  81. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  82. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  83. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  84. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  85. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  86. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  87. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  88. package/dist/src/agent/models/manager.js +1 -1
  89. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  90. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  91. package/dist/src/agent/reply/startup-context.d.ts +3 -0
  92. package/dist/src/agent/reply/startup-context.js +25 -2
  93. package/dist/src/agent/reply/startup-context.js.map +1 -1
  94. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  95. package/dist/src/agent/sandbox/path-policy.js +2 -2
  96. package/dist/src/agent/service/build-direct-message-content.js +1 -1
  97. package/dist/src/agent/service.d.ts +1 -0
  98. package/dist/src/agent/service.js +10 -4
  99. package/dist/src/agent/service.js.map +1 -1
  100. package/dist/src/agent/session/session-inspector.js +1 -1
  101. package/dist/src/agent/skills/config.js +1 -1
  102. package/dist/src/agent/skills/hub-hash.js +2 -2
  103. package/dist/src/agent/skills/hub-lock.js +1 -1
  104. package/dist/src/agent/skills/hub-pull.js +3 -3
  105. package/dist/src/agent/skills/index.js +1 -1
  106. package/dist/src/agent/skills/managed-store.js +1 -1
  107. package/dist/src/agent/skills/scanner.js +1 -1
  108. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  109. package/dist/src/agent/skills/skill-manager.js +1 -1
  110. package/dist/src/agent/tools/create-share-tool.d.ts +27 -0
  111. package/dist/src/agent/tools/create-share-tool.js +237 -0
  112. package/dist/src/agent/tools/create-share-tool.js.map +1 -0
  113. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  114. package/dist/src/agent/tools/factory.js +35 -1
  115. package/dist/src/agent/tools/factory.js.map +1 -1
  116. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  117. package/dist/src/agent/tools/index.d.ts +2 -0
  118. package/dist/src/agent/tools/index.js +3 -1
  119. package/dist/src/agent/tools/send-media.js +1 -1
  120. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  121. package/dist/src/agent/tools/workflow-tool.d.ts +41 -0
  122. package/dist/src/agent/tools/workflow-tool.js +271 -0
  123. package/dist/src/agent/tools/workflow-tool.js.map +1 -0
  124. package/dist/src/agent/tools/write.js +1 -1
  125. package/dist/src/agent/workflow/builtins/audit-repo.d.ts +9 -0
  126. package/dist/src/agent/workflow/builtins/audit-repo.js +115 -0
  127. package/dist/src/agent/workflow/builtins/audit-repo.js.map +1 -0
  128. package/dist/src/agent/workflow/builtins/index.d.ts +15 -0
  129. package/dist/src/agent/workflow/builtins/index.js +28 -0
  130. package/dist/src/agent/workflow/builtins/index.js.map +1 -0
  131. package/dist/src/agent/workflow/builtins/multi-perspective-review.d.ts +9 -0
  132. package/dist/src/agent/workflow/builtins/multi-perspective-review.js +113 -0
  133. package/dist/src/agent/workflow/builtins/multi-perspective-review.js.map +1 -0
  134. package/dist/src/agent/workflow/builtins/research.d.ts +9 -0
  135. package/dist/src/agent/workflow/builtins/research.js +129 -0
  136. package/dist/src/agent/workflow/builtins/research.js.map +1 -0
  137. package/dist/src/agent/workflow/catalog.d.ts +51 -0
  138. package/dist/src/agent/workflow/catalog.js +155 -0
  139. package/dist/src/agent/workflow/catalog.js.map +1 -0
  140. package/dist/src/agent/workflow/channel-capability.d.ts +76 -0
  141. package/dist/src/agent/workflow/channel-capability.js +1 -0
  142. package/dist/src/agent/workflow/index.d.ts +11 -0
  143. package/dist/src/agent/workflow/index.js +10 -0
  144. package/dist/src/agent/workflow/last-run-memory.d.ts +42 -0
  145. package/dist/src/agent/workflow/last-run-memory.js +60 -0
  146. package/dist/src/agent/workflow/last-run-memory.js.map +1 -0
  147. package/dist/src/agent/workflow/parser.d.ts +20 -0
  148. package/dist/src/agent/workflow/parser.js +137 -0
  149. package/dist/src/agent/workflow/parser.js.map +1 -0
  150. package/dist/src/agent/workflow/progress-broker.d.ts +80 -0
  151. package/dist/src/agent/workflow/progress-broker.js +263 -0
  152. package/dist/src/agent/workflow/progress-broker.js.map +1 -0
  153. package/dist/src/agent/workflow/runtime.d.ts +31 -0
  154. package/dist/src/agent/workflow/runtime.js +301 -0
  155. package/dist/src/agent/workflow/runtime.js.map +1 -0
  156. package/dist/src/agent/workflow/snapshot.d.ts +18 -0
  157. package/dist/src/agent/workflow/snapshot.js +144 -0
  158. package/dist/src/agent/workflow/snapshot.js.map +1 -0
  159. package/dist/src/agent/workflow/structured-output-tool.d.ts +33 -0
  160. package/dist/src/agent/workflow/structured-output-tool.js +58 -0
  161. package/dist/src/agent/workflow/structured-output-tool.js.map +1 -0
  162. package/dist/src/agent/workflow/subagent-runner.d.ts +42 -0
  163. package/dist/src/agent/workflow/subagent-runner.js +104 -0
  164. package/dist/src/agent/workflow/subagent-runner.js.map +1 -0
  165. package/dist/src/agent/workflow/types.d.ts +137 -0
  166. package/dist/src/agent/workflow/types.js +1 -0
  167. package/dist/src/auth/credentials.js +3 -3
  168. package/dist/src/auth/profiles/store.js +1 -1
  169. package/dist/src/auth/sync-provider-auth.js +1 -1
  170. package/dist/src/browser/cache-dir-policy.js +1 -1
  171. package/dist/src/browser/cdp-local-launcher.js +2 -2
  172. package/dist/src/browser/providers/browser-ext-install.js +4 -4
  173. package/dist/src/browser/providers/cloakbrowser.js +4 -4
  174. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  175. package/dist/src/browser/stealth.js +1 -1
  176. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  177. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  178. package/dist/src/channels/outbound/persist-store.js +1 -1
  179. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  180. package/dist/src/channels/pairing/pairing-store.js +2 -2
  181. package/dist/src/chat-commands/builtins/config.js +2 -2
  182. package/dist/src/chat-commands/builtins/model.js +40 -23
  183. package/dist/src/chat-commands/builtins/model.js.map +1 -1
  184. package/dist/src/chat-commands/builtins/system.js +30 -15
  185. package/dist/src/chat-commands/builtins/system.js.map +1 -1
  186. package/dist/src/chat-commands/builtins/workflow.d.ts +18 -0
  187. package/dist/src/chat-commands/builtins/workflow.js +167 -0
  188. package/dist/src/chat-commands/builtins/workflow.js.map +1 -0
  189. package/dist/src/chat-commands/context.js +1 -1
  190. package/dist/src/chat-commands/format-output.d.ts +28 -0
  191. package/dist/src/chat-commands/format-output.js +45 -0
  192. package/dist/src/chat-commands/format-output.js.map +1 -0
  193. package/dist/src/chat-commands/index.d.ts +1 -0
  194. package/dist/src/chat-commands/index.js +3 -1
  195. package/dist/src/chat-commands/index.js.map +1 -1
  196. package/dist/src/cli/commands/config.js +2 -2
  197. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  198. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  199. package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
  200. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  201. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  202. package/dist/src/cli/commands/extension-dev.js +1 -1
  203. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  204. package/dist/src/cli/commands/extension-pack.js +1 -1
  205. package/dist/src/cli/commands/gateway/lifecycle.js +10 -4
  206. package/dist/src/cli/commands/gateway/lifecycle.js.map +1 -1
  207. package/dist/src/cli/commands/gateway/shared.js +1 -1
  208. package/dist/src/cli/commands/image.js +1 -1
  209. package/dist/src/cli/commands/init.js +4 -4
  210. package/dist/src/cli/commands/onboard.js +2 -2
  211. package/dist/src/cli/commands/tunnel.js +2 -2
  212. package/dist/src/cli/utils/gateway-client.js +1 -1
  213. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  214. package/dist/src/config/agent-profile.js +1 -1
  215. package/dist/src/config/gateway-bind.js +1 -1
  216. package/dist/src/config/index.js +5 -5
  217. package/dist/src/config/loader.js +2 -2
  218. package/dist/src/config/models-json.js +2 -2
  219. package/dist/src/config/paths-state.js +1 -1
  220. package/dist/src/config/profile.js +2 -2
  221. package/dist/src/config/public-url.d.ts +28 -0
  222. package/dist/src/config/public-url.js +103 -0
  223. package/dist/src/config/public-url.js.map +1 -0
  224. package/dist/src/config/schema.d.ts +82 -0
  225. package/dist/src/config/schema.js +130 -1
  226. package/dist/src/config/schema.js.map +1 -1
  227. package/dist/src/config/workspace-path.js +1 -1
  228. package/dist/src/cron/executor.js +2 -2
  229. package/dist/src/cron/persistence.js +1 -1
  230. package/dist/src/cron/run-log-store.js +1 -1
  231. package/dist/src/daemon/constants.js +1 -1
  232. package/dist/src/daemon/install-plan.js +3 -3
  233. package/dist/src/daemon/install-plan.js.map +1 -1
  234. package/dist/src/daemon/launchd.js +2 -2
  235. package/dist/src/daemon/schtasks.js +38 -1
  236. package/dist/src/daemon/schtasks.js.map +1 -1
  237. package/dist/src/daemon/systemd.js +2 -2
  238. package/dist/src/extensions/bundle-mcp.js +1 -1
  239. package/dist/src/extensions/discover-extensions.js +1 -1
  240. package/dist/src/extensions/health.js +1 -1
  241. package/dist/src/extensions/loader.js +1 -1
  242. package/dist/src/extensions/lockfile.js +2 -2
  243. package/dist/src/gateway/agents-admin.js +2 -2
  244. package/dist/src/gateway/file-path-classifier.js +2 -2
  245. package/dist/src/gateway/hono/app.js +33 -2
  246. package/dist/src/gateway/hono/app.js.map +1 -1
  247. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  248. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  249. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  250. package/dist/src/gateway/hono/oauth.js +1 -1
  251. package/dist/src/gateway/hono/routes/agents.js +1 -1
  252. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  253. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  254. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  255. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  256. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  257. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  258. package/dist/src/gateway/hono/routes/models.js +1 -1
  259. package/dist/src/gateway/hono/routes/shares.js +631 -34
  260. package/dist/src/gateway/hono/routes/shares.js.map +1 -1
  261. package/dist/src/gateway/hono/routes/site-shares.d.ts +3 -0
  262. package/dist/src/gateway/hono/routes/site-shares.js +228 -0
  263. package/dist/src/gateway/hono/routes/site-shares.js.map +1 -0
  264. package/dist/src/gateway/hono/routes/tunnel.js +97 -8
  265. package/dist/src/gateway/hono/routes/tunnel.js.map +1 -1
  266. package/dist/src/gateway/hono/routes/workspace.js +5 -5
  267. package/dist/src/gateway/hono/sse.js +2 -2
  268. package/dist/src/gateway/host.d.ts +3 -1
  269. package/dist/src/gateway/host.js +3 -1
  270. package/dist/src/gateway/host.js.map +1 -1
  271. package/dist/src/gateway/lock.js +3 -3
  272. package/dist/src/gateway/ports.d.ts +6 -0
  273. package/dist/src/gateway/ports.js +38 -2
  274. package/dist/src/gateway/ports.js.map +1 -1
  275. package/dist/src/gateway/public-url.d.ts +8 -0
  276. package/dist/src/gateway/public-url.js +10 -0
  277. package/dist/src/gateway/public-url.js.map +1 -0
  278. package/dist/src/gateway/security/origin-check.d.ts +9 -1
  279. package/dist/src/gateway/security/origin-check.js +4 -0
  280. package/dist/src/gateway/security/origin-check.js.map +1 -1
  281. package/dist/src/gateway/server.js +15 -0
  282. package/dist/src/gateway/server.js.map +1 -1
  283. package/dist/src/gateway/service/agent-runner.js +2 -2
  284. package/dist/src/gateway/service/marketplace-service.js +2 -2
  285. package/dist/src/gateway/service/run-gateway-agent.js +2 -2
  286. package/dist/src/gateway/service.js +3 -2
  287. package/dist/src/gateway/service.js.map +1 -1
  288. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  289. package/dist/src/i18n/goals-bundle.js +1 -1
  290. package/dist/src/i18n/index.d.ts +1 -0
  291. package/dist/src/i18n/index.js +2 -1
  292. package/dist/src/i18n/locales/share-tool.en.js +15 -0
  293. package/dist/src/i18n/locales/share-tool.en.js.map +1 -0
  294. package/dist/src/i18n/locales/share-tool.zh.js +15 -0
  295. package/dist/src/i18n/locales/share-tool.zh.js.map +1 -0
  296. package/dist/src/i18n/share-tool-bundle.d.ts +20 -0
  297. package/dist/src/i18n/share-tool-bundle.js +56 -0
  298. package/dist/src/i18n/share-tool-bundle.js.map +1 -0
  299. package/dist/src/infra/gateway-processes.js +1 -0
  300. package/dist/src/infra/gateway-processes.js.map +1 -1
  301. package/dist/src/infra/restart.js +2 -2
  302. package/dist/src/infra/update-check.js +1 -1
  303. package/dist/src/infra/update-lock.js +3 -3
  304. package/dist/src/infra/update-runner.js +1 -1
  305. package/dist/src/infra/update-startup.js +2 -2
  306. package/dist/src/infra/write-file-atomic.js +2 -2
  307. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  308. package/dist/src/providers/index.js +2 -2
  309. package/dist/src/providers/model-registry.js +1 -1
  310. package/dist/src/session/config-store.js +2 -2
  311. package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
  312. package/dist/src/session/parity/sessions-json-file.js +1 -1
  313. package/dist/src/session/parity/transcript-file-lock.js +2 -2
  314. package/dist/src/session/parity/transcript-paths.js +1 -1
  315. package/dist/src/session/search-index-cache.js +1 -1
  316. package/dist/src/session/search-index.js +1 -1
  317. package/dist/src/session/session-title.js +3 -2
  318. package/dist/src/session/session-title.js.map +1 -1
  319. package/dist/src/session/store.js +5 -5
  320. package/dist/src/share/share-auto.d.ts +74 -0
  321. package/dist/src/share/share-auto.js +247 -0
  322. package/dist/src/share/share-auto.js.map +1 -0
  323. package/dist/src/share/share-config.js +63 -4
  324. package/dist/src/share/share-config.js.map +1 -1
  325. package/dist/src/share/share-landing.d.ts +28 -2
  326. package/dist/src/share/share-landing.js +155 -34
  327. package/dist/src/share/share-landing.js.map +1 -1
  328. package/dist/src/share/share-store.d.ts +48 -4
  329. package/dist/src/share/share-store.js +322 -51
  330. package/dist/src/share/share-store.js.map +1 -1
  331. package/dist/src/share/share-thumbnail.d.ts +35 -0
  332. package/dist/src/share/share-thumbnail.js +277 -0
  333. package/dist/src/share/share-thumbnail.js.map +1 -0
  334. package/dist/src/share/share-types.d.ts +68 -10
  335. package/dist/src/share/share-types.js +18 -1
  336. package/dist/src/share/share-types.js.map +1 -1
  337. package/dist/src/share/share-url.js +1 -1
  338. package/dist/src/share/share-zip.d.ts +35 -0
  339. package/dist/src/share/share-zip.js +303 -0
  340. package/dist/src/share/share-zip.js.map +1 -0
  341. package/dist/src/share/site-proxy.d.ts +35 -0
  342. package/dist/src/share/site-proxy.js +234 -0
  343. package/dist/src/share/site-proxy.js.map +1 -0
  344. package/dist/src/share/site-share-config.d.ts +11 -0
  345. package/dist/src/share/site-share-config.js +103 -0
  346. package/dist/src/share/site-share-config.js.map +1 -0
  347. package/dist/src/share/site-share-router.d.ts +23 -0
  348. package/dist/src/share/site-share-router.js +147 -0
  349. package/dist/src/share/site-share-router.js.map +1 -0
  350. package/dist/src/share/site-share-store.d.ts +53 -0
  351. package/dist/src/share/site-share-store.js +400 -0
  352. package/dist/src/share/site-share-store.js.map +1 -0
  353. package/dist/src/share/site-share-types.d.ts +103 -0
  354. package/dist/src/share/site-share-types.js +41 -0
  355. package/dist/src/share/site-share-types.js.map +1 -0
  356. package/dist/src/share/site-static-serve.d.ts +10 -0
  357. package/dist/src/share/site-static-serve.js +145 -0
  358. package/dist/src/share/site-static-serve.js.map +1 -0
  359. package/dist/src/tui/clipboard-image.js +3 -3
  360. package/dist/src/tui/theme-manager.js +1 -1
  361. package/dist/src/tui/tui-commands.js +18 -0
  362. package/dist/src/tui/tui-commands.js.map +1 -1
  363. package/dist/src/tui/tui-keybindings-file.js +1 -1
  364. package/dist/src/tui/tui-scoped-models.js +2 -2
  365. package/dist/src/tui/tui-settings.js +1 -1
  366. package/dist/src/tui/tui-workflow-slash.d.ts +32 -0
  367. package/dist/src/tui/tui-workflow-slash.js +63 -0
  368. package/dist/src/tui/tui-workflow-slash.js.map +1 -0
  369. package/dist/src/tui/tui.js +2 -2
  370. package/dist/src/tunnel/enable-lan-pairing.js +1 -1
  371. package/dist/src/tunnel/frpc-binary.js +3 -3
  372. package/dist/src/tunnel/frpc-config.js +1 -1
  373. package/dist/src/tunnel/frpc-extract.js +1 -1
  374. package/dist/src/tunnel/index.js +2 -2
  375. package/dist/src/tunnel/pair-context.d.ts +7 -1
  376. package/dist/src/tunnel/pair-context.js +25 -9
  377. package/dist/src/tunnel/pair-context.js.map +1 -1
  378. package/dist/src/tunnel/pair-url.d.ts +14 -1
  379. package/dist/src/tunnel/pair-url.js +14 -1
  380. package/dist/src/tunnel/pair-url.js.map +1 -1
  381. package/dist/src/tunnel/tunnel-service.js +2 -2
  382. package/dist/src/tunnel/tunnel-state.js +1 -1
  383. package/dist/src/utils/logger/audit.js +1 -1
  384. package/dist/src/utils/logger/log-store.js +1 -1
  385. package/dist/src/utils/logger/rotation.js +1 -1
  386. package/dist/src/voice/tts/audio.js +1 -1
  387. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  388. package/package.json +3 -2
  389. package/dist/gateway/static/root/assets/agents-tR-nNP04.js +0 -222
  390. package/dist/gateway/static/root/assets/apps-page-BDw6SP-d.js +0 -1
  391. package/dist/gateway/static/root/assets/button-KafIU8dx.js +0 -1
  392. package/dist/gateway/static/root/assets/channels-settings-DEFd-jj1.js +0 -1
  393. package/dist/gateway/static/root/assets/channels-status-swr-DI5FHdGe.js +0 -8
  394. package/dist/gateway/static/root/assets/cron-api-BSqY8LwW.js +0 -1
  395. package/dist/gateway/static/root/assets/cron-page-D7lVDjcR.js +0 -1
  396. package/dist/gateway/static/root/assets/dist-C57OMHW8.js +0 -48
  397. package/dist/gateway/static/root/assets/extension-page-CQo2Xsmg.js +0 -1
  398. package/dist/gateway/static/root/assets/extension-settings-page-CZf0WoZg.js +0 -1
  399. package/dist/gateway/static/root/assets/fetch-2iRFmd3n.js +0 -3
  400. package/dist/gateway/static/root/assets/heartbeat-config-api-B0drdQEJ.js +0 -1
  401. package/dist/gateway/static/root/assets/index-0Gt3TG4j.js +0 -4693
  402. package/dist/gateway/static/root/assets/index-BuFldCsB.css +0 -1
  403. package/dist/gateway/static/root/assets/logs-page-DMuORLfC.js +0 -1
  404. package/dist/gateway/static/root/assets/sessions-page-_UO8g6NN.js +0 -1
  405. package/dist/gateway/static/root/assets/settings-form-section-DkmHkknc.js +0 -1
  406. package/dist/gateway/static/root/assets/settings-page-Cz8FoW_A.js +0 -3
  407. package/dist/gateway/static/root/assets/skills-page-HrUOxF7H.js +0 -2
  408. package/dist/gateway/static/root/assets/theme-store-D01dJt95.js +0 -1
  409. package/dist/gateway/static/root/assets/utils-BFwcR6pL.js +0 -1
  410. package/dist/gateway/static/root/assets/voice-api-key-field-JF8-aqc5.js +0 -1
@@ -0,0 +1,301 @@
1
+ import { parseWorkflowScript } from "./parser.js";
2
+ import { availableParallelism } from "node:os";
3
+ import { Script, createContext } from "node:vm";
4
+ //#region src/agent/workflow/runtime.ts
5
+ /**
6
+ * Sandboxed workflow runtime.
7
+ *
8
+ * Parses the script via {@link parseWorkflowScript} (which strips the `meta`
9
+ * export), wraps the remaining body in an async IIFE, and runs it inside a
10
+ * Node `vm` context with a curated set of globals:
11
+ *
12
+ * - `agent(prompt, opts)` — spawns a subagent through the injected
13
+ * {@link SubagentRunner} and returns its result (string, or schema-validated
14
+ * object). Failures resolve to `null`.
15
+ * - `parallel(thunks)` — concurrent fan-out; thunks (not promises!) so the
16
+ * limiter sees each agent() call.
17
+ * - `pipeline(items, ...stages)` — per-item sequential stages, items run
18
+ * concurrently (no stage barrier). Each stage receives
19
+ * `(prevResult, originalItem, index)`. A stage that throws drops that item
20
+ * to `null` and skips remaining stages.
21
+ * - `phase(title)` — marks the current phase; surfaces through `onPhase`.
22
+ * - `log(message)` — appends to the workflow log.
23
+ * - `budget` — `{ total, spent(), remaining() }` for self-pacing scripts.
24
+ * - `args`, `cwd`, `process.cwd()`.
25
+ *
26
+ * The runtime is the only code that touches `vm`. It exposes no IO surface,
27
+ * carries no LLM dependency, and is fully driven by injected callbacks — that
28
+ * means the workflow tool, tests, and any future runner share one runtime.
29
+ */
30
+ const DEFAULT_CONCURRENCY_FLOOR = 1;
31
+ const DEFAULT_CONCURRENCY_CEILING = 16;
32
+ const DEFAULT_MAX_SUBAGENTS = 1e3;
33
+ async function runWorkflow(script, deps, options) {
34
+ const started = Date.now();
35
+ const { meta, body } = parseWorkflowScript(script);
36
+ const state = {
37
+ logs: [],
38
+ phases: [],
39
+ agentCount: 0,
40
+ spent: 0
41
+ };
42
+ const concurrency = clampConcurrency(options.concurrency);
43
+ const maxSubagents = Math.max(1, options.maxSubagents ?? DEFAULT_MAX_SUBAGENTS);
44
+ const limiter = createLimiter(concurrency);
45
+ const pendingAgentRuns = /* @__PURE__ */ new Set();
46
+ const log = (message) => {
47
+ const text = String(message);
48
+ state.logs.push(text);
49
+ options.onLog?.(text);
50
+ };
51
+ const phase = (title) => {
52
+ const text = requireString(title, "phase title");
53
+ state.currentPhase = text;
54
+ if (!state.phases.includes(text)) state.phases.push(text);
55
+ options.onPhase?.(text);
56
+ };
57
+ const budget = Object.freeze({
58
+ total: options.tokenBudget ?? null,
59
+ spent: () => state.spent,
60
+ remaining: () => options.tokenBudget == null ? Number.POSITIVE_INFINITY : Math.max(0, options.tokenBudget - state.spent)
61
+ });
62
+ const throwIfAborted = () => {
63
+ if (options.signal?.aborted) throw new Error("workflow aborted");
64
+ };
65
+ const agent = async (prompt, agentOptions = {}) => {
66
+ throwIfAborted();
67
+ if (budget.total !== null && budget.remaining() <= 0) throw new Error("workflow token budget exhausted");
68
+ if (state.agentCount >= maxSubagents) throw new Error(`workflow agent quota exhausted (max ${maxSubagents})`);
69
+ const taskPrompt = requireString(prompt, "agent prompt");
70
+ const normalized = normalizeAgentOptions(agentOptions);
71
+ const assignedPhase = normalized.phase ?? state.currentPhase;
72
+ const requestedLabel = normalized.label?.trim();
73
+ const runPromise = limiter(async () => {
74
+ state.agentCount += 1;
75
+ const id = state.agentCount;
76
+ const label = requestedLabel || defaultAgentLabel(assignedPhase, id);
77
+ options.onAgentStart?.({
78
+ id,
79
+ label,
80
+ phase: assignedPhase,
81
+ prompt: taskPrompt
82
+ });
83
+ try {
84
+ throwIfAborted();
85
+ const result = await deps.runner.run(taskPrompt, {
86
+ label,
87
+ schema: normalized.schema,
88
+ allowedToolNames: normalized.toolset,
89
+ maxIterations: normalized.maxIterations,
90
+ phase: assignedPhase,
91
+ signal: options.signal,
92
+ instructions: normalized.model ? `The parent workflow requested model "${normalized.model}".` : void 0
93
+ });
94
+ throwIfAborted();
95
+ const status = result === null ? "error" : "done";
96
+ state.spent += estimateTokens(result);
97
+ options.onAgentEnd?.({
98
+ id,
99
+ label,
100
+ phase: assignedPhase,
101
+ result,
102
+ status
103
+ });
104
+ return result;
105
+ } catch (e) {
106
+ if (options.signal?.aborted) {
107
+ options.onAgentEnd?.({
108
+ id,
109
+ label,
110
+ phase: assignedPhase,
111
+ result: null,
112
+ status: "skipped"
113
+ });
114
+ throw e;
115
+ }
116
+ log(`agent ${label} failed: ${e instanceof Error ? e.message : String(e)}`);
117
+ options.onAgentEnd?.({
118
+ id,
119
+ label,
120
+ phase: assignedPhase,
121
+ result: null,
122
+ status: "error"
123
+ });
124
+ return null;
125
+ }
126
+ });
127
+ pendingAgentRuns.add(runPromise);
128
+ runPromise.then(() => pendingAgentRuns.delete(runPromise), () => pendingAgentRuns.delete(runPromise));
129
+ return runPromise;
130
+ };
131
+ const parallel = async (thunks) => {
132
+ throwIfAborted();
133
+ if (!Array.isArray(thunks)) throw new TypeError("parallel() expects an array of functions");
134
+ for (const t of thunks) if (typeof t !== "function") throw new TypeError("parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)");
135
+ return Promise.all(thunks.map(async (thunk, index) => {
136
+ try {
137
+ return await thunk();
138
+ } catch (e) {
139
+ if (options.signal?.aborted) throw e;
140
+ log(`parallel[${index}] failed: ${e instanceof Error ? e.message : String(e)}`);
141
+ return null;
142
+ }
143
+ }));
144
+ };
145
+ const pipeline = async (items, ...stages) => {
146
+ throwIfAborted();
147
+ if (!Array.isArray(items)) throw new TypeError("pipeline() expects an array as the first argument");
148
+ for (const stage of stages) if (typeof stage !== "function") throw new TypeError("pipeline() stages must be functions: pipeline(items, item => ..., result => ...)");
149
+ const typedStages = stages;
150
+ return Promise.all(items.map(async (item, index) => {
151
+ let value = item;
152
+ for (const stage of typedStages) try {
153
+ throwIfAborted();
154
+ value = await stage(value, item, index);
155
+ throwIfAborted();
156
+ } catch (e) {
157
+ if (options.signal?.aborted) throw e;
158
+ log(`pipeline[${index}] failed: ${e instanceof Error ? e.message : String(e)}`);
159
+ return null;
160
+ }
161
+ return value;
162
+ }));
163
+ };
164
+ const context = createContext({
165
+ agent,
166
+ parallel,
167
+ pipeline,
168
+ log,
169
+ phase,
170
+ args: options.args,
171
+ cwd: options.cwd,
172
+ process: Object.freeze({ cwd: () => options.cwd }),
173
+ budget,
174
+ console: {
175
+ log,
176
+ info: log,
177
+ warn: (m) => log(`[warn] ${String(m)}`),
178
+ error: (m) => log(`[error] ${String(m)}`)
179
+ },
180
+ JSON,
181
+ Math,
182
+ Array,
183
+ Object,
184
+ String,
185
+ Number,
186
+ Boolean,
187
+ Set,
188
+ Map,
189
+ Promise
190
+ });
191
+ const script$ = new Script(`(async () => {\n${body}\n})()`, { filename: `${meta.name}.workflow.js` });
192
+ let result;
193
+ try {
194
+ result = await script$.runInContext(context);
195
+ await Promise.allSettled([...pendingAgentRuns]);
196
+ } catch (e) {
197
+ await Promise.allSettled([...pendingAgentRuns]);
198
+ throw e;
199
+ }
200
+ assertStructuredCloneable(result, "workflow result");
201
+ return {
202
+ meta,
203
+ result,
204
+ logs: state.logs,
205
+ phases: state.phases,
206
+ agentCount: state.agentCount,
207
+ durationMs: Date.now() - started
208
+ };
209
+ }
210
+ function emptySnapshotFor(name, description) {
211
+ return {
212
+ name,
213
+ description,
214
+ phases: [],
215
+ logs: [],
216
+ agents: [],
217
+ agentCount: 0,
218
+ runningCount: 0,
219
+ doneCount: 0,
220
+ errorCount: 0,
221
+ skippedCount: 0
222
+ };
223
+ }
224
+ function clampConcurrency(requested) {
225
+ if (typeof requested === "number" && Number.isFinite(requested) && requested >= 1) return Math.min(Math.floor(requested), DEFAULT_CONCURRENCY_CEILING);
226
+ let cpu = DEFAULT_CONCURRENCY_CEILING;
227
+ try {
228
+ cpu = availableParallelism();
229
+ } catch {}
230
+ return Math.max(DEFAULT_CONCURRENCY_FLOOR, Math.min(DEFAULT_CONCURRENCY_CEILING, cpu - 2));
231
+ }
232
+ function createLimiter(limit) {
233
+ let active = 0;
234
+ const queue = [];
235
+ const next = () => {
236
+ active -= 1;
237
+ const resume = queue.shift();
238
+ if (resume) resume();
239
+ };
240
+ return async (fn) => {
241
+ if (active >= limit) await new Promise((resolve) => queue.push(resolve));
242
+ active += 1;
243
+ try {
244
+ return await fn();
245
+ } finally {
246
+ next();
247
+ }
248
+ };
249
+ }
250
+ function requireString(value, name) {
251
+ if (typeof value !== "string") throw new TypeError(`${name} must be a string`);
252
+ return value;
253
+ }
254
+ function optionalString(value, name) {
255
+ if (value === void 0) return void 0;
256
+ return requireString(value, name);
257
+ }
258
+ function normalizeAgentOptions(value) {
259
+ if (value === void 0 || value === null) return {};
260
+ if (typeof value !== "object") throw new TypeError("agent options must be an object");
261
+ const options = value;
262
+ const toolset = options.toolset;
263
+ if (toolset !== void 0) {
264
+ if (!Array.isArray(toolset) || toolset.some((t) => typeof t !== "string")) throw new TypeError("agent toolset must be an array of strings");
265
+ }
266
+ const maxIterations = options.maxIterations;
267
+ if (maxIterations !== void 0) {
268
+ if (typeof maxIterations !== "number" || !Number.isFinite(maxIterations) || maxIterations < 1) throw new TypeError("agent maxIterations must be a positive number");
269
+ }
270
+ return {
271
+ label: optionalString(options.label, "agent label"),
272
+ phase: optionalString(options.phase, "agent phase"),
273
+ schema: options.schema,
274
+ model: optionalString(options.model, "agent model"),
275
+ toolset,
276
+ maxIterations
277
+ };
278
+ }
279
+ function assertStructuredCloneable(value, name) {
280
+ try {
281
+ structuredClone(value);
282
+ } catch (e) {
283
+ const detail = e instanceof Error ? ` ${e.message}` : "";
284
+ throw new Error(`${name} must be structured-cloneable; did you forget to await agent(), parallel(), or pipeline()?${detail}`);
285
+ }
286
+ }
287
+ function defaultAgentLabel(phase, index) {
288
+ return phase ? `${phase} agent ${index}` : `agent ${index}`;
289
+ }
290
+ function estimateTokens(value) {
291
+ if (value === null || value === void 0) return 0;
292
+ try {
293
+ return Math.ceil(JSON.stringify(value).length / 4);
294
+ } catch {
295
+ return Math.ceil(String(value).length / 4);
296
+ }
297
+ }
298
+ //#endregion
299
+ export { emptySnapshotFor, runWorkflow };
300
+
301
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","names":[],"sources":["../../../../src/agent/workflow/runtime.ts"],"sourcesContent":["/**\n * Sandboxed workflow runtime.\n *\n * Parses the script via {@link parseWorkflowScript} (which strips the `meta`\n * export), wraps the remaining body in an async IIFE, and runs it inside a\n * Node `vm` context with a curated set of globals:\n *\n * - `agent(prompt, opts)` — spawns a subagent through the injected\n * {@link SubagentRunner} and returns its result (string, or schema-validated\n * object). Failures resolve to `null`.\n * - `parallel(thunks)` — concurrent fan-out; thunks (not promises!) so the\n * limiter sees each agent() call.\n * - `pipeline(items, ...stages)` — per-item sequential stages, items run\n * concurrently (no stage barrier). Each stage receives\n * `(prevResult, originalItem, index)`. A stage that throws drops that item\n * to `null` and skips remaining stages.\n * - `phase(title)` — marks the current phase; surfaces through `onPhase`.\n * - `log(message)` — appends to the workflow log.\n * - `budget` — `{ total, spent(), remaining() }` for self-pacing scripts.\n * - `args`, `cwd`, `process.cwd()`.\n *\n * The runtime is the only code that touches `vm`. It exposes no IO surface,\n * carries no LLM dependency, and is fully driven by injected callbacks — that\n * means the workflow tool, tests, and any future runner share one runtime.\n */\n\nimport { availableParallelism } from 'node:os';\nimport { createContext, Script } from 'node:vm';\n\nimport { parseWorkflowScript } from './parser.js';\nimport type {\n AgentScriptOptions,\n SubagentRunner,\n WorkflowRunOptions,\n WorkflowRunResult,\n WorkflowSnapshot,\n WorkflowAgentStatus,\n} from './types.js';\n\nconst DEFAULT_CONCURRENCY_FLOOR = 1;\nconst DEFAULT_CONCURRENCY_CEILING = 16;\nconst DEFAULT_MAX_SUBAGENTS = 1000;\n\ninterface RuntimeState {\n currentPhase?: string;\n logs: string[];\n phases: string[];\n agentCount: number;\n spent: number;\n}\n\nexport interface RunWorkflowDeps {\n runner: SubagentRunner;\n}\n\nexport async function runWorkflow<T = unknown>(\n script: string,\n deps: RunWorkflowDeps,\n options: WorkflowRunOptions,\n): Promise<WorkflowRunResult<T>> {\n const started = Date.now();\n const { meta, body } = parseWorkflowScript(script);\n\n const state: RuntimeState = { logs: [], phases: [], agentCount: 0, spent: 0 };\n const concurrency = clampConcurrency(options.concurrency);\n const maxSubagents = Math.max(1, options.maxSubagents ?? DEFAULT_MAX_SUBAGENTS);\n const limiter = createLimiter(concurrency);\n const pendingAgentRuns = new Set<Promise<unknown>>();\n\n const log = (message: unknown) => {\n const text = String(message);\n state.logs.push(text);\n options.onLog?.(text);\n };\n\n const phase = (title: unknown) => {\n const text = requireString(title, 'phase title');\n state.currentPhase = text;\n if (!state.phases.includes(text)) state.phases.push(text);\n options.onPhase?.(text);\n };\n\n const budget = Object.freeze({\n total: options.tokenBudget ?? null,\n spent: () => state.spent,\n remaining: () =>\n options.tokenBudget == null\n ? Number.POSITIVE_INFINITY\n : Math.max(0, options.tokenBudget - state.spent),\n });\n\n const throwIfAborted = () => {\n if (options.signal?.aborted) throw new Error('workflow aborted');\n };\n\n const agent = async (prompt: unknown, agentOptions: unknown = {}) => {\n throwIfAborted();\n if (budget.total !== null && budget.remaining() <= 0) {\n throw new Error('workflow token budget exhausted');\n }\n if (state.agentCount >= maxSubagents) {\n throw new Error(`workflow agent quota exhausted (max ${maxSubagents})`);\n }\n\n const taskPrompt = requireString(prompt, 'agent prompt');\n const normalized = normalizeAgentOptions(agentOptions);\n const assignedPhase = normalized.phase ?? state.currentPhase;\n const requestedLabel = normalized.label?.trim();\n\n const runPromise = limiter(async () => {\n // Counter increments inside the limiter — id reflects start order, not enqueue order.\n state.agentCount += 1;\n const id = state.agentCount;\n const label = requestedLabel || defaultAgentLabel(assignedPhase, id);\n options.onAgentStart?.({ id, label, phase: assignedPhase, prompt: taskPrompt });\n\n try {\n throwIfAborted();\n const result = await deps.runner.run<unknown>(taskPrompt, {\n label,\n schema: normalized.schema,\n allowedToolNames: normalized.toolset,\n maxIterations: normalized.maxIterations,\n phase: assignedPhase,\n signal: options.signal,\n instructions: normalized.model\n ? `The parent workflow requested model \"${normalized.model}\".`\n : undefined,\n });\n throwIfAborted();\n\n const status: WorkflowAgentStatus = result === null ? 'error' : 'done';\n state.spent += estimateTokens(result);\n options.onAgentEnd?.({ id, label, phase: assignedPhase, result, status });\n return result;\n } catch (e) {\n if (options.signal?.aborted) {\n options.onAgentEnd?.({ id, label, phase: assignedPhase, result: null, status: 'skipped' });\n throw e;\n }\n const message = e instanceof Error ? e.message : String(e);\n log(`agent ${label} failed: ${message}`);\n options.onAgentEnd?.({ id, label, phase: assignedPhase, result: null, status: 'error' });\n return null;\n }\n });\n\n pendingAgentRuns.add(runPromise);\n // `then` (not `finally`) keeps the bookkeeping promise from re-throwing into\n // the unhandled-rejection channel when `runPromise` rejects on abort.\n runPromise.then(\n () => pendingAgentRuns.delete(runPromise),\n () => pendingAgentRuns.delete(runPromise),\n );\n return runPromise;\n };\n\n const parallel = async (thunks: unknown) => {\n throwIfAborted();\n if (!Array.isArray(thunks)) throw new TypeError('parallel() expects an array of functions');\n for (const t of thunks) {\n if (typeof t !== 'function') {\n throw new TypeError(\n 'parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)',\n );\n }\n }\n return Promise.all(\n thunks.map(async (thunk, index) => {\n try {\n return await (thunk as () => unknown)();\n } catch (e) {\n if (options.signal?.aborted) throw e;\n const message = e instanceof Error ? e.message : String(e);\n log(`parallel[${index}] failed: ${message}`);\n return null;\n }\n }),\n );\n };\n\n const pipeline = async (items: unknown, ...stages: Array<unknown>) => {\n throwIfAborted();\n if (!Array.isArray(items)) {\n throw new TypeError('pipeline() expects an array as the first argument');\n }\n for (const stage of stages) {\n if (typeof stage !== 'function') {\n throw new TypeError(\n 'pipeline() stages must be functions: pipeline(items, item => ..., result => ...)',\n );\n }\n }\n const typedStages = stages as Array<\n (prev: unknown, original: unknown, index: number) => unknown\n >;\n return Promise.all(\n items.map(async (item, index) => {\n let value: unknown = item;\n for (const stage of typedStages) {\n try {\n throwIfAborted();\n value = await stage(value, item, index);\n throwIfAborted();\n } catch (e) {\n if (options.signal?.aborted) throw e;\n const message = e instanceof Error ? e.message : String(e);\n log(`pipeline[${index}] failed: ${message}`);\n return null;\n }\n }\n return value;\n }),\n );\n };\n\n const context = createContext({\n agent,\n parallel,\n pipeline,\n log,\n phase,\n args: options.args,\n cwd: options.cwd,\n process: Object.freeze({ cwd: () => options.cwd }),\n budget,\n console: {\n log,\n info: log,\n warn: (m: unknown) => log(`[warn] ${String(m)}`),\n error: (m: unknown) => log(`[error] ${String(m)}`),\n },\n JSON,\n Math,\n Array,\n Object,\n String,\n Number,\n Boolean,\n Set,\n Map,\n Promise,\n });\n\n const wrapped = `(async () => {\\n${body}\\n})()`;\n const script$ = new Script(wrapped, { filename: `${meta.name}.workflow.js` });\n\n let result: unknown;\n try {\n result = await script$.runInContext(context);\n // Wait for any agent() runs the script forgot to await before declaring success.\n await Promise.allSettled([...pendingAgentRuns]);\n } catch (e) {\n // Drain pending agent calls before propagating, so the snapshot reflects final state.\n await Promise.allSettled([...pendingAgentRuns]);\n throw e;\n }\n\n assertStructuredCloneable(result, 'workflow result');\n\n return {\n meta,\n result: result as T,\n logs: state.logs,\n phases: state.phases,\n agentCount: state.agentCount,\n durationMs: Date.now() - started,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Initial snapshot helper — kept here so the runtime is the single source of\n// truth for \"what a fresh snapshot looks like for this workflow\".\n// ---------------------------------------------------------------------------\n\nexport function emptySnapshotFor(name: string, description?: string): WorkflowSnapshot {\n return {\n name,\n description,\n phases: [],\n logs: [],\n agents: [],\n agentCount: 0,\n runningCount: 0,\n doneCount: 0,\n errorCount: 0,\n skippedCount: 0,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\nfunction clampConcurrency(requested?: number): number {\n if (typeof requested === 'number' && Number.isFinite(requested) && requested >= 1) {\n return Math.min(Math.floor(requested), DEFAULT_CONCURRENCY_CEILING);\n }\n let cpu = DEFAULT_CONCURRENCY_CEILING;\n try {\n cpu = availableParallelism();\n } catch {\n // Some sandboxes throw; fall back to the ceiling.\n }\n return Math.max(DEFAULT_CONCURRENCY_FLOOR, Math.min(DEFAULT_CONCURRENCY_CEILING, cpu - 2));\n}\n\nfunction createLimiter(limit: number) {\n let active = 0;\n const queue: Array<() => void> = [];\n const next = () => {\n active -= 1;\n const resume = queue.shift();\n if (resume) resume();\n };\n return async <T>(fn: () => Promise<T>): Promise<T> => {\n if (active >= limit) {\n await new Promise<void>((resolve) => queue.push(resolve));\n }\n active += 1;\n try {\n return await fn();\n } finally {\n next();\n }\n };\n}\n\nfunction requireString(value: unknown, name: string): string {\n if (typeof value !== 'string') throw new TypeError(`${name} must be a string`);\n return value;\n}\n\nfunction optionalString(value: unknown, name: string): string | undefined {\n if (value === undefined) return undefined;\n return requireString(value, name);\n}\n\nfunction normalizeAgentOptions(value: unknown): AgentScriptOptions {\n if (value === undefined || value === null) return {};\n if (typeof value !== 'object') throw new TypeError('agent options must be an object');\n const options = value as AgentScriptOptions;\n const toolset = options.toolset;\n if (toolset !== undefined) {\n if (!Array.isArray(toolset) || toolset.some((t) => typeof t !== 'string')) {\n throw new TypeError('agent toolset must be an array of strings');\n }\n }\n const maxIterations = options.maxIterations;\n if (maxIterations !== undefined) {\n if (typeof maxIterations !== 'number' || !Number.isFinite(maxIterations) || maxIterations < 1) {\n throw new TypeError('agent maxIterations must be a positive number');\n }\n }\n return {\n label: optionalString(options.label, 'agent label'),\n phase: optionalString(options.phase, 'agent phase'),\n schema: options.schema,\n model: optionalString(options.model, 'agent model'),\n toolset,\n maxIterations,\n };\n}\n\nfunction assertStructuredCloneable(value: unknown, name: string): void {\n try {\n structuredClone(value);\n } catch (e) {\n const detail = e instanceof Error ? ` ${e.message}` : '';\n throw new Error(\n `${name} must be structured-cloneable; did you forget to await agent(), parallel(), or pipeline()?${detail}`,\n );\n }\n}\n\nfunction defaultAgentLabel(phase: string | undefined, index: number): string {\n return phase ? `${phase} agent ${index}` : `agent ${index}`;\n}\n\nfunction estimateTokens(value: unknown): number {\n if (value === null || value === undefined) return 0;\n try {\n return Math.ceil(JSON.stringify(value).length / 4);\n } catch {\n return Math.ceil(String(value).length / 4);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Workflow progress snapshot model + text renderers.
3
+ *
4
+ * The runtime emits per-event callbacks (`onPhase`, `onAgentStart`, `onAgentEnd`,
5
+ * `onLog`). The workflow tool wraps those callbacks to mutate a snapshot and push
6
+ * a text rendering through `onUpdate` — keeping TUI / Gateway / IM consumers in
7
+ * lock-step from a single source of truth.
8
+ */
9
+ import type { WorkflowMeta, WorkflowSnapshot } from './types.js';
10
+ export declare function createWorkflowSnapshot(meta: WorkflowMeta): WorkflowSnapshot;
11
+ export declare function recomputeCounts(snapshot: WorkflowSnapshot): void;
12
+ export interface RenderOptions {
13
+ maxAgentsPerPhase?: number;
14
+ maxLogs?: number;
15
+ showResultPreviews?: boolean;
16
+ }
17
+ export declare function renderWorkflowText(snapshot: WorkflowSnapshot, completed?: boolean, options?: RenderOptions): string;
18
+ export declare function previewValue(value: unknown, max?: number): string;
@@ -0,0 +1,144 @@
1
+ //#region src/agent/workflow/snapshot.ts
2
+ function createWorkflowSnapshot(meta) {
3
+ return {
4
+ name: meta.name,
5
+ description: meta.description,
6
+ phases: [],
7
+ logs: [],
8
+ agents: [],
9
+ agentCount: 0,
10
+ runningCount: 0,
11
+ doneCount: 0,
12
+ errorCount: 0,
13
+ skippedCount: 0
14
+ };
15
+ }
16
+ function recomputeCounts(snapshot) {
17
+ let running = 0;
18
+ let done = 0;
19
+ let error = 0;
20
+ let skipped = 0;
21
+ for (const agent of snapshot.agents) switch (agent.status) {
22
+ case "running":
23
+ running++;
24
+ break;
25
+ case "done":
26
+ done++;
27
+ break;
28
+ case "error":
29
+ error++;
30
+ break;
31
+ case "skipped":
32
+ skipped++;
33
+ break;
34
+ }
35
+ snapshot.agentCount = snapshot.agents.length;
36
+ snapshot.runningCount = running;
37
+ snapshot.doneCount = done;
38
+ snapshot.errorCount = error;
39
+ snapshot.skippedCount = skipped;
40
+ }
41
+ function renderWorkflowText(snapshot, completed = false, options = {}) {
42
+ const maxAgentsPerPhase = options.maxAgentsPerPhase ?? 6;
43
+ const maxLogs = options.maxLogs ?? 2;
44
+ const showPreviews = options.showResultPreviews ?? false;
45
+ const state = stateSuffix(snapshot);
46
+ const lines = [completed ? `◆ workflow ✓ ${snapshot.name} (${snapshot.doneCount}/${snapshot.agentCount} done${state})` : `◆ workflow: ${snapshot.name} (${snapshot.doneCount}/${snapshot.agentCount} done${state})`];
47
+ const phaseNames = uniqueOrdered([
48
+ ...snapshot.phases,
49
+ ...snapshot.currentPhase ? [snapshot.currentPhase] : [],
50
+ ...snapshot.agents.map((a) => a.phase).filter((p) => Boolean(p))
51
+ ]);
52
+ const rendered = /* @__PURE__ */ new Set();
53
+ for (const phase of phaseNames) {
54
+ const agents = snapshot.agents.filter((a) => a.phase === phase);
55
+ if (agents.length === 0 && snapshot.currentPhase !== phase) continue;
56
+ for (const a of agents) rendered.add(a);
57
+ const counts = countAgents(agents);
58
+ const completeHere = agents.length > 0 && counts.done + counts.error + counts.skipped === agents.length;
59
+ const marker = counts.running > 0 || !completeHere && snapshot.currentPhase === phase ? "▶" : completeHere ? "✓" : " ";
60
+ const tail = (counts.running ? ` · ${counts.running} running` : "") + (counts.error ? ` · ${counts.error} errors` : "") + (counts.skipped ? ` · ${counts.skipped} skipped` : "");
61
+ lines.push(` ${marker} ${phase} ${counts.done}/${agents.length}${tail}`);
62
+ const visible = agents.slice(-maxAgentsPerPhase);
63
+ for (const agent of visible) {
64
+ const previewText = showPreviews && agent.resultPreview ? ` — ${agent.resultPreview}` : "";
65
+ lines.push(` #${agent.id} ${statusIcon(agent.status)} ${shorten(agent.label, 56)}${previewText}`);
66
+ }
67
+ if (agents.length > visible.length) lines.push(` … ${agents.length - visible.length} earlier agents`);
68
+ }
69
+ const unphased = snapshot.agents.filter((a) => !rendered.has(a));
70
+ if (unphased.length > 0) {
71
+ lines.push(" unphased");
72
+ for (const agent of unphased.slice(-maxAgentsPerPhase)) {
73
+ const previewText = showPreviews && agent.resultPreview ? ` — ${agent.resultPreview}` : "";
74
+ lines.push(` #${agent.id} ${statusIcon(agent.status)} ${shorten(agent.label, 56)}${previewText}`);
75
+ }
76
+ }
77
+ const visibleLogs = snapshot.logs.slice(-maxLogs);
78
+ if (visibleLogs.length > 0) {
79
+ lines.push("");
80
+ for (const log of visibleLogs) lines.push(` log: ${shorten(log, 80)}`);
81
+ }
82
+ return lines.join("\n");
83
+ }
84
+ function previewValue(value, max = 80) {
85
+ if (value === null || value === void 0) return "";
86
+ const text = typeof value === "string" ? value : safeStringify(value);
87
+ if (!text) return "";
88
+ return text.length > max ? `${text.slice(0, max - 1)}…` : text;
89
+ }
90
+ function countAgents(agents) {
91
+ let done = 0;
92
+ let running = 0;
93
+ let error = 0;
94
+ let skipped = 0;
95
+ for (const a of agents) if (a.status === "done") done++;
96
+ else if (a.status === "running") running++;
97
+ else if (a.status === "error") error++;
98
+ else if (a.status === "skipped") skipped++;
99
+ return {
100
+ done,
101
+ running,
102
+ error,
103
+ skipped
104
+ };
105
+ }
106
+ function statusIcon(status) {
107
+ switch (status) {
108
+ case "queued": return "○";
109
+ case "running": return "●";
110
+ case "done": return "✓";
111
+ case "error": return "✗";
112
+ case "skipped": return "-";
113
+ }
114
+ }
115
+ function stateSuffix(snapshot) {
116
+ if (snapshot.errorCount > 0) return `, ${snapshot.errorCount} errors`;
117
+ if (snapshot.skippedCount > 0) return `, ${snapshot.skippedCount} skipped`;
118
+ if (snapshot.runningCount > 0) return `, ${snapshot.runningCount} running`;
119
+ return "";
120
+ }
121
+ function uniqueOrdered(values) {
122
+ const seen = /* @__PURE__ */ new Set();
123
+ const out = [];
124
+ for (const v of values) if (!seen.has(v)) {
125
+ seen.add(v);
126
+ out.push(v);
127
+ }
128
+ return out;
129
+ }
130
+ function shorten(value, max) {
131
+ const text = value.replace(/\s+/g, " ").trim();
132
+ return text.length > max ? `${text.slice(0, max - 1)}…` : text;
133
+ }
134
+ function safeStringify(value) {
135
+ try {
136
+ return JSON.stringify(value);
137
+ } catch {
138
+ return String(value);
139
+ }
140
+ }
141
+ //#endregion
142
+ export { createWorkflowSnapshot, previewValue, recomputeCounts, renderWorkflowText };
143
+
144
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","names":[],"sources":["../../../../src/agent/workflow/snapshot.ts"],"sourcesContent":["/**\n * Workflow progress snapshot model + text renderers.\n *\n * The runtime emits per-event callbacks (`onPhase`, `onAgentStart`, `onAgentEnd`,\n * `onLog`). The workflow tool wraps those callbacks to mutate a snapshot and push\n * a text rendering through `onUpdate` — keeping TUI / Gateway / IM consumers in\n * lock-step from a single source of truth.\n */\n\nimport type {\n WorkflowAgentSnapshot,\n WorkflowAgentStatus,\n WorkflowMeta,\n WorkflowSnapshot,\n} from './types.js';\n\nexport function createWorkflowSnapshot(meta: WorkflowMeta): WorkflowSnapshot {\n return {\n name: meta.name,\n description: meta.description,\n phases: [],\n logs: [],\n agents: [],\n agentCount: 0,\n runningCount: 0,\n doneCount: 0,\n errorCount: 0,\n skippedCount: 0,\n };\n}\n\nexport function recomputeCounts(snapshot: WorkflowSnapshot): void {\n let running = 0;\n let done = 0;\n let error = 0;\n let skipped = 0;\n for (const agent of snapshot.agents) {\n switch (agent.status) {\n case 'running':\n running++;\n break;\n case 'done':\n done++;\n break;\n case 'error':\n error++;\n break;\n case 'skipped':\n skipped++;\n break;\n }\n }\n snapshot.agentCount = snapshot.agents.length;\n snapshot.runningCount = running;\n snapshot.doneCount = done;\n snapshot.errorCount = error;\n snapshot.skippedCount = skipped;\n}\n\nexport interface RenderOptions {\n maxAgentsPerPhase?: number;\n maxLogs?: number;\n showResultPreviews?: boolean;\n}\n\nexport function renderWorkflowText(\n snapshot: WorkflowSnapshot,\n completed = false,\n options: RenderOptions = {},\n): string {\n const maxAgentsPerPhase = options.maxAgentsPerPhase ?? 6;\n const maxLogs = options.maxLogs ?? 2;\n const showPreviews = options.showResultPreviews ?? false;\n\n const state = stateSuffix(snapshot);\n const header = completed\n ? `◆ workflow ✓ ${snapshot.name} (${snapshot.doneCount}/${snapshot.agentCount} done${state})`\n : `◆ workflow: ${snapshot.name} (${snapshot.doneCount}/${snapshot.agentCount} done${state})`;\n const lines = [header];\n\n const phaseNames = uniqueOrdered([\n ...snapshot.phases,\n ...(snapshot.currentPhase ? [snapshot.currentPhase] : []),\n ...snapshot.agents.map((a) => a.phase).filter((p): p is string => Boolean(p)),\n ]);\n const rendered = new Set<WorkflowAgentSnapshot>();\n\n for (const phase of phaseNames) {\n const agents = snapshot.agents.filter((a) => a.phase === phase);\n if (agents.length === 0 && snapshot.currentPhase !== phase) continue;\n for (const a of agents) rendered.add(a);\n\n const counts = countAgents(agents);\n const completeHere = agents.length > 0 && counts.done + counts.error + counts.skipped === agents.length;\n const marker =\n counts.running > 0 || (!completeHere && snapshot.currentPhase === phase)\n ? '▶'\n : completeHere\n ? '✓'\n : ' ';\n\n const tail =\n (counts.running ? ` · ${counts.running} running` : '') +\n (counts.error ? ` · ${counts.error} errors` : '') +\n (counts.skipped ? ` · ${counts.skipped} skipped` : '');\n lines.push(` ${marker} ${phase} ${counts.done}/${agents.length}${tail}`);\n\n const visible = agents.slice(-maxAgentsPerPhase);\n for (const agent of visible) {\n const previewText = showPreviews && agent.resultPreview ? ` — ${agent.resultPreview}` : '';\n lines.push(\n ` #${agent.id} ${statusIcon(agent.status)} ${shorten(agent.label, 56)}${previewText}`,\n );\n }\n if (agents.length > visible.length) {\n lines.push(` … ${agents.length - visible.length} earlier agents`);\n }\n }\n\n const unphased = snapshot.agents.filter((a) => !rendered.has(a));\n if (unphased.length > 0) {\n lines.push(' unphased');\n for (const agent of unphased.slice(-maxAgentsPerPhase)) {\n const previewText = showPreviews && agent.resultPreview ? ` — ${agent.resultPreview}` : '';\n lines.push(\n ` #${agent.id} ${statusIcon(agent.status)} ${shorten(agent.label, 56)}${previewText}`,\n );\n }\n }\n\n const visibleLogs = snapshot.logs.slice(-maxLogs);\n if (visibleLogs.length > 0) {\n lines.push('');\n for (const log of visibleLogs) {\n lines.push(` log: ${shorten(log, 80)}`);\n }\n }\n return lines.join('\\n');\n}\n\nexport function previewValue(value: unknown, max = 80): string {\n if (value === null || value === undefined) return '';\n const text = typeof value === 'string' ? value : safeStringify(value);\n if (!text) return '';\n return text.length > max ? `${text.slice(0, max - 1)}…` : text;\n}\n\n// ---------------------------------------------------------------------------\n\nfunction countAgents(agents: WorkflowAgentSnapshot[]) {\n let done = 0;\n let running = 0;\n let error = 0;\n let skipped = 0;\n for (const a of agents) {\n if (a.status === 'done') done++;\n else if (a.status === 'running') running++;\n else if (a.status === 'error') error++;\n else if (a.status === 'skipped') skipped++;\n }\n return { done, running, error, skipped };\n}\n\nfunction statusIcon(status: WorkflowAgentStatus): string {\n switch (status) {\n case 'queued':\n return '○';\n case 'running':\n return '●';\n case 'done':\n return '✓';\n case 'error':\n return '✗';\n case 'skipped':\n return '-';\n }\n}\n\nfunction stateSuffix(snapshot: WorkflowSnapshot): string {\n if (snapshot.errorCount > 0) return `, ${snapshot.errorCount} errors`;\n if (snapshot.skippedCount > 0) return `, ${snapshot.skippedCount} skipped`;\n if (snapshot.runningCount > 0) return `, ${snapshot.runningCount} running`;\n return '';\n}\n\nfunction uniqueOrdered(values: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const v of values) {\n if (!seen.has(v)) {\n seen.add(v);\n out.push(v);\n }\n }\n return out;\n}\n\nfunction shorten(value: string, max: number): string {\n const text = value.replace(/\\s+/g, ' ').trim();\n return text.length > max ? `${text.slice(0, max - 1)}…` : text;\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * `structured_output` — terminating tool used to capture a subagent's final result.
3
+ *
4
+ * Injected into a subagent's toolset only when the workflow script asked for
5
+ * structured output via `agent(prompt, { schema })`. The subagent is instructed
6
+ * to invoke this tool exactly once with its final result; the tool sets
7
+ * `terminate: true` so the agent loop stops without paying for an extra
8
+ * assistant turn.
9
+ *
10
+ * Validation is done with ajv (already a xopc dep). pi-agent-core also validates
11
+ * arguments against `parameters` before calling `execute`, but we re-check here
12
+ * to (1) surface a clear error message back to the model when the schema is
13
+ * non-trivial, and (2) avoid trusting the upstream layer's validator strictness.
14
+ *
15
+ * Note: the file is named `structured-output-tool.ts` to avoid clashing with the
16
+ * existing `src/agent/tools/structured-output.ts` (an XML Element builder — a
17
+ * completely unrelated utility).
18
+ */
19
+ import type { AgentTool } from '@earendil-works/pi-agent-core';
20
+ import type { TSchema } from '@sinclair/typebox';
21
+ import type { JsonSchema } from './types.js';
22
+ export declare const STRUCTURED_OUTPUT_TOOL_NAME = "structured_output";
23
+ export interface StructuredOutputCapture<T = unknown> {
24
+ called: boolean;
25
+ value?: T;
26
+ }
27
+ export interface CreateStructuredOutputToolOptions<T = unknown> {
28
+ schema: JsonSchema;
29
+ capture: StructuredOutputCapture<T>;
30
+ /** Override the tool name (rarely needed; default `structured_output`). */
31
+ name?: string;
32
+ }
33
+ export declare function createStructuredOutputTool<T = unknown>(options: CreateStructuredOutputToolOptions<T>): AgentTool<TSchema, T>;
@@ -0,0 +1,58 @@
1
+ import Ajv from "ajv";
2
+ //#region src/agent/workflow/structured-output-tool.ts
3
+ /**
4
+ * `structured_output` — terminating tool used to capture a subagent's final result.
5
+ *
6
+ * Injected into a subagent's toolset only when the workflow script asked for
7
+ * structured output via `agent(prompt, { schema })`. The subagent is instructed
8
+ * to invoke this tool exactly once with its final result; the tool sets
9
+ * `terminate: true` so the agent loop stops without paying for an extra
10
+ * assistant turn.
11
+ *
12
+ * Validation is done with ajv (already a xopc dep). pi-agent-core also validates
13
+ * arguments against `parameters` before calling `execute`, but we re-check here
14
+ * to (1) surface a clear error message back to the model when the schema is
15
+ * non-trivial, and (2) avoid trusting the upstream layer's validator strictness.
16
+ *
17
+ * Note: the file is named `structured-output-tool.ts` to avoid clashing with the
18
+ * existing `src/agent/tools/structured-output.ts` (an XML Element builder — a
19
+ * completely unrelated utility).
20
+ */
21
+ const STRUCTURED_OUTPUT_TOOL_NAME = "structured_output";
22
+ const ajv = new Ajv({
23
+ allErrors: true,
24
+ strict: false
25
+ });
26
+ function createStructuredOutputTool(options) {
27
+ const name = options.name ?? "structured_output";
28
+ const validator = ajv.compile(options.schema);
29
+ return {
30
+ name,
31
+ label: "Structured Output",
32
+ description: "Return the final machine-readable result for this subagent task. Call this tool exactly once when finished. Do not emit a prose final answer afterwards.",
33
+ parameters: options.schema,
34
+ async execute(_toolCallId, params) {
35
+ if (!validator(params)) return {
36
+ content: [{
37
+ type: "text",
38
+ text: `structured_output: invalid arguments — ${ajv.errorsText(validator.errors, { separator: "; " })}. Adjust and call structured_output again.`
39
+ }],
40
+ details: params
41
+ };
42
+ options.capture.called = true;
43
+ options.capture.value = params;
44
+ return {
45
+ content: [{
46
+ type: "text",
47
+ text: "Structured output received."
48
+ }],
49
+ details: params,
50
+ terminate: true
51
+ };
52
+ }
53
+ };
54
+ }
55
+ //#endregion
56
+ export { STRUCTURED_OUTPUT_TOOL_NAME, createStructuredOutputTool };
57
+
58
+ //# sourceMappingURL=structured-output-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structured-output-tool.js","names":[],"sources":["../../../../src/agent/workflow/structured-output-tool.ts"],"sourcesContent":["/**\n * `structured_output` — terminating tool used to capture a subagent's final result.\n *\n * Injected into a subagent's toolset only when the workflow script asked for\n * structured output via `agent(prompt, { schema })`. The subagent is instructed\n * to invoke this tool exactly once with its final result; the tool sets\n * `terminate: true` so the agent loop stops without paying for an extra\n * assistant turn.\n *\n * Validation is done with ajv (already a xopc dep). pi-agent-core also validates\n * arguments against `parameters` before calling `execute`, but we re-check here\n * to (1) surface a clear error message back to the model when the schema is\n * non-trivial, and (2) avoid trusting the upstream layer's validator strictness.\n *\n * Note: the file is named `structured-output-tool.ts` to avoid clashing with the\n * existing `src/agent/tools/structured-output.ts` (an XML Element builder — a\n * completely unrelated utility).\n */\n\nimport Ajv, { type ValidateFunction } from 'ajv';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport type { TSchema } from '@sinclair/typebox';\n\nimport type { JsonSchema } from './types.js';\n\nexport const STRUCTURED_OUTPUT_TOOL_NAME = 'structured_output';\n\nexport interface StructuredOutputCapture<T = unknown> {\n called: boolean;\n value?: T;\n}\n\nexport interface CreateStructuredOutputToolOptions<T = unknown> {\n schema: JsonSchema;\n capture: StructuredOutputCapture<T>;\n /** Override the tool name (rarely needed; default `structured_output`). */\n name?: string;\n}\n\n// One Ajv instance per schema is fine — Ajv caches compiled validators internally.\n// We re-use a singleton to avoid the per-call construction cost.\nconst ajv = new Ajv({ allErrors: true, strict: false });\n\nexport function createStructuredOutputTool<T = unknown>(\n options: CreateStructuredOutputToolOptions<T>,\n): AgentTool<TSchema, T> {\n const name = options.name ?? STRUCTURED_OUTPUT_TOOL_NAME;\n const validator: ValidateFunction = ajv.compile(options.schema);\n\n return {\n name,\n label: 'Structured Output',\n description:\n 'Return the final machine-readable result for this subagent task. ' +\n 'Call this tool exactly once when finished. Do not emit a prose final answer afterwards.',\n parameters: options.schema as unknown as TSchema,\n async execute(\n _toolCallId: string,\n params: unknown,\n ): Promise<AgentToolResult<T>> {\n const valid = validator(params);\n if (!valid) {\n const reason = ajv.errorsText(validator.errors, { separator: '; ' });\n // Do NOT terminate on invalid input — let the model retry within the same run.\n return {\n content: [\n {\n type: 'text',\n text: `structured_output: invalid arguments — ${reason}. Adjust and call structured_output again.`,\n },\n ],\n details: params as T,\n };\n }\n options.capture.called = true;\n options.capture.value = params as T;\n return {\n content: [{ type: 'text', text: 'Structured output received.' }],\n details: params as T,\n terminate: true,\n };\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,8BAA8B;AAgB3C,MAAM,MAAM,IAAI,IAAI;CAAE,WAAW;CAAM,QAAQ;CAAO,CAAC;AAEvD,SAAgB,2BACd,SACuB;CACvB,MAAM,OAAO,QAAQ,QAAA;CACrB,MAAM,YAA8B,IAAI,QAAQ,QAAQ,OAAO;AAE/D,QAAO;EACL;EACA,OAAO;EACP,aACE;EAEF,YAAY,QAAQ;EACpB,MAAM,QACJ,aACA,QAC6B;AAE7B,OAAI,CADU,UAAU,OACd,CAGR,QAAO;IACL,SAAS,CACP;KACE,MAAM;KACN,MAAM,0CANG,IAAI,WAAW,UAAU,QAAQ,EAAE,WAAW,MAAM,CAMP,CAAC;KACxD,CACF;IACD,SAAS;IACV;AAEH,WAAQ,QAAQ,SAAS;AACzB,WAAQ,QAAQ,QAAQ;AACxB,UAAO;IACL,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM;KAA+B,CAAC;IAChE,SAAS;IACT,WAAW;IACZ;;EAEJ"}