@vellumai/assistant 0.4.46 → 0.4.49

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 (382) hide show
  1. package/ARCHITECTURE.md +7 -7
  2. package/README.md +2 -23
  3. package/docs/architecture/integrations.md +45 -41
  4. package/docs/architecture/keychain-broker.md +3 -3
  5. package/docs/architecture/security.md +5 -5
  6. package/docs/runbook-trusted-contacts.md +3 -8
  7. package/hook-templates/debug-prompt-logger/hook.json +1 -1
  8. package/hook-templates/debug-prompt-logger/run.sh +1 -3
  9. package/package.json +1 -1
  10. package/src/__tests__/actor-token-service.test.ts +0 -1
  11. package/src/__tests__/anthropic-provider.test.ts +156 -0
  12. package/src/__tests__/approval-cascade.test.ts +810 -0
  13. package/src/__tests__/approval-primitive.test.ts +0 -1
  14. package/src/__tests__/approval-routes-http.test.ts +2 -0
  15. package/src/__tests__/assistant-attachments.test.ts +12 -34
  16. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
  17. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
  18. package/src/__tests__/browser-fill-credential.test.ts +5 -2
  19. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
  20. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +2 -1
  21. package/src/__tests__/channel-guardian.test.ts +0 -2
  22. package/src/__tests__/channel-readiness-routes.test.ts +35 -25
  23. package/src/__tests__/channel-readiness-service.test.ts +10 -9
  24. package/src/__tests__/checker.test.ts +9 -29
  25. package/src/__tests__/cli.test.ts +23 -0
  26. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
  27. package/src/__tests__/computer-use-tools.test.ts +2 -19
  28. package/src/__tests__/config-watcher.test.ts +0 -1
  29. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  30. package/src/__tests__/context-image-dimensions.test.ts +332 -0
  31. package/src/__tests__/context-token-estimator.test.ts +196 -13
  32. package/src/__tests__/conversation-attention-store.test.ts +0 -1
  33. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  34. package/src/__tests__/conversation-routes-guardian-reply.test.ts +144 -0
  35. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  36. package/src/__tests__/credential-broker-browser-fill.test.ts +23 -22
  37. package/src/__tests__/credential-broker-server-use.test.ts +22 -21
  38. package/src/__tests__/credential-broker.test.ts +2 -1
  39. package/src/__tests__/credential-metadata-store.test.ts +239 -26
  40. package/src/__tests__/credential-resolve.test.ts +5 -4
  41. package/src/__tests__/credential-security-e2e.test.ts +8 -8
  42. package/src/__tests__/credential-security-invariants.test.ts +111 -7
  43. package/src/__tests__/credential-vault-unit.test.ts +287 -54
  44. package/src/__tests__/credential-vault.test.ts +406 -12
  45. package/src/__tests__/credentials-cli.test.ts +82 -6
  46. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  47. package/src/__tests__/ephemeral-permissions.test.ts +3 -3
  48. package/src/__tests__/gateway-only-enforcement.test.ts +4 -2
  49. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  50. package/src/__tests__/gemini-image-service.test.ts +75 -45
  51. package/src/__tests__/gemini-provider.test.ts +9 -6
  52. package/src/__tests__/guardian-action-conversation-turn.test.ts +1 -33
  53. package/src/__tests__/guardian-action-copy-generator.test.ts +0 -20
  54. package/src/__tests__/guardian-action-followup-executor.test.ts +1 -28
  55. package/src/__tests__/guardian-action-followup-store.test.ts +1 -1
  56. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
  57. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
  58. package/src/__tests__/guardian-grant-minting.test.ts +35 -0
  59. package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
  60. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
  61. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
  62. package/src/__tests__/heartbeat-service.test.ts +0 -1
  63. package/src/__tests__/host-cu-proxy.test.ts +629 -0
  64. package/src/__tests__/host-shell-tool.test.ts +27 -15
  65. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  66. package/src/__tests__/ingress-url-consistency.test.ts +14 -21
  67. package/src/__tests__/integration-status.test.ts +38 -25
  68. package/src/__tests__/intent-routing.test.ts +0 -1
  69. package/src/__tests__/invite-routes-http.test.ts +10 -9
  70. package/src/__tests__/keychain-broker-client.test.ts +11 -43
  71. package/src/__tests__/managed-proxy-context.test.ts +5 -3
  72. package/src/__tests__/media-generate-image.test.ts +63 -2
  73. package/src/__tests__/media-reuse-story.e2e.test.ts +7 -3
  74. package/src/__tests__/messaging-send-tool.test.ts +4 -6
  75. package/src/__tests__/notification-routing-intent.test.ts +0 -1
  76. package/src/__tests__/oauth-cli.test.ts +373 -14
  77. package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
  78. package/src/__tests__/oauth-scope-policy.test.ts +4 -6
  79. package/src/__tests__/oauth-store.test.ts +756 -0
  80. package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
  81. package/src/__tests__/provider-error-scenarios.test.ts +0 -1
  82. package/src/__tests__/provider-fail-open-selection.test.ts +3 -1
  83. package/src/__tests__/provider-managed-proxy-integration.test.ts +70 -6
  84. package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
  85. package/src/__tests__/public-ingress-urls.test.ts +15 -21
  86. package/src/__tests__/recording-handler.test.ts +3 -4
  87. package/src/__tests__/registry.test.ts +2 -2
  88. package/src/__tests__/runtime-events-sse.test.ts +55 -7
  89. package/src/__tests__/schedule-store.test.ts +0 -1
  90. package/src/__tests__/scheduler-recurrence.test.ts +0 -1
  91. package/src/__tests__/schema-transforms.test.ts +226 -0
  92. package/src/__tests__/scoped-approval-grants.test.ts +0 -1
  93. package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
  94. package/src/__tests__/script-proxy-injection-runtime.test.ts +23 -13
  95. package/src/__tests__/script-proxy-policy-runtime.test.ts +1 -1
  96. package/src/__tests__/script-proxy-session-manager.test.ts +1 -1
  97. package/src/__tests__/secret-ingress-handler.test.ts +0 -1
  98. package/src/__tests__/secret-onetime-send.test.ts +5 -3
  99. package/src/__tests__/send-endpoint-busy.test.ts +21 -6
  100. package/src/__tests__/sequence-store.test.ts +0 -1
  101. package/src/__tests__/session-init.benchmark.test.ts +4 -5
  102. package/src/__tests__/session-messaging-secret-redirect.test.ts +5 -4
  103. package/src/__tests__/skill-include-graph.test.ts +66 -0
  104. package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
  105. package/src/__tests__/skill-load-tool.test.ts +149 -1
  106. package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
  107. package/src/__tests__/skills-uninstall.test.ts +3 -3
  108. package/src/__tests__/skills.test.ts +3 -12
  109. package/src/__tests__/slack-channel-config.test.ts +76 -11
  110. package/src/__tests__/slack-share-routes.test.ts +17 -14
  111. package/src/__tests__/system-prompt.test.ts +0 -1
  112. package/src/__tests__/telegram-bot-username-resolution.test.ts +3 -0
  113. package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
  114. package/src/__tests__/terminal-tools.test.ts +4 -3
  115. package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
  116. package/src/__tests__/tool-approval-handler.test.ts +0 -1
  117. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
  118. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  119. package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
  120. package/src/__tests__/tool-executor.test.ts +0 -1
  121. package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
  122. package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
  123. package/src/__tests__/trust-store.test.ts +1 -22
  124. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  125. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
  126. package/src/__tests__/twilio-config.test.ts +2 -1
  127. package/src/__tests__/twilio-provider.test.ts +4 -2
  128. package/src/__tests__/twilio-routes.test.ts +5 -20
  129. package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
  130. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
  131. package/src/agent/ax-tree-compaction.test.ts +235 -0
  132. package/src/agent/loop.ts +76 -130
  133. package/src/calls/call-domain.ts +8 -10
  134. package/src/calls/relay-server.ts +9 -13
  135. package/src/calls/twilio-config.ts +4 -8
  136. package/src/calls/twilio-provider.ts +2 -1
  137. package/src/calls/twilio-rest.ts +2 -1
  138. package/src/calls/twilio-routes.ts +1 -2
  139. package/src/calls/voice-ingress-preflight.ts +1 -1
  140. package/src/cli/commands/browser-relay.ts +46 -15
  141. package/src/cli/commands/completions.ts +0 -3
  142. package/src/cli/commands/credentials.ts +110 -23
  143. package/src/cli/commands/oauth/apps.ts +255 -0
  144. package/src/cli/commands/oauth/connections.ts +299 -0
  145. package/src/cli/commands/oauth/index.ts +52 -0
  146. package/src/cli/commands/oauth/providers.ts +242 -0
  147. package/src/cli/commands/skills.ts +4 -338
  148. package/src/cli/program.ts +1 -5
  149. package/src/cli/reference.ts +1 -3
  150. package/src/cli.ts +3 -2
  151. package/src/config/assistant-feature-flags.ts +0 -3
  152. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
  153. package/src/config/bundled-skills/claude-code/TOOLS.json +0 -4
  154. package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
  155. package/src/config/bundled-skills/computer-use/TOOLS.json +22 -4
  156. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +29 -32
  157. package/src/config/bundled-skills/gmail/SKILL.md +4 -4
  158. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +54 -61
  159. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +25 -28
  160. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +14 -17
  161. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +39 -44
  162. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +61 -58
  163. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +50 -49
  164. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +11 -13
  165. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +148 -146
  166. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +4 -7
  167. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +175 -173
  168. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +4 -7
  169. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +71 -76
  170. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +32 -38
  171. package/src/config/bundled-skills/google-calendar/SKILL.md +2 -2
  172. package/src/config/bundled-skills/google-calendar/calendar-client.ts +90 -44
  173. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +9 -10
  174. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +5 -6
  175. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +4 -5
  176. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +14 -15
  177. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +37 -37
  178. package/src/config/bundled-skills/google-calendar/tools/shared.ts +4 -9
  179. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +24 -3
  180. package/src/config/bundled-skills/messaging/SKILL.md +6 -6
  181. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +62 -63
  182. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +15 -16
  183. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +4 -5
  184. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +6 -7
  185. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +4 -5
  186. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +14 -15
  187. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +4 -5
  188. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +128 -128
  189. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +33 -34
  190. package/src/config/bundled-skills/messaging/tools/shared.ts +12 -15
  191. package/src/config/bundled-skills/settings/SKILL.md +1 -1
  192. package/src/config/bundled-skills/settings/TOOLS.json +2 -8
  193. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
  194. package/src/config/bundled-skills/slack/tools/shared.ts +4 -10
  195. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +4 -5
  196. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +15 -16
  197. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +4 -5
  198. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +4 -5
  199. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +4 -5
  200. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +95 -92
  201. package/src/config/env-registry.ts +14 -83
  202. package/src/config/env.ts +11 -50
  203. package/src/config/feature-flag-registry.json +16 -16
  204. package/src/config/schema.ts +3 -1
  205. package/src/config/skills.ts +21 -2
  206. package/src/context/image-dimensions.ts +229 -0
  207. package/src/context/token-estimator.ts +75 -12
  208. package/src/context/window-manager.ts +49 -10
  209. package/src/daemon/assistant-attachments.ts +1 -13
  210. package/src/daemon/guardian-action-generators.ts +4 -5
  211. package/src/daemon/handlers/config-ingress.ts +8 -33
  212. package/src/daemon/handlers/config-slack-channel.ts +76 -56
  213. package/src/daemon/handlers/config-telegram.ts +53 -24
  214. package/src/daemon/handlers/sessions.ts +10 -24
  215. package/src/daemon/handlers/shared.ts +0 -130
  216. package/src/daemon/host-cu-proxy.ts +401 -0
  217. package/src/daemon/lifecycle.ts +39 -63
  218. package/src/daemon/message-protocol.ts +3 -0
  219. package/src/daemon/message-types/computer-use.ts +2 -119
  220. package/src/daemon/message-types/host-cu.ts +19 -0
  221. package/src/daemon/message-types/integrations.ts +1 -0
  222. package/src/daemon/message-types/messages.ts +3 -0
  223. package/src/daemon/server.ts +14 -21
  224. package/src/daemon/session-agent-loop-handlers.ts +2 -0
  225. package/src/daemon/session-attachments.ts +1 -2
  226. package/src/daemon/session-messaging.ts +3 -1
  227. package/src/daemon/session-slash.ts +1 -1
  228. package/src/daemon/session-surfaces.ts +40 -28
  229. package/src/daemon/session-tool-setup.ts +20 -11
  230. package/src/daemon/session.ts +139 -16
  231. package/src/daemon/tool-side-effects.ts +2 -8
  232. package/src/daemon/watch-handler.ts +2 -2
  233. package/src/email/providers/index.ts +2 -1
  234. package/src/events/tool-metrics-listener.ts +2 -2
  235. package/src/hooks/manager.ts +1 -4
  236. package/src/inbound/public-ingress-urls.ts +7 -7
  237. package/src/instrument.ts +15 -1
  238. package/src/logfire.ts +16 -5
  239. package/src/media/app-icon-generator.ts +30 -4
  240. package/src/media/avatar-router.ts +26 -3
  241. package/src/media/gemini-image-service.ts +28 -2
  242. package/src/memory/conversation-key-store.ts +21 -0
  243. package/src/memory/db-init.ts +4 -0
  244. package/src/memory/guardian-action-store.ts +1 -1
  245. package/src/memory/migrations/149-oauth-tables.ts +60 -0
  246. package/src/memory/migrations/index.ts +1 -0
  247. package/src/memory/schema/guardian.ts +1 -1
  248. package/src/memory/schema/index.ts +1 -0
  249. package/src/memory/schema/oauth.ts +65 -0
  250. package/src/messaging/provider.ts +19 -13
  251. package/src/messaging/providers/gmail/adapter.ts +40 -23
  252. package/src/messaging/providers/gmail/client.ts +283 -122
  253. package/src/messaging/providers/gmail/people-client.ts +32 -24
  254. package/src/messaging/providers/slack/adapter.ts +29 -19
  255. package/src/messaging/providers/slack/client.ts +265 -78
  256. package/src/messaging/providers/telegram-bot/adapter.ts +19 -18
  257. package/src/messaging/providers/whatsapp/adapter.ts +17 -11
  258. package/src/messaging/registry.ts +2 -31
  259. package/src/notifications/copy-composer.ts +0 -5
  260. package/src/notifications/signal.ts +4 -5
  261. package/src/oauth/byo-connection.test.ts +537 -0
  262. package/src/oauth/byo-connection.ts +128 -0
  263. package/src/oauth/connect-orchestrator.ts +139 -56
  264. package/src/oauth/connect-types.ts +17 -23
  265. package/src/oauth/connection-resolver.ts +58 -0
  266. package/src/oauth/connection.ts +38 -0
  267. package/src/oauth/manual-token-connection.ts +104 -0
  268. package/src/oauth/oauth-store.ts +496 -0
  269. package/src/oauth/platform-connection.test.ts +192 -0
  270. package/src/oauth/platform-connection.ts +111 -0
  271. package/src/oauth/provider-behaviors.ts +124 -0
  272. package/src/oauth/scope-policy.ts +9 -2
  273. package/src/oauth/seed-providers.ts +161 -0
  274. package/src/oauth/token-persistence.ts +74 -78
  275. package/src/permissions/checker.ts +8 -4
  276. package/src/permissions/defaults.ts +0 -1
  277. package/src/permissions/prompter.ts +10 -1
  278. package/src/permissions/trust-store.ts +13 -0
  279. package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
  280. package/src/prompts/system-prompt.ts +70 -45
  281. package/src/providers/anthropic/client.ts +133 -24
  282. package/src/providers/gemini/client.ts +15 -6
  283. package/src/providers/managed-proxy/constants.ts +2 -2
  284. package/src/providers/managed-proxy/context.ts +5 -1
  285. package/src/providers/ratelimit.ts +17 -0
  286. package/src/providers/registry.ts +2 -2
  287. package/src/providers/retry.ts +1 -27
  288. package/src/runtime/AGENTS.md +17 -0
  289. package/src/runtime/auth/route-policy.ts +0 -3
  290. package/src/runtime/channel-invite-transports/telegram.ts +2 -1
  291. package/src/runtime/channel-readiness-service.ts +168 -195
  292. package/src/runtime/channel-readiness-types.ts +4 -0
  293. package/src/runtime/channel-reply-delivery.ts +0 -40
  294. package/src/runtime/gateway-client.ts +0 -7
  295. package/src/runtime/guardian-action-conversation-turn.ts +1 -3
  296. package/src/runtime/guardian-action-followup-executor.ts +1 -1
  297. package/src/runtime/guardian-action-message-composer.ts +3 -23
  298. package/src/runtime/http-server.ts +17 -10
  299. package/src/runtime/http-types.ts +2 -3
  300. package/src/runtime/middleware/rate-limiter.ts +74 -20
  301. package/src/runtime/middleware/twilio-validation.ts +1 -11
  302. package/src/runtime/pending-interactions.ts +14 -12
  303. package/src/runtime/routes/channel-delivery-routes.ts +0 -1
  304. package/src/runtime/routes/channel-readiness-routes.ts +2 -0
  305. package/src/runtime/routes/conversation-routes.ts +73 -19
  306. package/src/runtime/routes/diagnostics-routes.ts +11 -9
  307. package/src/runtime/routes/events-routes.ts +21 -11
  308. package/src/runtime/routes/guardian-approval-interception.ts +20 -5
  309. package/src/runtime/routes/host-cu-routes.ts +97 -0
  310. package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
  311. package/src/runtime/routes/integrations/slack/share.ts +6 -6
  312. package/src/runtime/routes/integrations/twilio.ts +6 -5
  313. package/src/runtime/routes/log-export-routes.ts +126 -8
  314. package/src/runtime/routes/secret-routes.ts +3 -2
  315. package/src/runtime/routes/settings-routes.ts +113 -48
  316. package/src/runtime/routes/surface-action-routes.ts +1 -1
  317. package/src/runtime/routes/watch-routes.ts +128 -0
  318. package/src/schedule/integration-status.ts +10 -8
  319. package/src/security/credential-key.ts +14 -0
  320. package/src/security/keychain-broker-client.ts +5 -6
  321. package/src/security/oauth2.ts +1 -1
  322. package/src/security/token-manager.ts +145 -43
  323. package/src/skills/catalog-install.ts +358 -0
  324. package/src/skills/include-graph.ts +32 -0
  325. package/src/telegram/bot-username.ts +2 -3
  326. package/src/tools/apps/definitions.ts +0 -5
  327. package/src/tools/assets/materialize.ts +0 -5
  328. package/src/tools/assets/search.ts +0 -5
  329. package/src/tools/browser/headless-browser.ts +1 -67
  330. package/src/tools/browser/network-recorder.ts +1 -1
  331. package/src/tools/browser/network-recording-types.ts +1 -1
  332. package/src/tools/claude-code/claude-code.ts +0 -5
  333. package/src/tools/computer-use/definitions.ts +46 -11
  334. package/src/tools/computer-use/registry.ts +4 -5
  335. package/src/tools/credentials/broker.ts +5 -4
  336. package/src/tools/credentials/metadata-store.ts +22 -74
  337. package/src/tools/credentials/resolve.ts +2 -1
  338. package/src/tools/credentials/vault.ts +139 -151
  339. package/src/tools/filesystem/edit.ts +1 -6
  340. package/src/tools/filesystem/read.ts +0 -5
  341. package/src/tools/filesystem/write.ts +1 -6
  342. package/src/tools/host-filesystem/edit.ts +1 -6
  343. package/src/tools/host-filesystem/read.ts +1 -6
  344. package/src/tools/host-filesystem/write.ts +1 -6
  345. package/src/tools/mcp/mcp-tool-factory.ts +18 -1
  346. package/src/tools/memory/definitions.ts +0 -5
  347. package/src/tools/network/web-fetch.ts +0 -5
  348. package/src/tools/network/web-search.ts +0 -5
  349. package/src/tools/registry.ts +2 -7
  350. package/src/tools/schema-transforms.ts +99 -0
  351. package/src/tools/skills/load.ts +62 -8
  352. package/src/tools/swarm/delegate.ts +0 -5
  353. package/src/tools/system/avatar-generator.ts +0 -5
  354. package/src/tools/ui-surface/definitions.ts +0 -15
  355. package/src/tools/watch/screen-watch.ts +0 -5
  356. package/src/tools/watch/watch-state.ts +0 -12
  357. package/src/util/logger.ts +7 -41
  358. package/src/util/platform.ts +9 -28
  359. package/src/version.ts +10 -0
  360. package/src/watcher/providers/github.ts +51 -52
  361. package/src/watcher/providers/gmail.ts +88 -80
  362. package/src/watcher/providers/google-calendar.ts +94 -86
  363. package/src/watcher/providers/linear.ts +87 -93
  364. package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
  365. package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
  366. package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
  367. package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
  368. package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
  369. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
  370. package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
  371. package/src/cli/commands/dev.ts +0 -129
  372. package/src/cli/commands/map.ts +0 -391
  373. package/src/cli/commands/oauth.ts +0 -77
  374. package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +0 -16
  375. package/src/daemon/computer-use-session.ts +0 -1020
  376. package/src/daemon/ride-shotgun-handler.ts +0 -567
  377. package/src/oauth/provider-profiles.ts +0 -192
  378. package/src/prompts/computer-use-prompt.ts +0 -98
  379. package/src/runtime/routes/computer-use-routes.ts +0 -641
  380. package/src/runtime/telegram-streaming-delivery.test.ts +0 -597
  381. package/src/runtime/telegram-streaming-delivery.ts +0 -383
  382. package/src/tools/computer-use/request-computer-control.ts +0 -61
@@ -14,9 +14,15 @@ import { loadSkillCatalog } from "../../config/skills.js";
14
14
  import { normalizeActivationKey } from "../../daemon/handlers/config-voice.js";
15
15
  import { orchestrateOAuthConnect } from "../../oauth/connect-orchestrator.js";
16
16
  import {
17
- getProviderProfile,
17
+ getApp,
18
+ getConnectionByProvider,
19
+ getMostRecentAppByProvider,
20
+ getProvider,
21
+ } from "../../oauth/oauth-store.js";
22
+ import {
23
+ getProviderBehavior,
18
24
  resolveService,
19
- } from "../../oauth/provider-profiles.js";
25
+ } from "../../oauth/provider-behaviors.js";
20
26
  import {
21
27
  check,
22
28
  classifyRisk,
@@ -25,17 +31,23 @@ import {
25
31
  } from "../../permissions/checker.js";
26
32
  import { getSecureKey } from "../../security/secure-keys.js";
27
33
  import { parseToolManifestFile } from "../../skills/tool-manifest.js";
28
- import { assertMetadataWritable } from "../../tools/credentials/metadata-store.js";
29
34
  import {
30
35
  type ManifestOverride,
31
36
  resolveExecutionTarget,
32
37
  } from "../../tools/execution-target.js";
33
38
  import { getAllTools, getTool } from "../../tools/registry.js";
39
+ import {
40
+ injectReasonField,
41
+ REASON_SKIP_SET,
42
+ } from "../../tools/schema-transforms.js";
34
43
  import { isSideEffectTool } from "../../tools/side-effects.js";
35
44
  import { setAvatarTool } from "../../tools/system/avatar-generator.js";
36
45
  import { pathExists } from "../../util/fs.js";
37
46
  import { getLogger } from "../../util/logger.js";
38
47
  import { getWorkspaceDir } from "../../util/platform.js";
48
+ import { buildAssistantEvent } from "../assistant-event.js";
49
+ import { assistantEventHub } from "../assistant-event-hub.js";
50
+ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
39
51
  import { httpError } from "../http-errors.js";
40
52
  import type { RouteDefinition } from "../http-router.js";
41
53
  import { resolveWorkspacePath } from "./workspace-utils.js";
@@ -128,43 +140,39 @@ function sanitizeOAuthError(message: string): string {
128
140
  return "OAuth authentication failed. Please try again.";
129
141
  }
130
142
 
131
- /** Resolve client_secret from the keychain, checking canonical then alias service name. */
132
- function getClientSecret(
133
- resolvedService: string,
134
- rawService: string,
135
- ): string | undefined {
136
- return (
137
- getSecureKey(`credential:${resolvedService}:client_secret`) ??
138
- (resolvedService !== rawService
139
- ? getSecureKey(`credential:${rawService}:client_secret`)
140
- : undefined) ??
141
- undefined
142
- );
143
- }
144
-
145
143
  async function handleOAuthConnectStart(body: {
146
144
  service?: string;
147
145
  requestedScopes?: string[];
148
146
  }): Promise<Response> {
149
- try {
150
- assertMetadataWritable();
151
- } catch {
152
- return httpError(
153
- "UNPROCESSABLE_ENTITY",
154
- "Credential metadata file has an unrecognized version. Cannot store OAuth credentials.",
155
- 422,
156
- );
157
- }
158
-
159
147
  if (!body.service) {
160
148
  return httpError("BAD_REQUEST", "Missing required field: service", 400);
161
149
  }
162
150
 
163
151
  const resolvedService = resolveService(body.service);
164
152
 
165
- let clientId = getSecureKey(`credential:${resolvedService}:client_id`);
166
- if (!clientId && resolvedService !== body.service) {
167
- clientId = getSecureKey(`credential:${body.service}:client_id`);
153
+ // Resolve client_id and client_secret from oauth-store.
154
+ let clientId: string | undefined;
155
+ let clientSecret: string | undefined;
156
+
157
+ // Try existing connection first (re-auth flow)
158
+ const conn = getConnectionByProvider(resolvedService);
159
+ if (conn) {
160
+ const app = getApp(conn.oauthAppId);
161
+ if (app) {
162
+ clientId = app.clientId;
163
+ clientSecret = getSecureKey(`oauth_app/${app.id}/client_secret`);
164
+ }
165
+ }
166
+
167
+ // Fall back to most recent app for this provider (first-time connect with stored app)
168
+ if (!clientId) {
169
+ const dbApp = getMostRecentAppByProvider(resolvedService);
170
+ if (dbApp) {
171
+ clientId = dbApp.clientId;
172
+ if (!clientSecret) {
173
+ clientSecret = getSecureKey(`oauth_app/${dbApp.id}/client_secret`);
174
+ }
175
+ }
168
176
  }
169
177
 
170
178
  if (!clientId) {
@@ -175,12 +183,11 @@ async function handleOAuthConnectStart(body: {
175
183
  );
176
184
  }
177
185
 
178
- const clientSecret = getClientSecret(resolvedService, body.service);
179
-
180
- const profile = getProviderProfile(resolvedService);
186
+ const behavior = getProviderBehavior(resolvedService);
187
+ const providerRow = getProvider(resolvedService);
181
188
  const requiresSecret =
182
- profile?.setup?.requiresClientSecret ??
183
- !!(profile?.tokenEndpointAuthMethod || profile?.extraParams);
189
+ behavior?.setup?.requiresClientSecret ??
190
+ !!(providerRow?.tokenEndpointAuthMethod || providerRow?.extraParams);
184
191
  if (requiresSecret && !clientSecret) {
185
192
  return httpError(
186
193
  "BAD_REQUEST",
@@ -203,6 +210,45 @@ async function handleOAuthConnectStart(body: {
203
210
  openUrl: (url: string) => {
204
211
  authUrl = url;
205
212
  },
213
+ onDeferredComplete: (deferredResult) => {
214
+ // Prefer accountInfo from oauth-store when available.
215
+ let accountInfo = deferredResult.accountInfo;
216
+ try {
217
+ const conn = getConnectionByProvider(resolvedService);
218
+ if (conn?.accountInfo) accountInfo = conn.accountInfo;
219
+ } catch {
220
+ // DB not ready — use orchestrator value
221
+ }
222
+
223
+ // Emit oauth_connect_result to all connected SSE clients so the
224
+ // UI can update immediately when the deferred browser flow completes.
225
+ assistantEventHub
226
+ .publish(
227
+ buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, {
228
+ type: "oauth_connect_result",
229
+ success: deferredResult.success,
230
+ service: deferredResult.service,
231
+ accountInfo,
232
+ error: deferredResult.error,
233
+ }),
234
+ )
235
+ .catch((err) => {
236
+ log.warn(
237
+ { err, service: deferredResult.service },
238
+ "Failed to publish oauth_connect_result event",
239
+ );
240
+ });
241
+
242
+ if (!deferredResult.success) {
243
+ log.warn(
244
+ {
245
+ service: deferredResult.service,
246
+ err: deferredResult.error,
247
+ },
248
+ "Deferred OAuth connect failed",
249
+ );
250
+ }
251
+ },
206
252
  });
207
253
 
208
254
  if (!result.success) {
@@ -225,10 +271,19 @@ async function handleOAuthConnectStart(body: {
225
271
  });
226
272
  }
227
273
 
274
+ // Prefer accountInfo from oauth-store when available.
275
+ let responseAccountInfo = result.accountInfo;
276
+ try {
277
+ const conn = getConnectionByProvider(resolvedService);
278
+ if (conn?.accountInfo) responseAccountInfo = conn.accountInfo;
279
+ } catch {
280
+ // DB not ready — use orchestrator value
281
+ }
282
+
228
283
  return Response.json({
229
284
  ok: true,
230
285
  grantedScopes: result.grantedScopes,
231
- accountInfo: result.accountInfo,
286
+ accountInfo: responseAccountInfo,
232
287
  ...(authUrl ? { authUrl } : {}),
233
288
  });
234
289
  } catch (err) {
@@ -309,23 +364,34 @@ function resolveManifestOverride(
309
364
  function handleToolNamesList(): Response {
310
365
  const tools = getAllTools();
311
366
  const nameSet = new Set(tools.map((t) => t.name));
312
- const schemas: Record<
313
- string,
314
- {
315
- type: string;
316
- properties?: Record<string, unknown>;
317
- required?: string[];
318
- }
319
- > = {};
367
+ type SchemaShape = {
368
+ type: string;
369
+ properties?: Record<string, unknown>;
370
+ required?: string[];
371
+ };
372
+ const schemas: Record<string, SchemaShape> = {};
373
+
374
+ // Collect raw definitions from the registry so we can transform them.
375
+ const rawDefs: import("../../providers/types.js").ToolDefinition[] = [];
320
376
  for (const tool of tools) {
321
377
  try {
322
- const def = tool.getDefinition();
323
- schemas[tool.name] = def.input_schema as (typeof schemas)[string];
378
+ rawDefs.push(tool.getDefinition());
324
379
  } catch {
325
380
  // Skip tools whose definitions can't be resolved
326
381
  }
327
382
  }
328
383
 
384
+ // Apply reason injection so settings/debug schemas match runtime behavior.
385
+ const transformedDefs = injectReasonField(rawDefs, REASON_SKIP_SET);
386
+ for (const def of transformedDefs) {
387
+ schemas[def.name] = def.input_schema as SchemaShape;
388
+ }
389
+
390
+ // Skill manifest schemas are served raw (untransformed). Unlike runtime tool
391
+ // schemas which have `reason` injected via injectReasonField(), skill manifests
392
+ // reflect the original TOOLS.json content. This is intentional: skill tools are
393
+ // invoked through skill_execute (which has its own reason field), so their
394
+ // individual schemas are never sent to the LLM directly.
329
395
  try {
330
396
  const catalog = loadSkillCatalog();
331
397
  for (const skill of catalog) {
@@ -337,8 +403,7 @@ function handleToolNamesList(): Response {
337
403
  for (const entry of manifest.tools) {
338
404
  if (nameSet.has(entry.name)) continue;
339
405
  nameSet.add(entry.name);
340
- schemas[entry.name] =
341
- entry.input_schema as unknown as (typeof schemas)[string];
406
+ schemas[entry.name] = entry.input_schema as unknown as SchemaShape;
342
407
  }
343
408
  } catch {
344
409
  // Skip skills whose manifests can't be parsed
@@ -10,7 +10,7 @@ import type { RouteDefinition } from "../http-router.js";
10
10
 
11
11
  const log = getLogger("surface-action-routes");
12
12
 
13
- /** Any object that can handle a surface action (Session or ComputerUseSession). */
13
+ /** Any object that can handle a surface action. */
14
14
  interface SurfaceActionTarget {
15
15
  handleSurfaceAction(
16
16
  surfaceId: string,
@@ -0,0 +1,128 @@
1
+ /**
2
+ * HTTP route handler for watch (ambient observation) functionality.
3
+ *
4
+ * Decoupled from computer-use routes so that the watch endpoint has
5
+ * zero dependency on CU session state.
6
+ */
7
+
8
+ import { getLogger } from "../../util/logger.js";
9
+ import { httpError } from "../http-errors.js";
10
+ import type { RouteDefinition } from "../http-router.js";
11
+
12
+ const log = getLogger("watch-routes");
13
+
14
+ // ---------------------------------------------------------------------------
15
+ // Dependency injection interface
16
+ // ---------------------------------------------------------------------------
17
+
18
+ /**
19
+ * Minimal interface for watch observation handling.
20
+ * The daemon wires a concrete implementation at startup.
21
+ */
22
+ export interface WatchDeps {
23
+ /** Handle a watch observation. */
24
+ handleWatchObservation: (params: {
25
+ watchId: string;
26
+ sessionId: string;
27
+ ocrText: string;
28
+ appName?: string;
29
+ windowTitle?: string;
30
+ bundleIdentifier?: string;
31
+ timestamp: number;
32
+ captureIndex: number;
33
+ totalExpected: number;
34
+ }) => Promise<void>;
35
+ }
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Route handler
39
+ // ---------------------------------------------------------------------------
40
+
41
+ /**
42
+ * POST /v1/computer-use/watch — send a watch observation.
43
+ *
44
+ * Body: { watchId, sessionId, ocrText, appName?, windowTitle?,
45
+ * bundleIdentifier?, timestamp, captureIndex, totalExpected }
46
+ */
47
+ async function handleWatchObservationRoute(
48
+ req: Request,
49
+ deps: WatchDeps,
50
+ ): Promise<Response> {
51
+ const body = (await req.json()) as {
52
+ watchId?: string;
53
+ sessionId?: string;
54
+ ocrText?: string;
55
+ appName?: string;
56
+ windowTitle?: string;
57
+ bundleIdentifier?: string;
58
+ timestamp?: number;
59
+ captureIndex?: number;
60
+ totalExpected?: number;
61
+ };
62
+
63
+ if (!body.watchId || typeof body.watchId !== "string") {
64
+ return httpError("BAD_REQUEST", "watchId is required", 400);
65
+ }
66
+ if (!body.sessionId || typeof body.sessionId !== "string") {
67
+ return httpError("BAD_REQUEST", "sessionId is required", 400);
68
+ }
69
+ if (!body.ocrText || typeof body.ocrText !== "string") {
70
+ return httpError("BAD_REQUEST", "ocrText is required", 400);
71
+ }
72
+ if (typeof body.timestamp !== "number") {
73
+ return httpError("BAD_REQUEST", "timestamp is required", 400);
74
+ }
75
+ if (typeof body.captureIndex !== "number") {
76
+ return httpError("BAD_REQUEST", "captureIndex is required", 400);
77
+ }
78
+ if (typeof body.totalExpected !== "number") {
79
+ return httpError("BAD_REQUEST", "totalExpected is required", 400);
80
+ }
81
+
82
+ try {
83
+ await deps.handleWatchObservation({
84
+ watchId: body.watchId,
85
+ sessionId: body.sessionId,
86
+ ocrText: body.ocrText,
87
+ appName: body.appName,
88
+ windowTitle: body.windowTitle,
89
+ bundleIdentifier: body.bundleIdentifier,
90
+ timestamp: body.timestamp,
91
+ captureIndex: body.captureIndex,
92
+ totalExpected: body.totalExpected,
93
+ });
94
+
95
+ return Response.json({ ok: true });
96
+ } catch (err) {
97
+ const message = err instanceof Error ? err.message : String(err);
98
+ log.error(
99
+ { err, watchId: body.watchId },
100
+ "Failed to handle watch observation via HTTP",
101
+ );
102
+ return httpError("INTERNAL_ERROR", message, 500);
103
+ }
104
+ }
105
+
106
+ // ---------------------------------------------------------------------------
107
+ // Route definitions
108
+ // ---------------------------------------------------------------------------
109
+
110
+ export function watchRouteDefinitions(deps: {
111
+ getWatchDeps?: () => WatchDeps;
112
+ }): RouteDefinition[] {
113
+ const getDeps = (): WatchDeps => {
114
+ if (!deps.getWatchDeps) {
115
+ throw new Error("Watch deps not available");
116
+ }
117
+ return deps.getWatchDeps();
118
+ };
119
+
120
+ return [
121
+ {
122
+ endpoint: "computer-use/watch",
123
+ method: "POST",
124
+ policyKey: "computer-use/watch",
125
+ handler: async ({ req }) => handleWatchObservationRoute(req, getDeps()),
126
+ },
127
+ ];
128
+ }
@@ -1,5 +1,8 @@
1
1
  import { hasTwilioCredentials } from "../calls/twilio-rest.js";
2
- import { getSecureKey } from "../security/secure-keys.js";
2
+ import {
3
+ getConnectionByProvider,
4
+ isProviderConnected,
5
+ } from "../oauth/oauth-store.js";
3
6
 
4
7
  interface IntegrationProbe {
5
8
  name: string;
@@ -12,14 +15,12 @@ const INTEGRATION_PROBES: IntegrationProbe[] = [
12
15
  {
13
16
  name: "Gmail",
14
17
  category: "email",
15
- isConnected: () =>
16
- !!getSecureKey("credential:integration:gmail:access_token"),
18
+ isConnected: () => isProviderConnected("integration:gmail"),
17
19
  },
18
20
  {
19
21
  name: "Slack",
20
22
  category: "messaging",
21
- isConnected: () =>
22
- !!getSecureKey("credential:integration:slack:access_token"),
23
+ isConnected: () => isProviderConnected("integration:slack"),
23
24
  },
24
25
  {
25
26
  name: "Twilio",
@@ -29,9 +30,10 @@ const INTEGRATION_PROBES: IntegrationProbe[] = [
29
30
  {
30
31
  name: "Telegram",
31
32
  category: "messaging",
32
- isConnected: () =>
33
- !!getSecureKey("credential:telegram:bot_token") &&
34
- !!getSecureKey("credential:telegram:webhook_secret"),
33
+ isConnected: () => {
34
+ const conn = getConnectionByProvider("telegram");
35
+ return !!(conn && conn.status === "active");
36
+ },
35
37
  },
36
38
  ];
37
39
 
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Single source of truth for credential key format in the secure store.
3
+ *
4
+ * Keys follow the pattern: credential/{service}/{field}
5
+ */
6
+
7
+ /**
8
+ * Build a credential key for the secure store.
9
+ *
10
+ * @returns A key of the form `credential/{service}/{field}`
11
+ */
12
+ export function credentialKey(service: string, field: string): string {
13
+ return `credential/${service}/${field}`;
14
+ }
@@ -6,7 +6,7 @@
6
6
  * provides a graceful-fallback interface: every public method returns a
7
7
  * safe default on failure and never throws.
8
8
  *
9
- * Socket path: read from VELLUM_KEYCHAIN_BROKER_SOCKET env var.
9
+ * Socket path: derived from getRootDir() as `~/.vellum/keychain-broker.sock`.
10
10
  * Auth token: read from ~/.vellum/protected/keychain-broker.token on first
11
11
  * connection, cached for process lifetime.
12
12
  */
@@ -70,8 +70,8 @@ function getTokenPath(): string {
70
70
  return join(getRootDir(), "protected", "keychain-broker.token");
71
71
  }
72
72
 
73
- function getSocketPath(): string | undefined {
74
- return process.env.VELLUM_KEYCHAIN_BROKER_SOCKET;
73
+ function getSocketPath(): string {
74
+ return join(getRootDir(), "keychain-broker.sock");
75
75
  }
76
76
 
77
77
  // ---------------------------------------------------------------------------
@@ -172,7 +172,7 @@ export function createBrokerClient(): KeychainBrokerClient {
172
172
  function connect(): Promise<Socket> {
173
173
  return new Promise((resolve, reject) => {
174
174
  const socketPath = getSocketPath();
175
- if (!socketPath) {
175
+ if (!pathExists(socketPath)) {
176
176
  reject(new Error("No socket path"));
177
177
  return;
178
178
  }
@@ -328,8 +328,7 @@ export function createBrokerClient(): KeychainBrokerClient {
328
328
  return {
329
329
  isAvailable(): boolean {
330
330
  if (permanentlyUnavailable) return false;
331
- const socketPath = getSocketPath();
332
- if (!socketPath) return false;
331
+ if (!pathExists(getSocketPath())) return false;
333
332
  return pathExists(getTokenPath());
334
333
  },
335
334
 
@@ -691,7 +691,7 @@ export async function startOAuth2Flow(
691
691
  if (transport === "gateway") {
692
692
  if (!hasPublicUrl) {
693
693
  throw new Error(
694
- "Gateway transport requires a public ingress URL. Set ingress.publicBaseUrl or INGRESS_PUBLIC_BASE_URL, or use loopback transport.",
694
+ "Gateway transport requires a public ingress URL. Set ingress.publicBaseUrl, or use loopback transport.",
695
695
  );
696
696
  }
697
697
  log.debug({ transport: "gateway" }, "OAuth2 flow starting");