@vellumai/assistant 0.8.1 → 0.8.3

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 (630) hide show
  1. package/ARCHITECTURE.md +13 -19
  2. package/Dockerfile +75 -1
  3. package/bun.lock +11 -1
  4. package/docker-entrypoint.sh +17 -0
  5. package/docker-init-apt-root.sh +167 -0
  6. package/docker-kata-apt-env.sh +39 -0
  7. package/docs/plugins.md +88 -47
  8. package/docs/skills.md +9 -7
  9. package/examples/plugins/echo/README.md +27 -27
  10. package/examples/plugins/echo/package.json +3 -0
  11. package/examples/plugins/echo/register.ts +31 -31
  12. package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
  13. package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
  14. package/openapi.yaml +642 -5
  15. package/package.json +3 -1
  16. package/scripts/generate-openapi.ts +83 -10
  17. package/scripts/sync-llm-catalog.ts +2 -2
  18. package/scripts/sync-web-search-catalog.ts +47 -25
  19. package/src/__tests__/agent-image-optimize.test.ts +11 -3
  20. package/src/__tests__/agent-loop-exit-reason.test.ts +272 -0
  21. package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
  22. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
  23. package/src/__tests__/anthropic-provider.test.ts +45 -0
  24. package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
  25. package/src/__tests__/app-executors.test.ts +220 -4
  26. package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
  27. package/src/__tests__/bundled-asset.test.ts +6 -6
  28. package/src/__tests__/channel-availability-routes.test.ts +206 -0
  29. package/src/__tests__/channel-delivery-store.test.ts +289 -1
  30. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
  31. package/src/__tests__/clawhub.test.ts +75 -16
  32. package/src/__tests__/compactor-tail-resolution.test.ts +147 -0
  33. package/src/__tests__/config-get-vision-flag.test.ts +136 -0
  34. package/src/__tests__/config-loader-backfill.test.ts +115 -18
  35. package/src/__tests__/config-schema.test.ts +21 -0
  36. package/src/__tests__/config-set-route.test.ts +80 -0
  37. package/src/__tests__/config-sounds-sync.test.ts +97 -0
  38. package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
  39. package/src/__tests__/context-search-conversations-source.test.ts +117 -2
  40. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  41. package/src/__tests__/context-search-workspace-source.test.ts +7 -0
  42. package/src/__tests__/context-token-estimator.test.ts +31 -65
  43. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
  44. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  45. package/src/__tests__/conversation-agent-loop-overflow.test.ts +92 -92
  46. package/src/__tests__/conversation-agent-loop.test.ts +59 -1
  47. package/src/__tests__/conversation-error.test.ts +42 -3
  48. package/src/__tests__/conversation-fork-crud.test.ts +82 -0
  49. package/src/__tests__/conversation-inference-profile-route.test.ts +40 -4
  50. package/src/__tests__/conversation-lifecycle.test.ts +173 -0
  51. package/src/__tests__/conversation-media-retry.test.ts +19 -8
  52. package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
  53. package/src/__tests__/conversation-pairing.test.ts +54 -0
  54. package/src/__tests__/conversation-process-callsite.test.ts +4 -1
  55. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
  56. package/src/__tests__/conversation-queue.test.ts +4 -1
  57. package/src/__tests__/conversation-runtime-assembly.test.ts +102 -13
  58. package/src/__tests__/conversation-slash-queue.test.ts +59 -1
  59. package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
  60. package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
  61. package/src/__tests__/conversation-sync-tags.test.ts +235 -0
  62. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  63. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  64. package/src/__tests__/credential-security-invariants.test.ts +3 -2
  65. package/src/__tests__/date-context.test.ts +45 -0
  66. package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
  67. package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
  68. package/src/__tests__/disk-pressure-tools.test.ts +1 -0
  69. package/src/__tests__/dm-backfill.test.ts +121 -10
  70. package/src/__tests__/document-tool-security.test.ts +258 -0
  71. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  72. package/src/__tests__/edit-propagation.test.ts +33 -0
  73. package/src/__tests__/empty-response-pipeline.test.ts +0 -4
  74. package/src/__tests__/external-plugin-loader.test.ts +151 -55
  75. package/src/__tests__/filing-service.test.ts +140 -0
  76. package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
  77. package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
  78. package/src/__tests__/guardian-dispatch.test.ts +1 -0
  79. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +43 -62
  80. package/src/__tests__/heartbeat-service.test.ts +24 -164
  81. package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
  82. package/src/__tests__/helpers/tar-fixtures.ts +39 -0
  83. package/src/__tests__/helpers/wait-for.ts +21 -0
  84. package/src/__tests__/history-repair-pipeline.test.ts +0 -3
  85. package/src/__tests__/history-repair.test.ts +73 -0
  86. package/src/__tests__/host-app-control-proxy.test.ts +507 -10
  87. package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
  88. package/src/__tests__/image-credentials.test.ts +1 -1
  89. package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
  90. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +1 -1
  91. package/src/__tests__/inference-profile-reaper.test.ts +4 -2
  92. package/src/__tests__/inference-profile-session-handler.test.ts +18 -6
  93. package/src/__tests__/inference-profile-session-ipc.test.ts +17 -5
  94. package/src/__tests__/injector-background-turn.test.ts +153 -0
  95. package/src/__tests__/injector-chain.test.ts +15 -8
  96. package/src/__tests__/install-skill-routing.test.ts +155 -37
  97. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +99 -3
  98. package/src/__tests__/list-messages-page-latest.test.ts +55 -0
  99. package/src/__tests__/llm-call-pipeline.test.ts +0 -3
  100. package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
  101. package/src/__tests__/llm-catalog-parity.test.ts +58 -13
  102. package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
  103. package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
  104. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +36 -0
  105. package/src/__tests__/llm-request-log-source-factory.test.ts +29 -53
  106. package/src/__tests__/llm-resolver.test.ts +255 -2
  107. package/src/__tests__/llm-usage-store.test.ts +114 -0
  108. package/src/__tests__/managed-profile-guard.test.ts +41 -29
  109. package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
  110. package/src/__tests__/managed-store.test.ts +84 -192
  111. package/src/__tests__/media-generate-image.test.ts +1 -1
  112. package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
  113. package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
  114. package/src/__tests__/notification-decision-fallback.test.ts +0 -91
  115. package/src/__tests__/notification-decision-strategy.test.ts +14 -31
  116. package/src/__tests__/notification-deep-link.test.ts +15 -0
  117. package/src/__tests__/notification-guardian-path.test.ts +1 -2
  118. package/src/__tests__/notification-platform-adapter.test.ts +5 -4
  119. package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
  120. package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
  121. package/src/__tests__/oauth-commands-routes.test.ts +168 -16
  122. package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
  123. package/src/__tests__/openai-provider.test.ts +242 -3
  124. package/src/__tests__/openai-responses-cutover-guard.test.ts +17 -9
  125. package/src/__tests__/openrouter-provider-only.test.ts +51 -3
  126. package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
  127. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
  128. package/src/__tests__/persistence-pipeline.test.ts +0 -2
  129. package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +7 -2
  130. package/src/__tests__/platform.test.ts +2 -0
  131. package/src/__tests__/plugin-api-shim.test.ts +125 -0
  132. package/src/__tests__/plugin-bootstrap.test.ts +10 -36
  133. package/src/__tests__/plugin-external-api.test.ts +68 -0
  134. package/src/__tests__/plugin-registry.test.ts +0 -77
  135. package/src/__tests__/plugin-route-contribution.test.ts +0 -1
  136. package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
  137. package/src/__tests__/plugin-tool-contribution.test.ts +16 -15
  138. package/src/__tests__/plugin-types.test.ts +3 -13
  139. package/src/__tests__/process-message-background-slack.test.ts +8 -1
  140. package/src/__tests__/process-message-display-content.test.ts +421 -0
  141. package/src/__tests__/provider-catalog-visibility.test.ts +158 -0
  142. package/src/__tests__/provider-error-scenarios.test.ts +111 -0
  143. package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +33 -31
  144. package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
  145. package/src/__tests__/schedule-routes.test.ts +50 -3
  146. package/src/__tests__/schedule-store.test.ts +94 -0
  147. package/src/__tests__/scheduler-reuse-conversation.test.ts +54 -7
  148. package/src/__tests__/schema-transforms.test.ts +20 -0
  149. package/src/__tests__/search-skills-unified.test.ts +0 -5
  150. package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +1 -1
  151. package/src/__tests__/server-history-render.test.ts +43 -0
  152. package/src/__tests__/skill-load-feature-flag.test.ts +0 -12
  153. package/src/__tests__/skill-load-tool.test.ts +27 -89
  154. package/src/__tests__/skill-memory.test.ts +23 -3
  155. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
  156. package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
  157. package/src/__tests__/skills-install-extract.test.ts +49 -38
  158. package/src/__tests__/skills-install-staging.test.ts +159 -0
  159. package/src/__tests__/skills-uninstall.test.ts +9 -41
  160. package/src/__tests__/skills.test.ts +51 -58
  161. package/src/__tests__/slack-channel-config.test.ts +9 -0
  162. package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
  163. package/src/__tests__/system-prompt.test.ts +670 -63
  164. package/src/__tests__/terminal-tools.test.ts +28 -1
  165. package/src/__tests__/thread-backfill.test.ts +557 -27
  166. package/src/__tests__/title-generate-pipeline.test.ts +0 -13
  167. package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
  168. package/src/__tests__/tool-error-pipeline.test.ts +0 -3
  169. package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
  170. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  171. package/src/__tests__/tool-executor.test.ts +16 -4
  172. package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
  173. package/src/__tests__/turn-events-store.test.ts +256 -0
  174. package/src/__tests__/twilio-routes.test.ts +4 -0
  175. package/src/__tests__/user-plugin-loader.test.ts +0 -7
  176. package/src/__tests__/voice-session-bridge.test.ts +198 -0
  177. package/src/__tests__/web-search-catalog-parity.test.ts +32 -10
  178. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +115 -3
  179. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +50 -0
  180. package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
  181. package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
  182. package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
  183. package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
  184. package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
  185. package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
  186. package/src/a2a/__tests__/agent-card.test.ts +98 -0
  187. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
  188. package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
  189. package/src/a2a/__tests__/task-store.test.ts +246 -0
  190. package/src/a2a/agent-card.ts +58 -0
  191. package/src/a2a/feature-gate.ts +8 -0
  192. package/src/a2a/protocol-constants.ts +21 -0
  193. package/src/a2a/protocol-errors.ts +50 -0
  194. package/src/a2a/protocol-types.ts +162 -0
  195. package/src/a2a/task-store.ts +168 -0
  196. package/src/acp/resolve-agent.ts +1 -1
  197. package/src/agent/image-optimize.ts +13 -5
  198. package/src/agent/loop.ts +167 -18
  199. package/src/calls/voice-session-bridge.ts +61 -42
  200. package/src/channels/config.ts +9 -0
  201. package/src/channels/types.ts +122 -0
  202. package/src/cli/__tests__/unknown-command.test.ts +24 -0
  203. package/src/cli/commands/__tests__/changelog.test.ts +304 -319
  204. package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
  205. package/src/cli/commands/__tests__/schedules.test.ts +960 -0
  206. package/src/cli/commands/changelog.ts +106 -42
  207. package/src/cli/commands/conversations.ts +102 -17
  208. package/src/cli/commands/default-action.ts +10 -53
  209. package/src/cli/commands/notifications.ts +388 -346
  210. package/src/cli/commands/plugins.ts +252 -0
  211. package/src/cli/commands/schedules.ts +683 -0
  212. package/src/cli/commands/telemetry.ts +40 -0
  213. package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
  214. package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
  215. package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
  216. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
  217. package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
  218. package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
  219. package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
  220. package/src/cli/lib/cli-colors.ts +12 -0
  221. package/src/cli/lib/confirm-prompt.ts +79 -0
  222. package/src/cli/lib/install-from-github.ts +303 -0
  223. package/src/cli/lib/list-installed-plugins.ts +137 -0
  224. package/src/cli/lib/search-plugins.ts +163 -0
  225. package/src/cli/lib/uninstall-plugin.ts +82 -0
  226. package/src/cli/lib/unknown-command.ts +111 -0
  227. package/src/cli/program.ts +52 -2
  228. package/src/config/assistant-feature-flags.ts +24 -54
  229. package/src/config/bundled-skills/app-builder/SKILL.md +140 -22
  230. package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
  231. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
  232. package/src/config/bundled-skills/document/SKILL.md +23 -3
  233. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  234. package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
  235. package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
  236. package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
  237. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
  238. package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
  239. package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
  240. package/src/config/bundled-tool-registry.ts +6 -0
  241. package/src/config/call-site-defaults.ts +105 -0
  242. package/src/config/feature-flag-registry.json +41 -9
  243. package/src/config/llm-resolver.ts +52 -1
  244. package/src/config/loader.ts +64 -38
  245. package/src/config/schema.ts +9 -10
  246. package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
  247. package/src/config/schemas/__tests__/memory-v2.test.ts +3 -3
  248. package/src/config/schemas/channels.ts +17 -0
  249. package/src/config/schemas/compaction.ts +28 -0
  250. package/src/config/schemas/conversations.ts +10 -0
  251. package/src/config/schemas/heartbeat.ts +23 -0
  252. package/src/config/schemas/llm-request-logs.ts +31 -7
  253. package/src/config/schemas/llm.ts +1 -0
  254. package/src/config/schemas/memory-retrieval.ts +18 -0
  255. package/src/config/schemas/memory-retrospective.ts +1 -1
  256. package/src/config/schemas/memory-v2.ts +4 -4
  257. package/src/config/schemas/memory.ts +3 -1
  258. package/src/config/schemas/tools.ts +14 -0
  259. package/src/config/seed-inference-profiles.ts +99 -29
  260. package/src/config/skills.ts +3 -96
  261. package/src/context/compactor.ts +1107 -0
  262. package/src/context/token-estimator.ts +34 -36
  263. package/src/context/window-manager.ts +197 -1520
  264. package/src/credential-execution/managed-catalog.ts +37 -0
  265. package/src/credential-health/credential-health-service.ts +280 -19
  266. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +33 -18
  267. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
  268. package/src/daemon/__tests__/conversation-tool-setup.test.ts +74 -0
  269. package/src/daemon/approval-generators.ts +8 -6
  270. package/src/daemon/config-watcher.ts +94 -31
  271. package/src/daemon/conversation-agent-loop-handlers.ts +78 -0
  272. package/src/daemon/conversation-agent-loop.ts +198 -11
  273. package/src/daemon/conversation-error.ts +171 -37
  274. package/src/daemon/conversation-lifecycle.ts +53 -40
  275. package/src/daemon/conversation-messaging.ts +25 -6
  276. package/src/daemon/conversation-process.ts +49 -12
  277. package/src/daemon/conversation-runtime-assembly.ts +25 -1
  278. package/src/daemon/conversation-slash.ts +12 -5
  279. package/src/daemon/conversation-store.ts +11 -4
  280. package/src/daemon/conversation-tool-setup.ts +39 -7
  281. package/src/daemon/conversation.ts +33 -8
  282. package/src/daemon/date-context.ts +40 -0
  283. package/src/daemon/external-plugins-bootstrap.ts +217 -181
  284. package/src/daemon/first-greeting.ts +22 -2
  285. package/src/daemon/guardian-action-generators.ts +1 -125
  286. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
  287. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
  288. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
  289. package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
  290. package/src/daemon/handlers/config-a2a.ts +289 -0
  291. package/src/daemon/handlers/config-model.ts +6 -5
  292. package/src/daemon/handlers/config-slack-channel.ts +15 -3
  293. package/src/daemon/handlers/conversations.ts +1 -0
  294. package/src/daemon/handlers/shared.ts +14 -5
  295. package/src/daemon/handlers/skills.ts +111 -108
  296. package/src/daemon/history-repair.ts +28 -1
  297. package/src/daemon/host-app-control-proxy.ts +153 -27
  298. package/src/daemon/host-proxy-preactivation.ts +85 -18
  299. package/src/daemon/lifecycle.ts +89 -91
  300. package/src/daemon/meet-host-supervisor.ts +5 -4
  301. package/src/daemon/memory-v2-startup.ts +85 -0
  302. package/src/daemon/message-protocol.ts +1 -0
  303. package/src/daemon/message-types/conversations.ts +25 -0
  304. package/src/daemon/message-types/messages.ts +61 -0
  305. package/src/daemon/message-types/notifications.ts +21 -0
  306. package/src/daemon/message-types/subagents.ts +1 -0
  307. package/src/daemon/message-types/sync.ts +1 -0
  308. package/src/daemon/pkb-reminder-builder.test.ts +11 -54
  309. package/src/daemon/pkb-reminder-builder.ts +5 -20
  310. package/src/daemon/plugin-source-watcher.ts +146 -0
  311. package/src/daemon/process-message.ts +24 -3
  312. package/src/daemon/server.ts +11 -2
  313. package/src/daemon/skill-memory-refresh.ts +33 -0
  314. package/src/daemon/wake-target-adapter.ts +2 -0
  315. package/src/documents/document-store.ts +221 -3
  316. package/src/embedded/plugin-api.ts +40 -0
  317. package/src/export/__tests__/transcript-formatter.test.ts +121 -0
  318. package/src/export/transcript-formatter.ts +54 -20
  319. package/src/filing/filing-service.ts +39 -0
  320. package/src/heartbeat/__tests__/heartbeat-service.test.ts +135 -6
  321. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  322. package/src/heartbeat/heartbeat-service.ts +73 -189
  323. package/src/home/__tests__/feed-types.test.ts +80 -0
  324. package/src/home/feed-types.ts +36 -2
  325. package/src/home/post-connect-feed.ts +1 -0
  326. package/src/index.ts +18 -1
  327. package/src/ipc/cli-client.ts +147 -45
  328. package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
  329. package/src/mcp/client.ts +20 -4
  330. package/src/media/image-credentials.ts +3 -3
  331. package/src/memory/__tests__/bookmark-crud.test.ts +33 -27
  332. package/src/memory/__tests__/conversation-queries.test.ts +483 -0
  333. package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
  334. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
  335. package/src/memory/__tests__/memory-retrospective-job.test.ts +87 -4
  336. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +119 -14
  337. package/src/memory/__tests__/message-content.test.ts +35 -0
  338. package/src/memory/bookmark-crud.ts +42 -10
  339. package/src/memory/context-search/sources/conversations.ts +62 -2
  340. package/src/memory/context-search/sources/workspace.ts +4 -0
  341. package/src/memory/conversation-crud.ts +63 -19
  342. package/src/memory/conversation-queries.ts +197 -11
  343. package/src/memory/conversation-title-service.ts +26 -4
  344. package/src/memory/db-init.ts +12 -0
  345. package/src/memory/delivery-crud.ts +152 -5
  346. package/src/memory/embedding-backend.ts +4 -4
  347. package/src/memory/external-conversation-store.ts +66 -5
  348. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +150 -12
  349. package/src/memory/graph/conversation-graph-memory.ts +49 -21
  350. package/src/memory/graph/tools.ts +9 -40
  351. package/src/memory/indexer.ts +34 -29
  352. package/src/memory/invite-store.ts +53 -0
  353. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +73 -0
  354. package/src/memory/jobs/embed-concept-page.ts +20 -11
  355. package/src/memory/jobs-worker.ts +6 -1
  356. package/src/memory/llm-request-log-source-clickhouse.ts +24 -12
  357. package/src/memory/llm-request-log-source.ts +19 -52
  358. package/src/memory/llm-request-log-store.ts +92 -1
  359. package/src/memory/llm-usage-store.ts +125 -5
  360. package/src/memory/memory-retrospective-enqueue.ts +1 -20
  361. package/src/memory/memory-retrospective-job.ts +33 -6
  362. package/src/memory/memory-retrospective-startup-cleanup.ts +72 -5
  363. package/src/memory/message-content.ts +1 -1
  364. package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
  365. package/src/memory/migrations/229-delete-private-conversations.test.ts +38 -1
  366. package/src/memory/migrations/229-delete-private-conversations.ts +7 -0
  367. package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
  368. package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
  369. package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
  370. package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
  371. package/src/memory/migrations/251-a2a-tasks.ts +49 -0
  372. package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
  373. package/src/memory/migrations/index.ts +9 -0
  374. package/src/memory/migrations/registry.ts +16 -0
  375. package/src/memory/onboarding-events-store.ts +106 -0
  376. package/src/memory/schema/a2a.ts +15 -0
  377. package/src/memory/schema/bookmarks.ts +0 -2
  378. package/src/memory/schema/calls.ts +1 -0
  379. package/src/memory/schema/index.ts +1 -0
  380. package/src/memory/schema/inference.ts +3 -3
  381. package/src/memory/schema/infrastructure.ts +13 -0
  382. package/src/memory/turn-events-store.ts +127 -2
  383. package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
  384. package/src/memory/v2/__tests__/activation.test.ts +0 -8
  385. package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
  386. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
  387. package/src/memory/v2/__tests__/injection.test.ts +288 -11
  388. package/src/memory/v2/__tests__/migration.test.ts +87 -0
  389. package/src/memory/v2/__tests__/page-index.test.ts +83 -0
  390. package/src/memory/v2/__tests__/prompts-router.test.ts +58 -6
  391. package/src/memory/v2/__tests__/qdrant.test.ts +66 -3
  392. package/src/memory/v2/__tests__/router.test.ts +15 -0
  393. package/src/memory/v2/__tests__/skill-store.test.ts +387 -8
  394. package/src/memory/v2/__tests__/static-context.test.ts +12 -1
  395. package/src/memory/v2/activation-store.ts +14 -16
  396. package/src/memory/v2/cli-command-content.ts +19 -0
  397. package/src/memory/v2/cli-command-store.ts +304 -0
  398. package/src/memory/v2/frontmatter-sweep.ts +7 -1
  399. package/src/memory/v2/injection.ts +81 -26
  400. package/src/memory/v2/migration.ts +49 -19
  401. package/src/memory/v2/page-index.ts +63 -8
  402. package/src/memory/v2/prompts/router.ts +11 -8
  403. package/src/memory/v2/prompts/sweep.ts +2 -2
  404. package/src/memory/v2/qdrant.ts +135 -7
  405. package/src/memory/v2/router.ts +9 -8
  406. package/src/memory/v2/skill-store.ts +120 -35
  407. package/src/memory/v2/static-context.ts +4 -4
  408. package/src/memory/v2/types.ts +23 -0
  409. package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
  410. package/src/messaging/providers/a2a/deliver.ts +156 -0
  411. package/src/messaging/providers/gmail/client.ts +9 -2
  412. package/src/messaging/providers/index.ts +11 -2
  413. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
  414. package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
  415. package/src/messaging/providers/slack/adapter.ts +43 -5
  416. package/src/messaging/providers/slack/client.ts +27 -0
  417. package/src/messaging/providers/slack/deep-link.ts +65 -0
  418. package/src/messaging/providers/slack/download.ts +104 -0
  419. package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
  420. package/src/messaging/providers/slack/message-metadata.ts +27 -0
  421. package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
  422. package/src/messaging/providers/slack/render-transcript.ts +69 -5
  423. package/src/messaging/providers/slack/types.ts +20 -1
  424. package/src/notifications/__tests__/broadcaster.test.ts +203 -0
  425. package/src/notifications/__tests__/decision-engine.test.ts +283 -0
  426. package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
  427. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
  428. package/src/notifications/__tests__/home-feed-side-effect.test.ts +430 -7
  429. package/src/notifications/adapters/macos.ts +12 -2
  430. package/src/notifications/broadcaster.ts +29 -4
  431. package/src/notifications/conversation-pairing.ts +2 -1
  432. package/src/notifications/copy-composer.ts +17 -64
  433. package/src/notifications/decision-engine.ts +113 -45
  434. package/src/notifications/deterministic-checks.ts +96 -0
  435. package/src/notifications/emit-signal.ts +21 -1
  436. package/src/notifications/home-feed-side-effect.ts +138 -5
  437. package/src/notifications/signal.ts +3 -5
  438. package/src/notifications/types.ts +8 -0
  439. package/src/oauth/connection-resolver.ts +8 -4
  440. package/src/oauth/platform-connection.test.ts +43 -3
  441. package/src/oauth/platform-connection.ts +19 -6
  442. package/src/oauth/seed-providers.ts +10 -1
  443. package/src/permissions/checker.ts +2 -0
  444. package/src/permissions/ipc-risk-types.ts +1 -0
  445. package/src/permissions/question-prompter.test.ts +416 -0
  446. package/src/permissions/question-prompter.ts +294 -0
  447. package/src/platform/client.test.ts +1 -1
  448. package/src/platform/client.ts +1 -1
  449. package/src/plugin-api/constants.ts +26 -0
  450. package/src/plugin-api/index.ts +34 -1
  451. package/src/plugin-api/types.ts +104 -22
  452. package/src/plugins/defaults/circuit-breaker.ts +0 -5
  453. package/src/plugins/defaults/compaction.ts +0 -4
  454. package/src/plugins/defaults/empty-response.ts +0 -2
  455. package/src/plugins/defaults/history-repair.ts +0 -2
  456. package/src/plugins/defaults/injectors.ts +74 -22
  457. package/src/plugins/defaults/llm-call.ts +0 -2
  458. package/src/plugins/defaults/memory-retrieval.ts +0 -1
  459. package/src/plugins/defaults/overflow-reduce.ts +0 -1
  460. package/src/plugins/defaults/persistence.ts +0 -2
  461. package/src/plugins/defaults/title-generate.ts +0 -5
  462. package/src/plugins/defaults/token-estimate.ts +0 -2
  463. package/src/plugins/defaults/tool-error.ts +0 -7
  464. package/src/plugins/defaults/tool-execute.ts +0 -2
  465. package/src/plugins/defaults/tool-result-truncate.ts +0 -4
  466. package/src/plugins/ensure-plugin-api-shim.ts +96 -0
  467. package/src/plugins/external-api.ts +104 -0
  468. package/src/plugins/external-plugin-loader.ts +187 -42
  469. package/src/plugins/feature-gate.ts +22 -0
  470. package/src/plugins/pipeline.ts +37 -0
  471. package/src/plugins/registry.ts +48 -80
  472. package/src/plugins/types.ts +40 -26
  473. package/src/plugins/user-loader.ts +21 -2
  474. package/src/proactive-artifact/aux-message-injector.ts +11 -0
  475. package/src/proactive-artifact/job.test.ts +37 -5
  476. package/src/prompts/__tests__/system-prompt.test.ts +10 -43
  477. package/src/prompts/__tests__/task-progress-hint-section.test.ts +95 -0
  478. package/src/prompts/normalize-onboarding.ts +27 -0
  479. package/src/prompts/sections.ts +302 -0
  480. package/src/prompts/system-prompt.ts +63 -174
  481. package/src/prompts/templates/BOOTSTRAP.md +17 -1
  482. package/src/prompts/templates/system-sections.ts +164 -0
  483. package/src/providers/__tests__/inference.test.ts +24 -7
  484. package/src/providers/anthropic/client.ts +28 -28
  485. package/src/providers/call-site-routing.ts +24 -6
  486. package/src/providers/connection-resolution.ts +68 -11
  487. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
  488. package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
  489. package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
  490. package/src/providers/inference/adapter-factory.ts +32 -6
  491. package/src/providers/inference/auth.ts +12 -0
  492. package/src/providers/inference/backfill.ts +14 -1
  493. package/src/providers/inference/connections.ts +159 -34
  494. package/src/providers/inference/resolve-auth.ts +14 -4
  495. package/src/providers/model-catalog.ts +249 -12
  496. package/src/providers/model-intents.ts +3 -3
  497. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
  498. package/src/providers/openai/chat-completions-provider.ts +169 -8
  499. package/src/providers/openrouter/client.ts +49 -4
  500. package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -2
  501. package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
  502. package/src/providers/provider-availability.ts +17 -2
  503. package/src/providers/provider-catalog-visibility.ts +38 -0
  504. package/src/providers/provider-send-message.ts +27 -12
  505. package/src/providers/registry.ts +52 -15
  506. package/src/providers/retry.ts +47 -1
  507. package/src/runtime/__tests__/agent-wake.test.ts +152 -0
  508. package/src/runtime/agent-wake.ts +103 -15
  509. package/src/runtime/auth/route-policy.ts +21 -1
  510. package/src/runtime/btw-sidechain.ts +2 -0
  511. package/src/runtime/http-server.ts +7 -16
  512. package/src/runtime/http-types.ts +19 -47
  513. package/src/runtime/migrations/origin-mode.ts +1 -1
  514. package/src/runtime/pending-interactions.ts +1 -0
  515. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +17 -0
  516. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
  517. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +5 -1
  518. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +172 -23
  519. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
  520. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
  521. package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
  522. package/src/runtime/routes/__tests__/tts-routes.test.ts +64 -1
  523. package/src/runtime/routes/acp-routes-list.test.ts +143 -0
  524. package/src/runtime/routes/acp-routes.ts +5 -3
  525. package/src/runtime/routes/auth-routes.ts +1 -1
  526. package/src/runtime/routes/bookmark-routes.ts +5 -3
  527. package/src/runtime/routes/btw-routes.ts +5 -1
  528. package/src/runtime/routes/channel-availability-routes.ts +126 -0
  529. package/src/runtime/routes/consolidation-routes.ts +100 -0
  530. package/src/runtime/routes/conversation-cli-routes.ts +44 -3
  531. package/src/runtime/routes/conversation-list-routes.ts +3 -20
  532. package/src/runtime/routes/conversation-management-routes.ts +17 -42
  533. package/src/runtime/routes/conversation-query-routes.ts +99 -35
  534. package/src/runtime/routes/conversation-routes.ts +97 -11
  535. package/src/runtime/routes/documents-routes.ts +25 -86
  536. package/src/runtime/routes/group-routes.ts +5 -0
  537. package/src/runtime/routes/inbound-conversation.ts +28 -8
  538. package/src/runtime/routes/inbound-message-handler.ts +236 -41
  539. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +111 -0
  540. package/src/runtime/routes/inbound-stages/background-dispatch.ts +32 -1
  541. package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
  542. package/src/runtime/routes/index.ts +8 -0
  543. package/src/runtime/routes/inference-profile-session-handler.ts +17 -44
  544. package/src/runtime/routes/inference-profile-session-reaper.ts +7 -21
  545. package/src/runtime/routes/inference-provider-connection-routes.ts +199 -22
  546. package/src/runtime/routes/integrations/a2a.ts +235 -0
  547. package/src/runtime/routes/integrations/slack/share.ts +4 -52
  548. package/src/runtime/routes/integrations/slack/token.ts +43 -0
  549. package/src/runtime/routes/integrations/twilio.ts +6 -13
  550. package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
  551. package/src/runtime/routes/notification-routes.ts +1 -1
  552. package/src/runtime/routes/oauth-commands-routes.ts +105 -15
  553. package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
  554. package/src/runtime/routes/question-routes.ts +259 -0
  555. package/src/runtime/routes/rename-conversation-routes.ts +2 -33
  556. package/src/runtime/routes/schedule-routes.ts +4 -7
  557. package/src/runtime/routes/subagents-routes.ts +98 -18
  558. package/src/runtime/routes/telemetry-routes.ts +27 -0
  559. package/src/runtime/routes/tts-routes.ts +27 -2
  560. package/src/runtime/routes/workspace-routes.test.ts +43 -0
  561. package/src/runtime/routes/workspace-routes.ts +28 -0
  562. package/src/runtime/services/conversation-serializer.ts +39 -7
  563. package/src/runtime/sync/resource-sync-events.ts +93 -1
  564. package/src/schedule/schedule-store.ts +27 -2
  565. package/src/schedule/scheduler.ts +9 -1
  566. package/src/security/__tests__/untrusted-content.test.ts +86 -0
  567. package/src/security/untrusted-content.ts +93 -8
  568. package/src/skills/catalog-files.ts +1 -1
  569. package/src/skills/catalog-install.ts +233 -116
  570. package/src/skills/clawhub.ts +70 -13
  571. package/src/skills/managed-store.ts +4 -119
  572. package/src/skills/skillssh-registry.ts +27 -48
  573. package/src/subagent/manager.ts +17 -7
  574. package/src/telemetry/types.ts +113 -1
  575. package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
  576. package/src/telemetry/usage-telemetry-reporter.ts +113 -7
  577. package/src/tools/apps/executors.ts +58 -7
  578. package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
  579. package/src/tools/ask-question/ask-question-tool.ts +304 -0
  580. package/src/tools/browser/browser-execution.ts +15 -11
  581. package/src/tools/computer-use/definitions.ts +3 -3
  582. package/src/tools/credentials/vault.ts +1 -1
  583. package/src/tools/document/document-tool.ts +124 -1
  584. package/src/tools/filesystem/edit.ts +1 -1
  585. package/src/tools/filesystem/list.ts +1 -1
  586. package/src/tools/filesystem/read.ts +1 -1
  587. package/src/tools/filesystem/write.ts +5 -2
  588. package/src/tools/host-filesystem/transfer.ts +1 -1
  589. package/src/tools/host-terminal/host-shell.ts +1 -1
  590. package/src/tools/memory/register.ts +1 -9
  591. package/src/tools/permission-checker.ts +1 -1
  592. package/src/tools/registry.ts +17 -7
  593. package/src/tools/schedule/create.ts +2 -2
  594. package/src/tools/schema-transforms.ts +7 -2
  595. package/src/tools/side-effects.ts +1 -0
  596. package/src/tools/skills/delete-managed.ts +4 -4
  597. package/src/tools/skills/execute.ts +1 -1
  598. package/src/tools/skills/scaffold-managed.ts +3 -2
  599. package/src/tools/subagent/notify-parent.ts +1 -1
  600. package/src/tools/system/request-permission.ts +2 -2
  601. package/src/tools/terminal/safe-env.ts +60 -1
  602. package/src/tools/tool-manifest.ts +2 -0
  603. package/src/tools/types.ts +107 -21
  604. package/src/tools/ui-surface/definitions.ts +6 -5
  605. package/src/tts/__tests__/provider-adapters.test.ts +76 -2
  606. package/src/tts/providers/elevenlabs-provider.ts +75 -1
  607. package/src/types/onboarding-context.ts +2 -0
  608. package/src/util/errors.ts +17 -0
  609. package/src/util/platform.ts +10 -0
  610. package/src/watcher/__tests__/engine.test.ts +22 -0
  611. package/src/watcher/engine.ts +6 -2
  612. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +80 -15
  613. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +35 -22
  614. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +3 -1
  615. package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
  616. package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
  617. package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
  618. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
  619. package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
  620. package/src/workspace/migrations/registry.ts +10 -0
  621. package/src/workspace/migrations/runner.ts +39 -9
  622. package/src/workspace/migrations/types.ts +4 -0
  623. package/examples/plugins/echo/bun.lock +0 -25
  624. package/src/__tests__/context-window-manager.test.ts +0 -2481
  625. package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
  626. package/src/context/__tests__/compact-prompt.test.ts +0 -63
  627. package/src/context/prompts/compact.md +0 -26
  628. package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
  629. package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
  630. package/src/runtime/guardian-action-conversation-turn.ts +0 -99
@@ -1,6 +1,10 @@
1
1
  import type { Command } from "commander";
2
2
 
3
- import { cliIpcCall } from "../../ipc/cli-client.js";
3
+ import {
4
+ cliIpcCall,
5
+ exitCodeFromIpcResult,
6
+ exitFromIpcResult,
7
+ } from "../../ipc/cli-client.js";
4
8
  import { registerCommand } from "../lib/register-command.js";
5
9
  import { log } from "../logger.js";
6
10
  import { shouldOutputJson, writeOutput } from "../output.js";
@@ -13,110 +17,122 @@ export function registerNotificationsCommand(program: Command): void {
13
17
  registerCommand(program, {
14
18
  name: "notifications",
15
19
  transport: "ipc",
16
- description: "Send and inspect notifications through the unified notification router",
20
+ description:
21
+ "Send and inspect notifications through the unified notification router",
17
22
  build: (notifications) => {
18
23
  notifications.option("--json", "Machine-readable compact JSON output");
19
24
 
20
- notifications.addHelpText(
21
- "after",
22
- `
25
+ notifications.addHelpText(
26
+ "after",
27
+ `
23
28
  Notifications flow through a unified pipeline: a signal is emitted with a
24
29
  source channel, event name, and attention hints. The decision engine evaluates
25
30
  whether and where to deliver the notification based on connected channels,
26
31
  urgency, and user preferences.
27
32
 
33
+ Minimal usage: only --message is required. Add --urgent for a push + visual
34
+ flag in the inbox. Source channel/event name fall back to assistant_tool /
35
+ assistant.share when omitted.
36
+
28
37
  Examples:
29
- $ assistant notifications send --source-channel assistant_tool --source-event-name user.send_notification --message "Build finished"
30
- $ assistant notifications send --source-channel scheduler --source-event-name schedule.notify --message "Stand-up in 5 minutes" --urgency high
31
- $ assistant notifications send --source-channel watcher --source-event-name watcher.notification --message "File changed" --no-requires-action --is-async-background
32
- $ assistant notifications send --source-channel assistant_tool --source-event-name user.send_notification --message "Deploy complete" --preferred-channels vellum,telegram --json`,
33
- );
34
-
35
- // -------------------------------------------------------------------------
36
- // send
37
- // -------------------------------------------------------------------------
38
-
39
- notifications
40
- .command("send")
41
- .description("Send a notification through the unified notification router")
42
- .requiredOption(
43
- "--source-channel <channel>",
44
- "Source channel producing this notification",
45
- )
46
- .requiredOption(
47
- "--source-event-name <name>",
48
- "Event name for audit, routing, and dedupe grouping",
49
- )
50
- .requiredOption(
51
- "--message <message>",
52
- "Notification message the user should receive",
53
- )
54
- .option("--title <title>", "Optional notification title")
55
- .option(
56
- "--urgency <urgency>",
57
- "Urgency hint: low, medium, high (default: medium)",
58
- )
59
- .option(
60
- "--requires-action",
61
- "Whether the notification expects user action (default: true)",
62
- )
63
- .option(
64
- "--no-requires-action",
65
- "Mark that the notification does not expect user action",
66
- )
67
- .option(
68
- "--is-async-background",
69
- "Whether the event is asynchronous/background work (default: false)",
70
- )
71
- .option(
72
- "--no-is-async-background",
73
- "Mark that the event is not asynchronous/background work",
74
- )
75
- .option(
76
- "--visible-in-source-now",
77
- "Set true when user is already viewing the source context (default: false)",
78
- )
79
- .option(
80
- "--no-visible-in-source-now",
81
- "Mark that the user is not viewing the source context",
82
- )
83
- .option(
84
- "--deadline-at <epoch>",
85
- "Optional deadline timestamp in epoch milliseconds",
86
- )
87
- .option(
88
- "--preferred-channels <channels>",
89
- "Comma-separated channel hints (e.g. vellum,telegram,slack)",
90
- )
91
- .option(
92
- "--session-id <id>",
93
- "Source session or conversation ID (default: cli-<timestamp>)",
94
- )
95
- .option(
96
- "--dedupe-key <key>",
97
- "Optional dedupe key to suppress duplicate notifications",
98
- )
99
- .option(
100
- "--deep-link-metadata <json>",
101
- "Optional JSON metadata clients can use for deep linking",
102
- )
103
- .option(
104
- "--conversation-id <id>",
105
- "Local vellum conversation ID to deliver into. When set, the notification reuses the specified conversation instead of starting a new one — bypasses the LLM's conversation-routing decision via affinity hint.",
106
- )
107
- .addHelpText(
108
- "after",
109
- `
38
+ $ assistant notifications send --message "Build finished"
39
+ $ assistant notifications send --message "Pager: prod is down" --urgent
40
+ $ assistant notifications send --message "Build green" --conversation-id 649c4645-3a6f-4ded-a713-504f02ca806b`,
41
+ );
42
+
43
+ // -------------------------------------------------------------------------
44
+ // send
45
+ // -------------------------------------------------------------------------
46
+
47
+ notifications
48
+ .command("send")
49
+ .description(
50
+ "Send a notification through the unified notification router. Only --message is required; pass --urgent for a push + visual flag.",
51
+ )
52
+ .requiredOption(
53
+ "--message <message>",
54
+ "Notification message the user should receive",
55
+ )
56
+ .option(
57
+ "--urgent",
58
+ "Mark this notification as urgent (fires push + visual flag in inbox)",
59
+ false,
60
+ )
61
+ .option(
62
+ "--source-channel <channel>",
63
+ "Source channel producing this notification (default: assistant_tool)",
64
+ )
65
+ .option(
66
+ "--source-event-name <name>",
67
+ "Event name for audit, routing, and dedupe grouping (default: assistant.share)",
68
+ )
69
+ .option("--title <title>", "Optional notification title")
70
+ .option(
71
+ "--urgency <urgency>",
72
+ "Urgency hint: low, medium, high, critical (default: low; use --urgent for critical)",
73
+ )
74
+ .option(
75
+ "--requires-action",
76
+ "Whether the notification expects user action (default: false; use --urgent to force true)",
77
+ )
78
+ .option(
79
+ "--no-requires-action",
80
+ "Mark that the notification does not expect user action",
81
+ )
82
+ .option(
83
+ "--is-async-background",
84
+ "Whether the event is asynchronous/background work (default: false)",
85
+ )
86
+ .option(
87
+ "--no-is-async-background",
88
+ "Mark that the event is not asynchronous/background work",
89
+ )
90
+ .option(
91
+ "--visible-in-source-now",
92
+ "Set true when user is already viewing the source context (default: false)",
93
+ )
94
+ .option(
95
+ "--no-visible-in-source-now",
96
+ "Mark that the user is not viewing the source context",
97
+ )
98
+ .option(
99
+ "--deadline-at <epoch>",
100
+ "Optional deadline timestamp in epoch milliseconds",
101
+ )
102
+ .option(
103
+ "--preferred-channels <channels>",
104
+ "Comma-separated channel hints (e.g. vellum,telegram,slack)",
105
+ )
106
+ .option(
107
+ "--session-id <id>",
108
+ "Source session or conversation ID (default: cli-<timestamp>)",
109
+ )
110
+ .option(
111
+ "--dedupe-key <key>",
112
+ "Optional dedupe key to suppress duplicate notifications",
113
+ )
114
+ .option(
115
+ "--deep-link-metadata <json>",
116
+ "Optional JSON metadata clients can use for deep linking",
117
+ )
118
+ .option(
119
+ "--conversation-id <id>",
120
+ "Local vellum conversation ID to deliver into. When set, the notification reuses the specified conversation instead of starting a new one — bypasses the LLM's conversation-routing decision via affinity hint.",
121
+ )
122
+ .addHelpText(
123
+ "after",
124
+ `
110
125
  Arguments:
111
- --source-channel One of the registered source channels (see "assistant notifications --help")
112
- --source-event-name One of the registered event names (see "assistant notifications --help")
113
126
  --message The notification body text (required, must be non-empty)
127
+ --urgent Shortcut that maps to urgency=critical + requires-action=true
114
128
 
115
129
  Behavioral notes:
116
130
  - The signal is emitted through the full notification pipeline: event store,
117
131
  decision engine, deterministic checks, and channel dispatch.
118
- - --requires-action defaults to true; use --no-requires-action to disable.
119
- - --urgency defaults to medium if not specified.
132
+ - --urgent overrides --urgency and --requires-action defaults so the signal
133
+ is treated as critical and requires user action. Explicit --urgency /
134
+ --requires-action flags still win for back-compat.
135
+ - Without --urgent, --urgency defaults to low and --requires-action to false.
120
136
  - --preferred-channels are hints only; the decision engine may override them.
121
137
  - --dedupe-key suppresses duplicate signals with the same key.
122
138
  - --conversation-id pins delivery to an existing vellum conversation
@@ -124,184 +140,210 @@ Behavioral notes:
124
140
  binding-based pairing for their external threads.
125
141
 
126
142
  Examples:
127
- $ assistant notifications send --source-channel assistant_tool --source-event-name user.send_notification --message "Task complete"
128
- $ assistant notifications send --source-channel scheduler --source-event-name schedule.notify --message "Meeting in 5 min" --urgency high --title "Reminder"
129
- $ assistant notifications send --source-channel watcher --source-event-name watcher.notification --message "Detected change" --no-requires-action --is-async-background --json
130
- $ assistant notifications send --source-channel assistant_tool --source-event-name user.send_notification --message "Build green" --conversation-id 649c4645-3a6f-4ded-a713-504f02ca806b`,
131
- )
132
- .action(
133
- async (
134
- opts: {
135
- sourceChannel: string;
136
- sourceEventName: string;
137
- message: string;
138
- title?: string;
139
- urgency?: string;
140
- requiresAction: boolean;
141
- isAsyncBackground: boolean;
142
- visibleInSourceNow: boolean;
143
- deadlineAt?: string;
144
- preferredChannels?: string;
145
- sessionId?: string;
146
- dedupeKey?: string;
147
- deepLinkMetadata?: string;
148
- conversationId?: string;
149
- },
150
- cmd: Command,
151
- ) => {
152
- try {
153
- // Validate --message (keep basic validation for immediate CLI feedback)
154
- const message = opts.message.trim();
155
- if (message.length === 0) {
156
- writeOutput(cmd, {
157
- ok: false,
158
- error: "Message must be a non-empty string",
159
- });
160
- process.exitCode = 1;
161
- return;
162
- }
163
-
164
- // Validate --urgency
165
- const urgency = opts.urgency ?? "medium";
166
- if (urgency !== "low" && urgency !== "medium" && urgency !== "high") {
167
- writeOutput(cmd, {
168
- ok: false,
169
- error: `Invalid urgency "${opts.urgency}". Must be one of: low, medium, high`,
170
- });
171
- process.exitCode = 1;
172
- return;
173
- }
174
-
175
- // Parse --deadline-at
176
- let deadlineAt: number | undefined;
177
- if (opts.deadlineAt != null) {
178
- const parsed = Number(opts.deadlineAt);
179
- if (!Number.isFinite(parsed)) {
180
- writeOutput(cmd, {
181
- ok: false,
182
- error: `Invalid deadline-at "${opts.deadlineAt}". Must be a finite number (epoch milliseconds)`,
183
- });
184
- process.exitCode = 1;
185
- return;
186
- }
187
- deadlineAt = parsed;
188
- }
189
-
190
- // Parse --preferred-channels
191
- let preferredChannels: string[] | undefined;
192
- if (opts.preferredChannels) {
193
- preferredChannels = opts.preferredChannels
194
- .split(",")
195
- .map((ch) => ch.trim())
196
- .filter((ch) => ch.length > 0);
197
- }
198
-
199
- // Parse --deep-link-metadata
200
- let deepLinkMetadata: Record<string, unknown> | undefined;
201
- if (opts.deepLinkMetadata != null) {
143
+ $ assistant notifications send --message "Task complete"
144
+ $ assistant notifications send --message "Pager: prod is down" --urgent
145
+ $ assistant notifications send --message "Build green" --conversation-id 649c4645-3a6f-4ded-a713-504f02ca806b`,
146
+ )
147
+ .action(
148
+ async (
149
+ opts: {
150
+ sourceChannel?: string;
151
+ sourceEventName?: string;
152
+ message: string;
153
+ urgent: boolean;
154
+ title?: string;
155
+ urgency?: string;
156
+ requiresAction?: boolean;
157
+ isAsyncBackground: boolean;
158
+ visibleInSourceNow: boolean;
159
+ deadlineAt?: string;
160
+ preferredChannels?: string;
161
+ sessionId?: string;
162
+ dedupeKey?: string;
163
+ deepLinkMetadata?: string;
164
+ conversationId?: string;
165
+ },
166
+ cmd: Command,
167
+ ) => {
202
168
  try {
203
- deepLinkMetadata = JSON.parse(opts.deepLinkMetadata) as Record<
204
- string,
205
- unknown
206
- >;
207
- } catch {
169
+ // Apply defaults for optional source fields (minimal-surface
170
+ // ergonomics; explicit values from the CLI still win).
171
+ const sourceChannel = opts.sourceChannel ?? "assistant_tool";
172
+ const sourceEventName = opts.sourceEventName ?? "assistant.share";
173
+
174
+ // Validate --message (keep basic validation for immediate CLI feedback)
175
+ const message = opts.message.trim();
176
+ if (message.length === 0) {
177
+ writeOutput(cmd, {
178
+ ok: false,
179
+ error: "Message must be a non-empty string",
180
+ });
181
+ process.exitCode = 1;
182
+ return;
183
+ }
184
+
185
+ // --urgent is a shortcut for urgency=critical + requiresAction=true.
186
+ // Explicit --urgency / --requires-action flags still win so the
187
+ // back-compat path keeps working during the deprecation window.
188
+ const urgentDefaults = opts.urgent
189
+ ? { urgency: "critical", requiresAction: true }
190
+ : { urgency: "low", requiresAction: false };
191
+
192
+ // Validate --urgency
193
+ const urgency = opts.urgency ?? urgentDefaults.urgency;
194
+ if (
195
+ urgency !== "low" &&
196
+ urgency !== "medium" &&
197
+ urgency !== "high" &&
198
+ urgency !== "critical"
199
+ ) {
200
+ writeOutput(cmd, {
201
+ ok: false,
202
+ error: `Invalid urgency "${opts.urgency}". Must be one of: low, medium, high, critical`,
203
+ });
204
+ process.exitCode = 1;
205
+ return;
206
+ }
207
+ const requiresAction =
208
+ opts.requiresAction ?? urgentDefaults.requiresAction;
209
+
210
+ // Parse --deadline-at
211
+ let deadlineAt: number | undefined;
212
+ if (opts.deadlineAt != null) {
213
+ const parsed = Number(opts.deadlineAt);
214
+ if (!Number.isFinite(parsed)) {
215
+ writeOutput(cmd, {
216
+ ok: false,
217
+ error: `Invalid deadline-at "${opts.deadlineAt}". Must be a finite number (epoch milliseconds)`,
218
+ });
219
+ process.exitCode = 1;
220
+ return;
221
+ }
222
+ deadlineAt = parsed;
223
+ }
224
+
225
+ // Parse --preferred-channels
226
+ let preferredChannels: string[] | undefined;
227
+ if (opts.preferredChannels) {
228
+ preferredChannels = opts.preferredChannels
229
+ .split(",")
230
+ .map((ch) => ch.trim())
231
+ .filter((ch) => ch.length > 0);
232
+ }
233
+
234
+ // Parse --deep-link-metadata
235
+ let deepLinkMetadata: Record<string, unknown> | undefined;
236
+ if (opts.deepLinkMetadata != null) {
237
+ try {
238
+ deepLinkMetadata = JSON.parse(
239
+ opts.deepLinkMetadata,
240
+ ) as Record<string, unknown>;
241
+ } catch {
242
+ writeOutput(cmd, {
243
+ ok: false,
244
+ error: `Invalid deep-link-metadata: must be a valid JSON string`,
245
+ });
246
+ process.exitCode = 1;
247
+ return;
248
+ }
249
+ }
250
+
251
+ const sourceContextId = opts.sessionId ?? `cli-${Date.now()}`;
252
+
253
+ // Validate --conversation-id if provided
254
+ const conversationId = opts.conversationId?.trim();
255
+ if (opts.conversationId != null && !conversationId) {
256
+ writeOutput(cmd, {
257
+ ok: false,
258
+ error: "Conversation ID must be a non-empty string",
259
+ });
260
+ process.exitCode = 1;
261
+ return;
262
+ }
263
+
264
+ const result = await cliIpcCall<{
265
+ signalId: string;
266
+ dispatched: boolean;
267
+ deduplicated: boolean;
268
+ reason: string;
269
+ }>("emit_notification_signal", {
270
+ body: {
271
+ sourceChannel,
272
+ sourceEventName,
273
+ sourceContextId,
274
+ attentionHints: {
275
+ requiresAction,
276
+ urgency,
277
+ deadlineAt,
278
+ isAsyncBackground: opts.isAsyncBackground ?? false,
279
+ visibleInSourceNow: opts.visibleInSourceNow ?? false,
280
+ },
281
+ contextPayload: {
282
+ requestedMessage: message,
283
+ requestedBySource: sourceChannel,
284
+ ...(opts.title ? { requestedTitle: opts.title } : {}),
285
+ ...(preferredChannels?.length ? { preferredChannels } : {}),
286
+ ...(deepLinkMetadata ? { deepLinkMetadata } : {}),
287
+ },
288
+ ...(opts.dedupeKey ? { dedupeKey: opts.dedupeKey } : {}),
289
+ ...(conversationId
290
+ ? { conversationAffinityHint: { vellum: conversationId } }
291
+ : {}),
292
+ throwOnError: true,
293
+ },
294
+ });
295
+
296
+ if (!result.ok) {
297
+ if (shouldOutputJson(cmd)) {
298
+ writeOutput(cmd, { ok: false, error: result.error });
299
+ process.exitCode = exitCodeFromIpcResult(result);
300
+ return;
301
+ }
302
+ return exitFromIpcResult(result);
303
+ }
304
+
305
+ const signal = result.result!;
306
+
208
307
  writeOutput(cmd, {
209
- ok: false,
210
- error: `Invalid deep-link-metadata: must be a valid JSON string`,
308
+ ok: true,
309
+ signalId: signal.signalId,
310
+ dispatched: signal.dispatched,
311
+ reason: signal.reason,
211
312
  });
313
+
314
+ if (!shouldOutputJson(cmd)) {
315
+ log.info(
316
+ `Signal ${signal.signalId} emitted (dispatched: ${signal.dispatched})`,
317
+ );
318
+ if (signal.reason) {
319
+ log.info(` Reason: ${signal.reason}`);
320
+ }
321
+ }
322
+ } catch (err) {
323
+ const message = err instanceof Error ? err.message : String(err);
324
+ writeOutput(cmd, { ok: false, error: message });
212
325
  process.exitCode = 1;
213
- return;
214
- }
215
- }
216
-
217
- const sourceContextId = opts.sessionId ?? `cli-${Date.now()}`;
218
-
219
- // Validate --conversation-id if provided
220
- const conversationId = opts.conversationId?.trim();
221
- if (opts.conversationId != null && !conversationId) {
222
- writeOutput(cmd, {
223
- ok: false,
224
- error: "Conversation ID must be a non-empty string",
225
- });
226
- process.exitCode = 1;
227
- return;
228
- }
229
-
230
- const result = await cliIpcCall<{
231
- signalId: string;
232
- dispatched: boolean;
233
- deduplicated: boolean;
234
- reason: string;
235
- }>("emit_notification_signal", {
236
- body: {
237
- sourceChannel: opts.sourceChannel,
238
- sourceEventName: opts.sourceEventName,
239
- sourceContextId,
240
- attentionHints: {
241
- requiresAction: opts.requiresAction ?? true,
242
- urgency,
243
- deadlineAt,
244
- isAsyncBackground: opts.isAsyncBackground ?? false,
245
- visibleInSourceNow: opts.visibleInSourceNow ?? false,
246
- },
247
- contextPayload: {
248
- requestedMessage: message,
249
- requestedBySource: opts.sourceChannel,
250
- ...(opts.title ? { requestedTitle: opts.title } : {}),
251
- ...(preferredChannels?.length ? { preferredChannels } : {}),
252
- ...(deepLinkMetadata ? { deepLinkMetadata } : {}),
253
- },
254
- ...(opts.dedupeKey ? { dedupeKey: opts.dedupeKey } : {}),
255
- ...(conversationId
256
- ? { conversationAffinityHint: { vellum: conversationId } }
257
- : {}),
258
- throwOnError: true,
259
- },
260
- });
261
-
262
- if (!result.ok) {
263
- writeOutput(cmd, { ok: false, error: result.error });
264
- process.exitCode = 1;
265
- return;
266
- }
267
-
268
- const signal = result.result!;
269
-
270
- writeOutput(cmd, {
271
- ok: true,
272
- signalId: signal.signalId,
273
- dispatched: signal.dispatched,
274
- reason: signal.reason,
275
- });
276
-
277
- if (!shouldOutputJson(cmd)) {
278
- log.info(
279
- `Signal ${signal.signalId} emitted (dispatched: ${signal.dispatched})`,
280
- );
281
- if (signal.reason) {
282
- log.info(` Reason: ${signal.reason}`);
283
326
  }
284
- }
285
- } catch (err) {
286
- const message = err instanceof Error ? err.message : String(err);
287
- writeOutput(cmd, { ok: false, error: message });
288
- process.exitCode = 1;
289
- }
290
- },
291
- );
292
-
293
- // -------------------------------------------------------------------------
294
- // list
295
- // -------------------------------------------------------------------------
296
-
297
- notifications
298
- .command("list")
299
- .description("List recent notification events from the local event store")
300
- .option("--limit <n>", "Maximum number of events to return (default: 20)")
301
- .option("--source-event-name <name>", "Filter by source event name")
302
- .addHelpText(
303
- "after",
304
- `
327
+ },
328
+ );
329
+
330
+ // -------------------------------------------------------------------------
331
+ // list
332
+ // -------------------------------------------------------------------------
333
+
334
+ notifications
335
+ .command("list")
336
+ .description(
337
+ "List recent notification events from the local event store",
338
+ )
339
+ .option(
340
+ "--limit <n>",
341
+ "Maximum number of events to return (default: 20)",
342
+ )
343
+ .option("--source-event-name <name>", "Filter by source event name")
344
+ .addHelpText(
345
+ "after",
346
+ `
305
347
  Reads from the local notification events store, ordered by creation time
306
348
  (newest first). Each event represents a signal that was emitted through the
307
349
  notification pipeline.
@@ -311,92 +353,92 @@ Examples:
311
353
  $ assistant notifications list --limit 5
312
354
  $ assistant notifications list --source-event-name schedule.notify
313
355
  $ assistant notifications list --source-event-name schedule.notify --limit 10 --json`,
314
- )
315
- .action(
316
- async (
317
- opts: {
318
- limit?: string;
319
- sourceEventName?: string;
320
- },
321
- cmd: Command,
322
- ) => {
323
- try {
324
- // Validate --source-event-name (accept any non-empty string; custom
325
- // event names are valid since skills can emit arbitrary names)
326
- if (
327
- opts.sourceEventName != null &&
328
- opts.sourceEventName.trim().length === 0
329
- ) {
330
- writeOutput(cmd, {
331
- ok: false,
332
- error: "Source event name must be a non-empty string",
333
- });
334
- process.exitCode = 1;
335
- return;
336
- }
337
-
338
- // Parse and validate --limit
339
- let limit = 20;
340
- if (opts.limit != null) {
341
- const parsed = Number(opts.limit);
342
- if (
343
- !Number.isFinite(parsed) ||
344
- !Number.isInteger(parsed) ||
345
- parsed < 1
346
- ) {
347
- writeOutput(cmd, {
348
- ok: false,
349
- error: `Invalid limit "${opts.limit}". Must be a positive integer`,
356
+ )
357
+ .action(
358
+ async (
359
+ opts: {
360
+ limit?: string;
361
+ sourceEventName?: string;
362
+ },
363
+ cmd: Command,
364
+ ) => {
365
+ try {
366
+ // Validate --source-event-name (accept any non-empty string; custom
367
+ // event names are valid since skills can emit arbitrary names)
368
+ if (
369
+ opts.sourceEventName != null &&
370
+ opts.sourceEventName.trim().length === 0
371
+ ) {
372
+ writeOutput(cmd, {
373
+ ok: false,
374
+ error: "Source event name must be a non-empty string",
375
+ });
376
+ process.exitCode = 1;
377
+ return;
378
+ }
379
+
380
+ // Parse and validate --limit
381
+ let limit = 20;
382
+ if (opts.limit != null) {
383
+ const parsed = Number(opts.limit);
384
+ if (
385
+ !Number.isFinite(parsed) ||
386
+ !Number.isInteger(parsed) ||
387
+ parsed < 1
388
+ ) {
389
+ writeOutput(cmd, {
390
+ ok: false,
391
+ error: `Invalid limit "${opts.limit}". Must be a positive integer`,
392
+ });
393
+ process.exitCode = 1;
394
+ return;
395
+ }
396
+ limit = parsed;
397
+ }
398
+
399
+ const result = await cliIpcCall<
400
+ Array<{
401
+ id: string;
402
+ sourceEventName: string;
403
+ sourceChannel: string;
404
+ sourceContextId: string;
405
+ urgency: string;
406
+ dedupeKey: string | null;
407
+ createdAt: string;
408
+ }>
409
+ >("list_notification_events", {
410
+ body: { limit, sourceEventName: opts.sourceEventName },
350
411
  });
351
- process.exitCode = 1;
352
- return;
353
- }
354
- limit = parsed;
355
- }
356
-
357
- const result = await cliIpcCall<
358
- Array<{
359
- id: string;
360
- sourceEventName: string;
361
- sourceChannel: string;
362
- sourceContextId: string;
363
- urgency: string;
364
- dedupeKey: string | null;
365
- createdAt: string;
366
- }>
367
- >("list_notification_events", {
368
- body: { limit, sourceEventName: opts.sourceEventName },
369
- });
370
-
371
- if (!result.ok) {
372
- writeOutput(cmd, { ok: false, error: result.error });
373
- process.exitCode = 1;
374
- return;
375
- }
376
-
377
- const events = result.result!;
378
-
379
- writeOutput(cmd, { ok: true, events });
380
-
381
- if (!shouldOutputJson(cmd)) {
382
- if (events.length === 0) {
383
- log.info("No notification events found");
384
- } else {
385
- log.info(`${events.length} event(s):\n`);
386
- for (const event of events) {
387
- log.info(
388
- ` ${event.createdAt} ${event.sourceEventName} ${event.urgency} ${event.sourceChannel}`,
389
- );
412
+
413
+ if (!result.ok) {
414
+ writeOutput(cmd, { ok: false, error: result.error });
415
+ process.exitCode = exitCodeFromIpcResult(result);
416
+ return;
417
+ }
418
+
419
+ const events = result.result!;
420
+
421
+ writeOutput(cmd, { ok: true, events });
422
+
423
+ if (!shouldOutputJson(cmd)) {
424
+ if (events.length === 0) {
425
+ log.info("No notification events found");
426
+ } else {
427
+ log.info(`${events.length} event(s):\n`);
428
+ for (const event of events) {
429
+ log.info(
430
+ ` ${event.createdAt} ${event.sourceEventName} ${event.urgency} ${event.sourceChannel}`,
431
+ );
432
+ }
433
+ }
390
434
  }
435
+ } catch (err) {
436
+ const message = err instanceof Error ? err.message : String(err);
437
+ writeOutput(cmd, { ok: false, error: message });
438
+ process.exitCode = 1;
391
439
  }
392
- }
393
- } catch (err) {
394
- const message = err instanceof Error ? err.message : String(err);
395
- writeOutput(cmd, { ok: false, error: message });
396
- process.exitCode = 1;
397
- }
398
- },
399
- );
440
+ },
441
+ );
400
442
  },
401
443
  });
402
444
  }