@vellumai/assistant 0.8.2 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (503) hide show
  1. package/ARCHITECTURE.md +11 -12
  2. package/docker-entrypoint.sh +13 -2
  3. package/docker-init-apt-root.sh +79 -6
  4. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  5. package/openapi.yaml +945 -36
  6. package/package.json +1 -1
  7. package/src/__tests__/agent-loop-exit-reason.test.ts +271 -0
  8. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  9. package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
  10. package/src/__tests__/agent-loop.test.ts +88 -3
  11. package/src/__tests__/anthropic-provider.test.ts +272 -0
  12. package/src/__tests__/approval-cascade.test.ts +1 -1
  13. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
  14. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  15. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  16. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  17. package/src/__tests__/compaction-events.test.ts +1 -1
  18. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  19. package/src/__tests__/compactor-tail-resolution.test.ts +107 -1
  20. package/src/__tests__/config-get-vision-flag.test.ts +136 -0
  21. package/src/__tests__/config-loader-backfill.test.ts +115 -18
  22. package/src/__tests__/config-watcher.test.ts +1 -1
  23. package/src/__tests__/context-token-estimator.test.ts +112 -57
  24. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  25. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
  26. package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
  27. package/src/__tests__/conversation-agent-loop.test.ts +77 -3
  28. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  29. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  30. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  31. package/src/__tests__/conversation-fork-crud.test.ts +161 -0
  32. package/src/__tests__/conversation-lifecycle.test.ts +1 -1
  33. package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
  34. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  35. package/src/__tests__/conversation-media-retry.test.ts +19 -8
  36. package/src/__tests__/conversation-pairing.test.ts +2 -2
  37. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  38. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
  39. package/src/__tests__/conversation-queue.test.ts +1 -1
  40. package/src/__tests__/conversation-runtime-assembly.test.ts +290 -85
  41. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  42. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  43. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  44. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  45. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  46. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  47. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
  48. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  49. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  50. package/src/__tests__/credential-security-invariants.test.ts +6 -0
  51. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  52. package/src/__tests__/date-context.test.ts +45 -0
  53. package/src/__tests__/dm-backfill.test.ts +64 -0
  54. package/src/__tests__/dm-persistence.test.ts +33 -0
  55. package/src/__tests__/document-find-replace.test.ts +501 -0
  56. package/src/__tests__/external-plugin-loader.test.ts +91 -19
  57. package/src/__tests__/first-greeting.test.ts +23 -2
  58. package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
  59. package/src/__tests__/guardian-dispatch.test.ts +1 -0
  60. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  61. package/src/__tests__/heartbeat-service.test.ts +24 -164
  62. package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
  63. package/src/__tests__/host-app-control-proxy.test.ts +241 -0
  64. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  65. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  66. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  67. package/src/__tests__/host-file-proxy.test.ts +8 -1
  68. package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
  69. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  70. package/src/__tests__/identity-routes.test.ts +57 -0
  71. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  72. package/src/__tests__/injector-background-turn.test.ts +153 -0
  73. package/src/__tests__/injector-chain.test.ts +7 -0
  74. package/src/__tests__/injector-document-comments.test.ts +378 -0
  75. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  76. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +9 -2
  77. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  78. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  79. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  80. package/src/__tests__/list-messages-tool-merge.test.ts +17 -16
  81. package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
  82. package/src/__tests__/llm-catalog-parity.test.ts +3 -0
  83. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  84. package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
  85. package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
  86. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -0
  87. package/src/__tests__/llm-resolver.test.ts +340 -3
  88. package/src/__tests__/log-export-routes.test.ts +99 -2
  89. package/src/__tests__/managed-profile-guard.test.ts +10 -0
  90. package/src/__tests__/message-queue-steer.test.ts +114 -0
  91. package/src/__tests__/notification-decision-fallback.test.ts +0 -91
  92. package/src/__tests__/notification-decision-strategy.test.ts +14 -31
  93. package/src/__tests__/notification-deep-link.test.ts +15 -0
  94. package/src/__tests__/notification-guardian-path.test.ts +1 -2
  95. package/src/__tests__/notification-platform-adapter.test.ts +5 -4
  96. package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
  97. package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
  98. package/src/__tests__/openai-provider.test.ts +323 -3
  99. package/src/__tests__/openai-responses-cutover-guard.test.ts +3 -3
  100. package/src/__tests__/openai-responses-provider.test.ts +4 -4
  101. package/src/__tests__/openrouter-provider-only.test.ts +51 -3
  102. package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
  103. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  104. package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
  105. package/src/__tests__/platform-proxy-context.test.ts +6 -1
  106. package/src/__tests__/platform.test.ts +0 -3
  107. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  108. package/src/__tests__/plugin-tool-contribution.test.ts +3 -3
  109. package/src/__tests__/plugin-types.test.ts +2 -2
  110. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  111. package/src/__tests__/process-message-display-content.test.ts +21 -16
  112. package/src/__tests__/provider-catalog-visibility.test.ts +16 -0
  113. package/src/__tests__/provider-platform-proxy-integration.test.ts +27 -25
  114. package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
  115. package/src/__tests__/server-history-render.test.ts +83 -4
  116. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  117. package/src/__tests__/system-prompt.test.ts +57 -101
  118. package/src/__tests__/terminal-tools.test.ts +11 -1
  119. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  120. package/src/__tests__/thread-backfill.test.ts +370 -22
  121. package/src/__tests__/tool-executor.test.ts +90 -1
  122. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  123. package/src/__tests__/twilio-routes.test.ts +1 -1
  124. package/src/__tests__/web-fetch.test.ts +2 -2
  125. package/src/__tests__/workspace-git-service.test.ts +88 -5
  126. package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
  127. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  128. package/src/a2a/__tests__/agent-card.test.ts +98 -0
  129. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
  130. package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
  131. package/src/a2a/__tests__/task-store.test.ts +246 -0
  132. package/src/a2a/agent-card.ts +58 -0
  133. package/src/a2a/feature-gate.ts +8 -0
  134. package/src/a2a/protocol-constants.ts +21 -0
  135. package/src/a2a/protocol-errors.ts +50 -0
  136. package/src/a2a/protocol-types.ts +162 -0
  137. package/src/a2a/task-store.ts +168 -0
  138. package/src/agent/attachments.ts +1 -0
  139. package/src/agent/loop.ts +208 -22
  140. package/src/background-wake/next-wake.test.ts +289 -0
  141. package/src/background-wake/next-wake.ts +172 -0
  142. package/src/browser/operations.ts +15 -0
  143. package/src/channels/config.ts +9 -0
  144. package/src/channels/types.ts +14 -0
  145. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  146. package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
  147. package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
  148. package/src/cli/commands/__tests__/schedules.test.ts +469 -0
  149. package/src/cli/commands/conversations.ts +128 -1
  150. package/src/cli/commands/inference-providers.ts +147 -1
  151. package/src/cli/commands/memory-v2.ts +308 -0
  152. package/src/cli/commands/notifications.ts +89 -37
  153. package/src/cli/commands/plugins.ts +67 -0
  154. package/src/cli/commands/schedules.ts +297 -5
  155. package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
  156. package/src/cli/lib/install-from-github.ts +8 -9
  157. package/src/cli/lib/search-plugins.ts +163 -0
  158. package/src/cli/program.ts +14 -0
  159. package/src/cli/utils/conversation-id.ts +17 -5
  160. package/src/config/assistant-feature-flags.ts +24 -54
  161. package/src/config/bundled-skills/app-builder/SKILL.md +117 -1
  162. package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
  163. package/src/config/bundled-skills/document-editor/TOOLS.json +240 -0
  164. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  165. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  166. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  167. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  168. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  169. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  170. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
  171. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  172. package/src/config/bundled-tool-registry.ts +22 -12
  173. package/src/config/call-site-defaults.ts +124 -0
  174. package/src/config/feature-flag-registry.json +111 -23
  175. package/src/config/llm-resolver.ts +66 -1
  176. package/src/config/schema.ts +2 -0
  177. package/src/config/schemas/__tests__/memory-v2.test.ts +7 -3
  178. package/src/config/schemas/call-site-catalog.ts +21 -0
  179. package/src/config/schemas/channels.ts +9 -0
  180. package/src/config/schemas/conversations.ts +10 -0
  181. package/src/config/schemas/heartbeat.ts +14 -0
  182. package/src/config/schemas/llm.ts +4 -3
  183. package/src/config/schemas/memory-retrospective.ts +1 -1
  184. package/src/config/schemas/memory-v2.ts +51 -4
  185. package/src/config/schemas/memory.ts +3 -1
  186. package/src/config/seed-inference-profiles.ts +99 -29
  187. package/src/context/compactor.ts +80 -13
  188. package/src/context/token-estimator.ts +72 -31
  189. package/src/context/window-manager.ts +25 -0
  190. package/src/credential-health/credential-health-service.ts +34 -19
  191. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -22
  192. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  193. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  194. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  195. package/src/daemon/conversation-agent-loop-handlers.ts +231 -23
  196. package/src/daemon/conversation-agent-loop.ts +252 -56
  197. package/src/daemon/conversation-lifecycle.ts +142 -116
  198. package/src/daemon/conversation-messaging.ts +3 -0
  199. package/src/daemon/conversation-process.ts +273 -0
  200. package/src/daemon/conversation-queue-manager.ts +14 -0
  201. package/src/daemon/conversation-runtime-assembly.ts +144 -75
  202. package/src/daemon/conversation-slash.ts +37 -5
  203. package/src/daemon/conversation-surfaces.ts +45 -2
  204. package/src/daemon/conversation-tool-setup.ts +7 -0
  205. package/src/daemon/conversation.ts +42 -12
  206. package/src/daemon/date-context.ts +40 -0
  207. package/src/daemon/first-greeting.ts +10 -0
  208. package/src/daemon/guardian-action-generators.ts +1 -125
  209. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  210. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
  211. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
  212. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
  213. package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
  214. package/src/daemon/handlers/config-a2a.ts +449 -0
  215. package/src/daemon/handlers/config-model.test.ts +1 -0
  216. package/src/daemon/handlers/conversations.ts +80 -0
  217. package/src/daemon/handlers/shared.ts +92 -29
  218. package/src/daemon/host-app-control-proxy.ts +69 -18
  219. package/src/daemon/host-bash-proxy.ts +1 -1
  220. package/src/daemon/host-cu-proxy.ts +1 -1
  221. package/src/daemon/host-file-proxy.ts +1 -1
  222. package/src/daemon/host-proxy-preactivation.ts +85 -18
  223. package/src/daemon/host-transfer-proxy.ts +1 -1
  224. package/src/daemon/lifecycle.ts +67 -65
  225. package/src/daemon/memory-v2-startup.ts +49 -13
  226. package/src/daemon/message-protocol.ts +4 -0
  227. package/src/daemon/message-types/conversations.ts +8 -0
  228. package/src/daemon/message-types/document-comments.ts +50 -0
  229. package/src/daemon/message-types/messages.ts +68 -1
  230. package/src/daemon/message-types/notifications.ts +21 -0
  231. package/src/daemon/message-types/surfaces.ts +3 -1
  232. package/src/daemon/message-types/web-activity.ts +57 -0
  233. package/src/daemon/pkb-reminder-builder.test.ts +10 -53
  234. package/src/daemon/pkb-reminder-builder.ts +4 -19
  235. package/src/daemon/plugin-source-watcher.ts +135 -3
  236. package/src/daemon/process-message.ts +72 -12
  237. package/src/daemon/query-complexity-router.ts +75 -0
  238. package/src/daemon/skill-memory-refresh.ts +5 -1
  239. package/src/daemon/trust-context.ts +6 -0
  240. package/src/daemon/wake-target-adapter.ts +2 -0
  241. package/src/documents/document-comments-store.test.ts +338 -0
  242. package/src/documents/document-comments-store.ts +237 -0
  243. package/src/documents/document-store.ts +202 -0
  244. package/src/export/__tests__/transcript-formatter.test.ts +121 -0
  245. package/src/export/transcript-formatter.ts +54 -20
  246. package/src/heartbeat/__tests__/heartbeat-service.test.ts +44 -1
  247. package/src/heartbeat/heartbeat-service.ts +35 -191
  248. package/src/home/__tests__/feed-types.test.ts +40 -0
  249. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  250. package/src/home/feed-types.ts +20 -3
  251. package/src/home/home-content-refresh.ts +52 -0
  252. package/src/home/home-greeting-cache.ts +69 -0
  253. package/src/home/home-greeting.ts +94 -0
  254. package/src/home/suggested-prompts.ts +177 -9
  255. package/src/ipc/cli-client.ts +147 -45
  256. package/src/memory/__tests__/conversation-queries.test.ts +220 -0
  257. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  258. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
  259. package/src/memory/__tests__/memory-retrospective-job.test.ts +407 -10
  260. package/src/memory/conversation-crud.ts +133 -43
  261. package/src/memory/conversation-queries.ts +87 -1
  262. package/src/memory/conversation-title-service.ts +26 -4
  263. package/src/memory/db-init.ts +22 -0
  264. package/src/memory/delivery-crud.ts +41 -0
  265. package/src/memory/delivery-status.ts +141 -15
  266. package/src/memory/external-conversation-store.ts +32 -1
  267. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +84 -3
  268. package/src/memory/graph/conversation-graph-memory.ts +18 -6
  269. package/src/memory/graph/tools.ts +6 -37
  270. package/src/memory/invite-store.ts +53 -0
  271. package/src/memory/jobs-worker.ts +21 -1
  272. package/src/memory/llm-request-log-source-clickhouse.ts +7 -2
  273. package/src/memory/llm-request-log-store.ts +92 -1
  274. package/src/memory/memory-retrospective-constants.ts +28 -0
  275. package/src/memory/memory-retrospective-enqueue.ts +4 -22
  276. package/src/memory/memory-retrospective-job.ts +438 -21
  277. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  278. package/src/memory/memory-v2-activation-log-store.ts +26 -8
  279. package/src/memory/migrations/100-core-tables.ts +1 -0
  280. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  281. package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
  282. package/src/memory/migrations/251-a2a-tasks.ts +49 -0
  283. package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
  284. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  285. package/src/memory/migrations/253-document-comments.ts +47 -0
  286. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  287. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  288. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  289. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  290. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  291. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  292. package/src/memory/migrations/index.ts +20 -0
  293. package/src/memory/migrations/registry.ts +33 -0
  294. package/src/memory/onboarding-events-store.ts +7 -0
  295. package/src/memory/schema/a2a.ts +15 -0
  296. package/src/memory/schema/calls.ts +1 -0
  297. package/src/memory/schema/conversations.ts +3 -0
  298. package/src/memory/schema/index.ts +1 -0
  299. package/src/memory/schema/inference.ts +2 -0
  300. package/src/memory/schema/infrastructure.ts +2 -0
  301. package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
  302. package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
  303. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
  304. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  305. package/src/memory/v2/__tests__/injection.test.ts +221 -17
  306. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  307. package/src/memory/v2/__tests__/router.test.ts +489 -1
  308. package/src/memory/v2/__tests__/static-context.test.ts +12 -1
  309. package/src/memory/v2/activation-store.ts +14 -16
  310. package/src/memory/v2/cli-command-content.ts +19 -0
  311. package/src/memory/v2/cli-command-store.ts +304 -0
  312. package/src/memory/v2/consolidation-job.ts +14 -0
  313. package/src/memory/v2/frontmatter-sweep.ts +7 -1
  314. package/src/memory/v2/injection-events.ts +101 -0
  315. package/src/memory/v2/injection.ts +69 -29
  316. package/src/memory/v2/page-index.ts +246 -19
  317. package/src/memory/v2/page-store.ts +18 -0
  318. package/src/memory/v2/router.ts +209 -55
  319. package/src/memory/v2/static-context.ts +4 -4
  320. package/src/memory/v2/types.ts +23 -0
  321. package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
  322. package/src/messaging/providers/a2a/deliver.ts +156 -0
  323. package/src/messaging/providers/gmail/client.ts +9 -2
  324. package/src/messaging/providers/index.ts +18 -3
  325. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  326. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  327. package/src/messaging/providers/slack/adapter.ts +178 -25
  328. package/src/messaging/providers/slack/api.test.ts +54 -0
  329. package/src/messaging/providers/slack/api.ts +119 -3
  330. package/src/messaging/providers/slack/client.ts +12 -0
  331. package/src/messaging/providers/slack/deep-link.ts +20 -1
  332. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  333. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  334. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  335. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  336. package/src/messaging/providers/slack/send.test.ts +77 -0
  337. package/src/messaging/providers/slack/send.ts +8 -2
  338. package/src/messaging/providers/slack/types.ts +14 -0
  339. package/src/notifications/__tests__/broadcaster.test.ts +203 -0
  340. package/src/notifications/__tests__/decision-engine.test.ts +283 -0
  341. package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
  342. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +5 -1
  343. package/src/notifications/__tests__/home-feed-side-effect.test.ts +521 -36
  344. package/src/notifications/adapters/macos.ts +12 -2
  345. package/src/notifications/broadcaster.ts +29 -4
  346. package/src/notifications/conversation-seed-composer.ts +14 -2
  347. package/src/notifications/copy-composer.ts +17 -64
  348. package/src/notifications/decision-engine.ts +111 -44
  349. package/src/notifications/deferred-emit.ts +135 -0
  350. package/src/notifications/deterministic-checks.ts +96 -0
  351. package/src/notifications/emit-signal.ts +10 -1
  352. package/src/notifications/home-feed-side-effect.ts +136 -27
  353. package/src/notifications/signal.ts +0 -4
  354. package/src/notifications/types.ts +8 -0
  355. package/src/oauth/connect-orchestrator.ts +3 -0
  356. package/src/oauth/credential-token-resolver.ts +2 -0
  357. package/src/oauth/manual-token-connection.ts +19 -0
  358. package/src/oauth/oauth-store.ts +12 -0
  359. package/src/oauth/platform-connection.test.ts +43 -3
  360. package/src/oauth/platform-connection.ts +13 -4
  361. package/src/oauth/seed-providers.ts +22 -0
  362. package/src/permissions/prompter.ts +5 -2
  363. package/src/permissions/secret-prompter.ts +4 -1
  364. package/src/plugins/defaults/injectors.ts +118 -26
  365. package/src/plugins/external-plugin-loader.ts +82 -10
  366. package/src/plugins/types.ts +16 -7
  367. package/src/prompts/__tests__/system-prompt.test.ts +44 -45
  368. package/src/prompts/__tests__/task-progress-hint-section.test.ts +4 -8
  369. package/src/prompts/normalize-onboarding.ts +40 -0
  370. package/src/prompts/sections.ts +32 -14
  371. package/src/prompts/system-prompt.ts +105 -76
  372. package/src/prompts/template-detection.ts +37 -0
  373. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  374. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  375. package/src/prompts/templates/VOICE.md +3 -0
  376. package/src/prompts/templates/system-sections.ts +51 -10
  377. package/src/providers/__tests__/inference.test.ts +2 -0
  378. package/src/providers/anthropic/client.ts +132 -5
  379. package/src/providers/call-site-routing.ts +24 -6
  380. package/src/providers/connection-resolution.ts +63 -13
  381. package/src/providers/fireworks/client.ts +20 -2
  382. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
  383. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  384. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  385. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  386. package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
  387. package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
  388. package/src/providers/inference/adapter-factory.ts +24 -21
  389. package/src/providers/inference/auth.ts +15 -3
  390. package/src/providers/inference/backfill.ts +14 -1
  391. package/src/providers/inference/codex-token-refresh.ts +128 -0
  392. package/src/providers/inference/connections.ts +85 -5
  393. package/src/providers/inference/resolve-auth.ts +50 -5
  394. package/src/providers/model-catalog.ts +244 -242
  395. package/src/providers/model-intents.ts +3 -3
  396. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
  397. package/src/providers/openai/chat-completions-provider.ts +215 -25
  398. package/src/providers/openai/responses-provider.ts +9 -3
  399. package/src/providers/openrouter/client.ts +46 -4
  400. package/src/providers/platform-proxy/constants.ts +3 -4
  401. package/src/providers/provider-catalog-visibility.ts +3 -1
  402. package/src/providers/provider-send-message.ts +27 -12
  403. package/src/providers/registry.ts +30 -1
  404. package/src/providers/types.ts +25 -0
  405. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  406. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  407. package/src/runtime/agent-wake.ts +212 -57
  408. package/src/runtime/auth/route-policy.ts +20 -3
  409. package/src/runtime/background-job-runner.ts +26 -0
  410. package/src/runtime/channel-reply-delivery.ts +182 -47
  411. package/src/runtime/channel-retry-sweep.ts +141 -16
  412. package/src/runtime/http-server.ts +7 -16
  413. package/src/runtime/http-types.ts +7 -51
  414. package/src/runtime/pending-interactions.ts +51 -8
  415. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
  416. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  417. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +121 -5
  418. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
  419. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
  420. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  421. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -0
  422. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  423. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  424. package/src/runtime/routes/approval-routes.ts +4 -1
  425. package/src/runtime/routes/channel-availability-routes.ts +5 -0
  426. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  427. package/src/runtime/routes/consolidation-routes.ts +100 -0
  428. package/src/runtime/routes/content-source-routes.ts +78 -0
  429. package/src/runtime/routes/conversation-cli-routes.ts +146 -1
  430. package/src/runtime/routes/conversation-query-routes.ts +130 -12
  431. package/src/runtime/routes/conversation-routes.ts +288 -76
  432. package/src/runtime/routes/document-comments-routes.ts +287 -0
  433. package/src/runtime/routes/documents-routes.ts +33 -0
  434. package/src/runtime/routes/home-feed-routes.ts +6 -3
  435. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  436. package/src/runtime/routes/host-browser-routes.ts +8 -1
  437. package/src/runtime/routes/identity-routes.ts +21 -0
  438. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  439. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  440. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  441. package/src/runtime/routes/index.ts +14 -4
  442. package/src/runtime/routes/inference-provider-connection-routes.ts +192 -3
  443. package/src/runtime/routes/integrations/a2a.ts +294 -0
  444. package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
  445. package/src/runtime/routes/log-export-routes.ts +39 -0
  446. package/src/runtime/routes/memory-v2-routes.ts +217 -0
  447. package/src/runtime/routes/notification-routes.ts +19 -2
  448. package/src/runtime/routes/question-routes.ts +4 -1
  449. package/src/runtime/routes/sanity-routes.ts +159 -0
  450. package/src/runtime/routes/slack-channel-routes.ts +187 -0
  451. package/src/runtime/routes/subagents-routes.ts +41 -0
  452. package/src/runtime/services/conversation-serializer.ts +30 -4
  453. package/src/schedule/integration-status.ts +3 -1
  454. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  455. package/src/security/oauth2-device-code.ts +307 -0
  456. package/src/security/oauth2.ts +26 -9
  457. package/src/security/secure-keys.ts +5 -0
  458. package/src/skills/catalog-install.ts +6 -2
  459. package/src/subagent/manager.ts +2 -0
  460. package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
  461. package/src/tools/browser/browser-execution.ts +93 -0
  462. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  463. package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
  464. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
  465. package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
  466. package/src/tools/browser/cdp-client/factory.ts +87 -3
  467. package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
  468. package/src/tools/browser/cdp-client/types.ts +36 -0
  469. package/src/tools/browser/pinned-tabs.ts +90 -0
  470. package/src/tools/document/document-comment-tool.test.ts +379 -0
  471. package/src/tools/document/document-comment-tool.ts +156 -0
  472. package/src/tools/document/document-tool.ts +128 -2
  473. package/src/tools/memory/register.ts +1 -9
  474. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  475. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  476. package/src/tools/network/domain-normalize.ts +17 -0
  477. package/src/tools/network/web-fetch.ts +213 -64
  478. package/src/tools/network/web-search.ts +191 -66
  479. package/src/tools/registry.ts +2 -2
  480. package/src/tools/terminal/safe-env.ts +3 -2
  481. package/src/tools/tool-approval-handler.ts +19 -12
  482. package/src/tools/types.ts +41 -2
  483. package/src/tools/ui-surface/definitions.ts +3 -1
  484. package/src/types/onboarding-context.ts +4 -0
  485. package/src/util/__tests__/favicon.test.ts +84 -0
  486. package/src/util/favicon.ts +40 -0
  487. package/src/util/platform.ts +0 -5
  488. package/src/workspace/git-service.ts +75 -4
  489. package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
  490. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  491. package/src/workspace/migrations/registry.ts +4 -0
  492. package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
  493. package/src/config/bundled-skills/document/SKILL.md +0 -54
  494. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  495. package/src/daemon/seed-files.ts +0 -18
  496. package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
  497. package/src/runtime/guardian-action-conversation-turn.ts +0 -99
  498. package/src/runtime/routes/interface-routes.ts +0 -43
  499. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  500. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  501. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  502. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  503. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -95,97 +95,6 @@ describe("notification decision fallback copy", () => {
95
95
  );
96
96
  });
97
97
 
98
- test("enforces guardian-facing popup copy for heartbeat alerts", async () => {
99
- configuredProvider = { sendMessage: async () => ({}) };
100
- extractedToolUse = {
101
- input: {
102
- shouldNotify: true,
103
- selectedChannels: ["vellum"],
104
- reasoningSummary: "Heartbeat found a useful follow-up.",
105
- renderedCopy: {
106
- vellum: {
107
- title: "Heartbeat Follow-up",
108
- body: "The daily tracker is ready; consider reminding the guardian to review it before the next check-in.",
109
- },
110
- },
111
- dedupeKey: "heartbeat:test",
112
- confidence: 0.9,
113
- },
114
- };
115
-
116
- const decision = await evaluateSignal(
117
- makeSignal({
118
- sourceEventName: "heartbeat.alert",
119
- sourceChannel: "watcher",
120
- contextPayload: {
121
- summary:
122
- "The daily tracker is ready; consider reminding the guardian to review it before the next check-in.",
123
- conversationTitle: "Running Habit Tracking",
124
- },
125
- attentionHints: {
126
- requiresAction: true,
127
- urgency: "medium",
128
- isAsyncBackground: true,
129
- visibleInSourceNow: false,
130
- },
131
- }),
132
- ["vellum"] as NotificationChannel[],
133
- );
134
-
135
- expect(decision.fallbackUsed).toBe(false);
136
- expect(decision.renderedCopy.vellum?.title).toBe("Heartbeat Alert");
137
- expect(decision.renderedCopy.vellum?.body).toBe(
138
- "I found something worth your attention in a heartbeat check. Open the conversation for details.",
139
- );
140
- expect(decision.renderedCopy.vellum?.body).not.toContain(
141
- "reminding the guardian",
142
- );
143
- });
144
-
145
- test("keeps direct guardian-facing heartbeat copy", async () => {
146
- configuredProvider = { sendMessage: async () => ({}) };
147
- extractedToolUse = {
148
- input: {
149
- shouldNotify: true,
150
- selectedChannels: ["vellum"],
151
- reasoningSummary: "Heartbeat found a useful follow-up.",
152
- renderedCopy: {
153
- vellum: {
154
- title: "Tracker Ready",
155
- body: "Your daily tracker is ready. Review it before the next check-in.",
156
- },
157
- },
158
- dedupeKey: "heartbeat:direct-copy-test",
159
- confidence: 0.9,
160
- },
161
- };
162
-
163
- const decision = await evaluateSignal(
164
- makeSignal({
165
- sourceEventName: "heartbeat.alert",
166
- sourceChannel: "watcher",
167
- contextPayload: {
168
- summary:
169
- "The daily tracker is ready; consider reminding the guardian to review it before the next check-in.",
170
- conversationTitle: "Running Habit Tracking",
171
- },
172
- attentionHints: {
173
- requiresAction: true,
174
- urgency: "medium",
175
- isAsyncBackground: true,
176
- visibleInSourceNow: false,
177
- },
178
- }),
179
- ["vellum"] as NotificationChannel[],
180
- );
181
-
182
- expect(decision.fallbackUsed).toBe(false);
183
- expect(decision.renderedCopy.vellum?.title).toBe("Tracker Ready");
184
- expect(decision.renderedCopy.vellum?.body).toBe(
185
- "Your daily tracker is ready. Review it before the next check-in.",
186
- );
187
- });
188
-
189
98
  test("enforces free-text answer instructions for guardian.question when requestCode exists", async () => {
190
99
  const signal = makeSignal({
191
100
  contextPayload: {
@@ -147,7 +147,10 @@ describe("notification decision strategy", () => {
147
147
  expect(copy.telegram!.deliveryText).toBe("Take out the trash");
148
148
  });
149
149
 
150
- test("unknown event name produces generic copy with urgency prefix", () => {
150
+ test("unknown event name produces generic copy with empty body", () => {
151
+ // The event-name-derived body fallback was removed; the deterministic
152
+ // `checkRenderedCopyQuality` check in deterministic-checks.ts will
153
+ // suppress notifications that end up with an empty body.
151
154
  const signal = makeSignal({
152
155
  sourceEventName: "some_novel.event",
153
156
  attentionHints: {
@@ -161,12 +164,16 @@ describe("notification decision strategy", () => {
161
164
  const copy = composeFallbackCopy(signal, channels);
162
165
  expect(copy.vellum).toBeDefined();
163
166
  expect(copy.vellum!.title).toBe("Notification");
164
- expect(copy.vellum!.body).toContain("Urgent:");
165
- expect(copy.vellum!.body).toContain("action required");
166
- expect(copy.telegram!.deliveryText).toBe(copy.telegram!.body);
167
+ expect(copy.vellum!.body).toBe("");
168
+ // Telegram deliveryText falls back to title when body is empty; the
169
+ // checkRenderedCopyQuality check still suppresses on empty body.
170
+ expect(copy.telegram!.body).toBe("");
167
171
  });
168
172
 
169
- test("unknown event name without urgency produces clean generic copy", () => {
173
+ test("unknown event name without urgency also produces empty body", () => {
174
+ // The event-name-derived body fallback was removed; the deterministic
175
+ // `checkRenderedCopyQuality` check in deterministic-checks.ts will
176
+ // suppress notifications that end up with an empty body.
170
177
  const signal = makeSignal({
171
178
  sourceEventName: "background.sync_complete",
172
179
  attentionHints: {
@@ -179,10 +186,8 @@ describe("notification decision strategy", () => {
179
186
 
180
187
  const copy = composeFallbackCopy(signal, channels);
181
188
  expect(copy.vellum).toBeDefined();
182
- expect(copy.vellum!.body).not.toContain("Urgent:");
183
- expect(copy.vellum!.body).not.toContain("action required");
184
- // Dots and underscores in event name are replaced with spaces
185
- expect(copy.vellum!.body).toContain("background sync complete");
189
+ expect(copy.vellum!.title).toBe("Notification");
190
+ expect(copy.vellum!.body).toBe("");
186
191
  });
187
192
 
188
193
  test("fallback copy is generated for every requested channel", () => {
@@ -373,28 +378,6 @@ describe("notification decision strategy", () => {
373
378
  "A guardian question needs your attention",
374
379
  );
375
380
  });
376
-
377
- test("heartbeat.alert fallback avoids intermediary-instruction popup copy", () => {
378
- const signal = makeSignal({
379
- sourceEventName: "heartbeat.alert",
380
- contextPayload: {
381
- summary:
382
- "The daily tracker is ready; consider reminding the guardian to review it before the next check-in.",
383
- conversationTitle: "Running Habit Tracking",
384
- },
385
- });
386
-
387
- const copy = composeFallbackCopy(signal, channels);
388
- expect(copy.vellum).toBeDefined();
389
- expect(copy.vellum!.title).toBe("Heartbeat Alert");
390
- expect(copy.vellum!.body).toBe(
391
- "I found something worth your attention in a heartbeat check. Open the conversation for details.",
392
- );
393
- expect(copy.vellum!.conversationSeedMessage).toContain(
394
- "consider reminding the guardian",
395
- );
396
- expect(copy.telegram!.deliveryText).toBe(copy.vellum!.body);
397
- });
398
381
  });
399
382
 
400
383
  // -- NotificationChannel type correctness ----------------------------------
@@ -156,6 +156,7 @@ describe("notification deep-link metadata", () => {
156
156
  conversationId: "conv-123",
157
157
  conversationType: "notification",
158
158
  },
159
+ urgency: "medium",
159
160
  },
160
161
  { channel: "vellum" },
161
162
  );
@@ -179,6 +180,7 @@ describe("notification deep-link metadata", () => {
179
180
  {
180
181
  sourceEventName: "test.event",
181
182
  copy: { title: "Alert", body: "No deep link" },
183
+ urgency: "medium",
182
184
  },
183
185
  { channel: "vellum" },
184
186
  );
@@ -199,6 +201,7 @@ describe("notification deep-link metadata", () => {
199
201
  sourceEventName: "guardian.question",
200
202
  copy: { title: "Guardian Question", body: "What is the code?" },
201
203
  deepLinkTarget: { conversationId },
204
+ urgency: "medium",
202
205
  },
203
206
  { channel: "vellum" },
204
207
  );
@@ -215,6 +218,7 @@ describe("notification deep-link metadata", () => {
215
218
  {
216
219
  sourceEventName: "test.event",
217
220
  copy: { title: "T", body: "B" },
221
+ urgency: "medium",
218
222
  },
219
223
  { channel: "vellum" },
220
224
  );
@@ -231,6 +235,7 @@ describe("notification deep-link metadata", () => {
231
235
  {
232
236
  sourceEventName: "test.event",
233
237
  copy: { title: "T", body: "B" },
238
+ urgency: "medium",
234
239
  },
235
240
  { channel: "vellum" },
236
241
  );
@@ -247,6 +252,7 @@ describe("notification deep-link metadata", () => {
247
252
  {
248
253
  sourceEventName: "guardian.question",
249
254
  copy: { title: "Alert", body: "Body" },
255
+ urgency: "medium",
250
256
  },
251
257
  { channel: "vellum" },
252
258
  );
@@ -268,6 +274,7 @@ describe("notification deep-link metadata", () => {
268
274
  conversationId: "conv-task-run-42",
269
275
  workItemId: "work-item-7",
270
276
  },
277
+ urgency: "medium",
271
278
  },
272
279
  { channel: "vellum" },
273
280
  );
@@ -287,6 +294,7 @@ describe("notification deep-link metadata", () => {
287
294
  sourceEventName: "guardian.question",
288
295
  copy: { title: "Question", body: "Body" },
289
296
  deepLinkTarget: { conversationId: "conv-1", messageId: "msg-1" },
297
+ urgency: "medium",
290
298
  },
291
299
  { channel: "vellum" },
292
300
  );
@@ -309,6 +317,7 @@ describe("notification deep-link metadata", () => {
309
317
  sourceEventName: "schedule.notify",
310
318
  copy: { title: "Reminder", body: "Take out the trash" },
311
319
  deepLinkTarget: { conversationId: "conv-new-convo-001" },
320
+ urgency: "medium",
312
321
  },
313
322
  { channel: "vellum" },
314
323
  );
@@ -332,6 +341,7 @@ describe("notification deep-link metadata", () => {
332
341
  body: "Still need to take out the trash",
333
342
  },
334
343
  deepLinkTarget: { conversationId: "conv-reused-convo-042" },
344
+ urgency: "medium",
335
345
  },
336
346
  { channel: "vellum" },
337
347
  );
@@ -358,6 +368,7 @@ describe("notification deep-link metadata", () => {
358
368
  conversationId: stableConversationId,
359
369
  messageId: "msg-seed-1",
360
370
  },
371
+ urgency: "medium",
361
372
  },
362
373
  { channel: "vellum" },
363
374
  );
@@ -371,6 +382,7 @@ describe("notification deep-link metadata", () => {
371
382
  conversationId: stableConversationId,
372
383
  messageId: "msg-seed-2",
373
384
  },
385
+ urgency: "medium",
374
386
  },
375
387
  { channel: "vellum" },
376
388
  );
@@ -402,6 +414,7 @@ describe("notification deep-link metadata", () => {
402
414
  sourceEventName: "schedule.notify",
403
415
  copy: { title: "Reminder", body: "First" },
404
416
  deepLinkTarget: { conversationId, messageId: "msg-a" },
417
+ urgency: "medium",
405
418
  },
406
419
  { channel: "vellum" },
407
420
  );
@@ -411,6 +424,7 @@ describe("notification deep-link metadata", () => {
411
424
  sourceEventName: "schedule.notify",
412
425
  copy: { title: "Reminder", body: "Second" },
413
426
  deepLinkTarget: { conversationId, messageId: "msg-b" },
427
+ urgency: "medium",
414
428
  },
415
429
  { channel: "vellum" },
416
430
  );
@@ -442,6 +456,7 @@ describe("notification deep-link metadata", () => {
442
456
  sourceEventName: "activity.complete",
443
457
  copy: { title: "Activity", body },
444
458
  deepLinkTarget: { conversationId: boundConvId },
459
+ urgency: "medium",
445
460
  },
446
461
  { channel: "vellum" },
447
462
  );
@@ -31,8 +31,6 @@ mock.module("../config/loader.js", () => ({
31
31
  }),
32
32
  }));
33
33
 
34
-
35
-
36
34
  const emitCalls: unknown[] = [];
37
35
  let mockConversationCreated: ConversationCreatedInfo | null = null;
38
36
  let mockEmitResult: {
@@ -189,6 +187,7 @@ describe("ASK_GUARDIAN canonical notification path", () => {
189
187
  conversationId: "conv-from-thread-callback",
190
188
  title: "Guardian question",
191
189
  sourceEventName: "guardian.question",
190
+ silent: false,
192
191
  };
193
192
  mockEmitResult = {
194
193
  signalId: "sig-2",
@@ -37,7 +37,8 @@ interface FetchCall {
37
37
  }
38
38
 
39
39
  const fetchCalls: FetchCall[] = [];
40
- const fetchResponses: Array<{ ok: boolean; status: number; body?: string }> = [];
40
+ const fetchResponses: Array<{ ok: boolean; status: number; body?: string }> =
41
+ [];
41
42
  let clientAvailable = true;
42
43
 
43
44
  mock.module("../platform/client.js", () => ({
@@ -84,6 +85,7 @@ function makePayload(
84
85
  copy: { title: "Reminder", body: "Check the oven!" },
85
86
  deepLinkTarget: { type: "conversation", id: "conv-1" },
86
87
  contextPayload: { jobId: "job-1" },
88
+ urgency: "medium",
87
89
  ...overrides,
88
90
  };
89
91
  }
@@ -118,9 +120,7 @@ describe("PlatformPushAdapter", () => {
118
120
  expect(fetchCalls).toHaveLength(1);
119
121
 
120
122
  const call = fetchCalls[0]!;
121
- expect(call.path).toBe(
122
- "/v1/assistants/test-assistant-id/push/dispatch/",
123
- );
123
+ expect(call.path).toBe("/v1/assistants/test-assistant-id/push/dispatch/");
124
124
  expect(call.method).toBe("POST");
125
125
  expect(call.body.delivery_id).toBe("delivery-uuid-1");
126
126
  expect(call.body.source_event_name).toBe("schedule.notify");
@@ -216,6 +216,7 @@ describe("PlatformPushAdapter", () => {
216
216
  const payload: ChannelDeliveryPayload = {
217
217
  sourceEventName: "schedule.notify",
218
218
  copy: { title: "Hi", body: "Hello" },
219
+ urgency: "medium",
219
220
  };
220
221
 
221
222
  const result = await adapter.send(payload, makeDestination());
@@ -58,6 +58,7 @@ function makePayload(
58
58
  title: "Reminder",
59
59
  body: "Check the oven now!",
60
60
  },
61
+ urgency: "medium",
61
62
  ...overrides,
62
63
  };
63
64
  }
@@ -0,0 +1,113 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import type { ServerMessage } from "../daemon/message-protocol.js";
4
+ import { VellumAdapter } from "../notifications/adapters/macos.js";
5
+ import type {
6
+ ChannelDeliveryPayload,
7
+ ChannelDestination,
8
+ } from "../notifications/types.js";
9
+
10
+ function makePayload(
11
+ overrides?: Partial<ChannelDeliveryPayload>,
12
+ ): ChannelDeliveryPayload {
13
+ return {
14
+ deliveryId: "delivery-uuid-1",
15
+ sourceEventName: "schedule.notify",
16
+ copy: { title: "Reminder", body: "Hello" },
17
+ urgency: "medium",
18
+ ...overrides,
19
+ };
20
+ }
21
+
22
+ function makeDestination(
23
+ overrides?: Partial<ChannelDestination>,
24
+ ): ChannelDestination {
25
+ return {
26
+ channel: "vellum",
27
+ ...overrides,
28
+ };
29
+ }
30
+
31
+ function captureBroadcast(): {
32
+ adapter: VellumAdapter;
33
+ sent: ServerMessage[];
34
+ } {
35
+ const sent: ServerMessage[] = [];
36
+ const adapter = new VellumAdapter((msg) => sent.push(msg));
37
+ return { adapter, sent };
38
+ }
39
+
40
+ describe("VellumAdapter silent flag", () => {
41
+ test("non-urgent (low) urgency broadcasts silent: true", async () => {
42
+ const { adapter, sent } = captureBroadcast();
43
+ const result = await adapter.send(
44
+ makePayload({ urgency: "low" }),
45
+ makeDestination(),
46
+ );
47
+
48
+ expect(result.success).toBe(true);
49
+ expect(sent).toHaveLength(1);
50
+ const intent = sent[0] as Extract<
51
+ ServerMessage,
52
+ { type: "notification_intent" }
53
+ >;
54
+ expect(intent.type).toBe("notification_intent");
55
+ expect(intent.silent).toBe(true);
56
+ });
57
+
58
+ test("non-urgent (medium) urgency broadcasts silent: true", async () => {
59
+ const { adapter, sent } = captureBroadcast();
60
+ await adapter.send(makePayload({ urgency: "medium" }), makeDestination());
61
+
62
+ const intent = sent[0] as Extract<
63
+ ServerMessage,
64
+ { type: "notification_intent" }
65
+ >;
66
+ expect(intent.silent).toBe(true);
67
+ });
68
+
69
+ test("urgent (high) urgency broadcasts silent: false", async () => {
70
+ const { adapter, sent } = captureBroadcast();
71
+ await adapter.send(makePayload({ urgency: "high" }), makeDestination());
72
+
73
+ const intent = sent[0] as Extract<
74
+ ServerMessage,
75
+ { type: "notification_intent" }
76
+ >;
77
+ expect(intent.silent).toBe(false);
78
+ });
79
+
80
+ test("critical urgency broadcasts silent: false", async () => {
81
+ const { adapter, sent } = captureBroadcast();
82
+ await adapter.send(makePayload({ urgency: "critical" }), makeDestination());
83
+
84
+ const intent = sent[0] as Extract<
85
+ ServerMessage,
86
+ { type: "notification_intent" }
87
+ >;
88
+ expect(intent.silent).toBe(false);
89
+ });
90
+
91
+ test("broadcasts title, body, deepLinkTarget, and deliveryId verbatim", async () => {
92
+ const { adapter, sent } = captureBroadcast();
93
+ await adapter.send(
94
+ makePayload({
95
+ deliveryId: "delivery-xyz",
96
+ copy: { title: "T", body: "B" },
97
+ deepLinkTarget: { conversationId: "conv-abc" },
98
+ urgency: "high",
99
+ }),
100
+ makeDestination(),
101
+ );
102
+
103
+ const intent = sent[0] as Extract<
104
+ ServerMessage,
105
+ { type: "notification_intent" }
106
+ >;
107
+ expect(intent.deliveryId).toBe("delivery-xyz");
108
+ expect(intent.title).toBe("T");
109
+ expect(intent.body).toBe("B");
110
+ expect(intent.deepLinkMetadata).toEqual({ conversationId: "conv-abc" });
111
+ expect(intent.silent).toBe(false);
112
+ });
113
+ });