@elizaos/agent 2.0.0-alpha.144 → 2.0.0-alpha.151

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 (598) hide show
  1. package/apps/app-lifeops/src/actions/inbox-digest.d.ts +2 -0
  2. package/apps/app-lifeops/src/actions/inbox-digest.d.ts.map +1 -0
  3. package/apps/app-lifeops/src/actions/inbox-digest.js +1 -0
  4. package/apps/app-lifeops/src/actions/inbox-respond.d.ts +2 -0
  5. package/apps/app-lifeops/src/actions/inbox-respond.d.ts.map +1 -0
  6. package/apps/app-lifeops/src/actions/inbox-respond.js +1 -0
  7. package/apps/app-lifeops/src/actions/inbox-triage.d.ts +2 -0
  8. package/apps/app-lifeops/src/actions/inbox-triage.d.ts.map +1 -0
  9. package/apps/app-lifeops/src/actions/inbox-triage.js +1 -0
  10. package/apps/app-lifeops/src/actions/inbox.d.ts +3 -0
  11. package/apps/app-lifeops/src/actions/inbox.d.ts.map +1 -0
  12. package/apps/app-lifeops/src/actions/inbox.js +856 -0
  13. package/apps/app-lifeops/src/actions/update-owner-profile.d.ts +3 -0
  14. package/apps/app-lifeops/src/actions/update-owner-profile.d.ts.map +1 -0
  15. package/apps/app-lifeops/src/actions/update-owner-profile.js +131 -0
  16. package/apps/app-lifeops/src/inbox/channel-deep-links.d.ts.map +1 -0
  17. package/apps/app-lifeops/src/inbox/config.d.ts.map +1 -0
  18. package/{packages/agent → apps/app-lifeops}/src/inbox/config.js +1 -1
  19. package/apps/app-lifeops/src/inbox/message-fetcher.d.ts.map +1 -0
  20. package/apps/app-lifeops/src/inbox/reflection.d.ts.map +1 -0
  21. package/apps/app-lifeops/src/inbox/repository.d.ts.map +1 -0
  22. package/apps/app-lifeops/src/inbox/triage-classifier.d.ts.map +1 -0
  23. package/apps/app-lifeops/src/inbox/types.d.ts.map +1 -0
  24. package/apps/app-lifeops/src/lifeops/index.d.ts +25 -0
  25. package/apps/app-lifeops/src/lifeops/index.d.ts.map +1 -0
  26. package/apps/app-lifeops/src/lifeops/index.js +24 -0
  27. package/apps/app-lifeops/src/lifeops/screen-context.d.ts +52 -0
  28. package/apps/app-lifeops/src/lifeops/screen-context.d.ts.map +1 -0
  29. package/apps/app-lifeops/src/lifeops/screen-context.js +332 -0
  30. package/apps/app-lifeops/src/plugin.d.ts +3 -0
  31. package/apps/app-lifeops/src/plugin.d.ts.map +1 -1
  32. package/apps/app-lifeops/src/plugin.js +16 -3
  33. package/apps/app-lifeops/src/providers/inbox-triage.d.ts +3 -0
  34. package/apps/app-lifeops/src/providers/inbox-triage.d.ts.map +1 -0
  35. package/apps/app-lifeops/src/providers/inbox-triage.js +89 -0
  36. package/package.json +6 -4
  37. package/packages/agent/src/actions/calendar.d.ts +1 -18
  38. package/packages/agent/src/actions/calendar.d.ts.map +1 -1
  39. package/packages/agent/src/actions/calendar.js +1 -3143
  40. package/packages/agent/src/actions/check-balance.d.ts +17 -0
  41. package/packages/agent/src/actions/check-balance.d.ts.map +1 -0
  42. package/packages/agent/src/actions/check-balance.js +167 -0
  43. package/packages/agent/src/actions/connector-resolver.d.ts +75 -0
  44. package/packages/agent/src/actions/connector-resolver.d.ts.map +1 -0
  45. package/packages/agent/src/actions/connector-resolver.js +245 -0
  46. package/packages/agent/src/actions/context-signal-lexicon.d.ts +1 -1
  47. package/packages/agent/src/actions/context-signal-lexicon.d.ts.map +1 -1
  48. package/packages/agent/src/actions/context-signal-lexicon.js +6 -0
  49. package/packages/agent/src/actions/eject-plugin.d.ts +3 -0
  50. package/packages/agent/src/actions/eject-plugin.d.ts.map +1 -0
  51. package/packages/agent/src/actions/eject-plugin.js +48 -0
  52. package/packages/agent/src/actions/execute-trade.d.ts +17 -0
  53. package/packages/agent/src/actions/execute-trade.d.ts.map +1 -0
  54. package/packages/agent/src/actions/execute-trade.js +299 -0
  55. package/packages/agent/src/actions/get-self-status.d.ts +13 -0
  56. package/packages/agent/src/actions/get-self-status.d.ts.map +1 -0
  57. package/packages/agent/src/actions/get-self-status.js +66 -0
  58. package/packages/agent/src/actions/gmail.d.ts +1 -32
  59. package/packages/agent/src/actions/gmail.d.ts.map +1 -1
  60. package/packages/agent/src/actions/gmail.js +1 -1734
  61. package/packages/agent/src/actions/inbox-digest.d.ts +1 -1
  62. package/packages/agent/src/actions/inbox-digest.d.ts.map +1 -1
  63. package/packages/agent/src/actions/inbox-digest.js +1 -1
  64. package/packages/agent/src/actions/inbox-respond.d.ts +1 -1
  65. package/packages/agent/src/actions/inbox-respond.d.ts.map +1 -1
  66. package/packages/agent/src/actions/inbox-respond.js +1 -1
  67. package/packages/agent/src/actions/inbox-triage.d.ts +1 -1
  68. package/packages/agent/src/actions/inbox-triage.d.ts.map +1 -1
  69. package/packages/agent/src/actions/inbox-triage.js +1 -1
  70. package/packages/agent/src/actions/inbox.d.ts +1 -2
  71. package/packages/agent/src/actions/inbox.d.ts.map +1 -1
  72. package/packages/agent/src/actions/inbox.js +1 -856
  73. package/packages/agent/src/actions/index.d.ts +13 -0
  74. package/packages/agent/src/actions/index.d.ts.map +1 -1
  75. package/packages/agent/src/actions/index.js +13 -0
  76. package/packages/agent/src/actions/install-plugin.d.ts +3 -0
  77. package/packages/agent/src/actions/install-plugin.d.ts.map +1 -0
  78. package/packages/agent/src/actions/install-plugin.js +65 -0
  79. package/packages/agent/src/actions/life-goal-extractor.d.ts +1 -68
  80. package/packages/agent/src/actions/life-goal-extractor.d.ts.map +1 -1
  81. package/packages/agent/src/actions/life-goal-extractor.js +1 -354
  82. package/packages/agent/src/actions/life-param-extractor.d.ts +1 -77
  83. package/packages/agent/src/actions/life-param-extractor.d.ts.map +1 -1
  84. package/packages/agent/src/actions/life-param-extractor.js +1 -423
  85. package/packages/agent/src/actions/life-recent-context.d.ts +1 -8
  86. package/packages/agent/src/actions/life-recent-context.d.ts.map +1 -1
  87. package/packages/agent/src/actions/life-recent-context.js +1 -84
  88. package/packages/agent/src/actions/life-update-extractor.d.ts +1 -26
  89. package/packages/agent/src/actions/life-update-extractor.d.ts.map +1 -1
  90. package/packages/agent/src/actions/life-update-extractor.js +1 -195
  91. package/packages/agent/src/actions/life.d.ts +1 -8
  92. package/packages/agent/src/actions/life.d.ts.map +1 -1
  93. package/packages/agent/src/actions/life.extractor.d.ts +1 -17
  94. package/packages/agent/src/actions/life.extractor.d.ts.map +1 -1
  95. package/packages/agent/src/actions/life.extractor.js +1 -264
  96. package/packages/agent/src/actions/life.js +1 -3379
  97. package/packages/agent/src/actions/lifeops-extraction-config.d.ts +1 -15
  98. package/packages/agent/src/actions/lifeops-extraction-config.d.ts.map +1 -1
  99. package/packages/agent/src/actions/lifeops-extraction-config.js +1 -25
  100. package/packages/agent/src/actions/lifeops-google-helpers.d.ts +1 -61
  101. package/packages/agent/src/actions/lifeops-google-helpers.d.ts.map +1 -1
  102. package/packages/agent/src/actions/lifeops-google-helpers.js +1 -607
  103. package/packages/agent/src/actions/list-ejected.d.ts +3 -0
  104. package/packages/agent/src/actions/list-ejected.d.ts.map +1 -0
  105. package/packages/agent/src/actions/list-ejected.js +35 -0
  106. package/packages/agent/src/actions/log-level.d.ts +3 -0
  107. package/packages/agent/src/actions/log-level.d.ts.map +1 -0
  108. package/packages/agent/src/actions/log-level.js +125 -0
  109. package/packages/agent/src/actions/manage-tasks.d.ts.map +1 -1
  110. package/packages/agent/src/actions/manage-tasks.js +51 -15
  111. package/packages/agent/src/actions/media.d.ts +21 -0
  112. package/packages/agent/src/actions/media.d.ts.map +1 -0
  113. package/packages/agent/src/actions/media.js +384 -0
  114. package/packages/agent/src/actions/read-messages.d.ts +14 -0
  115. package/packages/agent/src/actions/read-messages.d.ts.map +1 -0
  116. package/packages/agent/src/actions/read-messages.js +228 -0
  117. package/packages/agent/src/actions/reinject-plugin.d.ts +3 -0
  118. package/packages/agent/src/actions/reinject-plugin.d.ts.map +1 -0
  119. package/packages/agent/src/actions/reinject-plugin.js +47 -0
  120. package/packages/agent/src/actions/send-message.d.ts +0 -7
  121. package/packages/agent/src/actions/send-message.d.ts.map +1 -1
  122. package/packages/agent/src/actions/send-message.js +170 -49
  123. package/packages/agent/src/actions/sync-plugin.d.ts +3 -0
  124. package/packages/agent/src/actions/sync-plugin.d.ts.map +1 -0
  125. package/packages/agent/src/actions/sync-plugin.js +47 -0
  126. package/packages/agent/src/actions/timezone-normalization.d.ts +1 -2
  127. package/packages/agent/src/actions/timezone-normalization.d.ts.map +1 -1
  128. package/packages/agent/src/actions/timezone-normalization.js +1 -107
  129. package/packages/agent/src/actions/transfer-token.d.ts +17 -0
  130. package/packages/agent/src/actions/transfer-token.d.ts.map +1 -0
  131. package/packages/agent/src/actions/transfer-token.js +470 -0
  132. package/packages/agent/src/actions/update-owner-profile.d.ts +1 -2
  133. package/packages/agent/src/actions/update-owner-profile.d.ts.map +1 -1
  134. package/packages/agent/src/actions/update-owner-profile.js +1 -131
  135. package/packages/agent/src/actions/wallet-action-shared.d.ts +15 -0
  136. package/packages/agent/src/actions/wallet-action-shared.d.ts.map +1 -0
  137. package/packages/agent/src/actions/wallet-action-shared.js +24 -0
  138. package/packages/agent/src/api/agent-admin-routes.d.ts.map +1 -1
  139. package/packages/agent/src/api/agent-admin-routes.js +1 -1
  140. package/packages/agent/src/api/binance-skill-helpers.d.ts.map +1 -1
  141. package/packages/agent/src/api/binance-skill-helpers.js +8 -3
  142. package/packages/agent/src/api/chat-routes.d.ts.map +1 -1
  143. package/packages/agent/src/api/chat-routes.js +20 -5
  144. package/packages/agent/src/api/coding-agents-auth-sanitize.d.ts +1 -22
  145. package/packages/agent/src/api/coding-agents-auth-sanitize.d.ts.map +1 -1
  146. package/packages/agent/src/api/coding-agents-auth-sanitize.js +1 -39
  147. package/packages/agent/src/api/coding-agents-preflight-normalize.d.ts +1 -28
  148. package/packages/agent/src/api/coding-agents-preflight-normalize.d.ts.map +1 -1
  149. package/packages/agent/src/api/coding-agents-preflight-normalize.js +1 -45
  150. package/packages/agent/src/api/coordinator-types.d.ts +1 -46
  151. package/packages/agent/src/api/coordinator-types.d.ts.map +1 -1
  152. package/packages/agent/src/api/coordinator-types.js +1 -1
  153. package/packages/agent/src/api/coordinator-wiring.d.ts +1 -45
  154. package/packages/agent/src/api/coordinator-wiring.d.ts.map +1 -1
  155. package/packages/agent/src/api/coordinator-wiring.js +1 -108
  156. package/packages/agent/src/api/index.d.ts +1 -1
  157. package/packages/agent/src/api/index.d.ts.map +1 -1
  158. package/packages/agent/src/api/index.js +1 -1
  159. package/packages/agent/src/api/lifeops-browser-packaging.d.ts +1 -15
  160. package/packages/agent/src/api/lifeops-browser-packaging.d.ts.map +1 -1
  161. package/packages/agent/src/api/lifeops-browser-packaging.js +1 -305
  162. package/packages/agent/src/api/lifeops-routes.d.ts +1 -19
  163. package/packages/agent/src/api/lifeops-routes.d.ts.map +1 -1
  164. package/packages/agent/src/api/lifeops-routes.js +1 -1173
  165. package/packages/agent/src/api/server.d.ts.map +1 -1
  166. package/packages/agent/src/api/server.js +6 -6
  167. package/packages/agent/src/api/task-agent-message-routing.d.ts +1 -9
  168. package/packages/agent/src/api/task-agent-message-routing.d.ts.map +1 -1
  169. package/packages/agent/src/api/task-agent-message-routing.js +1 -62
  170. package/packages/agent/src/api/website-blocker-routes.d.ts +1 -6
  171. package/packages/agent/src/api/website-blocker-routes.d.ts.map +1 -1
  172. package/packages/agent/src/api/website-blocker-routes.js +1 -174
  173. package/packages/agent/src/config/types.agent-defaults.d.ts +1 -1
  174. package/packages/agent/src/config/types.agent-defaults.d.ts.map +1 -1
  175. package/packages/agent/src/evals/coordinator-eval-client.d.ts +1 -38
  176. package/packages/agent/src/evals/coordinator-eval-client.d.ts.map +1 -1
  177. package/packages/agent/src/evals/coordinator-eval-client.js +1 -138
  178. package/packages/agent/src/evals/coordinator-live-runner.d.ts +1 -56
  179. package/packages/agent/src/evals/coordinator-live-runner.d.ts.map +1 -1
  180. package/packages/agent/src/evals/coordinator-live-runner.js +1 -546
  181. package/packages/agent/src/evals/coordinator-preflight.d.ts +1 -31
  182. package/packages/agent/src/evals/coordinator-preflight.d.ts.map +1 -1
  183. package/packages/agent/src/evals/coordinator-preflight.js +1 -296
  184. package/packages/agent/src/evals/coordinator-scenarios.d.ts +1 -23
  185. package/packages/agent/src/evals/coordinator-scenarios.d.ts.map +1 -1
  186. package/packages/agent/src/evals/coordinator-scenarios.js +1 -1141
  187. package/packages/agent/src/lifeops/app-state.d.ts +1 -10
  188. package/packages/agent/src/lifeops/app-state.d.ts.map +1 -1
  189. package/packages/agent/src/lifeops/app-state.js +1 -32
  190. package/packages/agent/src/lifeops/apple-reminders.d.ts +1 -57
  191. package/packages/agent/src/lifeops/apple-reminders.d.ts.map +1 -1
  192. package/packages/agent/src/lifeops/apple-reminders.js +1 -325
  193. package/packages/agent/src/lifeops/defaults.d.ts +1 -23
  194. package/packages/agent/src/lifeops/defaults.d.ts.map +1 -1
  195. package/packages/agent/src/lifeops/defaults.js +1 -205
  196. package/packages/agent/src/lifeops/engine.d.ts +1 -7
  197. package/packages/agent/src/lifeops/engine.d.ts.map +1 -1
  198. package/packages/agent/src/lifeops/engine.js +1 -389
  199. package/packages/agent/src/lifeops/goal-grounding.d.ts +1 -53
  200. package/packages/agent/src/lifeops/goal-grounding.d.ts.map +1 -1
  201. package/packages/agent/src/lifeops/goal-grounding.js +1 -147
  202. package/packages/agent/src/lifeops/goal-semantic-evaluator.d.ts +1 -11
  203. package/packages/agent/src/lifeops/goal-semantic-evaluator.d.ts.map +1 -1
  204. package/packages/agent/src/lifeops/goal-semantic-evaluator.js +1 -154
  205. package/packages/agent/src/lifeops/google-api-error.d.ts +1 -6
  206. package/packages/agent/src/lifeops/google-api-error.d.ts.map +1 -1
  207. package/packages/agent/src/lifeops/google-api-error.js +1 -35
  208. package/packages/agent/src/lifeops/google-calendar.d.ts +1 -52
  209. package/packages/agent/src/lifeops/google-calendar.d.ts.map +1 -1
  210. package/packages/agent/src/lifeops/google-calendar.js +1 -268
  211. package/packages/agent/src/lifeops/google-connector-gateway.d.ts +1 -18
  212. package/packages/agent/src/lifeops/google-connector-gateway.d.ts.map +1 -1
  213. package/packages/agent/src/lifeops/google-connector-gateway.js +1 -65
  214. package/packages/agent/src/lifeops/google-fetch.d.ts +1 -10
  215. package/packages/agent/src/lifeops/google-fetch.d.ts.map +1 -1
  216. package/packages/agent/src/lifeops/google-fetch.js +1 -85
  217. package/packages/agent/src/lifeops/google-gmail.d.ts +1 -53
  218. package/packages/agent/src/lifeops/google-gmail.d.ts.map +1 -1
  219. package/packages/agent/src/lifeops/google-gmail.js +1 -471
  220. package/packages/agent/src/lifeops/google-managed-client.d.ts +1 -126
  221. package/packages/agent/src/lifeops/google-managed-client.d.ts.map +1 -1
  222. package/packages/agent/src/lifeops/google-managed-client.js +1 -294
  223. package/packages/agent/src/lifeops/google-oauth.d.ts +1 -60
  224. package/packages/agent/src/lifeops/google-oauth.d.ts.map +1 -1
  225. package/packages/agent/src/lifeops/google-oauth.js +1 -494
  226. package/packages/agent/src/lifeops/google-scopes.d.ts +1 -12
  227. package/packages/agent/src/lifeops/google-scopes.d.ts.map +1 -1
  228. package/packages/agent/src/lifeops/google-scopes.js +1 -96
  229. package/packages/agent/src/lifeops/index.d.ts +1 -2
  230. package/packages/agent/src/lifeops/index.d.ts.map +1 -1
  231. package/packages/agent/src/lifeops/index.js +1 -2
  232. package/packages/agent/src/lifeops/owner-profile.d.ts +1 -14
  233. package/packages/agent/src/lifeops/owner-profile.d.ts.map +1 -1
  234. package/packages/agent/src/lifeops/owner-profile.js +1 -194
  235. package/packages/agent/src/lifeops/repository.d.ts +1 -208
  236. package/packages/agent/src/lifeops/repository.d.ts.map +1 -1
  237. package/packages/agent/src/lifeops/repository.js +1 -3187
  238. package/packages/agent/src/lifeops/runtime.d.ts +1 -13
  239. package/packages/agent/src/lifeops/runtime.d.ts.map +1 -1
  240. package/packages/agent/src/lifeops/runtime.js +1 -120
  241. package/packages/agent/src/lifeops/screen-context.d.ts +1 -51
  242. package/packages/agent/src/lifeops/screen-context.d.ts.map +1 -1
  243. package/packages/agent/src/lifeops/screen-context.js +1 -332
  244. package/packages/agent/src/lifeops/seed-routines.d.ts +1 -19
  245. package/packages/agent/src/lifeops/seed-routines.d.ts.map +1 -1
  246. package/packages/agent/src/lifeops/seed-routines.js +1 -111
  247. package/packages/agent/src/lifeops/service.d.ts +1 -274
  248. package/packages/agent/src/lifeops/service.d.ts.map +1 -1
  249. package/packages/agent/src/lifeops/service.js +1 -9260
  250. package/packages/agent/src/lifeops/sql.d.ts +1 -30
  251. package/packages/agent/src/lifeops/sql.d.ts.map +1 -1
  252. package/packages/agent/src/lifeops/sql.js +1 -247
  253. package/packages/agent/src/lifeops/time.d.ts +1 -16
  254. package/packages/agent/src/lifeops/time.d.ts.map +1 -1
  255. package/packages/agent/src/lifeops/time.js +1 -132
  256. package/packages/agent/src/lifeops/twilio.d.ts +1 -24
  257. package/packages/agent/src/lifeops/twilio.d.ts.map +1 -1
  258. package/packages/agent/src/lifeops/twilio.js +1 -157
  259. package/packages/agent/src/lifeops/x-poster.d.ts +1 -18
  260. package/packages/agent/src/lifeops/x-poster.d.ts.map +1 -1
  261. package/packages/agent/src/lifeops/x-poster.js +1 -148
  262. package/packages/agent/src/providers/inbox-triage.d.ts +1 -2
  263. package/packages/agent/src/providers/inbox-triage.d.ts.map +1 -1
  264. package/packages/agent/src/providers/inbox-triage.js +1 -89
  265. package/packages/agent/src/providers/index.d.ts +4 -1
  266. package/packages/agent/src/providers/index.d.ts.map +1 -1
  267. package/packages/agent/src/providers/index.js +4 -1
  268. package/packages/agent/src/providers/lifeops.d.ts +1 -2
  269. package/packages/agent/src/providers/lifeops.d.ts.map +1 -1
  270. package/packages/agent/src/providers/lifeops.js +1 -157
  271. package/packages/agent/src/providers/local-models.d.ts +118 -0
  272. package/packages/agent/src/providers/local-models.d.ts.map +1 -0
  273. package/packages/agent/src/providers/local-models.js +427 -0
  274. package/packages/agent/src/providers/media-provider.d.ts +192 -0
  275. package/packages/agent/src/providers/media-provider.d.ts.map +1 -0
  276. package/packages/agent/src/providers/media-provider.js +1088 -0
  277. package/packages/agent/src/providers/self-status.d.ts +4 -0
  278. package/packages/agent/src/providers/self-status.d.ts.map +1 -0
  279. package/packages/agent/src/providers/self-status.js +12 -0
  280. package/packages/agent/src/providers/tasks.d.ts.map +1 -1
  281. package/packages/agent/src/providers/tasks.js +7 -7
  282. package/packages/agent/src/runtime/core-plugins.js +1 -1
  283. package/packages/agent/src/runtime/eliza-plugin.d.ts.map +1 -1
  284. package/packages/agent/src/runtime/eliza-plugin.js +1 -7
  285. package/packages/agent/src/runtime/eliza.js +2 -2
  286. package/packages/agent/src/runtime/plugin-collector.js +3 -3
  287. package/packages/agent/src/runtime/plugin-lifecycle.d.ts.map +1 -1
  288. package/packages/agent/src/runtime/plugin-lifecycle.js +3 -13
  289. package/packages/agent/src/runtime/trajectory-internals.d.ts.map +1 -1
  290. package/packages/agent/src/runtime/trajectory-internals.js +1 -3
  291. package/packages/agent/src/services/built-in-app-routes/hyperscape.d.ts.map +1 -1
  292. package/packages/agent/src/services/coding-task-executor.d.ts +3 -3
  293. package/packages/agent/src/services/coding-task-executor.js +3 -3
  294. package/packages/shared/src/awareness/index.d.ts +2 -0
  295. package/packages/shared/src/awareness/index.d.ts.map +1 -0
  296. package/packages/shared/src/awareness/index.js +1 -0
  297. package/packages/shared/src/awareness/registry.d.ts +27 -0
  298. package/packages/shared/src/awareness/registry.d.ts.map +1 -0
  299. package/packages/shared/src/awareness/registry.js +161 -0
  300. package/packages/shared/src/i18n/generated/validation-keyword-data.d.ts +24 -0
  301. package/packages/shared/src/i18n/generated/validation-keyword-data.d.ts.map +1 -1
  302. package/packages/shared/src/i18n/generated/validation-keyword-data.js +24 -0
  303. package/packages/shared/src/runtime-env.d.ts.map +1 -1
  304. package/packages/shared/src/runtime-env.js +5 -1
  305. package/packages/typescript/src/generated/action-docs.d.ts +135 -0
  306. package/packages/typescript/src/generated/action-docs.d.ts.map +1 -1
  307. package/packages/typescript/src/generated/action-docs.js +237 -0
  308. package/packages/typescript/src/i18n/generated/validation-keyword-data.d.ts +24 -0
  309. package/packages/typescript/src/i18n/generated/validation-keyword-data.d.ts.map +1 -1
  310. package/packages/typescript/src/i18n/generated/validation-keyword-data.js +24 -0
  311. package/packages/typescript/src/index.node.d.ts +2 -2
  312. package/packages/typescript/src/index.node.d.ts.map +1 -1
  313. package/packages/typescript/src/index.node.js +4 -3
  314. package/packages/typescript/src/plugin-lifecycle.d.ts.map +1 -1
  315. package/packages/typescript/src/plugin-lifecycle.js +42 -3
  316. package/packages/typescript/src/services/message.d.ts.map +1 -1
  317. package/packages/typescript/src/services/message.js +32 -0
  318. package/apps/app-training/src/core/cli.d.ts +0 -11
  319. package/apps/app-training/src/core/cli.d.ts.map +0 -1
  320. package/apps/app-training/src/core/cli.js +0 -302
  321. package/apps/app-training/src/core/context-audit.d.ts +0 -51
  322. package/apps/app-training/src/core/context-audit.d.ts.map +0 -1
  323. package/apps/app-training/src/core/context-audit.js +0 -141
  324. package/apps/app-training/src/core/context-catalog.d.ts +0 -47
  325. package/apps/app-training/src/core/context-catalog.d.ts.map +0 -1
  326. package/apps/app-training/src/core/context-catalog.js +0 -259
  327. package/apps/app-training/src/core/context-types.d.ts +0 -3
  328. package/apps/app-training/src/core/context-types.d.ts.map +0 -1
  329. package/apps/app-training/src/core/context-types.js +0 -11
  330. package/apps/app-training/src/core/dataset-generator.d.ts +0 -135
  331. package/apps/app-training/src/core/dataset-generator.d.ts.map +0 -1
  332. package/apps/app-training/src/core/dataset-generator.js +0 -703
  333. package/apps/app-training/src/core/replay-validator.d.ts +0 -96
  334. package/apps/app-training/src/core/replay-validator.d.ts.map +0 -1
  335. package/apps/app-training/src/core/replay-validator.js +0 -265
  336. package/apps/app-training/src/core/roleplay-executor.d.ts +0 -123
  337. package/apps/app-training/src/core/roleplay-executor.d.ts.map +0 -1
  338. package/apps/app-training/src/core/roleplay-executor.js +0 -645
  339. package/apps/app-training/src/core/roleplay-trajectories.d.ts +0 -54
  340. package/apps/app-training/src/core/roleplay-trajectories.d.ts.map +0 -1
  341. package/apps/app-training/src/core/roleplay-trajectories.js +0 -73
  342. package/apps/app-training/src/core/scenario-blueprints.d.ts +0 -62
  343. package/apps/app-training/src/core/scenario-blueprints.d.ts.map +0 -1
  344. package/apps/app-training/src/core/scenario-blueprints.js +0 -790
  345. package/apps/app-training/src/core/trajectory-task-datasets.d.ts +0 -38
  346. package/apps/app-training/src/core/trajectory-task-datasets.d.ts.map +0 -1
  347. package/apps/app-training/src/core/trajectory-task-datasets.js +0 -281
  348. package/apps/app-training/src/core/vertex-tuning.d.ts +0 -139
  349. package/apps/app-training/src/core/vertex-tuning.d.ts.map +0 -1
  350. package/apps/app-training/src/core/vertex-tuning.js +0 -234
  351. package/packages/agent/src/inbox/channel-deep-links.d.ts.map +0 -1
  352. package/packages/agent/src/inbox/config.d.ts.map +0 -1
  353. package/packages/agent/src/inbox/message-fetcher.d.ts.map +0 -1
  354. package/packages/agent/src/inbox/reflection.d.ts.map +0 -1
  355. package/packages/agent/src/inbox/repository.d.ts.map +0 -1
  356. package/packages/agent/src/inbox/triage-classifier.d.ts.map +0 -1
  357. package/packages/agent/src/inbox/types.d.ts.map +0 -1
  358. package/packages/agent/src/training/cli.d.ts +0 -2
  359. package/packages/agent/src/training/cli.d.ts.map +0 -1
  360. package/packages/agent/src/training/cli.js +0 -2
  361. package/packages/agent/src/training/context-audit.d.ts +0 -2
  362. package/packages/agent/src/training/context-audit.d.ts.map +0 -1
  363. package/packages/agent/src/training/context-audit.js +0 -2
  364. package/packages/agent/src/training/context-catalog.d.ts +0 -2
  365. package/packages/agent/src/training/context-catalog.d.ts.map +0 -1
  366. package/packages/agent/src/training/context-catalog.js +0 -2
  367. package/packages/agent/src/training/context-types.d.ts +0 -2
  368. package/packages/agent/src/training/context-types.d.ts.map +0 -1
  369. package/packages/agent/src/training/context-types.js +0 -2
  370. package/packages/agent/src/training/dataset-generator.d.ts +0 -2
  371. package/packages/agent/src/training/dataset-generator.d.ts.map +0 -1
  372. package/packages/agent/src/training/dataset-generator.js +0 -2
  373. package/packages/agent/src/training/replay-validator.d.ts +0 -2
  374. package/packages/agent/src/training/replay-validator.d.ts.map +0 -1
  375. package/packages/agent/src/training/replay-validator.js +0 -2
  376. package/packages/agent/src/training/roleplay-executor.d.ts +0 -2
  377. package/packages/agent/src/training/roleplay-executor.d.ts.map +0 -1
  378. package/packages/agent/src/training/roleplay-executor.js +0 -2
  379. package/packages/agent/src/training/roleplay-trajectories.d.ts +0 -2
  380. package/packages/agent/src/training/roleplay-trajectories.d.ts.map +0 -1
  381. package/packages/agent/src/training/roleplay-trajectories.js +0 -2
  382. package/packages/agent/src/training/scenario-blueprints.d.ts +0 -2
  383. package/packages/agent/src/training/scenario-blueprints.d.ts.map +0 -1
  384. package/packages/agent/src/training/scenario-blueprints.js +0 -2
  385. package/packages/agent/src/training/trajectory-task-datasets.d.ts +0 -2
  386. package/packages/agent/src/training/trajectory-task-datasets.d.ts.map +0 -1
  387. package/packages/agent/src/training/trajectory-task-datasets.js +0 -2
  388. package/packages/agent/src/training/vertex-tuning.d.ts +0 -2
  389. package/packages/agent/src/training/vertex-tuning.d.ts.map +0 -1
  390. package/packages/agent/src/training/vertex-tuning.js +0 -2
  391. package/packages/typescript/src/features/orchestrator/actions/coding-task-handlers.d.ts +0 -41
  392. package/packages/typescript/src/features/orchestrator/actions/coding-task-handlers.d.ts.map +0 -1
  393. package/packages/typescript/src/features/orchestrator/actions/coding-task-handlers.js +0 -443
  394. package/packages/typescript/src/features/orchestrator/actions/coding-task-helpers.d.ts +0 -34
  395. package/packages/typescript/src/features/orchestrator/actions/coding-task-helpers.d.ts.map +0 -1
  396. package/packages/typescript/src/features/orchestrator/actions/coding-task-helpers.js +0 -171
  397. package/packages/typescript/src/features/orchestrator/actions/eval-metadata.d.ts +0 -11
  398. package/packages/typescript/src/features/orchestrator/actions/eval-metadata.d.ts.map +0 -1
  399. package/packages/typescript/src/features/orchestrator/actions/eval-metadata.js +0 -55
  400. package/packages/typescript/src/features/orchestrator/actions/finalize-workspace.d.ts +0 -11
  401. package/packages/typescript/src/features/orchestrator/actions/finalize-workspace.d.ts.map +0 -1
  402. package/packages/typescript/src/features/orchestrator/actions/finalize-workspace.js +0 -214
  403. package/packages/typescript/src/features/orchestrator/actions/list-agents.d.ts +0 -13
  404. package/packages/typescript/src/features/orchestrator/actions/list-agents.d.ts.map +0 -1
  405. package/packages/typescript/src/features/orchestrator/actions/list-agents.js +0 -174
  406. package/packages/typescript/src/features/orchestrator/actions/manage-issues.d.ts +0 -11
  407. package/packages/typescript/src/features/orchestrator/actions/manage-issues.d.ts.map +0 -1
  408. package/packages/typescript/src/features/orchestrator/actions/manage-issues.js +0 -428
  409. package/packages/typescript/src/features/orchestrator/actions/provision-workspace.d.ts +0 -11
  410. package/packages/typescript/src/features/orchestrator/actions/provision-workspace.d.ts.map +0 -1
  411. package/packages/typescript/src/features/orchestrator/actions/provision-workspace.js +0 -189
  412. package/packages/typescript/src/features/orchestrator/actions/send-to-agent.d.ts +0 -12
  413. package/packages/typescript/src/features/orchestrator/actions/send-to-agent.d.ts.map +0 -1
  414. package/packages/typescript/src/features/orchestrator/actions/send-to-agent.js +0 -265
  415. package/packages/typescript/src/features/orchestrator/actions/spawn-agent.d.ts +0 -12
  416. package/packages/typescript/src/features/orchestrator/actions/spawn-agent.d.ts.map +0 -1
  417. package/packages/typescript/src/features/orchestrator/actions/spawn-agent.js +0 -356
  418. package/packages/typescript/src/features/orchestrator/actions/start-coding-task.d.ts +0 -22
  419. package/packages/typescript/src/features/orchestrator/actions/start-coding-task.d.ts.map +0 -1
  420. package/packages/typescript/src/features/orchestrator/actions/start-coding-task.js +0 -270
  421. package/packages/typescript/src/features/orchestrator/actions/stop-agent.d.ts +0 -12
  422. package/packages/typescript/src/features/orchestrator/actions/stop-agent.d.ts.map +0 -1
  423. package/packages/typescript/src/features/orchestrator/actions/stop-agent.js +0 -192
  424. package/packages/typescript/src/features/orchestrator/actions/task-control.d.ts +0 -3
  425. package/packages/typescript/src/features/orchestrator/actions/task-control.d.ts.map +0 -1
  426. package/packages/typescript/src/features/orchestrator/actions/task-control.js +0 -217
  427. package/packages/typescript/src/features/orchestrator/actions/task-history.d.ts +0 -3
  428. package/packages/typescript/src/features/orchestrator/actions/task-history.d.ts.map +0 -1
  429. package/packages/typescript/src/features/orchestrator/actions/task-history.js +0 -323
  430. package/packages/typescript/src/features/orchestrator/actions/task-share.d.ts +0 -3
  431. package/packages/typescript/src/features/orchestrator/actions/task-share.d.ts.map +0 -1
  432. package/packages/typescript/src/features/orchestrator/actions/task-share.js +0 -168
  433. package/packages/typescript/src/features/orchestrator/actions/task-thread-target.d.ts +0 -11
  434. package/packages/typescript/src/features/orchestrator/actions/task-thread-target.d.ts.map +0 -1
  435. package/packages/typescript/src/features/orchestrator/actions/task-thread-target.js +0 -68
  436. package/packages/typescript/src/features/orchestrator/api/agent-routes.d.ts +0 -18
  437. package/packages/typescript/src/features/orchestrator/api/agent-routes.d.ts.map +0 -1
  438. package/packages/typescript/src/features/orchestrator/api/agent-routes.js +0 -654
  439. package/packages/typescript/src/features/orchestrator/api/coordinator-routes.d.ts +0 -22
  440. package/packages/typescript/src/features/orchestrator/api/coordinator-routes.d.ts.map +0 -1
  441. package/packages/typescript/src/features/orchestrator/api/coordinator-routes.js +0 -403
  442. package/packages/typescript/src/features/orchestrator/api/hook-routes.d.ts +0 -18
  443. package/packages/typescript/src/features/orchestrator/api/hook-routes.d.ts.map +0 -1
  444. package/packages/typescript/src/features/orchestrator/api/hook-routes.js +0 -164
  445. package/packages/typescript/src/features/orchestrator/api/issue-routes.d.ts +0 -17
  446. package/packages/typescript/src/features/orchestrator/api/issue-routes.d.ts.map +0 -1
  447. package/packages/typescript/src/features/orchestrator/api/issue-routes.js +0 -132
  448. package/packages/typescript/src/features/orchestrator/api/routes.d.ts +0 -37
  449. package/packages/typescript/src/features/orchestrator/api/routes.d.ts.map +0 -1
  450. package/packages/typescript/src/features/orchestrator/api/routes.js +0 -96
  451. package/packages/typescript/src/features/orchestrator/api/workspace-routes.d.ts +0 -17
  452. package/packages/typescript/src/features/orchestrator/api/workspace-routes.d.ts.map +0 -1
  453. package/packages/typescript/src/features/orchestrator/api/workspace-routes.js +0 -149
  454. package/packages/typescript/src/features/orchestrator/base-plugin.d.ts +0 -19
  455. package/packages/typescript/src/features/orchestrator/base-plugin.d.ts.map +0 -1
  456. package/packages/typescript/src/features/orchestrator/base-plugin.js +0 -75
  457. package/packages/typescript/src/features/orchestrator/claude-jsonl-completion-watcher.d.ts +0 -101
  458. package/packages/typescript/src/features/orchestrator/claude-jsonl-completion-watcher.d.ts.map +0 -1
  459. package/packages/typescript/src/features/orchestrator/claude-jsonl-completion-watcher.js +0 -310
  460. package/packages/typescript/src/features/orchestrator/index.d.ts +0 -33
  461. package/packages/typescript/src/features/orchestrator/index.d.ts.map +0 -1
  462. package/packages/typescript/src/features/orchestrator/index.js +0 -30
  463. package/packages/typescript/src/features/orchestrator/patch-agent-orchestrator-plugin.d.ts +0 -15
  464. package/packages/typescript/src/features/orchestrator/patch-agent-orchestrator-plugin.d.ts.map +0 -1
  465. package/packages/typescript/src/features/orchestrator/patch-agent-orchestrator-plugin.js +0 -1449
  466. package/packages/typescript/src/features/orchestrator/providers/action-examples.d.ts +0 -14
  467. package/packages/typescript/src/features/orchestrator/providers/action-examples.d.ts.map +0 -1
  468. package/packages/typescript/src/features/orchestrator/providers/action-examples.js +0 -151
  469. package/packages/typescript/src/features/orchestrator/providers/active-workspace-context.d.ts +0 -13
  470. package/packages/typescript/src/features/orchestrator/providers/active-workspace-context.d.ts.map +0 -1
  471. package/packages/typescript/src/features/orchestrator/providers/active-workspace-context.js +0 -142
  472. package/packages/typescript/src/features/orchestrator/services/agent-credentials.d.ts +0 -6
  473. package/packages/typescript/src/features/orchestrator/services/agent-credentials.d.ts.map +0 -1
  474. package/packages/typescript/src/features/orchestrator/services/agent-credentials.js +0 -91
  475. package/packages/typescript/src/features/orchestrator/services/agent-metrics.d.ts +0 -30
  476. package/packages/typescript/src/features/orchestrator/services/agent-metrics.d.ts.map +0 -1
  477. package/packages/typescript/src/features/orchestrator/services/agent-metrics.js +0 -54
  478. package/packages/typescript/src/features/orchestrator/services/agent-selection.d.ts +0 -53
  479. package/packages/typescript/src/features/orchestrator/services/agent-selection.d.ts.map +0 -1
  480. package/packages/typescript/src/features/orchestrator/services/agent-selection.js +0 -70
  481. package/packages/typescript/src/features/orchestrator/services/ansi-utils.d.ts +0 -61
  482. package/packages/typescript/src/features/orchestrator/services/ansi-utils.d.ts.map +0 -1
  483. package/packages/typescript/src/features/orchestrator/services/ansi-utils.js +0 -252
  484. package/packages/typescript/src/features/orchestrator/services/config-env.d.ts +0 -13
  485. package/packages/typescript/src/features/orchestrator/services/config-env.d.ts.map +0 -1
  486. package/packages/typescript/src/features/orchestrator/services/config-env.js +0 -37
  487. package/packages/typescript/src/features/orchestrator/services/coordinator-event-normalizer.d.ts +0 -50
  488. package/packages/typescript/src/features/orchestrator/services/coordinator-event-normalizer.d.ts.map +0 -1
  489. package/packages/typescript/src/features/orchestrator/services/coordinator-event-normalizer.js +0 -184
  490. package/packages/typescript/src/features/orchestrator/services/debug-capture.d.ts +0 -38
  491. package/packages/typescript/src/features/orchestrator/services/debug-capture.d.ts.map +0 -1
  492. package/packages/typescript/src/features/orchestrator/services/debug-capture.js +0 -113
  493. package/packages/typescript/src/features/orchestrator/services/pty-auto-response.d.ts +0 -30
  494. package/packages/typescript/src/features/orchestrator/services/pty-auto-response.d.ts.map +0 -1
  495. package/packages/typescript/src/features/orchestrator/services/pty-auto-response.js +0 -146
  496. package/packages/typescript/src/features/orchestrator/services/pty-init.d.ts +0 -54
  497. package/packages/typescript/src/features/orchestrator/services/pty-init.d.ts.map +0 -1
  498. package/packages/typescript/src/features/orchestrator/services/pty-init.js +0 -315
  499. package/packages/typescript/src/features/orchestrator/services/pty-service.d.ts +0 -175
  500. package/packages/typescript/src/features/orchestrator/services/pty-service.d.ts.map +0 -1
  501. package/packages/typescript/src/features/orchestrator/services/pty-service.js +0 -1469
  502. package/packages/typescript/src/features/orchestrator/services/pty-session-io.d.ts +0 -49
  503. package/packages/typescript/src/features/orchestrator/services/pty-session-io.d.ts.map +0 -1
  504. package/packages/typescript/src/features/orchestrator/services/pty-session-io.js +0 -180
  505. package/packages/typescript/src/features/orchestrator/services/pty-spawn.d.ts +0 -53
  506. package/packages/typescript/src/features/orchestrator/services/pty-spawn.d.ts.map +0 -1
  507. package/packages/typescript/src/features/orchestrator/services/pty-spawn.js +0 -280
  508. package/packages/typescript/src/features/orchestrator/services/pty-types.d.ts +0 -80
  509. package/packages/typescript/src/features/orchestrator/services/pty-types.d.ts.map +0 -1
  510. package/packages/typescript/src/features/orchestrator/services/pty-types.js +0 -51
  511. package/packages/typescript/src/features/orchestrator/services/repo-input.d.ts +0 -16
  512. package/packages/typescript/src/features/orchestrator/services/repo-input.d.ts.map +0 -1
  513. package/packages/typescript/src/features/orchestrator/services/repo-input.js +0 -88
  514. package/packages/typescript/src/features/orchestrator/services/stall-classifier.d.ts +0 -69
  515. package/packages/typescript/src/features/orchestrator/services/stall-classifier.d.ts.map +0 -1
  516. package/packages/typescript/src/features/orchestrator/services/stall-classifier.js +0 -446
  517. package/packages/typescript/src/features/orchestrator/services/swarm-coordinator-prompts.d.ts +0 -97
  518. package/packages/typescript/src/features/orchestrator/services/swarm-coordinator-prompts.d.ts.map +0 -1
  519. package/packages/typescript/src/features/orchestrator/services/swarm-coordinator-prompts.js +0 -342
  520. package/packages/typescript/src/features/orchestrator/services/swarm-coordinator.d.ts +0 -421
  521. package/packages/typescript/src/features/orchestrator/services/swarm-coordinator.d.ts.map +0 -1
  522. package/packages/typescript/src/features/orchestrator/services/swarm-coordinator.js +0 -2356
  523. package/packages/typescript/src/features/orchestrator/services/swarm-decision-loop.d.ts +0 -52
  524. package/packages/typescript/src/features/orchestrator/services/swarm-decision-loop.d.ts.map +0 -1
  525. package/packages/typescript/src/features/orchestrator/services/swarm-decision-loop.js +0 -1538
  526. package/packages/typescript/src/features/orchestrator/services/swarm-event-triage.d.ts +0 -49
  527. package/packages/typescript/src/features/orchestrator/services/swarm-event-triage.d.ts.map +0 -1
  528. package/packages/typescript/src/features/orchestrator/services/swarm-event-triage.js +0 -171
  529. package/packages/typescript/src/features/orchestrator/services/swarm-history.d.ts +0 -27
  530. package/packages/typescript/src/features/orchestrator/services/swarm-history.d.ts.map +0 -1
  531. package/packages/typescript/src/features/orchestrator/services/swarm-history.js +0 -148
  532. package/packages/typescript/src/features/orchestrator/services/swarm-idle-watchdog.d.ts +0 -22
  533. package/packages/typescript/src/features/orchestrator/services/swarm-idle-watchdog.d.ts.map +0 -1
  534. package/packages/typescript/src/features/orchestrator/services/swarm-idle-watchdog.js +0 -265
  535. package/packages/typescript/src/features/orchestrator/services/task-acceptance.d.ts +0 -8
  536. package/packages/typescript/src/features/orchestrator/services/task-acceptance.d.ts.map +0 -1
  537. package/packages/typescript/src/features/orchestrator/services/task-acceptance.js +0 -114
  538. package/packages/typescript/src/features/orchestrator/services/task-agent-auth.d.ts +0 -68
  539. package/packages/typescript/src/features/orchestrator/services/task-agent-auth.d.ts.map +0 -1
  540. package/packages/typescript/src/features/orchestrator/services/task-agent-auth.js +0 -559
  541. package/packages/typescript/src/features/orchestrator/services/task-agent-frameworks.d.ts +0 -82
  542. package/packages/typescript/src/features/orchestrator/services/task-agent-frameworks.d.ts.map +0 -1
  543. package/packages/typescript/src/features/orchestrator/services/task-agent-frameworks.js +0 -738
  544. package/packages/typescript/src/features/orchestrator/services/task-kind.d.ts +0 -3
  545. package/packages/typescript/src/features/orchestrator/services/task-kind.d.ts.map +0 -1
  546. package/packages/typescript/src/features/orchestrator/services/task-kind.js +0 -40
  547. package/packages/typescript/src/features/orchestrator/services/task-policy.d.ts +0 -17
  548. package/packages/typescript/src/features/orchestrator/services/task-policy.d.ts.map +0 -1
  549. package/packages/typescript/src/features/orchestrator/services/task-policy.js +0 -226
  550. package/packages/typescript/src/features/orchestrator/services/task-registry.d.ts +0 -550
  551. package/packages/typescript/src/features/orchestrator/services/task-registry.d.ts.map +0 -1
  552. package/packages/typescript/src/features/orchestrator/services/task-registry.js +0 -2182
  553. package/packages/typescript/src/features/orchestrator/services/task-share.d.ts +0 -18
  554. package/packages/typescript/src/features/orchestrator/services/task-share.d.ts.map +0 -1
  555. package/packages/typescript/src/features/orchestrator/services/task-share.js +0 -159
  556. package/packages/typescript/src/features/orchestrator/services/task-validation.d.ts +0 -69
  557. package/packages/typescript/src/features/orchestrator/services/task-validation.d.ts.map +0 -1
  558. package/packages/typescript/src/features/orchestrator/services/task-validation.js +0 -587
  559. package/packages/typescript/src/features/orchestrator/services/task-verifier-runner.d.ts +0 -5
  560. package/packages/typescript/src/features/orchestrator/services/task-verifier-runner.d.ts.map +0 -1
  561. package/packages/typescript/src/features/orchestrator/services/task-verifier-runner.js +0 -372
  562. package/packages/typescript/src/features/orchestrator/services/trajectory-context.d.ts +0 -73
  563. package/packages/typescript/src/features/orchestrator/services/trajectory-context.d.ts.map +0 -1
  564. package/packages/typescript/src/features/orchestrator/services/trajectory-context.js +0 -64
  565. package/packages/typescript/src/features/orchestrator/services/trajectory-feedback.d.ts +0 -53
  566. package/packages/typescript/src/features/orchestrator/services/trajectory-feedback.d.ts.map +0 -1
  567. package/packages/typescript/src/features/orchestrator/services/trajectory-feedback.js +0 -260
  568. package/packages/typescript/src/features/orchestrator/services/workspace-git-ops.d.ts +0 -28
  569. package/packages/typescript/src/features/orchestrator/services/workspace-git-ops.d.ts.map +0 -1
  570. package/packages/typescript/src/features/orchestrator/services/workspace-git-ops.js +0 -105
  571. package/packages/typescript/src/features/orchestrator/services/workspace-github.d.ts +0 -58
  572. package/packages/typescript/src/features/orchestrator/services/workspace-github.d.ts.map +0 -1
  573. package/packages/typescript/src/features/orchestrator/services/workspace-github.js +0 -139
  574. package/packages/typescript/src/features/orchestrator/services/workspace-lifecycle.d.ts +0 -18
  575. package/packages/typescript/src/features/orchestrator/services/workspace-lifecycle.d.ts.map +0 -1
  576. package/packages/typescript/src/features/orchestrator/services/workspace-lifecycle.js +0 -86
  577. package/packages/typescript/src/features/orchestrator/services/workspace-service.d.ts +0 -118
  578. package/packages/typescript/src/features/orchestrator/services/workspace-service.d.ts.map +0 -1
  579. package/packages/typescript/src/features/orchestrator/services/workspace-service.js +0 -533
  580. package/packages/typescript/src/features/orchestrator/services/workspace-types.d.ts +0 -81
  581. package/packages/typescript/src/features/orchestrator/services/workspace-types.d.ts.map +0 -1
  582. package/packages/typescript/src/features/orchestrator/services/workspace-types.js +0 -8
  583. package/packages/typescript/src/features/orchestrator/task-progress-streamer.d.ts +0 -38
  584. package/packages/typescript/src/features/orchestrator/task-progress-streamer.d.ts.map +0 -1
  585. package/packages/typescript/src/features/orchestrator/task-progress-streamer.js +0 -293
  586. /package/{packages/agent → apps/app-lifeops}/src/inbox/channel-deep-links.d.ts +0 -0
  587. /package/{packages/agent → apps/app-lifeops}/src/inbox/channel-deep-links.js +0 -0
  588. /package/{packages/agent → apps/app-lifeops}/src/inbox/config.d.ts +0 -0
  589. /package/{packages/agent → apps/app-lifeops}/src/inbox/message-fetcher.d.ts +0 -0
  590. /package/{packages/agent → apps/app-lifeops}/src/inbox/message-fetcher.js +0 -0
  591. /package/{packages/agent → apps/app-lifeops}/src/inbox/reflection.d.ts +0 -0
  592. /package/{packages/agent → apps/app-lifeops}/src/inbox/reflection.js +0 -0
  593. /package/{packages/agent → apps/app-lifeops}/src/inbox/repository.d.ts +0 -0
  594. /package/{packages/agent → apps/app-lifeops}/src/inbox/repository.js +0 -0
  595. /package/{packages/agent → apps/app-lifeops}/src/inbox/triage-classifier.d.ts +0 -0
  596. /package/{packages/agent → apps/app-lifeops}/src/inbox/triage-classifier.js +0 -0
  597. /package/{packages/agent → apps/app-lifeops}/src/inbox/types.d.ts +0 -0
  598. /package/{packages/agent → apps/app-lifeops}/src/inbox/types.js +0 -0
@@ -1,3379 +1 @@
1
- import { ModelType, parseJSONObjectFromText } from "@elizaos/core";
2
- import { getValidationKeywordTerms, textIncludesKeywordTerm, } from "@elizaos/shared/validation-keywords";
3
- import { buildNativeAppleReminderMetadata, } from "../lifeops/apple-reminders.js";
4
- import { resolveDefaultTimeZone, resolveDefaultWindowPolicy, } from "../lifeops/defaults.js";
5
- import { LifeOpsService, LifeOpsServiceError } from "../lifeops/service.js";
6
- import { addDaysToLocalDate, buildUtcDateFromLocalParts, getZonedDateParts, } from "../lifeops/time.js";
7
- import { gmailAction } from "./gmail.js";
8
- import { renderGroundedActionReply } from "./grounded-action-reply.js";
9
- import { extractLifeOperationWithLlm, } from "./life.extractor.js";
10
- import { extractGoalCreatePlanWithLlm, extractGoalUpdatePlanWithLlm, mergeGoalMetadataWithGrounding, } from "./life-goal-extractor.js";
11
- import { extractReminderIntensityWithLlm, extractTaskCreatePlanWithLlm, } from "./life-param-extractor.js";
12
- import { recentConversationTexts } from "./life-recent-context.js";
13
- import { extractUpdateFieldsWithLlm } from "./life-update-extractor.js";
14
- import { calendarReadUnavailableMessage, dayRange, detailArray, detailBoolean, detailNumber, detailObject, detailString, formatCalendarFeed, formatNextEventContext, formatOverviewForQuery, getGoogleCapabilityStatus, hasLifeOpsAccess, INTERNAL_URL, messageText, toActionData, weekRange, } from "./lifeops-google-helpers.js";
15
- import { extractExplicitTimeZoneFromText, normalizeExplicitTimeZoneToken, } from "./timezone-normalization.js";
16
- const LIFE_EMAIL_QUERY_TERMS = getValidationKeywordTerms("contextSignal.gmail.strong", {
17
- includeAllLocales: true,
18
- });
19
- const LIFE_I18N_OPTS = { includeAllLocales: true };
20
- const LIFE_COMPLETE_TERMS = getValidationKeywordTerms("contextSignal.lifeops_complete.strong", LIFE_I18N_OPTS);
21
- const LIFE_SKIP_TERMS = getValidationKeywordTerms("contextSignal.lifeops_skip.strong", LIFE_I18N_OPTS);
22
- const LIFE_SNOOZE_TERMS = getValidationKeywordTerms("contextSignal.lifeops_snooze.strong", LIFE_I18N_OPTS);
23
- const LIFE_DELETE_TERMS = getValidationKeywordTerms("contextSignal.lifeops_delete.strong", LIFE_I18N_OPTS);
24
- const LIFE_UPDATE_TERMS = getValidationKeywordTerms("contextSignal.lifeops_update.strong", LIFE_I18N_OPTS);
25
- const LIFE_OVERVIEW_TERMS = getValidationKeywordTerms("contextSignal.lifeops_overview.strong", LIFE_I18N_OPTS);
26
- const LIFE_REMINDER_PREF_TERMS = getValidationKeywordTerms("contextSignal.lifeops_reminder_pref.strong", LIFE_I18N_OPTS);
27
- const LIFE_CALENDAR_TERMS = getValidationKeywordTerms("contextSignal.calendar.strong", LIFE_I18N_OPTS);
28
- const LIFE_CADENCE_TERMS = getValidationKeywordTerms("contextSignal.lifeops_cadence.strong", LIFE_I18N_OPTS);
29
- const LIFE_GOAL_TERMS = getValidationKeywordTerms("contextSignal.lifeops_goal.strong", LIFE_I18N_OPTS);
30
- const LIFE_ESCALATION_TERMS = getValidationKeywordTerms("contextSignal.lifeops_escalation.strong", LIFE_I18N_OPTS);
31
- const LIFE_PHONE_TERMS = getValidationKeywordTerms("contextSignal.lifeops_phone.strong", LIFE_I18N_OPTS);
32
- const LIFE_REVIEW_TERMS = getValidationKeywordTerms("contextSignal.lifeops_review.strong", LIFE_I18N_OPTS);
33
- const LIFE_LIFEOPS_STRONG_TERMS = getValidationKeywordTerms("contextSignal.lifeops.strong", LIFE_I18N_OPTS);
34
- const LIFE_AFFIRMATIVE_TERMS = getValidationKeywordTerms("contextSignal.affirmative.strong", LIFE_I18N_OPTS);
35
- const LIFE_NEGATIVE_TERMS = getValidationKeywordTerms("contextSignal.negative.strong", LIFE_I18N_OPTS);
36
- const LIFE_DRAFT_EDIT_TERMS = getValidationKeywordTerms("contextSignal.draft_edit.strong", LIFE_I18N_OPTS);
37
- const LIFE_TEMPORAL_NEXT_TERMS = getValidationKeywordTerms("contextSignal.temporal_next.strong", LIFE_I18N_OPTS);
38
- function textMatchesAnyTerm(text, terms) {
39
- return terms.some((term) => textIncludesKeywordTerm(text, term));
40
- }
41
- const ACTION_TO_OPERATION = {
42
- create: "create_definition",
43
- create_goal: "create_goal",
44
- update: "update_definition",
45
- update_goal: "update_goal",
46
- delete: "delete_definition",
47
- delete_goal: "delete_goal",
48
- complete: "complete_occurrence",
49
- skip: "skip_occurrence",
50
- snooze: "snooze_occurrence",
51
- review: "review_goal",
52
- phone: "capture_phone",
53
- escalation: "configure_escalation",
54
- reminder_preference: "set_reminder_preference",
55
- calendar: "query_calendar_today",
56
- next_event: "query_calendar_next",
57
- email: "query_email",
58
- overview: "query_overview",
59
- };
60
- // CADENCE_HINT_RE removed — cadence detection uses i18n LIFE_CADENCE_TERMS
61
- const GENERIC_DERIVED_TITLE_RE = /^(?:new\s+)?(?:habit|routine|task|goal|life goal|thing|item|something|anything|stuff|plan|reminder|todo|to do|achieve|achieve a|achieve an)$/i;
62
- /** Maximum age (ms) for a deferred draft before it expires. */
63
- const DRAFT_EXPIRY_MS = 5 * 60 * 1000; // 5 minutes
64
- /** Maximum conversation turns before a deferred draft expires. */
65
- const DRAFT_MAX_TURNS = 3;
66
- function normalizeLifeTimeZoneToken(value) {
67
- return normalizeExplicitTimeZoneToken(value);
68
- }
69
- function extractLifeTimeZoneFromText(value) {
70
- return extractExplicitTimeZoneFromText(value);
71
- }
72
- // ── Intent classifier ─────────────────────────────────
73
- export function classifyIntent(intent) {
74
- // All matching is i18n-aware via validation keyword terms.
75
- // English words are included in the base terms so no regex needed.
76
- // Reminder preference — check early
77
- if (textMatchesAnyTerm(intent, LIFE_REMINDER_PREF_TERMS)) {
78
- return "set_reminder_preference";
79
- }
80
- // Update — check before calendar so "edit my workout schedule" doesn't hit calendar
81
- if (textMatchesAnyTerm(intent, LIFE_UPDATE_TERMS)) {
82
- if (textMatchesAnyTerm(intent, LIFE_GOAL_TERMS))
83
- return "update_goal";
84
- return "update_definition";
85
- }
86
- // Escalation config — check before phone capture
87
- if (textMatchesAnyTerm(intent, LIFE_ESCALATION_TERMS))
88
- return "configure_escalation";
89
- // Phone capture
90
- if (textMatchesAnyTerm(intent, LIFE_PHONE_TERMS))
91
- return "capture_phone";
92
- // Review — check before calendar
93
- if (textMatchesAnyTerm(intent, LIFE_REVIEW_TERMS))
94
- return "review_goal";
95
- // Delete — check before calendar
96
- if (textMatchesAnyTerm(intent, LIFE_DELETE_TERMS)) {
97
- if (textMatchesAnyTerm(intent, LIFE_GOAL_TERMS))
98
- return "delete_goal";
99
- return "delete_definition";
100
- }
101
- // Completion
102
- if (looksLikeCompletionReport(intent))
103
- return "complete_occurrence";
104
- // Skip
105
- if (textMatchesAnyTerm(intent, LIFE_SKIP_TERMS))
106
- return "skip_occurrence";
107
- // Snooze
108
- if (textMatchesAnyTerm(intent, LIFE_SNOOZE_TERMS))
109
- return "snooze_occurrence";
110
- // Calendar query — only when not a lifeops create or lifeops item reference
111
- if (!looksLikeDefinitionCreateIntent(intent) &&
112
- !looksLikeGoalCreateIntent(intent) &&
113
- !textMatchesAnyTerm(intent, LIFE_LIFEOPS_STRONG_TERMS) &&
114
- textMatchesAnyTerm(intent, LIFE_CALENDAR_TERMS)) {
115
- // Sub-classify: next event vs today/tomorrow/week
116
- const lower = intent.toLowerCase();
117
- if (textMatchesAnyTerm(lower, LIFE_TEMPORAL_NEXT_TERMS))
118
- return "query_calendar_next";
119
- return "query_calendar_today";
120
- }
121
- // Email query
122
- if (textMatchesAnyTerm(intent, LIFE_EMAIL_QUERY_TERMS))
123
- return "query_email";
124
- // Overview
125
- if (textMatchesAnyTerm(intent, LIFE_OVERVIEW_TERMS))
126
- return "query_overview";
127
- // Create definition (has cadence hint)
128
- if (looksLikeDefinitionCreateIntent(intent))
129
- return "create_definition";
130
- // Create goal (goal mention without cadence)
131
- if (looksLikeGoalCreateIntent(intent))
132
- return "create_goal";
133
- // Default: create a task/habit/routine
134
- return "create_definition";
135
- }
136
- async function resolveLifeOperationPlan(args) {
137
- const { runtime, message, state, intent, explicitOperation } = args;
138
- if (explicitOperation) {
139
- return {
140
- operation: explicitOperation,
141
- confidence: 1,
142
- missing: [],
143
- shouldAct: true,
144
- };
145
- }
146
- const extracted = await extractLifeOperationWithLlm({
147
- runtime,
148
- message,
149
- state,
150
- intent,
151
- });
152
- if (!extracted.shouldAct || !extracted.operation) {
153
- return {
154
- operation: extracted.operation,
155
- confidence: extracted.confidence,
156
- missing: extracted.missing,
157
- shouldAct: false,
158
- };
159
- }
160
- return {
161
- operation: extracted.operation,
162
- confidence: extracted.confidence,
163
- missing: extracted.missing,
164
- shouldAct: true,
165
- };
166
- }
167
- function looksLikeDefinitionCreateIntent(text) {
168
- return hasCadenceHint(text);
169
- }
170
- function looksLikeGoalCreateIntent(text) {
171
- return textMatchesAnyTerm(text, LIFE_GOAL_TERMS) && !hasCadenceHint(text);
172
- }
173
- function hasCadenceHint(text) {
174
- return textMatchesAnyTerm(text, LIFE_CADENCE_TERMS);
175
- }
176
- function shouldForceLifeCreateExecution(args) {
177
- if (args.operation !== "create_definition") {
178
- return false;
179
- }
180
- const blockingFields = args.missing.filter((field) => field !== "title" && field !== "schedule");
181
- if (blockingFields.length > 0) {
182
- return false;
183
- }
184
- if (typeof args.title === "string" && args.title.trim().length > 0) {
185
- return true;
186
- }
187
- if (normalizeCadenceDetail(detailObject(args.details, "cadence"))) {
188
- return true;
189
- }
190
- return false;
191
- }
192
- function looksLikeCompletionReport(text) {
193
- // Exclude overview queries — these mention "done/finish" but ask what's remaining
194
- if (textMatchesAnyTerm(text, LIFE_OVERVIEW_TERMS)) {
195
- return false;
196
- }
197
- // Exclude create-intent with cadence — "create a habit until I complete it"
198
- if (textMatchesAnyTerm(text, LIFE_CADENCE_TERMS)) {
199
- return false;
200
- }
201
- return textMatchesAnyTerm(text, LIFE_COMPLETE_TERMS);
202
- }
203
- // ── Helpers ───────────────────────────────────────────
204
- function requestedOwnership(domain) {
205
- if (domain === "agent_ops") {
206
- return { domain: "agent_ops", subjectType: "agent" };
207
- }
208
- return { domain: "user_lifeops", subjectType: "owner" };
209
- }
210
- function normalizeIntentText(value) {
211
- return normalizeLifeInputText(value).toLowerCase();
212
- }
213
- function normalizeLifeInputText(value) {
214
- return value
215
- .replace(/[\u00a0\u1680\u2000-\u200b\u202f\u205f\u3000]/g, " ")
216
- .replace(/\s+/g, " ")
217
- .trim();
218
- }
219
- function normalizeTitle(value) {
220
- return normalizeIntentText(value);
221
- }
222
- function matchByTitle(entries, targetTitle) {
223
- const normalized = normalizeTitle(targetTitle);
224
- return (entries.find((e) => normalizeTitle(e.definition?.title ?? e.goal?.title ?? "") ===
225
- normalized) ??
226
- entries.find((e) => normalizeTitle(e.definition?.title ?? e.goal?.title ?? "").includes(normalized)) ??
227
- null);
228
- }
229
- function coerceDeferredLifeDraft(value) {
230
- if (!value || typeof value !== "object") {
231
- return null;
232
- }
233
- const record = value;
234
- const operation = record.operation;
235
- const intent = typeof record.intent === "string" ? record.intent.trim() : "";
236
- const request = record.request && typeof record.request === "object"
237
- ? record.request
238
- : null;
239
- const createdAt = typeof record.createdAt === "number" && Number.isFinite(record.createdAt)
240
- ? record.createdAt
241
- : undefined;
242
- if (!request || !intent) {
243
- return null;
244
- }
245
- const title = typeof request.title === "string" ? request.title.trim() : "";
246
- if (!title) {
247
- return null;
248
- }
249
- if (operation === "create_definition") {
250
- const kind = typeof request.kind === "string"
251
- ? request.kind
252
- : null;
253
- const cadence = request.cadence;
254
- if (!kind || !cadence) {
255
- return null;
256
- }
257
- return {
258
- createdAt,
259
- intent,
260
- operation,
261
- request: {
262
- cadence,
263
- description: typeof request.description === "string"
264
- ? request.description
265
- : undefined,
266
- goalRef: typeof request.goalRef === "string" ? request.goalRef : undefined,
267
- kind,
268
- priority: typeof request.priority === "number" ? request.priority : undefined,
269
- progressionRule: request.progressionRule,
270
- reminderPlan: request.reminderPlan,
271
- timezone: typeof request.timezone === "string" ? request.timezone : undefined,
272
- title,
273
- metadata: request.metadata && typeof request.metadata === "object"
274
- ? request.metadata
275
- : undefined,
276
- windowPolicy: request.windowPolicy,
277
- websiteAccess: request.websiteAccess,
278
- },
279
- };
280
- }
281
- if (operation === "create_goal") {
282
- return {
283
- createdAt,
284
- intent,
285
- operation,
286
- request: {
287
- cadence: request.cadence,
288
- description: typeof request.description === "string"
289
- ? request.description
290
- : undefined,
291
- metadata: request.metadata && typeof request.metadata === "object"
292
- ? request.metadata
293
- : undefined,
294
- successCriteria: request.successCriteria,
295
- supportStrategy: request.supportStrategy,
296
- title,
297
- },
298
- };
299
- }
300
- return null;
301
- }
302
- function stateActionResults(state) {
303
- if (!state || typeof state !== "object") {
304
- return [];
305
- }
306
- const stateRecord = state;
307
- const data = stateRecord.data && typeof stateRecord.data === "object"
308
- ? stateRecord.data
309
- : undefined;
310
- const providerResults = data?.providers && typeof data.providers === "object"
311
- ? data.providers
312
- : undefined;
313
- const providerActionState = providerResults?.ACTION_STATE &&
314
- typeof providerResults.ACTION_STATE === "object"
315
- ? providerResults.ACTION_STATE
316
- : undefined;
317
- const providerActionStateData = providerActionState?.data && typeof providerActionState.data === "object"
318
- ? providerActionState.data
319
- : undefined;
320
- const providerRecentMessages = providerResults?.RECENT_MESSAGES &&
321
- typeof providerResults.RECENT_MESSAGES === "object"
322
- ? providerResults.RECENT_MESSAGES
323
- : undefined;
324
- const providerRecentMessagesData = providerRecentMessages?.data &&
325
- typeof providerRecentMessages.data === "object"
326
- ? providerRecentMessages.data
327
- : undefined;
328
- const candidates = [
329
- data?.actionResults,
330
- providerActionStateData?.actionResults,
331
- providerActionStateData?.recentActionMemories,
332
- providerRecentMessagesData?.actionResults,
333
- ].filter(Array.isArray);
334
- if (candidates.length === 0) {
335
- return [];
336
- }
337
- return candidates.flatMap((entries) => entries.flatMap((entry) => {
338
- if (!entry || typeof entry !== "object") {
339
- return [];
340
- }
341
- if ("content" in entry) {
342
- const content = entry.content &&
343
- typeof entry.content === "object"
344
- ? entry
345
- .content
346
- : null;
347
- if (!content) {
348
- return [];
349
- }
350
- const contentData = content.data && typeof content.data === "object"
351
- ? { ...content.data }
352
- : {};
353
- if (typeof content.actionName === "string" &&
354
- typeof contentData.actionName !== "string") {
355
- contentData.actionName = content.actionName;
356
- }
357
- return [
358
- {
359
- success: content.actionStatus !== "failed",
360
- text: typeof content.text === "string" ? content.text : undefined,
361
- data: contentData,
362
- error: typeof content.error === "string" ? content.error : undefined,
363
- },
364
- ];
365
- }
366
- return [entry];
367
- }));
368
- }
369
- function stateMessageDrafts(state) {
370
- if (!state || typeof state !== "object") {
371
- return [];
372
- }
373
- const stateRecord = state;
374
- const data = stateRecord.data && typeof stateRecord.data === "object"
375
- ? stateRecord.data
376
- : undefined;
377
- const providerResults = data?.providers && typeof data.providers === "object"
378
- ? data.providers
379
- : undefined;
380
- const providerRecentMessages = providerResults?.RECENT_MESSAGES &&
381
- typeof providerResults.RECENT_MESSAGES === "object"
382
- ? providerResults.RECENT_MESSAGES
383
- : undefined;
384
- const providerRecentMessagesData = providerRecentMessages?.data &&
385
- typeof providerRecentMessages.data === "object"
386
- ? providerRecentMessages.data
387
- : undefined;
388
- const recentMessagesData = [
389
- stateRecord.recentMessagesData,
390
- stateRecord.recentMessages,
391
- providerRecentMessagesData?.recentMessages,
392
- ].find(Array.isArray);
393
- if (!Array.isArray(recentMessagesData)) {
394
- return [];
395
- }
396
- const drafts = [];
397
- for (const item of recentMessagesData) {
398
- if (!item || typeof item !== "object") {
399
- continue;
400
- }
401
- const content = item.content;
402
- if (!content || typeof content !== "object") {
403
- continue;
404
- }
405
- const contentRecord = content;
406
- const candidate = coerceDeferredLifeDraft(contentRecord.lifeDraft) ??
407
- coerceDeferredLifeDraft(contentRecord.data && typeof contentRecord.data === "object"
408
- ? contentRecord.data.lifeDraft
409
- : undefined);
410
- if (candidate) {
411
- drafts.push(candidate);
412
- }
413
- }
414
- return drafts;
415
- }
416
- function stateRecentMessageEntries(state) {
417
- if (!state || typeof state !== "object") {
418
- return [];
419
- }
420
- const stateRecord = state;
421
- const data = stateRecord.data && typeof stateRecord.data === "object"
422
- ? stateRecord.data
423
- : undefined;
424
- const providerResults = data?.providers && typeof data.providers === "object"
425
- ? data.providers
426
- : undefined;
427
- const providerRecentMessages = providerResults?.RECENT_MESSAGES &&
428
- typeof providerResults.RECENT_MESSAGES === "object"
429
- ? providerResults.RECENT_MESSAGES
430
- : undefined;
431
- const providerRecentMessagesData = providerRecentMessages?.data &&
432
- typeof providerRecentMessages.data === "object"
433
- ? providerRecentMessages.data
434
- : undefined;
435
- const recentMessagesData = [
436
- stateRecord.recentMessagesData,
437
- stateRecord.recentMessages,
438
- providerRecentMessagesData?.recentMessages,
439
- ].find(Array.isArray);
440
- if (!Array.isArray(recentMessagesData)) {
441
- return [];
442
- }
443
- return recentMessagesData.filter((item) => Boolean(item) && typeof item === "object");
444
- }
445
- function isDeferredLifeDraftMessageEntry(item) {
446
- const content = item.content && typeof item.content === "object"
447
- ? item.content
448
- : null;
449
- if (!content) {
450
- return false;
451
- }
452
- return Boolean(coerceDeferredLifeDraft(content.lifeDraft) ??
453
- coerceDeferredLifeDraft(content.data && typeof content.data === "object"
454
- ? content.data.lifeDraft
455
- : undefined));
456
- }
457
- function countTurnsSinceLatestDeferredLifeDraft(state) {
458
- const entries = stateRecentMessageEntries(state);
459
- if (entries.length === 0) {
460
- return undefined;
461
- }
462
- let latestDraftIndex = -1;
463
- for (let index = entries.length - 1; index >= 0; index--) {
464
- if (isDeferredLifeDraftMessageEntry(entries[index])) {
465
- latestDraftIndex = index;
466
- break;
467
- }
468
- }
469
- if (latestDraftIndex < 0) {
470
- return undefined;
471
- }
472
- let turns = 0;
473
- for (const entry of entries.slice(latestDraftIndex + 1)) {
474
- const content = entry.content && typeof entry.content === "object"
475
- ? entry.content
476
- : null;
477
- if (!content || isDeferredLifeDraftMessageEntry(entry)) {
478
- continue;
479
- }
480
- if (typeof content.text === "string" && content.text.trim().length > 0) {
481
- turns++;
482
- }
483
- }
484
- return turns;
485
- }
486
- function latestDeferredLifeDraft(state) {
487
- for (const result of [...stateActionResults(state)].reverse()) {
488
- const resultData = result.data && typeof result.data === "object"
489
- ? result.data
490
- : null;
491
- const completedCreate = result.success &&
492
- resultData &&
493
- !coerceDeferredLifeDraft(resultData.lifeDraft) &&
494
- ((resultData.definition && typeof resultData.definition === "object") ||
495
- (resultData.goal && typeof resultData.goal === "object"));
496
- if (completedCreate) {
497
- return null;
498
- }
499
- const candidate = coerceDeferredLifeDraft(result.data?.lifeDraft);
500
- if (candidate) {
501
- return candidate;
502
- }
503
- }
504
- const messageDrafts = stateMessageDrafts(state);
505
- return messageDrafts.length > 0
506
- ? messageDrafts[messageDrafts.length - 1]
507
- : null;
508
- }
509
- function looksLikeDeferredLifeConfirmation(text) {
510
- const normalized = text.trim().toLowerCase();
511
- if (!normalized)
512
- return false;
513
- if (textMatchesAnyTerm(normalized, LIFE_NEGATIVE_TERMS))
514
- return false;
515
- if (textMatchesAnyTerm(normalized, LIFE_DRAFT_EDIT_TERMS))
516
- return false;
517
- return textMatchesAnyTerm(normalized, LIFE_AFFIRMATIVE_TERMS);
518
- }
519
- function normalizeDeferredLifeDraftReference(value) {
520
- return normalizeIntentText(value ?? "")
521
- .replace(/\b(the|that|this|a|an|my|routine|habit|task|goal|reminder)\b/g, " ")
522
- .replace(/\s+/g, " ")
523
- .trim();
524
- }
525
- function matchesDeferredLifeDraftTitle(value, draft) {
526
- if (!draft) {
527
- return false;
528
- }
529
- const normalizedValue = normalizeDeferredLifeDraftReference(value);
530
- const normalizedDraftTitle = normalizeDeferredLifeDraftReference(draft.request.title);
531
- if (!normalizedValue || !normalizedDraftTitle) {
532
- return false;
533
- }
534
- return (normalizedValue === normalizedDraftTitle ||
535
- normalizedValue.includes(normalizedDraftTitle) ||
536
- normalizedDraftTitle.includes(normalizedValue));
537
- }
538
- function deferredLifeDraftExpiryReason(args) {
539
- if (!args.draft) {
540
- return null;
541
- }
542
- if (args.draft.createdAt) {
543
- const ageMs = Date.now() - args.draft.createdAt;
544
- if (ageMs >= DRAFT_EXPIRY_MS) {
545
- return "age";
546
- }
547
- }
548
- if (typeof args.turnsSinceDraft === "number" &&
549
- args.turnsSinceDraft >= DRAFT_MAX_TURNS) {
550
- return "turns";
551
- }
552
- return null;
553
- }
554
- function looksLikeDeferredLifeDraftEdit(text) {
555
- const normalized = normalizeIntentText(text);
556
- if (!normalized || looksLikeDeferredLifeConfirmation(text))
557
- return false;
558
- if (textMatchesAnyTerm(normalized, LIFE_NEGATIVE_TERMS))
559
- return false;
560
- if (textMatchesAnyTerm(normalized, LIFE_DRAFT_EDIT_TERMS))
561
- return true;
562
- return hasCadenceHint(normalized) || /\b\d+\b/.test(normalized);
563
- }
564
- async function extractDeferredLifeDraftFollowupWithLlm(args) {
565
- if (typeof args.runtime.useModel !== "function") {
566
- return null;
567
- }
568
- const recentConversation = await recentConversationTexts({
569
- runtime: args.runtime,
570
- message: args.message,
571
- state: args.state,
572
- limit: 12,
573
- });
574
- const prompt = [
575
- "Decide how the assistant should interpret the user's follow-up to a previewed LifeOps draft that has not been saved yet.",
576
- "Use the current message, the draft summary, and recent conversation.",
577
- "The user may speak in any language.",
578
- "",
579
- "Return ONLY valid JSON with exactly this shape:",
580
- '{"mode":"confirm"|"edit"|"cancel"|"none"}',
581
- "",
582
- "Choose confirm when the user clearly approves saving the current draft now.",
583
- "Choose edit when the user wants to change the draft or continue specifying it before saving.",
584
- "Choose cancel when the user says not to save it, never mind, not yet, hold off, or equivalent.",
585
- "Choose none when the follow-up is unrelated or too ambiguous to attach to the draft.",
586
- "",
587
- "Previewed draft:",
588
- stringifyDeferredLifeDraftForPrompt(args.draft),
589
- "",
590
- `Current user message: ${JSON.stringify(args.currentText)}`,
591
- `Recent conversation: ${JSON.stringify(recentConversation.join("\n"))}`,
592
- ].join("\n");
593
- try {
594
- const result = await args.runtime.useModel(ModelType.TEXT_LARGE, {
595
- prompt,
596
- });
597
- const raw = typeof result === "string" ? result : "";
598
- const parsed = parseJSONObjectFromText(raw);
599
- const mode = parsed && typeof parsed.mode === "string"
600
- ? parsed.mode.trim().toLowerCase()
601
- : "";
602
- switch (mode) {
603
- case "confirm":
604
- case "edit":
605
- case "cancel":
606
- return mode;
607
- default:
608
- return null;
609
- }
610
- }
611
- catch {
612
- return null;
613
- }
614
- }
615
- function stringifyDeferredLifeDraftForPrompt(draft) {
616
- if (draft.operation === "create_definition") {
617
- return JSON.stringify({
618
- operation: draft.operation,
619
- title: draft.request.title,
620
- kind: draft.request.kind,
621
- cadence: draft.request.cadence,
622
- timezone: draft.request.timezone ?? null,
623
- description: draft.request.description ?? null,
624
- });
625
- }
626
- return JSON.stringify({
627
- operation: draft.operation,
628
- title: draft.request.title,
629
- cadence: draft.request.cadence ?? null,
630
- description: draft.request.description ?? null,
631
- });
632
- }
633
- function resolveDeferredLifeDraftReuseMode(args) {
634
- if (!args.draft) {
635
- return null;
636
- }
637
- if (deferredLifeDraftExpiryReason(args)) {
638
- return null;
639
- }
640
- if (detailBoolean(args.details, "confirmed") === true) {
641
- return "confirm";
642
- }
643
- const words = args.currentText.trim().split(/\s+/).filter(Boolean);
644
- const isConfirmationFollowup = words.length > 0 &&
645
- words.length <= 6 &&
646
- !hasCadenceHint(args.currentText.toLowerCase()) &&
647
- looksLikeDeferredLifeConfirmation(args.currentText);
648
- if (isConfirmationFollowup) {
649
- if (args.explicitAction &&
650
- ACTION_TO_OPERATION[args.explicitAction] !== args.draft.operation) {
651
- return null;
652
- }
653
- return "confirm";
654
- }
655
- const explicitReferenceMatchesDraft = matchesDeferredLifeDraftTitle(args.title, args.draft) ||
656
- matchesDeferredLifeDraftTitle(args.target, args.draft);
657
- if (looksLikeDeferredLifeConfirmation(args.currentText)) {
658
- if (args.explicitAction &&
659
- ACTION_TO_OPERATION[args.explicitAction] !== args.draft.operation) {
660
- return null;
661
- }
662
- if (explicitReferenceMatchesDraft) {
663
- return "confirm";
664
- }
665
- }
666
- const normalizedCurrentText = normalizeIntentText(args.currentText);
667
- const normalizedParamsIntent = typeof args.paramsIntent === "string" && args.paramsIntent.trim().length > 0
668
- ? normalizeIntentText(args.paramsIntent)
669
- : "";
670
- if (normalizedParamsIntent &&
671
- normalizedParamsIntent !== normalizedCurrentText &&
672
- !looksLikeDeferredLifeConfirmation(args.paramsIntent ?? "")) {
673
- return null;
674
- }
675
- if (args.explicitAction &&
676
- ACTION_TO_OPERATION[args.explicitAction] !== args.draft.operation) {
677
- return null;
678
- }
679
- if (args.llmMode === "confirm" || args.llmMode === "edit") {
680
- return args.llmMode;
681
- }
682
- if (args.title || args.target) {
683
- return null;
684
- }
685
- return looksLikeDeferredLifeDraftEdit(args.currentText) ? "edit" : null;
686
- }
687
- async function resolveGoal(service, target, domain) {
688
- if (!target)
689
- return null;
690
- const goals = (await service.listGoals()).filter((e) => domain ? e.goal.domain === domain : true);
691
- return goals.find((e) => e.goal.id === target) ?? matchByTitle(goals, target);
692
- }
693
- async function resolveDefinition(service, target, domain) {
694
- if (!target)
695
- return null;
696
- const defs = (await service.listDefinitions()).filter((e) => domain ? e.definition.domain === domain : true);
697
- return (defs.find((e) => e.definition.id === target) ?? matchByTitle(defs, target));
698
- }
699
- function tokenizeTitle(value) {
700
- return normalizeTitle(value)
701
- .split(" ")
702
- .filter((token) => token.length >= 3);
703
- }
704
- async function resolveDefinitionFromIntent(service, target, intent, domain) {
705
- const direct = await resolveDefinition(service, target, domain);
706
- if (direct) {
707
- return direct;
708
- }
709
- const defs = (await service.listDefinitions()).filter((entry) => domain ? entry.definition.domain === domain : true);
710
- const intentTokens = new Set(tokenizeTitle(intent));
711
- let best = null;
712
- let bestScore = 0;
713
- let tied = false;
714
- for (const entry of defs) {
715
- const title = normalizeTitle(entry.definition.title);
716
- if (title.length > 0 && normalizeTitle(intent).includes(title)) {
717
- return entry;
718
- }
719
- const overlap = tokenizeTitle(entry.definition.title).filter((token) => intentTokens.has(token)).length;
720
- if (overlap === 0) {
721
- continue;
722
- }
723
- if (overlap > bestScore) {
724
- best = entry;
725
- bestScore = overlap;
726
- tied = false;
727
- continue;
728
- }
729
- if (overlap === bestScore) {
730
- tied = true;
731
- }
732
- }
733
- return bestScore > 0 && !tied ? best : null;
734
- }
735
- function formatOccurrenceDisambiguationLabel(occurrence) {
736
- const hints = [];
737
- if (typeof occurrence.windowName === "string" &&
738
- occurrence.windowName.trim()) {
739
- hints.push(occurrence.windowName.trim());
740
- }
741
- if (occurrence.dueAt) {
742
- const dueAt = new Date(occurrence.dueAt);
743
- if (!Number.isNaN(dueAt.getTime())) {
744
- hints.push(dueAt.toLocaleString(undefined, {
745
- month: "short",
746
- day: "numeric",
747
- hour: "numeric",
748
- minute: "2-digit",
749
- }));
750
- }
751
- }
752
- return hints.length > 0
753
- ? `${occurrence.title} (${hints.join(", ")})`
754
- : occurrence.title;
755
- }
756
- async function resolveOccurrence(service, target, domain) {
757
- if (!target)
758
- return { match: null, ambiguousCandidates: [] };
759
- const overview = await service.getOverview();
760
- const all = [
761
- ...overview.owner.occurrences,
762
- ...overview.agentOps.occurrences,
763
- ].filter((o) => (domain ? o.domain === domain : true));
764
- const normalized = normalizeTitle(target);
765
- // Exact ID match
766
- const byId = all.find((o) => o.id === target);
767
- if (byId)
768
- return { match: byId, ambiguousCandidates: [] };
769
- // Exact normalized-title match
770
- const exactMatches = all.filter((o) => normalizeTitle(o.title) === normalized);
771
- if (exactMatches.length === 1) {
772
- return { match: exactMatches[0], ambiguousCandidates: [] };
773
- }
774
- if (exactMatches.length > 1) {
775
- return {
776
- match: null,
777
- ambiguousCandidates: exactMatches.map(formatOccurrenceDisambiguationLabel),
778
- };
779
- }
780
- // Substring matches — disambiguate when multiple
781
- const substringMatches = all.filter((o) => normalizeTitle(o.title).includes(normalized));
782
- if (substringMatches.length === 1) {
783
- return { match: substringMatches[0], ambiguousCandidates: [] };
784
- }
785
- if (substringMatches.length > 1) {
786
- // Prefer startsWith over generic includes
787
- const startsWithMatches = substringMatches.filter((o) => normalizeTitle(o.title).startsWith(normalized));
788
- if (startsWithMatches.length === 1) {
789
- return { match: startsWithMatches[0], ambiguousCandidates: [] };
790
- }
791
- if (startsWithMatches.length > 1) {
792
- return {
793
- match: null,
794
- ambiguousCandidates: startsWithMatches.map(formatOccurrenceDisambiguationLabel),
795
- };
796
- }
797
- // Still ambiguous — return candidates for the caller to list
798
- return {
799
- match: null,
800
- ambiguousCandidates: substringMatches.map(formatOccurrenceDisambiguationLabel),
801
- };
802
- }
803
- const targetTokens = normalized.split(/\s+/).filter(Boolean);
804
- if (targetTokens.length > 1) {
805
- const tokenSetMatches = all.filter((occurrence) => {
806
- const occurrenceTokens = new Set(normalizeTitle(occurrence.title).split(/\s+/).filter(Boolean));
807
- return targetTokens.every((token) => occurrenceTokens.has(token));
808
- });
809
- if (tokenSetMatches.length === 1) {
810
- return { match: tokenSetMatches[0], ambiguousCandidates: [] };
811
- }
812
- if (tokenSetMatches.length > 1) {
813
- return {
814
- match: null,
815
- ambiguousCandidates: tokenSetMatches.map(formatOccurrenceDisambiguationLabel),
816
- };
817
- }
818
- }
819
- return { match: null, ambiguousCandidates: [] };
820
- }
821
- function deriveOccurrenceTargetFromIntent(intent, operation) {
822
- const normalized = normalizeLifeInputText(intent);
823
- if (!normalized) {
824
- return null;
825
- }
826
- let candidate = normalized;
827
- if (operation === "snooze_occurrence") {
828
- candidate = candidate
829
- .replace(/^(?:please\s+)?(?:snooze|postpone|push\b.*\bback|remind me later about)\s+/i, "")
830
- .replace(/\bfor\s+\d+\s*(?:minutes?|hours?)\b.*$/i, "")
831
- .replace(/\b(?:until|til)\b.+$/i, "")
832
- .trim();
833
- }
834
- else if (operation === "skip_occurrence") {
835
- candidate = candidate
836
- .replace(/^(?:please\s+)?(?:skip|pass on)\s+/i, "")
837
- .replace(/\b(?:today|tonight|for now)\b.*$/i, "")
838
- .trim();
839
- }
840
- else if (operation === "complete_occurrence") {
841
- candidate = candidate
842
- .replace(/^(?:please\s+)?(?:mark\s+|i(?:'ve| have)?\s+|just\s+)?(?:done|completed|finished|did)\s+/i, "")
843
- .replace(/\b(?:done|complete|completed|finished)\b.*$/i, "")
844
- .trim();
845
- }
846
- return candidate.length > 0 ? candidate : null;
847
- }
848
- async function resolveOccurrenceWithIntentFallback(args) {
849
- const direct = await resolveOccurrence(args.service, args.target, args.domain);
850
- if (direct.match || direct.ambiguousCandidates.length > 0) {
851
- return direct;
852
- }
853
- const fallbackTarget = deriveOccurrenceTargetFromIntent(args.intent, args.operation);
854
- if (!fallbackTarget ||
855
- (args.target &&
856
- normalizeTitle(fallbackTarget) === normalizeTitle(args.target))) {
857
- return direct;
858
- }
859
- return resolveOccurrence(args.service, fallbackTarget, args.domain);
860
- }
861
- function summarizeCadence(cadence) {
862
- switch (cadence.kind) {
863
- case "once": {
864
- const dueAt = new Date(cadence.dueAt);
865
- if (Number.isNaN(dueAt.getTime())) {
866
- return "once";
867
- }
868
- return `once on ${dueAt.toLocaleString(undefined, {
869
- month: "short",
870
- day: "numeric",
871
- hour: "numeric",
872
- minute: "2-digit",
873
- timeZone: resolveDefaultTimeZone(),
874
- })}`;
875
- }
876
- case "daily":
877
- return `every day in ${cadence.windows.join(", ")}`;
878
- case "times_per_day":
879
- return cadence.slots
880
- .map((slot) => slot.label?.trim() || `${slot.minuteOfDay}`)
881
- .filter(Boolean)
882
- .join(" and ");
883
- case "interval":
884
- return `every ${cadence.everyMinutes} minutes in ${cadence.windows.join(", ")}`;
885
- case "weekly":
886
- return `weekly on ${cadence.weekdays
887
- .map((weekday) => [
888
- "Sunday",
889
- "Monday",
890
- "Tuesday",
891
- "Wednesday",
892
- "Thursday",
893
- "Friday",
894
- "Saturday",
895
- ][weekday] ?? String(weekday))
896
- .join(", ")}`;
897
- }
898
- }
899
- function extractNaturalTimePhrase(intent) {
900
- const normalized = normalizeLifeInputText(intent).toLowerCase();
901
- if (/\bmornings?\s+only\b|\bmornings?\b/.test(normalized)) {
902
- return "mornings now";
903
- }
904
- if (/\bafternoons?\s+only\b|\bafternoons?\b/.test(normalized)) {
905
- return "afternoons now";
906
- }
907
- if (/\bevenings?\s+only\b|\bevenings?\b/.test(normalized)) {
908
- return "evenings now";
909
- }
910
- if (/\bnights?\s+only\b|\bnights?\b/.test(normalized)) {
911
- return "nights now";
912
- }
913
- const timeMatch = normalized.match(/\b(\d{1,2}(?::\d{2})?\s*(?:am|pm))\b/);
914
- if (timeMatch?.[1]) {
915
- return `${timeMatch[1].replace(/\s+/g, "")} now`;
916
- }
917
- return null;
918
- }
919
- function buildRuleBasedLifeReply(args) {
920
- const context = args.context ?? {};
921
- const updated = context.updated && typeof context.updated === "object"
922
- ? context.updated
923
- : null;
924
- const created = context.created && typeof context.created === "object"
925
- ? context.created
926
- : null;
927
- const title = (typeof updated?.title === "string" ? updated.title : null) ??
928
- (typeof created?.title === "string" ? created.title : null) ??
929
- (typeof context.title === "string" ? context.title : null) ??
930
- null;
931
- const timePhrase = extractNaturalTimePhrase(args.intent);
932
- switch (args.scenario) {
933
- case "updated_definition":
934
- if (title && timePhrase) {
935
- return `${title} is set for ${timePhrase}.`;
936
- }
937
- if (title) {
938
- return `${title} is updated.`;
939
- }
940
- break;
941
- case "deleted_definition":
942
- if (title) {
943
- return `${title} is off your list.`;
944
- }
945
- break;
946
- case "deleted_goal":
947
- if (title) {
948
- return `${title} is off your goals list.`;
949
- }
950
- break;
951
- case "completed_occurrence":
952
- if (title) {
953
- return `Marked ${title} done.`;
954
- }
955
- break;
956
- case "skipped_occurrence":
957
- if (title) {
958
- return `Okay, skipping ${title} for now.`;
959
- }
960
- break;
961
- case "snoozed_occurrence":
962
- if (title) {
963
- return `Okay, I'll bring ${title} back a bit later.`;
964
- }
965
- break;
966
- default:
967
- break;
968
- }
969
- return args.fallback;
970
- }
971
- async function renderLifeActionReply(args) {
972
- const { runtime, message, state, intent, scenario, fallback, context } = args;
973
- const naturalFallback = buildRuleBasedLifeReply({
974
- scenario,
975
- intent,
976
- fallback,
977
- context,
978
- });
979
- return renderGroundedActionReply({
980
- runtime,
981
- message,
982
- state,
983
- intent,
984
- domain: "lifeops",
985
- scenario,
986
- fallback: naturalFallback,
987
- context,
988
- preferCharacterVoice: true,
989
- additionalRules: [
990
- "Mirror the user's phrasing for time and date when possible.",
991
- "Prefer phrases like tomorrow morning, every night, 7 am, or the user's own wording over robotic schedule language.",
992
- "Never surface raw ISO timestamps unless the user used raw ISO timestamps.",
993
- "If this is a preview, make clear it is not saved yet and the user can confirm or change it naturally.",
994
- "If this is reply-only, do not pretend you saved or changed anything.",
995
- ],
996
- });
997
- }
998
- function buildLifeClarificationFallback(args) {
999
- const missing = new Set(args.missing);
1000
- if (args.operation === "create_goal") {
1001
- return "What do you want the goal to be?";
1002
- }
1003
- if (missing.has("title") && missing.has("schedule")) {
1004
- return "What do you want the todo to be, and when should it happen?";
1005
- }
1006
- if (missing.has("title")) {
1007
- return "What do you want it to be?";
1008
- }
1009
- if (missing.has("schedule")) {
1010
- return "When should it happen?";
1011
- }
1012
- return "Tell me a bit more about what you want to set up.";
1013
- }
1014
- function buildLifeServiceErrorFallback(error, intent) {
1015
- const normalized = error.message.toLowerCase();
1016
- if (normalized.includes("utc 'z' suffix") ||
1017
- normalized.includes("local datetime without 'z'") ||
1018
- normalized.includes("time didn't parse") ||
1019
- normalized.includes("invalid dueat") ||
1020
- normalized.includes("cadence.dueat")) {
1021
- return `I couldn't pin down the reminder time from "${intent}". Tell me the time again in plain language, like "Friday at 8 pm Pacific."`;
1022
- }
1023
- if (normalized.includes("when windowpreset is not provided") ||
1024
- normalized.includes("startat is required")) {
1025
- return "I still need the time for that reminder. Tell me when it should happen.";
1026
- }
1027
- if (error.status === 429 || normalized.includes("rate limit")) {
1028
- return "LifeOps is rate-limited right now. Try again in a bit.";
1029
- }
1030
- return "I couldn't finish that LifeOps change yet. Tell me the task and timing again, and I'll try it a different way.";
1031
- }
1032
- // ── Calendar/email formatters ─────────────────────────
1033
- const DEFAULT_WINDOW_SLOT_TIMES = {
1034
- morning: {
1035
- minuteOfDay: 8 * 60,
1036
- durationMinutes: 45,
1037
- label: "Morning",
1038
- },
1039
- afternoon: {
1040
- minuteOfDay: 13 * 60,
1041
- durationMinutes: 45,
1042
- label: "Afternoon",
1043
- },
1044
- evening: {
1045
- minuteOfDay: 18 * 60,
1046
- durationMinutes: 45,
1047
- label: "Evening",
1048
- },
1049
- night: {
1050
- minuteOfDay: 21 * 60,
1051
- durationMinutes: 45,
1052
- label: "Night",
1053
- },
1054
- };
1055
- function buildSlotsFromWindows(windows) {
1056
- return windows.map((window, index) => {
1057
- const preset = DEFAULT_WINDOW_SLOT_TIMES[window];
1058
- return {
1059
- key: windows.indexOf(window) === index ? window : `${window}-${index + 1}`,
1060
- label: preset.label,
1061
- minuteOfDay: preset.minuteOfDay,
1062
- durationMinutes: preset.durationMinutes,
1063
- };
1064
- });
1065
- }
1066
- function buildDistributedDailySlots(count) {
1067
- const normalizedCount = Math.max(1, Math.min(6, count));
1068
- const presets = {
1069
- 1: [9 * 60],
1070
- 2: [8 * 60, 21 * 60],
1071
- 3: [8 * 60, 13 * 60, 20 * 60],
1072
- 4: [8 * 60, 12 * 60, 16 * 60, 20 * 60],
1073
- 5: [8 * 60, 11 * 60, 14 * 60, 17 * 60, 20 * 60],
1074
- 6: [8 * 60, 10 * 60, 12 * 60, 14 * 60, 17 * 60, 20 * 60],
1075
- };
1076
- const minutes = presets[normalizedCount] ?? presets[1];
1077
- return minutes.map((minuteOfDay, index) => ({
1078
- key: `slot-${index + 1}`,
1079
- label: `Time ${index + 1}`,
1080
- minuteOfDay,
1081
- durationMinutes: 45,
1082
- }));
1083
- }
1084
- function inferWindowFromMinuteOfDay(minuteOfDay) {
1085
- if (minuteOfDay < 12 * 60) {
1086
- return "morning";
1087
- }
1088
- if (minuteOfDay < 17 * 60) {
1089
- return "afternoon";
1090
- }
1091
- if (minuteOfDay < 21 * 60) {
1092
- return "evening";
1093
- }
1094
- return "night";
1095
- }
1096
- function buildSingleDailySlot(minuteOfDay, durationMinutes = 45) {
1097
- return {
1098
- key: `time-${minuteOfDay}`,
1099
- label: formatMinuteOfDayLabel(minuteOfDay),
1100
- minuteOfDay,
1101
- durationMinutes,
1102
- };
1103
- }
1104
- function addYearsToLocalDate(dateOnly, yearDelta) {
1105
- const utcDate = new Date(Date.UTC(dateOnly.year + yearDelta, dateOnly.month - 1, dateOnly.day, 12));
1106
- return {
1107
- year: utcDate.getUTCFullYear(),
1108
- month: utcDate.getUTCMonth() + 1,
1109
- day: utcDate.getUTCDate(),
1110
- };
1111
- }
1112
- function buildCustomTimeWindowPolicy(minuteOfDay, timeZone) {
1113
- const basePolicy = resolveDefaultWindowPolicy(timeZone);
1114
- return {
1115
- timezone: basePolicy.timezone,
1116
- windows: [
1117
- ...basePolicy.windows,
1118
- {
1119
- name: "custom",
1120
- label: formatMinuteOfDayLabel(minuteOfDay),
1121
- startMinute: minuteOfDay,
1122
- endMinute: Math.min(minuteOfDay + 1, 24 * 60),
1123
- },
1124
- ],
1125
- };
1126
- }
1127
- function formatMinuteOfDayLabel(minuteOfDay) {
1128
- const hour24 = Math.floor(minuteOfDay / 60);
1129
- const minute = minuteOfDay % 60;
1130
- const meridiem = hour24 >= 12 ? "pm" : "am";
1131
- const hour12 = hour24 % 12 === 0 ? 12 : hour24 % 12;
1132
- return minute === 0
1133
- ? `${hour12}${meridiem}`
1134
- : `${hour12}:${String(minute).padStart(2, "0")}${meridiem}`;
1135
- }
1136
- function parseClockToken(token) {
1137
- const normalized = token.trim().toLowerCase();
1138
- if (normalized === "noon") {
1139
- return 12 * 60;
1140
- }
1141
- if (normalized === "midnight") {
1142
- return 0;
1143
- }
1144
- const match = normalized.match(/^(\d{1,2})(?::(\d{2}))?\s*(am|pm)$/);
1145
- if (!match) {
1146
- return null;
1147
- }
1148
- const hour = Number(match[1]);
1149
- const minute = Number(match[2] ?? "0");
1150
- if (!Number.isFinite(hour) || !Number.isFinite(minute) || minute >= 60) {
1151
- return null;
1152
- }
1153
- if (hour < 1 || hour > 12) {
1154
- return null;
1155
- }
1156
- const meridiem = match[3];
1157
- const normalizedHour = meridiem === "am" ? hour % 12 : hour % 12 === 0 ? 12 : (hour % 12) + 12;
1158
- return normalizedHour * 60 + minute;
1159
- }
1160
- function parseTimeOfDayToken(token) {
1161
- const normalized = normalizeLifeInputText(token).toLowerCase();
1162
- const hhmmMatch = normalized.match(/^(\d{1,2}):(\d{2})$/);
1163
- if (hhmmMatch) {
1164
- const hour = Number(hhmmMatch[1]);
1165
- const minute = Number(hhmmMatch[2]);
1166
- if (Number.isFinite(hour) &&
1167
- Number.isFinite(minute) &&
1168
- hour >= 0 &&
1169
- hour <= 23 &&
1170
- minute >= 0 &&
1171
- minute < 60) {
1172
- return hour * 60 + minute;
1173
- }
1174
- }
1175
- return parseClockToken(normalized);
1176
- }
1177
- function resolveAlarmDayOffset(intent) {
1178
- const lower = normalizeLifeInputText(intent).toLowerCase();
1179
- if (/\btomorrow\b/.test(lower))
1180
- return 1;
1181
- if (/\b(today|tonight)\b/.test(lower))
1182
- return 0;
1183
- return null;
1184
- }
1185
- function buildOneOffDueAtFromMinuteOfDay(args) {
1186
- const now = args.now ?? new Date();
1187
- const timeZone = args.timeZone ?? resolveDefaultTimeZone();
1188
- const nowParts = getZonedDateParts(now, timeZone);
1189
- let localDate = {
1190
- year: nowParts.year,
1191
- month: nowParts.month,
1192
- day: nowParts.day,
1193
- };
1194
- const explicitDate = typeof args.intent === "string"
1195
- ? parseExplicitLocalDateForLifeRequest(args.intent, timeZone, now)
1196
- : null;
1197
- if (explicitDate) {
1198
- localDate = explicitDate;
1199
- }
1200
- const explicitDayOffset = typeof args.intent === "string" ? resolveAlarmDayOffset(args.intent) : null;
1201
- if (explicitDate === null && explicitDayOffset !== null) {
1202
- localDate = addDaysToLocalDate(localDate, explicitDayOffset);
1203
- }
1204
- const buildCandidate = () => buildUtcDateFromLocalParts(timeZone, {
1205
- ...localDate,
1206
- hour: Math.floor(args.minuteOfDay / 60),
1207
- minute: args.minuteOfDay % 60,
1208
- second: 0,
1209
- });
1210
- let candidate = buildCandidate();
1211
- if (candidate.getTime() <= now.getTime()) {
1212
- if (explicitDate && !explicitDate.explicitYear) {
1213
- localDate = addYearsToLocalDate(localDate, 1);
1214
- candidate = buildCandidate();
1215
- }
1216
- else if (explicitDate === null && explicitDayOffset === null) {
1217
- localDate = addDaysToLocalDate(localDate, 1);
1218
- candidate = buildCandidate();
1219
- }
1220
- }
1221
- return candidate.toISOString();
1222
- }
1223
- function parseExplicitLocalDateForLifeRequest(value, timeZone, now = new Date()) {
1224
- const normalized = normalizeLifeInputText(value).toLowerCase();
1225
- const localToday = getZonedDateParts(now, timeZone);
1226
- const monthMap = {
1227
- january: 1,
1228
- jan: 1,
1229
- february: 2,
1230
- feb: 2,
1231
- march: 3,
1232
- mar: 3,
1233
- april: 4,
1234
- apr: 4,
1235
- may: 5,
1236
- june: 6,
1237
- jun: 6,
1238
- july: 7,
1239
- jul: 7,
1240
- august: 8,
1241
- aug: 8,
1242
- september: 9,
1243
- sept: 9,
1244
- sep: 9,
1245
- october: 10,
1246
- oct: 10,
1247
- november: 11,
1248
- nov: 11,
1249
- december: 12,
1250
- dec: 12,
1251
- };
1252
- const weekdayMap = {
1253
- sunday: 0,
1254
- sun: 0,
1255
- monday: 1,
1256
- mon: 1,
1257
- tuesday: 2,
1258
- tue: 2,
1259
- tues: 2,
1260
- wednesday: 3,
1261
- wed: 3,
1262
- thursday: 4,
1263
- thu: 4,
1264
- thur: 4,
1265
- thurs: 4,
1266
- friday: 5,
1267
- fri: 5,
1268
- saturday: 6,
1269
- sat: 6,
1270
- };
1271
- const isoMatch = normalized.match(/\b(\d{4})-(\d{1,2})-(\d{1,2})\b/);
1272
- if (isoMatch) {
1273
- return {
1274
- year: Number(isoMatch[1]),
1275
- month: Number(isoMatch[2]),
1276
- day: Number(isoMatch[3]),
1277
- explicitYear: true,
1278
- };
1279
- }
1280
- const monthNameMatch = normalized.match(/\b(jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:t(?:ember)?)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?)\.?\s+(\d{1,2})(?:st|nd|rd|th)?(?:,?\s+(\d{4}))?\b/i);
1281
- if (monthNameMatch) {
1282
- return {
1283
- year: monthNameMatch[3] ? Number(monthNameMatch[3]) : localToday.year,
1284
- month: monthMap[monthNameMatch[1].toLowerCase().replace(/\./g, "")],
1285
- day: Number(monthNameMatch[2]),
1286
- explicitYear: Boolean(monthNameMatch[3]),
1287
- };
1288
- }
1289
- const numericMatch = normalized.match(/\b(\d{1,2})[/-](\d{1,2})(?:[/-](\d{2,4}))?\b/);
1290
- if (numericMatch) {
1291
- const yearRaw = numericMatch[3];
1292
- const year = yearRaw === undefined
1293
- ? localToday.year
1294
- : yearRaw.length === 2
1295
- ? 2000 + Number(yearRaw)
1296
- : Number(yearRaw);
1297
- return {
1298
- year,
1299
- month: Number(numericMatch[1]),
1300
- day: Number(numericMatch[2]),
1301
- explicitYear: Boolean(yearRaw),
1302
- };
1303
- }
1304
- const weekdayMatch = normalized.match(/\b(?:(this|next)\s+)?(sun(?:day)?|mon(?:day)?|tue(?:s(?:day)?)?|wed(?:nesday)?|thu(?:r(?:s(?:day)?)?)?|fri(?:day)?|sat(?:urday)?)\b/i);
1305
- if (!weekdayMatch) {
1306
- return null;
1307
- }
1308
- const weekdayToken = weekdayMatch[2]?.toLowerCase();
1309
- const targetWeekday = weekdayToken ? weekdayMap[weekdayToken] : undefined;
1310
- if (targetWeekday === undefined) {
1311
- return null;
1312
- }
1313
- const qualifier = weekdayMatch[1]?.toLowerCase() ?? "";
1314
- const currentWeekday = new Date(Date.UTC(localToday.year, Math.max(0, localToday.month - 1), localToday.day, 12)).getUTCDay();
1315
- let delta = (targetWeekday - currentWeekday + 7) % 7;
1316
- if (qualifier === "next") {
1317
- delta = delta === 0 ? 7 : delta + 7;
1318
- }
1319
- const resolved = addDaysToLocalDate({
1320
- year: localToday.year,
1321
- month: localToday.month,
1322
- day: localToday.day,
1323
- }, delta);
1324
- return {
1325
- ...resolved,
1326
- explicitYear: false,
1327
- };
1328
- }
1329
- function mergeMetadataRecords(...records) {
1330
- const merged = Object.assign({}, ...records.filter((record) => record != null && Object.keys(record).length > 0));
1331
- return Object.keys(merged).length > 0 ? merged : undefined;
1332
- }
1333
- function extractExplicitDailySlots(intent) {
1334
- const tokens = [
1335
- ...intent.matchAll(/\b(\d{1,2}(?::\d{2})?\s*(?:am|pm)|noon|midnight)\b/gi),
1336
- ].map((match) => match[1]);
1337
- const seen = new Set();
1338
- const slots = [];
1339
- for (const [index, token] of tokens.entries()) {
1340
- const minuteOfDay = parseClockToken(token);
1341
- if (minuteOfDay === null || seen.has(minuteOfDay)) {
1342
- continue;
1343
- }
1344
- seen.add(minuteOfDay);
1345
- slots.push({
1346
- key: `clock-${index + 1}`,
1347
- label: token.trim(),
1348
- minuteOfDay,
1349
- durationMinutes: 45,
1350
- });
1351
- }
1352
- return slots.sort((left, right) => left.minuteOfDay - right.minuteOfDay);
1353
- }
1354
- function normalizeLifeWindows(value) {
1355
- const values = Array.isArray(value) ? value : value == null ? [] : [value];
1356
- const normalized = values.flatMap((entry) => {
1357
- if (typeof entry !== "string") {
1358
- return [];
1359
- }
1360
- const lower = normalizeLifeInputText(entry).toLowerCase();
1361
- if (lower === "morning")
1362
- return ["morning"];
1363
- if (lower === "afternoon")
1364
- return ["afternoon"];
1365
- if (lower === "evening")
1366
- return ["evening"];
1367
- if (lower === "night")
1368
- return ["night"];
1369
- return [];
1370
- });
1371
- return [...new Set(normalized)];
1372
- }
1373
- function normalizeCadenceDetail(value) {
1374
- if (!value || typeof value !== "object" || Array.isArray(value)) {
1375
- return undefined;
1376
- }
1377
- const record = value;
1378
- const cadenceKind = typeof record.kind === "string"
1379
- ? normalizeLifeInputText(record.kind).toLowerCase()
1380
- : typeof record.type === "string"
1381
- ? normalizeLifeInputText(record.type).toLowerCase()
1382
- : "";
1383
- if (!cadenceKind) {
1384
- return undefined;
1385
- }
1386
- if (cadenceKind === "once" && typeof record.dueAt === "string") {
1387
- return {
1388
- kind: "once",
1389
- dueAt: record.dueAt,
1390
- };
1391
- }
1392
- if (cadenceKind === "interval") {
1393
- const everyMinutes = typeof record.everyMinutes === "number"
1394
- ? record.everyMinutes
1395
- : typeof record.everyMinutes === "string"
1396
- ? Number(record.everyMinutes)
1397
- : typeof record.minutes === "number"
1398
- ? record.minutes
1399
- : typeof record.minutes === "string"
1400
- ? Number(record.minutes)
1401
- : NaN;
1402
- if (Number.isFinite(everyMinutes) && everyMinutes > 0) {
1403
- return {
1404
- kind: "interval",
1405
- everyMinutes,
1406
- windows: normalizeLifeWindows(record.windows),
1407
- };
1408
- }
1409
- return undefined;
1410
- }
1411
- if (cadenceKind === "weekly") {
1412
- const weekdays = Array.isArray(record.weekdays)
1413
- ? record.weekdays
1414
- .map((entry) => typeof entry === "number"
1415
- ? entry
1416
- : typeof entry === "string"
1417
- ? Number(entry)
1418
- : NaN)
1419
- .filter((entry) => Number.isFinite(entry))
1420
- : [];
1421
- if (weekdays.length > 0) {
1422
- return {
1423
- kind: "weekly",
1424
- weekdays,
1425
- windows: normalizeLifeWindows(record.windows),
1426
- };
1427
- }
1428
- return undefined;
1429
- }
1430
- const explicitTimes = Array.isArray(record.times)
1431
- ? record.times
1432
- .map((entry) => typeof entry === "string" ? parseTimeOfDayToken(entry) : null)
1433
- .filter((entry) => entry !== null)
1434
- : [];
1435
- if (explicitTimes.length > 0) {
1436
- return {
1437
- kind: "times_per_day",
1438
- slots: explicitTimes.map((minuteOfDay, index) => ({
1439
- key: `time-${index + 1}`,
1440
- label: formatMinuteOfDayLabel(minuteOfDay),
1441
- minuteOfDay,
1442
- durationMinutes: 45,
1443
- })),
1444
- visibilityLeadMinutes: 90,
1445
- visibilityLagMinutes: 180,
1446
- };
1447
- }
1448
- if (cadenceKind === "times_per_day") {
1449
- if (Array.isArray(record.slots)) {
1450
- const slots = record.slots
1451
- .map((entry, index) => {
1452
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
1453
- return null;
1454
- }
1455
- const slot = entry;
1456
- const minuteOfDay = typeof slot.minuteOfDay === "number"
1457
- ? slot.minuteOfDay
1458
- : typeof slot.minuteOfDay === "string"
1459
- ? Number(slot.minuteOfDay)
1460
- : null;
1461
- if (minuteOfDay === null || !Number.isFinite(minuteOfDay)) {
1462
- return null;
1463
- }
1464
- return {
1465
- key: typeof slot.key === "string" && slot.key.trim().length > 0
1466
- ? slot.key
1467
- : `slot-${index + 1}`,
1468
- label: typeof slot.label === "string" && slot.label.trim().length > 0
1469
- ? slot.label
1470
- : formatMinuteOfDayLabel(minuteOfDay),
1471
- minuteOfDay,
1472
- durationMinutes: typeof slot.durationMinutes === "number" &&
1473
- Number.isFinite(slot.durationMinutes) &&
1474
- slot.durationMinutes > 0
1475
- ? slot.durationMinutes
1476
- : 45,
1477
- };
1478
- })
1479
- .filter((entry) => entry !== null);
1480
- if (slots.length > 0) {
1481
- return {
1482
- kind: "times_per_day",
1483
- slots,
1484
- visibilityLeadMinutes: typeof record.visibilityLeadMinutes === "number"
1485
- ? record.visibilityLeadMinutes
1486
- : 90,
1487
- visibilityLagMinutes: typeof record.visibilityLagMinutes === "number"
1488
- ? record.visibilityLagMinutes
1489
- : 180,
1490
- };
1491
- }
1492
- }
1493
- const count = typeof record.count === "number"
1494
- ? record.count
1495
- : typeof record.count === "string"
1496
- ? Number(record.count)
1497
- : NaN;
1498
- if (Number.isFinite(count) && count > 0) {
1499
- return {
1500
- kind: "times_per_day",
1501
- slots: buildDistributedDailySlots(count),
1502
- visibilityLeadMinutes: 90,
1503
- visibilityLagMinutes: 180,
1504
- };
1505
- }
1506
- }
1507
- if (cadenceKind === "daily") {
1508
- const windows = normalizeLifeWindows(record.windows ?? record.window);
1509
- if (windows.length > 0) {
1510
- return {
1511
- kind: "daily",
1512
- windows,
1513
- };
1514
- }
1515
- return {
1516
- kind: "daily",
1517
- windows: ["morning"],
1518
- };
1519
- }
1520
- return undefined;
1521
- }
1522
- /**
1523
- * Convert LLM-extracted params into a typed LifeOpsCadence.
1524
- * Returns null when the LLM output is insufficient to construct a
1525
- * valid cadence, letting the caller fall back to regex-derived values.
1526
- */
1527
- function buildCadenceFromLlmParams(params, context) {
1528
- const kind = params.cadenceKind;
1529
- if (!kind)
1530
- return null;
1531
- const effectiveTimeZone = context?.timeZone;
1532
- const timeOfDayMinute = typeof params.timeOfDay === "string"
1533
- ? parseTimeOfDayToken(params.timeOfDay)
1534
- : null;
1535
- const explicitSlots = typeof context?.intent === "string"
1536
- ? extractExplicitDailySlots(context.intent)
1537
- : [];
1538
- const slotDuration = typeof params.durationMinutes === "number" && params.durationMinutes > 0
1539
- ? params.durationMinutes
1540
- : 45;
1541
- const windows = (params.windows ?? []).filter((w) => w === "morning" || w === "afternoon" || w === "evening" || w === "night");
1542
- const effectiveWindows = windows.length > 0
1543
- ? windows
1544
- : timeOfDayMinute !== null
1545
- ? [inferWindowFromMinuteOfDay(timeOfDayMinute)]
1546
- : ["morning"];
1547
- if (kind === "once") {
1548
- if (timeOfDayMinute !== null) {
1549
- return {
1550
- cadence: {
1551
- kind: "once",
1552
- dueAt: buildOneOffDueAtFromMinuteOfDay({
1553
- intent: context?.intent,
1554
- minuteOfDay: timeOfDayMinute,
1555
- now: context?.now,
1556
- timeZone: effectiveTimeZone,
1557
- }),
1558
- },
1559
- };
1560
- }
1561
- return { cadence: { kind: "once", dueAt: new Date().toISOString() } };
1562
- }
1563
- if (kind === "daily") {
1564
- if (explicitSlots.length >= 2) {
1565
- return {
1566
- cadence: {
1567
- kind: "times_per_day",
1568
- slots: explicitSlots.map((slot) => ({
1569
- ...slot,
1570
- durationMinutes: slot.durationMinutes ?? slotDuration,
1571
- })),
1572
- visibilityLeadMinutes: 90,
1573
- visibilityLagMinutes: 180,
1574
- },
1575
- };
1576
- }
1577
- if (timeOfDayMinute !== null) {
1578
- return {
1579
- cadence: {
1580
- kind: "times_per_day",
1581
- slots: [buildSingleDailySlot(timeOfDayMinute, slotDuration)],
1582
- visibilityLeadMinutes: 90,
1583
- visibilityLagMinutes: 180,
1584
- },
1585
- };
1586
- }
1587
- if (effectiveWindows.length >= 2) {
1588
- return {
1589
- cadence: {
1590
- kind: "times_per_day",
1591
- slots: buildSlotsFromWindows(effectiveWindows),
1592
- visibilityLeadMinutes: 90,
1593
- visibilityLagMinutes: 180,
1594
- },
1595
- };
1596
- }
1597
- return { cadence: { kind: "daily", windows: effectiveWindows } };
1598
- }
1599
- if (kind === "weekly") {
1600
- const weekdays = params.weekdays;
1601
- if (!weekdays || weekdays.length === 0)
1602
- return null;
1603
- if (timeOfDayMinute !== null) {
1604
- return {
1605
- cadence: { kind: "weekly", weekdays, windows: ["custom"] },
1606
- windowPolicy: buildCustomTimeWindowPolicy(timeOfDayMinute, effectiveTimeZone ?? resolveDefaultTimeZone()),
1607
- };
1608
- }
1609
- return { cadence: { kind: "weekly", weekdays, windows: effectiveWindows } };
1610
- }
1611
- if (kind === "interval") {
1612
- const everyMinutes = params.everyMinutes;
1613
- if (!everyMinutes || everyMinutes <= 0)
1614
- return null;
1615
- return {
1616
- cadence: {
1617
- kind: "interval",
1618
- everyMinutes,
1619
- windows: effectiveWindows,
1620
- startMinuteOfDay: timeOfDayMinute ?? undefined,
1621
- durationMinutes: typeof params.durationMinutes === "number" &&
1622
- params.durationMinutes > 0
1623
- ? params.durationMinutes
1624
- : undefined,
1625
- },
1626
- };
1627
- }
1628
- if (kind === "times_per_day") {
1629
- if (explicitSlots.length >= 2) {
1630
- return {
1631
- cadence: {
1632
- kind: "times_per_day",
1633
- slots: explicitSlots.map((slot) => ({
1634
- ...slot,
1635
- durationMinutes: slot.durationMinutes ?? slotDuration,
1636
- })),
1637
- visibilityLeadMinutes: 90,
1638
- visibilityLagMinutes: 180,
1639
- },
1640
- };
1641
- }
1642
- if (timeOfDayMinute !== null) {
1643
- return {
1644
- cadence: {
1645
- kind: "times_per_day",
1646
- slots: [buildSingleDailySlot(timeOfDayMinute, slotDuration)],
1647
- visibilityLeadMinutes: 90,
1648
- visibilityLagMinutes: 180,
1649
- },
1650
- };
1651
- }
1652
- const count = params.timesPerDay;
1653
- if (!count || count <= 0)
1654
- return null;
1655
- return {
1656
- cadence: {
1657
- kind: "times_per_day",
1658
- slots: buildDistributedDailySlots(count).map((slot) => ({
1659
- ...slot,
1660
- durationMinutes: slotDuration,
1661
- })),
1662
- visibilityLeadMinutes: 90,
1663
- visibilityLagMinutes: 180,
1664
- },
1665
- };
1666
- }
1667
- return null;
1668
- }
1669
- function buildCadenceFromUpdateFields(args) {
1670
- const { currentCadence, currentWindowPolicy, timeZone, update } = args;
1671
- const kind = (update.cadenceKind ??
1672
- currentCadence.kind);
1673
- const requestedWindows = normalizeLifeWindows(update.windows ?? []);
1674
- const timeOfDayMinute = typeof update.timeOfDay === "string"
1675
- ? parseTimeOfDayToken(update.timeOfDay)
1676
- : null;
1677
- if (kind === "interval") {
1678
- const everyMinutes = update.everyMinutes ??
1679
- (currentCadence.kind === "interval" ? currentCadence.everyMinutes : null);
1680
- if (!everyMinutes || everyMinutes <= 0) {
1681
- return null;
1682
- }
1683
- const windows = requestedWindows.length > 0
1684
- ? requestedWindows
1685
- : currentCadence.kind === "interval" &&
1686
- currentCadence.windows.length > 0
1687
- ? normalizeLifeWindows(currentCadence.windows)
1688
- : timeOfDayMinute !== null
1689
- ? [inferWindowFromMinuteOfDay(timeOfDayMinute)]
1690
- : ["morning"];
1691
- return {
1692
- cadence: {
1693
- kind: "interval",
1694
- everyMinutes,
1695
- windows,
1696
- startMinuteOfDay: timeOfDayMinute ??
1697
- (currentCadence.kind === "interval"
1698
- ? currentCadence.startMinuteOfDay
1699
- : undefined),
1700
- maxOccurrencesPerDay: currentCadence.kind === "interval"
1701
- ? currentCadence.maxOccurrencesPerDay
1702
- : undefined,
1703
- durationMinutes: currentCadence.kind === "interval"
1704
- ? currentCadence.durationMinutes
1705
- : undefined,
1706
- visibilityLeadMinutes: currentCadence.kind === "interval"
1707
- ? currentCadence.visibilityLeadMinutes
1708
- : undefined,
1709
- visibilityLagMinutes: currentCadence.kind === "interval"
1710
- ? currentCadence.visibilityLagMinutes
1711
- : undefined,
1712
- },
1713
- };
1714
- }
1715
- if (kind === "weekly") {
1716
- const weekdays = update.weekdays ??
1717
- (currentCadence.kind === "weekly" ? currentCadence.weekdays : null);
1718
- if (!weekdays || weekdays.length === 0) {
1719
- return null;
1720
- }
1721
- if (timeOfDayMinute !== null) {
1722
- return {
1723
- cadence: {
1724
- kind: "weekly",
1725
- weekdays,
1726
- windows: ["custom"],
1727
- visibilityLeadMinutes: currentCadence.kind === "weekly"
1728
- ? currentCadence.visibilityLeadMinutes
1729
- : undefined,
1730
- visibilityLagMinutes: currentCadence.kind === "weekly"
1731
- ? currentCadence.visibilityLagMinutes
1732
- : undefined,
1733
- },
1734
- windowPolicy: buildCustomTimeWindowPolicy(timeOfDayMinute, timeZone),
1735
- };
1736
- }
1737
- return {
1738
- cadence: {
1739
- kind: "weekly",
1740
- weekdays,
1741
- windows: requestedWindows.length > 0
1742
- ? requestedWindows
1743
- : currentCadence.kind === "weekly" &&
1744
- currentCadence.windows.length > 0
1745
- ? currentCadence.windows
1746
- : ["morning"],
1747
- visibilityLeadMinutes: currentCadence.kind === "weekly"
1748
- ? currentCadence.visibilityLeadMinutes
1749
- : undefined,
1750
- visibilityLagMinutes: currentCadence.kind === "weekly"
1751
- ? currentCadence.visibilityLagMinutes
1752
- : undefined,
1753
- },
1754
- windowPolicy: currentWindowPolicy.windows.some((window) => (requestedWindows.length > 0
1755
- ? requestedWindows
1756
- : ["morning"]).includes(window.name))
1757
- ? undefined
1758
- : resolveDefaultWindowPolicy(timeZone),
1759
- };
1760
- }
1761
- if (kind === "daily") {
1762
- if (timeOfDayMinute !== null) {
1763
- return {
1764
- cadence: {
1765
- kind: "times_per_day",
1766
- slots: [buildSingleDailySlot(timeOfDayMinute)],
1767
- visibilityLeadMinutes: 90,
1768
- visibilityLagMinutes: 180,
1769
- },
1770
- };
1771
- }
1772
- return {
1773
- cadence: {
1774
- kind: "daily",
1775
- windows: requestedWindows.length > 0
1776
- ? requestedWindows
1777
- : currentCadence.kind === "daily" &&
1778
- currentCadence.windows.length > 0
1779
- ? currentCadence.windows
1780
- : ["morning"],
1781
- visibilityLeadMinutes: currentCadence.kind === "daily"
1782
- ? currentCadence.visibilityLeadMinutes
1783
- : undefined,
1784
- visibilityLagMinutes: currentCadence.kind === "daily"
1785
- ? currentCadence.visibilityLagMinutes
1786
- : undefined,
1787
- },
1788
- };
1789
- }
1790
- if (kind === "times_per_day") {
1791
- if (timeOfDayMinute !== null) {
1792
- return {
1793
- cadence: {
1794
- kind: "times_per_day",
1795
- slots: [buildSingleDailySlot(timeOfDayMinute)],
1796
- visibilityLeadMinutes: 90,
1797
- visibilityLagMinutes: 180,
1798
- },
1799
- };
1800
- }
1801
- if (requestedWindows.length > 0) {
1802
- return {
1803
- cadence: {
1804
- kind: "times_per_day",
1805
- slots: buildSlotsFromWindows(requestedWindows),
1806
- visibilityLeadMinutes: 90,
1807
- visibilityLagMinutes: 180,
1808
- },
1809
- };
1810
- }
1811
- return currentCadence.kind === "times_per_day"
1812
- ? { cadence: currentCadence }
1813
- : null;
1814
- }
1815
- return currentCadence.kind === "once" ? { cadence: currentCadence } : null;
1816
- }
1817
- function hasDefinitionUpdateChanges(request) {
1818
- return (request.title != null ||
1819
- request.cadence != null ||
1820
- request.priority != null ||
1821
- request.description != null ||
1822
- request.windowPolicy != null ||
1823
- request.reminderPlan != null);
1824
- }
1825
- function buildDefaultReminderPlan(label) {
1826
- return {
1827
- steps: [{ channel: "in_app", offsetMinutes: 0, label }],
1828
- };
1829
- }
1830
- function scoreDefinitionTitleQuality(value) {
1831
- const normalized = normalizeTitle(value ?? "");
1832
- if (!normalized) {
1833
- return Number.NEGATIVE_INFINITY;
1834
- }
1835
- let score = normalized.split(/\s+/).filter(Boolean).length;
1836
- if (/\b\d+\b/.test(normalized)) {
1837
- score += 6;
1838
- }
1839
- if (/[+&]/.test(value ?? "") || /\band\b/.test(normalized)) {
1840
- score += 4;
1841
- }
1842
- if (/^(?:do|work out|workout|habit|routine|task|todo|reminder|alarm)\b/.test(normalized)) {
1843
- score -= 5;
1844
- }
1845
- if (GENERIC_DERIVED_TITLE_RE.test(normalized)) {
1846
- score -= 6;
1847
- }
1848
- return score;
1849
- }
1850
- function shouldAdoptPlannerTitle(args) {
1851
- const plannerTitle = args.plannerTitle?.trim();
1852
- if (!plannerTitle) {
1853
- return false;
1854
- }
1855
- const currentTitle = args.currentTitle?.trim();
1856
- if (!currentTitle) {
1857
- return true;
1858
- }
1859
- if (normalizeTitle(currentTitle) === normalizeTitle(plannerTitle)) {
1860
- return false;
1861
- }
1862
- return (scoreDefinitionTitleQuality(plannerTitle) >
1863
- scoreDefinitionTitleQuality(currentTitle));
1864
- }
1865
- function shouldAdoptPlannerCadence(args) {
1866
- const { currentCadence, plannerCadence } = args;
1867
- if (!currentCadence) {
1868
- return true;
1869
- }
1870
- if (currentCadence.kind === "times_per_day") {
1871
- return ((plannerCadence.kind === "times_per_day" &&
1872
- plannerCadence.slots.length >= currentCadence.slots.length) ||
1873
- (plannerCadence.kind === "once" && currentCadence.slots.length === 1));
1874
- }
1875
- if (currentCadence.kind === "weekly") {
1876
- return (plannerCadence.kind === "weekly" &&
1877
- plannerCadence.weekdays.length >= currentCadence.weekdays.length &&
1878
- (currentCadence.windows.includes("custom")
1879
- ? plannerCadence.windows.includes("custom")
1880
- : plannerCadence.windows.length >= currentCadence.windows.length));
1881
- }
1882
- if (currentCadence.kind === "interval") {
1883
- return plannerCadence.kind === "interval";
1884
- }
1885
- if (currentCadence.kind === "once") {
1886
- return plannerCadence.kind === "once";
1887
- }
1888
- if (currentCadence.kind === "daily") {
1889
- return (plannerCadence.kind === "times_per_day" ||
1890
- (plannerCadence.kind === "daily" &&
1891
- plannerCadence.windows.length >= currentCadence.windows.length));
1892
- }
1893
- return true;
1894
- }
1895
- function shouldRequireLifeCreateConfirmation(args) {
1896
- if (args.messageSource === "autonomy") {
1897
- return false;
1898
- }
1899
- if (args.requestKind && args.cadence?.kind === "once") {
1900
- return false;
1901
- }
1902
- return !args.confirmed;
1903
- }
1904
- function describeReminderIntensity(intensity) {
1905
- switch (intensity) {
1906
- case "minimal":
1907
- return "minimal";
1908
- case "normal":
1909
- return "normal";
1910
- case "persistent":
1911
- return "persistent";
1912
- case "high_priority_only":
1913
- return "high priority only";
1914
- }
1915
- return "normal";
1916
- }
1917
- // ── Main action ───────────────────────────────────────
1918
- export const lifeAction = {
1919
- name: "LIFE",
1920
- similes: [
1921
- "MANAGE_LIFEOPS",
1922
- "QUERY_LIFEOPS",
1923
- "CREATE_TASK",
1924
- "CREATE_HABIT",
1925
- "CREATE_GOAL",
1926
- "TRACK_HABIT",
1927
- "COMPLETE_TASK",
1928
- "SET_ALARM",
1929
- "SET_REMINDER",
1930
- "SNOOZE_REMINDER",
1931
- "SET_REMINDER_INTENSITY",
1932
- ],
1933
- description: "Manage the user's personal routines, habits, goals, reminders, alarms, and escalation settings through LifeOps. " +
1934
- "USE this action for: creating, editing, or deleting tasks, habits, routines, and goals; " +
1935
- "setting one-off alarms or wake-up reminders like 'set an alarm for 7am' or 'wake me up at 7'; " +
1936
- "helping the user actually set up follow-through when they say things like 'help me brush my teeth every day', 'i keep forgetting x', or 'help me actually do it'; " +
1937
- "using LifeOps defaults for common routines when the user gives a natural window instead of an exact clock, like water reminders, stretch breaks, weekday-after-lunch Invisalign checks, or brushing when they wake up and before bed; " +
1938
- "marking items as complete, skipping, or snoozing them; reviewing goal progress; " +
1939
- "setting up phone/SMS escalation channels; adjusting reminder frequency or intensity; " +
1940
- "querying an overview of active LifeOps items. " +
1941
- "ALWAYS use LIFE for dynamic status questions like 'what's still left for today', 'what do i still need to do today', or 'anything else in my LifeOps list', even when the conversation already mentioned tasks, because their status may have changed after a completion, snooze, or reminder. " +
1942
- "DO NOT use this action for Gmail inbox triage, email search, drafting or sending emails — use GMAIL_ACTION instead. " +
1943
- "DO NOT use this action for calendar lookups, scheduling meetings, searching events, or travel itineraries — use CALENDAR_ACTION instead. " +
1944
- "This action provides the final grounded reply; do not pair it with a speculative REPLY action or fall back to advice-only chat when the user wants real LifeOps follow-through.",
1945
- suppressPostActionContinuation: true,
1946
- validate: async (runtime, message) => {
1947
- return hasLifeOpsAccess(runtime, message);
1948
- },
1949
- handler: async (runtime, message, state, options) => {
1950
- if (!(await hasLifeOpsAccess(runtime, message))) {
1951
- const fallback = "Life management is restricted to the owner, explicitly granted users, and the agent.";
1952
- return {
1953
- success: false,
1954
- text: await renderLifeActionReply({
1955
- runtime,
1956
- message,
1957
- state,
1958
- intent: normalizeLifeInputText(messageText(message)),
1959
- scenario: "reply_only",
1960
- fallback,
1961
- context: {
1962
- reason: "access_restricted",
1963
- },
1964
- }),
1965
- };
1966
- }
1967
- const rawParams = options?.parameters;
1968
- const params = rawParams ?? {};
1969
- const currentText = normalizeLifeInputText(messageText(message));
1970
- const details = params.details;
1971
- const deferredDraft = latestDeferredLifeDraft(state);
1972
- const turnsSinceDraft = deferredDraft != null
1973
- ? (countTurnsSinceLatestDeferredLifeDraft(state) ?? 0) + 1
1974
- : undefined;
1975
- const draftExpiryReason = deferredLifeDraftExpiryReason({
1976
- draft: deferredDraft,
1977
- turnsSinceDraft,
1978
- });
1979
- if (draftExpiryReason && looksLikeDeferredLifeConfirmation(currentText)) {
1980
- const fallback = "That LifeOps draft expired. Please restate it and I'll preview it again.";
1981
- return {
1982
- success: false,
1983
- text: await renderLifeActionReply({
1984
- runtime,
1985
- message,
1986
- state,
1987
- intent: currentText,
1988
- scenario: "reply_only",
1989
- fallback,
1990
- context: {
1991
- reason: "draft_expired",
1992
- },
1993
- }),
1994
- };
1995
- }
1996
- const deferredDraftFollowupMode = deferredDraft
1997
- ? await extractDeferredLifeDraftFollowupWithLlm({
1998
- runtime,
1999
- message,
2000
- state,
2001
- currentText,
2002
- draft: deferredDraft,
2003
- })
2004
- : null;
2005
- if (deferredDraftFollowupMode === "cancel") {
2006
- const fallback = "Okay, I won't save it yet.";
2007
- return {
2008
- success: true,
2009
- text: await renderLifeActionReply({
2010
- runtime,
2011
- message,
2012
- state,
2013
- intent: currentText,
2014
- scenario: "reply_only",
2015
- fallback,
2016
- context: {
2017
- reason: "draft_cancelled",
2018
- draft: deferredDraft
2019
- ? {
2020
- operation: deferredDraft.operation,
2021
- title: deferredDraft.request.title,
2022
- }
2023
- : null,
2024
- },
2025
- }),
2026
- data: {
2027
- actionName: "LIFE",
2028
- noop: true,
2029
- },
2030
- };
2031
- }
2032
- const deferredDraftReuseMode = resolveDeferredLifeDraftReuseMode({
2033
- currentText,
2034
- details,
2035
- draft: deferredDraft,
2036
- explicitAction: params.action,
2037
- paramsIntent: params.intent,
2038
- target: params.target,
2039
- title: params.title,
2040
- llmMode: deferredDraftFollowupMode,
2041
- turnsSinceDraft,
2042
- });
2043
- const reuseDeferredDraft = deferredDraftReuseMode !== null;
2044
- const intent = reuseDeferredDraft
2045
- ? deferredDraftReuseMode === "confirm"
2046
- ? normalizeLifeInputText(deferredDraft?.intent ?? "")
2047
- : normalizeLifeInputText(params.intent?.trim() ?? currentText)
2048
- : normalizeLifeInputText(params.intent?.trim() ?? currentText);
2049
- if (!intent) {
2050
- const fallback = "Tell me what you want me to do.";
2051
- return {
2052
- success: false,
2053
- text: await renderLifeActionReply({
2054
- runtime,
2055
- message,
2056
- state,
2057
- intent: currentText,
2058
- scenario: "reply_only",
2059
- fallback,
2060
- context: {
2061
- reason: "missing_intent",
2062
- },
2063
- }),
2064
- };
2065
- }
2066
- const explicitOperation = params.action
2067
- ? ACTION_TO_OPERATION[params.action]
2068
- : undefined;
2069
- const operationPlan = reuseDeferredDraft && deferredDraft
2070
- ? {
2071
- confidence: 1,
2072
- missing: [],
2073
- operation: deferredDraft.operation,
2074
- shouldAct: true,
2075
- }
2076
- : await resolveLifeOperationPlan({
2077
- runtime,
2078
- message,
2079
- state,
2080
- intent,
2081
- explicitOperation,
2082
- });
2083
- const forceCreateExecution = shouldForceLifeCreateExecution({
2084
- intent,
2085
- missing: operationPlan.missing,
2086
- operation: operationPlan.operation,
2087
- details,
2088
- title: params.title,
2089
- });
2090
- if (!operationPlan.shouldAct && !forceCreateExecution) {
2091
- const fallback = buildLifeClarificationFallback({
2092
- missing: operationPlan.missing,
2093
- operation: operationPlan.operation,
2094
- });
2095
- return {
2096
- success: true,
2097
- text: await renderLifeActionReply({
2098
- runtime,
2099
- message,
2100
- state,
2101
- intent,
2102
- scenario: operationPlan.operation === "create_goal"
2103
- ? "clarify_create_goal"
2104
- : "clarify_create_definition",
2105
- fallback,
2106
- context: {
2107
- missing: operationPlan.missing,
2108
- operation: operationPlan.operation,
2109
- },
2110
- }),
2111
- data: {
2112
- actionName: "LIFE",
2113
- noop: true,
2114
- suggestedOperation: operationPlan.operation,
2115
- },
2116
- };
2117
- }
2118
- const operation = (forceCreateExecution ? "create_definition" : operationPlan.operation) ??
2119
- classifyIntent(intent);
2120
- const service = new LifeOpsService(runtime);
2121
- const domain = detailString(details, "domain");
2122
- const ownership = requestedOwnership(domain);
2123
- const chatText = intent;
2124
- const targetName = params.target ?? params.title;
2125
- const createConfirmed = deferredDraftReuseMode === "confirm" ||
2126
- detailBoolean(details, "confirmed") === true;
2127
- try {
2128
- const createDefinition = async () => {
2129
- const deferredDefinitionDraft = reuseDeferredDraft && deferredDraft?.operation === "create_definition"
2130
- ? deferredDraft
2131
- : null;
2132
- const editingDeferredDefinitionDraft = deferredDraftReuseMode === "edit" &&
2133
- deferredDefinitionDraft?.operation === "create_definition";
2134
- const explicitCadenceDetail = normalizeCadenceDetail(detailObject(details, "cadence"));
2135
- const fallbackTitle = deferredDefinitionDraft?.request.title ?? null;
2136
- let title = editingDeferredDefinitionDraft
2137
- ? (params.title ?? fallbackTitle)
2138
- : (fallbackTitle ?? params.title ?? null);
2139
- const fallbackCadence = deferredDefinitionDraft?.request.cadence;
2140
- let cadence = editingDeferredDefinitionDraft
2141
- ? (explicitCadenceDetail ?? fallbackCadence ?? undefined)
2142
- : (fallbackCadence ?? explicitCadenceDetail ?? undefined);
2143
- let windowPolicy = editingDeferredDefinitionDraft
2144
- ? (detailObject(details, "windowPolicy") ?? deferredDefinitionDraft?.request.windowPolicy)
2145
- : (deferredDefinitionDraft?.request.windowPolicy ??
2146
- detailObject(details, "windowPolicy"));
2147
- const explicitPriority = detailNumber(details, "priority");
2148
- const explicitDescription = detailString(details, "description");
2149
- const explicitMetadata = detailObject(details, "metadata");
2150
- // Track whether cadence/title came from explicit high-confidence
2151
- // sources so the planner only fills genuine gaps.
2152
- const hadExplicitCadence = Boolean((editingDeferredDefinitionDraft
2153
- ? (explicitCadenceDetail ??
2154
- deferredDefinitionDraft?.request.cadence)
2155
- : deferredDefinitionDraft?.request.cadence) ??
2156
- explicitCadenceDetail);
2157
- const hadExplicitTitle = Boolean((editingDeferredDefinitionDraft
2158
- ? params.title
2159
- : deferredDefinitionDraft?.request.title) ?? params.title);
2160
- // ── LLM parameter enhancement (fills gaps) ────────
2161
- // Skip when reusing a confirmed deferred draft — the user already
2162
- // approved those values.
2163
- let llmPlan = null;
2164
- let llmDescription;
2165
- let llmPriority;
2166
- let llmRequestKind = null;
2167
- if (!deferredDefinitionDraft || editingDeferredDefinitionDraft) {
2168
- llmPlan = await extractTaskCreatePlanWithLlm({
2169
- runtime,
2170
- intent,
2171
- state: state ?? undefined,
2172
- message: message ?? undefined,
2173
- });
2174
- const shouldHonorPlannerResponse = llmPlan?.mode === "respond" &&
2175
- Boolean(llmPlan.response) &&
2176
- !editingDeferredDefinitionDraft &&
2177
- !params.title &&
2178
- !explicitCadenceDetail &&
2179
- !detailString(details, "description") &&
2180
- !detailString(details, "goalId") &&
2181
- !detailString(details, "goalTitle") &&
2182
- !detailString(details, "kind");
2183
- if (shouldHonorPlannerResponse && llmPlan?.response) {
2184
- return {
2185
- success: true,
2186
- text: llmPlan.response,
2187
- };
2188
- }
2189
- if (llmPlan) {
2190
- llmRequestKind = llmPlan.requestKind;
2191
- if (!hadExplicitTitle &&
2192
- shouldAdoptPlannerTitle({
2193
- currentTitle: title,
2194
- plannerTitle: llmPlan.title,
2195
- })) {
2196
- title = llmPlan.title;
2197
- }
2198
- if ((editingDeferredDefinitionDraft || !hadExplicitCadence) &&
2199
- llmPlan.cadenceKind) {
2200
- const llmCadenceTimeZone = normalizeLifeTimeZoneToken(detailString(details, "timeZone") ??
2201
- llmPlan.timeZone ??
2202
- deferredDefinitionDraft?.request.timezone ??
2203
- windowPolicy?.timezone) ?? extractLifeTimeZoneFromText(intent);
2204
- const llmCadence = buildCadenceFromLlmParams(llmPlan, {
2205
- intent,
2206
- timeZone: llmCadenceTimeZone ?? undefined,
2207
- });
2208
- if (llmCadence &&
2209
- shouldAdoptPlannerCadence({
2210
- currentCadence: cadence,
2211
- plannerCadence: llmCadence.cadence,
2212
- })) {
2213
- cadence = llmCadence.cadence;
2214
- windowPolicy = llmCadence.windowPolicy ?? windowPolicy;
2215
- }
2216
- }
2217
- if (!explicitDescription && llmPlan.description) {
2218
- llmDescription = llmPlan.description;
2219
- }
2220
- if (explicitPriority === undefined && llmPlan.priority) {
2221
- llmPriority = llmPlan.priority;
2222
- }
2223
- }
2224
- }
2225
- const resolvedTimeZone = normalizeLifeTimeZoneToken(detailString(details, "timeZone") ??
2226
- llmPlan?.timeZone ??
2227
- deferredDefinitionDraft?.request.timezone ??
2228
- windowPolicy?.timezone) ?? extractLifeTimeZoneFromText(intent);
2229
- const timedRequestKind = llmRequestKind;
2230
- const nativeAppleMetadata = timedRequestKind && cadence?.kind === "once"
2231
- ? buildNativeAppleReminderMetadata({
2232
- kind: timedRequestKind,
2233
- source: "llm",
2234
- })
2235
- : undefined;
2236
- const definitionMetadata = editingDeferredDefinitionDraft
2237
- ? mergeMetadataRecords(deferredDefinitionDraft?.request.metadata, mergeMetadataRecords(explicitMetadata, nativeAppleMetadata))
2238
- : (deferredDefinitionDraft?.request.metadata ??
2239
- mergeMetadataRecords(explicitMetadata, nativeAppleMetadata));
2240
- if (!title) {
2241
- const fallback = "What should I call it?";
2242
- return {
2243
- success: false,
2244
- text: await renderLifeActionReply({
2245
- runtime,
2246
- message,
2247
- state,
2248
- intent,
2249
- scenario: "clarify_create_definition",
2250
- fallback,
2251
- context: {
2252
- missing: ["title"],
2253
- operation: "create_definition",
2254
- },
2255
- }),
2256
- };
2257
- }
2258
- if (!cadence) {
2259
- const fallback = "When should it happen?";
2260
- return {
2261
- success: false,
2262
- text: await renderLifeActionReply({
2263
- runtime,
2264
- message,
2265
- state,
2266
- intent,
2267
- scenario: "clarify_create_definition",
2268
- fallback,
2269
- context: {
2270
- missing: ["schedule"],
2271
- operation: "create_definition",
2272
- },
2273
- }),
2274
- };
2275
- }
2276
- const kind = (editingDeferredDefinitionDraft
2277
- ? detailString(details, "kind")
2278
- : deferredDefinitionDraft?.request.kind) ??
2279
- detailString(details, "kind") ??
2280
- "habit";
2281
- const definitionDraft = {
2282
- intent,
2283
- operation: "create_definition",
2284
- createdAt: editingDeferredDefinitionDraft
2285
- ? Date.now()
2286
- : (deferredDefinitionDraft?.createdAt ?? Date.now()),
2287
- request: {
2288
- cadence,
2289
- description: explicitDescription ??
2290
- llmDescription ??
2291
- (editingDeferredDefinitionDraft
2292
- ? deferredDefinitionDraft?.request.description
2293
- : undefined),
2294
- goalRef: detailString(details, "goalId") ??
2295
- detailString(details, "goalTitle") ??
2296
- deferredDefinitionDraft?.request.goalRef ??
2297
- undefined,
2298
- kind,
2299
- priority: explicitPriority ??
2300
- llmPriority ??
2301
- deferredDefinitionDraft?.request.priority,
2302
- progressionRule: detailObject(details, "progressionRule") ??
2303
- deferredDefinitionDraft?.request.progressionRule,
2304
- reminderPlan: detailObject(details, "reminderPlan") ??
2305
- deferredDefinitionDraft?.request.reminderPlan ??
2306
- buildDefaultReminderPlan(`${title} reminder`),
2307
- timezone: extractLifeTimeZoneFromText(intent) ??
2308
- normalizeLifeTimeZoneToken(llmPlan?.timeZone) ??
2309
- normalizeLifeTimeZoneToken(resolvedTimeZone ?? deferredDefinitionDraft?.request.timezone) ??
2310
- resolvedTimeZone ??
2311
- deferredDefinitionDraft?.request.timezone,
2312
- title,
2313
- metadata: definitionMetadata,
2314
- windowPolicy,
2315
- websiteAccess: detailObject(details, "websiteAccess") ?? deferredDefinitionDraft?.request.websiteAccess,
2316
- },
2317
- };
2318
- if (shouldRequireLifeCreateConfirmation({
2319
- confirmed: createConfirmed,
2320
- messageSource: typeof message.content?.source === "string"
2321
- ? message.content.source
2322
- : undefined,
2323
- requestKind: timedRequestKind,
2324
- cadence: definitionDraft.request.cadence,
2325
- })) {
2326
- const fallback = `I can save this as a ${definitionDraft.request.kind} named "${definitionDraft.request.title}" that happens ${summarizeCadence(definitionDraft.request.cadence)}. Confirm and I'll save it, or tell me what to change.`;
2327
- return {
2328
- success: true,
2329
- text: await renderLifeActionReply({
2330
- runtime,
2331
- message,
2332
- state,
2333
- intent,
2334
- scenario: "preview_definition",
2335
- fallback,
2336
- context: {
2337
- draft: definitionDraft.request,
2338
- requestKind: timedRequestKind,
2339
- },
2340
- }),
2341
- data: {
2342
- actionName: "LIFE",
2343
- deferred: true,
2344
- lifeDraft: definitionDraft,
2345
- preview: {
2346
- cadence: definitionDraft.request.cadence,
2347
- kind: definitionDraft.request.kind,
2348
- title: definitionDraft.request.title,
2349
- },
2350
- },
2351
- };
2352
- }
2353
- const resolvedGoal = definitionDraft.request.goalRef
2354
- ? await resolveGoal(service, definitionDraft.request.goalRef, domain)
2355
- : null;
2356
- const created = await service.createDefinition({
2357
- ownership,
2358
- kind: definitionDraft.request.kind,
2359
- title: definitionDraft.request.title,
2360
- description: definitionDraft.request.description,
2361
- originalIntent: definitionDraft.intent || definitionDraft.request.title,
2362
- cadence: definitionDraft.request.cadence,
2363
- timezone: extractLifeTimeZoneFromText(definitionDraft.intent) ??
2364
- normalizeLifeTimeZoneToken(definitionDraft.request.timezone) ??
2365
- definitionDraft.request.timezone,
2366
- priority: definitionDraft.request.priority,
2367
- windowPolicy: definitionDraft.request.windowPolicy,
2368
- progressionRule: definitionDraft.request.progressionRule,
2369
- reminderPlan: definitionDraft.request.reminderPlan,
2370
- metadata: definitionDraft.request.metadata,
2371
- websiteAccess: definitionDraft.request.websiteAccess,
2372
- goalId: resolvedGoal?.goal.id ?? null,
2373
- source: "chat",
2374
- });
2375
- const fallback = `Saved "${created.definition.title}" as ${summarizeCadence(created.definition.cadence)}.`;
2376
- return {
2377
- success: true,
2378
- text: await renderLifeActionReply({
2379
- runtime,
2380
- message,
2381
- state,
2382
- intent,
2383
- scenario: "saved_definition",
2384
- fallback,
2385
- context: {
2386
- created: {
2387
- title: created.definition.title,
2388
- cadence: created.definition.cadence,
2389
- },
2390
- requestKind: timedRequestKind,
2391
- },
2392
- }),
2393
- data: toActionData(created),
2394
- };
2395
- };
2396
- // ── Queries ─────────────────────────────────────
2397
- if (operation === "query_calendar_today" ||
2398
- operation === "query_calendar_next") {
2399
- const google = await getGoogleCapabilityStatus(service);
2400
- if (!google.hasCalendarRead) {
2401
- return {
2402
- success: false,
2403
- text: calendarReadUnavailableMessage(google),
2404
- };
2405
- }
2406
- if (operation === "query_calendar_next") {
2407
- const ctx = await service.getNextCalendarEventContext(INTERNAL_URL);
2408
- return {
2409
- success: true,
2410
- text: formatNextEventContext(ctx),
2411
- data: toActionData(ctx),
2412
- };
2413
- }
2414
- const timeRangeHint = intent.toLowerCase();
2415
- const range = /\btomorrow\b/.test(timeRangeHint)
2416
- ? dayRange(1)
2417
- : /\b(this week|week)\b/.test(timeRangeHint)
2418
- ? weekRange()
2419
- : dayRange(0);
2420
- const label = /\btomorrow\b/.test(timeRangeHint)
2421
- ? "tomorrow"
2422
- : /\b(this week|week)\b/.test(timeRangeHint)
2423
- ? "this week"
2424
- : "today";
2425
- const feed = await service.getCalendarFeed(INTERNAL_URL, {
2426
- timeMin: range.timeMin,
2427
- timeMax: range.timeMax,
2428
- });
2429
- return {
2430
- success: true,
2431
- text: formatCalendarFeed(feed, label),
2432
- data: toActionData(feed),
2433
- };
2434
- }
2435
- if (operation === "query_email") {
2436
- const limit = detailNumber(details, "limit") ?? 10;
2437
- return ((await gmailAction.handler?.(runtime, message, state, {
2438
- parameters: {
2439
- subaction: "triage",
2440
- intent,
2441
- details: {
2442
- ...details,
2443
- maxResults: limit,
2444
- },
2445
- },
2446
- })) ?? {
2447
- success: false,
2448
- text: "I couldn't route that Gmail request yet.",
2449
- });
2450
- }
2451
- if (operation === "query_overview") {
2452
- const overview = await service.getOverview();
2453
- const userQuery = messageText(message) || intent || "overview";
2454
- const fallback = formatOverviewForQuery(overview, userQuery);
2455
- return {
2456
- success: true,
2457
- text: await renderLifeActionReply({
2458
- runtime,
2459
- message,
2460
- state,
2461
- intent: userQuery,
2462
- scenario: "overview",
2463
- fallback,
2464
- context: {
2465
- summary: overview.owner.summary,
2466
- occurrenceTitles: overview.owner.occurrences
2467
- .slice(0, 6)
2468
- .map((occurrence) => occurrence.title),
2469
- goalTitles: overview.owner.goals
2470
- .slice(0, 3)
2471
- .map((goal) => goal.title),
2472
- },
2473
- }),
2474
- data: toActionData(overview),
2475
- };
2476
- }
2477
- // ── Mutations ───────────────────────────────────
2478
- if (operation === "create_definition") {
2479
- return await createDefinition();
2480
- }
2481
- if (operation === "create_goal") {
2482
- const deferredGoalDraft = reuseDeferredDraft && deferredDraft?.operation === "create_goal"
2483
- ? deferredDraft
2484
- : null;
2485
- const editingDeferredGoalDraft = deferredDraftReuseMode === "edit" &&
2486
- deferredGoalDraft?.operation === "create_goal";
2487
- const explicitDescription = detailString(details, "description");
2488
- const explicitCadence = normalizeCadenceDetail(detailObject(details, "cadence"));
2489
- const explicitSuccessCriteria = detailObject(details, "successCriteria");
2490
- const explicitSupportStrategy = detailObject(details, "supportStrategy");
2491
- const explicitMetadata = detailObject(details, "metadata");
2492
- let title = editingDeferredGoalDraft
2493
- ? (params.title ?? deferredGoalDraft?.request.title ?? null)
2494
- : (deferredGoalDraft?.request.title ?? params.title ?? null);
2495
- let description = editingDeferredGoalDraft
2496
- ? (explicitDescription ?? deferredGoalDraft?.request.description)
2497
- : (deferredGoalDraft?.request.description ?? explicitDescription);
2498
- let cadence = editingDeferredGoalDraft
2499
- ? (explicitCadence ?? deferredGoalDraft?.request.cadence)
2500
- : (deferredGoalDraft?.request.cadence ?? explicitCadence);
2501
- let successCriteria = editingDeferredGoalDraft
2502
- ? (explicitSuccessCriteria ??
2503
- deferredGoalDraft?.request.successCriteria)
2504
- : (deferredGoalDraft?.request.successCriteria ??
2505
- explicitSuccessCriteria);
2506
- let supportStrategy = editingDeferredGoalDraft
2507
- ? (explicitSupportStrategy ??
2508
- deferredGoalDraft?.request.supportStrategy)
2509
- : (deferredGoalDraft?.request.supportStrategy ??
2510
- explicitSupportStrategy);
2511
- let goalMetadata = editingDeferredGoalDraft
2512
- ? (explicitMetadata ?? deferredGoalDraft?.request.metadata)
2513
- : (deferredGoalDraft?.request.metadata ?? explicitMetadata);
2514
- let evaluationSummary = null;
2515
- if (!deferredGoalDraft || editingDeferredGoalDraft) {
2516
- const llmPlan = await extractGoalCreatePlanWithLlm({
2517
- runtime,
2518
- intent,
2519
- state: state ?? undefined,
2520
- message: message ?? undefined,
2521
- });
2522
- if (!title && llmPlan.title) {
2523
- title = llmPlan.title;
2524
- }
2525
- if (!description && llmPlan.description) {
2526
- description = llmPlan.description;
2527
- }
2528
- if (!cadence && llmPlan.cadence) {
2529
- cadence = llmPlan.cadence;
2530
- }
2531
- if (!successCriteria && llmPlan.successCriteria) {
2532
- successCriteria = llmPlan.successCriteria;
2533
- }
2534
- if (!supportStrategy && llmPlan.supportStrategy) {
2535
- supportStrategy = llmPlan.supportStrategy;
2536
- }
2537
- evaluationSummary = llmPlan.evaluationSummary;
2538
- if (llmPlan.groundingState === "grounded" &&
2539
- llmPlan.successCriteria &&
2540
- title) {
2541
- goalMetadata = mergeGoalMetadataWithGrounding({
2542
- metadata: {
2543
- ...(goalMetadata ?? {}),
2544
- source: "chat",
2545
- originalIntent: intent,
2546
- },
2547
- nowIso: new Date().toISOString(),
2548
- plan: llmPlan,
2549
- });
2550
- }
2551
- if (llmPlan.groundingState !== "grounded" ||
2552
- !title ||
2553
- !successCriteria ||
2554
- !supportStrategy) {
2555
- return {
2556
- success: true,
2557
- text: llmPlan.response ??
2558
- "What would count as success for that goal, and over what time window?",
2559
- data: {
2560
- actionName: "LIFE",
2561
- noop: true,
2562
- suggestedOperation: "create_goal",
2563
- },
2564
- };
2565
- }
2566
- }
2567
- if (!title)
2568
- return {
2569
- success: false,
2570
- text: await renderLifeActionReply({
2571
- runtime,
2572
- message,
2573
- state,
2574
- intent,
2575
- scenario: "clarify_create_goal",
2576
- fallback: "What are you trying to achieve?",
2577
- context: {
2578
- missing: ["title"],
2579
- operation: "create_goal",
2580
- },
2581
- }),
2582
- };
2583
- const goalDraft = deferredGoalDraft ?? {
2584
- intent,
2585
- operation: "create_goal",
2586
- createdAt: Date.now(),
2587
- request: {
2588
- cadence,
2589
- description,
2590
- metadata: goalMetadata,
2591
- successCriteria,
2592
- supportStrategy,
2593
- title,
2594
- },
2595
- };
2596
- if (shouldRequireLifeCreateConfirmation({
2597
- confirmed: createConfirmed,
2598
- messageSource: typeof message.content?.source === "string"
2599
- ? message.content.source
2600
- : undefined,
2601
- })) {
2602
- const fallback = evaluationSummary
2603
- ? `I can save "${goalDraft.request.title}" as a goal. Success looks like this: ${evaluationSummary} Confirm and I'll save it, or tell me what to change.`
2604
- : `I can save this goal as "${goalDraft.request.title}". Confirm and I'll save it, or tell me what to change.`;
2605
- return {
2606
- success: true,
2607
- text: await renderLifeActionReply({
2608
- runtime,
2609
- message,
2610
- state,
2611
- intent,
2612
- scenario: "preview_goal",
2613
- fallback,
2614
- context: {
2615
- draft: goalDraft.request,
2616
- groundingSummary: evaluationSummary,
2617
- },
2618
- }),
2619
- data: {
2620
- actionName: "LIFE",
2621
- deferred: true,
2622
- lifeDraft: goalDraft,
2623
- preview: {
2624
- title: goalDraft.request.title,
2625
- },
2626
- },
2627
- };
2628
- }
2629
- const created = await service.createGoal({
2630
- ownership,
2631
- title: goalDraft.request.title,
2632
- description: goalDraft.request.description,
2633
- cadence: goalDraft.request.cadence,
2634
- supportStrategy: goalDraft.request.supportStrategy,
2635
- successCriteria: goalDraft.request.successCriteria,
2636
- metadata: {
2637
- ...(goalDraft.request.metadata ?? {}),
2638
- source: "chat",
2639
- originalIntent: goalDraft.intent || goalDraft.request.title,
2640
- },
2641
- });
2642
- const fallback = `Saved goal "${created.goal.title}".`;
2643
- return {
2644
- success: true,
2645
- text: await renderLifeActionReply({
2646
- runtime,
2647
- message,
2648
- state,
2649
- intent,
2650
- scenario: "saved_goal",
2651
- fallback,
2652
- context: {
2653
- created: {
2654
- title: created.goal.title,
2655
- cadence: created.goal.cadence,
2656
- },
2657
- },
2658
- }),
2659
- data: toActionData(created),
2660
- };
2661
- }
2662
- if (operation === "update_definition") {
2663
- const target = await resolveDefinition(service, targetName, domain);
2664
- if (!target)
2665
- return {
2666
- success: false,
2667
- text: "I could not find that item to update.",
2668
- };
2669
- const request = {
2670
- ownership,
2671
- title: params.title !== target.definition.title ? params.title : undefined,
2672
- description: detailString(details, "description"),
2673
- cadence: normalizeCadenceDetail(detailObject(details, "cadence")),
2674
- priority: detailNumber(details, "priority"),
2675
- windowPolicy: detailObject(details, "windowPolicy"),
2676
- reminderPlan: detailObject(details, "reminderPlan"),
2677
- };
2678
- // If no explicit changes from structured details, try LLM extraction
2679
- const hasExplicitChanges = hasDefinitionUpdateChanges(request);
2680
- if (!hasExplicitChanges && intent) {
2681
- const llmFields = await extractUpdateFieldsWithLlm({
2682
- runtime,
2683
- intent,
2684
- currentTitle: target.definition.title,
2685
- currentCadenceKind: target.definition.cadence.kind,
2686
- currentWindows: target.definition.windowPolicy?.windows?.map((w) => w.name) ?? [],
2687
- });
2688
- if (llmFields) {
2689
- if (llmFields.title)
2690
- request.title = llmFields.title;
2691
- if (llmFields.priority)
2692
- request.priority = llmFields.priority;
2693
- if (llmFields.description)
2694
- request.description = llmFields.description;
2695
- if (llmFields.cadenceKind ||
2696
- llmFields.windows ||
2697
- llmFields.weekdays ||
2698
- llmFields.everyMinutes ||
2699
- llmFields.timeOfDay) {
2700
- const built = buildCadenceFromUpdateFields({
2701
- currentCadence: target.definition.cadence,
2702
- currentWindowPolicy: target.definition.windowPolicy,
2703
- timeZone: target.definition.timezone,
2704
- update: llmFields,
2705
- });
2706
- if (built) {
2707
- request.cadence = built.cadence;
2708
- request.windowPolicy = built.windowPolicy;
2709
- }
2710
- }
2711
- }
2712
- }
2713
- if (!hasDefinitionUpdateChanges(request)) {
2714
- return {
2715
- success: false,
2716
- text: `Tell me what to change about "${target.definition.title}" and I'll update it.`,
2717
- };
2718
- }
2719
- const updated = await service.updateDefinition(target.definition.id, request);
2720
- const fallback = `Updated "${updated.definition.title}".`;
2721
- return {
2722
- success: true,
2723
- text: await renderLifeActionReply({
2724
- runtime,
2725
- message,
2726
- state,
2727
- intent,
2728
- scenario: "updated_definition",
2729
- fallback,
2730
- context: {
2731
- previousTitle: target.definition.title,
2732
- updated: {
2733
- title: updated.definition.title,
2734
- },
2735
- },
2736
- }),
2737
- data: toActionData(updated),
2738
- };
2739
- }
2740
- if (operation === "update_goal") {
2741
- const target = await resolveGoal(service, targetName, domain);
2742
- if (!target)
2743
- return {
2744
- success: false,
2745
- text: "I could not find that goal to update.",
2746
- };
2747
- const request = {
2748
- ownership,
2749
- title: params.title !== target.goal.title ? params.title : undefined,
2750
- description: detailString(details, "description"),
2751
- cadence: normalizeCadenceDetail(detailObject(details, "cadence")),
2752
- supportStrategy: detailObject(details, "supportStrategy"),
2753
- successCriteria: detailObject(details, "successCriteria"),
2754
- };
2755
- const hasExplicitGoalChanges = request.title !== undefined ||
2756
- request.description !== undefined ||
2757
- request.cadence !== undefined ||
2758
- request.supportStrategy !== undefined ||
2759
- request.successCriteria !== undefined;
2760
- if (!hasExplicitGoalChanges) {
2761
- const llmPlan = await extractGoalUpdatePlanWithLlm({
2762
- runtime,
2763
- currentGoal: target.goal,
2764
- intent,
2765
- state: state ?? undefined,
2766
- message: message ?? undefined,
2767
- });
2768
- if (llmPlan.mode === "respond") {
2769
- return {
2770
- success: true,
2771
- text: llmPlan.response ??
2772
- `Tell me what to change about "${target.goal.title}" and I'll update it.`,
2773
- data: {
2774
- actionName: "LIFE",
2775
- noop: true,
2776
- suggestedOperation: "update_goal",
2777
- },
2778
- };
2779
- }
2780
- if (llmPlan.title)
2781
- request.title = llmPlan.title;
2782
- if (llmPlan.description)
2783
- request.description = llmPlan.description;
2784
- if (llmPlan.cadence)
2785
- request.cadence = llmPlan.cadence;
2786
- if (llmPlan.supportStrategy)
2787
- request.supportStrategy = llmPlan.supportStrategy;
2788
- if (llmPlan.successCriteria)
2789
- request.successCriteria = llmPlan.successCriteria;
2790
- if (llmPlan.groundingState) {
2791
- request.metadata = mergeGoalMetadataWithGrounding({
2792
- metadata: target.goal.metadata,
2793
- nowIso: new Date().toISOString(),
2794
- plan: {
2795
- cadence: llmPlan.cadence,
2796
- confidence: llmPlan.confidence,
2797
- evaluationSummary: llmPlan.evaluationSummary,
2798
- groundingState: llmPlan.groundingState,
2799
- missingCriticalFields: llmPlan.missingCriticalFields,
2800
- successCriteria: llmPlan.successCriteria ?? target.goal.successCriteria,
2801
- targetDomain: llmPlan.targetDomain,
2802
- },
2803
- });
2804
- }
2805
- }
2806
- if (request.title === undefined &&
2807
- request.description === undefined &&
2808
- request.cadence === undefined &&
2809
- request.supportStrategy === undefined &&
2810
- request.successCriteria === undefined &&
2811
- request.metadata === undefined) {
2812
- return {
2813
- success: false,
2814
- text: `Tell me what to change about "${target.goal.title}" and I'll update it.`,
2815
- };
2816
- }
2817
- const updated = await service.updateGoal(target.goal.id, request);
2818
- const fallback = `Updated goal "${updated.goal.title}".`;
2819
- return {
2820
- success: true,
2821
- text: await renderLifeActionReply({
2822
- runtime,
2823
- message,
2824
- state,
2825
- intent,
2826
- scenario: "updated_goal",
2827
- fallback,
2828
- context: {
2829
- previousTitle: target.goal.title,
2830
- updated: {
2831
- title: updated.goal.title,
2832
- },
2833
- },
2834
- }),
2835
- data: toActionData(updated),
2836
- };
2837
- }
2838
- if (operation === "delete_definition") {
2839
- const target = await resolveDefinition(service, targetName, domain);
2840
- if (!target)
2841
- return {
2842
- success: false,
2843
- text: "I could not find that item to delete.",
2844
- };
2845
- await service.deleteDefinition(target.definition.id);
2846
- const fallback = `Deleted "${target.definition.title}" and its occurrences.`;
2847
- return {
2848
- success: true,
2849
- text: await renderLifeActionReply({
2850
- runtime,
2851
- message,
2852
- state,
2853
- intent,
2854
- scenario: "deleted_definition",
2855
- fallback,
2856
- context: {
2857
- deleted: {
2858
- title: target.definition.title,
2859
- },
2860
- },
2861
- }),
2862
- };
2863
- }
2864
- if (operation === "delete_goal") {
2865
- const target = await resolveGoal(service, targetName, domain);
2866
- if (!target)
2867
- return {
2868
- success: false,
2869
- text: "I could not find that goal to delete.",
2870
- };
2871
- await service.deleteGoal(target.goal.id);
2872
- const fallback = `Deleted goal "${target.goal.title}".`;
2873
- return {
2874
- success: true,
2875
- text: await renderLifeActionReply({
2876
- runtime,
2877
- message,
2878
- state,
2879
- intent,
2880
- scenario: "deleted_goal",
2881
- fallback,
2882
- context: {
2883
- deleted: {
2884
- title: target.goal.title,
2885
- },
2886
- },
2887
- }),
2888
- };
2889
- }
2890
- if (operation === "complete_occurrence") {
2891
- const { match: target, ambiguousCandidates } = await resolveOccurrenceWithIntentFallback({
2892
- service,
2893
- target: targetName,
2894
- domain,
2895
- intent,
2896
- operation,
2897
- });
2898
- if (!target) {
2899
- if (ambiguousCandidates.length > 0) {
2900
- return {
2901
- success: false,
2902
- text: `Multiple items match — which one?\n${ambiguousCandidates.map((t) => ` - ${t}`).join("\n")}`,
2903
- };
2904
- }
2905
- return {
2906
- success: false,
2907
- text: "I could not find that active item to complete.",
2908
- };
2909
- }
2910
- const completed = await service.completeOccurrence(target.id, {
2911
- note: detailString(details, "note"),
2912
- });
2913
- const fallback = `Marked "${completed.title}" done.`;
2914
- return {
2915
- success: true,
2916
- text: await renderLifeActionReply({
2917
- runtime,
2918
- message,
2919
- state,
2920
- intent,
2921
- scenario: "completed_occurrence",
2922
- fallback,
2923
- context: {
2924
- completed: {
2925
- title: completed.title,
2926
- },
2927
- note: detailString(details, "note"),
2928
- },
2929
- }),
2930
- data: toActionData(completed),
2931
- };
2932
- }
2933
- if (operation === "skip_occurrence") {
2934
- const { match: target, ambiguousCandidates } = await resolveOccurrenceWithIntentFallback({
2935
- service,
2936
- target: targetName,
2937
- domain,
2938
- intent,
2939
- operation,
2940
- });
2941
- if (!target) {
2942
- if (ambiguousCandidates.length > 0) {
2943
- return {
2944
- success: false,
2945
- text: `Multiple items match — which one?\n${ambiguousCandidates.map((t) => ` - ${t}`).join("\n")}`,
2946
- };
2947
- }
2948
- return {
2949
- success: false,
2950
- text: "I could not find that active item to skip.",
2951
- };
2952
- }
2953
- const skipped = await service.skipOccurrence(target.id);
2954
- const fallback = `Skipped "${skipped.title}".`;
2955
- return {
2956
- success: true,
2957
- text: await renderLifeActionReply({
2958
- runtime,
2959
- message,
2960
- state,
2961
- intent,
2962
- scenario: "skipped_occurrence",
2963
- fallback,
2964
- context: {
2965
- skipped: {
2966
- title: skipped.title,
2967
- },
2968
- },
2969
- }),
2970
- data: toActionData(skipped),
2971
- };
2972
- }
2973
- if (operation === "snooze_occurrence") {
2974
- const { match: target, ambiguousCandidates } = await resolveOccurrenceWithIntentFallback({
2975
- service,
2976
- target: targetName,
2977
- domain,
2978
- intent,
2979
- operation,
2980
- });
2981
- if (!target) {
2982
- if (ambiguousCandidates.length > 0) {
2983
- return {
2984
- success: false,
2985
- text: `Multiple items match — which one?\n${ambiguousCandidates.map((t) => ` - ${t}`).join("\n")}`,
2986
- };
2987
- }
2988
- return {
2989
- success: false,
2990
- text: "I could not find that active item to snooze.",
2991
- };
2992
- }
2993
- const preset = detailString(details, "preset");
2994
- const minutes = detailNumber(details, "minutes");
2995
- const snoozed = await service.snoozeOccurrence(target.id, {
2996
- preset,
2997
- minutes,
2998
- });
2999
- const fallback = `Snoozed "${snoozed.title}".`;
3000
- return {
3001
- success: true,
3002
- text: await renderLifeActionReply({
3003
- runtime,
3004
- message,
3005
- state,
3006
- intent,
3007
- scenario: "snoozed_occurrence",
3008
- fallback,
3009
- context: {
3010
- snoozed: {
3011
- title: snoozed.title,
3012
- },
3013
- preset: preset ?? null,
3014
- minutes: minutes ?? null,
3015
- },
3016
- }),
3017
- data: toActionData(snoozed),
3018
- };
3019
- }
3020
- if (operation === "review_goal") {
3021
- const target = await resolveGoal(service, targetName, domain);
3022
- if (!target)
3023
- return {
3024
- success: false,
3025
- text: "I could not find that goal to review.",
3026
- };
3027
- const review = await service.reviewGoal(target.goal.id);
3028
- return {
3029
- success: true,
3030
- text: review.summary.explanation,
3031
- data: toActionData(review),
3032
- };
3033
- }
3034
- if (operation === "set_reminder_preference") {
3035
- const reminderIntensityPlan = await extractReminderIntensityWithLlm({
3036
- runtime,
3037
- intent,
3038
- });
3039
- if (reminderIntensityPlan.intensity === "unknown") {
3040
- return {
3041
- success: false,
3042
- text: "I need to know whether you want reminders minimal, normal, persistent, or high priority only.",
3043
- };
3044
- }
3045
- const intensity = reminderIntensityPlan.intensity;
3046
- const target = await resolveDefinitionFromIntent(service, targetName, intent, domain);
3047
- const request = {
3048
- intensity,
3049
- definitionId: target?.definition.id ?? null,
3050
- note: chatText || intent,
3051
- };
3052
- const preference = await service.setReminderPreference(request);
3053
- if (target) {
3054
- const fallback = intensity === "high_priority_only"
3055
- ? `Reminder intensity for "${target.definition.title}" is now high priority only.`
3056
- : `Reminder intensity for "${target.definition.title}" is now ${describeReminderIntensity(preference.effective.intensity)}.`;
3057
- return {
3058
- success: true,
3059
- text: await renderLifeActionReply({
3060
- runtime,
3061
- message,
3062
- state,
3063
- intent,
3064
- scenario: "set_reminder_preference",
3065
- fallback,
3066
- context: {
3067
- scope: "definition",
3068
- targetTitle: target.definition.title,
3069
- intensity: preference.effective.intensity,
3070
- },
3071
- }),
3072
- data: toActionData(preference),
3073
- };
3074
- }
3075
- const fallback = intensity === "high_priority_only"
3076
- ? "Global LifeOps reminders are now high priority only."
3077
- : `Global LifeOps reminders are now ${describeReminderIntensity(preference.effective.intensity)}.`;
3078
- return {
3079
- success: true,
3080
- text: await renderLifeActionReply({
3081
- runtime,
3082
- message,
3083
- state,
3084
- intent,
3085
- scenario: "set_reminder_preference",
3086
- fallback,
3087
- context: {
3088
- scope: "global",
3089
- intensity: preference.effective.intensity,
3090
- },
3091
- }),
3092
- data: toActionData(preference),
3093
- };
3094
- }
3095
- if (operation === "capture_phone") {
3096
- const phoneNumber = detailString(details, "phoneNumber") ?? params.title;
3097
- if (!phoneNumber)
3098
- return {
3099
- success: false,
3100
- text: "I need a phone number to set up SMS or voice contact.",
3101
- };
3102
- const allowSms = detailBoolean(details, "allowSms") ?? true;
3103
- const allowVoice = detailBoolean(details, "allowVoice") ?? false;
3104
- const result = await service.capturePhoneConsent({
3105
- phoneNumber,
3106
- consentGiven: true,
3107
- allowSms,
3108
- allowVoice,
3109
- privacyClass: "private",
3110
- });
3111
- const channels = [];
3112
- if (allowSms)
3113
- channels.push("SMS");
3114
- if (allowVoice)
3115
- channels.push("voice calls");
3116
- const fallback = `Phone number ${result.phoneNumber} saved. Enabled for: ${channels.join(" and ") || "reminders"}.`;
3117
- return {
3118
- success: true,
3119
- text: await renderLifeActionReply({
3120
- runtime,
3121
- message,
3122
- state,
3123
- intent,
3124
- scenario: "captured_phone",
3125
- fallback,
3126
- context: {
3127
- phoneNumber: result.phoneNumber,
3128
- channels,
3129
- },
3130
- }),
3131
- data: toActionData(result),
3132
- };
3133
- }
3134
- if (operation === "configure_escalation") {
3135
- const target = await resolveDefinition(service, targetName, domain);
3136
- if (!target)
3137
- return {
3138
- success: false,
3139
- text: "I could not find that item to configure its reminders.",
3140
- };
3141
- const rawSteps = detailArray(details, "steps") ??
3142
- detailArray(details, "escalationSteps");
3143
- const steps = rawSteps
3144
- ? rawSteps
3145
- .filter((s) => typeof s === "object" && s !== null)
3146
- .map((s) => ({
3147
- channel: String(s.channel ?? "in_app"),
3148
- offsetMinutes: typeof s.offsetMinutes === "number" ? s.offsetMinutes : 0,
3149
- label: typeof s.label === "string"
3150
- ? s.label
3151
- : String(s.channel ?? "reminder"),
3152
- }))
3153
- : [{ channel: "in_app", offsetMinutes: 0, label: "In-app reminder" }];
3154
- const updated = await service.updateDefinition(target.definition.id, {
3155
- ownership,
3156
- reminderPlan: { steps },
3157
- });
3158
- const summary = steps
3159
- .map((s) => `${s.channel} at +${s.offsetMinutes}m`)
3160
- .join(", ");
3161
- const fallback = `Updated reminder plan for "${updated.definition.title}": ${summary}.`;
3162
- return {
3163
- success: true,
3164
- text: await renderLifeActionReply({
3165
- runtime,
3166
- message,
3167
- state,
3168
- intent,
3169
- scenario: "configured_escalation",
3170
- fallback,
3171
- context: {
3172
- targetTitle: updated.definition.title,
3173
- steps,
3174
- },
3175
- }),
3176
- data: toActionData(updated),
3177
- };
3178
- }
3179
- return {
3180
- success: false,
3181
- text: "I didn't understand that life management request.",
3182
- };
3183
- }
3184
- catch (err) {
3185
- if (err instanceof LifeOpsServiceError) {
3186
- const fallback = buildLifeServiceErrorFallback(err, intent);
3187
- return {
3188
- success: false,
3189
- text: await renderLifeActionReply({
3190
- runtime,
3191
- message,
3192
- state,
3193
- intent,
3194
- scenario: "service_error",
3195
- fallback,
3196
- context: {
3197
- status: err.status,
3198
- operation,
3199
- },
3200
- }),
3201
- };
3202
- }
3203
- throw err;
3204
- }
3205
- },
3206
- parameters: [
3207
- {
3208
- name: "action",
3209
- description: "What kind of life operation to perform.",
3210
- required: false,
3211
- schema: {
3212
- type: "string",
3213
- enum: [
3214
- "create",
3215
- "create_goal",
3216
- "update",
3217
- "update_goal",
3218
- "delete",
3219
- "delete_goal",
3220
- "complete",
3221
- "skip",
3222
- "snooze",
3223
- "review",
3224
- "phone",
3225
- "escalation",
3226
- "reminder_preference",
3227
- "calendar",
3228
- "next_event",
3229
- "email",
3230
- "overview",
3231
- ],
3232
- },
3233
- },
3234
- {
3235
- name: "intent",
3236
- description: 'Natural language description of what to do. Examples: "create a daily brushing habit for morning and night", "snooze brushing for 30 minutes", "what\'s on my calendar today".',
3237
- required: false,
3238
- schema: { type: "string" },
3239
- },
3240
- {
3241
- name: "title",
3242
- description: "Name for a new item, or the name of an existing item to act on.",
3243
- required: false,
3244
- schema: { type: "string" },
3245
- },
3246
- {
3247
- name: "target",
3248
- description: "Name or ID of an existing item when different from title (e.g., when renaming).",
3249
- required: false,
3250
- schema: { type: "string" },
3251
- },
3252
- {
3253
- name: "details",
3254
- description: "Structured data when needed. May include: cadence (schedule object), kind (task/habit/routine), description, priority, progressionRule, reminderPlan, confirmed (boolean when the user explicitly approves a previewed create), preset (snooze preset like 15m/30m/1h/tonight/tomorrow_morning), minutes (snooze minutes), phoneNumber, allowSms, allowVoice, steps (escalation steps array), goalId, goalTitle, supportStrategy, successCriteria, note, limit, domain (user_lifeops/agent_ops), or reminder preference targeting.",
3255
- required: false,
3256
- schema: { type: "object" },
3257
- },
3258
- ],
3259
- examples: [
3260
- [
3261
- {
3262
- name: "{{name1}}",
3263
- content: {
3264
- text: "help me remember to drink water",
3265
- },
3266
- },
3267
- {
3268
- name: "{{agentName}}",
3269
- content: {
3270
- text: 'I can set up a "Drink water" habit with a reasonable daytime default cadence. Confirm and I\'ll save it.',
3271
- actions: ["LIFE"],
3272
- },
3273
- },
3274
- ],
3275
- [
3276
- {
3277
- name: "{{name1}}",
3278
- content: {
3279
- text: "help me remember to stretch during the day",
3280
- },
3281
- },
3282
- {
3283
- name: "{{agentName}}",
3284
- content: {
3285
- text: 'I can set up a "Stretch" habit with daytime stretch-break defaults. Confirm and I\'ll save it.',
3286
- actions: ["LIFE"],
3287
- },
3288
- },
3289
- ],
3290
- [
3291
- {
3292
- name: "{{name1}}",
3293
- content: {
3294
- text: "please remind me about my Invisalign on weekdays after lunch",
3295
- },
3296
- },
3297
- {
3298
- name: "{{agentName}}",
3299
- content: {
3300
- text: "I can set up a weekday-after-lunch Invisalign habit. Confirm and I'll save it.",
3301
- actions: ["LIFE"],
3302
- },
3303
- },
3304
- ],
3305
- [
3306
- {
3307
- name: "{{name1}}",
3308
- content: {
3309
- text: "recuérdame cepillarme los dientes por la mañana y por la noche",
3310
- },
3311
- },
3312
- {
3313
- name: "{{agentName}}",
3314
- content: {
3315
- text: 'Puedo guardar el hábito "Brush teeth" para la mañana y la noche. Confirma y lo guardo.',
3316
- actions: ["LIFE"],
3317
- },
3318
- },
3319
- ],
3320
- [
3321
- {
3322
- name: "{{name1}}",
3323
- content: {
3324
- text: "help me brush my teeth at 8 am and 9 pm every day",
3325
- },
3326
- },
3327
- {
3328
- name: "{{agentName}}",
3329
- content: {
3330
- text: 'I can set up a habit named "Brush teeth" for 8 am and 9 pm daily. Confirm and I\'ll save it.',
3331
- actions: ["LIFE"],
3332
- },
3333
- },
3334
- ],
3335
- [
3336
- {
3337
- name: "{{name1}}",
3338
- content: {
3339
- text: "what life ops tasks are still left for today?",
3340
- },
3341
- },
3342
- {
3343
- name: "{{agentName}}",
3344
- content: {
3345
- text: "You have 2 LifeOps tasks left for today: call mom and pay rent.",
3346
- actions: ["LIFE"],
3347
- },
3348
- },
3349
- {
3350
- name: "{{name1}}",
3351
- content: {
3352
- text: "anything else in my life ops list i need to get done today?",
3353
- },
3354
- },
3355
- {
3356
- name: "{{agentName}}",
3357
- content: {
3358
- text: "You have 1 LifeOps task left for today: pay rent.",
3359
- actions: ["LIFE"],
3360
- },
3361
- },
3362
- ],
3363
- [
3364
- {
3365
- name: "{{name1}}",
3366
- content: {
3367
- text: "remind me less about brush teeth",
3368
- },
3369
- },
3370
- {
3371
- name: "{{agentName}}",
3372
- content: {
3373
- text: 'Reminder intensity for "Brush teeth" is now minimal.',
3374
- actions: ["LIFE"],
3375
- },
3376
- },
3377
- ],
3378
- ],
3379
- };
1
+ export * from "@elizaos/app-lifeops/actions/life";