@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
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Route handler for channel availability.
3
+ *
4
+ * GET /v1/channels/available — return the channels this assistant can
5
+ * surface to clients (Contacts / GuardianChannels views, etc.) along with
6
+ * their display metadata (label, subtitle, icon, verification capability,
7
+ * setup-message copy). Today this is a fixed base list plus `email` when
8
+ * an inbox is registered; eventually the list will be driven by
9
+ * plugins/skills the assistant has loaded. Clients should treat the
10
+ * response as authoritative and stop carrying their own per-channel
11
+ * switches.
12
+ *
13
+ * Distinct from `/v1/channels/readiness` (which answers "is this channel
14
+ * configured and working?"). Availability answers "could this channel be
15
+ * surfaced for setup/verification at all?".
16
+ */
17
+
18
+ import { z } from "zod";
19
+
20
+ import { isA2AEnabled } from "../../a2a/feature-gate.js";
21
+ import {
22
+ CHANNEL_IDS,
23
+ CHANNEL_METADATA,
24
+ type ChannelId,
25
+ type ChannelInfo,
26
+ } from "../../channels/types.js";
27
+ import { getConfig } from "../../config/loader.js";
28
+ import { VellumPlatformClient } from "../../platform/client.js";
29
+ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
30
+
31
+ // Base list every assistant currently surfaces. Order is the display
32
+ // order clients should render. Keep stable — clients sort by index.
33
+ const BASE_AVAILABLE_CHANNELS: readonly ChannelId[] = [
34
+ "slack",
35
+ "telegram",
36
+ "phone",
37
+ ] as const;
38
+
39
+ interface EmailAddressListResponse {
40
+ count?: number;
41
+ results?: Array<{ id: string; address: string }>;
42
+ }
43
+
44
+ /**
45
+ * Best-effort check that an inbox address is registered for this
46
+ * assistant. A platform fetch failure is treated as "no inbox" — we
47
+ * prefer to under-report than block the entire Contacts page when the
48
+ * platform is briefly unreachable.
49
+ */
50
+ async function hasRegisteredInbox(): Promise<boolean> {
51
+ const client = await VellumPlatformClient.create();
52
+ if (!client?.platformAssistantId) {
53
+ return false;
54
+ }
55
+
56
+ try {
57
+ const response = await client.fetch(
58
+ `/v1/assistants/${client.platformAssistantId}/email-addresses/`,
59
+ );
60
+ if (!response.ok) {
61
+ return false;
62
+ }
63
+ const data = (await response.json()) as EmailAddressListResponse;
64
+ if (typeof data.count === "number") {
65
+ return data.count > 0;
66
+ }
67
+ return Array.isArray(data.results) && data.results.length > 0;
68
+ } catch {
69
+ return false;
70
+ }
71
+ }
72
+
73
+ async function handleGetChannelAvailability(
74
+ _args: RouteHandlerArgs,
75
+ ): Promise<{ channels: ChannelInfo[] }> {
76
+ const ids: ChannelId[] = [...BASE_AVAILABLE_CHANNELS];
77
+ if (await hasRegisteredInbox()) {
78
+ ids.push("email");
79
+ }
80
+ if (isA2AEnabled(getConfig())) {
81
+ ids.push("a2a");
82
+ }
83
+ // CHANNEL_METADATA is `Partial<Record<ChannelId, ChannelInfo>>` because
84
+ // unsurfaced channels deliberately have no metadata. `ids` only ever
85
+ // contains channels that BASE_AVAILABLE_CHANNELS / the email branch
86
+ // explicitly chose, so the lookup is always defined — filter to satisfy
87
+ // the type system without a non-null assertion.
88
+ const channels = ids
89
+ .map((id) => CHANNEL_METADATA[id])
90
+ .filter((info): info is ChannelInfo => info !== undefined);
91
+ return { channels };
92
+ }
93
+
94
+ const channelInfoSchema = z.object({
95
+ id: z.enum(CHANNEL_IDS),
96
+ label: z.string(),
97
+ subtitle: z.string(),
98
+ icon: z.string(),
99
+ supportsVerification: z.boolean(),
100
+ setupMessages: z.object({
101
+ guardian: z.string(),
102
+ contact: z.string(),
103
+ }),
104
+ });
105
+
106
+ export const ROUTES: RouteDefinition[] = [
107
+ {
108
+ operationId: "channels_available_get",
109
+ endpoint: "channels/available",
110
+ method: "GET",
111
+ summary: "Get available channels",
112
+ description:
113
+ "Return the channels this assistant can surface to clients, with " +
114
+ "display metadata (label, icon, verification capability, setup " +
115
+ "copy). Today this is a fixed base list plus `email` when an inbox " +
116
+ "is registered; will become plugin/skill-driven in future.",
117
+ tags: ["channels"],
118
+ requirePolicyEnforcement: true,
119
+ handler: handleGetChannelAvailability,
120
+ responseBody: z.object({
121
+ channels: z
122
+ .array(channelInfoSchema)
123
+ .describe("Available channels in display order"),
124
+ }),
125
+ },
126
+ ];
@@ -17,11 +17,16 @@ import { z } from "zod";
17
17
 
18
18
  import { getConfig } from "../../config/loader.js";
19
19
  import { getMemoryCheckpoint } from "../../memory/checkpoints.js";
20
+ import {
21
+ getMessageRoleStatsByConversation,
22
+ listConversationsBySource,
23
+ } from "../../memory/conversation-queries.js";
20
24
  import {
21
25
  enqueueMemoryJob,
22
26
  hasActiveJobOfType,
23
27
  } from "../../memory/jobs-store.js";
24
28
  import { GRAPH_MAINTENANCE_CHECKPOINTS } from "../../memory/jobs-worker.js";
29
+ import { MEMORY_V2_CONSOLIDATION_SOURCE } from "../../memory/v2/constants.js";
25
30
  import { BadRequestError } from "./errors.js";
26
31
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
27
32
 
@@ -111,4 +116,99 @@ export const ROUTES: RouteDefinition[] = [
111
116
  return { success: true, ran: true, jobId };
112
117
  },
113
118
  },
119
+ {
120
+ operationId: "listConsolidationRuns",
121
+ endpoint: "consolidation/runs",
122
+ method: "GET",
123
+ policyKey: "consolidation",
124
+ summary: "List consolidation runs",
125
+ description:
126
+ "Return recent memory v2 consolidation conversations as run records. " +
127
+ "Each consolidation dispatch creates exactly one background conversation " +
128
+ "tagged with `source = memory_v2_consolidation`; that conversation IS " +
129
+ "the run. Synthetic fields: `id` mirrors `conversationId` (no separate " +
130
+ "run row exists), `scheduledFor` and `startedAt` both equal " +
131
+ "`conversation.createdAt` (no separate schedule timestamp), " +
132
+ "`finishedAt` is the `createdAt` of the latest assistant message in " +
133
+ "the conversation (NOT `conversation.lastMessageAt`, which the kickoff " +
134
+ "user prompt bumps before the agent runs). `status` is `'ok'` when " +
135
+ "the conversation has at least one assistant message — i.e. positive " +
136
+ "evidence the agent emitted output — otherwise `'running'`. This is a " +
137
+ "weaker signal than heartbeat's `'ok'`: without a dedicated runs " +
138
+ "table we cannot distinguish 'ran cleanly' from 'crashed after " +
139
+ "emitting at least one assistant message'. `skipReason` and `error` " +
140
+ "are always null — skipped runs (lock held, disabled, empty buffer) " +
141
+ "never create a conversation, and run failure detail is not stored " +
142
+ "on the conversation row. Shape mirrors `heartbeat/runs` so the " +
143
+ "schedules settings UI can reuse its run-row component.",
144
+ tags: ["consolidation"],
145
+ queryParams: [
146
+ {
147
+ name: "limit",
148
+ schema: { type: "integer" },
149
+ description: "Max runs to return (default 20, max 100)",
150
+ },
151
+ ],
152
+ responseBody: z.object({
153
+ runs: z
154
+ .array(
155
+ z.object({
156
+ id: z.string(),
157
+ scheduledFor: z.number(),
158
+ startedAt: z.number().nullable(),
159
+ finishedAt: z.number().nullable(),
160
+ durationMs: z.number().nullable(),
161
+ status: z.enum(["ok", "running"]),
162
+ skipReason: z.string().nullable(),
163
+ error: z.string().nullable(),
164
+ conversationId: z.string().nullable(),
165
+ createdAt: z.number(),
166
+ }),
167
+ )
168
+ .describe("Consolidation run records"),
169
+ }),
170
+ handler: async ({ queryParams }: RouteHandlerArgs) => {
171
+ const params = queryParams ?? {};
172
+ const rawLimit = Number(params.limit ?? 20);
173
+ const limit = Number.isFinite(rawLimit)
174
+ ? Math.min(Math.max(Math.floor(rawLimit), 1), 100)
175
+ : 20;
176
+ const rows = listConversationsBySource(
177
+ MEMORY_V2_CONSOLIDATION_SOURCE,
178
+ limit,
179
+ );
180
+ // Aggregate assistant-message stats in one batched query: presence of
181
+ // an assistant message is the strongest "agent emitted output" signal
182
+ // available without a dedicated consolidation runs table. The kickoff
183
+ // user prompt is persisted via `addMessage` before the agent run,
184
+ // which bumps `conversations.lastMessageAt` — so that field cannot
185
+ // be used to infer completion.
186
+ const assistantStats = getMessageRoleStatsByConversation(
187
+ rows.map((r) => r.id),
188
+ "assistant",
189
+ );
190
+ return {
191
+ runs: rows.map((c) => {
192
+ const stat = assistantStats.get(c.id);
193
+ const hasAssistantOutput = (stat?.count ?? 0) > 0;
194
+ const finishedAt = hasAssistantOutput ? stat!.lastAt : null;
195
+ return {
196
+ id: c.id,
197
+ scheduledFor: c.createdAt,
198
+ startedAt: c.createdAt,
199
+ finishedAt,
200
+ durationMs:
201
+ finishedAt != null ? finishedAt - c.createdAt : null,
202
+ status: (hasAssistantOutput ? "ok" : "running") as
203
+ | "ok"
204
+ | "running",
205
+ skipReason: null,
206
+ error: null,
207
+ conversationId: c.id,
208
+ createdAt: c.createdAt,
209
+ };
210
+ }),
211
+ };
212
+ },
213
+ },
114
214
  ];
@@ -6,15 +6,18 @@
6
6
  * used by the macOS / web clients.
7
7
  */
8
8
 
9
+ import { v4 as uuid } from "uuid";
9
10
  import { z } from "zod";
10
11
 
11
12
  import { clearAllConversations as clearAllActive } from "../../daemon/handlers/conversations.js";
12
13
  import { formatJson, formatMarkdown } from "../../export/formatter.js";
13
14
  import {
15
+ addMessage,
14
16
  createConversation,
15
17
  getConversation,
16
18
  getMessages,
17
19
  } from "../../memory/conversation-crud.js";
20
+ import { setConversationKey } from "../../memory/conversation-key-store.js";
18
21
  import { listConversations } from "../../memory/conversation-queries.js";
19
22
  import { getLogger } from "../../util/logger.js";
20
23
  import { BadRequestError, NotFoundError } from "./errors.js";
@@ -45,12 +48,43 @@ function handleListCli({ body = {} }: RouteHandlerArgs) {
45
48
  // create (CLI)
46
49
  // ---------------------------------------------------------------------------
47
50
 
48
- function handleCreateCli({ body = {} }: RouteHandlerArgs) {
51
+ const seededConversationMessageSchema = z.object({
52
+ role: z.enum(["user", "assistant"]),
53
+ content: z.string(),
54
+ });
55
+
56
+ type SeededConversationMessage = z.infer<
57
+ typeof seededConversationMessageSchema
58
+ >;
59
+
60
+ function textContentJson(text: string): string {
61
+ return JSON.stringify([{ type: "text", text }]);
62
+ }
63
+
64
+ async function handleCreateCli({ body = {} }: RouteHandlerArgs) {
49
65
  const title = body.title as string | undefined;
66
+ const messages =
67
+ (body.messages as SeededConversationMessage[] | undefined) ?? [];
68
+
50
69
  const conversation = createConversation(title);
70
+ const conversationKey = uuid();
71
+ setConversationKey(conversationKey, conversation.id);
72
+
73
+ for (const message of messages) {
74
+ await addMessage(
75
+ conversation.id,
76
+ message.role,
77
+ textContentJson(message.content),
78
+ undefined,
79
+ { skipIndexing: true },
80
+ );
81
+ }
82
+
51
83
  return {
52
84
  id: conversation.id,
53
85
  title: conversation.title ?? "New Conversation",
86
+ conversationKey,
87
+ messagesInserted: messages.length,
54
88
  };
55
89
  }
56
90
 
@@ -109,7 +143,10 @@ function handleExportCli({ body = {} }: RouteHandlerArgs) {
109
143
  async function handleClearCli(_args: RouteHandlerArgs) {
110
144
  // Tear down in-memory conversation state before DB clear.
111
145
  const cleared = clearAllActive();
112
- log.info({ cleared }, "CLI conversations clear: active conversations torn down");
146
+ log.info(
147
+ { cleared },
148
+ "CLI conversations clear: active conversations torn down",
149
+ );
113
150
  return { cleared };
114
151
  }
115
152
 
@@ -146,14 +183,18 @@ export const ROUTES: RouteDefinition[] = [
146
183
  endpoint: "conversations/cli/create",
147
184
  method: "POST",
148
185
  summary: "Create a conversation (CLI)",
149
- description: "Create a new conversation with an optional title.",
186
+ description:
187
+ "Create a new conversation with an optional title and seeded messages.",
150
188
  tags: ["conversations"],
151
189
  requestBody: z.object({
152
190
  title: z.string().optional(),
191
+ messages: z.array(seededConversationMessageSchema).optional(),
153
192
  }),
154
193
  responseBody: z.object({
155
194
  id: z.string(),
156
195
  title: z.string(),
196
+ conversationKey: z.string(),
197
+ messagesInserted: z.number().int().nonnegative(),
157
198
  }),
158
199
  handler: handleCreateCli,
159
200
  },
@@ -28,12 +28,11 @@ import { getBindingsForConversations } from "../../memory/external-conversation-
28
28
  import { listGroups } from "../../memory/group-crud.js";
29
29
  import { UserError } from "../../util/errors.js";
30
30
  import { getLogger } from "../../util/logger.js";
31
- import { buildAssistantEvent } from "../assistant-event.js";
32
- import { assistantEventHub } from "../assistant-event-hub.js";
33
31
  import {
34
32
  buildConversationDetailResponse,
35
33
  serializeConversationSummary,
36
34
  } from "../services/conversation-serializer.js";
35
+ import { publishConversationListAndMetadataChanged } from "../sync/resource-sync-events.js";
37
36
  import {
38
37
  BadRequestError,
39
38
  InternalError,
@@ -54,22 +53,6 @@ function resolveOrThrow(rawId: string): string {
54
53
  return id;
55
54
  }
56
55
 
57
- function publishListInvalidated(): void {
58
- assistantEventHub
59
- .publish(
60
- buildAssistantEvent({
61
- type: "conversation_list_invalidated",
62
- reason: "seen_changed",
63
- }),
64
- )
65
- .catch((err) => {
66
- log.warn(
67
- { err },
68
- "Failed to publish conversation_list_invalidated (seen_changed)",
69
- );
70
- });
71
- }
72
-
73
56
  // ---------------------------------------------------------------------------
74
57
  // Handlers
75
58
  // ---------------------------------------------------------------------------
@@ -159,7 +142,7 @@ function handleRecordSeen({ body = {} }: RouteHandlerArgs) {
159
142
  });
160
143
 
161
144
  if (wasUnseen) {
162
- publishListInvalidated();
145
+ publishConversationListAndMetadataChanged("seen_changed", conversationId);
163
146
  }
164
147
 
165
148
  return { ok: true };
@@ -179,7 +162,7 @@ function handleMarkUnread({ body = {} }: RouteHandlerArgs) {
179
162
  try {
180
163
  const changed = markConversationUnread(conversationId);
181
164
  if (changed) {
182
- publishListInvalidated();
165
+ publishConversationListAndMetadataChanged("seen_changed", conversationId);
183
166
  }
184
167
  return { ok: true };
185
168
  } catch (err) {
@@ -27,7 +27,6 @@ import {
27
27
  switchConversation,
28
28
  undoLastMessage,
29
29
  } from "../../daemon/handlers/conversations.js";
30
- import type { ConversationListInvalidatedReason } from "../../daemon/message-types/conversations.js";
31
30
  import { normalizeConversationType } from "../../daemon/message-types/shared.js";
32
31
  import {
33
32
  archiveConversation,
@@ -49,9 +48,12 @@ import { enqueueMemoryJob } from "../../memory/jobs-store.js";
49
48
  import { deleteSchedule } from "../../schedule/schedule-store.js";
50
49
  import { UserError } from "../../util/errors.js";
51
50
  import { getLogger } from "../../util/logger.js";
52
- import { buildAssistantEvent } from "../assistant-event.js";
53
- import { assistantEventHub } from "../assistant-event-hub.js";
54
51
  import { buildConversationDetailResponse } from "../services/conversation-serializer.js";
52
+ import {
53
+ publishConversationListAndMetadataChanged,
54
+ publishConversationListChanged,
55
+ publishConversationTitleChanged,
56
+ } from "../sync/resource-sync-events.js";
55
57
  import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
56
58
  import { setInferenceProfileSession } from "./inference-profile-session-handler.js";
57
59
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
@@ -68,24 +70,6 @@ function resolveOrThrow(rawId: string): string {
68
70
  return id;
69
71
  }
70
72
 
71
- function publishListInvalidated(
72
- reason: ConversationListInvalidatedReason,
73
- ): void {
74
- assistantEventHub
75
- .publish(
76
- buildAssistantEvent({
77
- type: "conversation_list_invalidated",
78
- reason,
79
- }),
80
- )
81
- .catch((err) => {
82
- log.warn(
83
- { err },
84
- `Failed to publish conversation_list_invalidated (${reason})`,
85
- );
86
- });
87
- }
88
-
89
73
  function cancelScheduleIfLast(conversationId: string): void {
90
74
  const conv = getConversation(conversationId);
91
75
  if (
@@ -108,6 +92,7 @@ function handleCreateConversation({ body = {} }: RouteHandlerArgs) {
108
92
  });
109
93
  if (result.created) {
110
94
  updateConversationTitle(result.conversationId, "New Conversation");
95
+ publishConversationListAndMetadataChanged("created", result.conversationId);
111
96
  }
112
97
  log.info(
113
98
  {
@@ -151,6 +136,7 @@ async function handleForkConversation({ body = {} }: RouteHandlerArgs) {
151
136
  `Forked conversation ${forkedConversation.id} could not be loaded`,
152
137
  );
153
138
  }
139
+ publishConversationListAndMetadataChanged("created", forkedConversation.id);
154
140
  return { conversation: detail.conversation };
155
141
  } catch (err) {
156
142
  if (err instanceof UserError) {
@@ -217,25 +203,7 @@ function handleRenameConversation({
217
203
  }
218
204
  updateConversationTitle(pathParams.id!, name, 0);
219
205
 
220
- assistantEventHub
221
- .publish(
222
- buildAssistantEvent(
223
- {
224
- type: "conversation_title_updated",
225
- conversationId: pathParams.id!,
226
- title: name,
227
- },
228
- pathParams.id!,
229
- ),
230
- )
231
- .catch((err) => {
232
- log.warn(
233
- { err, conversationId: pathParams.id },
234
- "Failed to publish conversation_title_updated",
235
- );
236
- });
237
-
238
- publishListInvalidated("renamed");
206
+ publishConversationTitleChanged(pathParams.id!, name);
239
207
 
240
208
  return { ok: true };
241
209
  }
@@ -249,6 +217,7 @@ function handleClearAllConversations({ headers = {} }: RouteHandlerArgs) {
249
217
  );
250
218
  }
251
219
  clearAllConversations();
220
+ publishConversationListChanged("deleted");
252
221
  return undefined;
253
222
  }
254
223
 
@@ -279,6 +248,7 @@ function handleWipeConversation({ pathParams = {} }: RouteHandlerArgs) {
279
248
  },
280
249
  "Wiped conversation and reverted memory changes",
281
250
  );
251
+ publishConversationListAndMetadataChanged("deleted", resolvedId);
282
252
  return {
283
253
  wiped: true,
284
254
  unsupersededItems: 0,
@@ -308,7 +278,7 @@ function handleDeleteConversation({ pathParams = {} }: RouteHandlerArgs) {
308
278
  }
309
279
  log.info({ conversationId: resolvedId }, "Deleted conversation");
310
280
 
311
- publishListInvalidated("deleted");
281
+ publishConversationListAndMetadataChanged("deleted", resolvedId);
312
282
 
313
283
  return undefined;
314
284
  }
@@ -319,6 +289,7 @@ function handleArchiveConversation({ pathParams = {} }: RouteHandlerArgs) {
319
289
  if (!archived) {
320
290
  throw new NotFoundError(`Conversation ${pathParams.id} not found`);
321
291
  }
292
+ publishConversationListAndMetadataChanged("reordered", resolvedId);
322
293
  return { ok: true, conversationId: resolvedId };
323
294
  }
324
295
 
@@ -328,6 +299,7 @@ function handleUnarchiveConversation({ pathParams = {} }: RouteHandlerArgs) {
328
299
  if (!unarchived) {
329
300
  throw new NotFoundError(`Conversation ${pathParams.id} not found`);
330
301
  }
302
+ publishConversationListAndMetadataChanged("reordered", resolvedId);
331
303
  return { ok: true, conversationId: resolvedId };
332
304
  }
333
305
 
@@ -387,7 +359,10 @@ function handleReorderConversations({ body = {} }: RouteHandlerArgs) {
387
359
  groupId: u.groupId,
388
360
  })),
389
361
  );
390
- publishListInvalidated("reordered");
362
+ publishConversationListAndMetadataChanged(
363
+ "reordered",
364
+ updates.map((u) => u.conversationId),
365
+ );
391
366
  return { ok: true };
392
367
  }
393
368