@vellumai/assistant 0.8.3 → 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 (342) hide show
  1. package/docker-entrypoint.sh +0 -1
  2. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  3. package/openapi.yaml +610 -16
  4. package/package.json +1 -1
  5. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
  6. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  7. package/src/__tests__/agent-loop.test.ts +88 -3
  8. package/src/__tests__/anthropic-provider.test.ts +272 -0
  9. package/src/__tests__/approval-cascade.test.ts +1 -1
  10. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
  11. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  12. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  13. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  14. package/src/__tests__/compaction-events.test.ts +1 -1
  15. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  16. package/src/__tests__/config-watcher.test.ts +1 -1
  17. package/src/__tests__/context-token-estimator.test.ts +91 -1
  18. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  19. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
  20. package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
  21. package/src/__tests__/conversation-agent-loop.test.ts +25 -7
  22. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  23. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  24. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  25. package/src/__tests__/conversation-fork-crud.test.ts +161 -0
  26. package/src/__tests__/conversation-lifecycle.test.ts +1 -1
  27. package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
  28. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  29. package/src/__tests__/conversation-pairing.test.ts +2 -2
  30. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  31. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
  32. package/src/__tests__/conversation-queue.test.ts +1 -1
  33. package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
  34. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  35. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  36. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  37. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  38. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  39. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  40. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
  41. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  42. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  43. package/src/__tests__/credential-security-invariants.test.ts +6 -0
  44. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  45. package/src/__tests__/dm-backfill.test.ts +64 -0
  46. package/src/__tests__/dm-persistence.test.ts +33 -0
  47. package/src/__tests__/document-find-replace.test.ts +501 -0
  48. package/src/__tests__/first-greeting.test.ts +23 -2
  49. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  50. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  51. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  52. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  53. package/src/__tests__/host-file-proxy.test.ts +8 -1
  54. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  55. package/src/__tests__/identity-routes.test.ts +57 -0
  56. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  57. package/src/__tests__/injector-chain.test.ts +2 -0
  58. package/src/__tests__/injector-document-comments.test.ts +378 -0
  59. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  60. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  61. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  62. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  63. package/src/__tests__/list-messages-tool-merge.test.ts +17 -16
  64. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  65. package/src/__tests__/llm-resolver.test.ts +85 -1
  66. package/src/__tests__/log-export-routes.test.ts +99 -2
  67. package/src/__tests__/message-queue-steer.test.ts +114 -0
  68. package/src/__tests__/openai-provider.test.ts +105 -0
  69. package/src/__tests__/openai-responses-provider.test.ts +4 -4
  70. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  71. package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
  72. package/src/__tests__/platform.test.ts +0 -3
  73. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  74. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  75. package/src/__tests__/process-message-display-content.test.ts +21 -16
  76. package/src/__tests__/server-history-render.test.ts +83 -4
  77. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  78. package/src/__tests__/system-prompt.test.ts +51 -28
  79. package/src/__tests__/terminal-tools.test.ts +11 -1
  80. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  81. package/src/__tests__/thread-backfill.test.ts +370 -22
  82. package/src/__tests__/tool-executor.test.ts +90 -1
  83. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  84. package/src/__tests__/twilio-routes.test.ts +1 -1
  85. package/src/__tests__/web-fetch.test.ts +2 -2
  86. package/src/__tests__/workspace-git-service.test.ts +88 -5
  87. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  88. package/src/agent/attachments.ts +1 -0
  89. package/src/agent/loop.ts +57 -20
  90. package/src/background-wake/next-wake.test.ts +289 -0
  91. package/src/background-wake/next-wake.ts +172 -0
  92. package/src/browser/operations.ts +15 -0
  93. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  94. package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
  95. package/src/cli/commands/conversations.ts +128 -1
  96. package/src/cli/commands/inference-providers.ts +147 -1
  97. package/src/cli/commands/memory-v2.ts +308 -0
  98. package/src/cli/commands/notifications.ts +24 -2
  99. package/src/cli/utils/conversation-id.ts +17 -5
  100. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  101. package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
  102. package/src/config/bundled-skills/document-editor/TOOLS.json +240 -0
  103. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  104. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  105. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  106. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  107. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  108. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  109. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  110. package/src/config/bundled-tool-registry.ts +22 -12
  111. package/src/config/call-site-defaults.ts +19 -0
  112. package/src/config/feature-flag-registry.json +99 -3
  113. package/src/config/llm-resolver.ts +16 -2
  114. package/src/config/schemas/__tests__/memory-v2.test.ts +4 -0
  115. package/src/config/schemas/call-site-catalog.ts +21 -0
  116. package/src/config/schemas/llm.ts +3 -0
  117. package/src/config/schemas/memory-v2.ts +48 -1
  118. package/src/context/compactor.ts +8 -1
  119. package/src/context/token-estimator.ts +47 -4
  120. package/src/context/window-manager.ts +25 -0
  121. package/src/credential-health/credential-health-service.ts +34 -19
  122. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  123. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  124. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  125. package/src/daemon/conversation-agent-loop-handlers.ts +153 -23
  126. package/src/daemon/conversation-agent-loop.ts +223 -54
  127. package/src/daemon/conversation-lifecycle.ts +142 -116
  128. package/src/daemon/conversation-messaging.ts +3 -0
  129. package/src/daemon/conversation-process.ts +273 -0
  130. package/src/daemon/conversation-queue-manager.ts +14 -0
  131. package/src/daemon/conversation-runtime-assembly.ts +135 -75
  132. package/src/daemon/conversation-slash.ts +37 -5
  133. package/src/daemon/conversation-surfaces.ts +45 -2
  134. package/src/daemon/conversation-tool-setup.ts +7 -0
  135. package/src/daemon/conversation.ts +42 -5
  136. package/src/daemon/first-greeting.ts +10 -0
  137. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  138. package/src/daemon/handlers/config-a2a.ts +160 -0
  139. package/src/daemon/handlers/config-model.test.ts +1 -0
  140. package/src/daemon/handlers/conversations.ts +79 -0
  141. package/src/daemon/handlers/shared.ts +92 -29
  142. package/src/daemon/host-bash-proxy.ts +1 -1
  143. package/src/daemon/host-cu-proxy.ts +1 -1
  144. package/src/daemon/host-file-proxy.ts +1 -1
  145. package/src/daemon/host-transfer-proxy.ts +1 -1
  146. package/src/daemon/lifecycle.ts +18 -4
  147. package/src/daemon/message-protocol.ts +4 -0
  148. package/src/daemon/message-types/conversations.ts +8 -0
  149. package/src/daemon/message-types/document-comments.ts +50 -0
  150. package/src/daemon/message-types/messages.ts +68 -1
  151. package/src/daemon/message-types/surfaces.ts +3 -1
  152. package/src/daemon/message-types/web-activity.ts +57 -0
  153. package/src/daemon/plugin-source-watcher.ts +135 -3
  154. package/src/daemon/process-message.ts +69 -12
  155. package/src/daemon/query-complexity-router.ts +75 -0
  156. package/src/daemon/trust-context.ts +6 -0
  157. package/src/documents/document-comments-store.test.ts +338 -0
  158. package/src/documents/document-comments-store.ts +237 -0
  159. package/src/documents/document-store.ts +202 -0
  160. package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
  161. package/src/heartbeat/heartbeat-service.ts +1 -0
  162. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  163. package/src/home/feed-types.ts +6 -1
  164. package/src/home/home-content-refresh.ts +52 -0
  165. package/src/home/home-greeting-cache.ts +69 -0
  166. package/src/home/home-greeting.ts +94 -0
  167. package/src/home/suggested-prompts.ts +177 -9
  168. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  169. package/src/memory/__tests__/memory-retrospective-job.test.ts +320 -6
  170. package/src/memory/conversation-crud.ts +133 -43
  171. package/src/memory/db-init.ts +16 -0
  172. package/src/memory/delivery-crud.ts +41 -0
  173. package/src/memory/delivery-status.ts +141 -15
  174. package/src/memory/external-conversation-store.ts +32 -1
  175. package/src/memory/jobs-worker.ts +21 -1
  176. package/src/memory/memory-retrospective-constants.ts +28 -0
  177. package/src/memory/memory-retrospective-enqueue.ts +3 -2
  178. package/src/memory/memory-retrospective-job.ts +408 -18
  179. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  180. package/src/memory/memory-v2-activation-log-store.ts +26 -8
  181. package/src/memory/migrations/100-core-tables.ts +1 -0
  182. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  183. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  184. package/src/memory/migrations/253-document-comments.ts +47 -0
  185. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  186. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  187. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  188. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  189. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  190. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  191. package/src/memory/migrations/index.ts +17 -0
  192. package/src/memory/migrations/registry.ts +25 -0
  193. package/src/memory/onboarding-events-store.ts +7 -0
  194. package/src/memory/schema/calls.ts +1 -0
  195. package/src/memory/schema/conversations.ts +3 -0
  196. package/src/memory/schema/infrastructure.ts +1 -0
  197. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  198. package/src/memory/v2/__tests__/injection.test.ts +31 -14
  199. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  200. package/src/memory/v2/__tests__/router.test.ts +489 -1
  201. package/src/memory/v2/consolidation-job.ts +14 -0
  202. package/src/memory/v2/injection-events.ts +101 -0
  203. package/src/memory/v2/injection.ts +21 -10
  204. package/src/memory/v2/page-index.ts +209 -7
  205. package/src/memory/v2/page-store.ts +18 -0
  206. package/src/memory/v2/router.ts +209 -55
  207. package/src/messaging/providers/index.ts +7 -1
  208. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  209. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  210. package/src/messaging/providers/slack/adapter.ts +178 -25
  211. package/src/messaging/providers/slack/api.test.ts +54 -0
  212. package/src/messaging/providers/slack/api.ts +119 -3
  213. package/src/messaging/providers/slack/client.ts +12 -0
  214. package/src/messaging/providers/slack/deep-link.ts +20 -1
  215. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  216. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  217. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  218. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  219. package/src/messaging/providers/slack/send.test.ts +77 -0
  220. package/src/messaging/providers/slack/send.ts +8 -2
  221. package/src/messaging/providers/slack/types.ts +14 -0
  222. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
  223. package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
  224. package/src/notifications/conversation-seed-composer.ts +14 -2
  225. package/src/notifications/deferred-emit.ts +135 -0
  226. package/src/notifications/emit-signal.ts +9 -1
  227. package/src/notifications/home-feed-side-effect.ts +60 -30
  228. package/src/oauth/connect-orchestrator.ts +3 -0
  229. package/src/oauth/credential-token-resolver.ts +2 -0
  230. package/src/oauth/manual-token-connection.ts +19 -0
  231. package/src/oauth/oauth-store.ts +12 -0
  232. package/src/oauth/seed-providers.ts +22 -0
  233. package/src/permissions/prompter.ts +5 -2
  234. package/src/permissions/secret-prompter.ts +4 -1
  235. package/src/plugins/defaults/injectors.ts +82 -9
  236. package/src/prompts/__tests__/system-prompt.test.ts +46 -2
  237. package/src/prompts/normalize-onboarding.ts +40 -0
  238. package/src/prompts/sections.ts +32 -14
  239. package/src/prompts/system-prompt.ts +105 -68
  240. package/src/prompts/template-detection.ts +37 -0
  241. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  242. package/src/prompts/templates/BOOTSTRAP.md +8 -0
  243. package/src/prompts/templates/VOICE.md +3 -0
  244. package/src/prompts/templates/system-sections.ts +53 -3
  245. package/src/providers/anthropic/client.ts +132 -5
  246. package/src/providers/fireworks/client.ts +20 -2
  247. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  248. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  249. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  250. package/src/providers/inference/adapter-factory.ts +15 -1
  251. package/src/providers/inference/auth.ts +3 -3
  252. package/src/providers/inference/codex-token-refresh.ts +128 -0
  253. package/src/providers/inference/resolve-auth.ts +49 -6
  254. package/src/providers/model-catalog.ts +48 -1
  255. package/src/providers/openai/chat-completions-provider.ts +57 -20
  256. package/src/providers/openai/responses-provider.ts +9 -3
  257. package/src/providers/openrouter/client.ts +5 -1
  258. package/src/providers/types.ts +25 -0
  259. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  260. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  261. package/src/runtime/agent-wake.ts +151 -56
  262. package/src/runtime/auth/route-policy.ts +7 -3
  263. package/src/runtime/background-job-runner.ts +26 -0
  264. package/src/runtime/channel-reply-delivery.ts +182 -47
  265. package/src/runtime/channel-retry-sweep.ts +141 -16
  266. package/src/runtime/http-types.ts +7 -4
  267. package/src/runtime/pending-interactions.ts +51 -8
  268. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  269. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +55 -1
  270. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  271. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -0
  272. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  273. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  274. package/src/runtime/routes/approval-routes.ts +4 -1
  275. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  276. package/src/runtime/routes/content-source-routes.ts +78 -0
  277. package/src/runtime/routes/conversation-cli-routes.ts +146 -1
  278. package/src/runtime/routes/conversation-query-routes.ts +60 -1
  279. package/src/runtime/routes/conversation-routes.ts +281 -76
  280. package/src/runtime/routes/document-comments-routes.ts +287 -0
  281. package/src/runtime/routes/documents-routes.ts +33 -0
  282. package/src/runtime/routes/home-feed-routes.ts +6 -3
  283. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  284. package/src/runtime/routes/host-browser-routes.ts +8 -1
  285. package/src/runtime/routes/identity-routes.ts +21 -0
  286. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  287. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  288. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  289. package/src/runtime/routes/index.ts +12 -4
  290. package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
  291. package/src/runtime/routes/integrations/a2a.ts +60 -1
  292. package/src/runtime/routes/log-export-routes.ts +39 -0
  293. package/src/runtime/routes/memory-v2-routes.ts +217 -0
  294. package/src/runtime/routes/notification-routes.ts +19 -2
  295. package/src/runtime/routes/question-routes.ts +4 -1
  296. package/src/runtime/routes/sanity-routes.ts +159 -0
  297. package/src/runtime/routes/slack-channel-routes.ts +187 -0
  298. package/src/runtime/services/conversation-serializer.ts +30 -4
  299. package/src/schedule/integration-status.ts +3 -1
  300. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  301. package/src/security/oauth2-device-code.ts +307 -0
  302. package/src/security/oauth2.ts +26 -9
  303. package/src/security/secure-keys.ts +5 -0
  304. package/src/skills/catalog-install.ts +6 -2
  305. package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
  306. package/src/tools/browser/browser-execution.ts +93 -0
  307. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  308. package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
  309. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
  310. package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
  311. package/src/tools/browser/cdp-client/factory.ts +87 -3
  312. package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
  313. package/src/tools/browser/cdp-client/types.ts +36 -0
  314. package/src/tools/browser/pinned-tabs.ts +90 -0
  315. package/src/tools/document/document-comment-tool.test.ts +379 -0
  316. package/src/tools/document/document-comment-tool.ts +156 -0
  317. package/src/tools/document/document-tool.ts +128 -2
  318. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  319. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  320. package/src/tools/network/domain-normalize.ts +17 -0
  321. package/src/tools/network/web-fetch.ts +213 -64
  322. package/src/tools/network/web-search.ts +191 -66
  323. package/src/tools/terminal/safe-env.ts +3 -2
  324. package/src/tools/tool-approval-handler.ts +19 -12
  325. package/src/tools/types.ts +4 -0
  326. package/src/tools/ui-surface/definitions.ts +3 -1
  327. package/src/types/onboarding-context.ts +4 -0
  328. package/src/util/__tests__/favicon.test.ts +84 -0
  329. package/src/util/favicon.ts +40 -0
  330. package/src/util/platform.ts +0 -5
  331. package/src/workspace/git-service.ts +75 -4
  332. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  333. package/src/workspace/migrations/registry.ts +2 -0
  334. package/src/config/bundled-skills/document/SKILL.md +0 -54
  335. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  336. package/src/daemon/seed-files.ts +0 -18
  337. package/src/runtime/routes/interface-routes.ts +0 -43
  338. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  339. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  340. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  341. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  342. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -0,0 +1,318 @@
1
+ /**
2
+ * Tests for `assistant/src/memory/v2/injection-events.ts` and its sibling
3
+ * migration `256-memory-v2-injection-events.ts`.
4
+ *
5
+ * Coverage matrix:
6
+ * - Migration creates the table + both indexes; safe to re-run.
7
+ * - Backfill replays router-sourced concepts from memory_v2_activation_logs
8
+ * and is idempotent on a forced re-run with cleared checkpoint.
9
+ * - Backfill is a no-op when the activation-logs table doesn't exist
10
+ * (pre-234 DB).
11
+ * - recordInjectionEvents appends one row per slug per call; empty list
12
+ * is a no-op.
13
+ * - computeInjectionScore matches the closed-form decay at known deltas
14
+ * (0d ≈ 1, 3d ≈ 0.5, 6d ≈ 0.25) and sums multiple events linearly.
15
+ * - computeInjectionScores returns the same per-slug values in batch and
16
+ * omits slugs with no events.
17
+ *
18
+ * Uses an in-memory bun:sqlite database — no real workspace DB.
19
+ */
20
+
21
+ import { Database } from "bun:sqlite";
22
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
23
+
24
+ import { drizzle } from "drizzle-orm/bun-sqlite";
25
+
26
+ import { makeMockLogger } from "../../../__tests__/helpers/mock-logger.js";
27
+
28
+ mock.module("../../../util/logger.js", () => ({
29
+ getLogger: () => makeMockLogger(),
30
+ }));
31
+
32
+ import type { DrizzleDb } from "../../db-connection.js";
33
+ import { getSqliteFrom } from "../../db-connection.js";
34
+ import { migrateMemoryV2ActivationLogs } from "../../migrations/234-memory-v2-activation-logs.js";
35
+ import {
36
+ downMemoryV2InjectionEvents,
37
+ migrateMemoryV2InjectionEvents,
38
+ } from "../../migrations/256-memory-v2-injection-events.js";
39
+ import * as schema from "../../schema.js";
40
+ import {
41
+ computeInjectionScore,
42
+ computeInjectionScores,
43
+ INJECTION_SCORE_HALF_LIFE_MS,
44
+ recordInjectionEvents,
45
+ } from "../injection-events.js";
46
+
47
+ // memory_checkpoints is required by withCrashRecovery and is normally
48
+ // created by an early core migration. Stand it up by hand so we can run
49
+ // the v2 migrations in isolation against a fresh in-memory DB.
50
+ const CHECKPOINTS_DDL = /*sql*/ `
51
+ CREATE TABLE memory_checkpoints (
52
+ key TEXT PRIMARY KEY,
53
+ value TEXT NOT NULL,
54
+ updated_at INTEGER NOT NULL
55
+ )
56
+ `;
57
+
58
+ let sqlite: Database;
59
+ let database: DrizzleDb;
60
+
61
+ beforeEach(() => {
62
+ sqlite = new Database(":memory:");
63
+ database = drizzle(sqlite, { schema });
64
+ getSqliteFrom(database).exec(CHECKPOINTS_DDL);
65
+ });
66
+
67
+ afterEach(() => {
68
+ sqlite.close();
69
+ });
70
+
71
+ function insertActivationLog(
72
+ rawDb: Database,
73
+ args: {
74
+ id: string;
75
+ concepts: Array<{ slug: string; source: string; status?: string }>;
76
+ createdAt: number;
77
+ },
78
+ ): void {
79
+ rawDb
80
+ .prepare(
81
+ `INSERT INTO memory_v2_activation_logs (
82
+ id, conversation_id, message_id, turn, mode,
83
+ concepts_json, skills_json, config_json, created_at
84
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
85
+ )
86
+ .run(
87
+ args.id,
88
+ "conv-1",
89
+ `msg-${args.id}`,
90
+ 1,
91
+ "router",
92
+ JSON.stringify(args.concepts),
93
+ "[]",
94
+ "{}",
95
+ args.createdAt,
96
+ );
97
+ }
98
+
99
+ describe("migrateMemoryV2InjectionEvents", () => {
100
+ test("creates table and both indexes; safe to re-run", () => {
101
+ migrateMemoryV2InjectionEvents(database);
102
+ migrateMemoryV2InjectionEvents(database);
103
+
104
+ const raw = getSqliteFrom(database);
105
+ const table = raw
106
+ .query(
107
+ `SELECT name FROM sqlite_master WHERE type='table' AND name='memory_v2_injection_events'`,
108
+ )
109
+ .get();
110
+ expect(table).toBeTruthy();
111
+
112
+ const indexNames = new Set(
113
+ (
114
+ raw
115
+ .query(
116
+ `SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='memory_v2_injection_events'`,
117
+ )
118
+ .all() as Array<{ name: string }>
119
+ ).map((r) => r.name),
120
+ );
121
+ expect(indexNames.has("idx_memory_v2_injection_events_slug_time")).toBe(
122
+ true,
123
+ );
124
+ expect(indexNames.has("idx_memory_v2_injection_events_time")).toBe(true);
125
+ });
126
+
127
+ test("backfill replays router-sourced concepts and ignores carry_over", () => {
128
+ migrateMemoryV2ActivationLogs(database);
129
+ const raw = getSqliteFrom(database);
130
+ insertActivationLog(raw, {
131
+ id: "log-1",
132
+ concepts: [
133
+ { slug: "alice", source: "router", status: "injected" },
134
+ { slug: "bob", source: "router", status: "in_context" },
135
+ { slug: "ghost", source: "carry_over", status: "not_injected" },
136
+ ],
137
+ createdAt: 1_000_000,
138
+ });
139
+ insertActivationLog(raw, {
140
+ id: "log-2",
141
+ concepts: [{ slug: "alice", source: "router", status: "injected" }],
142
+ createdAt: 2_000_000,
143
+ });
144
+
145
+ migrateMemoryV2InjectionEvents(database);
146
+
147
+ const rows = raw
148
+ .query(
149
+ `SELECT slug, injected_at FROM memory_v2_injection_events ORDER BY injected_at, slug`,
150
+ )
151
+ .all() as Array<{ slug: string; injected_at: number }>;
152
+ expect(rows).toEqual([
153
+ { slug: "alice", injected_at: 1_000_000 },
154
+ { slug: "bob", injected_at: 1_000_000 },
155
+ { slug: "alice", injected_at: 2_000_000 },
156
+ ]);
157
+ });
158
+
159
+ test("backfill is a no-op when memory_v2_activation_logs is absent", () => {
160
+ // No activation-logs migration applied first.
161
+ expect(() => migrateMemoryV2InjectionEvents(database)).not.toThrow();
162
+ const { n } = getSqliteFrom(database)
163
+ .query(`SELECT COUNT(*) as n FROM memory_v2_injection_events`)
164
+ .get() as { n: number };
165
+ expect(n).toBe(0);
166
+ });
167
+
168
+ test("forced re-run does not double-insert existing events", () => {
169
+ migrateMemoryV2ActivationLogs(database);
170
+ const raw = getSqliteFrom(database);
171
+ insertActivationLog(raw, {
172
+ id: "log-1",
173
+ concepts: [{ slug: "alice", source: "router", status: "injected" }],
174
+ createdAt: 1_000_000,
175
+ });
176
+
177
+ migrateMemoryV2InjectionEvents(database);
178
+ // Simulate someone manually clearing the checkpoint — the in-table
179
+ // guard should still prevent re-backfill.
180
+ raw
181
+ .prepare(
182
+ `DELETE FROM memory_checkpoints WHERE key = 'migration_memory_v2_injection_events_v1'`,
183
+ )
184
+ .run();
185
+ migrateMemoryV2InjectionEvents(database);
186
+
187
+ const { n } = raw
188
+ .query(`SELECT COUNT(*) as n FROM memory_v2_injection_events`)
189
+ .get() as { n: number };
190
+ expect(n).toBe(1);
191
+ });
192
+
193
+ test("downMemoryV2InjectionEvents drops the table", () => {
194
+ migrateMemoryV2InjectionEvents(database);
195
+ downMemoryV2InjectionEvents(database);
196
+ const table = getSqliteFrom(database)
197
+ .query(
198
+ `SELECT name FROM sqlite_master WHERE type='table' AND name='memory_v2_injection_events'`,
199
+ )
200
+ .get();
201
+ expect(table).toBeFalsy();
202
+ });
203
+ });
204
+
205
+ describe("recordInjectionEvents", () => {
206
+ beforeEach(() => {
207
+ migrateMemoryV2InjectionEvents(database);
208
+ });
209
+
210
+ test("appends one row per slug at the same timestamp", () => {
211
+ const t = 1_000_000;
212
+ recordInjectionEvents(database, ["alice", "bob", "alice"], t);
213
+ const rows = getSqliteFrom(database)
214
+ .query(
215
+ `SELECT slug, injected_at FROM memory_v2_injection_events ORDER BY id`,
216
+ )
217
+ .all();
218
+ expect(rows).toEqual([
219
+ { slug: "alice", injected_at: t },
220
+ { slug: "bob", injected_at: t },
221
+ { slug: "alice", injected_at: t },
222
+ ]);
223
+ });
224
+
225
+ test("empty list is a no-op", () => {
226
+ recordInjectionEvents(database, [], 1_000_000);
227
+ const { n } = getSqliteFrom(database)
228
+ .query(`SELECT COUNT(*) as n FROM memory_v2_injection_events`)
229
+ .get() as { n: number };
230
+ expect(n).toBe(0);
231
+ });
232
+ });
233
+
234
+ describe("computeInjectionScore", () => {
235
+ beforeEach(() => {
236
+ migrateMemoryV2InjectionEvents(database);
237
+ });
238
+
239
+ test("returns 0 for a slug with no events", () => {
240
+ expect(computeInjectionScore(database, "missing", Date.now())).toBe(0);
241
+ });
242
+
243
+ test("single event 0 days ago → score ≈ 1", () => {
244
+ const now = 10_000_000_000;
245
+ recordInjectionEvents(database, ["alice"], now);
246
+ expect(computeInjectionScore(database, "alice", now)).toBeCloseTo(1, 5);
247
+ });
248
+
249
+ test("single event 3 days (one half-life) ago → score ≈ 0.5", () => {
250
+ const now = 10_000_000_000;
251
+ recordInjectionEvents(
252
+ database,
253
+ ["alice"],
254
+ now - INJECTION_SCORE_HALF_LIFE_MS,
255
+ );
256
+ expect(computeInjectionScore(database, "alice", now)).toBeCloseTo(0.5, 5);
257
+ });
258
+
259
+ test("single event 6 days (two half-lives) ago → score ≈ 0.25", () => {
260
+ const now = 10_000_000_000;
261
+ recordInjectionEvents(
262
+ database,
263
+ ["alice"],
264
+ now - 2 * INJECTION_SCORE_HALF_LIFE_MS,
265
+ );
266
+ expect(computeInjectionScore(database, "alice", now)).toBeCloseTo(0.25, 5);
267
+ });
268
+
269
+ test("multiple events sum independently", () => {
270
+ const now = 10_000_000_000;
271
+ recordInjectionEvents(database, ["alice"], now);
272
+ recordInjectionEvents(
273
+ database,
274
+ ["alice"],
275
+ now - INJECTION_SCORE_HALF_LIFE_MS,
276
+ );
277
+ recordInjectionEvents(
278
+ database,
279
+ ["alice"],
280
+ now - 2 * INJECTION_SCORE_HALF_LIFE_MS,
281
+ );
282
+ expect(computeInjectionScore(database, "alice", now)).toBeCloseTo(1.75, 5);
283
+ });
284
+ });
285
+
286
+ describe("computeInjectionScores", () => {
287
+ beforeEach(() => {
288
+ migrateMemoryV2InjectionEvents(database);
289
+ });
290
+
291
+ test("returns the same per-slug values as the single-slug helper", () => {
292
+ const now = 10_000_000_000;
293
+ recordInjectionEvents(database, ["alice", "bob"], now);
294
+ recordInjectionEvents(
295
+ database,
296
+ ["alice"],
297
+ now - INJECTION_SCORE_HALF_LIFE_MS,
298
+ );
299
+
300
+ const scores = computeInjectionScores(
301
+ database,
302
+ ["alice", "bob", "ghost"],
303
+ now,
304
+ );
305
+ expect(scores.get("alice")).toBeCloseTo(1.5, 5);
306
+ expect(scores.get("bob")).toBeCloseTo(1, 5);
307
+ // ghost has no events — omitted from the result, not present as 0.
308
+ expect(scores.has("ghost")).toBe(false);
309
+ expect(scores.get("alice")).toBeCloseTo(
310
+ computeInjectionScore(database, "alice", now),
311
+ 5,
312
+ );
313
+ });
314
+
315
+ test("empty slug list returns empty map", () => {
316
+ expect(computeInjectionScores(database, [], Date.now()).size).toBe(0);
317
+ });
318
+ });
@@ -260,6 +260,8 @@ mock.module("../page-store.js", () => ({
260
260
  interface RouterResultStub {
261
261
  selectedSlugs: string[];
262
262
  failureReason: string | null;
263
+ /** Tier provenance per slug. Defaults to `tier3:0` for any selected slug. */
264
+ sourceBySlug?: Map<string, string>;
263
265
  }
264
266
 
265
267
  const routerState = {
@@ -270,12 +272,20 @@ const routerState = {
270
272
  mock.module("../router.js", () => ({
271
273
  runRouter: async () => {
272
274
  routerState.callCount++;
273
- return (
274
- routerState.nextResult ?? {
275
- selectedSlugs: [],
276
- failureReason: null,
277
- }
278
- );
275
+ const result = routerState.nextResult ?? {
276
+ selectedSlugs: [],
277
+ failureReason: null,
278
+ };
279
+ // Synthesize a default sourceBySlug for stubs that don't set one — pre-
280
+ // tier-provenance tests stage `selectedSlugs` only and expect every pick
281
+ // to flow through as a router selection. Treating them as `tier3:0` is
282
+ // the closest equivalent under the new model.
283
+ if (!result.sourceBySlug) {
284
+ const map = new Map<string, string>();
285
+ for (const slug of result.selectedSlugs) map.set(slug, "tier3:0");
286
+ result.sourceBySlug = map;
287
+ }
288
+ return result;
279
289
  },
280
290
  }));
281
291
 
@@ -388,6 +398,8 @@ import type { SkillEntry } from "../types.js";
388
398
  const { getSqliteFrom } = await import("../../db-connection.js");
389
399
  const { migrateActivationState } =
390
400
  await import("../../migrations/232-activation-state.js");
401
+ const { migrateMemoryV2InjectionEvents } =
402
+ await import("../../migrations/256-memory-v2-injection-events.js");
391
403
  const schema = await import("../../schema.js");
392
404
  const { clearEverInjected, hydrate, save } =
393
405
  await import("../activation-store.js");
@@ -409,6 +421,7 @@ function createTestDb(): DrizzleDb {
409
421
  )
410
422
  `);
411
423
  migrateActivationState(db);
424
+ migrateMemoryV2InjectionEvents(db);
412
425
  return db;
413
426
  }
414
427
 
@@ -743,7 +756,7 @@ describe("injectMemoryV2Block", () => {
743
756
 
744
757
  expect(result.block).not.toBeNull();
745
758
  expect(result.block).toContain(
746
- "**CRITICAL:** These are page summaries. Read the page file if it looks relevant.",
759
+ 'Use `file_read("memory/concepts/path/to/file.md")` to read the full pages for any of the injected memory summaries you want more information on.',
747
760
  );
748
761
  expect(result.block).toContain(
749
762
  "# memory/concepts/summarized-page.md\nA short prose description",
@@ -776,11 +789,13 @@ describe("injectMemoryV2Block", () => {
776
789
  });
777
790
 
778
791
  expect(result.block).not.toBeNull();
779
- // CRITICAL header appears exactly once.
780
- const criticalCount = (
781
- result.block!.match(/\*\*CRITICAL:\*\* These are page summaries\./g) ?? []
792
+ // Header appears exactly once.
793
+ const headerCount = (
794
+ result.block!.match(
795
+ /Use `file_read\("memory\/concepts\/path\/to\/file\.md"\)` to read/g,
796
+ ) ?? []
782
797
  ).length;
783
- expect(criticalCount).toBe(1);
798
+ expect(headerCount).toBe(1);
784
799
  // summarized-page → short form (path + summary, no body, no frontmatter).
785
800
  expect(result.block).toContain("# memory/concepts/summarized-page.md\nA");
786
801
  expect(result.block).not.toContain("Long-form body content");
@@ -1820,7 +1835,9 @@ describe("injectMemoryV2Block", () => {
1820
1835
  expect(row.mode).toBe("router");
1821
1836
  const aliceRow = row.concepts.find((c) => c.slug === "alice-vscode");
1822
1837
  expect(aliceRow).toBeDefined();
1823
- expect(aliceRow!.source).toBe("router");
1838
+ // Default-stub provenance is `tier3:0` (single-batch path); see the
1839
+ // runRouter mock for the synthesis rule.
1840
+ expect(aliceRow!.source).toBe("tier3:0");
1824
1841
  expect(aliceRow!.status).toBe("injected");
1825
1842
  expect(aliceRow!.finalActivation).toBe(0);
1826
1843
  expect(aliceRow!.ownActivation).toBe(0);
@@ -2002,7 +2019,7 @@ describe("injectMemoryV2Block", () => {
2002
2019
  );
2003
2020
  expect(phantom).toBeDefined();
2004
2021
  expect(phantom!.status).toBe("page_missing");
2005
- expect(phantom!.source).toBe("router");
2022
+ expect(phantom!.source).toBe("tier3:0");
2006
2023
  });
2007
2024
 
2008
2025
  test("flag-on: router re-picking a prior-everInjected slug does NOT re-render it; non-overlapping picks render and append to everInjected", async () => {
@@ -2107,7 +2124,7 @@ describe("injectMemoryV2Block", () => {
2107
2124
  expect(bobRow).toBeDefined();
2108
2125
  expect(aliceRow!.source).toBe("carry_over");
2109
2126
  expect(aliceRow!.status).toBe("in_context");
2110
- expect(bobRow!.source).toBe("router");
2127
+ expect(bobRow!.source).toBe("tier3:0");
2111
2128
  expect(bobRow!.status).toBe("injected");
2112
2129
  });
2113
2130