@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091926.ebb2d62

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 (490) hide show
  1. package/ARCHITECTURE.md +6 -6
  2. package/bun.lock +2 -2
  3. package/docs/activation-funnel-telemetry.md +310 -0
  4. package/examples/plugins/echo/README.md +61 -60
  5. package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
  6. package/examples/plugins/echo/hooks/stop.ts +16 -0
  7. package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
  8. package/examples/plugins/echo/package.json +1 -2
  9. package/examples/plugins/echo/src/emit.ts +19 -0
  10. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
  11. package/openapi.yaml +273 -121
  12. package/package.json +2 -2
  13. package/scripts/sync-llm-catalog.ts +2 -0
  14. package/src/__tests__/activation-early-marking.test.ts +120 -0
  15. package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
  16. package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
  17. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
  18. package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
  19. package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
  20. package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
  21. package/src/__tests__/agent-loop-thinking.test.ts +36 -20
  22. package/src/__tests__/agent-loop.test.ts +441 -96
  23. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
  24. package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
  25. package/src/__tests__/anthropic-provider.test.ts +23 -8
  26. package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
  27. package/src/__tests__/app-control-flow.test.ts +1 -1
  28. package/src/__tests__/app-dir-path-guard.test.ts +1 -0
  29. package/src/__tests__/app-executors.test.ts +132 -0
  30. package/src/__tests__/approval-cascade.test.ts +6 -5
  31. package/src/__tests__/approval-routes-http.test.ts +4 -1
  32. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  33. package/src/__tests__/build-persisted-content.test.ts +75 -1
  34. package/src/__tests__/channel-approval-routes.test.ts +1 -1
  35. package/src/__tests__/channel-approvals.test.ts +1 -1
  36. package/src/__tests__/compaction-circuit.test.ts +258 -0
  37. package/src/__tests__/compaction-direct.test.ts +146 -0
  38. package/src/__tests__/compaction-events.test.ts +7 -7
  39. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  40. package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
  41. package/src/__tests__/config-managed-gemini-defaults.test.ts +2 -46
  42. package/src/__tests__/context-overflow-reducer.test.ts +265 -125
  43. package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
  44. package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
  45. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
  46. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
  47. package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
  48. package/src/__tests__/conversation-agent-loop.test.ts +342 -623
  49. package/src/__tests__/conversation-clean-command.test.ts +5 -2
  50. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
  51. package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
  52. package/src/__tests__/conversation-error.test.ts +15 -1
  53. package/src/__tests__/conversation-history-web-search.test.ts +6 -1
  54. package/src/__tests__/conversation-media-retry.test.ts +1 -1
  55. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
  56. package/src/__tests__/conversation-process-callsite.test.ts +15 -15
  57. package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
  58. package/src/__tests__/conversation-queue.test.ts +10 -10
  59. package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
  60. package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
  61. package/src/__tests__/conversation-slash-queue.test.ts +7 -5
  62. package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
  63. package/src/__tests__/conversation-speed-override.test.ts +11 -10
  64. package/src/__tests__/conversation-starter-routes.test.ts +14 -6
  65. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
  66. package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
  67. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
  68. package/src/__tests__/conversation-undo.test.ts +2 -2
  69. package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
  70. package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
  71. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
  72. package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
  73. package/src/__tests__/corrected-target.test.ts +93 -0
  74. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -4
  75. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  76. package/src/__tests__/cu-unified-flow.test.ts +36 -0
  77. package/src/__tests__/db-acp-history.test.ts +101 -0
  78. package/src/__tests__/dynamic-page-surface.test.ts +31 -0
  79. package/src/__tests__/embedding-managed-proxy-selection.test.ts +6 -40
  80. package/src/__tests__/empty-response-hook.test.ts +1 -1
  81. package/src/__tests__/file-write-tool.test.ts +63 -0
  82. package/src/__tests__/gateway-only-guard.test.ts +17 -2
  83. package/src/__tests__/guardian-grant-minting.test.ts +1 -1
  84. package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
  85. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  87. package/src/__tests__/heartbeat-service.test.ts +1 -0
  88. package/src/__tests__/history-repair-hook.test.ts +5 -1
  89. package/src/__tests__/host-app-control-proxy.test.ts +45 -0
  90. package/src/__tests__/host-app-control-routes.test.ts +1 -1
  91. package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
  92. package/src/__tests__/inference-profile-reaper.test.ts +62 -0
  93. package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
  94. package/src/__tests__/injector-background-turn.test.ts +13 -23
  95. package/src/__tests__/injector-chain.test.ts +268 -44
  96. package/src/__tests__/injector-disk-pressure.test.ts +210 -52
  97. package/src/__tests__/injector-document-comments.test.ts +97 -114
  98. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  99. package/src/__tests__/injector-v3-suppression.test.ts +4 -4
  100. package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
  102. package/src/__tests__/llm-catalog-parity.test.ts +4 -0
  103. package/src/__tests__/llm-resolver.test.ts +73 -0
  104. package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
  105. package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
  106. package/src/__tests__/notification-decision-strategy.test.ts +3 -3
  107. package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
  108. package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
  109. package/src/__tests__/persist-unsendable-image.test.ts +97 -1
  110. package/src/__tests__/persistence-secret-redaction.test.ts +78 -0
  111. package/src/__tests__/plugin-api-shim.test.ts +6 -9
  112. package/src/__tests__/plugin-bootstrap.test.ts +91 -81
  113. package/src/__tests__/plugin-registry.test.ts +3 -49
  114. package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
  115. package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
  116. package/src/__tests__/plugin-types.test.ts +0 -70
  117. package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
  118. package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
  119. package/src/__tests__/published-app-updater.test.ts +138 -0
  120. package/src/__tests__/reaction-persistence.test.ts +1 -1
  121. package/src/__tests__/retry-thinking-adaptive-only.test.ts +245 -0
  122. package/src/__tests__/send-endpoint-busy.test.ts +4 -1
  123. package/src/__tests__/server-history-render.test.ts +39 -0
  124. package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
  125. package/src/__tests__/steer-tool-repair.test.ts +1 -1
  126. package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
  127. package/src/__tests__/subagent-detail.test.ts +25 -7
  128. package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
  129. package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
  130. package/src/__tests__/subagent-manager-notify.test.ts +1 -3
  131. package/src/__tests__/subagent-notify-parent.test.ts +1 -3
  132. package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
  133. package/src/__tests__/title-generate-hook.test.ts +5 -1
  134. package/src/__tests__/tool-error-hook.test.ts +1 -1
  135. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
  136. package/src/__tests__/tool-start-timestamp.test.ts +218 -0
  137. package/src/__tests__/user-plugin-loader.test.ts +54 -286
  138. package/src/__tests__/web-fetch.test.ts +45 -0
  139. package/src/acp/__tests__/agent-process.test.ts +161 -0
  140. package/src/acp/__tests__/client-handler.test.ts +40 -0
  141. package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
  142. package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
  143. package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
  144. package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
  145. package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
  146. package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
  147. package/src/acp/agent-process.ts +61 -1
  148. package/src/acp/auto-install.test.ts +280 -0
  149. package/src/acp/auto-install.ts +232 -0
  150. package/src/acp/client-handler.ts +31 -0
  151. package/src/acp/prepare-agent-env.ts +80 -27
  152. package/src/acp/resolve-agent.test.ts +188 -28
  153. package/src/acp/resolve-agent.ts +119 -42
  154. package/src/acp/resume-hint.ts +23 -0
  155. package/src/acp/session-manager.ts +507 -73
  156. package/src/agent/compaction-circuit.ts +60 -102
  157. package/src/agent/loop.ts +403 -251
  158. package/src/api/events/tool-result.ts +9 -0
  159. package/src/api/events/tool-use-start.ts +7 -0
  160. package/src/api/responses/conversation-message.ts +72 -13
  161. package/src/api/responses/memory-v3-selection-log.ts +19 -10
  162. package/src/approvals/guardian-request-resolvers.ts +27 -1
  163. package/src/background-wake/next-wake.ts +1 -0
  164. package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
  165. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  166. package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
  167. package/src/cli/commands/memory-v3.ts +57 -199
  168. package/src/cli/commands/plugins.ts +43 -37
  169. package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
  170. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
  171. package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
  172. package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
  173. package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
  174. package/src/cli/lib/install-from-github.ts +797 -60
  175. package/src/cli/lib/plugin-catalog-cache.ts +84 -0
  176. package/src/cli/lib/plugin-details.ts +416 -0
  177. package/src/cli/lib/plugin-marketplace.ts +215 -0
  178. package/src/cli/lib/search-plugins.ts +201 -29
  179. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  180. package/src/config/acp-defaults.test.ts +10 -0
  181. package/src/config/acp-defaults.ts +9 -3
  182. package/src/config/acp-schema.ts +1 -7
  183. package/src/config/bundled-skills/acp/SKILL.md +80 -41
  184. package/src/config/bundled-skills/acp/TOOLS.json +4 -4
  185. package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
  186. package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
  187. package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
  188. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
  189. package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
  190. package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
  191. package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
  192. package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
  193. package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
  194. package/src/config/bundled-tool-registry.ts +4 -0
  195. package/src/config/call-site-defaults.ts +0 -3
  196. package/src/config/feature-flag-registry.json +10 -56
  197. package/src/config/llm-resolver.ts +39 -7
  198. package/src/config/loader.ts +5 -22
  199. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
  200. package/src/config/schemas/call-site-catalog.ts +0 -21
  201. package/src/config/schemas/heartbeat.ts +9 -0
  202. package/src/config/schemas/llm.ts +17 -3
  203. package/src/config/schemas/memory-v3.ts +58 -8
  204. package/src/config/seed-inference-profiles.ts +18 -0
  205. package/src/context/compactor.ts +22 -4
  206. package/src/context/post-turn-tool-result-truncation.ts +39 -1
  207. package/src/context/strip-injections.ts +8 -2
  208. package/src/daemon/conversation-agent-loop-handlers.ts +120 -42
  209. package/src/daemon/conversation-agent-loop.ts +308 -1297
  210. package/src/daemon/conversation-error.ts +31 -4
  211. package/src/daemon/conversation-history.ts +1 -1
  212. package/src/daemon/conversation-lifecycle.ts +11 -255
  213. package/src/daemon/conversation-media-retry.ts +19 -6
  214. package/src/daemon/conversation-messaging.ts +17 -0
  215. package/src/daemon/conversation-process.ts +22 -141
  216. package/src/daemon/conversation-queue-manager.ts +8 -0
  217. package/src/daemon/conversation-registry.ts +159 -0
  218. package/src/daemon/conversation-runtime-assembly.ts +361 -393
  219. package/src/daemon/conversation-store.ts +9 -90
  220. package/src/daemon/conversation-surfaces.ts +165 -11
  221. package/src/daemon/conversation-workspace.ts +17 -0
  222. package/src/daemon/conversation.ts +444 -62
  223. package/src/daemon/disk-pressure-policy.ts +0 -1
  224. package/src/daemon/external-plugins-bootstrap.ts +36 -46
  225. package/src/daemon/handlers/config-channels.ts +11 -2
  226. package/src/daemon/handlers/conversations.ts +3 -1
  227. package/src/daemon/handlers/shared.ts +9 -1
  228. package/src/daemon/handlers/skills.ts +4 -1
  229. package/src/daemon/host-app-control-proxy.ts +72 -57
  230. package/src/daemon/host-proxy-preactivation.ts +1 -3
  231. package/src/daemon/lifecycle.ts +21 -7
  232. package/src/daemon/persist-unsendable-image.ts +62 -25
  233. package/src/daemon/process-message.ts +1 -1
  234. package/src/daemon/server.ts +2 -0
  235. package/src/daemon/tool-side-effects.ts +15 -0
  236. package/src/daemon/wake-conversation-ops.ts +269 -0
  237. package/src/embedded/plugin-api.ts +2 -2
  238. package/src/export/__tests__/transcript-formatter.test.ts +5 -0
  239. package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
  240. package/src/heartbeat/heartbeat-run-store.ts +23 -1
  241. package/src/heartbeat/heartbeat-service.ts +26 -0
  242. package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
  243. package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
  244. package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
  245. package/src/ipc/skill-routes/memory.ts +4 -2
  246. package/src/memory/__tests__/activation-session-store.test.ts +41 -0
  247. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
  248. package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
  249. package/src/memory/activation-session-store.ts +43 -0
  250. package/src/memory/conversation-crud.ts +29 -19
  251. package/src/memory/conversation-starter-checkpoints.ts +1 -0
  252. package/src/memory/db-init.ts +6 -0
  253. package/src/memory/embedding-backend.ts +5 -22
  254. package/src/memory/job-handlers/conversation-starters.ts +13 -2
  255. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
  256. package/src/memory/jobs-worker.ts +25 -1
  257. package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
  258. package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
  259. package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
  260. package/src/memory/migrations/index.ts +3 -0
  261. package/src/memory/onboarding-events-store.ts +66 -18
  262. package/src/memory/schema/acp.ts +4 -0
  263. package/src/memory/schema/infrastructure.ts +13 -0
  264. package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
  265. package/src/memory/v2/__tests__/page-store.test.ts +22 -0
  266. package/src/memory/v2/consolidation-job.ts +2 -63
  267. package/src/memory/v2/types.ts +5 -0
  268. package/src/messaging/providers/telegram-bot/api.ts +14 -5
  269. package/src/notifications/__tests__/copy-composer.test.ts +244 -0
  270. package/src/notifications/access-request-copy.ts +298 -0
  271. package/src/notifications/adapters/slack.ts +3 -3
  272. package/src/notifications/adapters/telegram.ts +9 -2
  273. package/src/notifications/copy-composer.ts +49 -267
  274. package/src/notifications/decision-engine.ts +16 -35
  275. package/src/notifications/home-feed-side-effect.ts +1 -6
  276. package/src/plugin-api/constants.ts +4 -0
  277. package/src/plugin-api/index.ts +40 -11
  278. package/src/plugin-api/types.ts +108 -0
  279. package/src/plugins/defaults/compaction/compact.ts +106 -0
  280. package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
  281. package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
  282. package/src/plugins/defaults/compaction/manager-store.ts +57 -0
  283. package/src/plugins/defaults/compaction/package.json +1 -2
  284. package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
  285. package/src/plugins/defaults/empty-response/package.json +0 -1
  286. package/src/plugins/defaults/history-repair/package.json +0 -1
  287. package/src/plugins/defaults/index.ts +156 -26
  288. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
  289. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
  290. package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
  291. package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
  292. package/src/plugins/defaults/memory-retrieval/package.json +14 -0
  293. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
  294. package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
  295. package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
  296. package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
  297. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
  298. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
  299. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
  300. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
  301. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
  302. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
  303. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
  304. package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
  305. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
  306. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
  307. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
  308. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
  309. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
  310. package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
  311. package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
  312. package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
  313. package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
  314. package/src/plugins/defaults/memory-v3-shadow/injector.ts +76 -0
  315. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
  316. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
  317. package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
  318. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
  319. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
  320. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
  321. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
  322. package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
  323. package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
  324. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
  325. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
  326. package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
  327. package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
  328. package/src/plugins/defaults/title-generate/package.json +0 -1
  329. package/src/plugins/defaults/tool-error/package.json +0 -1
  330. package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
  331. package/src/plugins/external-api.ts +12 -2
  332. package/src/plugins/pipeline.ts +6 -293
  333. package/src/plugins/registry.ts +9 -37
  334. package/src/plugins/types.ts +76 -381
  335. package/src/plugins/user-loader.ts +30 -127
  336. package/src/prompts/__tests__/system-prompt.test.ts +6 -0
  337. package/src/prompts/system-prompt.ts +61 -10
  338. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
  339. package/src/providers/anthropic/client.ts +9 -10
  340. package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
  341. package/src/providers/inference/logit-bias.ts +55 -0
  342. package/src/providers/model-catalog.ts +57 -0
  343. package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
  344. package/src/providers/openai/chat-completions-provider.ts +44 -1
  345. package/src/providers/retry.ts +57 -7
  346. package/src/providers/types.ts +6 -0
  347. package/src/runtime/__tests__/agent-wake.test.ts +555 -691
  348. package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
  349. package/src/runtime/agent-wake.ts +108 -209
  350. package/src/runtime/assistant-event-hub.ts +1 -1
  351. package/src/runtime/channel-approvals.ts +1 -1
  352. package/src/runtime/interactive-ui.ts +1 -1
  353. package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
  354. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
  355. package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
  356. package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
  357. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
  358. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
  359. package/src/runtime/routes/acp-routes.test.ts +185 -32
  360. package/src/runtime/routes/acp-routes.ts +328 -30
  361. package/src/runtime/routes/app-management-routes.ts +3 -0
  362. package/src/runtime/routes/approval-routes.ts +1 -1
  363. package/src/runtime/routes/browser-routes.ts +1 -1
  364. package/src/runtime/routes/browser-tabs-routes.ts +6 -10
  365. package/src/runtime/routes/channel-verification-routes.ts +14 -5
  366. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  367. package/src/runtime/routes/conversation-list-routes.ts +1 -1
  368. package/src/runtime/routes/conversation-query-routes.ts +1 -1
  369. package/src/runtime/routes/conversation-routes.ts +30 -2
  370. package/src/runtime/routes/conversation-starter-routes.ts +13 -7
  371. package/src/runtime/routes/conversations-import-routes.ts +24 -7
  372. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  373. package/src/runtime/routes/host-cu-routes.ts +1 -1
  374. package/src/runtime/routes/identity-routes.ts +18 -3
  375. package/src/runtime/routes/inbound-message-handler.ts +1 -1
  376. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
  377. package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
  378. package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
  379. package/src/runtime/routes/memory-v3-routes.ts +65 -305
  380. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
  381. package/src/runtime/routes/playground/helpers.ts +1 -1
  382. package/src/runtime/routes/plugins-routes.ts +337 -35
  383. package/src/runtime/routes/stt-routes.ts +45 -12
  384. package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
  385. package/src/runtime/routes/work-items-routes.ts +2 -4
  386. package/src/runtime/routes/workspace-routes.ts +50 -15
  387. package/src/runtime/services/conversation-serializer.ts +1 -1
  388. package/src/runtime/verification-outbound-actions.ts +147 -2
  389. package/src/runtime/verification-templates.ts +29 -3
  390. package/src/services/published-app-updater.ts +30 -8
  391. package/src/signals/cancel.ts +2 -4
  392. package/src/subagent/manager.ts +21 -5
  393. package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
  394. package/src/telemetry/activation-funnel.ts +167 -0
  395. package/src/telemetry/types.ts +13 -0
  396. package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
  397. package/src/telemetry/usage-telemetry-reporter.ts +26 -1
  398. package/src/tools/acp/context.ts +20 -0
  399. package/src/tools/acp/list-agents.test.ts +9 -19
  400. package/src/tools/acp/list-agents.ts +3 -15
  401. package/src/tools/acp/spawn.test.ts +173 -202
  402. package/src/tools/acp/spawn.ts +37 -172
  403. package/src/tools/acp/steer.test.ts +105 -8
  404. package/src/tools/acp/steer.ts +48 -17
  405. package/src/tools/apps/executors.ts +166 -50
  406. package/src/tools/browser/browser-execution.ts +12 -2
  407. package/src/tools/filesystem/write.ts +34 -0
  408. package/src/tools/network/web-fetch.ts +65 -24
  409. package/src/tools/skills/load.ts +1 -1
  410. package/src/tools/subagent/spawn.ts +2 -4
  411. package/src/tools/ui-surface/definitions.ts +32 -5
  412. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
  413. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
  414. package/docs/plugins.md +0 -832
  415. package/examples/plugins/echo/register.ts +0 -143
  416. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
  417. package/src/__tests__/compaction-pipeline.test.ts +0 -210
  418. package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
  419. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
  420. package/src/__tests__/pipeline-runner.test.ts +0 -554
  421. package/src/daemon/wake-target-adapter.ts +0 -253
  422. package/src/memory/v3/__tests__/assign.test.ts +0 -242
  423. package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
  424. package/src/memory/v3/__tests__/core.test.ts +0 -39
  425. package/src/memory/v3/__tests__/health.test.ts +0 -219
  426. package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
  427. package/src/memory/v3/__tests__/needle.test.ts +0 -107
  428. package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
  429. package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
  430. package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
  431. package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
  432. package/src/memory/v3/__tests__/router.test.ts +0 -332
  433. package/src/memory/v3/__tests__/selector.test.ts +0 -470
  434. package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
  435. package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
  436. package/src/memory/v3/__tests__/tree.test.ts +0 -192
  437. package/src/memory/v3/assign.ts +0 -268
  438. package/src/memory/v3/capabilities.ts +0 -124
  439. package/src/memory/v3/core.ts +0 -26
  440. package/src/memory/v3/health.ts +0 -0
  441. package/src/memory/v3/maintain-job.ts +0 -314
  442. package/src/memory/v3/needle.ts +0 -115
  443. package/src/memory/v3/orchestrate.ts +0 -126
  444. package/src/memory/v3/page-content.ts +0 -34
  445. package/src/memory/v3/provider-blocks.ts +0 -26
  446. package/src/memory/v3/reconcile.ts +0 -523
  447. package/src/memory/v3/router.ts +0 -190
  448. package/src/memory/v3/selection-log-store.ts +0 -84
  449. package/src/memory/v3/selector.ts +0 -226
  450. package/src/memory/v3/shadow-plugin.ts +0 -411
  451. package/src/memory/v3/snapshot.ts +0 -209
  452. package/src/memory/v3/tree.ts +0 -174
  453. package/src/memory/v3/types.ts +0 -59
  454. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
  455. package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
  456. package/src/plugins/defaults/circuit-breaker/package.json +0 -15
  457. package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
  458. package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
  459. package/src/plugins/defaults/compaction/register.ts +0 -35
  460. package/src/plugins/defaults/compaction/terminal.ts +0 -73
  461. package/src/plugins/defaults/empty-response/register.ts +0 -23
  462. package/src/plugins/defaults/history-repair/register.ts +0 -24
  463. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
  464. package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
  465. package/src/plugins/defaults/overflow-reduce/package.json +0 -15
  466. package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
  467. package/src/plugins/defaults/title-generate/register.ts +0 -35
  468. package/src/plugins/defaults/tool-error/register.ts +0 -23
  469. package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
  470. package/src/proactive-artifact/aux-message-injector.ts +0 -97
  471. package/src/proactive-artifact/decision.test.ts +0 -226
  472. package/src/proactive-artifact/decision.ts +0 -165
  473. package/src/proactive-artifact/index.ts +0 -7
  474. package/src/proactive-artifact/job.test.ts +0 -962
  475. package/src/proactive-artifact/job.ts +0 -372
  476. package/src/proactive-artifact/message-copy.ts +0 -58
  477. package/src/proactive-artifact/trigger-state.test.ts +0 -286
  478. package/src/proactive-artifact/trigger-state.ts +0 -123
  479. package/src/util/map-limit.ts +0 -27
  480. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
  481. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
  482. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
  483. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
  484. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
  485. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
  486. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
  487. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
  488. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
  489. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
  490. /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
@@ -0,0 +1,80 @@
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ // Silence the logger.
4
+ mock.module("../../util/logger.js", () => ({
5
+ getLogger: () =>
6
+ new Proxy({} as Record<string, unknown>, {
7
+ get: () => () => {},
8
+ }),
9
+ }));
10
+
11
+ // Mutable usage-data gate, flipped per-test.
12
+ let collectUsageData = true;
13
+ mock.module("../../config/loader.js", () => ({
14
+ getConfig: () => ({ collectUsageData }),
15
+ }));
16
+
17
+ import { getDb } from "../db-connection.js";
18
+ import { initializeDb } from "../db-init.js";
19
+ import {
20
+ queryUnreportedOnboardingEvents,
21
+ recordActivationEvent,
22
+ } from "../onboarding-events-store.js";
23
+ import { onboardingEvents } from "../schema.js";
24
+
25
+ initializeDb();
26
+
27
+ function resetTable(): void {
28
+ getDb().delete(onboardingEvents).run();
29
+ }
30
+
31
+ describe("onboarding-events-store: recordActivationEvent", () => {
32
+ beforeEach(() => {
33
+ collectUsageData = true;
34
+ resetTable();
35
+ });
36
+
37
+ test("persists an activation funnel event that round-trips through the query", () => {
38
+ const event = recordActivationEvent({
39
+ stepName: "activation_moment_1_complete",
40
+ sessionId: "conv-1",
41
+ });
42
+ expect(event).not.toBeNull();
43
+
44
+ const rows = queryUnreportedOnboardingEvents(0, undefined, 10);
45
+ expect(rows).toHaveLength(1);
46
+ const row = rows[0]!;
47
+ expect(row.stepName).toBe("activation_moment_1_complete");
48
+ expect(row.stepIndex).toBe(1);
49
+ expect(row.funnelVersion).toBe("activation_v1_2026_06");
50
+ expect(row.screen).toBe("activation_moment_1_complete");
51
+ expect(row.abVariant).toBe("variant-a");
52
+ expect(row.sessionId).toBe("conv-1");
53
+ expect(row.completedAt).toBe(new Date(row.createdAt).toISOString());
54
+ });
55
+
56
+ test("honors an explicit abVariant override", () => {
57
+ recordActivationEvent({
58
+ stepName: "activation_moment_2_complete",
59
+ sessionId: "conv-2",
60
+ abVariant: "variant-b",
61
+ });
62
+
63
+ const rows = queryUnreportedOnboardingEvents(0, undefined, 10);
64
+ expect(rows).toHaveLength(1);
65
+ expect(rows[0]!.abVariant).toBe("variant-b");
66
+ expect(rows[0]!.stepIndex).toBe(2);
67
+ });
68
+
69
+ test("returns null and writes no row when collectUsageData is disabled", () => {
70
+ collectUsageData = false;
71
+ const event = recordActivationEvent({
72
+ stepName: "activation_moment_1_complete",
73
+ sessionId: "conv-3",
74
+ });
75
+ expect(event).toBeNull();
76
+
77
+ const rows = queryUnreportedOnboardingEvents(0, undefined, 10);
78
+ expect(rows).toHaveLength(0);
79
+ });
80
+ });
@@ -0,0 +1,43 @@
1
+ import { eq } from "drizzle-orm";
2
+
3
+ import { getLogger } from "../util/logger.js";
4
+ import { getDb } from "./db-connection.js";
5
+ import { activationSessions } from "./schema.js";
6
+
7
+ const log = getLogger("activation-session-store");
8
+
9
+ /**
10
+ * Mark a conversation as an activation-rail session. Idempotent (the row's
11
+ * primary key is the conversation id) and best-effort: a write failure is
12
+ * logged and swallowed so it never blocks the turn that triggered it.
13
+ */
14
+ export function markActivationSession(conversationId: string): void {
15
+ try {
16
+ getDb()
17
+ .insert(activationSessions)
18
+ .values({ conversationId, createdAt: Date.now() })
19
+ .onConflictDoNothing()
20
+ .run();
21
+ } catch (err) {
22
+ log.warn({ err, conversationId }, "Failed to mark activation session");
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Whether the given conversation was started on the activation rail. Best-effort:
28
+ * a read failure is logged and treated as "not an activation session".
29
+ */
30
+ export function isActivationSession(conversationId: string): boolean {
31
+ try {
32
+ const row = getDb()
33
+ .select({ conversationId: activationSessions.conversationId })
34
+ .from(activationSessions)
35
+ .where(eq(activationSessions.conversationId, conversationId))
36
+ .limit(1)
37
+ .get();
38
+ return row !== undefined;
39
+ } catch (err) {
40
+ log.warn({ err, conversationId }, "Failed to read activation session");
41
+ return false;
42
+ }
43
+ }
@@ -277,6 +277,7 @@ export interface MessageRow {
277
277
  content: string;
278
278
  createdAt: number;
279
279
  metadata: string | null;
280
+ clientMessageId: string | null;
280
281
  }
281
282
 
282
283
  const parseMessage = createRowMapper<typeof messages.$inferSelect, MessageRow>({
@@ -286,6 +287,7 @@ const parseMessage = createRowMapper<typeof messages.$inferSelect, MessageRow>({
286
287
  content: "content",
287
288
  createdAt: "createdAt",
288
289
  metadata: "metadata",
290
+ clientMessageId: "clientMessageId",
289
291
  });
290
292
 
291
293
  export type ConversationCreateType = "standard" | "background" | "scheduled";
@@ -1903,21 +1905,30 @@ export function listActiveInferenceProfileSessions(
1903
1905
  }
1904
1906
 
1905
1907
  /**
1906
- * Resolve the per-turn inference-profile override from an already-loaded
1907
- * conversation row. Returns the row's `inferenceProfile` for interactive
1908
- * conversations, `undefined` for automation threads (subagent fan-out,
1909
- * scheduled tasks, update bulletins) so they run on the workspace defaults
1910
- * rather than inheriting an interactive override.
1911
- *
1912
- * Prefer this row-based form when the caller already needs to read the
1913
- * conversation row for other reasons (e.g. the agent loop's title check).
1908
+ * The conversation fields needed to resolve a per-turn inference-profile
1909
+ * override. Satisfied by both the DB {@link ConversationRow} and the live
1910
+ * in-memory `Conversation`, so callers can derive the override from whichever
1911
+ * representation they already hold without a redundant row fetch.
1912
+ */
1913
+ export interface OverrideProfileFields {
1914
+ conversationType?: string | null;
1915
+ inferenceProfile?: string | null;
1916
+ inferenceProfileExpiresAt?: number | null;
1917
+ }
1918
+
1919
+ /**
1920
+ * Resolve the per-turn inference-profile override from a conversation's
1921
+ * fields. Returns the `inferenceProfile` for interactive conversations,
1922
+ * `undefined` for automation threads (subagent fan-out, scheduled tasks,
1923
+ * update bulletins) so they run on the workspace defaults rather than
1924
+ * inheriting an interactive override.
1914
1925
  */
1915
- export function getConversationOverrideProfileFromRow(
1916
- conv: ConversationRow | null,
1926
+ export function resolveOverrideProfile(
1927
+ fields: OverrideProfileFields | null,
1917
1928
  ): string | undefined {
1918
1929
  if (
1919
- conv?.conversationType === "background" ||
1920
- conv?.conversationType === "scheduled"
1930
+ fields?.conversationType === "background" ||
1931
+ fields?.conversationType === "scheduled"
1921
1932
  ) {
1922
1933
  return undefined;
1923
1934
  }
@@ -1931,24 +1942,23 @@ export function getConversationOverrideProfileFromRow(
1931
1942
  // Without this, a session at the exact-expiry millisecond would be served
1932
1943
  // for one extra turn here while being cleared by the reaper.
1933
1944
  if (
1934
- conv?.inferenceProfileExpiresAt != null &&
1935
- conv.inferenceProfileExpiresAt <= Date.now()
1945
+ fields?.inferenceProfileExpiresAt != null &&
1946
+ fields.inferenceProfileExpiresAt <= Date.now()
1936
1947
  ) {
1937
1948
  return undefined;
1938
1949
  }
1939
- return conv?.inferenceProfile ?? undefined;
1950
+ return fields?.inferenceProfile ?? undefined;
1940
1951
  }
1941
1952
 
1942
1953
  /**
1943
1954
  * Resolve the per-turn inference-profile override by conversation id.
1944
- * Convenience wrapper around `getConversationOverrideProfileFromRow` for
1945
- * standalone callers (e.g. subagent spawn, opportunity-wake) that don't
1946
- * already have the row in hand.
1955
+ * Convenience wrapper for standalone callers (e.g. subagent spawn,
1956
+ * opportunity-wake) that don't already have the conversation in hand.
1947
1957
  */
1948
1958
  export function getConversationOverrideProfile(
1949
1959
  conversationId: string,
1950
1960
  ): string | undefined {
1951
- return getConversationOverrideProfileFromRow(getConversation(conversationId));
1961
+ return resolveOverrideProfile(getConversation(conversationId));
1952
1962
  }
1953
1963
 
1954
1964
  export function setLastNotifiedInferenceProfile(
@@ -15,6 +15,7 @@ import { memoryCheckpoints } from "./schema.js";
15
15
  export const CK_ITEM_COUNT = "conversation_starters:item_count_at_last_gen";
16
16
  export const CK_BATCH = "conversation_starters:generation_batch";
17
17
  export const CK_LAST_GEN_AT = "conversation_starters:last_gen_at";
18
+ export const CK_LAST_ATTEMPT_AT = "conversation_starters:last_attempt_at";
18
19
 
19
20
  export function checkpointKey(base: string, scopeId: string): string {
20
21
  return `${base}:${scopeId}`;
@@ -16,6 +16,7 @@ import { getDb, getSqlite } from "./db-connection.js";
16
16
  import { migrateToolCreatedItems } from "./graph/bootstrap.js";
17
17
  import {
18
18
  addCoreColumns,
19
+ createActivationSessionsTable,
19
20
  createApprovalPromptTsTrackerTable,
20
21
  createAssistantInboxTables,
21
22
  createAuthFallbackEventsTable,
@@ -41,6 +42,7 @@ import {
41
42
  migrate230AcpSessionHistory,
42
43
  migrate231RepairMemoryGraphEventDates,
43
44
  migrateA2ATasks,
45
+ migrateAcpSessionHistoryCwd,
44
46
  migrateActivationState,
45
47
  migrateActivationStateFkCascade,
46
48
  migrateAddConversationInferenceProfile,
@@ -160,6 +162,7 @@ import {
160
162
  migrateOAuthProvidersScopeSeparator,
161
163
  migrateOAuthProvidersTokenAuthMethodDefault,
162
164
  migrateOAuthProvidersTokenExchangeBodyFormat,
165
+ migrateOnboardingEventsFunnelColumns,
163
166
  migrateOnboardingEventsPriorAssistants,
164
167
  migrateProviderConnectionBaseUrlAndModels,
165
168
  migrateProviderConnectionStatusLabel,
@@ -478,6 +481,9 @@ export function initializeDb(): void {
478
481
  migrateScheduleSourceConversation,
479
482
  migrateMessagesRoleCreatedAtIndex,
480
483
  createAuthFallbackEventsTable,
484
+ migrateAcpSessionHistoryCwd,
485
+ migrateOnboardingEventsFunnelColumns,
486
+ createActivationSessionsTable,
481
487
  ];
482
488
 
483
489
  // Run each migration step, catching and logging individual failures so one
@@ -1,6 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
2
 
3
- import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
4
3
  import { getOllamaBaseUrlEnv } from "../config/env.js";
5
4
  import { resolveCallSiteConfig } from "../config/llm-resolver.js";
6
5
  import type { AssistantConfig } from "../config/types.js";
@@ -302,13 +301,10 @@ export async function selectEmbeddingBackend(
302
301
  };
303
302
  }
304
303
 
305
- // When the managed-gemini-embeddings-enabled flag is on AND managed proxy
306
- // prerequisites are satisfied, insert managed-proxy Gemini at the front of
307
- // the auto chain so platform assistants use Vellum-managed Gemini embeddings.
308
- if (
309
- (requested === "auto" || requested === "gemini") &&
310
- isAssistantFeatureFlagEnabled("managed-gemini-embeddings-enabled", config)
311
- ) {
304
+ // When managed proxy prerequisites are satisfied, insert managed-proxy Gemini
305
+ // at the front of the auto chain so platform assistants use Vellum-managed
306
+ // Gemini embeddings.
307
+ if (requested === "auto" || requested === "gemini") {
312
308
  const proxyCtx = await resolveManagedProxyContext();
313
309
  if (proxyCtx.enabled) {
314
310
  const meta = PLATFORM_PROVIDER_META["gemini"];
@@ -677,12 +673,7 @@ async function selectFallbackBackends(
677
673
  geminiCacheExtras(config),
678
674
  ),
679
675
  );
680
- } else if (
681
- isAssistantFeatureFlagEnabled(
682
- "managed-gemini-embeddings-enabled",
683
- config,
684
- )
685
- ) {
676
+ } else {
686
677
  // Try managed proxy Gemini as fallback when no direct key exists.
687
678
  const proxyCtx = await resolveManagedProxyContext();
688
679
  const meta = PLATFORM_PROVIDER_META["gemini"];
@@ -724,14 +715,6 @@ async function selectFallbackBackends(
724
715
  );
725
716
  if (cached) backends.push(cached);
726
717
  }
727
- } else {
728
- // Preserve cached backend on transient credential-store failures.
729
- const cached = getCached(
730
- "gemini",
731
- config.memory.embeddings.geminiModel,
732
- geminiCacheExtras(config),
733
- );
734
- if (cached) backends.push(cached);
735
718
  }
736
719
  break;
737
720
  }
@@ -22,6 +22,7 @@ import {
22
22
  checkpointKey,
23
23
  CK_BATCH,
24
24
  CK_ITEM_COUNT,
25
+ CK_LAST_ATTEMPT_AT,
25
26
  CK_LAST_GEN_AT,
26
27
  countActiveMemoryNodes,
27
28
  getCheckpointValue,
@@ -336,6 +337,7 @@ Bad → Good (incomplete phrase → complete):
336
337
  config: {
337
338
  callSite: "conversationStarters" as const,
338
339
  max_tokens: 2048,
340
+ temperature: 0.7,
339
341
  tool_choice: {
340
342
  type: "tool" as const,
341
343
  name: "store_conversation_starters",
@@ -395,18 +397,27 @@ export async function generateConversationStartersJob(
395
397
  const db = getDb();
396
398
  const now = Date.now();
397
399
 
400
+ // Record attempt time so the route handler's cooldown prevents rapid retries
401
+ // even when generation produces 0 valid starters.
402
+ upsertCheckpoint(
403
+ checkpointKey(CK_LAST_ATTEMPT_AT, scopeId),
404
+ String(now),
405
+ now,
406
+ );
407
+
398
408
  const starters = await generateStarters(scopeId);
399
409
  if (starters.length === 0) {
400
410
  log.info({ scopeId }, "No conversation starters generated");
401
411
 
402
- // Sync checkpoints so both `staleByAge` and `checkpointAhead` clear.
412
+ // Sync the item count checkpoint so `checkpointAhead` clears, but do NOT
413
+ // update `CK_LAST_GEN_AT` — the stale TTL should trigger a retry on the
414
+ // next GET rather than blocking retries for the full TTL window.
403
415
  const totalActive = countActiveMemoryNodes(scopeId);
404
416
  upsertCheckpoint(
405
417
  checkpointKey(CK_ITEM_COUNT, scopeId),
406
418
  String(totalActive),
407
419
  now,
408
420
  );
409
- upsertCheckpoint(checkpointKey(CK_LAST_GEN_AT, scopeId), String(now), now);
410
421
  return;
411
422
  }
412
423
 
@@ -143,9 +143,8 @@ afterAll(() => {
143
143
  // `getWorkspaceDir()` resolves to the tmpdir.
144
144
  const { DEFAULT_CONFIG } = await import("../../../config/defaults.js");
145
145
  const { getDb } = await import("../../db-connection.js");
146
- const { resetDbForTesting } = await import(
147
- "../../../__tests__/db-test-helpers.js"
148
- );
146
+ const { resetDbForTesting } =
147
+ await import("../../../__tests__/db-test-helpers.js");
149
148
  const { initializeDb } = await import("../../db-init.js");
150
149
  const { memoryEmbeddings, memoryJobs } = await import("../../schema.js");
151
150
  const { claimMemoryJobs } = await import("../../jobs-store.js");
@@ -187,12 +186,14 @@ function makeJob(payload: Record<string, unknown>): MemoryJob {
187
186
 
188
187
  beforeEach(() => {
189
188
  resetDbForTesting();
189
+ // The first run pays the full cold-start migration chain; bump the hook
190
+ // timeout above bun's 5s default so the leading test doesn't flake in CI.
190
191
  initializeDb();
191
192
  embedWithBackendCalls.length = 0;
192
193
  upsertCalls.length = 0;
193
194
  deleteCalls.length = 0;
194
195
  _resetQdrantBreaker();
195
- });
196
+ }, 30_000);
196
197
 
197
198
  afterEach(() => {
198
199
  // Clean up any pages written between tests so each scenario starts fresh.
@@ -8,6 +8,7 @@ import {
8
8
  diskPressureBackgroundSkipLogFields,
9
9
  shouldLogDiskPressureBackgroundSkip,
10
10
  } from "../daemon/disk-pressure-background-gate.js";
11
+ import { maintainJob as memoryV3MaintainJob } from "../plugins/defaults/memory-v3-shadow/maintain-job.js";
11
12
  import { getLogger } from "../util/logger.js";
12
13
  import { getWorkspaceDir } from "../util/platform.js";
13
14
  import { getMemoryCheckpoint, setMemoryCheckpoint } from "./checkpoints.js";
@@ -87,7 +88,6 @@ import {
87
88
  memoryV2ConsolidateJob,
88
89
  } from "./v2/consolidation-job.js";
89
90
  import { memoryV2SweepJob } from "./v2/sweep-job.js";
90
- import { maintainJob as memoryV3MaintainJob } from "./v3/maintain-job.js";
91
91
 
92
92
  const log = getLogger("memory-jobs-worker");
93
93
 
@@ -95,6 +95,16 @@ const AUTOMATIC_CONSOLIDATION_JOB_PAYLOAD = {
95
95
  trigger: MEMORY_V2_CONSOLIDATION_JOB_TRIGGERS.automatic,
96
96
  } as const;
97
97
 
98
+ /**
99
+ * Minimum buffer entries required for a scheduled consolidation run. The
100
+ * time-based schedule noops when `memory/buffer.md` has fewer non-empty lines
101
+ * than this threshold — the LLM cost of a full consolidation pass outweighs
102
+ * the benefit when the buffer is nearly empty. Mirrors the heartbeat
103
+ * max-consecutive-runs skip pattern. Manual "Run now" and the size-based
104
+ * trigger are not affected.
105
+ */
106
+ export const MIN_BUFFER_LINES_FOR_CONSOLIDATION = 10;
107
+
98
108
  /**
99
109
  * V1 job types that read or write the v1 Qdrant collection via
100
110
  * `getQdrantClient()`. When `memory.v2.enabled` is true, the v1 client is
@@ -815,6 +825,20 @@ export function maybeEnqueueGraphMaintenanceJobs(
815
825
  for (const { key, intervalMs, jobType } of schedule) {
816
826
  const lastRun = parseInt(getMemoryCheckpoint(key) ?? "0", 10);
817
827
  if (nowMs - lastRun >= intervalMs) {
828
+ // Noop scheduled consolidation when the buffer has too few entries to
829
+ // justify an LLM run — mirrors the heartbeat max-consecutive-runs skip.
830
+ // The checkpoint advances so the next check fires after the regular
831
+ // interval. Manual "Run now" is unaffected (routes layer, not schedule).
832
+ if (jobType === consolidateEntry.jobType) {
833
+ const bufferPath = join(getWorkspaceDir(), "memory", "buffer.md");
834
+ if (countBufferLines(bufferPath) < MIN_BUFFER_LINES_FOR_CONSOLIDATION) {
835
+ log.debug(
836
+ "Scheduled consolidation skipped: buffer under minimum line threshold",
837
+ );
838
+ setMemoryCheckpoint(key, String(nowMs));
839
+ continue;
840
+ }
841
+ }
818
842
  const payload =
819
843
  jobType === consolidateEntry.jobType
820
844
  ? AUTOMATIC_CONSOLIDATION_JOB_PAYLOAD
@@ -0,0 +1,36 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { getSqliteFrom } from "../db-connection.js";
3
+ import { withCrashRecovery } from "./validate-migration-state.js";
4
+
5
+ const CHECKPOINT_KEY = "migration_acp_session_history_cwd_v1";
6
+
7
+ const TABLE = "acp_session_history";
8
+ const COLUMN = "cwd";
9
+
10
+ /**
11
+ * Add a nullable `cwd TEXT` column to `acp_session_history`.
12
+ *
13
+ * Records the working directory the ACP agent process was spawned with so
14
+ * that a persisted session can later be resumed (`session/load` /
15
+ * `session/resume` both require the original cwd to reconstruct params).
16
+ *
17
+ * `NULL` for rows persisted before this migration ran — legacy sessions
18
+ * simply are not resumable.
19
+ *
20
+ * Idempotent — the PRAGMA guard makes re-running a no-op once the column
21
+ * exists.
22
+ */
23
+ export function migrateAcpSessionHistoryCwd(database: DrizzleDb): void {
24
+ withCrashRecovery(database, CHECKPOINT_KEY, () => {
25
+ const raw = getSqliteFrom(database);
26
+
27
+ const columns = raw.query(`PRAGMA table_info(${TABLE})`).all() as Array<{
28
+ name: string;
29
+ }>;
30
+ const columnNames = new Set(columns.map((c) => c.name));
31
+
32
+ if (!columnNames.has(COLUMN)) {
33
+ raw.exec(`ALTER TABLE ${TABLE} ADD COLUMN ${COLUMN} TEXT`);
34
+ }
35
+ });
36
+ }
@@ -0,0 +1,46 @@
1
+ import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
2
+
3
+ const TABLE = "onboarding_events";
4
+ const COLUMNS: Array<{ name: string; type: string }> = [
5
+ { name: "session_id", type: "TEXT" },
6
+ { name: "step_name", type: "TEXT" },
7
+ { name: "step_index", type: "INTEGER" },
8
+ { name: "completed_at", type: "TEXT" },
9
+ { name: "funnel_version", type: "TEXT" },
10
+ ];
11
+
12
+ /**
13
+ * Add nullable funnel-tracking columns to `onboarding_events`.
14
+ *
15
+ * The original table (#30733) recorded one row per onboarding screen but had
16
+ * no way to stitch those rows into an ordered, per-attempt funnel: there was
17
+ * no session correlator, no step ordering, and no completion timestamp. These
18
+ * columns let the activation-funnel reporting attribute each event to a single
19
+ * onboarding attempt (`session_id`), order steps within it (`step_name` /
20
+ * `step_index`), record when a step finished (`completed_at`), and version the
21
+ * funnel shape so changes to the step set don't silently corrupt historical
22
+ * conversion math (`funnel_version`).
23
+ *
24
+ * All columns are nullable — `NULL` for rows persisted before this migration
25
+ * ran.
26
+ *
27
+ * Idempotent — re-running is a no-op once the columns exist. Pure DDL with a
28
+ * PRAGMA guard, no registry entry needed (matches the 252 / 261 / 264 / 265 /
29
+ * 267 pattern).
30
+ */
31
+ export function migrateOnboardingEventsFunnelColumns(
32
+ database: DrizzleDb,
33
+ ): void {
34
+ const raw = getSqliteFrom(database);
35
+
36
+ const columns = raw.query(`PRAGMA table_info(${TABLE})`).all() as Array<{
37
+ name: string;
38
+ }>;
39
+ const columnNames = new Set(columns.map((c) => c.name));
40
+
41
+ for (const { name, type } of COLUMNS) {
42
+ if (!columnNames.has(name)) {
43
+ raw.exec(`ALTER TABLE ${TABLE} ADD COLUMN ${name} ${type}`);
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,15 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+
3
+ /**
4
+ * Create the activation_sessions table. One row per conversation that was
5
+ * started on the activation-rail bootstrap template, used by the activation
6
+ * funnel telemetry to scope events to activation conversations.
7
+ */
8
+ export function createActivationSessionsTable(database: DrizzleDb): void {
9
+ database.run(/*sql*/ `
10
+ CREATE TABLE IF NOT EXISTS activation_sessions (
11
+ conversation_id TEXT PRIMARY KEY,
12
+ created_at INTEGER NOT NULL
13
+ )
14
+ `);
15
+ }
@@ -259,6 +259,9 @@ export { migrateScheduleScriptTimeout } from "./269-schedule-script-timeout.js";
259
259
  export { migrateMessagesRoleCreatedAtIndex } from "./270-messages-role-created-at-index.js";
260
260
  export { migrateScheduleSourceConversation } from "./270-schedule-source-conversation.js";
261
261
  export { createAuthFallbackEventsTable } from "./271-create-auth-fallback-events.js";
262
+ export { migrateAcpSessionHistoryCwd } from "./272-acp-session-history-cwd.js";
263
+ export { migrateOnboardingEventsFunnelColumns } from "./273-onboarding-events-funnel-columns.js";
264
+ export { createActivationSessionsTable } from "./274-create-activation-sessions.js";
262
265
  export {
263
266
  MIGRATION_REGISTRY,
264
267
  type MigrationRegistryEntry,
@@ -2,6 +2,12 @@ import { and, asc, eq, gt, or } from "drizzle-orm";
2
2
  import { v4 as uuid } from "uuid";
3
3
 
4
4
  import { getConfig } from "../config/loader.js";
5
+ import {
6
+ ACTIVATION_AB_VARIANT,
7
+ ACTIVATION_FUNNEL_VERSION,
8
+ activationStepIndex,
9
+ type ActivationStepName,
10
+ } from "../telemetry/activation-funnel.js";
5
11
  import { getDb } from "./db-connection.js";
6
12
  import { onboardingEvents } from "./schema.js";
7
13
 
@@ -16,6 +22,11 @@ export interface OnboardingEvent {
16
22
  googleScopesJson: string | null;
17
23
  priorAssistantsJson: string | null;
18
24
  abVariant: string | null;
25
+ sessionId: string | null;
26
+ stepName: string | null;
27
+ stepIndex: number | null;
28
+ completedAt: string | null;
29
+ funnelVersion: string | null;
19
30
  }
20
31
 
21
32
  export interface RecordOnboardingEventParams {
@@ -27,6 +38,17 @@ export interface RecordOnboardingEventParams {
27
38
  googleScopes?: string[];
28
39
  priorAssistants?: string[];
29
40
  abVariant?: string;
41
+ sessionId?: string | null;
42
+ stepName?: string | null;
43
+ stepIndex?: number | null;
44
+ completedAt?: string | null;
45
+ funnelVersion?: string | null;
46
+ }
47
+
48
+ /** Insert a fully-built event row. Shared by all record* entry points. */
49
+ function insertOnboardingEvent(event: OnboardingEvent): OnboardingEvent {
50
+ getDb().insert(onboardingEvents).values(event).run();
51
+ return event;
30
52
  }
31
53
 
32
54
  /**
@@ -37,8 +59,7 @@ export function recordOnboardingEvent(
37
59
  params: RecordOnboardingEventParams,
38
60
  ): OnboardingEvent | null {
39
61
  if (!getConfig().collectUsageData) return null;
40
- const db = getDb();
41
- const event: OnboardingEvent = {
62
+ return insertOnboardingEvent({
42
63
  id: uuid(),
43
64
  createdAt: Date.now(),
44
65
  screen: params.screen,
@@ -53,22 +74,44 @@ export function recordOnboardingEvent(
53
74
  ? JSON.stringify(params.priorAssistants)
54
75
  : null,
55
76
  abVariant: params.abVariant ?? null,
56
- };
57
- db.insert(onboardingEvents)
58
- .values({
59
- id: event.id,
60
- createdAt: event.createdAt,
61
- screen: event.screen,
62
- toolsJson: event.toolsJson,
63
- tasksJson: event.tasksJson,
64
- tone: event.tone,
65
- googleConnected: event.googleConnected,
66
- googleScopesJson: event.googleScopesJson,
67
- priorAssistantsJson: event.priorAssistantsJson,
68
- abVariant: event.abVariant,
69
- })
70
- .run();
71
- return event;
77
+ sessionId: params.sessionId ?? null,
78
+ stepName: params.stepName ?? null,
79
+ stepIndex: params.stepIndex ?? null,
80
+ completedAt: params.completedAt ?? null,
81
+ funnelVersion: params.funnelVersion ?? null,
82
+ });
83
+ }
84
+
85
+ /**
86
+ * Record an activation-funnel milestone event. Reuses the onboarding telemetry
87
+ * substrate (`screen` carries the step name to satisfy the NOT NULL column).
88
+ * Returns null when usage data collection is disabled.
89
+ */
90
+ export function recordActivationEvent(params: {
91
+ stepName: ActivationStepName;
92
+ sessionId: string;
93
+ userId?: string | null;
94
+ abVariant?: string;
95
+ }): OnboardingEvent | null {
96
+ if (!getConfig().collectUsageData) return null;
97
+ const createdAt = Date.now();
98
+ return insertOnboardingEvent({
99
+ id: uuid(),
100
+ createdAt,
101
+ screen: params.stepName,
102
+ toolsJson: null,
103
+ tasksJson: null,
104
+ tone: null,
105
+ googleConnected: null,
106
+ googleScopesJson: null,
107
+ priorAssistantsJson: null,
108
+ abVariant: params.abVariant ?? ACTIVATION_AB_VARIANT,
109
+ sessionId: params.sessionId,
110
+ stepName: params.stepName,
111
+ stepIndex: activationStepIndex(params.stepName),
112
+ completedAt: new Date(createdAt).toISOString(),
113
+ funnelVersion: ACTIVATION_FUNNEL_VERSION,
114
+ });
72
115
  }
73
116
 
74
117
  /**
@@ -93,6 +136,11 @@ export function queryUnreportedOnboardingEvents(
93
136
  googleScopesJson: onboardingEvents.googleScopesJson,
94
137
  priorAssistantsJson: onboardingEvents.priorAssistantsJson,
95
138
  abVariant: onboardingEvents.abVariant,
139
+ sessionId: onboardingEvents.sessionId,
140
+ stepName: onboardingEvents.stepName,
141
+ stepIndex: onboardingEvents.stepIndex,
142
+ completedAt: onboardingEvents.completedAt,
143
+ funnelVersion: onboardingEvents.funnelVersion,
96
144
  })
97
145
  .from(onboardingEvents)
98
146
  .where(