@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
@@ -0,0 +1,49 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+ import { tableHasColumn } from "./schema-introspection.js";
4
+ import { withCrashRecovery } from "./validate-migration-state.js";
5
+
6
+ const CHECKPOINT_KEY = "migration_a2a_tasks_v1";
7
+
8
+ /**
9
+ * Create the a2a_tasks table for tracking A2A request/response lifecycle.
10
+ *
11
+ * Each row represents one inbound A2A task, tracking its state machine
12
+ * progression through submitted -> working -> completed/failed/canceled/rejected.
13
+ */
14
+ export function migrateA2ATasks(database: DrizzleDb): void {
15
+ withCrashRecovery(database, CHECKPOINT_KEY, () => {
16
+ if (tableHasColumn(database, "a2a_tasks", "id")) {
17
+ return;
18
+ }
19
+ const raw = getSqliteFrom(database);
20
+ raw.exec(/*sql*/ `
21
+ CREATE TABLE IF NOT EXISTS a2a_tasks (
22
+ id TEXT PRIMARY KEY,
23
+ context_id TEXT,
24
+ conversation_id TEXT,
25
+ state TEXT NOT NULL DEFAULT 'submitted',
26
+ status_message TEXT,
27
+ request_message_json TEXT NOT NULL,
28
+ artifacts_json TEXT,
29
+ push_url TEXT,
30
+ sender_assistant_id TEXT NOT NULL,
31
+ created_at INTEGER NOT NULL,
32
+ updated_at INTEGER NOT NULL
33
+ )
34
+ `);
35
+ raw.exec(/*sql*/ `
36
+ CREATE INDEX IF NOT EXISTS idx_a2a_tasks_context
37
+ ON a2a_tasks (context_id)
38
+ `);
39
+ raw.exec(/*sql*/ `
40
+ CREATE INDEX IF NOT EXISTS idx_a2a_tasks_conversation
41
+ ON a2a_tasks (conversation_id)
42
+ `);
43
+ });
44
+ }
45
+
46
+ export function downA2ATasks(database: DrizzleDb): void {
47
+ const raw = getSqliteFrom(database);
48
+ raw.exec(/*sql*/ `DROP TABLE IF EXISTS a2a_tasks`);
49
+ }
@@ -0,0 +1,32 @@
1
+ import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
2
+
3
+ /**
4
+ * Adds `agent_loop_exit_reason` (nullable TEXT) to the `llm_request_logs`
5
+ * table.
6
+ *
7
+ * The agent loop sets this column on its final log row via
8
+ * `setAgentLoopExitReasonOnLatestLog` once the `while (true)` body exits.
9
+ * Intermediate rows keep NULL — downstream tooling (notably the LLM
10
+ * Context Inspector) reads "row has non-null value" as "this is the final
11
+ * call of a complete agent-loop run". Encoding the run-end via row state
12
+ * keeps the schema additive: no new tables, no FK churn.
13
+ *
14
+ * Idempotent — re-running is a no-op once the column exists. Modeled on
15
+ * migration 250 (`provider-connection-base-url-and-models`).
16
+ */
17
+ export function migrateLlmRequestLogAgentLoopExitReason(
18
+ database: DrizzleDb,
19
+ ): void {
20
+ const raw = getSqliteFrom(database);
21
+
22
+ const columns = raw
23
+ .query(`PRAGMA table_info(llm_request_logs)`)
24
+ .all() as Array<{ name: string }>;
25
+ const columnNames = new Set(columns.map((c) => c.name));
26
+
27
+ if (!columnNames.has("agent_loop_exit_reason")) {
28
+ raw.exec(
29
+ `ALTER TABLE llm_request_logs ADD COLUMN agent_loop_exit_reason TEXT`,
30
+ );
31
+ }
32
+ }
@@ -0,0 +1,15 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ export function migrateConversationLastNotifiedProfile(
5
+ database: DrizzleDb,
6
+ ): void {
7
+ const raw = getSqliteFrom(database);
8
+ try {
9
+ raw.exec(
10
+ `ALTER TABLE conversations ADD COLUMN last_notified_inference_profile TEXT DEFAULT NULL`,
11
+ );
12
+ } catch {
13
+ // Column already exists — nothing to do.
14
+ }
15
+ }
@@ -0,0 +1,47 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+
4
+ /**
5
+ * Create the `document_comments` table for inline and document-level comments.
6
+ *
7
+ * Supports threaded replies via `parent_comment_id` and resolution tracking
8
+ * via `status`, `resolved_by`, and `resolved_at`. The FK on `surface_id`
9
+ * cascades deletes from `documents` — when a document is removed, all its
10
+ * comments are cleaned up automatically.
11
+ *
12
+ * Idempotent — re-running is a no-op once the table and indices exist.
13
+ */
14
+ export function migrateCreateDocumentComments(database: DrizzleDb): void {
15
+ const raw = getSqliteFrom(database);
16
+
17
+ raw.exec(/*sql*/ `
18
+ CREATE TABLE IF NOT EXISTS document_comments (
19
+ id TEXT PRIMARY KEY,
20
+ surface_id TEXT NOT NULL,
21
+ conversation_id TEXT NOT NULL,
22
+ author TEXT NOT NULL,
23
+ content TEXT NOT NULL,
24
+ anchor_start INTEGER,
25
+ anchor_end INTEGER,
26
+ anchor_text TEXT,
27
+ parent_comment_id TEXT,
28
+ status TEXT NOT NULL DEFAULT 'open',
29
+ resolved_by TEXT,
30
+ resolved_at INTEGER,
31
+ created_at INTEGER NOT NULL,
32
+ updated_at INTEGER NOT NULL,
33
+ FOREIGN KEY (surface_id) REFERENCES documents(surface_id) ON DELETE CASCADE,
34
+ FOREIGN KEY (parent_comment_id) REFERENCES document_comments(id) ON DELETE CASCADE
35
+ )
36
+ `);
37
+
38
+ raw.exec(/*sql*/ `
39
+ CREATE INDEX IF NOT EXISTS idx_document_comments_surface
40
+ ON document_comments(surface_id)
41
+ `);
42
+
43
+ raw.exec(/*sql*/ `
44
+ CREATE INDEX IF NOT EXISTS idx_document_comments_parent
45
+ ON document_comments(parent_comment_id)
46
+ `);
47
+ }
@@ -0,0 +1,43 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { tableHasColumn } from "./schema-introspection.js";
3
+ import { withCrashRecovery } from "./validate-migration-state.js";
4
+
5
+ const CHECKPOINT_KEY = "migration_external_conversation_binding_chat_name_v1";
6
+
7
+ export function migrateExternalConversationBindingChatName(
8
+ database: DrizzleDb,
9
+ ): void {
10
+ withCrashRecovery(database, CHECKPOINT_KEY, () => {
11
+ if (
12
+ tableHasColumn(
13
+ database,
14
+ "external_conversation_bindings",
15
+ "external_chat_name",
16
+ )
17
+ ) {
18
+ return;
19
+ }
20
+
21
+ database.run(
22
+ `ALTER TABLE external_conversation_bindings ADD COLUMN external_chat_name TEXT`,
23
+ );
24
+ });
25
+ }
26
+
27
+ export function downExternalConversationBindingChatName(
28
+ database: DrizzleDb,
29
+ ): void {
30
+ if (
31
+ !tableHasColumn(
32
+ database,
33
+ "external_conversation_bindings",
34
+ "external_chat_name",
35
+ )
36
+ ) {
37
+ return;
38
+ }
39
+
40
+ database.run(
41
+ `ALTER TABLE external_conversation_bindings DROP COLUMN external_chat_name`,
42
+ );
43
+ }
@@ -0,0 +1,24 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+ import { tableHasColumn } from "./schema-introspection.js";
4
+ import { withCrashRecovery } from "./validate-migration-state.js";
5
+
6
+ const CHECKPOINT_KEY = "migration_channel_inbound_delivery_attempts_v1";
7
+
8
+ /** Add a delivery-specific retry counter for channel inbound events. */
9
+ export function migrateChannelInboundDeliveryAttempts(
10
+ database: DrizzleDb,
11
+ ): void {
12
+ withCrashRecovery(database, CHECKPOINT_KEY, () => {
13
+ if (
14
+ tableHasColumn(database, "channel_inbound_events", "delivery_attempts")
15
+ ) {
16
+ return;
17
+ }
18
+ const raw = getSqliteFrom(database);
19
+ raw.exec(/*sql*/ `
20
+ ALTER TABLE channel_inbound_events
21
+ ADD COLUMN delivery_attempts INTEGER NOT NULL DEFAULT 0
22
+ `);
23
+ });
24
+ }
@@ -0,0 +1,113 @@
1
+ import { getLogger } from "../../util/logger.js";
2
+ import type { DrizzleDb } from "../db-connection.js";
3
+ import { getSqliteFrom } from "../db-connection.js";
4
+ import { withCrashRecovery } from "./validate-migration-state.js";
5
+
6
+ const CHECKPOINT_KEY = "migration_memory_v2_injection_events_v1";
7
+ const log = getLogger("memory-v2-injection-events-migration");
8
+
9
+ /**
10
+ * Create the memory_v2_injection_events table — an append-only event log of
11
+ * (slug, injected_at) tuples capturing every router selection.
12
+ *
13
+ * This is the data source for the time-decayed injection frequency score
14
+ * that drives tier 2 assignment in memory router v4. Score is computed on
15
+ * read as `Σ exp(-λ × (now - tᵢ))` with `λ = ln(2) / 3 days`, so the table
16
+ * just accumulates raw events; the formula or half-life can change later
17
+ * without losing signal.
18
+ *
19
+ * Backfill: walks existing `memory_v2_activation_logs` and replays each
20
+ * row's router-sourced slugs as historical events. Without backfill the
21
+ * scores would take ~3 half-lives (≈9 days) to reach steady state; with
22
+ * backfill tier 2 assignment has signal from day one.
23
+ *
24
+ * Indexes:
25
+ * - `(slug, injected_at)` for per-slug score reads (the hot path).
26
+ * - `(injected_at)` for time-range pruning later.
27
+ */
28
+ export function migrateMemoryV2InjectionEvents(database: DrizzleDb): void {
29
+ withCrashRecovery(database, CHECKPOINT_KEY, () => {
30
+ const raw = getSqliteFrom(database);
31
+ raw.exec(/*sql*/ `
32
+ CREATE TABLE IF NOT EXISTS memory_v2_injection_events (
33
+ id INTEGER PRIMARY KEY,
34
+ slug TEXT NOT NULL,
35
+ injected_at INTEGER NOT NULL
36
+ )
37
+ `);
38
+ raw.exec(/*sql*/ `
39
+ CREATE INDEX IF NOT EXISTS idx_memory_v2_injection_events_slug_time
40
+ ON memory_v2_injection_events (slug, injected_at)
41
+ `);
42
+ raw.exec(/*sql*/ `
43
+ CREATE INDEX IF NOT EXISTS idx_memory_v2_injection_events_time
44
+ ON memory_v2_injection_events (injected_at)
45
+ `);
46
+
47
+ // Bail before backfill on databases that predate memory_v2_activation_logs
48
+ // (migration 234) — there's no historical signal to replay.
49
+ const logsTable = raw
50
+ .query(
51
+ `SELECT name FROM sqlite_master WHERE type='table' AND name='memory_v2_activation_logs'`,
52
+ )
53
+ .get();
54
+ if (!logsTable) return;
55
+
56
+ // Re-run safety net independent of the checkpoint: if events already
57
+ // exist, do not append duplicates. The checkpoint normally short-circuits
58
+ // re-runs in withCrashRecovery; this guards the manual-clear path.
59
+ const existing = raw
60
+ .query(`SELECT COUNT(*) as n FROM memory_v2_injection_events`)
61
+ .get() as { n: number };
62
+ if (existing.n > 0) return;
63
+
64
+ const rows = raw
65
+ .query(
66
+ `SELECT concepts_json, created_at FROM memory_v2_activation_logs ORDER BY created_at ASC`,
67
+ )
68
+ .all() as Array<{ concepts_json: string; created_at: number }>;
69
+ if (rows.length === 0) return;
70
+
71
+ const insert = raw.prepare(
72
+ `INSERT INTO memory_v2_injection_events (slug, injected_at) VALUES (?, ?)`,
73
+ );
74
+ const replay = raw.transaction(
75
+ (events: ReadonlyArray<{ slug: string; t: number }>) => {
76
+ for (const e of events) insert.run(e.slug, e.t);
77
+ },
78
+ );
79
+
80
+ const buffer: Array<{ slug: string; t: number }> = [];
81
+ let parseFailures = 0;
82
+ for (const row of rows) {
83
+ let concepts: Array<{ slug?: unknown; source?: unknown }>;
84
+ try {
85
+ concepts = JSON.parse(row.concepts_json) as Array<{
86
+ slug?: unknown;
87
+ source?: unknown;
88
+ }>;
89
+ } catch {
90
+ parseFailures += 1;
91
+ continue;
92
+ }
93
+ if (!Array.isArray(concepts)) continue;
94
+ for (const c of concepts) {
95
+ if (typeof c.slug !== "string") continue;
96
+ // Carry-over entries were not router-selected this turn — exclude.
97
+ if (c.source !== "router") continue;
98
+ buffer.push({ slug: c.slug, t: row.created_at });
99
+ }
100
+ }
101
+
102
+ if (buffer.length > 0) replay(buffer);
103
+ log.info(
104
+ { inserted: buffer.length, rowsScanned: rows.length, parseFailures },
105
+ `Backfilled ${buffer.length} injection events from ${rows.length} activation log rows`,
106
+ );
107
+ });
108
+ }
109
+
110
+ export function downMemoryV2InjectionEvents(database: DrizzleDb): void {
111
+ const raw = getSqliteFrom(database);
112
+ raw.exec(/*sql*/ `DROP TABLE IF EXISTS memory_v2_injection_events`);
113
+ }
@@ -0,0 +1,22 @@
1
+ import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
2
+
3
+ /**
4
+ * Strip `base_url` from provider connections whose provider is NOT
5
+ * `openai-compatible`. These values should never have been accepted — the
6
+ * route layer now rejects them, but existing rows may still carry one from
7
+ * before the validation was added. Setting it to NULL prevents
8
+ * API-key exfiltration via a redirected base URL.
9
+ *
10
+ * Idempotent — re-running is a no-op once all non-openai-compatible rows
11
+ * already have NULL base_url.
12
+ */
13
+ export function migrateStripBaseUrlNonOpenaiCompatible(
14
+ database: DrizzleDb,
15
+ ): void {
16
+ const raw = getSqliteFrom(database);
17
+
18
+ // Only clear base_url on rows where provider is NOT openai-compatible.
19
+ raw.exec(
20
+ `UPDATE provider_connections SET base_url = NULL WHERE provider != 'openai-compatible' AND base_url IS NOT NULL`,
21
+ );
22
+ }
@@ -0,0 +1,13 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+
3
+ export function migrateOnboardingEventsPriorAssistants(
4
+ database: DrizzleDb,
5
+ ): void {
6
+ try {
7
+ database.run(
8
+ /*sql*/ `ALTER TABLE onboarding_events ADD COLUMN prior_assistants_json TEXT`,
9
+ );
10
+ } catch {
11
+ /* already exists */
12
+ }
13
+ }
@@ -0,0 +1,33 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { tableHasColumn } from "./schema-introspection.js";
3
+ import { withCrashRecovery } from "./validate-migration-state.js";
4
+
5
+ const CHECKPOINT_KEY = "migration_conversation_cleaned_at_v1";
6
+
7
+ const COLUMN_NAME = "cleaned_at";
8
+ const COLUMN_DEFINITION = "cleaned_at INTEGER";
9
+
10
+ /**
11
+ * Add a `cleaned_at` timestamp to conversations.
12
+ *
13
+ * Records the moment `/clean` ran. The load path uses it to skip metadata
14
+ * reinjection (and strip injection prefixes from message content) for
15
+ * messages whose `created_at < cleaned_at`, so the clean survives daemon
16
+ * restart and conversation eviction. `forkConversation` copies the marker
17
+ * to the child only when the fork point is at-or-after the clean.
18
+ */
19
+ export function migrateConversationCleanedAt(database: DrizzleDb): void {
20
+ withCrashRecovery(database, CHECKPOINT_KEY, () => {
21
+ if (tableHasColumn(database, "conversations", COLUMN_NAME)) {
22
+ return;
23
+ }
24
+ database.run(`ALTER TABLE conversations ADD COLUMN ${COLUMN_DEFINITION}`);
25
+ });
26
+ }
27
+
28
+ export function downConversationCleanedAt(database: DrizzleDb): void {
29
+ if (!tableHasColumn(database, "conversations", COLUMN_NAME)) {
30
+ return;
31
+ }
32
+ database.run(`ALTER TABLE conversations DROP COLUMN ${COLUMN_NAME}`);
33
+ }
@@ -214,6 +214,26 @@ export {
214
214
  downNormalizeSlackExternalContent,
215
215
  migrateNormalizeSlackExternalContent,
216
216
  } from "./249-normalize-slack-external-content.js";
217
+ export { migrateProviderConnectionBaseUrlAndModels } from "./250-provider-connection-base-url-and-models.js";
218
+ export { downA2ATasks, migrateA2ATasks } from "./251-a2a-tasks.js";
219
+ export { migrateLlmRequestLogAgentLoopExitReason } from "./252-llm-request-log-agent-loop-exit-reason.js";
220
+ export { migrateConversationLastNotifiedProfile } from "./253-conversation-last-notified-profile.js";
221
+ export { migrateCreateDocumentComments } from "./253-document-comments.js";
222
+ export {
223
+ downExternalConversationBindingChatName,
224
+ migrateExternalConversationBindingChatName,
225
+ } from "./254-external-conversation-binding-chat-name.js";
226
+ export { migrateChannelInboundDeliveryAttempts } from "./255-channel-inbound-delivery-attempts.js";
227
+ export {
228
+ downMemoryV2InjectionEvents,
229
+ migrateMemoryV2InjectionEvents,
230
+ } from "./256-memory-v2-injection-events.js";
231
+ export { migrateStripBaseUrlNonOpenaiCompatible } from "./257-strip-base-url-non-openai-compatible.js";
232
+ export { migrateOnboardingEventsPriorAssistants } from "./258-onboarding-events-prior-assistants.js";
233
+ export {
234
+ downConversationCleanedAt,
235
+ migrateConversationCleanedAt,
236
+ } from "./259-conversation-cleaned-at.js";
217
237
  export {
218
238
  MIGRATION_REGISTRY,
219
239
  type MigrationRegistryEntry,
@@ -49,6 +49,10 @@ import { downSlackCompactionWatermark } from "./235-slack-compaction-watermark.j
49
49
  import { downToolInvocationsMatchedRuleId } from "./236-tool-invocations-matched-rule-id.js";
50
50
  import { downHeartbeatRuns } from "./237-heartbeat-runs.js";
51
51
  import { downNormalizeSlackExternalContent } from "./249-normalize-slack-external-content.js";
52
+ import { downA2ATasks } from "./251-a2a-tasks.js";
53
+ import { downExternalConversationBindingChatName } from "./254-external-conversation-binding-chat-name.js";
54
+ import { downMemoryV2InjectionEvents } from "./256-memory-v2-injection-events.js";
55
+ import { downConversationCleanedAt } from "./259-conversation-cleaned-at.js";
52
56
 
53
57
  export interface MigrationRegistryEntry {
54
58
  /** The checkpoint key written to memory_checkpoints on completion. */
@@ -420,6 +424,35 @@ export const MIGRATION_REGISTRY: MigrationRegistryEntry[] = [
420
424
  "Normalize legacy persisted Slack external_content wrappers back to raw message content",
421
425
  down: downNormalizeSlackExternalContent,
422
426
  },
427
+ {
428
+ key: "migration_a2a_tasks_v1",
429
+ version: 49,
430
+ description:
431
+ "Create a2a_tasks table for tracking A2A request/response lifecycle",
432
+ down: downA2ATasks,
433
+ },
434
+ {
435
+ key: "migration_external_conversation_binding_chat_name_v1",
436
+ version: 50,
437
+ description:
438
+ "Add external_chat_name to external conversation bindings for channel footer metadata",
439
+ down: downExternalConversationBindingChatName,
440
+ },
441
+ {
442
+ key: "migration_memory_v2_injection_events_v1",
443
+ version: 51,
444
+ dependsOn: ["migration_memory_v2_activation_logs_v1"],
445
+ description:
446
+ "Create memory_v2_injection_events table and backfill from activation logs for EMA-based tier 2 routing",
447
+ down: downMemoryV2InjectionEvents,
448
+ },
449
+ {
450
+ key: "migration_conversation_cleaned_at_v1",
451
+ version: 52,
452
+ description:
453
+ "Add cleaned_at timestamp to conversations so /clean survives reload and forks inherit conditionally on fork point",
454
+ down: downConversationCleanedAt,
455
+ },
423
456
  ];
424
457
 
425
458
  export function getMaxMigrationVersion(): number {
@@ -14,6 +14,7 @@ export interface OnboardingEvent {
14
14
  tone: string | null;
15
15
  googleConnected: boolean | null;
16
16
  googleScopesJson: string | null;
17
+ priorAssistantsJson: string | null;
17
18
  abVariant: string | null;
18
19
  }
19
20
 
@@ -24,6 +25,7 @@ export interface RecordOnboardingEventParams {
24
25
  tone?: string;
25
26
  googleConnected?: boolean;
26
27
  googleScopes?: string[];
28
+ priorAssistants?: string[];
27
29
  abVariant?: string;
28
30
  }
29
31
 
@@ -47,6 +49,9 @@ export function recordOnboardingEvent(
47
49
  googleScopesJson: params.googleScopes
48
50
  ? JSON.stringify(params.googleScopes)
49
51
  : null,
52
+ priorAssistantsJson: params.priorAssistants
53
+ ? JSON.stringify(params.priorAssistants)
54
+ : null,
50
55
  abVariant: params.abVariant ?? null,
51
56
  };
52
57
  db.insert(onboardingEvents)
@@ -59,6 +64,7 @@ export function recordOnboardingEvent(
59
64
  tone: event.tone,
60
65
  googleConnected: event.googleConnected,
61
66
  googleScopesJson: event.googleScopesJson,
67
+ priorAssistantsJson: event.priorAssistantsJson,
62
68
  abVariant: event.abVariant,
63
69
  })
64
70
  .run();
@@ -85,6 +91,7 @@ export function queryUnreportedOnboardingEvents(
85
91
  tone: onboardingEvents.tone,
86
92
  googleConnected: onboardingEvents.googleConnected,
87
93
  googleScopesJson: onboardingEvents.googleScopesJson,
94
+ priorAssistantsJson: onboardingEvents.priorAssistantsJson,
88
95
  abVariant: onboardingEvents.abVariant,
89
96
  })
90
97
  .from(onboardingEvents)
@@ -0,0 +1,15 @@
1
+ import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
2
+
3
+ export const a2aTasks = sqliteTable("a2a_tasks", {
4
+ id: text("id").primaryKey(),
5
+ contextId: text("context_id"),
6
+ conversationId: text("conversation_id"),
7
+ state: text("state").notNull().default("submitted"),
8
+ statusMessage: text("status_message"),
9
+ requestMessageJson: text("request_message_json").notNull(),
10
+ artifactsJson: text("artifacts_json"),
11
+ pushUrl: text("push_url"),
12
+ senderAssistantId: text("sender_assistant_id").notNull(),
13
+ createdAt: integer("created_at").notNull(),
14
+ updatedAt: integer("updated_at").notNull(),
15
+ });
@@ -78,6 +78,7 @@ export const externalConversationBindings = sqliteTable(
78
78
  .references(() => conversations.id, { onDelete: "cascade" }),
79
79
  sourceChannel: text("source_channel").notNull(),
80
80
  externalChatId: text("external_chat_id").notNull(),
81
+ externalChatName: text("external_chat_name"),
81
82
  externalThreadId: text("external_thread_id"),
82
83
  externalUserId: text("external_user_id"),
83
84
  displayName: text("display_name"),
@@ -21,6 +21,7 @@ export const conversations = sqliteTable(
21
21
  .notNull()
22
22
  .default(0),
23
23
  contextCompactedAt: integer("context_compacted_at"),
24
+ cleanedAt: integer("cleaned_at"),
24
25
  slackContextCompactionWatermarkTs: text(
25
26
  "slack_context_compaction_watermark_ts",
26
27
  ),
@@ -41,6 +42,7 @@ export const conversations = sqliteTable(
41
42
  inferenceProfile: text("inference_profile"),
42
43
  inferenceProfileSessionId: text("inference_profile_session_id"),
43
44
  inferenceProfileExpiresAt: integer("inference_profile_expires_at"),
45
+ lastNotifiedInferenceProfile: text("last_notified_inference_profile"),
44
46
  },
45
47
  (table) => [
46
48
  index("idx_conversations_updated_at").on(table.updatedAt),
@@ -150,6 +152,7 @@ export const channelInboundEvents = sqliteTable("channel_inbound_events", {
150
152
  deliveryStatus: text("delivery_status").notNull().default("pending"),
151
153
  processingStatus: text("processing_status").notNull().default("pending"),
152
154
  processingAttempts: integer("processing_attempts").notNull().default(0),
155
+ deliveryAttempts: integer("delivery_attempts").notNull().default(0),
153
156
  lastProcessingError: text("last_processing_error"),
154
157
  retryAfter: integer("retry_after"),
155
158
  rawPayload: text("raw_payload"),
@@ -1,3 +1,4 @@
1
+ export * from "./a2a.js";
1
2
  export * from "./acp.js";
2
3
  export * from "./bookmarks.js";
3
4
  export * from "./calls.js";
@@ -17,6 +17,8 @@ export const providerConnections = sqliteTable(
17
17
  auth: text("auth").notNull(),
18
18
  status: text("status").notNull().default("active"),
19
19
  label: text("label"),
20
+ baseUrl: text("base_url"),
21
+ models: text("models"),
20
22
  createdAt: integer("created_at").notNull(),
21
23
  updatedAt: integer("updated_at").notNull(),
22
24
  },
@@ -137,6 +137,7 @@ export const llmRequestLogs = sqliteTable(
137
137
  requestPayload: text("request_payload").notNull(),
138
138
  responsePayload: text("response_payload").notNull(),
139
139
  createdAt: integer("created_at").notNull(),
140
+ agentLoopExitReason: text("agent_loop_exit_reason"),
140
141
  },
141
142
  (table) => [
142
143
  index("idx_llm_request_logs_message_id").on(table.messageId),
@@ -241,6 +242,7 @@ export const onboardingEvents = sqliteTable("onboarding_events", {
241
242
  tone: text("tone"),
242
243
  googleConnected: integer("google_connected", { mode: "boolean" }),
243
244
  googleScopesJson: text("google_scopes_json"),
245
+ priorAssistantsJson: text("prior_assistants_json"),
244
246
  abVariant: text("ab_variant"),
245
247
  });
246
248