@vellumai/assistant 0.4.49 → 0.4.51

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 (353) hide show
  1. package/ARCHITECTURE.md +24 -33
  2. package/README.md +3 -3
  3. package/docs/architecture/integrations.md +2 -2
  4. package/docs/architecture/keychain-broker.md +6 -6
  5. package/docs/architecture/memory.md +180 -119
  6. package/knip.json +32 -0
  7. package/package.json +3 -2
  8. package/src/__tests__/agent-loop.test.ts +3 -1
  9. package/src/__tests__/anthropic-provider.test.ts +114 -23
  10. package/src/__tests__/approval-cascade.test.ts +1 -15
  11. package/src/__tests__/approval-routes-http.test.ts +2 -0
  12. package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
  13. package/src/__tests__/btw-routes.test.ts +61 -5
  14. package/src/__tests__/canonical-guardian-store.test.ts +95 -0
  15. package/src/__tests__/checker.test.ts +13 -0
  16. package/src/__tests__/config-schema.test.ts +1 -68
  17. package/src/__tests__/config-watcher.test.ts +8 -0
  18. package/src/__tests__/context-memory-e2e.test.ts +11 -100
  19. package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
  20. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  21. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  22. package/src/__tests__/credential-security-invariants.test.ts +8 -7
  23. package/src/__tests__/credential-vault-unit.test.ts +23 -18
  24. package/src/__tests__/credential-vault.test.ts +30 -18
  25. package/src/__tests__/credentials-cli.test.ts +257 -82
  26. package/src/__tests__/cu-unified-flow.test.ts +532 -0
  27. package/src/__tests__/date-context.test.ts +93 -77
  28. package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
  29. package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
  30. package/src/__tests__/history-repair.test.ts +245 -0
  31. package/src/__tests__/host-cu-proxy.test.ts +165 -3
  32. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  33. package/src/__tests__/inbound-invite-redemption.test.ts +36 -7
  34. package/src/__tests__/integration-status.test.ts +31 -30
  35. package/src/__tests__/invite-redemption-service.test.ts +166 -13
  36. package/src/__tests__/invite-routes-http.test.ts +166 -5
  37. package/src/__tests__/keychain-broker-client.test.ts +4 -4
  38. package/src/__tests__/list-messages-attachments.test.ts +193 -0
  39. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
  40. package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
  41. package/src/__tests__/memory-recall-quality.test.ts +244 -407
  42. package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
  43. package/src/__tests__/memory-regressions.test.ts +477 -2841
  44. package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
  45. package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
  46. package/src/__tests__/mime-builder.test.ts +28 -0
  47. package/src/__tests__/native-web-search.test.ts +1 -0
  48. package/src/__tests__/oauth-cli.test.ts +824 -31
  49. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  50. package/src/__tests__/oauth-store.test.ts +363 -17
  51. package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
  52. package/src/__tests__/registry.test.ts +0 -1
  53. package/src/__tests__/relay-server.test.ts +55 -1
  54. package/src/__tests__/schedule-tools.test.ts +32 -0
  55. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  56. package/src/__tests__/secret-onetime-send.test.ts +1 -0
  57. package/src/__tests__/secret-routes-managed-proxy.test.ts +183 -0
  58. package/src/__tests__/secure-keys.test.ts +78 -18
  59. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  60. package/src/__tests__/server-history-render.test.ts +2 -2
  61. package/src/__tests__/session-abort-tool-results.test.ts +1 -14
  62. package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
  63. package/src/__tests__/session-agent-loop.test.ts +19 -15
  64. package/src/__tests__/session-confirmation-signals.test.ts +1 -15
  65. package/src/__tests__/session-error.test.ts +124 -2
  66. package/src/__tests__/session-history-web-search.test.ts +918 -0
  67. package/src/__tests__/session-pre-run-repair.test.ts +1 -14
  68. package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
  69. package/src/__tests__/session-queue.test.ts +37 -27
  70. package/src/__tests__/session-runtime-assembly.test.ts +54 -0
  71. package/src/__tests__/session-slash-known.test.ts +1 -15
  72. package/src/__tests__/session-slash-queue.test.ts +1 -15
  73. package/src/__tests__/session-slash-unknown.test.ts +1 -15
  74. package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
  75. package/src/__tests__/session-workspace-injection.test.ts +3 -37
  76. package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
  77. package/src/__tests__/skills-install-extract.test.ts +93 -0
  78. package/src/__tests__/skills.test.ts +2 -2
  79. package/src/__tests__/skillssh-registry.test.ts +451 -0
  80. package/src/__tests__/slack-channel-config.test.ts +10 -8
  81. package/src/__tests__/trust-store.test.ts +15 -0
  82. package/src/__tests__/twilio-config.test.ts +11 -10
  83. package/src/__tests__/twilio-provider.test.ts +9 -4
  84. package/src/__tests__/voice-invite-redemption.test.ts +85 -5
  85. package/src/agent/ax-tree-compaction.test.ts +51 -0
  86. package/src/agent/loop.ts +39 -12
  87. package/src/approvals/AGENTS.md +1 -1
  88. package/src/approvals/guardian-request-resolvers.ts +14 -2
  89. package/src/bundler/compiler-tools.ts +66 -2
  90. package/src/calls/call-domain.ts +134 -3
  91. package/src/calls/call-store.ts +6 -0
  92. package/src/calls/relay-server.ts +44 -6
  93. package/src/calls/relay-setup-router.ts +17 -1
  94. package/src/calls/twilio-config.ts +5 -4
  95. package/src/calls/twilio-provider.ts +14 -9
  96. package/src/calls/twilio-rest.ts +10 -7
  97. package/src/calls/types.ts +3 -1
  98. package/src/cli/commands/config.ts +14 -9
  99. package/src/cli/commands/contacts.ts +3 -0
  100. package/src/cli/commands/credentials.ts +170 -174
  101. package/src/cli/commands/doctor.ts +11 -8
  102. package/src/cli/commands/keys.ts +9 -9
  103. package/src/cli/commands/mcp.ts +46 -59
  104. package/src/cli/commands/memory.ts +16 -165
  105. package/src/cli/commands/oauth/apps.ts +68 -10
  106. package/src/cli/commands/oauth/connections.ts +475 -105
  107. package/src/cli/commands/oauth/index.ts +3 -3
  108. package/src/cli/commands/oauth/providers.ts +18 -4
  109. package/src/cli/commands/sessions.ts +5 -2
  110. package/src/cli/commands/skills.ts +173 -1
  111. package/src/cli/http-client.ts +0 -20
  112. package/src/cli/main-screen.tsx +2 -2
  113. package/src/cli/program.ts +5 -6
  114. package/src/cli.ts +20 -22
  115. package/src/config/__tests__/feature-flag-registry-bundled.test.ts +39 -0
  116. package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
  117. package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
  118. package/src/config/bundled-skills/contacts/SKILL.md +35 -11
  119. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
  120. package/src/config/bundled-skills/gmail/SKILL.md +1 -1
  121. package/src/config/bundled-skills/gmail/TOOLS.json +52 -0
  122. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +13 -3
  123. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +9 -2
  124. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +5 -1
  125. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +5 -1
  126. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +5 -1
  127. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +5 -1
  128. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +9 -2
  129. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +5 -1
  130. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +5 -1
  131. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +5 -1
  132. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +5 -1
  133. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +5 -1
  134. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +5 -1
  135. package/src/config/bundled-skills/google-calendar/TOOLS.json +20 -0
  136. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +2 -1
  137. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +2 -1
  138. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +2 -1
  139. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +2 -1
  140. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +2 -1
  141. package/src/config/bundled-skills/google-calendar/tools/shared.ts +8 -2
  142. package/src/config/bundled-skills/messaging/SKILL.md +1 -1
  143. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
  144. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  145. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +2 -2
  146. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +2 -2
  147. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +2 -2
  148. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +2 -2
  149. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +2 -2
  150. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +2 -2
  151. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -2
  152. package/src/config/bundled-skills/messaging/tools/shared.ts +7 -5
  153. package/src/config/bundled-skills/slack/tools/shared.ts +1 -1
  154. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +1 -1
  155. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +1 -1
  156. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +1 -1
  157. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +1 -1
  158. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +1 -1
  159. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +1 -1
  160. package/src/config/bundled-tool-registry.ts +2 -5
  161. package/src/config/loader.ts +6 -42
  162. package/src/config/schema.ts +1 -12
  163. package/src/config/schemas/memory-lifecycle.ts +0 -9
  164. package/src/config/schemas/memory-processing.ts +0 -180
  165. package/src/config/schemas/memory-retrieval.ts +32 -104
  166. package/src/config/schemas/memory.ts +0 -10
  167. package/src/config/types.ts +0 -4
  168. package/src/contacts/contact-store.ts +39 -2
  169. package/src/contacts/contacts-write.ts +9 -0
  170. package/src/context/window-manager.ts +4 -1
  171. package/src/daemon/config-watcher.ts +55 -2
  172. package/src/daemon/daemon-control.ts +1 -1
  173. package/src/daemon/date-context.ts +114 -31
  174. package/src/daemon/handlers/config-ingress.ts +2 -2
  175. package/src/daemon/handlers/config-slack-channel.ts +59 -39
  176. package/src/daemon/handlers/config-telegram.ts +23 -14
  177. package/src/daemon/handlers/session-history.ts +1 -358
  178. package/src/daemon/handlers/sessions.ts +18 -13
  179. package/src/daemon/handlers/shared.ts +3 -17
  180. package/src/daemon/handlers/skills.ts +20 -1
  181. package/src/daemon/history-repair.ts +72 -8
  182. package/src/daemon/host-cu-proxy.ts +55 -26
  183. package/src/daemon/lifecycle.ts +39 -4
  184. package/src/daemon/mcp-reload-service.ts +2 -2
  185. package/src/daemon/message-types/computer-use.ts +1 -12
  186. package/src/daemon/message-types/memory.ts +4 -16
  187. package/src/daemon/message-types/messages.ts +1 -0
  188. package/src/daemon/message-types/sessions.ts +4 -42
  189. package/src/daemon/server.ts +6 -1
  190. package/src/daemon/session-agent-loop-handlers.ts +38 -0
  191. package/src/daemon/session-agent-loop.ts +334 -48
  192. package/src/daemon/session-error.ts +89 -6
  193. package/src/daemon/session-history.ts +17 -7
  194. package/src/daemon/session-media-retry.ts +6 -2
  195. package/src/daemon/session-memory.ts +69 -149
  196. package/src/daemon/session-process.ts +10 -1
  197. package/src/daemon/session-runtime-assembly.ts +49 -19
  198. package/src/daemon/session-slash.ts +3 -5
  199. package/src/daemon/session-surfaces.ts +4 -1
  200. package/src/daemon/session-tool-setup.ts +7 -1
  201. package/src/daemon/session.ts +12 -2
  202. package/src/email/providers/index.ts +2 -2
  203. package/src/instrument.ts +61 -1
  204. package/src/media/avatar-router.ts +1 -1
  205. package/src/memory/admin.ts +2 -191
  206. package/src/memory/canonical-guardian-store.ts +38 -2
  207. package/src/memory/conversation-crud.ts +0 -33
  208. package/src/memory/conversation-queries.ts +25 -83
  209. package/src/memory/db-init.ts +32 -0
  210. package/src/memory/embedding-backend.ts +84 -8
  211. package/src/memory/embedding-types.ts +9 -1
  212. package/src/memory/indexer.ts +7 -46
  213. package/src/memory/invite-store.ts +19 -0
  214. package/src/memory/items-extractor.ts +274 -76
  215. package/src/memory/job-handlers/backfill.ts +2 -127
  216. package/src/memory/job-handlers/cleanup.ts +2 -16
  217. package/src/memory/job-handlers/extraction.ts +2 -138
  218. package/src/memory/job-handlers/index-maintenance.ts +1 -6
  219. package/src/memory/job-handlers/summarization.ts +3 -148
  220. package/src/memory/job-utils.ts +21 -59
  221. package/src/memory/jobs-store.ts +1 -159
  222. package/src/memory/jobs-worker.ts +9 -52
  223. package/src/memory/migrations/104-core-indexes.ts +3 -3
  224. package/src/memory/migrations/149-oauth-tables.ts +2 -0
  225. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
  226. package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
  227. package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
  228. package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
  229. package/src/memory/migrations/154-drop-fts.ts +20 -0
  230. package/src/memory/migrations/155-drop-conflicts.ts +7 -0
  231. package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
  232. package/src/memory/migrations/157-invite-contact-id.ts +104 -0
  233. package/src/memory/migrations/index.ts +8 -0
  234. package/src/memory/migrations/registry.ts +6 -0
  235. package/src/memory/qdrant-client.ts +148 -51
  236. package/src/memory/raw-query.ts +1 -1
  237. package/src/memory/retriever.test.ts +294 -273
  238. package/src/memory/retriever.ts +421 -645
  239. package/src/memory/schema/calls.ts +2 -0
  240. package/src/memory/schema/contacts.ts +1 -0
  241. package/src/memory/schema/memory-core.ts +3 -48
  242. package/src/memory/schema/oauth.ts +2 -0
  243. package/src/memory/search/formatting.ts +263 -176
  244. package/src/memory/search/lexical.ts +1 -254
  245. package/src/memory/search/ranking.ts +0 -455
  246. package/src/memory/search/semantic.ts +100 -14
  247. package/src/memory/search/staleness.ts +47 -0
  248. package/src/memory/search/tier-classifier.ts +21 -0
  249. package/src/memory/search/types.ts +15 -77
  250. package/src/memory/task-memory-cleanup.ts +4 -6
  251. package/src/messaging/provider.ts +1 -1
  252. package/src/messaging/providers/gmail/adapter.ts +1 -1
  253. package/src/messaging/providers/gmail/mime-builder.ts +17 -7
  254. package/src/messaging/providers/telegram-bot/adapter.ts +17 -8
  255. package/src/messaging/providers/whatsapp/adapter.ts +13 -9
  256. package/src/messaging/registry.ts +9 -5
  257. package/src/oauth/byo-connection.test.ts +40 -25
  258. package/src/oauth/connect-orchestrator.ts +4 -10
  259. package/src/oauth/connection-resolver.ts +20 -6
  260. package/src/oauth/manual-token-connection.ts +5 -5
  261. package/src/oauth/oauth-store.ts +183 -31
  262. package/src/oauth/platform-connection.test.ts +1 -1
  263. package/src/oauth/provider-behaviors.ts +503 -4
  264. package/src/oauth/seed-providers.ts +214 -8
  265. package/src/oauth/token-persistence.ts +31 -16
  266. package/src/permissions/defaults.ts +1 -0
  267. package/src/permissions/trust-store.ts +23 -1
  268. package/src/playbooks/playbook-compiler.ts +1 -1
  269. package/src/prompts/system-prompt.ts +18 -2
  270. package/src/providers/anthropic/client.ts +56 -126
  271. package/src/providers/types.ts +7 -1
  272. package/src/runtime/AGENTS.md +9 -0
  273. package/src/runtime/auth/route-policy.ts +6 -3
  274. package/src/runtime/channel-readiness-service.ts +48 -40
  275. package/src/runtime/guardian-reply-router.ts +24 -22
  276. package/src/runtime/http-server.ts +2 -2
  277. package/src/runtime/http-types.ts +2 -0
  278. package/src/runtime/invite-redemption-service.ts +72 -12
  279. package/src/runtime/invite-service.ts +43 -0
  280. package/src/runtime/middleware/twilio-validation.ts +1 -1
  281. package/src/runtime/pending-interactions.ts +2 -2
  282. package/src/runtime/routes/brain-graph-routes.ts +10 -90
  283. package/src/runtime/routes/btw-routes.ts +10 -5
  284. package/src/runtime/routes/conversation-routes.ts +56 -11
  285. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
  286. package/src/runtime/routes/integrations/slack/channel.ts +2 -2
  287. package/src/runtime/routes/integrations/telegram.ts +2 -2
  288. package/src/runtime/routes/integrations/twilio.ts +17 -17
  289. package/src/runtime/routes/invite-routes.ts +29 -4
  290. package/src/runtime/routes/memory-item-routes.test.ts +754 -0
  291. package/src/runtime/routes/memory-item-routes.ts +503 -0
  292. package/src/runtime/routes/secret-routes.ts +17 -0
  293. package/src/runtime/routes/session-management-routes.ts +3 -3
  294. package/src/runtime/routes/settings-routes.ts +3 -3
  295. package/src/runtime/routes/trust-rules-routes.ts +14 -0
  296. package/src/runtime/routes/workspace-routes.ts +9 -4
  297. package/src/runtime/routes/workspace-utils.ts +8 -2
  298. package/src/schedule/integration-status.ts +26 -19
  299. package/src/security/keychain-broker-client.ts +17 -4
  300. package/src/security/oauth2.ts +6 -7
  301. package/src/security/secure-keys.ts +44 -19
  302. package/src/security/token-manager.ts +46 -39
  303. package/src/services/vercel-deploy.ts +0 -24
  304. package/src/signals/confirm.ts +78 -0
  305. package/src/signals/mcp-reload.ts +18 -0
  306. package/src/skills/catalog-install.ts +74 -18
  307. package/src/skills/skillssh-registry.ts +503 -0
  308. package/src/tools/assets/search.ts +5 -1
  309. package/src/tools/computer-use/definitions.ts +0 -10
  310. package/src/tools/computer-use/registry.ts +1 -1
  311. package/src/tools/credentials/vault.ts +22 -7
  312. package/src/tools/memory/definitions.ts +4 -13
  313. package/src/tools/memory/handlers.test.ts +83 -103
  314. package/src/tools/memory/handlers.ts +50 -85
  315. package/src/tools/network/script-proxy/session-manager.ts +8 -8
  316. package/src/tools/schedule/create.ts +10 -3
  317. package/src/tools/schedule/update.ts +8 -1
  318. package/src/tools/skills/load.ts +25 -2
  319. package/src/watcher/provider-types.ts +1 -1
  320. package/src/watcher/providers/github.ts +1 -1
  321. package/src/watcher/providers/gmail.ts +3 -3
  322. package/src/watcher/providers/google-calendar.ts +3 -3
  323. package/src/watcher/providers/linear.ts +1 -1
  324. package/src/__tests__/clarification-resolver.test.ts +0 -193
  325. package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
  326. package/src/__tests__/conflict-policy.test.ts +0 -269
  327. package/src/__tests__/conflict-store.test.ts +0 -372
  328. package/src/__tests__/contradiction-checker.test.ts +0 -361
  329. package/src/__tests__/entity-extractor.test.ts +0 -211
  330. package/src/__tests__/entity-search.test.ts +0 -1117
  331. package/src/__tests__/profile-compiler.test.ts +0 -392
  332. package/src/__tests__/session-conflict-gate.test.ts +0 -1228
  333. package/src/__tests__/session-profile-injection.test.ts +0 -557
  334. package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
  335. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
  336. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
  337. package/src/daemon/session-conflict-gate.ts +0 -167
  338. package/src/daemon/session-dynamic-profile.ts +0 -77
  339. package/src/memory/clarification-resolver.ts +0 -417
  340. package/src/memory/conflict-intent.ts +0 -205
  341. package/src/memory/conflict-policy.ts +0 -127
  342. package/src/memory/conflict-store.ts +0 -410
  343. package/src/memory/contradiction-checker.ts +0 -508
  344. package/src/memory/entity-extractor.ts +0 -535
  345. package/src/memory/format-recall.ts +0 -47
  346. package/src/memory/fts-reconciler.ts +0 -165
  347. package/src/memory/job-handlers/conflict.ts +0 -200
  348. package/src/memory/profile-compiler.ts +0 -195
  349. package/src/memory/recall-cache.ts +0 -117
  350. package/src/memory/search/entity.ts +0 -535
  351. package/src/memory/search/query-expansion.test.ts +0 -70
  352. package/src/memory/search/query-expansion.ts +0 -118
  353. package/src/runtime/routes/mcp-routes.ts +0 -20
@@ -4,10 +4,15 @@ import { seedProviders } from "./oauth-store.js";
4
4
  * Protocol-level seed data for each well-known OAuth provider.
5
5
  *
6
6
  * These values are upserted into the `oauth_providers` SQLite table on
7
- * every startup so that corrections (e.g. a fixed baseUrl) propagate to
8
- * existing installations. Code-side behavioral fields (identityVerifier,
9
- * injectionTemplates, setup, etc.) live in `provider-behaviors.ts` and
10
- * are never persisted to the DB.
7
+ * every startup. Only Vellum implementation fields (authUrl, tokenUrl,
8
+ * tokenEndpointAuthMethod, extraParams, callbackTransport, loopbackPort,
9
+ * pingUrl) are overwritten on subsequent startups — user-customizable
10
+ * fields (defaultScopes, scopePolicy, userinfoUrl, baseUrl) are only
11
+ * written on initial insert and preserved across restarts.
12
+ *
13
+ * Code-side behavioral fields (identityVerifier, injectionTemplates,
14
+ * setup, etc.) live in `provider-behaviors.ts` and are never persisted
15
+ * to the DB.
11
16
  */
12
17
  const PROVIDER_SEED_DATA: Record<
13
18
  string,
@@ -17,6 +22,7 @@ const PROVIDER_SEED_DATA: Record<
17
22
  tokenUrl: string;
18
23
  tokenEndpointAuthMethod?: string;
19
24
  userinfoUrl?: string;
25
+ pingUrl?: string;
20
26
  baseUrl?: string;
21
27
  defaultScopes: string[];
22
28
  scopePolicy: {
@@ -29,11 +35,12 @@ const PROVIDER_SEED_DATA: Record<
29
35
  loopbackPort?: number;
30
36
  }
31
37
  > = {
32
- "integration:gmail": {
33
- providerKey: "integration:gmail",
38
+ "integration:google": {
39
+ providerKey: "integration:google",
34
40
  authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
35
41
  tokenUrl: "https://oauth2.googleapis.com/token",
36
42
  userinfoUrl: "https://www.googleapis.com/oauth2/v2/userinfo",
43
+ pingUrl: "https://www.googleapis.com/oauth2/v2/userinfo",
37
44
  baseUrl: "https://gmail.googleapis.com/gmail/v1/users/me",
38
45
  defaultScopes: [
39
46
  "https://www.googleapis.com/auth/gmail.readonly",
@@ -45,8 +52,11 @@ const PROVIDER_SEED_DATA: Record<
45
52
  "https://www.googleapis.com/auth/contacts.readonly",
46
53
  ],
47
54
  scopePolicy: {
48
- allowAdditionalScopes: false,
49
- allowedOptionalScopes: [],
55
+ allowAdditionalScopes: true,
56
+ allowedOptionalScopes: [
57
+ "https://www.googleapis.com/auth/drive.readonly",
58
+ "https://www.googleapis.com/auth/drive.file",
59
+ ],
50
60
  forbiddenScopes: [],
51
61
  },
52
62
  extraParams: { access_type: "offline", prompt: "consent" },
@@ -57,6 +67,7 @@ const PROVIDER_SEED_DATA: Record<
57
67
  providerKey: "integration:slack",
58
68
  authUrl: "https://slack.com/oauth/v2/authorize",
59
69
  tokenUrl: "https://slack.com/api/oauth.v2.access",
70
+ pingUrl: "https://slack.com/api/auth.test",
60
71
  baseUrl: "https://slack.com/api",
61
72
  defaultScopes: [
62
73
  "channels:read",
@@ -90,6 +101,7 @@ const PROVIDER_SEED_DATA: Record<
90
101
  providerKey: "integration:notion",
91
102
  authUrl: "https://api.notion.com/v1/oauth/authorize",
92
103
  tokenUrl: "https://api.notion.com/v1/oauth/token",
104
+ pingUrl: "https://api.notion.com/v1/users/me",
93
105
  baseUrl: "https://api.notion.com",
94
106
  defaultScopes: [],
95
107
  scopePolicy: {
@@ -99,12 +111,14 @@ const PROVIDER_SEED_DATA: Record<
99
111
  },
100
112
  extraParams: { owner: "user" },
101
113
  tokenEndpointAuthMethod: "client_secret_basic",
114
+ callbackTransport: "gateway",
102
115
  },
103
116
 
104
117
  "integration:twitter": {
105
118
  providerKey: "integration:twitter",
106
119
  authUrl: "https://twitter.com/i/oauth2/authorize",
107
120
  tokenUrl: "https://api.x.com/2/oauth2/token",
121
+ pingUrl: "https://api.x.com/2/users/me",
108
122
  baseUrl: "https://api.x.com",
109
123
  defaultScopes: [
110
124
  "tweet.read",
@@ -121,6 +135,197 @@ const PROVIDER_SEED_DATA: Record<
121
135
  callbackTransport: "gateway",
122
136
  },
123
137
 
138
+ "integration:github": {
139
+ providerKey: "integration:github",
140
+ authUrl: "https://github.com/login/oauth/authorize",
141
+ tokenUrl: "https://github.com/login/oauth/access_token",
142
+ pingUrl: "https://api.github.com/user",
143
+ baseUrl: "https://api.github.com",
144
+ defaultScopes: ["repo", "read:user", "notifications"],
145
+ scopePolicy: {
146
+ allowAdditionalScopes: true,
147
+ allowedOptionalScopes: [
148
+ "read:org",
149
+ "write:discussion",
150
+ "gist",
151
+ "project",
152
+ ],
153
+ forbiddenScopes: ["delete_repo", "admin:org"],
154
+ },
155
+ callbackTransport: "loopback",
156
+ },
157
+
158
+ "integration:linear": {
159
+ providerKey: "integration:linear",
160
+ authUrl: "https://linear.app/oauth/authorize",
161
+ tokenUrl: "https://api.linear.app/oauth/token",
162
+ pingUrl: "https://api.linear.app/graphql",
163
+ baseUrl: "https://api.linear.app",
164
+ defaultScopes: ["read", "write", "issues:create"],
165
+ scopePolicy: {
166
+ allowAdditionalScopes: false,
167
+ allowedOptionalScopes: [],
168
+ forbiddenScopes: [],
169
+ },
170
+ extraParams: { prompt: "consent" },
171
+ callbackTransport: "loopback",
172
+ },
173
+
174
+ "integration:spotify": {
175
+ providerKey: "integration:spotify",
176
+ authUrl: "https://accounts.spotify.com/authorize",
177
+ tokenUrl: "https://accounts.spotify.com/api/token",
178
+ pingUrl: "https://api.spotify.com/v1/me",
179
+ baseUrl: "https://api.spotify.com/v1",
180
+ defaultScopes: [
181
+ "user-read-playback-state",
182
+ "user-modify-playback-state",
183
+ "user-read-currently-playing",
184
+ "user-read-recently-played",
185
+ "playlist-read-private",
186
+ "playlist-modify-public",
187
+ "playlist-modify-private",
188
+ "user-library-read",
189
+ "user-library-modify",
190
+ ],
191
+ scopePolicy: {
192
+ allowAdditionalScopes: false,
193
+ allowedOptionalScopes: [],
194
+ forbiddenScopes: [],
195
+ },
196
+ callbackTransport: "loopback",
197
+ },
198
+
199
+ "integration:todoist": {
200
+ providerKey: "integration:todoist",
201
+ authUrl: "https://todoist.com/oauth/authorize",
202
+ tokenUrl: "https://todoist.com/oauth/access_token",
203
+ pingUrl: "https://api.todoist.com/rest/v2/projects",
204
+ baseUrl: "https://api.todoist.com/rest/v2",
205
+ defaultScopes: ["data:read_write"],
206
+ scopePolicy: {
207
+ allowAdditionalScopes: false,
208
+ allowedOptionalScopes: [],
209
+ forbiddenScopes: ["data:delete"],
210
+ },
211
+ callbackTransport: "loopback",
212
+ },
213
+
214
+ "integration:discord": {
215
+ providerKey: "integration:discord",
216
+ authUrl: "https://discord.com/oauth2/authorize",
217
+ tokenUrl: "https://discord.com/api/v10/oauth2/token",
218
+ pingUrl: "https://discord.com/api/v10/users/@me",
219
+ baseUrl: "https://discord.com/api/v10",
220
+ defaultScopes: [
221
+ "identify",
222
+ "guilds",
223
+ "guilds.members.read",
224
+ "messages.read",
225
+ ],
226
+ scopePolicy: {
227
+ allowAdditionalScopes: false,
228
+ allowedOptionalScopes: ["bot"],
229
+ forbiddenScopes: [],
230
+ },
231
+ callbackTransport: "loopback",
232
+ },
233
+
234
+ "integration:dropbox": {
235
+ providerKey: "integration:dropbox",
236
+ authUrl: "https://www.dropbox.com/oauth2/authorize",
237
+ tokenUrl: "https://api.dropboxapi.com/oauth2/token",
238
+ pingUrl: "https://api.dropboxapi.com/2/users/get_current_account",
239
+ baseUrl: "https://api.dropboxapi.com/2",
240
+ defaultScopes: [
241
+ "files.metadata.read",
242
+ "files.content.read",
243
+ "files.content.write",
244
+ "sharing.read",
245
+ ],
246
+ scopePolicy: {
247
+ allowAdditionalScopes: false,
248
+ allowedOptionalScopes: [],
249
+ forbiddenScopes: [],
250
+ },
251
+ extraParams: { token_access_type: "offline" },
252
+ callbackTransport: "loopback",
253
+ },
254
+
255
+ "integration:asana": {
256
+ providerKey: "integration:asana",
257
+ authUrl: "https://app.asana.com/-/oauth_authorize",
258
+ tokenUrl: "https://app.asana.com/-/oauth_token",
259
+ pingUrl: "https://app.asana.com/api/1.0/users/me",
260
+ baseUrl: "https://app.asana.com/api/1.0",
261
+ defaultScopes: ["default"],
262
+ scopePolicy: {
263
+ allowAdditionalScopes: false,
264
+ allowedOptionalScopes: [],
265
+ forbiddenScopes: [],
266
+ },
267
+ callbackTransport: "loopback",
268
+ },
269
+
270
+ "integration:airtable": {
271
+ providerKey: "integration:airtable",
272
+ authUrl: "https://airtable.com/oauth2/v1/authorize",
273
+ tokenUrl: "https://airtable.com/oauth2/v1/token",
274
+ pingUrl: "https://api.airtable.com/v0/meta/whoami",
275
+ baseUrl: "https://api.airtable.com/v0",
276
+ defaultScopes: [
277
+ "data.records:read",
278
+ "data.records:write",
279
+ "schema.bases:read",
280
+ ],
281
+ scopePolicy: {
282
+ allowAdditionalScopes: false,
283
+ allowedOptionalScopes: [],
284
+ forbiddenScopes: [],
285
+ },
286
+ tokenEndpointAuthMethod: "client_secret_post",
287
+ callbackTransport: "loopback",
288
+ },
289
+
290
+ "integration:hubspot": {
291
+ providerKey: "integration:hubspot",
292
+ authUrl: "https://app.hubspot.com/oauth/authorize",
293
+ tokenUrl: "https://api.hubapi.com/oauth/v1/token",
294
+ pingUrl: "https://api.hubapi.com/crm/v3/objects/contacts?limit=1",
295
+ baseUrl: "https://api.hubapi.com",
296
+ defaultScopes: [
297
+ "crm.objects.contacts.read",
298
+ "crm.objects.contacts.write",
299
+ "crm.objects.deals.read",
300
+ "crm.objects.deals.write",
301
+ "crm.objects.companies.read",
302
+ ],
303
+ scopePolicy: {
304
+ allowAdditionalScopes: true,
305
+ allowedOptionalScopes: [
306
+ "crm.objects.companies.write",
307
+ "crm.objects.owners.read",
308
+ ],
309
+ forbiddenScopes: [],
310
+ },
311
+ callbackTransport: "loopback",
312
+ },
313
+
314
+ "integration:figma": {
315
+ providerKey: "integration:figma",
316
+ authUrl: "https://www.figma.com/oauth",
317
+ tokenUrl: "https://api.figma.com/v1/oauth/token",
318
+ pingUrl: "https://api.figma.com/v1/me",
319
+ baseUrl: "https://api.figma.com/v1",
320
+ defaultScopes: ["files:read", "file_comments:write"],
321
+ scopePolicy: {
322
+ allowAdditionalScopes: false,
323
+ allowedOptionalScopes: [],
324
+ forbiddenScopes: [],
325
+ },
326
+ callbackTransport: "loopback",
327
+ },
328
+
124
329
  // Manual-token providers: these don't use OAuth2 flows but need provider
125
330
  // rows so that oauth_app and oauth_connection FK chains can reference them.
126
331
  // The authUrl/tokenUrl values are placeholders — never used at runtime.
@@ -128,6 +333,7 @@ const PROVIDER_SEED_DATA: Record<
128
333
  providerKey: "slack_channel",
129
334
  authUrl: "urn:manual-token",
130
335
  tokenUrl: "urn:manual-token",
336
+ pingUrl: "https://slack.com/api/auth.test",
131
337
  baseUrl: "https://slack.com/api",
132
338
  defaultScopes: [],
133
339
  scopePolicy: {
@@ -10,19 +10,17 @@
10
10
  * `oauth_connection/{id}/...`).
11
11
  */
12
12
 
13
- import type {
14
- OAuth2FlowResult,
15
- TokenEndpointAuthMethod,
16
- } from "../security/oauth2.js";
13
+ import type { OAuth2FlowResult } from "../security/oauth2.js";
17
14
  import {
18
15
  deleteSecureKeyAsync,
19
16
  setSecureKeyAsync,
20
17
  } from "../security/secure-keys.js";
21
- import type { CredentialInjectionTemplate } from "../tools/credentials/policy-types.js";
22
18
  import { runPostConnectHook } from "../tools/credentials/post-connect-hooks.js";
23
19
  import {
24
20
  createConnection,
21
+ getApp,
25
22
  getConnectionByProvider,
23
+ getConnectionByProviderAndAccount,
26
24
  updateConnection,
27
25
  upsertApp,
28
26
  } from "./oauth-store.js";
@@ -38,11 +36,7 @@ export interface StoreOAuth2TokensParams {
38
36
  rawTokenResponse: Record<string, unknown>;
39
37
  clientId: string;
40
38
  clientSecret?: string;
41
- tokenUrl: string;
42
- tokenEndpointAuthMethod?: TokenEndpointAuthMethod;
43
39
  userinfoUrl?: string;
44
- allowedTools?: string[];
45
- wellKnownInjectionTemplates?: CredentialInjectionTemplate[];
46
40
  /** Fallback account info from an identity verifier (e.g. @username, email). */
47
41
  identityAccountInfo?: string;
48
42
  /** Pre-resolved oauth_app ID — skips the upsertApp() call if provided. */
@@ -101,13 +95,20 @@ export async function storeOAuth2Tokens(
101
95
 
102
96
  // 1. Upsert the oauth_app row (or use the pre-resolved ID).
103
97
  const app = params.oauthAppId
104
- ? { id: params.oauthAppId }
105
- : await upsertApp(service, clientId, clientSecret);
98
+ ? (getApp(params.oauthAppId) ?? {
99
+ id: params.oauthAppId,
100
+ clientSecretCredentialPath: `oauth_app/${params.oauthAppId}/client_secret`,
101
+ })
102
+ : await upsertApp(
103
+ service,
104
+ clientId,
105
+ clientSecret ? { clientSecretValue: clientSecret } : undefined,
106
+ );
106
107
 
107
108
  // When oauthAppId is pre-resolved, still persist clientSecret if provided.
108
109
  if (params.oauthAppId && clientSecret) {
109
110
  const stored = await setSecureKeyAsync(
110
- `oauth_app/${params.oauthAppId}/client_secret`,
111
+ app.clientSecretCredentialPath,
111
112
  clientSecret,
112
113
  );
113
114
  if (!stored) {
@@ -115,14 +116,28 @@ export async function storeOAuth2Tokens(
115
116
  }
116
117
  }
117
118
 
118
- // 2. Upsert oauth_connection — reuse existing active connection for this
119
- // provider, or create a new one.
120
- const existingConn = getConnectionByProvider(service);
119
+ // 2. Upsert oauth_connection — reuse existing active connection for the
120
+ // same account, or create a new one for a different account.
121
+ // First try to match by account info (email); fall back to provider-only
122
+ // lookup so that re-auth without userinfo still updates the right row.
123
+ const existingConn = resolvedAccountInfo
124
+ ? getConnectionByProviderAndAccount(service, resolvedAccountInfo)
125
+ : getConnectionByProvider(service);
121
126
  let connId: string;
122
127
 
123
128
  const hasRefreshToken = !!tokens.refreshToken;
124
129
 
125
- if (existingConn) {
130
+ // Only reuse the existing connection if it's the same account (or we can't
131
+ // tell). When the user connects a different account for the same service,
132
+ // create a separate connection so we don't overwrite the first account's
133
+ // tokens.
134
+ const isNewAccount =
135
+ existingConn &&
136
+ resolvedAccountInfo !== undefined &&
137
+ existingConn.accountInfo !== undefined &&
138
+ resolvedAccountInfo !== existingConn.accountInfo;
139
+
140
+ if (existingConn && !isNewAccount) {
126
141
  connId = existingConn.id;
127
142
  updateConnection(connId, {
128
143
  oauthAppId: app.id,
@@ -20,6 +20,7 @@ const HOST_FILE_TOOLS = [
20
20
  "host_file_edit",
21
21
  ] as const;
22
22
  const COMPUTER_USE_TOOLS = [
23
+ "computer_use_observe",
23
24
  "computer_use_click",
24
25
  "computer_use_type_text",
25
26
  "computer_use_key",
@@ -283,12 +283,28 @@ function loadFromDisk(): TrustRule[] {
283
283
  // Restore persisted starter bundle flag
284
284
  cachedStarterBundleAccepted = data.starterBundleAccepted === true;
285
285
 
286
+ // Defense-in-depth: strip any __internal: prefixed rules that may have
287
+ // been hand-edited into trust.json.
288
+ const sanitizedRules = rawRules.filter((r) => {
289
+ if (typeof r.tool === "string" && r.tool.startsWith("__internal:")) {
290
+ log.warn(
291
+ { ruleId: r.id, tool: r.tool },
292
+ "Stripping __internal: rule from trust file on load",
293
+ );
294
+ return false;
295
+ }
296
+ return true;
297
+ });
298
+
286
299
  if (
287
300
  data.version === TRUST_FILE_VERSION ||
288
301
  data.version === 1 ||
289
302
  data.version === 2
290
303
  ) {
291
- rules = rawRules;
304
+ rules = sanitizedRules;
305
+ if (sanitizedRules.length < rawRules.length) {
306
+ needsSave = true;
307
+ }
292
308
  if (data.version !== TRUST_FILE_VERSION) {
293
309
  needsSave = true;
294
310
  log.info(
@@ -395,6 +411,8 @@ export function addRule(
395
411
  executionTarget?: string;
396
412
  },
397
413
  ): TrustRule {
414
+ if (tool.startsWith("__internal:"))
415
+ throw new Error(`Cannot create internal pseudo-rule via addRule: ${tool}`);
398
416
  // Re-read from disk to avoid lost updates if another call modified rules
399
417
  // between our last read and now (e.g. two rapid trust rule additions).
400
418
  cachedRules = null;
@@ -437,6 +455,10 @@ export function updateRule(
437
455
  const defaultIds = new Set(getDefaultRuleTemplates().map((t) => t.id));
438
456
  if (defaultIds.has(id))
439
457
  throw new Error(`Cannot modify default trust rule: ${id}`);
458
+ if (updates.tool?.startsWith("__internal:"))
459
+ throw new Error(
460
+ `Cannot update tool to internal pseudo-rule: ${updates.tool}`,
461
+ );
440
462
 
441
463
  // Re-read from disk to avoid lost updates from concurrent modifications.
442
464
  cachedRules = null;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Compile all active playbook memory items into a triage context block
3
3
  * that can be injected into the system prompt alongside the contact
4
- * graph and dynamic profile.
4
+ * graph.
5
5
  */
6
6
 
7
7
  import { and, desc, eq, isNull } from "drizzle-orm";
@@ -690,7 +690,7 @@ function buildMemoryRecallSection(): string {
690
690
  "- The auto-injected memory context doesn't contain what you need",
691
691
  "- The user references something from a previous session",
692
692
  "",
693
- "The tool searches across semantic, lexical, entity graph, and recency sources. Be specific in your query for best results.",
693
+ "The tool uses hybrid search (dense and sparse vectors) supplemented by recency. Be specific in your query for best results.",
694
694
  ].join("\n");
695
695
  }
696
696
 
@@ -845,7 +845,7 @@ export function buildCliReferenceSection(): string {
845
845
  return [
846
846
  "## Assistant CLI",
847
847
  "",
848
- "The `assistant` CLI is installed on the user's machine and available via `bash`.",
848
+ "The `assistant` CLI is available in the sandbox. Always use the `bash` tool (never `host_bash`) when running `assistant` commands.",
849
849
  "For account and authentication work, prefer real `assistant` CLI workflows over any legacy account-record abstraction.",
850
850
  "- Use `assistant credentials ...` for stored secrets and credential metadata.",
851
851
  "- Use `assistant oauth connections token <provider-key>` for connected integration tokens.",
@@ -960,6 +960,22 @@ function buildDynamicSkillWorkflowSection(
960
960
  );
961
961
  }
962
962
 
963
+ lines.push(
964
+ "",
965
+ "### Community Skills Discovery",
966
+ "",
967
+ "When no built-in skill satisfies a request, search the community skills.sh registry:",
968
+ "1. Run `assistant skills search <query>` to find community skills. Results include install counts and security audit badges (ATH, Socket, Snyk).",
969
+ "2. Present the search results to the user, highlighting the security audit status. ATH is Gen Agent Trust Hub. Audits show PASS (safe/low risk), WARN (medium risk), or FAIL (high/critical risk) for each provider.",
970
+ "3. Check the skill's **source owner** to determine the trust level:",
971
+ " - **Vellum-owned** (source starts with `vellum-ai/`): These are first-party skills published by the Vellum team. Install them directly without prompting — they are vetted and trusted.",
972
+ " - **Third-party** (any other owner): Ask the user for permission before installing. Say something like: \"I found a community skill that could help with this, but it's published by a third party — we haven't vetted it. Want to install it anyway?\" Share the skill name, source, audit results, and install count.",
973
+ "4. Install with `assistant skills add <owner>/<repo>@<skill-name>` (e.g., `assistant skills add vercel-labs/skills@find-skills`).",
974
+ "5. After installation, load the skill with `skill_load` as usual.",
975
+ "",
976
+ "**Never install third-party community skills without explicit user confirmation.** Vellum-owned skills (`vellum-ai/*`) can be installed automatically.",
977
+ );
978
+
963
979
  return lines.join("\n");
964
980
  }
965
981