@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
@@ -14,19 +14,19 @@ import { registerPlatformDisconnectCommand } from "./disconnect.js";
14
14
  export function registerPlatformCommand(program: Command): void {
15
15
  const platform = program
16
16
  .command("platform")
17
- .description("Manage platform integration for containerized deployments")
17
+ .description("Manage Vellum Platform integration")
18
18
  .option("--json", "Machine-readable compact JSON output");
19
19
 
20
20
  platform.addHelpText(
21
21
  "after",
22
22
  `
23
- The platform subsystem manages the connection to Vellum Platform, callback
24
- routing, containerized deployment context, and webhook forwarding for
25
- assistants. Use 'connect', 'status', and 'disconnect' to manage platform
26
- credentials. When IS_CONTAINERIZED=true with a configured VELLUM_PLATFORM_URL
27
- and PLATFORM_ASSISTANT_ID, external service callbacks (Telegram webhooks,
28
- Twilio webhooks, OAuth redirects) route through the platform's gateway proxy
29
- instead of hitting the assistant directly.
23
+ The platform subsystem manages the connection to Vellum Platform. Use
24
+ 'connect', 'status', and 'disconnect' to manage platform credentials.
25
+ Any assistant using the managed LLM proxy can use these commands.
26
+
27
+ When IS_PLATFORM=true (platform-managed deployments), external service
28
+ callbacks (Telegram webhooks, Twilio webhooks, OAuth redirects) also
29
+ route through the platform's gateway proxy via 'callback-routes'.
30
30
 
31
31
  Examples:
32
32
  $ assistant platform status --json
@@ -54,11 +54,11 @@ Examples:
54
54
  "after",
55
55
  `
56
56
  Reads platform-related environment variables and stored credentials to report
57
- the current containerized deployment context and connection state. Does not
57
+ the current platform deployment context and connection state. Does not
58
58
  require the assistant to be running.
59
59
 
60
60
  Fields:
61
- containerized Whether IS_CONTAINERIZED is set (boolean)
61
+ isPlatform Whether IS_PLATFORM is set (boolean)
62
62
  baseUrl VELLUM_PLATFORM_URL — the platform gateway base URL
63
63
  assistantId PLATFORM_ASSISTANT_ID — this assistant's platform UUID
64
64
  hasInternalApiKey Whether PLATFORM_INTERNAL_API_KEY is set (boolean,
@@ -112,7 +112,7 @@ Examples:
112
112
  const connected = !!storedBaseUrl && hasStoredApiKey;
113
113
 
114
114
  const result = {
115
- containerized: context.containerized,
115
+ isPlatform: context.isPlatform,
116
116
  baseUrl: context.platformBaseUrl,
117
117
  assistantId: context.assistantId,
118
118
  hasInternalApiKey: context.hasInternalApiKey,
@@ -126,7 +126,7 @@ Examples:
126
126
  if (shouldOutputJson(cmd)) {
127
127
  writeOutput(cmd, result);
128
128
  } else {
129
- log.info(`Containerized: ${result.containerized}`);
129
+ log.info(`Platform: ${result.isPlatform}`);
130
130
  log.info(`Base URL: ${result.baseUrl || "(not set)"}`);
131
131
  log.info(`Assistant ID: ${result.assistantId || "(not set)"}`);
132
132
  log.info(
@@ -167,7 +167,7 @@ Examples:
167
167
  "after",
168
168
  `
169
169
  Callback routes tell the platform gateway how to forward inbound provider
170
- webhooks to the correct containerized assistant instance. Each route maps a
170
+ webhooks to the correct platform-managed assistant instance. Each route maps a
171
171
  callback path and type to a stable external URL that external services
172
172
  (Telegram, Twilio, OAuth providers) should use.
173
173
 
@@ -196,7 +196,7 @@ Examples:
196
196
  `
197
197
  Registers a callback route with the platform's internal gateway endpoint so
198
198
  the platform knows how to forward inbound provider webhooks to this
199
- containerized assistant instance.
199
+ platform-managed assistant instance.
200
200
 
201
201
  Arguments:
202
202
  --path The path portion after the ingress base URL. Leading/trailing
@@ -210,7 +210,7 @@ Known callback path/type combinations:
210
210
  --path webhooks/twilio/status --type twilio_status
211
211
  --path oauth/callback --type oauth
212
212
 
213
- Requires a containerized environment (IS_CONTAINERIZED=true) with
213
+ Requires a platform-managed environment (IS_PLATFORM=true) with
214
214
  VELLUM_PLATFORM_URL and PLATFORM_ASSISTANT_ID configured. Returns the
215
215
  platform-provided stable callback URL that external services should use.
216
216
 
@@ -225,7 +225,7 @@ Examples:
225
225
  writeOutput(cmd, {
226
226
  ok: false,
227
227
  error:
228
- "Platform callbacks not available — missing containerized platform registration context",
228
+ "Platform callbacks not available — missing platform registration context",
229
229
  });
230
230
  process.exitCode = 1;
231
231
  return;
@@ -12,6 +12,7 @@ import {
12
12
  uninstallSkillLocally,
13
13
  } from "../../skills/catalog-install.js";
14
14
  import { filterByQuery } from "../../skills/catalog-search.js";
15
+ import { clawhubSearch } from "../../skills/clawhub.js";
15
16
  import type {
16
17
  AuditResponse,
17
18
  SkillsShSearchResult,
@@ -111,7 +112,9 @@ Examples:
111
112
 
112
113
  skills
113
114
  .command("search <query>")
114
- .description("Search the Vellum catalog and skills.sh community registry")
115
+ .description(
116
+ "Search the Vellum catalog, skills.sh, and clawhub community registries",
117
+ )
115
118
  .option("--limit <n>", "Maximum number of community results", "10")
116
119
  .option("--json", "Machine-readable JSON output")
117
120
  .addHelpText(
@@ -119,11 +122,11 @@ Examples:
119
122
  `
120
123
  Arguments:
121
124
  query Free-text search term matched against skill names, descriptions,
122
- and tags. Searches the Vellum catalog first, then the skills.sh
123
- community registry.
125
+ and tags. Searches the Vellum catalog, the skills.sh community
126
+ registry, and the clawhub registry.
124
127
 
125
- Displays results from both sources with clear labels. When a skill ID
126
- exists in both the Vellum catalog and the community registry, a conflict
128
+ Displays results from all sources with clear labels. When a skill ID
129
+ exists in both the Vellum catalog and a community registry, a conflict
127
130
  note is shown with guidance on which install command to use.
128
131
 
129
132
  Examples:
@@ -155,32 +158,64 @@ Examples:
155
158
  (s) => s.description,
156
159
  ]);
157
160
 
158
- // ── Community registry search (non-fatal on failure) ─────────
161
+ // ── Community registry searches (non-fatal on failure) ────────
162
+ // Run skills.sh and clawhub searches in parallel.
159
163
  let registryResults: SkillsShSearchResult[] = [];
160
164
  let registryError: string | undefined;
161
- try {
162
- registryResults = await searchSkillsRegistry(query, limit);
163
- } catch (err) {
164
- registryError = err instanceof Error ? err.message : String(err);
165
+ let clawhubResults: Awaited<
166
+ ReturnType<typeof clawhubSearch>
167
+ >["skills"] = [];
168
+ let clawhubError: string | undefined;
169
+
170
+ const [skillsShResult, clawhubResult] = await Promise.allSettled([
171
+ searchSkillsRegistry(query, limit),
172
+ clawhubSearch(query, { limit }),
173
+ ]);
174
+
175
+ if (skillsShResult.status === "fulfilled") {
176
+ registryResults = skillsShResult.value;
177
+ } else {
178
+ registryError =
179
+ skillsShResult.reason instanceof Error
180
+ ? skillsShResult.reason.message
181
+ : String(skillsShResult.reason);
182
+ }
183
+
184
+ if (clawhubResult.status === "fulfilled") {
185
+ clawhubResults = clawhubResult.value.skills;
186
+ } else {
187
+ clawhubError =
188
+ clawhubResult.reason instanceof Error
189
+ ? clawhubResult.reason.message
190
+ : String(clawhubResult.reason);
165
191
  }
166
192
 
167
193
  // ── Conflict detection ───────────────────────────────────────
168
194
  const catalogIds = new Set(catalogMatches.map((s) => s.id));
169
- const conflictIds = new Set(
170
- registryResults
195
+ const conflictIds = new Set([
196
+ ...registryResults
171
197
  .filter((r) => catalogIds.has(r.skillId))
172
198
  .map((r) => r.skillId),
173
- );
199
+ ...clawhubResults
200
+ .filter((r) => catalogIds.has(r.slug))
201
+ .map((r) => r.slug),
202
+ ]);
174
203
 
175
- if (catalogMatches.length === 0 && registryResults.length === 0) {
204
+ if (
205
+ catalogMatches.length === 0 &&
206
+ registryResults.length === 0 &&
207
+ clawhubResults.length === 0
208
+ ) {
176
209
  if (json) {
177
210
  console.log(
178
211
  JSON.stringify({
179
212
  ok: true,
180
213
  catalog: [],
181
214
  community: [],
215
+ clawhub: [],
182
216
  audits: {},
183
217
  ...(registryError ? { registryError } : {}),
218
+ ...(clawhubError ? { clawhubError } : {}),
184
219
  }),
185
220
  );
186
221
  } else {
@@ -188,6 +223,9 @@ Examples:
188
223
  if (registryError) {
189
224
  log.warn(`(skills.sh registry unavailable: ${registryError})`);
190
225
  }
226
+ if (clawhubError) {
227
+ log.warn(`(clawhub registry unavailable: ${clawhubError})`);
228
+ }
191
229
  }
192
230
  return;
193
231
  }
@@ -219,8 +257,10 @@ Examples:
219
257
  ok: true,
220
258
  catalog: catalogMatches,
221
259
  community: registryResults,
260
+ clawhub: clawhubResults,
222
261
  audits: allAudits,
223
262
  ...(registryError ? { registryError } : {}),
263
+ ...(clawhubError ? { clawhubError } : {}),
224
264
  }),
225
265
  );
226
266
  return;
@@ -280,6 +320,38 @@ Examples:
280
320
  } else if (registryError) {
281
321
  log.warn(`\n(skills.sh registry unavailable: ${registryError})`);
282
322
  }
323
+
324
+ // ── Display clawhub results ─────────────────────────────────
325
+ if (clawhubResults.length > 0) {
326
+ log.info(`Clawhub registry (${clawhubResults.length}):\n`);
327
+ for (const r of clawhubResults) {
328
+ const installed = isInstalled(r.slug);
329
+ const badge = installed ? " [installed]" : "";
330
+ log.info(` ${r.name}${badge}`);
331
+ if (r.name !== r.slug) {
332
+ log.info(` ID: ${r.slug}`);
333
+ }
334
+ if (r.author) {
335
+ log.info(` Author: ${r.author}`);
336
+ }
337
+ if (r.description) {
338
+ log.info(` Description: ${r.description}`);
339
+ }
340
+ if (r.stars > 0) {
341
+ log.info(` Stars: ${r.stars}`);
342
+ }
343
+ if (r.installs > 0) {
344
+ log.info(` Installs: ${r.installs}`);
345
+ }
346
+ log.info(` Install: npx clawhub install ${r.slug}`);
347
+ if (conflictIds.has(r.slug)) {
348
+ log.info(` NOTE: Conflicts with Vellum catalog skill`);
349
+ }
350
+ log.info("");
351
+ }
352
+ } else if (clawhubError) {
353
+ log.warn(`\n(clawhub registry unavailable: ${clawhubError})`);
354
+ }
283
355
  } catch (err) {
284
356
  const msg = err instanceof Error ? err.message : String(err);
285
357
  if (json) {
@@ -416,8 +488,8 @@ Arguments:
416
488
 
417
489
  Notes:
418
490
  Fetches the skill's SKILL.md and supporting files from the specified GitHub
419
- repository and installs them into the workspace skills directory. A
420
- version.json file is written with origin metadata for provenance tracking.
491
+ repository and installs them into the workspace skills directory. An
492
+ install-meta.json file is written with origin metadata for provenance tracking.
421
493
 
422
494
  Examples:
423
495
  $ assistant skills add vercel-labs/skills@find-skills
@@ -18,7 +18,7 @@ export function registerTrustCommand(program: Command): void {
18
18
  Trust rules are pattern-based decisions (allow/deny) for tool invocations.
19
19
  Each rule specifies a tool name, a command pattern matched with glob syntax,
20
20
  a scope, a decision (allow or deny), and a priority. Rules are stored in
21
- ~/.vellum/protected/trust.json and evaluated in priority order when the
21
+ the protected directory (trust.json) and evaluated in priority order when the
22
22
  assistant invokes a tool.
23
23
 
24
24
  Examples:
@@ -141,7 +141,7 @@ Examples:
141
141
  .addHelpText(
142
142
  "after",
143
143
  `
144
- Removes every trust rule from ~/.vellum/protected/trust.json. Prompts for
144
+ Removes every trust rule from the protected directory (trust.json). Prompts for
145
145
  confirmation before proceeding (y/N). This action is irreversible — all
146
146
  rules must be re-created manually after clearing.
147
147
 
@@ -7,7 +7,6 @@
7
7
  * (health check, JWT minting, HTTP call).
8
8
  */
9
9
 
10
- import providerEnvVarsRegistry from "../../../../meta/provider-env-vars.json" with { type: "json" };
11
10
  import { getRuntimeHttpHost, getRuntimeHttpPort } from "../../config/env.js";
12
11
  import { API_KEY_PROVIDERS } from "../../config/loader.js";
13
12
  import { healthCheckHost, isHttpHealthy } from "../../daemon/daemon-control.js";
@@ -25,13 +24,13 @@ import {
25
24
  getSecureKeyResultAsync,
26
25
  setSecureKeyAsync,
27
26
  } from "../../security/secure-keys.js";
27
+ import { PROVIDER_ENV_VAR_NAMES } from "../../shared/provider-env-vars.js";
28
28
  import { getLogger } from "../../util/logger.js";
29
29
 
30
30
  const log = getLogger("daemon-credential-client");
31
31
  const CREDENTIAL_KEY_PREFIX = "credential/";
32
32
 
33
- const PROVIDER_ENV_VARS: Record<string, string> =
34
- providerEnvVarsRegistry.providers;
33
+ const PROVIDER_ENV_VARS: Record<string, string> = PROVIDER_ENV_VAR_NAMES;
35
34
 
36
35
  // ---------------------------------------------------------------------------
37
36
  // Private daemon fetch helper
@@ -5,7 +5,7 @@
5
5
  "name": "acp_spawn",
6
6
  "description": "Spawn an external coding agent (e.g. Claude Code, Codex, Gemini CLI) via ACP to work on a task. The agent runs as a subprocess and streams results back. Use this when you want to delegate a coding task to an external agent that has its own tools, file editing, and terminal access. If ACP is not enabled, follow the setup instructions in SKILL.md to install claude-agent-acp and configure it. The command MUST be 'claude-agent-acp' - NEVER use 'claude', 'claude -p', or 'claude --acp'.",
7
7
  "category": "orchestration",
8
- "risk": "low",
8
+ "risk": "high",
9
9
  "input_schema": {
10
10
  "type": "object",
11
11
  "properties": {
@@ -6,7 +6,6 @@ metadata:
6
6
  emoji: "👥"
7
7
  vellum:
8
8
  display-name: "Contacts"
9
- feature-flag: "contacts"
10
9
  ---
11
10
 
12
11
  Manage the user's contacts, relationship graph, access control (trusted contacts), and invite links. This skill covers contact CRUD with multi-channel tracking, controlling who can message the assistant through external channels (Telegram, phone), and creating/managing invite links that grant access.
@@ -47,14 +47,6 @@
47
47
  "is_primary": {
48
48
  "type": "boolean",
49
49
  "description": "Whether this is the primary channel for this type"
50
- },
51
- "external_user_id": {
52
- "type": "string",
53
- "description": "Platform-native user ID (e.g. Slack user ID like U12345). Used to cache user lookups."
54
- },
55
- "external_chat_id": {
56
- "type": "string",
57
- "description": "Platform-native chat/DM channel ID (e.g. Slack DM channel like D12345). Used to cache DM channel lookups."
58
50
  }
59
51
  },
60
52
  "required": ["type", "address"]
@@ -63,16 +63,12 @@ export async function executeContactUpsert(
63
63
  type: string;
64
64
  address: string;
65
65
  is_primary?: boolean;
66
- external_user_id?: string;
67
- external_chat_id?: string;
68
66
  }>
69
67
  | undefined;
70
68
  const channels = rawChannels?.map((ch) => ({
71
69
  type: ch.type,
72
70
  address: ch.address,
73
71
  isPrimary: ch.is_primary,
74
- externalUserId: ch.external_user_id,
75
- externalChatId: ch.external_chat_id,
76
72
  }));
77
73
 
78
74
  try {
@@ -28,22 +28,14 @@ Do not offer AgentMail as an option or mention it unless the user specifically a
28
28
  ### Gmail
29
29
 
30
30
  1. **Try connecting directly first.** Run `assistant oauth status google`. This will show whether or not the user had previously connected their google account. If so, they are ready to go.
31
- 2. **If no connections are found:** The user needs to either use Vellum's managed google integration or set up their own google oauth app.
32
- - Call `skill_load` with `skill: "vellum-oauth-integrations"` with `provider-key: google` throughout.
33
- - To use `your-own` mode, you will need to call `skill_load` with `skill: google-oauth-app-setup`. In this case:
34
- - Tell the user Gmail isn't connected yet and briefly explain what the setup involves, then use `ui_show` with `surface_type: "confirmation"` to ask for permission to start:
35
- - **message:** "Ready to set up Gmail?"
36
- - **detail:** "I'll open a few pages in your browser and walk you through setting up Google Cloud credentials - creating a project, enabling APIs, and connecting your account. Takes about 5 minutes.\n\n**Your emails stay under your control** — I only ever create drafts. Nothing gets sent without your explicit say-so."
37
- - **confirmLabel:** "Get Started"
38
- - **cancelLabel:** "Not Now"
39
- - If the user confirms, briefly acknowledge (e.g., "Setting up Gmail now...") and proceed with the setup guide. If they decline, acknowledge and let them know they can set it up later.
31
+ 2. **If no connections are found:** Call `skill_load` with `skill: "vellum-oauth-integrations"`. The skill will evaluate whether managed or your-own mode is appropriate and guide the user accordingly.
40
32
 
41
33
  ## Error Recovery
42
34
 
43
35
  When a Gmail tool fails with a token or authorization error:
44
36
 
45
37
  1. **Try to reconnect silently.** Call `assistant oauth ping google`. This often resolves expired tokens automatically.
46
- 2. **If reconnection fails, go straight to setup.** Don't present options, ask which route the user prefers, or explain what went wrong technically. Just tell the user briefly (e.g., "Gmail needs to be reconnected - let me set that up") and immediately follow the connection setup flow for Gmail (e.g., install and load **google-oauth-app-setup**). The user came to you to get something done, not to troubleshoot OAuth - make it seamless.
38
+ 2. **If reconnection fails, go straight to setup.** Don't present options, ask which route the user prefers, or explain what went wrong technically. Just tell the user briefly (e.g., "Gmail needs to be reconnected - let me set that up") and immediately load **vellum-oauth-integrations**. The user came to you to get something done, not to troubleshoot OAuth - make it seamless.
47
39
  3. **Never try alternative approaches.** Don't use bash, curl, browser automation, or any workaround. If the Gmail tools can't do it, the reconnection flow is the answer.
48
40
  4. **Never expose error details.** The user doesn't need to see error messages about tokens, OAuth, or API failures. Translate errors into plain language.
49
41
 
@@ -15,15 +15,7 @@ You are a Google Calendar assistant with full access to the user's calendar. Use
15
15
  Before using any Calendar tool, verify that Google Calendar is connected by attempting a lightweight call (e.g., `calendar_list_events` with a narrow date range). If the call fails with a token/authorization error:
16
16
 
17
17
  1. **Try connecting directly first.** Run `assistant oauth status google`. This will show whether or not the user had previously connected their google account. If so, they are ready to go.
18
- 2. **If no connections are found:** The user needs to either use Vellum's managed google integration or set up their own google oauth app.
19
- - Call `skill_load` with `skill: "vellum-oauth-integrations"` with `provider-key: google` throughout.
20
- - To use `your-own` mode, you will need to call `skill_load` with `skill: google-oauth-app-setup`. In this case:
21
- - Tell the user Google account isn't connected yet and briefly explain what the setup involves, then use `ui_show` with `surface_type: "confirmation"` to ask for permission to start:
22
- - **message:** "Ready to set up Google Calendar?"
23
- - **detail:** "I'll open a few pages in your browser and walk you through setting up Google Cloud credentials - creating a project, enabling APIs, and connecting your account. Takes about 5 minutes.\n\n**Your emails stay under your control** — I only ever create drafts. Nothing gets sent without your explicit say-so."
24
- - **confirmLabel:** "Get Started"
25
- - **cancelLabel:** "Not Now"
26
- - If the user confirms, briefly acknowledge (e.g., "Setting up Google Calendar now...") and proceed with the setup guide. If they decline, acknowledge and let them know they can set it up later.
18
+ 2. **If no connections are found:** Call `skill_load` with `skill: "vellum-oauth-integrations"`. The skill will evaluate whether managed or your-own mode is appropriate and guide the user accordingly.
27
19
 
28
20
  ## Capabilities
29
21
 
@@ -19,13 +19,13 @@ You are a unified messaging assistant with access to multiple platforms (Gmail,
19
19
 
20
20
  When composing messages on behalf of your user to external recipients, refer to yourself as an "assistant" (not "AI assistant"). Use your user's name and pronouns from USER.md. Don't volunteer that you are an AI unless directly asked.
21
21
 
22
- For Gmail management (archive, label, triage, declutter), load the **gmail** skill. For email sequences, load the **sequences** skill.
22
+ For Email management (archive, label, triage, declutter), load the **gmail** or **outlook** skill. For email sequences, load the **sequences** skill.
23
23
 
24
24
  ## Email Routing Priority
25
25
 
26
- When the user mentions "email" - sending, reading, checking, decluttering, drafting, or anything else - **always default to the user's own email (Gmail)** unless they explicitly ask about the assistant's own email address (e.g., "set up your email", "send from your address", "check your inbox"). The vast majority of email requests are about the user's Gmail, not the assistant's AgentMail address.
26
+ When the user mentions "email" - sending, reading, checking, decluttering, drafting, or anything else - **always default to the user's own email** unless they explicitly ask about the assistant's own email address (e.g., "set up your email", "send from your address", "check your inbox"). The vast majority of email requests are about the user's Gmail or Outlook, not the assistant's AgentMail address.
27
27
 
28
- Do not offer AgentMail as an option or mention it unless the user specifically asks. If Gmail is not connected, guide them through Gmail setup - do not suggest AgentMail as an alternative.
28
+ Do not offer AgentMail as an option or mention it unless the user specifically asks. If Gmail and Outlookk are not connected, guide them through setup - do not suggest AgentMail as an alternative.
29
29
 
30
30
  ## Communication Style
31
31
 
@@ -44,33 +44,25 @@ Before using any messaging tool, verify that the platform is connected by callin
44
44
 
45
45
  ### Public Ingress (required for Telegram)
46
46
 
47
- Telegram setup requires webhook routing, but it does **not** always require ngrok. Before suggesting public ingress for Telegram, check managed callback availability with `assistant platform status --json`. If that reports `containerized: true` with a non-empty `assistantId` and `available: true`, use the platform callback route flow and do not prompt for ngrok. Only use the **public-ingress** skill for local assistants that genuinely need a public gateway URL. Slack uses Socket Mode and does not require public ingress. Gmail on the desktop app uses a loopback callback and does not require public ingress; the channel path (Path B in the google-oauth-app-setup skill) handles public ingress internally when needed.
47
+ Telegram setup requires webhook routing, but it does **not** always require ngrok. Before suggesting public ingress for Telegram, check managed callback availability with `assistant platform status --json`. If that reports `isPlatform: true` with a non-empty `assistantId` and `available: true`, use the platform callback route flow and do not prompt for ngrok. Only use the **public-ingress** skill for local assistants that genuinely need a public gateway URL. Slack uses Socket Mode and does not require public ingress. Gmail/Outlook on the desktop app uses a loopback callback and does not require public ingress; the channel path (Path B in the vellum-oauth-integrations skill) handles public ingress internally when needed.
48
48
 
49
49
  ### Email Connection Flow
50
50
 
51
51
  When the user asks to "connect my email", "set up email", "manage my email", or similar - and has not named a specific provider:
52
52
 
53
- 1. **Discover what's connected.** Call `messaging_auth_test` for `gmail` (and any other email-capable platforms). If one succeeds, tell the user it's already connected and proceed with their request.
53
+ 1. **Discover what's connected.** Call `messaging_auth_test` for `gmail`or `outlook` (and any other email-capable platforms). If one succeeds, tell the user it's already connected and proceed with their request.
54
54
  2. **If nothing is connected**, ask which provider they use - but keep it brief and conversational (e.g., "Which email do you use - Gmail, Outlook, etc.?"), not a numbered list of options with descriptions.
55
- 3. **Once the provider is known, act immediately.** Don't present setup options or explain OAuth. If it's Gmail, follow the Gmail section below. For any other provider, let the user know that only Gmail is fully supported right now, and offer to set up Gmail instead.
55
+ 3. **Once the provider is known, act immediately.** Don't present setup options or explain OAuth. If it's Gmail or Outlook, follow the sections below. For any other provider, let the user know that only Gmail and Outlook are fully supported right now, and offer to set up Gmail/Outlook instead.
56
56
 
57
57
  ### Gmail
58
58
 
59
59
  1. **Try connecting directly first.** Run `assistant oauth status google`. This will show whether or not the user had previously connected their google account. If so, they are ready to go.
60
- 2. **If no connections are found:** The user needs to either use Vellum's managed google integration or set up their own google oauth app.
61
- - Call `skill_load` with `skill: "vellum-oauth-integrations"` with `provider-key: google` throughout.
62
- - To use `your-own` mode, you will need to call `skill_load` with `skill: google-oauth-app-setup`. In this case:
63
- - Tell the user Gmail isn't connected yet and briefly explain what the setup involves, then use `ui_show` with `surface_type: "confirmation"` to ask for permission to start:
64
- - **message:** "Ready to set up Gmail?"
65
- - **detail:** "I'll open a few pages in your browser and walk you through setting up Google Cloud credentials - creating a project, enabling APIs, and connecting your account. Takes about 5 minutes."
66
- - **confirmLabel:** "Get Started"
67
- - **cancelLabel:** "Not Now"
68
- - If the user confirms, briefly acknowledge (e.g., "Setting up Gmail now...") and proceed with the setup guide. If they decline, acknowledge and let them know they can set it up later.
60
+ 2. **If no connections are found:** Call `skill_load` with `skill: "vellum-oauth-integrations"`. The skill will evaluate whether managed or your-own mode is appropriate and guide the user accordingly.
69
61
 
70
62
  ### Outlook
71
63
 
72
64
  1. **Try connecting directly first.** Run `assistant oauth status outlook`. This will show whether the user has previously connected their Outlook account.
73
- 2. **If no connections are found:** Guide the user to connect their Microsoft account through the OAuth flow.
65
+ 2. **If no connections are found:** Call `skill_load` with `skill: "vellum-oauth-integrations"`. The skill will evaluate whether managed or your-own mode is appropriate and guide the user accordingly.
74
66
 
75
67
  ### Slack
76
68
 
@@ -101,7 +93,7 @@ The guardian-verify-setup skill handles the full outbound verification flow for
101
93
  When a messaging tool fails with a token or authorization error:
102
94
 
103
95
  1. **Try to reconnect silently.** Run `assistant oauth ping <provider>`. This often resolves expired tokens automatically.
104
- 2. **If reconnection fails, go straight to setup.** Don't present options, ask which route the user prefers, or explain what went wrong technically. Just tell the user briefly (e.g., "Gmail needs to be reconnected - let me set that up") and immediately follow the connection setup flow for that platform (e.g., install and load **google-oauth-app-setup** for Gmail). The user came to you to get something done, not to troubleshoot OAuth - make it seamless.
96
+ 2. **If reconnection fails, go straight to setup.** Don't present options, ask which route the user prefers, or explain what went wrong technically. Just tell the user briefly (e.g., "Gmail needs to be reconnected - let me set that up") and immediately load **vellum-oauth-integrations**. The user came to you to get something done, not to troubleshoot OAuth - make it seamless.
105
97
  3. **Never try alternative approaches.** Don't use bash, curl, browser automation, or any workaround. If the messaging tools can't do it, the reconnection flow is the answer.
106
98
  4. **Never expose error details.** The user doesn't need to see error messages about tokens, OAuth, or API failures. Translate errors into plain language.
107
99
 
@@ -114,7 +106,7 @@ When a messaging tool fails with a token or authorization error:
114
106
 
115
107
  ## Capabilities
116
108
 
117
- ### Universal (Gmail)
109
+ ### Gmail
118
110
 
119
111
  - **Auth Test**: Verify connection and show account info
120
112
  - **List Conversations**: Show inboxes, DMs with unread counts
@@ -1,10 +1,9 @@
1
- import { and, eq } from "drizzle-orm";
1
+ import { and, eq, sql } from "drizzle-orm";
2
2
  import { v4 as uuid } from "uuid";
3
3
 
4
4
  import { getDb } from "../../../../memory/db.js";
5
- import { computeMemoryFingerprint } from "../../../../memory/fingerprint.js";
6
5
  import { enqueueMemoryJob } from "../../../../memory/jobs-store.js";
7
- import { memoryItems } from "../../../../memory/schema.js";
6
+ import { memoryGraphNodes } from "../../../../memory/schema.js";
8
7
  import { clampUnitInterval } from "../../../../memory/validation.js";
9
8
  import { extractStylePatterns } from "../../../../messaging/style-analyzer.js";
10
9
  import type {
@@ -14,6 +13,12 @@ import type {
14
13
  import { truncate } from "../../../../util/truncate.js";
15
14
  import { err, getProviderConnection, ok, resolveProvider } from "./shared.js";
16
15
 
16
+ /** Map legacy caller kinds to valid MemoryType values. */
17
+ const KIND_TO_MEMORY_TYPE: Record<string, string> = {
18
+ style: "behavioral",
19
+ relationship: "semantic",
20
+ };
21
+
17
22
  function upsertMemoryItem(opts: {
18
23
  kind: string;
19
24
  subject: string;
@@ -23,58 +28,60 @@ function upsertMemoryItem(opts: {
23
28
  }): void {
24
29
  const db = getDb();
25
30
  const now = Date.now();
26
- const fingerprint = computeMemoryFingerprint(
27
- opts.scopeId,
28
- opts.kind,
29
- opts.subject,
30
- opts.statement,
31
- );
31
+ const content = `${opts.subject}\n${opts.statement}`;
32
32
 
33
33
  const existing = db
34
34
  .select()
35
- .from(memoryItems)
35
+ .from(memoryGraphNodes)
36
36
  .where(
37
37
  and(
38
- eq(memoryItems.fingerprint, fingerprint),
39
- eq(memoryItems.scopeId, opts.scopeId),
38
+ eq(memoryGraphNodes.content, content),
39
+ eq(memoryGraphNodes.scopeId, opts.scopeId),
40
+ sql`${memoryGraphNodes.fidelity} != 'gone'`,
40
41
  ),
41
42
  )
42
43
  .get();
43
44
 
44
45
  if (existing) {
45
- db.update(memoryItems)
46
+ db.update(memoryGraphNodes)
46
47
  .set({
47
- statement: opts.statement,
48
- status: "active",
49
- importance: clampUnitInterval(
50
- Math.max(existing.importance ?? 0, opts.importance),
48
+ content,
49
+ type: KIND_TO_MEMORY_TYPE[opts.kind] ?? opts.kind,
50
+ fidelity: "vivid",
51
+ significance: clampUnitInterval(
52
+ Math.max(existing.significance ?? 0, opts.importance),
51
53
  ),
52
- lastSeenAt: now,
53
- sourceType: existing.sourceType === "tool" ? "tool" : "extraction",
54
+ lastAccessed: now,
55
+ sourceType: existing.sourceType === "direct" ? "direct" : "inferred",
54
56
  })
55
- .where(eq(memoryItems.id, existing.id))
57
+ .where(eq(memoryGraphNodes.id, existing.id))
56
58
  .run();
57
- enqueueMemoryJob("embed_item", { itemId: existing.id });
59
+ enqueueMemoryJob("embed_graph_node", { nodeId: existing.id });
58
60
  } else {
59
61
  const id = uuid();
60
- db.insert(memoryItems)
62
+ db.insert(memoryGraphNodes)
61
63
  .values({
62
64
  id,
63
- kind: opts.kind,
64
- subject: opts.subject,
65
- statement: opts.statement,
66
- status: "active",
65
+ content,
66
+ type: KIND_TO_MEMORY_TYPE[opts.kind] ?? opts.kind,
67
+ created: now,
68
+ lastAccessed: now,
69
+ lastConsolidated: now,
70
+ emotionalCharge: '{"valence":0,"intensity":0.1,"decayCurve":"linear","decayRate":0.05,"originalIntensity":0.1}',
71
+ fidelity: "vivid",
67
72
  confidence: 0.8,
68
- importance: clampUnitInterval(opts.importance),
69
- fingerprint,
70
- sourceType: "extraction",
73
+ significance: clampUnitInterval(opts.importance),
74
+ stability: 14,
75
+ reinforcementCount: 0,
76
+ lastReinforced: now,
77
+ sourceConversations: "[]",
78
+ sourceType: "inferred",
79
+ narrativeRole: null,
80
+ partOfStory: null,
71
81
  scopeId: opts.scopeId,
72
- firstSeenAt: now,
73
- lastSeenAt: now,
74
- lastUsedAt: null,
75
82
  })
76
83
  .run();
77
- enqueueMemoryJob("embed_item", { itemId: id });
84
+ enqueueMemoryJob("embed_graph_node", { nodeId: id });
78
85
  }
79
86
  }
80
87