@vellumai/assistant 0.5.16 → 0.6.0

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 (407) hide show
  1. package/ARCHITECTURE.md +1 -1
  2. package/Dockerfile +0 -3
  3. package/knip.json +2 -1
  4. package/openapi.yaml +660 -80
  5. package/package.json +1 -1
  6. package/src/__tests__/actor-token-service.test.ts +68 -0
  7. package/src/__tests__/agent-loop.test.ts +0 -32
  8. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  9. package/src/__tests__/anthropic-provider.test.ts +57 -3
  10. package/src/__tests__/app-compiler.test.ts +120 -0
  11. package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
  12. package/src/__tests__/call-conversation-messages.test.ts +2 -6
  13. package/src/__tests__/call-domain.test.ts +2 -6
  14. package/src/__tests__/call-pointer-messages.test.ts +2 -14
  15. package/src/__tests__/call-recovery.test.ts +2 -6
  16. package/src/__tests__/call-routes-http.test.ts +2 -6
  17. package/src/__tests__/call-store.test.ts +2 -6
  18. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
  19. package/src/__tests__/canonical-guardian-store.test.ts +2 -6
  20. package/src/__tests__/channel-delivery-store.test.ts +2 -6
  21. package/src/__tests__/channel-retry-sweep.test.ts +2 -6
  22. package/src/__tests__/checker.test.ts +25 -3
  23. package/src/__tests__/clawhub.test.ts +54 -24
  24. package/src/__tests__/cli-command-risk-guard.test.ts +14 -0
  25. package/src/__tests__/cli-memory.test.ts +74 -69
  26. package/src/__tests__/config-schema.test.ts +1 -1
  27. package/src/__tests__/config-set-platform-guard.test.ts +302 -0
  28. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
  29. package/src/__tests__/contacts-tools.test.ts +31 -0
  30. package/src/__tests__/context-overflow-reducer.test.ts +86 -0
  31. package/src/__tests__/context-token-estimator.test.ts +175 -10
  32. package/src/__tests__/conversation-agent-loop-overflow.test.ts +9 -0
  33. package/src/__tests__/conversation-agent-loop.test.ts +9 -0
  34. package/src/__tests__/conversation-attachments.test.ts +2 -6
  35. package/src/__tests__/conversation-attention-store.test.ts +2 -6
  36. package/src/__tests__/conversation-clear-safety.test.ts +2 -6
  37. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
  38. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
  39. package/src/__tests__/conversation-disk-view.test.ts +2 -6
  40. package/src/__tests__/conversation-error.test.ts +33 -2
  41. package/src/__tests__/conversation-fork-crud.test.ts +2 -6
  42. package/src/__tests__/conversation-history-web-search.test.ts +5 -0
  43. package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
  44. package/src/__tests__/conversation-media-retry.test.ts +91 -0
  45. package/src/__tests__/conversation-starter-routes.test.ts +20 -11
  46. package/src/__tests__/conversation-store.test.ts +2 -6
  47. package/src/__tests__/conversation-usage.test.ts +2 -6
  48. package/src/__tests__/conversation-wipe.test.ts +11 -408
  49. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  50. package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
  51. package/src/__tests__/credential-security-e2e.test.ts +2 -0
  52. package/src/__tests__/followup-tools.test.ts +2 -6
  53. package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
  54. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
  55. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
  56. package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
  57. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
  58. package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
  59. package/src/__tests__/guardian-action-store.test.ts +2 -6
  60. package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
  61. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
  62. package/src/__tests__/guardian-dispatch.test.ts +2 -6
  63. package/src/__tests__/guardian-grant-minting.test.ts +2 -14
  64. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
  65. package/src/__tests__/guardian-routing-invariants.test.ts +192 -6
  66. package/src/__tests__/guardian-routing-state.test.ts +2 -6
  67. package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
  68. package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
  69. package/src/__tests__/injection-block.test.ts +154 -0
  70. package/src/__tests__/install-meta.test.ts +506 -0
  71. package/src/__tests__/install-skill-routing.test.ts +292 -0
  72. package/src/__tests__/invite-redemption-service.test.ts +2 -6
  73. package/src/__tests__/invite-routes-http.test.ts +2 -6
  74. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -14
  75. package/src/__tests__/list-messages-attachments.test.ts +2 -6
  76. package/src/__tests__/llm-context-route-provider.test.ts +2 -6
  77. package/src/__tests__/llm-request-log-turn-query.test.ts +2 -6
  78. package/src/__tests__/llm-usage-store.test.ts +2 -6
  79. package/src/__tests__/log-export-workspace.test.ts +2 -6
  80. package/src/__tests__/managed-store.test.ts +38 -11
  81. package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
  82. package/src/__tests__/memory-recall-log-store.test.ts +2 -6
  83. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
  84. package/src/__tests__/non-member-access-request.test.ts +2 -6
  85. package/src/__tests__/notification-guardian-path.test.ts +2 -6
  86. package/src/__tests__/oauth-cli.test.ts +364 -2
  87. package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
  88. package/src/__tests__/outlook-attachments.test.ts +301 -0
  89. package/src/__tests__/outlook-automation-tools.test.ts +425 -0
  90. package/src/__tests__/outlook-categories.test.ts +212 -0
  91. package/src/__tests__/outlook-client-automation.test.ts +246 -0
  92. package/src/__tests__/outlook-compose-tools.test.ts +325 -0
  93. package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
  94. package/src/__tests__/outlook-email-watcher.test.ts +322 -0
  95. package/src/__tests__/outlook-follow-up.test.ts +196 -0
  96. package/src/__tests__/outlook-messaging-provider.test.ts +498 -3
  97. package/src/__tests__/outlook-trash.test.ts +77 -0
  98. package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
  99. package/src/__tests__/platform-callback-registration.test.ts +4 -4
  100. package/src/__tests__/playbook-execution.test.ts +76 -80
  101. package/src/__tests__/playbook-tools.test.ts +5 -7
  102. package/src/__tests__/provider-error-scenarios.test.ts +21 -0
  103. package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
  104. package/src/__tests__/registry.test.ts +2 -2
  105. package/src/__tests__/require-fresh-approval.test.ts +64 -2
  106. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
  107. package/src/__tests__/runtime-events-sse.test.ts +2 -6
  108. package/src/__tests__/schedule-store.test.ts +2 -6
  109. package/src/__tests__/schedule-tools.test.ts +2 -6
  110. package/src/__tests__/scheduler-recurrence.test.ts +1 -5
  111. package/src/__tests__/scoped-approval-grants.test.ts +2 -6
  112. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
  113. package/src/__tests__/search-skills-unified.test.ts +421 -0
  114. package/src/__tests__/secret-onetime-send.test.ts +2 -0
  115. package/src/__tests__/send-endpoint-busy.test.ts +2 -6
  116. package/src/__tests__/sequence-store.test.ts +2 -6
  117. package/src/__tests__/server-history-render.test.ts +2 -6
  118. package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
  119. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  120. package/src/__tests__/skill-load-feature-flag.test.ts +11 -11
  121. package/src/__tests__/skill-memory.test.ts +140 -98
  122. package/src/__tests__/skills-uninstall.test.ts +2 -2
  123. package/src/__tests__/skills.test.ts +1 -1
  124. package/src/__tests__/slack-inbound-verification.test.ts +2 -6
  125. package/src/__tests__/task-compiler.test.ts +2 -6
  126. package/src/__tests__/task-management-tools.test.ts +2 -6
  127. package/src/__tests__/task-memory-cleanup.test.ts +173 -229
  128. package/src/__tests__/task-runner.test.ts +2 -6
  129. package/src/__tests__/task-scheduler.test.ts +2 -6
  130. package/src/__tests__/test-preload.ts +3 -0
  131. package/src/__tests__/tool-approval-handler.test.ts +2 -6
  132. package/src/__tests__/tool-grant-request-escalation.test.ts +2 -6
  133. package/src/__tests__/tool-side-effects-slack-dm.test.ts +276 -0
  134. package/src/__tests__/trust-store.test.ts +1 -1
  135. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -6
  136. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -6
  137. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -6
  138. package/src/__tests__/trusted-contact-verification.test.ts +2 -6
  139. package/src/__tests__/turn-boundary-resolution.test.ts +2 -6
  140. package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -6
  141. package/src/__tests__/usage-routes.test.ts +2 -6
  142. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  143. package/src/__tests__/voice-invite-redemption.test.ts +2 -6
  144. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -6
  145. package/src/__tests__/voice-session-bridge.test.ts +2 -6
  146. package/src/__tests__/volume-security-guard.test.ts +2 -0
  147. package/src/__tests__/workspace-lifecycle.test.ts +29 -1
  148. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -6
  149. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -6
  150. package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
  151. package/src/__tests__/workspace-policy.test.ts +1 -1
  152. package/src/agent/attachments.ts +7 -2
  153. package/src/agent/image-optimize.ts +165 -0
  154. package/src/agent/loop.ts +1 -15
  155. package/src/bundler/app-compiler.ts +179 -2
  156. package/src/bundler/package-resolver.ts +3 -5
  157. package/src/cli/__tests__/notifications.test.ts +1 -2
  158. package/src/cli/cli-memory.ts +67 -64
  159. package/src/cli/commands/avatar.ts +3 -3
  160. package/src/cli/commands/config.ts +26 -13
  161. package/src/cli/commands/doctor.ts +2 -2
  162. package/src/cli/commands/memory.ts +41 -55
  163. package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
  164. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
  165. package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
  166. package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
  167. package/src/cli/commands/oauth/connect.ts +11 -6
  168. package/src/cli/commands/oauth/mode.ts +7 -0
  169. package/src/cli/commands/oauth/shared.ts +39 -3
  170. package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
  171. package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
  172. package/src/cli/commands/platform/__tests__/status.test.ts +5 -5
  173. package/src/cli/commands/platform/index.ts +16 -16
  174. package/src/cli/commands/skills.ts +88 -16
  175. package/src/cli/commands/trust.ts +2 -2
  176. package/src/cli/lib/daemon-credential-client.ts +2 -3
  177. package/src/config/bundled-skills/acp/TOOLS.json +1 -1
  178. package/src/config/bundled-skills/contacts/SKILL.md +0 -1
  179. package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
  180. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
  181. package/src/config/bundled-skills/gmail/SKILL.md +2 -10
  182. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
  183. package/src/config/bundled-skills/messaging/SKILL.md +10 -18
  184. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
  185. package/src/config/bundled-skills/outlook/SKILL.md +189 -0
  186. package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
  187. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
  188. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
  189. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
  190. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
  191. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
  192. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
  193. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
  194. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
  195. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
  196. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
  197. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
  198. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
  199. package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
  200. package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
  201. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
  202. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
  203. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
  204. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
  205. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
  206. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
  207. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
  208. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
  209. package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
  210. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
  211. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
  212. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
  213. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
  214. package/src/config/bundled-skills/slack/SKILL.md +1 -7
  215. package/src/config/bundled-tool-registry.ts +56 -4
  216. package/src/config/env-registry.ts +15 -8
  217. package/src/config/feature-flag-registry.json +21 -124
  218. package/src/config/schemas/platform.ts +8 -0
  219. package/src/config/schemas/timeouts.ts +1 -1
  220. package/src/config/skills.ts +18 -7
  221. package/src/context/token-estimator.ts +25 -18
  222. package/src/context/window-manager.ts +6 -2
  223. package/src/credential-execution/process-manager.ts +3 -1
  224. package/src/daemon/context-overflow-reducer.ts +46 -2
  225. package/src/daemon/conversation-agent-loop-handlers.ts +123 -82
  226. package/src/daemon/conversation-agent-loop.ts +96 -61
  227. package/src/daemon/conversation-error.ts +31 -8
  228. package/src/daemon/conversation-lifecycle.ts +33 -0
  229. package/src/daemon/conversation-media-retry.ts +85 -7
  230. package/src/daemon/conversation-notifiers.ts +4 -1
  231. package/src/daemon/conversation-runtime-assembly.ts +5 -0
  232. package/src/daemon/conversation.ts +41 -2
  233. package/src/daemon/daemon-control.ts +8 -2
  234. package/src/daemon/handlers/shared.ts +22 -12
  235. package/src/daemon/handlers/skills.ts +416 -202
  236. package/src/daemon/lifecycle.ts +40 -1
  237. package/src/daemon/main.ts +5 -1
  238. package/src/daemon/message-types/conversations.ts +4 -1
  239. package/src/daemon/message-types/messages.ts +3 -1
  240. package/src/daemon/message-types/skills.ts +97 -36
  241. package/src/daemon/providers-setup.ts +5 -0
  242. package/src/daemon/server.ts +11 -2
  243. package/src/daemon/tool-side-effects.ts +27 -5
  244. package/src/heartbeat/heartbeat-service.ts +1 -0
  245. package/src/hooks/cli.ts +2 -2
  246. package/src/hooks/runner.ts +15 -38
  247. package/src/inbound/platform-callback-registration.ts +14 -14
  248. package/src/memory/admin.ts +11 -45
  249. package/src/memory/conversation-bootstrap.ts +2 -0
  250. package/src/memory/conversation-crud.ts +242 -348
  251. package/src/memory/conversation-group-migration.ts +157 -0
  252. package/src/memory/conversation-queries.ts +4 -2
  253. package/src/memory/db-init.ts +30 -3
  254. package/src/memory/embed.ts +73 -0
  255. package/src/memory/embedding-backend.ts +8 -14
  256. package/src/memory/embedding-runtime-manager.ts +12 -114
  257. package/src/memory/fingerprint.ts +2 -2
  258. package/src/memory/graph/bootstrap.ts +512 -0
  259. package/src/memory/graph/capability-seed.ts +297 -0
  260. package/src/memory/graph/consolidation.ts +691 -0
  261. package/src/memory/graph/conversation-graph-memory.ts +630 -0
  262. package/src/memory/graph/decay.test.ts +208 -0
  263. package/src/memory/graph/decay.ts +195 -0
  264. package/src/memory/graph/extraction-job.ts +69 -0
  265. package/src/memory/graph/extraction.test.ts +936 -0
  266. package/src/memory/graph/extraction.ts +1254 -0
  267. package/src/memory/graph/graph-search.ts +266 -0
  268. package/src/memory/graph/image-ref-utils.ts +29 -0
  269. package/src/memory/graph/injection.test.ts +513 -0
  270. package/src/memory/graph/injection.ts +439 -0
  271. package/src/memory/graph/inspect.ts +534 -0
  272. package/src/memory/graph/narrative.ts +267 -0
  273. package/src/memory/graph/pattern-scan.ts +269 -0
  274. package/src/memory/graph/retriever.ts +1008 -0
  275. package/src/memory/graph/scoring.test.ts +548 -0
  276. package/src/memory/graph/scoring.ts +232 -0
  277. package/src/memory/graph/serendipity.ts +65 -0
  278. package/src/memory/graph/store.test.ts +1050 -0
  279. package/src/memory/graph/store.ts +699 -0
  280. package/src/memory/graph/tool-handlers.ts +426 -0
  281. package/src/memory/graph/tools.ts +141 -0
  282. package/src/memory/graph/triggers.test.ts +487 -0
  283. package/src/memory/graph/triggers.ts +223 -0
  284. package/src/memory/graph/types.ts +271 -0
  285. package/src/memory/group-crud.ts +191 -0
  286. package/src/memory/indexer.ts +37 -19
  287. package/src/memory/job-handlers/cleanup.ts +0 -53
  288. package/src/memory/job-handlers/conversation-starters.ts +91 -53
  289. package/src/memory/job-handlers/embedding.ts +5 -31
  290. package/src/memory/job-handlers/index-maintenance.ts +23 -11
  291. package/src/memory/job-handlers/summarization.ts +32 -17
  292. package/src/memory/job-utils.ts +1 -1
  293. package/src/memory/jobs-store.ts +50 -70
  294. package/src/memory/jobs-worker.ts +147 -112
  295. package/src/memory/message-content.ts +1 -0
  296. package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
  297. package/src/memory/migrations/203-drop-memory-items-tables.ts +23 -0
  298. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
  299. package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
  300. package/src/memory/migrations/index.ts +4 -0
  301. package/src/memory/migrations/registry.ts +8 -0
  302. package/src/memory/qdrant-client.ts +44 -17
  303. package/src/memory/schema/index.ts +1 -0
  304. package/src/memory/schema/memory-graph.ts +139 -0
  305. package/src/memory/search/semantic.ts +47 -91
  306. package/src/memory/task-memory-cleanup.ts +28 -50
  307. package/src/messaging/providers/outlook/adapter.ts +8 -1
  308. package/src/messaging/providers/outlook/client.ts +299 -0
  309. package/src/messaging/providers/outlook/types.ts +118 -0
  310. package/src/notifications/adapters/macos.ts +1 -0
  311. package/src/notifications/copy-composer.ts +9 -0
  312. package/src/notifications/signal.ts +16 -0
  313. package/src/oauth/seed-providers.ts +2 -1
  314. package/src/permissions/checker.ts +24 -3
  315. package/src/permissions/defaults.ts +4 -4
  316. package/src/permissions/workspace-policy.ts +1 -1
  317. package/src/playbooks/playbook-compiler.ts +19 -18
  318. package/src/playbooks/types.ts +4 -3
  319. package/src/prompts/system-prompt.ts +3 -29
  320. package/src/providers/anthropic/client.ts +47 -19
  321. package/src/providers/gemini/client.ts +1 -1
  322. package/src/providers/openai/client.ts +1 -1
  323. package/src/providers/registry.ts +1 -1
  324. package/src/providers/retry.ts +19 -3
  325. package/src/runtime/actor-trust-resolver.ts +5 -1
  326. package/src/runtime/auth/route-policy.ts +7 -0
  327. package/src/runtime/guardian-reply-router.ts +5 -1
  328. package/src/runtime/http-server.ts +23 -3
  329. package/src/runtime/middleware/auth.ts +20 -0
  330. package/src/runtime/routes/attachment-routes.test.ts +106 -0
  331. package/src/runtime/routes/attachment-routes.ts +106 -16
  332. package/src/runtime/routes/brain-graph-routes.ts +21 -22
  333. package/src/runtime/routes/btw-routes.ts +8 -0
  334. package/src/runtime/routes/conversation-management-routes.ts +2 -0
  335. package/src/runtime/routes/conversation-starter-routes.ts +2 -2
  336. package/src/runtime/routes/debug-routes.ts +1 -1
  337. package/src/runtime/routes/global-search-routes.ts +21 -19
  338. package/src/runtime/routes/group-routes.ts +207 -0
  339. package/src/runtime/routes/guardian-action-routes.ts +21 -10
  340. package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
  341. package/src/runtime/routes/inbound-message-handler.ts +19 -0
  342. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
  343. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
  344. package/src/runtime/routes/memory-item-routes.test.ts +2 -14
  345. package/src/runtime/routes/memory-item-routes.ts +341 -388
  346. package/src/runtime/routes/schedule-routes.ts +2 -0
  347. package/src/runtime/routes/skills-routes.ts +103 -37
  348. package/src/runtime/routes/work-items-routes.test.ts +2 -6
  349. package/src/schedule/scheduler.ts +8 -1
  350. package/src/security/oauth2.ts +1 -1
  351. package/src/security/secure-keys.ts +4 -8
  352. package/src/shared/provider-env-vars.ts +19 -0
  353. package/src/skills/catalog-cache.ts +5 -0
  354. package/src/skills/catalog-install.ts +15 -14
  355. package/src/skills/clawhub.ts +134 -154
  356. package/src/skills/install-meta.ts +208 -0
  357. package/src/skills/managed-store.ts +27 -16
  358. package/src/skills/skill-memory.ts +152 -77
  359. package/src/skills/skillssh-registry.ts +19 -17
  360. package/src/tasks/task-runner.ts +3 -1
  361. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
  362. package/src/tools/browser/runtime-check.ts +3 -1
  363. package/src/tools/memory/register.ts +63 -46
  364. package/src/tools/permission-checker.ts +7 -1
  365. package/src/tools/shared/filesystem/image-read.ts +22 -85
  366. package/src/tools/terminal/safe-env.ts +1 -0
  367. package/src/tools/tool-manifest.ts +3 -3
  368. package/src/util/browser.ts +25 -10
  369. package/src/util/bun-runtime.ts +172 -0
  370. package/src/watcher/providers/outlook-calendar.ts +343 -0
  371. package/src/watcher/providers/outlook.ts +198 -0
  372. package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
  373. package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
  374. package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
  375. package/src/workspace/migrations/registry.ts +6 -0
  376. package/src/__tests__/context-memory-e2e.test.ts +0 -415
  377. package/src/__tests__/journal-context.test.ts +0 -268
  378. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
  379. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
  380. package/src/__tests__/memory-query-builder.test.ts +0 -59
  381. package/src/__tests__/memory-recall-quality.test.ts +0 -1046
  382. package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
  383. package/src/__tests__/memory-regressions.test.ts +0 -3696
  384. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
  385. package/src/daemon/conversation-memory.ts +0 -207
  386. package/src/memory/conversation-starters-cadence.ts +0 -74
  387. package/src/memory/items-extractor.ts +0 -860
  388. package/src/memory/job-handlers/batch-extraction.ts +0 -753
  389. package/src/memory/job-handlers/extraction.ts +0 -40
  390. package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -355
  391. package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
  392. package/src/memory/journal-memory.ts +0 -224
  393. package/src/memory/query-builder.ts +0 -47
  394. package/src/memory/query-expansion.ts +0 -83
  395. package/src/memory/retriever.test.ts +0 -1592
  396. package/src/memory/retriever.ts +0 -1331
  397. package/src/memory/search/formatting.test.ts +0 -140
  398. package/src/memory/search/formatting.ts +0 -262
  399. package/src/memory/search/mmr.ts +0 -139
  400. package/src/memory/search/ranking.ts +0 -15
  401. package/src/memory/search/staleness.ts +0 -40
  402. package/src/memory/search/tier-classifier.ts +0 -18
  403. package/src/memory/search/types.ts +0 -121
  404. package/src/prompts/journal-context.ts +0 -154
  405. package/src/tools/memory/definitions.ts +0 -69
  406. package/src/tools/memory/handlers.test.ts +0 -562
  407. package/src/tools/memory/handlers.ts +0 -434
@@ -6,13 +6,25 @@
6
6
  * text stubs to shrink the payload before retrying.
7
7
  */
8
8
 
9
+ import { estimateContentBlockTokens } from "../context/token-estimator.js";
9
10
  import { getSummaryFromContextMessage } from "../context/window-manager.js";
10
11
  import type { ContentBlock, Message } from "../providers/types.js";
11
12
 
13
+ export interface StripMediaOptions {
14
+ /** Token budget available for media in the latest user message. Keeps as
15
+ * many images as fit within this budget instead of the hardcoded limit. */
16
+ mediaTokenBudget?: number;
17
+ /** Provider name for per-image token estimation. */
18
+ providerName?: string;
19
+ }
20
+
12
21
  const RETRY_KEEP_LATEST_MEDIA_BLOCKS = 3;
13
22
  const MAX_MEDIA_STUB_TEXT = 2_000;
14
23
 
15
- export function stripMediaPayloadsForRetry(messages: Message[]): {
24
+ export function stripMediaPayloadsForRetry(
25
+ messages: Message[],
26
+ options?: StripMediaOptions,
27
+ ): {
16
28
  messages: Message[];
17
29
  modified: boolean;
18
30
  replacedBlocks: number;
@@ -31,6 +43,8 @@ export function stripMediaPayloadsForRetry(messages: Message[]): {
31
43
  let modified = false;
32
44
  let replacedBlocks = 0;
33
45
  let keptLatestMediaBlocks = 0;
46
+ let cumulativeMediaTokens = 0;
47
+ const useBudget = options?.mediaTokenBudget != null;
34
48
 
35
49
  const nextMessages = messages.map((msg, msgIndex) => {
36
50
  const nextContent: ContentBlock[] = [];
@@ -39,9 +53,20 @@ export function stripMediaPayloadsForRetry(messages: Message[]): {
39
53
  // few (in the most recent user message) and strip older ones so the
40
54
  // retry can actually reduce context size when images are the cause.
41
55
  if (block.type === "image") {
42
- const keep =
43
- latestUserIndex === msgIndex &&
44
- keptLatestMediaBlocks < RETRY_KEEP_LATEST_MEDIA_BLOCKS;
56
+ let keep = false;
57
+ if (latestUserIndex === msgIndex) {
58
+ if (useBudget) {
59
+ const cost = estimateContentBlockTokens(block, {
60
+ providerName: options!.providerName,
61
+ });
62
+ if (cumulativeMediaTokens + cost <= options!.mediaTokenBudget!) {
63
+ cumulativeMediaTokens += cost;
64
+ keep = true;
65
+ }
66
+ } else {
67
+ keep = keptLatestMediaBlocks < RETRY_KEEP_LATEST_MEDIA_BLOCKS;
68
+ }
69
+ }
45
70
  if (keep) {
46
71
  keptLatestMediaBlocks += 1;
47
72
  nextContent.push(block);
@@ -54,9 +79,20 @@ export function stripMediaPayloadsForRetry(messages: Message[]): {
54
79
  }
55
80
 
56
81
  if (block.type === "file") {
57
- const keep =
58
- latestUserIndex === msgIndex &&
59
- keptLatestMediaBlocks < RETRY_KEEP_LATEST_MEDIA_BLOCKS;
82
+ let keep = false;
83
+ if (latestUserIndex === msgIndex) {
84
+ if (useBudget) {
85
+ const cost = estimateContentBlockTokens(block, {
86
+ providerName: options!.providerName,
87
+ });
88
+ if (cumulativeMediaTokens + cost <= options!.mediaTokenBudget!) {
89
+ cumulativeMediaTokens += cost;
90
+ keep = true;
91
+ }
92
+ } else {
93
+ keep = keptLatestMediaBlocks < RETRY_KEEP_LATEST_MEDIA_BLOCKS;
94
+ }
95
+ }
60
96
  if (keep) {
61
97
  keptLatestMediaBlocks += 1;
62
98
  nextContent.push(block);
@@ -112,6 +148,48 @@ export function stripMediaPayloadsForRetry(messages: Message[]): {
112
148
  };
113
149
  }
114
150
 
151
+ /**
152
+ * Estimate the total token cost of stubs that will replace unconditionally
153
+ * stubbed media blocks (non-latest-user-message images/files and all
154
+ * tool_result-nested media). This lets callers account for stub overhead
155
+ * when computing the available media token budget.
156
+ */
157
+ export function estimateUnconditionalStubTokens(
158
+ messages: Message[],
159
+ options?: { providerName?: string },
160
+ ): number {
161
+ let latestUserIndex: number | null = null;
162
+ for (let i = messages.length - 1; i >= 0; i--) {
163
+ const msg = messages[i];
164
+ if (msg.role !== "user") continue;
165
+ if (isToolResultOnlyMessage(msg)) continue;
166
+ if (getSummaryFromContextMessage(msg) != null) continue;
167
+ latestUserIndex = i;
168
+ break;
169
+ }
170
+
171
+ let stubTokens = 0;
172
+ for (let msgIndex = 0; msgIndex < messages.length; msgIndex++) {
173
+ const msg = messages[msgIndex];
174
+ for (const block of msg.content) {
175
+ if (block.type === "image" && msgIndex !== latestUserIndex) {
176
+ stubTokens += estimateContentBlockTokens(imageBlockToStub(block), options);
177
+ } else if (block.type === "file" && msgIndex !== latestUserIndex) {
178
+ stubTokens += estimateContentBlockTokens(fileBlockToStub(block), options);
179
+ } else if (block.type === "tool_result" && block.contentBlocks) { // guard:allow-tool-result-only — web_search_tool_result has no contentBlocks
180
+ for (const cb of block.contentBlocks) {
181
+ if (cb.type === "image") {
182
+ stubTokens += estimateContentBlockTokens(imageBlockToStub(cb), options);
183
+ } else if (cb.type === "file") {
184
+ stubTokens += estimateContentBlockTokens(fileBlockToStub(cb), options);
185
+ }
186
+ }
187
+ }
188
+ }
189
+ }
190
+ return stubTokens;
191
+ }
192
+
115
193
  function imageBlockToStub(
116
194
  block: Extract<ContentBlock, { type: "image" }>,
117
195
  ): Extract<ContentBlock, { type: "text" }> {
@@ -99,6 +99,7 @@ export function registerConversationNotifiers(
99
99
  ctx.sendToClient({
100
100
  type: "message_complete",
101
101
  conversationId: conversationId,
102
+ messageId: msg.id,
102
103
  });
103
104
  }
104
105
  },
@@ -133,6 +134,7 @@ export function registerConversationNotifiers(
133
134
  ctx.sendToClient({
134
135
  type: "message_complete",
135
136
  conversationId: conversationId,
137
+ messageId: msg.id,
136
138
  });
137
139
  }
138
140
  },
@@ -145,7 +147,7 @@ export function registerConversationNotifiers(
145
147
  const callee = callSession?.toNumber ?? "the caller";
146
148
  const questionText = `**Live call question** (to ${callee}):\n\n${question}\n\n_Use the call answer API to respond._`;
147
149
 
148
- await addMessage(
150
+ const msg = await addMessage(
149
151
  conversationId,
150
152
  "assistant",
151
153
  JSON.stringify([{ type: "text", text: questionText }]),
@@ -168,6 +170,7 @@ export function registerConversationNotifiers(
168
170
  ctx.sendToClient({
169
171
  type: "message_complete",
170
172
  conversationId: conversationId,
173
+ messageId: msg.id,
171
174
  });
172
175
  },
173
176
  );
@@ -1049,6 +1049,11 @@ const RUNTIME_INJECTION_PREFIXES = [
1049
1049
  "<turn_context>",
1050
1050
  "<memory_context __injected>",
1051
1051
  "<memory_context>", // backward-compat: strip legacy blocks from pre-__injected history
1052
+ // NOTE: <memory __injected> is intentionally NOT stripped — memory
1053
+ // injections persist in history so the assistant can reference them.
1054
+ // Context compaction handles these blocks during history reduction, and
1055
+ // the InContextTracker deduplicates nodes across turns, so accumulation
1056
+ // does not cause unbounded context growth.
1052
1057
  "<voice_call_control>",
1053
1058
  "<workspace_top_level>",
1054
1059
  TEMPORAL_INJECTED_PREFIX,
@@ -44,6 +44,7 @@ import { registerToolTraceListener } from "../events/tool-trace-listener.js";
44
44
  import { getHookManager } from "../hooks/manager.js";
45
45
  import { resolveCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
46
46
  import { updateConversationContextWindow } from "../memory/conversation-crud.js";
47
+ import { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
47
48
  import { PermissionPrompter } from "../permissions/prompter.js";
48
49
  import { SecretPrompter } from "../permissions/secret-prompter.js";
49
50
  import { patternMatchesCandidate } from "../permissions/trust-store.js";
@@ -57,6 +58,7 @@ import type { AuthContext } from "../runtime/auth/types.js";
57
58
  import * as approvalOverrides from "../runtime/conversation-approval-overrides.js";
58
59
  import * as pendingInteractions from "../runtime/pending-interactions.js";
59
60
  import { ToolExecutor } from "../tools/executor.js";
61
+ import { getLogger } from "../util/logger.js";
60
62
  import type { AssistantAttachmentDraft } from "./assistant-attachments.js";
61
63
  import { runAgentLoopImpl } from "./conversation-agent-loop.js";
62
64
  import type { HistoryConversationContext } from "./conversation-history.js";
@@ -118,6 +120,8 @@ import type {
118
120
  } from "./message-types/messages.js";
119
121
  import { TraceEmitter } from "./trace-emitter.js";
120
122
 
123
+ const log = getLogger("conversation");
124
+
121
125
  export interface ConversationMemoryPolicy {
122
126
  scopeId: string;
123
127
  includeDefaultFallback: boolean;
@@ -243,6 +247,7 @@ export class Conversation {
243
247
  public readonly traceEmitter: TraceEmitter;
244
248
  public readonly hasSystemPromptOverride: boolean;
245
249
  public memoryPolicy: ConversationMemoryPolicy;
250
+ /** @internal */ readonly graphMemory: ConversationGraphMemory;
246
251
  /** @internal */ streamThinking: boolean;
247
252
  /** @internal */ turnCount = 0;
248
253
  public lastAssistantAttachments: AssistantAttachmentDraft[] = [];
@@ -251,6 +256,8 @@ export class Conversation {
251
256
  /** @internal */ currentTurnInterfaceContext: TurnInterfaceContext | null =
252
257
  null;
253
258
  /** @internal */ activityVersion = 0;
259
+ /** Last emitted activity state message, retained for replay on SSE reconnection. */
260
+ /** @internal */ lastActivityStateMsg: ServerMessage | null = null;
254
261
  /** Set by the agent loop to track confirmation outcomes for persistence. */
255
262
  onConfirmationOutcome?: (
256
263
  requestId: string,
@@ -280,6 +287,10 @@ export class Conversation {
280
287
  this.memoryPolicy = memoryPolicy
281
288
  ? { ...memoryPolicy }
282
289
  : { ...DEFAULT_MEMORY_POLICY };
290
+ this.graphMemory = new ConversationGraphMemory(
291
+ this.memoryPolicy.scopeId,
292
+ conversationId,
293
+ );
283
294
  this.traceEmitter = new TraceEmitter(conversationId, sendToClient);
284
295
  this.prompter = new PermissionPrompter(sendToClient);
285
296
  this.prompter.setOnStateChanged((requestId, state, source, toolUseId) => {
@@ -486,6 +497,19 @@ export class Conversation {
486
497
  this.hostCuProxy?.updateSender(sendToClient, !hasNoClient);
487
498
  this.hostFileProxy?.updateSender(sendToClient, !hasNoClient);
488
499
  }
500
+
501
+ // Replay last activity state so a reconnecting client sees the current phase
502
+ // instead of being stuck on the last state it received before disconnection.
503
+ if (!hasNoClient && this.lastActivityStateMsg) {
504
+ try {
505
+ sendToClient(this.lastActivityStateMsg);
506
+ } catch (err) {
507
+ log.warn(
508
+ { err, conversationId: this.conversationId },
509
+ "Failed to replay activity state on client reconnection",
510
+ );
511
+ }
512
+ }
489
513
  }
490
514
 
491
515
  /** Returns the current sendToClient reference for identity comparison. */
@@ -862,7 +886,14 @@ export class Conversation {
862
886
  type: "confirmation_state_changed",
863
887
  ...params,
864
888
  } as ServerMessage;
865
- this.sendToClient(msg);
889
+ try {
890
+ this.sendToClient(msg);
891
+ } catch (err) {
892
+ log.warn(
893
+ { err, conversationId: this.conversationId },
894
+ "sendToClient threw in emitConfirmationStateChanged",
895
+ );
896
+ }
866
897
  }
867
898
 
868
899
  emitActivityState(
@@ -883,7 +914,15 @@ export class Conversation {
883
914
  reason,
884
915
  ...(statusText ? { statusText } : {}),
885
916
  } as ServerMessage;
886
- this.sendToClient(msg);
917
+ this.lastActivityStateMsg = msg;
918
+ try {
919
+ this.sendToClient(msg);
920
+ } catch (err) {
921
+ log.warn(
922
+ { err, conversationId: this.conversationId },
923
+ "sendToClient threw in emitActivityState",
924
+ );
925
+ }
887
926
  }
888
927
 
889
928
  async forceCompact(): Promise<ContextWindowResult> {
@@ -12,12 +12,14 @@ import { resolve } from "node:path";
12
12
  import { getRuntimeHttpHost, getRuntimeHttpPort } from "../config/env.js";
13
13
  import { getIsContainerized } from "../config/env-registry.js";
14
14
  import { loadOrCreateSigningKey } from "../runtime/auth/token-service.js";
15
+ import { ensureBun } from "../util/bun-runtime.js";
15
16
  import { DaemonError } from "../util/errors.js";
16
17
  import { getLogger } from "../util/logger.js";
17
18
  import {
18
19
  ensureDataDir,
19
20
  getDaemonStartupLockPath,
20
21
  getDaemonStderrLogPath,
22
+ getDataDir,
21
23
  getPidPath,
22
24
  getWorkspaceConfigPath,
23
25
  } from "../util/platform.js";
@@ -371,6 +373,10 @@ async function startDaemonLocked(): Promise<{
371
373
  }
372
374
  }
373
375
 
376
+ // Resolve bun before opening stderrFd to avoid leaking the file
377
+ // descriptor if ensureBun() throws (same pattern as loadOrCreateSigningKey).
378
+ const bunPath = await ensureBun();
379
+
374
380
  // Redirect the child's stderr to a file instead of piping it back to the
375
381
  // parent. A pipe's read end is destroyed when the parent exits, leaving
376
382
  // fd 2 broken in the child. Bun (unlike Node.js) does not ignore SIGPIPE,
@@ -378,7 +384,7 @@ async function startDaemonLocked(): Promise<{
378
384
  const stderrPath = getDaemonStderrLogPath();
379
385
  const stderrFd = openSync(stderrPath, "w");
380
386
 
381
- const child = spawn("bun", ["run", mainPath], {
387
+ const child = spawn(bunPath, ["run", mainPath], {
382
388
  detached: true,
383
389
  stdio: ["ignore", "ignore", stderrFd],
384
390
  env: spawnEnv,
@@ -413,7 +419,7 @@ async function startDaemonLocked(): Promise<{
413
419
  const stderr = readFileSync(stderrPath, "utf-8").trim();
414
420
  const detail = stderr
415
421
  ? `\n${stderr}`
416
- : `\nCheck logs at ~/.vellum/workspace/data/logs/ for details.`;
422
+ : `\nCheck logs at ${getDataDir()}/logs/ for details.`;
417
423
  throw new DaemonError(
418
424
  `Daemon exited immediately (code ${
419
425
  childExitCode ?? "unknown"
@@ -60,8 +60,10 @@ export interface HistoryToolCall {
60
60
  input: Record<string, unknown>;
61
61
  result?: string;
62
62
  isError?: boolean;
63
- /** Base64-encoded image data from tool contentBlocks (e.g. browser_screenshot). */
63
+ /** Base64-encoded image data from tool contentBlocks (e.g. browser_screenshot). @deprecated Use imageDataList. */
64
64
  imageData?: string;
65
+ /** Base64-encoded image data from tool contentBlocks (e.g. browser_screenshot, image generation). */
66
+ imageDataList?: string[];
65
67
  /** Unix ms when the tool started executing. */
66
68
  startedAt?: number;
67
69
  /** Unix ms when the tool completed. */
@@ -341,16 +343,19 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
341
343
  const resultContent =
342
344
  typeof block.content === "string" ? block.content : "";
343
345
  const isError = block.is_error === true;
344
- // Extract base64 image data from persisted contentBlocks (e.g. browser_screenshot)
345
- let imageData: string | undefined;
346
+ // Extract base64 image data from persisted contentBlocks (e.g. browser_screenshot, image generation)
347
+ const imageDataList: string[] = [];
346
348
  if (Array.isArray(block.contentBlocks)) {
347
- const imgBlock = block.contentBlocks.find(
348
- (b: Record<string, unknown>) => isRecord(b) && b.type === "image",
349
- );
350
- if (imgBlock && isRecord(imgBlock) && isRecord(imgBlock.source)) {
351
- const src = imgBlock.source as Record<string, unknown>;
352
- if (typeof src.data === "string") {
353
- imageData = src.data;
349
+ for (const cb of block.contentBlocks) {
350
+ if (
351
+ isRecord(cb) &&
352
+ cb.type === "image" &&
353
+ isRecord(cb.source) &&
354
+ typeof (cb.source as Record<string, unknown>).data === "string"
355
+ ) {
356
+ imageDataList.push(
357
+ (cb.source as Record<string, unknown>).data as string,
358
+ );
354
359
  }
355
360
  }
356
361
  }
@@ -358,14 +363,19 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
358
363
  if (matched) {
359
364
  matched.result = resultContent;
360
365
  matched.isError = isError;
361
- if (imageData) matched.imageData = imageData;
366
+ if (imageDataList.length > 0) {
367
+ matched.imageData = imageDataList[0];
368
+ matched.imageDataList = imageDataList;
369
+ }
362
370
  } else {
363
371
  toolCalls.push({
364
372
  name: "unknown",
365
373
  input: {},
366
374
  result: resultContent,
367
375
  isError,
368
- ...(imageData ? { imageData } : {}),
376
+ ...(imageDataList.length > 0
377
+ ? { imageData: imageDataList[0], imageDataList }
378
+ : {}),
369
379
  });
370
380
  }
371
381
  continue;