@elizaos/agent 2.0.3-beta.2 → 2.0.3-beta.4

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 (381) hide show
  1. package/__tests__/view-user-journeys.d.ts.map +1 -1
  2. package/__tests__/view-user-journeys.js +52 -41
  3. package/actions/context-signal.d.ts +2 -2
  4. package/actions/files.d.ts +9 -0
  5. package/actions/files.d.ts.map +1 -0
  6. package/actions/files.js +183 -0
  7. package/actions/index.d.ts +17 -17
  8. package/api/accounts-routes.d.ts +1 -1
  9. package/api/accounts-routes.js +1 -1
  10. package/api/agent-admin-routes.d.ts +1 -1
  11. package/api/agent-admin-routes.js +2 -2
  12. package/api/agent-model.d.ts +1 -1
  13. package/api/agent-status-routes.d.ts +1 -3
  14. package/api/agent-status-routes.d.ts.map +1 -1
  15. package/api/agent-status-routes.js +0 -2
  16. package/api/approval-routes.d.ts +38 -0
  17. package/api/approval-routes.d.ts.map +1 -0
  18. package/api/approval-routes.js +223 -0
  19. package/api/background-routes.d.ts +13 -0
  20. package/api/background-routes.d.ts.map +1 -0
  21. package/api/background-routes.js +91 -0
  22. package/api/binance-skill-helpers.d.ts +2 -2
  23. package/api/binance-skill-helpers.js +2 -2
  24. package/api/builtin-views.d.ts.map +1 -1
  25. package/api/builtin-views.js +44 -4
  26. package/api/character-routes.d.ts +1 -1
  27. package/api/chat-augmentation.d.ts.map +1 -1
  28. package/api/chat-augmentation.js +17 -0
  29. package/api/chat-routes.d.ts +29 -2
  30. package/api/chat-routes.d.ts.map +1 -1
  31. package/api/chat-routes.js +76 -1
  32. package/api/commands-routes.d.ts +10 -8
  33. package/api/commands-routes.d.ts.map +1 -1
  34. package/api/commands-routes.js +17 -59
  35. package/api/config-routes.d.ts +1 -1
  36. package/api/config-routes.d.ts.map +1 -1
  37. package/api/config-routes.js +0 -2
  38. package/api/connector-routes.d.ts +1 -1
  39. package/api/conversation-metadata.d.ts +1 -1
  40. package/api/conversation-metadata.d.ts.map +1 -1
  41. package/api/conversation-metadata.js +0 -1
  42. package/api/conversation-routes.d.ts +4 -3
  43. package/api/conversation-routes.d.ts.map +1 -1
  44. package/api/conversation-routes.js +34 -1
  45. package/api/documents-service-loader.d.ts +0 -4
  46. package/api/documents-service-loader.d.ts.map +1 -1
  47. package/api/documents-service-loader.js +0 -2
  48. package/api/files-routes.d.ts +14 -0
  49. package/api/files-routes.d.ts.map +1 -0
  50. package/api/files-routes.js +47 -0
  51. package/api/first-run-routes.d.ts +1 -1
  52. package/api/health-routes.d.ts +2 -2
  53. package/api/index.d.ts +40 -39
  54. package/api/index.d.ts.map +1 -1
  55. package/api/index.js +1 -0
  56. package/api/interactions-routes.d.ts +33 -0
  57. package/api/interactions-routes.d.ts.map +1 -0
  58. package/api/interactions-routes.js +63 -0
  59. package/api/media-runtime.d.ts +2 -1
  60. package/api/media-runtime.d.ts.map +1 -1
  61. package/api/media-runtime.js +64 -7
  62. package/api/media-store.d.ts +36 -0
  63. package/api/media-store.d.ts.map +1 -1
  64. package/api/media-store.js +141 -2
  65. package/api/memory-bounds.d.ts +0 -1
  66. package/api/memory-bounds.d.ts.map +1 -1
  67. package/api/memory-bounds.js +0 -1
  68. package/api/misc-routes.d.ts +1 -1
  69. package/api/model-provider-helpers.d.ts +2 -2
  70. package/api/model-provider-helpers.js +2 -2
  71. package/api/permissions-routes-extra.d.ts +1 -1
  72. package/api/permissions-routes.d.ts +1 -1
  73. package/api/permissions-routes.d.ts.map +1 -1
  74. package/api/permissions-routes.js +8 -7
  75. package/api/plugin-discovery-helpers.d.ts +5 -6
  76. package/api/plugin-discovery-helpers.d.ts.map +1 -1
  77. package/api/plugin-discovery-helpers.js +3 -4
  78. package/api/plugin-runtime-apply.d.ts +2 -2
  79. package/api/plugin-runtime-apply.d.ts.map +1 -1
  80. package/api/plugin-runtime-apply.js +74 -0
  81. package/api/provider-switch-config.d.ts +1 -1
  82. package/api/provider-switch-routes.d.ts +2 -2
  83. package/api/registry-routes.d.ts +1 -1
  84. package/api/registry-service.d.ts +1 -1
  85. package/api/remote-capability-routes.d.ts +2 -2
  86. package/api/remote-capability-routes.d.ts.map +1 -1
  87. package/api/remote-capability-routes.js +19 -0
  88. package/api/server-autonomy-helpers.d.ts +2 -2
  89. package/api/server-helpers-auth.d.ts +10 -0
  90. package/api/server-helpers-auth.d.ts.map +1 -1
  91. package/api/server-helpers-auth.js +16 -210
  92. package/api/server-helpers-config.d.ts +1 -1
  93. package/api/server-helpers-mcp.d.ts +2 -2
  94. package/api/server-helpers-plugin.d.ts +1 -1
  95. package/api/server-helpers-swarm.d.ts +3 -3
  96. package/api/server-helpers-swarm.d.ts.map +1 -1
  97. package/api/server-helpers-swarm.js +15 -5
  98. package/api/server-helpers-wallet.d.ts +1 -1
  99. package/api/server-helpers.d.ts +4 -4
  100. package/api/server-lazy-routes.d.ts +40 -38
  101. package/api/server-lazy-routes.d.ts.map +1 -1
  102. package/api/server-lazy-routes.js +7 -0
  103. package/api/server-route-dispatch.d.ts +2 -2
  104. package/api/server-route-dispatch.d.ts.map +1 -1
  105. package/api/server-route-dispatch.js +7 -0
  106. package/api/server-types.d.ts +9 -7
  107. package/api/server-types.d.ts.map +1 -1
  108. package/api/server.d.ts +19 -19
  109. package/api/server.d.ts.map +1 -1
  110. package/api/server.js +111 -17
  111. package/api/static-file-server.d.ts +2 -2
  112. package/api/static-file-server.js +2 -2
  113. package/api/subscription-routes.d.ts +4 -4
  114. package/api/subscription-routes.js +3 -4
  115. package/api/suggestions-routes.d.ts +1 -1
  116. package/api/suggestions-routes.d.ts.map +1 -1
  117. package/api/suggestions-routes.js +2 -3
  118. package/api/terminal-execution-routing.d.ts +1 -1
  119. package/api/training-service-like.d.ts +1 -1
  120. package/api/trajectory-fallback-routes.d.ts.map +1 -1
  121. package/api/trajectory-fallback-routes.js +21 -1
  122. package/api/update-routes.d.ts +1 -1
  123. package/api/view-registry-types.d.ts +1 -1
  124. package/api/views-registry.d.ts +14 -4
  125. package/api/views-registry.d.ts.map +1 -1
  126. package/api/views-registry.js +107 -72
  127. package/api/views-routes.d.ts +1 -1
  128. package/api/views-routes.d.ts.map +1 -1
  129. package/api/views-routes.js +131 -14
  130. package/api/views-search-index.d.ts +1 -1
  131. package/api/wallet-capability.d.ts +3 -3
  132. package/api/wallet-rpc.d.ts +1 -1
  133. package/api/wallet.d.ts +3 -3
  134. package/api/wallet.d.ts.map +1 -1
  135. package/api/wallet.js +4 -3
  136. package/api/workbench-context.d.ts +1 -1
  137. package/api/workbench-helpers.d.ts +3 -3
  138. package/api/workbench-helpers.js +3 -3
  139. package/api/workbench-routes.d.ts +2 -2
  140. package/api/workbench-vfs-routes.d.ts +1 -1
  141. package/api/ws-event-replay.d.ts +1 -2
  142. package/api/ws-event-replay.d.ts.map +1 -1
  143. package/api/ws-event-replay.js +1 -2
  144. package/api/x-relay-routes.d.ts +2 -2
  145. package/api/x402-route-validation.d.ts +4 -0
  146. package/api/x402-route-validation.d.ts.map +1 -0
  147. package/api/x402-route-validation.js +6 -0
  148. package/assets/view-heroes/background.png +0 -0
  149. package/auth/account-storage.d.ts +1 -1
  150. package/auth/anthropic.d.ts +1 -1
  151. package/auth/credentials.d.ts +2 -2
  152. package/auth/index.d.ts +7 -7
  153. package/auth/oauth-flow.d.ts +2 -2
  154. package/auth/openai-codex.d.ts +1 -1
  155. package/awareness/index.d.ts +1 -1
  156. package/config/config.js +0 -1
  157. package/config/env-vars.d.ts +1 -1
  158. package/config/env-vars.d.ts.map +1 -1
  159. package/config/env-vars.js +0 -1
  160. package/config/index.d.ts +10 -10
  161. package/config/model-metadata.d.ts +1 -1
  162. package/config/owner-contacts.d.ts +1 -1
  163. package/config/schema.d.ts +1 -1
  164. package/hooks/discovery.d.ts +1 -1
  165. package/hooks/eligibility.d.ts +2 -2
  166. package/hooks/index.d.ts +2 -2
  167. package/hooks/loader.d.ts +2 -2
  168. package/hooks/registry.d.ts +1 -1
  169. package/index.d.ts +87 -85
  170. package/index.d.ts.map +1 -1
  171. package/index.js +11 -3
  172. package/package.json +54 -44
  173. package/providers/media-provider.d.ts +1 -1
  174. package/providers/page-scoped-context.d.ts.map +1 -1
  175. package/providers/page-scoped-context.js +1 -70
  176. package/providers/relevant-conversations.d.ts.map +1 -1
  177. package/providers/relevant-conversations.js +8 -9
  178. package/providers/workspace.d.ts +1 -1
  179. package/runtime/actions/web-fetch.d.ts.map +1 -1
  180. package/runtime/actions/web-fetch.js +23 -3
  181. package/runtime/actions/web-search.d.ts +32 -0
  182. package/runtime/actions/web-search.d.ts.map +1 -0
  183. package/runtime/actions/web-search.js +245 -0
  184. package/runtime/advanced-capabilities-config.d.ts +1 -1
  185. package/runtime/boot-telemetry.d.ts +1 -1
  186. package/runtime/conversation-compactor-runtime.d.ts +1 -1
  187. package/runtime/conversation-compactor-runtime.js +1 -1
  188. package/runtime/conversation-compactor.d.ts +1 -1
  189. package/runtime/core-plugins.d.ts.map +1 -1
  190. package/runtime/core-plugins.js +9 -0
  191. package/runtime/custom-actions.d.ts +18 -9
  192. package/runtime/custom-actions.d.ts.map +1 -1
  193. package/runtime/custom-actions.js +85 -23
  194. package/runtime/eliza-plugin.d.ts.map +1 -1
  195. package/runtime/eliza-plugin.js +15 -1
  196. package/runtime/eliza.d.ts +9 -7
  197. package/runtime/eliza.d.ts.map +1 -1
  198. package/runtime/eliza.js +86 -23
  199. package/runtime/first-time-setup.d.ts +1 -3
  200. package/runtime/first-time-setup.d.ts.map +1 -1
  201. package/runtime/first-time-setup.js +0 -2
  202. package/runtime/index.d.ts +18 -18
  203. package/runtime/load-plugin-from-vfs.d.ts +2 -2
  204. package/runtime/mobile-dns.d.ts.map +1 -1
  205. package/runtime/mobile-dns.js +2 -5
  206. package/runtime/operations/classifier.d.ts +1 -1
  207. package/runtime/operations/cold-strategy.d.ts +1 -1
  208. package/runtime/operations/health-checks.d.ts +1 -1
  209. package/runtime/operations/health.d.ts +1 -1
  210. package/runtime/operations/index.d.ts +10 -10
  211. package/runtime/operations/manager.d.ts +3 -3
  212. package/runtime/operations/reload-hot.d.ts +1 -1
  213. package/runtime/operations/repository.d.ts +1 -1
  214. package/runtime/operations/vault-bridge.d.ts +1 -1
  215. package/runtime/plugin-collector.d.ts +6 -1
  216. package/runtime/plugin-collector.d.ts.map +1 -1
  217. package/runtime/plugin-collector.js +11 -28
  218. package/runtime/plugin-lifecycle.d.ts.map +1 -1
  219. package/runtime/plugin-lifecycle.js +1 -0
  220. package/runtime/plugin-resolver.d.ts +2 -2
  221. package/runtime/plugin-resolver.d.ts.map +1 -1
  222. package/runtime/plugin-resolver.js +113 -65
  223. package/runtime/plugin-types.d.ts +1 -1
  224. package/runtime/prompt-optimization.d.ts +4 -4
  225. package/runtime/remote-coding-runner-gate.d.ts +7 -0
  226. package/runtime/remote-coding-runner-gate.d.ts.map +1 -0
  227. package/runtime/remote-coding-runner-gate.js +36 -0
  228. package/runtime/roles/src/index.d.ts +4 -4
  229. package/runtime/roles.d.ts +2 -2
  230. package/runtime/sandbox-character.d.ts +1 -1
  231. package/runtime/tool-call-cache/cache.d.ts +1 -1
  232. package/runtime/tool-call-cache/disk-store.d.ts +1 -1
  233. package/runtime/tool-call-cache/index.d.ts +6 -6
  234. package/runtime/tool-call-cache/key.d.ts +1 -1
  235. package/runtime/tool-call-cache/redact.d.ts +1 -1
  236. package/runtime/tool-call-cache/registry.d.ts +1 -1
  237. package/runtime/tool-call-cache-wrapper.d.ts +7 -9
  238. package/runtime/tool-call-cache-wrapper.d.ts.map +1 -1
  239. package/runtime/tool-call-cache-wrapper.js +6 -11
  240. package/runtime/trajectory-export.d.ts +3 -3
  241. package/runtime/trajectory-internals.d.ts +2 -1
  242. package/runtime/trajectory-internals.d.ts.map +1 -1
  243. package/runtime/trajectory-persistence.d.ts +5 -5
  244. package/runtime/trajectory-steps-reader.d.ts +1 -1
  245. package/runtime/trajectory-steps-writer.d.ts +1 -1
  246. package/runtime/trajectory-storage.d.ts +4 -4
  247. package/runtime/view-action-affinity.d.ts +18 -15
  248. package/runtime/view-action-affinity.d.ts.map +1 -1
  249. package/runtime/view-action-affinity.js +26 -29
  250. package/runtime/web-search-tools.d.ts +4 -1
  251. package/runtime/web-search-tools.d.ts.map +1 -1
  252. package/runtime/web-search-tools.js +37 -9
  253. package/security/index.d.ts +3 -3
  254. package/services/approval/index.d.ts +9 -0
  255. package/services/approval/index.d.ts.map +1 -0
  256. package/services/approval/index.js +8 -0
  257. package/services/approval/service.d.ts +35 -0
  258. package/services/approval/service.d.ts.map +1 -0
  259. package/services/approval/service.js +40 -0
  260. package/services/approval/sql.d.ts +18 -0
  261. package/services/approval/sql.d.ts.map +1 -0
  262. package/services/approval/sql.js +104 -0
  263. package/services/approval/store.d.ts +39 -0
  264. package/services/approval/store.d.ts.map +1 -0
  265. package/services/approval/store.js +534 -0
  266. package/services/approval/types.d.ts +207 -0
  267. package/services/approval/types.d.ts.map +1 -0
  268. package/services/approval/types.js +34 -0
  269. package/services/character-persistence.d.ts +2 -2
  270. package/services/client-chat-sender.d.ts +1 -1
  271. package/services/config-plugin-manager.d.ts +2 -2
  272. package/services/connector-setup-service.d.ts +1 -1
  273. package/services/cove-quote-x509.d.ts +1 -1
  274. package/services/cove-quote.d.ts +2 -2
  275. package/services/dstack-tee-provider.d.ts +1 -1
  276. package/services/file-storage.d.ts +20 -0
  277. package/services/file-storage.d.ts.map +1 -0
  278. package/services/file-storage.js +70 -0
  279. package/services/global-pause/index.d.ts +8 -0
  280. package/services/global-pause/index.d.ts.map +1 -0
  281. package/services/global-pause/index.js +7 -0
  282. package/services/global-pause/service.d.ts +29 -0
  283. package/services/global-pause/service.d.ts.map +1 -0
  284. package/services/global-pause/service.js +34 -0
  285. package/services/global-pause/store.d.ts +31 -0
  286. package/services/global-pause/store.d.ts.map +1 -0
  287. package/services/global-pause/store.js +83 -0
  288. package/services/handoff/index.d.ts +8 -0
  289. package/services/handoff/index.d.ts.map +1 -0
  290. package/services/handoff/index.js +7 -0
  291. package/services/handoff/service.d.ts +29 -0
  292. package/services/handoff/service.d.ts.map +1 -0
  293. package/services/handoff/service.js +34 -0
  294. package/services/handoff/store.d.ts +76 -0
  295. package/services/handoff/store.d.ts.map +1 -0
  296. package/services/handoff/store.js +148 -0
  297. package/services/index.d.ts +30 -31
  298. package/services/index.d.ts.map +1 -1
  299. package/services/index.js +0 -6
  300. package/services/js-runtime-bridge.d.ts.map +1 -1
  301. package/services/js-runtime-bridge.js +8 -2
  302. package/services/knowledge-graph/index.d.ts +4 -4
  303. package/services/knowledge-graph/service.d.ts +2 -2
  304. package/services/pending-prompts/index.d.ts +8 -0
  305. package/services/pending-prompts/index.d.ts.map +1 -0
  306. package/services/pending-prompts/index.js +7 -0
  307. package/services/pending-prompts/service.d.ts +34 -0
  308. package/services/pending-prompts/service.d.ts.map +1 -0
  309. package/services/pending-prompts/service.js +68 -0
  310. package/services/pending-prompts/store.d.ts +70 -0
  311. package/services/pending-prompts/store.d.ts.map +1 -0
  312. package/services/pending-prompts/store.js +191 -0
  313. package/services/plugin-compiler.d.ts +1 -1
  314. package/services/plugin-installer.d.ts.map +1 -1
  315. package/services/plugin-installer.js +21 -11
  316. package/services/plugin-manager-types.d.ts +1 -1
  317. package/services/proactive-interaction-decider.d.ts +62 -11
  318. package/services/proactive-interaction-decider.d.ts.map +1 -1
  319. package/services/proactive-interaction-decider.js +223 -35
  320. package/services/push/apns-provider.d.ts +1 -1
  321. package/services/push/fcm-provider.d.ts +1 -1
  322. package/services/push/notification-push-service.d.ts +2 -2
  323. package/services/registry-client-app-meta.d.ts +1 -1
  324. package/services/registry-client-endpoints.d.ts +2 -2
  325. package/services/registry-client-local.d.ts +1 -1
  326. package/services/registry-client-network.d.ts +1 -1
  327. package/services/registry-client-queries.d.ts +1 -1
  328. package/services/registry-client.d.ts +3 -3
  329. package/services/relationships-graph.d.ts +1 -1
  330. package/services/remote-capability-cloud-sandbox.d.ts +3 -3
  331. package/services/remote-capability-endpoint-conformance.d.ts +1 -1
  332. package/services/remote-capability-endpoint-provider.d.ts +4 -4
  333. package/services/remote-capability-url-endpoint-providers.d.ts +1 -1
  334. package/services/remote-plugin-adapter.d.ts.map +1 -1
  335. package/services/remote-plugin-adapter.js +3 -0
  336. package/services/remote-plugin-bridge.d.ts.map +1 -1
  337. package/services/remote-plugin-bridge.js +97 -26
  338. package/services/remote-signing-service.d.ts +4 -4
  339. package/services/research-task-executor.d.ts +1 -1
  340. package/services/sandbox-manager.d.ts +1 -1
  341. package/services/self-updater.d.ts +1 -1
  342. package/services/self-updater.d.ts.map +1 -1
  343. package/services/self-updater.js +23 -9
  344. package/services/shell-execution-router.d.ts +1 -1
  345. package/services/shell-execution-router.d.ts.map +1 -1
  346. package/services/shell-execution-router.js +19 -2
  347. package/services/tee-boot-gate-state.d.ts +1 -1
  348. package/services/tee-boot-gate.d.ts +4 -4
  349. package/services/tee-confidential-inference.d.ts +3 -3
  350. package/services/tee-key-release.d.ts +2 -2
  351. package/services/tee-model-key-boot.d.ts +4 -4
  352. package/services/tee-policy.d.ts +1 -1
  353. package/services/tee-production-profile.d.ts +1 -1
  354. package/services/tee-release-policy.d.ts +1 -1
  355. package/services/tee-revocation.d.ts +2 -2
  356. package/services/tee-runtime-config.d.ts +1 -1
  357. package/services/tee-sealed-volume.d.ts +3 -3
  358. package/services/tee-signer-backend.d.ts +3 -3
  359. package/services/update-checker.d.ts +1 -1
  360. package/services/vault-signer-backend.d.ts +1 -1
  361. package/services/vfs-git.d.ts +1 -1
  362. package/test-support/index.d.ts +3 -3
  363. package/triggers/runtime.d.ts +1 -1
  364. package/triggers/scheduling.d.ts +3 -22
  365. package/triggers/scheduling.d.ts.map +1 -1
  366. package/triggers/scheduling.js +2 -214
  367. package/tui/agent-terminal-tui.d.ts.map +1 -1
  368. package/tui/agent-terminal-tui.js +174 -72
  369. package/types/index.d.ts +3 -3
  370. package/api/nfa-routes.d.ts +0 -6
  371. package/api/nfa-routes.d.ts.map +0 -1
  372. package/api/nfa-routes.js +0 -125
  373. package/api/server-auth.d.ts +0 -46
  374. package/api/server-auth.d.ts.map +0 -1
  375. package/api/server-auth.js +0 -504
  376. package/runtime/restart.d.ts +0 -9
  377. package/runtime/restart.d.ts.map +0 -1
  378. package/runtime/restart.js +0 -8
  379. package/test-utils/sqlite-compat.d.ts +0 -23
  380. package/test-utils/sqlite-compat.d.ts.map +0 -1
  381. package/test-utils/sqlite-compat.js +0 -214
@@ -0,0 +1,534 @@
1
+ /**
2
+ * `PgApprovalQueue` — concrete approval queue backed by the `approval_requests`
3
+ * table from `@elizaos/plugin-sql` (public schema, no schema prefix).
4
+ *
5
+ * Promoted from `@elizaos/plugin-personal-assistant`'s `lifeops/approval-queue.ts`
6
+ * into a first-class `@elizaos/agent` runtime store (LifeOps Slice 4). The raw
7
+ * SQL is unchanged — it has no schema prefix, so it targets plugin-sql's public
8
+ * `approval_requests` table exactly as before. There is no data migration.
9
+ *
10
+ * Design notes:
11
+ * - The state-transition table below is the single source of truth for
12
+ * legal moves. Anything not enumerated throws
13
+ * `ApprovalStateTransitionError` — there is no fallback, no auto-retry,
14
+ * no silent normalization (Commandment 8).
15
+ * - All logging goes through the structured logger only (Commandment 9).
16
+ * - Each row is scoped to an agent via `agentId`. Cross-agent access is
17
+ * not supported.
18
+ */
19
+ import { randomUUID } from "node:crypto";
20
+ import { logger, ServiceType } from "@elizaos/core";
21
+ import { executeRawSql, parseJsonRecord, sqlInteger, sqlJson, sqlText, toText, } from "./sql.js";
22
+ import { ApprovalNotFoundError, ApprovalStateTransitionError, } from "./types.js";
23
+ const ALLOWED_TRANSITIONS = {
24
+ pending: ["approved", "rejected", "expired"],
25
+ approved: ["executing", "rejected"],
26
+ executing: ["done"],
27
+ done: [],
28
+ rejected: [],
29
+ expired: [],
30
+ };
31
+ function assertTransition(id, from, to) {
32
+ if (!ALLOWED_TRANSITIONS[from].includes(to)) {
33
+ throw new ApprovalStateTransitionError(id, from, to);
34
+ }
35
+ }
36
+ const VALID_STATES = new Set([
37
+ "pending",
38
+ "approved",
39
+ "executing",
40
+ "done",
41
+ "rejected",
42
+ "expired",
43
+ ]);
44
+ const VALID_ACTIONS = new Set([
45
+ "send_message",
46
+ "send_email",
47
+ "schedule_event",
48
+ "modify_event",
49
+ "cancel_event",
50
+ "book_travel",
51
+ "make_call",
52
+ "sign_document",
53
+ "execute_workflow",
54
+ "spend_money",
55
+ ]);
56
+ const VALID_CHANNELS = new Set([
57
+ "telegram",
58
+ "discord",
59
+ "slack",
60
+ "imessage",
61
+ "sms",
62
+ "x_dm",
63
+ "email",
64
+ "google_calendar",
65
+ "browser",
66
+ "phone",
67
+ "internal",
68
+ ]);
69
+ function isRecord(value) {
70
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
71
+ }
72
+ function parseState(value) {
73
+ const text = toText(value);
74
+ if (!VALID_STATES.has(text)) {
75
+ throw new Error(`[ApprovalQueue] unknown state from db: ${text}`);
76
+ }
77
+ return text;
78
+ }
79
+ function parseAction(value) {
80
+ const text = toText(value);
81
+ if (!VALID_ACTIONS.has(text)) {
82
+ throw new Error(`[ApprovalQueue] unknown action from db: ${text}`);
83
+ }
84
+ return text;
85
+ }
86
+ function parseChannel(value) {
87
+ const text = toText(value);
88
+ if (!VALID_CHANNELS.has(text)) {
89
+ throw new Error(`[ApprovalQueue] unknown channel from db: ${text}`);
90
+ }
91
+ return text;
92
+ }
93
+ function parseTimestamp(value) {
94
+ if (value instanceof Date)
95
+ return value;
96
+ const text = toText(value);
97
+ if (!text) {
98
+ throw new Error("[ApprovalQueue] missing timestamp from db");
99
+ }
100
+ const date = new Date(text);
101
+ if (Number.isNaN(date.getTime())) {
102
+ throw new Error(`[ApprovalQueue] invalid timestamp from db: ${text}`);
103
+ }
104
+ return date;
105
+ }
106
+ function parseOptionalTimestamp(value) {
107
+ if (value === null || value === undefined || value === "")
108
+ return null;
109
+ return parseTimestamp(value);
110
+ }
111
+ function parseOptionalText(value) {
112
+ if (value === null || value === undefined)
113
+ return null;
114
+ const text = toText(value);
115
+ return text === "" ? null : text;
116
+ }
117
+ function requireRecord(value, label) {
118
+ if (!isRecord(value)) {
119
+ throw new Error(`[ApprovalQueue] invalid ${label}: expected object`);
120
+ }
121
+ return value;
122
+ }
123
+ function requireStringField(record, field, label) {
124
+ if (typeof record[field] !== "string") {
125
+ throw new Error(`[ApprovalQueue] invalid ${label}.${field}: expected string`);
126
+ }
127
+ }
128
+ function requireNullableStringField(record, field, label) {
129
+ const value = record[field];
130
+ if (value !== null && typeof value !== "string") {
131
+ throw new Error(`[ApprovalQueue] invalid ${label}.${field}: expected string or null`);
132
+ }
133
+ }
134
+ function requireOptionalNullableStringField(record, field, label) {
135
+ if (record[field] === undefined) {
136
+ return;
137
+ }
138
+ requireNullableStringField(record, field, label);
139
+ }
140
+ function requireStringArrayField(record, field, label) {
141
+ const value = record[field];
142
+ if (!Array.isArray(value) ||
143
+ value.some((entry) => typeof entry !== "string")) {
144
+ throw new Error(`[ApprovalQueue] invalid ${label}.${field}: expected string[]`);
145
+ }
146
+ }
147
+ function requireFiniteNumberField(record, field, label) {
148
+ const value = record[field];
149
+ if (typeof value !== "number" || !Number.isFinite(value)) {
150
+ throw new Error(`[ApprovalQueue] invalid ${label}.${field}: expected number`);
151
+ }
152
+ }
153
+ function requireNullableFiniteNumberField(record, field, label) {
154
+ const value = record[field];
155
+ if (value !== null &&
156
+ (typeof value !== "number" || !Number.isFinite(value))) {
157
+ throw new Error(`[ApprovalQueue] invalid ${label}.${field}: expected number or null`);
158
+ }
159
+ }
160
+ function requireBooleanField(record, field, label) {
161
+ if (typeof record[field] !== "boolean") {
162
+ throw new Error(`[ApprovalQueue] invalid ${label}.${field}: expected boolean`);
163
+ }
164
+ }
165
+ function requireOptionalRecordField(record, field, label) {
166
+ const value = record[field];
167
+ if (value !== undefined && value !== null && !isRecord(value)) {
168
+ throw new Error(`[ApprovalQueue] invalid ${label}.${field}: expected object or null`);
169
+ }
170
+ }
171
+ function requirePrimitiveRecordField(record, field, label) {
172
+ const value = requireRecord(record[field], `${label}.${field}`);
173
+ for (const [key, entry] of Object.entries(value)) {
174
+ if (typeof entry !== "string" &&
175
+ typeof entry !== "number" &&
176
+ typeof entry !== "boolean") {
177
+ throw new Error(`[ApprovalQueue] invalid ${label}.${field}.${key}: expected string, number, or boolean`);
178
+ }
179
+ }
180
+ }
181
+ function requireTravelPassengers(record, label) {
182
+ const passengers = record.passengers;
183
+ if (passengers === undefined) {
184
+ return;
185
+ }
186
+ if (!Array.isArray(passengers)) {
187
+ throw new Error(`[ApprovalQueue] invalid ${label}.passengers: expected array`);
188
+ }
189
+ passengers.forEach((passenger, index) => {
190
+ const passengerRecord = requireRecord(passenger, `${label}.passengers[${index}]`);
191
+ requireStringField(passengerRecord, "givenName", `${label}.passengers[${index}]`);
192
+ requireStringField(passengerRecord, "familyName", `${label}.passengers[${index}]`);
193
+ requireStringField(passengerRecord, "bornOn", `${label}.passengers[${index}]`);
194
+ for (const field of [
195
+ "offerPassengerId",
196
+ "email",
197
+ "phoneNumber",
198
+ "title",
199
+ "gender",
200
+ ]) {
201
+ requireOptionalNullableStringField(passengerRecord, field, `${label}.passengers[${index}]`);
202
+ }
203
+ });
204
+ }
205
+ function requireTravelCalendarSync(record, label) {
206
+ const value = record.calendarSync;
207
+ if (value === undefined || value === null) {
208
+ return;
209
+ }
210
+ const calendarSync = requireRecord(value, `${label}.calendarSync`);
211
+ requireBooleanField(calendarSync, "enabled", `${label}.calendarSync`);
212
+ for (const field of [
213
+ "calendarId",
214
+ "title",
215
+ "description",
216
+ "location",
217
+ "timeZone",
218
+ ]) {
219
+ requireOptionalNullableStringField(calendarSync, field, `${label}.calendarSync`);
220
+ }
221
+ }
222
+ function requireTravelCost(record, label) {
223
+ const value = record.cost;
224
+ if (value === undefined || value === null) {
225
+ return;
226
+ }
227
+ const cost = requireRecord(value, `${label}.cost`);
228
+ requireFiniteNumberField(cost, "totalUsd", `${label}.cost`);
229
+ requireFiniteNumberField(cost, "creatorMarkupUsd", `${label}.cost`);
230
+ requireFiniteNumberField(cost, "platformFeeUsd", `${label}.cost`);
231
+ requireNullableFiniteNumberField(cost, "markupPercent", `${label}.cost`);
232
+ }
233
+ function requirePaymentRequired(record, label) {
234
+ const value = record.paymentRequired;
235
+ if (value === undefined || value === null) {
236
+ return;
237
+ }
238
+ const payment = requireRecord(value, `${label}.paymentRequired`);
239
+ for (const field of ["amount", "asset", "network", "payTo", "scheme"]) {
240
+ requireStringField(payment, field, `${label}.paymentRequired`);
241
+ }
242
+ requireNullableStringField(payment, "expiresAt", `${label}.paymentRequired`);
243
+ requireNullableStringField(payment, "description", `${label}.paymentRequired`);
244
+ }
245
+ function assertApprovalPayload(record, action, label) {
246
+ switch (action) {
247
+ case "send_message":
248
+ requireStringField(record, "recipient", label);
249
+ requireStringField(record, "body", label);
250
+ requireNullableStringField(record, "replyToMessageId", label);
251
+ break;
252
+ case "send_email":
253
+ requireStringArrayField(record, "to", label);
254
+ requireStringArrayField(record, "cc", label);
255
+ requireStringArrayField(record, "bcc", label);
256
+ requireStringField(record, "subject", label);
257
+ requireStringField(record, "body", label);
258
+ requireNullableStringField(record, "threadId", label);
259
+ requireOptionalNullableStringField(record, "replyToMessageId", label);
260
+ break;
261
+ case "schedule_event":
262
+ requireStringField(record, "calendarId", label);
263
+ requireStringField(record, "title", label);
264
+ requireFiniteNumberField(record, "startsAtMs", label);
265
+ requireFiniteNumberField(record, "endsAtMs", label);
266
+ requireStringArrayField(record, "attendees", label);
267
+ requireNullableStringField(record, "location", label);
268
+ requireNullableStringField(record, "description", label);
269
+ break;
270
+ case "modify_event": {
271
+ requireStringField(record, "calendarId", label);
272
+ requireStringField(record, "eventId", label);
273
+ const patch = requireRecord(record.patch, `${label}.patch`);
274
+ requireNullableStringField(patch, "title", `${label}.patch`);
275
+ requireNullableFiniteNumberField(patch, "startsAtMs", `${label}.patch`);
276
+ requireNullableFiniteNumberField(patch, "endsAtMs", `${label}.patch`);
277
+ const attendees = patch.attendees;
278
+ if (attendees !== null &&
279
+ (!Array.isArray(attendees) ||
280
+ attendees.some((entry) => typeof entry !== "string"))) {
281
+ throw new Error(`[ApprovalQueue] invalid ${label}.patch.attendees: expected string[] or null`);
282
+ }
283
+ requireNullableStringField(patch, "location", `${label}.patch`);
284
+ requireNullableStringField(patch, "description", `${label}.patch`);
285
+ break;
286
+ }
287
+ case "cancel_event":
288
+ requireStringField(record, "calendarId", label);
289
+ requireStringField(record, "eventId", label);
290
+ requireBooleanField(record, "notifyAttendees", label);
291
+ break;
292
+ case "book_travel":
293
+ if (record.kind !== "flight" &&
294
+ record.kind !== "hotel" &&
295
+ record.kind !== "ground") {
296
+ throw new Error(`[ApprovalQueue] invalid ${label}.kind`);
297
+ }
298
+ requireStringField(record, "provider", label);
299
+ requireStringField(record, "itineraryRef", label);
300
+ requireFiniteNumberField(record, "totalCents", label);
301
+ requireStringField(record, "currency", label);
302
+ requireOptionalNullableStringField(record, "offerId", label);
303
+ requireOptionalNullableStringField(record, "offerRequestId", label);
304
+ if (record.orderType !== undefined &&
305
+ record.orderType !== null &&
306
+ record.orderType !== "hold" &&
307
+ record.orderType !== "instant") {
308
+ throw new Error(`[ApprovalQueue] invalid ${label}.orderType`);
309
+ }
310
+ requireOptionalRecordField(record, "search", label);
311
+ requireTravelPassengers(record, label);
312
+ requireTravelCalendarSync(record, label);
313
+ requireOptionalNullableStringField(record, "summary", label);
314
+ requireTravelCost(record, label);
315
+ requirePaymentRequired(record, label);
316
+ break;
317
+ case "make_call":
318
+ requireStringField(record, "to", label);
319
+ requireStringField(record, "script", label);
320
+ requireFiniteNumberField(record, "maxDurationSeconds", label);
321
+ break;
322
+ case "sign_document":
323
+ requireStringField(record, "documentId", label);
324
+ requireStringField(record, "documentName", label);
325
+ requireStringField(record, "signatureUrl", label);
326
+ requireStringField(record, "deadline", label);
327
+ break;
328
+ case "execute_workflow":
329
+ requireStringField(record, "workflowId", label);
330
+ requirePrimitiveRecordField(record, "input", label);
331
+ break;
332
+ case "spend_money":
333
+ requireStringField(record, "vendor", label);
334
+ requireFiniteNumberField(record, "amountCents", label);
335
+ requireStringField(record, "currency", label);
336
+ requireStringField(record, "memo", label);
337
+ break;
338
+ }
339
+ }
340
+ function validateApprovalPayload(value, label) {
341
+ const record = requireRecord(value, label);
342
+ const action = parseAction(record.action);
343
+ assertApprovalPayload(record, action, label);
344
+ return record;
345
+ }
346
+ function rowToRequest(row) {
347
+ const action = parseAction(row.action);
348
+ const payload = validateApprovalPayload(parseJsonRecord(row.payload), `row ${toText(row.id)} payload`);
349
+ if (payload.action !== action) {
350
+ throw new Error(`[ApprovalQueue] row ${toText(row.id)} payload action ${payload.action} does not match request action ${action}`);
351
+ }
352
+ return {
353
+ id: toText(row.id),
354
+ createdAt: parseTimestamp(row.created_at),
355
+ updatedAt: parseTimestamp(row.updated_at),
356
+ state: parseState(row.state),
357
+ requestedBy: toText(row.requested_by),
358
+ subjectUserId: toText(row.subject_user_id),
359
+ action,
360
+ payload,
361
+ channel: parseChannel(row.channel),
362
+ reason: toText(row.reason),
363
+ expiresAt: parseTimestamp(row.expires_at),
364
+ resolvedAt: parseOptionalTimestamp(row.resolved_at),
365
+ resolvedBy: parseOptionalText(row.resolved_by),
366
+ resolutionReason: parseOptionalText(row.resolution_reason),
367
+ };
368
+ }
369
+ const SELECT_COLUMNS = "id, state, requested_by, subject_user_id, action, payload, channel, reason, expires_at, resolved_at, resolved_by, resolution_reason, created_at, updated_at";
370
+ function timestampLiteral(date) {
371
+ return sqlText(date.toISOString());
372
+ }
373
+ function getNotifier(runtime) {
374
+ const svc = runtime.getService(ServiceType.NOTIFICATION);
375
+ return svc && typeof svc.notify === "function" ? svc : null;
376
+ }
377
+ export class PgApprovalQueue {
378
+ runtime;
379
+ agentId;
380
+ constructor(runtime, options) {
381
+ this.runtime = runtime;
382
+ this.agentId = options.agentId;
383
+ }
384
+ async enqueue(input) {
385
+ const payload = validateApprovalPayload(input.payload, "enqueue payload");
386
+ if (input.action !== payload.action) {
387
+ throw new Error(`[ApprovalQueue] payload action ${payload.action} does not match request action ${input.action}`);
388
+ }
389
+ const id = randomUUID();
390
+ const now = new Date();
391
+ const sql = `INSERT INTO approval_requests (
392
+ id, state, requested_by, subject_user_id, action, payload, channel, reason,
393
+ expires_at, resolved_at, resolved_by, resolution_reason,
394
+ agent_id, created_at, updated_at
395
+ ) VALUES (
396
+ ${sqlText(id)},
397
+ ${sqlText("pending")},
398
+ ${sqlText(input.requestedBy)},
399
+ ${sqlText(input.subjectUserId)},
400
+ ${sqlText(input.action)},
401
+ ${sqlJson(payload)},
402
+ ${sqlText(input.channel)},
403
+ ${sqlText(input.reason)},
404
+ ${timestampLiteral(input.expiresAt)},
405
+ NULL, NULL, NULL,
406
+ ${sqlText(this.agentId)},
407
+ ${timestampLiteral(now)},
408
+ ${timestampLiteral(now)}
409
+ ) RETURNING ${SELECT_COLUMNS}`;
410
+ const rows = await executeRawSql(this.runtime, sql);
411
+ if (rows.length === 0) {
412
+ throw new Error("[ApprovalQueue] enqueue returned no rows");
413
+ }
414
+ logger.info(`[ApprovalQueue] enqueued ${input.action} for ${input.subjectUserId} as ${id}`);
415
+ // An outbound action now needs the owner's go-ahead. Surface it on the
416
+ // notification rail so the owner can act without watching the queue
417
+ // (fire-and-forget; a notify failure must not block the enqueue).
418
+ void getNotifier(this.runtime)
419
+ ?.notify({
420
+ title: "Approval needed",
421
+ body: input.reason.slice(0, 200),
422
+ category: "approval",
423
+ priority: "high",
424
+ source: "lifeops",
425
+ deepLink: "/chat",
426
+ groupKey: `approval:${id}`,
427
+ data: { requestId: id, kind: input.action },
428
+ })
429
+ .catch(() => { });
430
+ return rowToRequest(rows[0]);
431
+ }
432
+ async list(filter) {
433
+ const where = [`agent_id = ${sqlText(this.agentId)}`];
434
+ if (filter.subjectUserId !== null) {
435
+ where.push(`subject_user_id = ${sqlText(filter.subjectUserId)}`);
436
+ }
437
+ if (filter.state !== null) {
438
+ where.push(`state = ${sqlText(filter.state)}`);
439
+ }
440
+ if (filter.action !== null) {
441
+ where.push(`action = ${sqlText(filter.action)}`);
442
+ }
443
+ const sql = `SELECT ${SELECT_COLUMNS} FROM approval_requests
444
+ WHERE ${where.join(" AND ")}
445
+ ORDER BY created_at DESC
446
+ LIMIT ${sqlInteger(filter.limit)}`;
447
+ const rows = await executeRawSql(this.runtime, sql);
448
+ return rows.map(rowToRequest);
449
+ }
450
+ async byId(id) {
451
+ const rows = await this.fetchById(id);
452
+ return rows ?? null;
453
+ }
454
+ async approve(id, resolution) {
455
+ return this.transitionWithResolution(id, "approved", resolution);
456
+ }
457
+ async reject(id, resolution) {
458
+ return this.transitionWithResolution(id, "rejected", resolution);
459
+ }
460
+ async markExecuting(id) {
461
+ return this.transitionWithoutResolution(id, "executing");
462
+ }
463
+ async markDone(id) {
464
+ return this.transitionWithoutResolution(id, "done");
465
+ }
466
+ async markExpired(id) {
467
+ return this.transitionWithoutResolution(id, "expired");
468
+ }
469
+ async purgeExpired(now) {
470
+ const sql = `UPDATE approval_requests
471
+ SET state = ${sqlText("expired")}, updated_at = ${timestampLiteral(now)}
472
+ WHERE agent_id = ${sqlText(this.agentId)}
473
+ AND state = ${sqlText("pending")}
474
+ AND expires_at <= ${timestampLiteral(now)}
475
+ RETURNING id`;
476
+ const rows = await executeRawSql(this.runtime, sql);
477
+ const ids = rows.map((row) => toText(row.id));
478
+ if (ids.length > 0) {
479
+ logger.info(`[ApprovalQueue] purged ${ids.length} expired requests`);
480
+ }
481
+ return ids;
482
+ }
483
+ async fetchById(id) {
484
+ const sql = `SELECT ${SELECT_COLUMNS} FROM approval_requests
485
+ WHERE id = ${sqlText(id)} AND agent_id = ${sqlText(this.agentId)}
486
+ LIMIT 1`;
487
+ const rows = await executeRawSql(this.runtime, sql);
488
+ if (rows.length === 0)
489
+ return null;
490
+ return rowToRequest(rows[0]);
491
+ }
492
+ async transitionWithResolution(id, target, resolution) {
493
+ const current = await this.fetchById(id);
494
+ if (!current)
495
+ throw new ApprovalNotFoundError(id);
496
+ assertTransition(id, current.state, target);
497
+ const now = new Date();
498
+ const sql = `UPDATE approval_requests
499
+ SET state = ${sqlText(target)},
500
+ resolved_at = ${timestampLiteral(now)},
501
+ resolved_by = ${sqlText(resolution.resolvedBy)},
502
+ resolution_reason = ${sqlText(resolution.resolutionReason)},
503
+ updated_at = ${timestampLiteral(now)}
504
+ WHERE id = ${sqlText(id)} AND agent_id = ${sqlText(this.agentId)}
505
+ RETURNING ${SELECT_COLUMNS}`;
506
+ const rows = await executeRawSql(this.runtime, sql);
507
+ if (rows.length === 0) {
508
+ throw new ApprovalNotFoundError(id);
509
+ }
510
+ logger.info(`[ApprovalQueue] ${current.state} -> ${target} (${id}) by ${resolution.resolvedBy}`);
511
+ return rowToRequest(rows[0]);
512
+ }
513
+ async transitionWithoutResolution(id, target) {
514
+ const current = await this.fetchById(id);
515
+ if (!current)
516
+ throw new ApprovalNotFoundError(id);
517
+ assertTransition(id, current.state, target);
518
+ const now = new Date();
519
+ const sql = `UPDATE approval_requests
520
+ SET state = ${sqlText(target)},
521
+ updated_at = ${timestampLiteral(now)}
522
+ WHERE id = ${sqlText(id)} AND agent_id = ${sqlText(this.agentId)}
523
+ RETURNING ${SELECT_COLUMNS}`;
524
+ const rows = await executeRawSql(this.runtime, sql);
525
+ if (rows.length === 0) {
526
+ throw new ApprovalNotFoundError(id);
527
+ }
528
+ logger.info(`[ApprovalQueue] ${current.state} -> ${target} (${id})`);
529
+ return rowToRequest(rows[0]);
530
+ }
531
+ }
532
+ export function createApprovalQueue(runtime, options) {
533
+ return new PgApprovalQueue(runtime, options);
534
+ }