@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
@@ -6,11 +6,23 @@
6
6
  *
7
7
  * Two sources of prompts:
8
8
  * - **Deterministic** — derived from missing OAuth connections.
9
+ * Computed inline (read-only, safe for GET).
9
10
  * - **Assistant-generated** — contextual suggestions from the LLM
10
- * (placeholder; not yet implemented).
11
+ * based on what's relevant to the user. Read from an in-memory
12
+ * cache in the GET path; generation runs in the background via
13
+ * `refreshAssistantSuggestedPrompts`.
11
14
  */
12
15
 
13
- import { isProviderConnected, listProviders } from "../oauth/oauth-store.js";
16
+ import { resolveCallSiteConfig } from "../config/llm-resolver.js";
17
+ import { getConfig } from "../config/loader.js";
18
+ import { listProviders } from "../oauth/oauth-store.js";
19
+ import { resolvePersonaContext } from "../prompts/persona-resolver.js";
20
+ import { buildSystemPrompt } from "../prompts/system-prompt.js";
21
+ import { getConfiguredProvider } from "../providers/provider-send-message.js";
22
+ import { buildAssistantEvent } from "../runtime/assistant-event.js";
23
+ import { assistantEventHub } from "../runtime/assistant-event-hub.js";
24
+ import { runBtwSidechain } from "../runtime/btw-sidechain.js";
25
+ import { isOAuthProviderConnected } from "../schedule/integration-status.js";
14
26
  import { getLogger } from "../util/logger.js";
15
27
  import type { SuggestedPrompt } from "./feed-types.js";
16
28
 
@@ -72,27 +84,88 @@ const CONNECT_PROMPT_META: Record<
72
84
  },
73
85
  };
74
86
 
87
+ const LLM_SUGGESTIONS_TIMEOUT_MS = 5_000;
88
+ const LLM_CACHE_TTL_MS = 30 * 60 * 1000; // 30 minutes
89
+
90
+ // ---------------------------------------------------------------------------
91
+ // In-memory cache for LLM-generated suggestions
92
+ // ---------------------------------------------------------------------------
93
+
94
+ let cachedLLMPrompts: SuggestedPrompt[] = [];
95
+ let cachedLLMPromptsAt = 0;
96
+
75
97
  /**
76
- * Produce deterministic suggested prompts based on missing OAuth
77
- * connections and (in the future) assistant-generated conversation
78
- * starters.
98
+ * Produce suggested prompts from both deterministic and cached LLM sources.
99
+ * Deterministic prompts always come first; cached LLM-generated prompts are
100
+ * appended when available. No LLM calls happen in this path — safe for GET.
79
101
  */
80
102
  export async function getSuggestedPrompts(): Promise<SuggestedPrompt[]> {
81
103
  const prompts: SuggestedPrompt[] = [];
82
104
 
105
+ let deterministicPrompts: SuggestedPrompt[] = [];
83
106
  try {
84
- const deterministicPrompts = await getDeterministicPrompts();
107
+ deterministicPrompts = await getDeterministicPrompts();
85
108
  prompts.push(...deterministicPrompts);
86
109
  } catch (err) {
87
110
  log.warn({ err }, "Failed to compute deterministic suggested prompts");
88
111
  }
89
112
 
90
- // Placeholder: assistant-generated prompts will be added here once
91
- // the LLM producer is implemented.
113
+ if (Date.now() - cachedLLMPromptsAt < LLM_CACHE_TTL_MS) {
114
+ prompts.push(...cachedLLMPrompts);
115
+ }
92
116
 
93
117
  return prompts;
94
118
  }
95
119
 
120
+ /**
121
+ * Drops the in-memory LLM suggestion cache so the next call to
122
+ * `getSuggestedPrompts()` returns only the fresh deterministic list (and
123
+ * a follow-up background refresh repopulates the LLM half).
124
+ *
125
+ * Called from OAuth connect/disconnect paths so a freshly-connected
126
+ * provider stops surfacing as a "Connect X" pill within one reload — the
127
+ * 30-minute TTL would otherwise pin a stale suggestion until the next
128
+ * periodic refresh.
129
+ */
130
+ export function invalidateAssistantSuggestedPromptsCache(): void {
131
+ cachedLLMPrompts = [];
132
+ cachedLLMPromptsAt = 0;
133
+ assistantEventHub
134
+ .publish(
135
+ buildAssistantEvent({
136
+ type: "home_feed_updated",
137
+ updatedAt: new Date().toISOString(),
138
+ newItemCount: 0,
139
+ }),
140
+ )
141
+ .catch((err) => {
142
+ log.warn(
143
+ { err },
144
+ "Failed to publish home_feed_updated after prompt cache invalidation",
145
+ );
146
+ });
147
+ }
148
+
149
+ /**
150
+ * Generate LLM-based suggestion prompts and write them to the in-memory
151
+ * cache. No-ops when the cache is still fresh. Intended for background
152
+ * invocation (daemon startup / periodic refresh), not the GET path.
153
+ */
154
+ export async function refreshAssistantSuggestedPrompts(): Promise<void> {
155
+ if (Date.now() - cachedLLMPromptsAt < LLM_CACHE_TTL_MS) {
156
+ return;
157
+ }
158
+
159
+ try {
160
+ const deterministicPrompts = await getDeterministicPrompts();
161
+ const llmPrompts = await generateAssistantPrompts(deterministicPrompts);
162
+ cachedLLMPrompts = llmPrompts;
163
+ cachedLLMPromptsAt = Date.now();
164
+ } catch (err) {
165
+ log.warn({ err }, "Failed to refresh assistant suggested prompts");
166
+ }
167
+ }
168
+
96
169
  /**
97
170
  * Check which well-known OAuth providers are not connected and return
98
171
  * a "Connect X" prompt for each. For connected providers that have
@@ -107,7 +180,7 @@ async function getDeterministicPrompts(): Promise<SuggestedPrompt[]> {
107
180
  const meta = CONNECT_PROMPT_META[provider.provider];
108
181
  if (!meta) continue;
109
182
 
110
- const connected = await isProviderConnected(provider.provider);
183
+ const connected = await isOAuthProviderConnected(provider.provider);
111
184
 
112
185
  if (!connected) {
113
186
  prompts.push({
@@ -135,3 +208,98 @@ async function getDeterministicPrompts(): Promise<SuggestedPrompt[]> {
135
208
 
136
209
  return prompts;
137
210
  }
211
+
212
+ // ---------------------------------------------------------------------------
213
+ // LLM-generated suggestions
214
+ // ---------------------------------------------------------------------------
215
+
216
+ interface LLMSuggestion {
217
+ label: string;
218
+ prompt: string;
219
+ }
220
+
221
+ /**
222
+ * Ask the LLM to generate contextual conversation-starter suggestions
223
+ * based on the assistant's persona and the user's connected services.
224
+ * Returns an empty array on failure so deterministic prompts still show.
225
+ */
226
+ async function generateAssistantPrompts(
227
+ deterministicPrompts: SuggestedPrompt[],
228
+ ): Promise<SuggestedPrompt[]> {
229
+ const config = getConfig();
230
+ const resolved = resolveCallSiteConfig("homeSuggestedPrompts", config.llm);
231
+
232
+ const provider = await getConfiguredProvider("homeSuggestedPrompts");
233
+ if (!provider) {
234
+ return [];
235
+ }
236
+
237
+ const { userPersona, userSlug, channelPersona } = resolvePersonaContext(
238
+ undefined,
239
+ undefined,
240
+ );
241
+
242
+ const systemPrompt = buildSystemPrompt({
243
+ excludeBootstrap: true,
244
+ excludeCustomPrefix: true,
245
+ userPersona,
246
+ channelPersona,
247
+ userSlug,
248
+ });
249
+
250
+ const existingLabels = deterministicPrompts.map((p) => p.label).join(", ");
251
+ const contextNote = existingLabels
252
+ ? `The user already has these suggestions: ${existingLabels}. Do NOT duplicate them.`
253
+ : "";
254
+
255
+ const result = await runBtwSidechain({
256
+ content:
257
+ "Suggest 2-3 short, actionable conversation starters for the home page. " +
258
+ "Each should be something specific and helpful you can do for the user right now. " +
259
+ `${contextNote} ` +
260
+ 'Return ONLY a JSON array of objects with "label" (max 5 words) and "prompt" (the full message to send). ' +
261
+ "No markdown fences, no explanation.",
262
+ provider,
263
+ systemPrompt,
264
+ messages: [],
265
+ tools: [],
266
+ callSite: "homeSuggestedPrompts",
267
+ maxTokens: resolved.maxTokens,
268
+ timeoutMs: LLM_SUGGESTIONS_TIMEOUT_MS,
269
+ });
270
+
271
+ const text = result.text.trim();
272
+ if (!text) {
273
+ return [];
274
+ }
275
+
276
+ const parsed = parseLLMSuggestions(text);
277
+ return parsed.map((s, i) => ({
278
+ id: `assistant-${i}-${s.label.toLowerCase().replace(/\s+/g, "-")}`,
279
+ label: s.label,
280
+ prompt: s.prompt,
281
+ source: "assistant" as const,
282
+ }));
283
+ }
284
+
285
+ function parseLLMSuggestions(text: string): LLMSuggestion[] {
286
+ try {
287
+ const cleaned = text
288
+ .replace(/^```(?:json)?\n?/m, "")
289
+ .replace(/\n?```$/m, "");
290
+ const parsed = JSON.parse(cleaned);
291
+ if (!Array.isArray(parsed)) {
292
+ return [];
293
+ }
294
+ return parsed.filter(
295
+ (item): item is LLMSuggestion =>
296
+ typeof item === "object" &&
297
+ item !== null &&
298
+ typeof item.label === "string" &&
299
+ typeof item.prompt === "string",
300
+ );
301
+ } catch {
302
+ log.warn("Failed to parse LLM suggestions response");
303
+ return [];
304
+ }
305
+ }
@@ -19,7 +19,7 @@
19
19
  * Tests use a temp workspace pinned via `VELLUM_WORKSPACE_DIR` so the DB
20
20
  * lives under `tmpdir()` and `~/.vellum/` is never touched.
21
21
  */
22
- import { mkdtempSync, rmSync } from "node:fs";
22
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
23
23
  import { tmpdir } from "node:os";
24
24
  import { join } from "node:path";
25
25
  import {
@@ -66,7 +66,7 @@ const { initializeDb } = await import("../db-init.js");
66
66
  const { resetTestTables } = await import("../raw-query.js");
67
67
  const { memoryJobs } = await import("../schema.js");
68
68
  const { applyNestedDefaults } = await import("../../config/loader.js");
69
- const { setMemoryCheckpoint, deleteMemoryCheckpoint } =
69
+ const { getMemoryCheckpoint, setMemoryCheckpoint, deleteMemoryCheckpoint } =
70
70
  await import("../checkpoints.js");
71
71
  const { maybeEnqueueGraphMaintenanceJobs } = await import("../jobs-worker.js");
72
72
 
@@ -75,6 +75,7 @@ const CONSOLIDATE_CHECKPOINT_KEY = "memory_v2_consolidate_last_run";
75
75
  function buildConfig(overrides: {
76
76
  v2Enabled?: boolean;
77
77
  intervalHours?: number;
78
+ maxBufferLines?: number | null;
78
79
  }) {
79
80
  const partial = applyNestedDefaults({});
80
81
  if (overrides.v2Enabled !== undefined) {
@@ -83,9 +84,26 @@ function buildConfig(overrides: {
83
84
  if (overrides.intervalHours !== undefined) {
84
85
  partial.memory.v2.consolidation_interval_hours = overrides.intervalHours;
85
86
  }
87
+ if (overrides.maxBufferLines !== undefined) {
88
+ partial.memory.v2.consolidation_max_buffer_lines = overrides.maxBufferLines;
89
+ }
86
90
  return partial;
87
91
  }
88
92
 
93
+ function writeBuffer(lineCount: number): void {
94
+ const memoryDir = join(tmpWorkspace, "memory");
95
+ mkdirSync(memoryDir, { recursive: true });
96
+ const entries = Array.from(
97
+ { length: lineCount },
98
+ (_, i) => `- [Jan 15, 2:${String(i).padStart(2, "0")} PM] note ${i}`,
99
+ );
100
+ writeFileSync(join(memoryDir, "buffer.md"), entries.join("\n") + "\n");
101
+ }
102
+
103
+ function removeBuffer(): void {
104
+ rmSync(join(tmpWorkspace, "memory", "buffer.md"), { force: true });
105
+ }
106
+
89
107
  function countPendingJobs(type: string): number {
90
108
  return getDb()
91
109
  .select()
@@ -216,3 +234,118 @@ describe("maybeEnqueueGraphMaintenanceJobs — memory v2 consolidation", () => {
216
234
  expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
217
235
  });
218
236
  });
237
+
238
+ describe("maybeEnqueueGraphMaintenanceJobs — buffer-size trigger", () => {
239
+ test("default threshold (100 lines) fires once the buffer reaches it", () => {
240
+ const config = buildConfig({ v2Enabled: true, intervalHours: 1 });
241
+
242
+ const now = Date.now();
243
+ // Recent checkpoint so the time-based trigger does not fire.
244
+ setMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY, String(now - 60_000));
245
+ writeBuffer(100);
246
+
247
+ maybeEnqueueGraphMaintenanceJobs(config, now);
248
+
249
+ expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
250
+ });
251
+
252
+ test("explicit null disables the size trigger", () => {
253
+ const config = buildConfig({
254
+ v2Enabled: true,
255
+ intervalHours: 1,
256
+ maxBufferLines: null,
257
+ });
258
+
259
+ const now = Date.now();
260
+ setMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY, String(now - 60_000));
261
+ writeBuffer(500);
262
+
263
+ maybeEnqueueGraphMaintenanceJobs(config, now);
264
+
265
+ expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
266
+ });
267
+
268
+ test("enqueues when buffer reaches the threshold even if interval not elapsed", () => {
269
+ const config = buildConfig({
270
+ v2Enabled: true,
271
+ intervalHours: 1,
272
+ maxBufferLines: 5,
273
+ });
274
+
275
+ const now = Date.now();
276
+ setMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY, String(now - 60_000));
277
+ writeBuffer(10);
278
+
279
+ maybeEnqueueGraphMaintenanceJobs(config, now);
280
+
281
+ expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
282
+ // Checkpoint refreshed so the next tick doesn't immediately re-fire.
283
+ expect(getMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY)).toBe(String(now));
284
+ });
285
+
286
+ test("does not enqueue when buffer is under the threshold", () => {
287
+ const config = buildConfig({
288
+ v2Enabled: true,
289
+ intervalHours: 1,
290
+ maxBufferLines: 5,
291
+ });
292
+
293
+ const now = Date.now();
294
+ setMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY, String(now - 60_000));
295
+ writeBuffer(3);
296
+
297
+ maybeEnqueueGraphMaintenanceJobs(config, now);
298
+
299
+ expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
300
+ });
301
+
302
+ test("treats missing buffer file as zero lines", () => {
303
+ const config = buildConfig({
304
+ v2Enabled: true,
305
+ intervalHours: 1,
306
+ maxBufferLines: 1,
307
+ });
308
+
309
+ const now = Date.now();
310
+ setMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY, String(now - 60_000));
311
+ removeBuffer();
312
+
313
+ maybeEnqueueGraphMaintenanceJobs(config, now);
314
+
315
+ expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
316
+ });
317
+
318
+ test("does not double-enqueue when both triggers would fire", () => {
319
+ const config = buildConfig({
320
+ v2Enabled: true,
321
+ intervalHours: 1,
322
+ maxBufferLines: 5,
323
+ });
324
+
325
+ const now = Date.now();
326
+ // Stale checkpoint so time-based fires, AND buffer over threshold.
327
+ setMemoryCheckpoint(
328
+ CONSOLIDATE_CHECKPOINT_KEY,
329
+ String(now - 2 * 60 * 60 * 1000),
330
+ );
331
+ writeBuffer(10);
332
+
333
+ maybeEnqueueGraphMaintenanceJobs(config, now);
334
+
335
+ expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
336
+ });
337
+
338
+ test("size trigger inert when v2 is disabled", () => {
339
+ const config = buildConfig({
340
+ v2Enabled: false,
341
+ intervalHours: 1,
342
+ maxBufferLines: 1,
343
+ });
344
+
345
+ writeBuffer(100);
346
+
347
+ maybeEnqueueGraphMaintenanceJobs(config, Date.now());
348
+
349
+ expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
350
+ });
351
+ });