@vellumai/assistant 0.5.15 → 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 (503) hide show
  1. package/ARCHITECTURE.md +3 -3
  2. package/Dockerfile +0 -3
  3. package/docs/architecture/integrations.md +15 -14
  4. package/knip.json +4 -1
  5. package/openapi.yaml +670 -122
  6. package/package.json +1 -1
  7. package/src/__tests__/actor-token-service.test.ts +68 -0
  8. package/src/__tests__/agent-loop.test.ts +0 -32
  9. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  10. package/src/__tests__/anthropic-provider.test.ts +57 -3
  11. package/src/__tests__/app-compiler.test.ts +120 -0
  12. package/src/__tests__/assistant-feature-flags-integration.test.ts +5 -377
  13. package/src/__tests__/call-conversation-messages.test.ts +2 -6
  14. package/src/__tests__/call-domain.test.ts +2 -6
  15. package/src/__tests__/call-pointer-messages.test.ts +2 -14
  16. package/src/__tests__/call-recovery.test.ts +2 -6
  17. package/src/__tests__/call-routes-http.test.ts +2 -6
  18. package/src/__tests__/call-store.test.ts +2 -6
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
  20. package/src/__tests__/canonical-guardian-store.test.ts +2 -6
  21. package/src/__tests__/ces-rpc-credential-backend.test.ts +4 -1
  22. package/src/__tests__/channel-delivery-store.test.ts +2 -6
  23. package/src/__tests__/channel-retry-sweep.test.ts +2 -6
  24. package/src/__tests__/checker.test.ts +84 -3
  25. package/src/__tests__/clawhub.test.ts +54 -24
  26. package/src/__tests__/cli-command-risk-guard.test.ts +108 -6
  27. package/src/__tests__/cli-memory.test.ts +377 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -2
  29. package/src/__tests__/config-schema.test.ts +1 -3
  30. package/src/__tests__/config-set-platform-guard.test.ts +302 -0
  31. package/src/__tests__/config-watcher-feature-flags.test.ts +211 -0
  32. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
  33. package/src/__tests__/contacts-tools.test.ts +31 -0
  34. package/src/__tests__/context-overflow-reducer.test.ts +86 -0
  35. package/src/__tests__/context-token-estimator.test.ts +175 -10
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +9 -0
  37. package/src/__tests__/conversation-agent-loop.test.ts +9 -0
  38. package/src/__tests__/conversation-attachments.test.ts +2 -6
  39. package/src/__tests__/conversation-attention-store.test.ts +2 -6
  40. package/src/__tests__/conversation-clear-safety.test.ts +2 -6
  41. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
  42. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
  43. package/src/__tests__/conversation-disk-view.test.ts +2 -6
  44. package/src/__tests__/conversation-error.test.ts +33 -2
  45. package/src/__tests__/conversation-fork-crud.test.ts +2 -6
  46. package/src/__tests__/conversation-history-web-search.test.ts +5 -0
  47. package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
  48. package/src/__tests__/conversation-media-retry.test.ts +91 -0
  49. package/src/__tests__/conversation-runtime-assembly.test.ts +7 -4
  50. package/src/__tests__/conversation-slash-commands.test.ts +2 -6
  51. package/src/__tests__/conversation-starter-routes.test.ts +20 -11
  52. package/src/__tests__/conversation-store.test.ts +2 -6
  53. package/src/__tests__/conversation-usage.test.ts +3 -6
  54. package/src/__tests__/conversation-wipe.test.ts +11 -408
  55. package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
  56. package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
  57. package/src/__tests__/credential-security-e2e.test.ts +6 -1
  58. package/src/__tests__/docker-signing-key-bootstrap.test.ts +7 -73
  59. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -7
  60. package/src/__tests__/followup-tools.test.ts +2 -6
  61. package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
  62. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
  63. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
  64. package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
  65. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
  66. package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
  67. package/src/__tests__/guardian-action-store.test.ts +2 -6
  68. package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
  69. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
  70. package/src/__tests__/guardian-dispatch.test.ts +2 -6
  71. package/src/__tests__/guardian-grant-minting.test.ts +2 -14
  72. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
  73. package/src/__tests__/guardian-routing-invariants.test.ts +343 -6
  74. package/src/__tests__/guardian-routing-state.test.ts +2 -6
  75. package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
  76. package/src/__tests__/heartbeat-service.test.ts +1 -3
  77. package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
  78. package/src/__tests__/injection-block.test.ts +154 -0
  79. package/src/__tests__/install-meta.test.ts +506 -0
  80. package/src/__tests__/install-skill-routing.test.ts +292 -0
  81. package/src/__tests__/intent-routing.test.ts +6 -18
  82. package/src/__tests__/invite-redemption-service.test.ts +2 -6
  83. package/src/__tests__/invite-routes-http.test.ts +2 -6
  84. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -14
  85. package/src/__tests__/list-messages-attachments.test.ts +2 -6
  86. package/src/__tests__/llm-context-route-provider.test.ts +2 -6
  87. package/src/__tests__/llm-request-log-turn-query.test.ts +2 -6
  88. package/src/__tests__/llm-usage-store.test.ts +2 -6
  89. package/src/__tests__/log-export-workspace.test.ts +4 -34
  90. package/src/__tests__/managed-skill-lifecycle.test.ts +7 -37
  91. package/src/__tests__/managed-store.test.ts +40 -21
  92. package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
  93. package/src/__tests__/memory-recall-log-store.test.ts +2 -6
  94. package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
  95. package/src/__tests__/messaging-send-tool.test.ts +6 -6
  96. package/src/__tests__/migration-cross-version-compatibility.test.ts +1 -29
  97. package/src/__tests__/migration-export-http.test.ts +3 -34
  98. package/src/__tests__/migration-import-commit-http.test.ts +1 -29
  99. package/src/__tests__/migration-import-preflight-http.test.ts +3 -34
  100. package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +2 -1
  101. package/src/__tests__/non-member-access-request.test.ts +2 -6
  102. package/src/__tests__/notification-guardian-path.test.ts +2 -6
  103. package/src/__tests__/oauth-apps-routes.test.ts +120 -10
  104. package/src/__tests__/oauth-cli.test.ts +364 -2
  105. package/src/__tests__/oauth-connect-orchestrator.test.ts +709 -0
  106. package/src/__tests__/oauth-provider-serializer.test.ts +2 -1
  107. package/src/__tests__/oauth-provider-visibility.test.ts +149 -0
  108. package/src/__tests__/oauth-providers-routes.test.ts +5 -2
  109. package/src/__tests__/oauth-store.test.ts +0 -5
  110. package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
  111. package/src/__tests__/outlook-attachments.test.ts +301 -0
  112. package/src/__tests__/outlook-automation-tools.test.ts +425 -0
  113. package/src/__tests__/outlook-categories.test.ts +212 -0
  114. package/src/__tests__/outlook-client-automation.test.ts +246 -0
  115. package/src/__tests__/outlook-compose-tools.test.ts +325 -0
  116. package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
  117. package/src/__tests__/outlook-email-watcher.test.ts +322 -0
  118. package/src/__tests__/outlook-follow-up.test.ts +196 -0
  119. package/src/__tests__/outlook-messaging-provider.test.ts +1071 -0
  120. package/src/__tests__/outlook-trash.test.ts +77 -0
  121. package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
  122. package/src/__tests__/path-policy.test.ts +2 -17
  123. package/src/__tests__/permission-types.test.ts +0 -1
  124. package/src/__tests__/platform-callback-registration.test.ts +7 -11
  125. package/src/__tests__/playbook-execution.test.ts +76 -80
  126. package/src/__tests__/playbook-tools.test.ts +5 -7
  127. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  128. package/src/__tests__/provider-error-scenarios.test.ts +21 -2
  129. package/src/__tests__/qdrant-manager.test.ts +68 -21
  130. package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
  131. package/src/__tests__/registry.test.ts +2 -2
  132. package/src/__tests__/require-fresh-approval.test.ts +64 -3
  133. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
  134. package/src/__tests__/runtime-events-sse.test.ts +2 -6
  135. package/src/__tests__/sandbox-diagnostics.test.ts +20 -29
  136. package/src/__tests__/scaffold-managed-skill-tool.test.ts +2 -10
  137. package/src/__tests__/schedule-store.test.ts +2 -6
  138. package/src/__tests__/schedule-tools.test.ts +2 -6
  139. package/src/__tests__/scheduler-recurrence.test.ts +1 -5
  140. package/src/__tests__/scoped-approval-grants.test.ts +2 -6
  141. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
  142. package/src/__tests__/search-skills-unified.test.ts +421 -0
  143. package/src/__tests__/secret-allowlist.test.ts +20 -35
  144. package/src/__tests__/secret-onetime-send.test.ts +2 -0
  145. package/src/__tests__/send-endpoint-busy.test.ts +2 -6
  146. package/src/__tests__/sequence-store.test.ts +2 -6
  147. package/src/__tests__/server-history-render.test.ts +2 -6
  148. package/src/__tests__/shell-credential-ref.test.ts +0 -5
  149. package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
  150. package/src/__tests__/skill-feature-flags.test.ts +6 -6
  151. package/src/__tests__/skill-load-feature-flag.test.ts +13 -54
  152. package/src/__tests__/skill-load-inline-command.test.ts +3 -65
  153. package/src/__tests__/skill-load-inline-includes.test.ts +3 -65
  154. package/src/__tests__/skill-load-tool.test.ts +3 -67
  155. package/src/__tests__/skill-memory.test.ts +480 -195
  156. package/src/__tests__/skills-uninstall.test.ts +2 -2
  157. package/src/__tests__/skills.test.ts +23 -50
  158. package/src/__tests__/slack-channel-config.test.ts +2 -21
  159. package/src/__tests__/slack-inbound-verification.test.ts +2 -6
  160. package/src/__tests__/starter-bundle.test.ts +2 -8
  161. package/src/__tests__/stt-hints.test.ts +7 -2
  162. package/src/__tests__/system-prompt.test.ts +25 -45
  163. package/src/__tests__/task-compiler.test.ts +2 -27
  164. package/src/__tests__/task-management-tools.test.ts +2 -27
  165. package/src/__tests__/task-memory-cleanup.test.ts +173 -250
  166. package/src/__tests__/task-runner.test.ts +2 -27
  167. package/src/__tests__/task-scheduler.test.ts +2 -27
  168. package/src/__tests__/terminal-tools.test.ts +1 -17
  169. package/src/__tests__/test-preload.ts +3 -0
  170. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +0 -79
  171. package/src/__tests__/tool-approval-handler.test.ts +4 -27
  172. package/src/__tests__/tool-execution-abort-cleanup.test.ts +2 -11
  173. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -25
  174. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  175. package/src/__tests__/tool-executor.test.ts +0 -1
  176. package/src/__tests__/tool-grant-request-escalation.test.ts +4 -27
  177. package/src/__tests__/tool-preview-lifecycle.test.ts +0 -20
  178. package/src/__tests__/tool-side-effects-slack-dm.test.ts +276 -0
  179. package/src/__tests__/trust-store.test.ts +10 -42
  180. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -30
  181. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +3 -27
  182. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -28
  183. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -28
  184. package/src/__tests__/trusted-contact-verification.test.ts +2 -28
  185. package/src/__tests__/turn-boundary-resolution.test.ts +2 -34
  186. package/src/__tests__/twilio-provider.test.ts +0 -16
  187. package/src/__tests__/twilio-routes-twiml.test.ts +7 -12
  188. package/src/__tests__/twilio-routes.test.ts +0 -24
  189. package/src/__tests__/update-bulletin.test.ts +17 -89
  190. package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -26
  191. package/src/__tests__/usage-routes.test.ts +2 -27
  192. package/src/__tests__/user-reference.test.ts +1 -5
  193. package/src/__tests__/vbundle-pax-and-symlink.test.ts +4 -34
  194. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +2 -53
  195. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  196. package/src/__tests__/voice-invite-redemption.test.ts +2 -27
  197. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -30
  198. package/src/__tests__/voice-session-bridge.test.ts +2 -27
  199. package/src/__tests__/volume-security-guard.test.ts +2 -0
  200. package/src/__tests__/workspace-lifecycle.test.ts +29 -1
  201. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -29
  202. package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +2 -2
  203. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +4 -29
  204. package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
  205. package/src/__tests__/workspace-migration-down-functions.test.ts +0 -6
  206. package/src/__tests__/workspace-policy.test.ts +1 -1
  207. package/src/acp/client-handler.ts +1 -2
  208. package/src/agent/attachments.ts +7 -2
  209. package/src/agent/image-optimize.ts +165 -0
  210. package/src/agent/loop.ts +1 -15
  211. package/src/bundler/app-compiler.ts +179 -2
  212. package/src/bundler/package-resolver.ts +3 -5
  213. package/src/cli/__tests__/notifications.test.ts +1 -24
  214. package/src/cli/cli-memory.ts +179 -0
  215. package/src/cli/commands/avatar.ts +3 -3
  216. package/src/cli/commands/config.ts +26 -13
  217. package/src/cli/commands/doctor.ts +2 -2
  218. package/src/cli/commands/memory.ts +41 -55
  219. package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
  220. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
  221. package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
  222. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
  223. package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
  224. package/src/cli/commands/oauth/connect.ts +26 -6
  225. package/src/cli/commands/oauth/mode.ts +7 -0
  226. package/src/cli/commands/oauth/providers.ts +49 -42
  227. package/src/cli/commands/oauth/shared.ts +39 -3
  228. package/src/cli/commands/platform/__tests__/connect.test.ts +3 -49
  229. package/src/cli/commands/platform/__tests__/disconnect.test.ts +3 -49
  230. package/src/cli/commands/platform/__tests__/status.test.ts +5 -55
  231. package/src/cli/commands/platform/index.ts +16 -16
  232. package/src/cli/commands/skills.ts +88 -16
  233. package/src/cli/commands/trust.ts +2 -2
  234. package/src/cli/lib/daemon-credential-client.ts +2 -3
  235. package/src/config/bundled-skills/acp/TOOLS.json +1 -1
  236. package/src/config/bundled-skills/computer-use/TOOLS.json +7 -7
  237. package/src/config/bundled-skills/contacts/SKILL.md +0 -1
  238. package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
  239. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
  240. package/src/config/bundled-skills/gmail/SKILL.md +2 -10
  241. package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
  242. package/src/config/bundled-skills/messaging/SKILL.md +26 -19
  243. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
  244. package/src/config/bundled-skills/outlook/SKILL.md +189 -0
  245. package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
  246. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
  247. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
  248. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
  249. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
  250. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
  251. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
  252. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
  253. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
  254. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
  255. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
  256. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
  257. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
  258. package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
  259. package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
  260. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
  261. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
  262. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
  263. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
  264. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
  265. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
  266. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
  267. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
  268. package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
  269. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
  270. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
  271. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
  272. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
  273. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  274. package/src/config/bundled-skills/slack/SKILL.md +1 -7
  275. package/src/config/bundled-tool-registry.ts +56 -4
  276. package/src/config/env-registry.ts +15 -8
  277. package/src/config/feature-flag-registry.json +29 -116
  278. package/src/config/loader.ts +4 -0
  279. package/src/config/schemas/platform.ts +8 -0
  280. package/src/config/schemas/security.ts +0 -6
  281. package/src/config/schemas/services.ts +8 -0
  282. package/src/config/schemas/timeouts.ts +1 -1
  283. package/src/config/skills.ts +18 -7
  284. package/src/context/token-estimator.ts +25 -18
  285. package/src/context/window-manager.ts +32 -9
  286. package/src/credential-execution/approval-bridge.ts +0 -1
  287. package/src/credential-execution/process-manager.ts +3 -1
  288. package/src/daemon/config-watcher.ts +51 -0
  289. package/src/daemon/context-overflow-reducer.ts +46 -2
  290. package/src/daemon/conversation-agent-loop-handlers.ts +123 -82
  291. package/src/daemon/conversation-agent-loop.ts +99 -63
  292. package/src/daemon/conversation-error.ts +31 -8
  293. package/src/daemon/conversation-lifecycle.ts +33 -0
  294. package/src/daemon/conversation-media-retry.ts +85 -7
  295. package/src/daemon/conversation-notifiers.ts +4 -1
  296. package/src/daemon/conversation-process.ts +1 -0
  297. package/src/daemon/conversation-runtime-assembly.ts +5 -0
  298. package/src/daemon/conversation-usage.ts +1 -0
  299. package/src/daemon/conversation.ts +41 -2
  300. package/src/daemon/daemon-control.ts +8 -2
  301. package/src/daemon/handlers/shared.ts +22 -12
  302. package/src/daemon/handlers/skills.ts +423 -201
  303. package/src/daemon/lifecycle.ts +52 -4
  304. package/src/daemon/main.ts +5 -1
  305. package/src/daemon/message-types/conversations.ts +5 -1
  306. package/src/daemon/message-types/messages.ts +3 -1
  307. package/src/daemon/message-types/skills.ts +97 -36
  308. package/src/daemon/providers-setup.ts +7 -0
  309. package/src/daemon/server.ts +35 -22
  310. package/src/daemon/tool-side-effects.ts +27 -5
  311. package/src/events/domain-events.ts +1 -2
  312. package/src/heartbeat/heartbeat-service.ts +1 -0
  313. package/src/hooks/cli.ts +2 -2
  314. package/src/hooks/runner.ts +15 -38
  315. package/src/inbound/platform-callback-registration.ts +14 -14
  316. package/src/memory/admin.ts +11 -45
  317. package/src/memory/conversation-bootstrap.ts +2 -0
  318. package/src/memory/conversation-crud.ts +242 -348
  319. package/src/memory/conversation-group-migration.ts +157 -0
  320. package/src/memory/conversation-queries.ts +4 -2
  321. package/src/memory/db-init.ts +39 -3
  322. package/src/memory/embed.ts +73 -0
  323. package/src/memory/embedding-backend.ts +8 -14
  324. package/src/memory/embedding-runtime-manager.ts +12 -114
  325. package/src/memory/fingerprint.ts +2 -2
  326. package/src/memory/graph/bootstrap.ts +512 -0
  327. package/src/memory/graph/capability-seed.ts +297 -0
  328. package/src/memory/graph/consolidation.ts +691 -0
  329. package/src/memory/graph/conversation-graph-memory.ts +630 -0
  330. package/src/memory/graph/decay.test.ts +208 -0
  331. package/src/memory/graph/decay.ts +195 -0
  332. package/src/memory/graph/extraction-job.ts +69 -0
  333. package/src/memory/graph/extraction.test.ts +936 -0
  334. package/src/memory/graph/extraction.ts +1254 -0
  335. package/src/memory/graph/graph-search.ts +266 -0
  336. package/src/memory/graph/image-ref-utils.ts +29 -0
  337. package/src/memory/graph/injection.test.ts +513 -0
  338. package/src/memory/graph/injection.ts +439 -0
  339. package/src/memory/graph/inspect.ts +534 -0
  340. package/src/memory/graph/narrative.ts +267 -0
  341. package/src/memory/graph/pattern-scan.ts +269 -0
  342. package/src/memory/graph/retriever.ts +1008 -0
  343. package/src/memory/graph/scoring.test.ts +548 -0
  344. package/src/memory/graph/scoring.ts +232 -0
  345. package/src/memory/graph/serendipity.ts +65 -0
  346. package/src/memory/graph/store.test.ts +1050 -0
  347. package/src/memory/graph/store.ts +699 -0
  348. package/src/memory/graph/tool-handlers.ts +426 -0
  349. package/src/memory/graph/tools.ts +141 -0
  350. package/src/memory/graph/triggers.test.ts +487 -0
  351. package/src/memory/graph/triggers.ts +223 -0
  352. package/src/memory/graph/types.ts +271 -0
  353. package/src/memory/group-crud.ts +191 -0
  354. package/src/memory/indexer.ts +37 -19
  355. package/src/memory/job-handlers/cleanup.ts +0 -53
  356. package/src/memory/job-handlers/conversation-starters.ts +91 -53
  357. package/src/memory/job-handlers/embedding.test.ts +3 -27
  358. package/src/memory/job-handlers/embedding.ts +5 -31
  359. package/src/memory/job-handlers/index-maintenance.ts +23 -11
  360. package/src/memory/job-handlers/summarization.ts +32 -17
  361. package/src/memory/job-utils.ts +1 -1
  362. package/src/memory/jobs-store.ts +50 -70
  363. package/src/memory/jobs-worker.ts +147 -112
  364. package/src/memory/llm-usage-store.ts +35 -2
  365. package/src/memory/message-content.ts +1 -0
  366. package/src/memory/migrations/201-oauth-providers-feature-flag.ts +11 -0
  367. package/src/memory/migrations/202-drop-callback-transport-column.ts +13 -0
  368. package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
  369. package/src/memory/migrations/203-drop-memory-items-tables.ts +23 -0
  370. package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
  371. package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
  372. package/src/memory/migrations/index.ts +6 -0
  373. package/src/memory/migrations/registry.ts +8 -0
  374. package/src/memory/qdrant-client.ts +44 -17
  375. package/src/memory/qdrant-manager.ts +26 -5
  376. package/src/memory/schema/index.ts +1 -0
  377. package/src/memory/schema/memory-graph.ts +139 -0
  378. package/src/memory/schema/oauth.ts +1 -1
  379. package/src/memory/search/semantic.ts +47 -91
  380. package/src/memory/slack-thread-store.ts +17 -0
  381. package/src/memory/task-memory-cleanup.ts +28 -50
  382. package/src/messaging/providers/outlook/adapter.ts +200 -0
  383. package/src/messaging/providers/outlook/client.ts +610 -0
  384. package/src/messaging/providers/outlook/types.ts +201 -0
  385. package/src/notifications/adapters/macos.ts +1 -0
  386. package/src/notifications/adapters/slack.ts +1 -1
  387. package/src/notifications/copy-composer.ts +9 -0
  388. package/src/notifications/signal.ts +16 -0
  389. package/src/oauth/__tests__/identity-verifier.test.ts +1 -1
  390. package/src/oauth/connect-orchestrator.ts +10 -3
  391. package/src/oauth/oauth-store.ts +10 -11
  392. package/src/oauth/provider-serializer.ts +3 -0
  393. package/src/oauth/provider-visibility.ts +16 -0
  394. package/src/oauth/seed-providers.ts +50 -17
  395. package/src/permissions/checker.ts +62 -9
  396. package/src/permissions/defaults.ts +4 -4
  397. package/src/permissions/types.ts +2 -4
  398. package/src/permissions/workspace-policy.ts +1 -1
  399. package/src/playbooks/playbook-compiler.ts +19 -18
  400. package/src/playbooks/types.ts +4 -3
  401. package/src/prompts/system-prompt.ts +6 -93
  402. package/src/prompts/templates/UPDATES.md +6 -0
  403. package/src/providers/anthropic/client.ts +47 -19
  404. package/src/providers/gemini/client.ts +1 -1
  405. package/src/providers/openai/client.ts +1 -1
  406. package/src/providers/registry.ts +1 -1
  407. package/src/providers/retry.ts +19 -3
  408. package/src/runtime/actor-trust-resolver.ts +5 -1
  409. package/src/runtime/auth/__tests__/credential-service.test.ts +1 -27
  410. package/src/runtime/auth/__tests__/token-service.test.ts +1 -25
  411. package/src/runtime/auth/route-policy.ts +7 -4
  412. package/src/runtime/guardian-reply-router.ts +10 -2
  413. package/src/runtime/http-server.ts +23 -3
  414. package/src/runtime/middleware/auth.ts +20 -0
  415. package/src/runtime/routes/attachment-routes.test.ts +106 -0
  416. package/src/runtime/routes/attachment-routes.ts +106 -16
  417. package/src/runtime/routes/brain-graph-routes.ts +21 -22
  418. package/src/runtime/routes/btw-routes.ts +8 -0
  419. package/src/runtime/routes/conversation-management-routes.ts +2 -0
  420. package/src/runtime/routes/conversation-query-routes.ts +2 -58
  421. package/src/runtime/routes/conversation-starter-routes.ts +2 -2
  422. package/src/runtime/routes/debug-routes.ts +1 -1
  423. package/src/runtime/routes/global-search-routes.ts +21 -19
  424. package/src/runtime/routes/group-routes.ts +207 -0
  425. package/src/runtime/routes/guardian-action-routes.ts +21 -10
  426. package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
  427. package/src/runtime/routes/inbound-message-handler.ts +19 -0
  428. package/src/runtime/routes/inbound-stages/background-dispatch.ts +43 -2
  429. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
  430. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
  431. package/src/runtime/routes/memory-item-routes.test.ts +2 -31
  432. package/src/runtime/routes/memory-item-routes.ts +385 -341
  433. package/src/runtime/routes/oauth-apps.ts +18 -1
  434. package/src/runtime/routes/oauth-providers.ts +13 -1
  435. package/src/runtime/routes/schedule-routes.ts +2 -0
  436. package/src/runtime/routes/settings-routes.ts +1 -0
  437. package/src/runtime/routes/skills-routes.ts +103 -37
  438. package/src/runtime/routes/usage-routes.ts +19 -2
  439. package/src/runtime/routes/work-items-routes.test.ts +2 -27
  440. package/src/runtime/routes/workspace-routes.test.ts +3 -27
  441. package/src/schedule/scheduler.ts +8 -1
  442. package/src/security/oauth2.ts +1 -1
  443. package/src/security/secret-allowlist.ts +4 -4
  444. package/src/security/secure-keys.ts +4 -8
  445. package/src/shared/provider-env-vars.ts +19 -0
  446. package/src/skills/catalog-cache.ts +5 -0
  447. package/src/skills/catalog-install.ts +15 -14
  448. package/src/skills/clawhub.ts +134 -154
  449. package/src/skills/install-meta.ts +208 -0
  450. package/src/skills/managed-store.ts +27 -16
  451. package/src/skills/skill-memory.ts +210 -96
  452. package/src/skills/skillssh-registry.ts +19 -17
  453. package/src/tasks/task-runner.ts +3 -1
  454. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
  455. package/src/tools/browser/runtime-check.ts +3 -1
  456. package/src/tools/memory/register.ts +63 -46
  457. package/src/tools/permission-checker.ts +7 -19
  458. package/src/tools/shared/filesystem/image-read.ts +22 -85
  459. package/src/tools/skills/skill-script-runner.ts +1 -1
  460. package/src/tools/terminal/safe-env.ts +1 -0
  461. package/src/tools/tool-manifest.ts +3 -3
  462. package/src/util/browser.ts +25 -10
  463. package/src/util/bun-runtime.ts +172 -0
  464. package/src/util/device-id.ts +3 -65
  465. package/src/watcher/providers/outlook-calendar.ts +343 -0
  466. package/src/watcher/providers/outlook.ts +198 -0
  467. package/src/workspace/git-service.ts +27 -6
  468. package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
  469. package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
  470. package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
  471. package/src/workspace/migrations/registry.ts +6 -0
  472. package/src/__tests__/context-memory-e2e.test.ts +0 -415
  473. package/src/__tests__/journal-context.test.ts +0 -268
  474. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
  475. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
  476. package/src/__tests__/memory-query-builder.test.ts +0 -59
  477. package/src/__tests__/memory-recall-quality.test.ts +0 -1046
  478. package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
  479. package/src/__tests__/memory-regressions.test.ts +0 -3696
  480. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
  481. package/src/daemon/conversation-memory.ts +0 -207
  482. package/src/memory/conversation-starters-cadence.ts +0 -74
  483. package/src/memory/items-extractor.ts +0 -860
  484. package/src/memory/job-handlers/batch-extraction.ts +0 -741
  485. package/src/memory/job-handlers/extraction.ts +0 -40
  486. package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -383
  487. package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
  488. package/src/memory/journal-memory.ts +0 -224
  489. package/src/memory/query-builder.ts +0 -47
  490. package/src/memory/query-expansion.ts +0 -83
  491. package/src/memory/retriever.test.ts +0 -1590
  492. package/src/memory/retriever.ts +0 -1323
  493. package/src/memory/search/formatting.test.ts +0 -140
  494. package/src/memory/search/formatting.ts +0 -262
  495. package/src/memory/search/mmr.ts +0 -136
  496. package/src/memory/search/ranking.ts +0 -15
  497. package/src/memory/search/staleness.ts +0 -40
  498. package/src/memory/search/tier-classifier.ts +0 -18
  499. package/src/memory/search/types.ts +0 -121
  500. package/src/prompts/journal-context.ts +0 -156
  501. package/src/tools/memory/definitions.ts +0 -69
  502. package/src/tools/memory/handlers.test.ts +0 -590
  503. package/src/tools/memory/handlers.ts +0 -434
@@ -1,67 +1,56 @@
1
1
  import { getConfig } from "../../config/loader.js";
2
+ import {
3
+ handleRecall,
4
+ handleRemember,
5
+ type RecallInput,
6
+ type RememberInput,
7
+ } from "../../memory/graph/tool-handlers.js";
8
+ import {
9
+ graphRecallDefinition,
10
+ graphRememberDefinition,
11
+ } from "../../memory/graph/tools.js";
2
12
  import { RiskLevel } from "../../permissions/types.js";
3
13
  import type { ToolDefinition } from "../../providers/types.js";
4
14
  import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
5
- import {
6
- memoryManageDefinition,
7
- memoryRecallDefinition,
8
- } from "./definitions.js";
9
- import {
10
- handleMemoryDelete,
11
- handleMemoryRecall,
12
- handleMemorySave,
13
- handleMemoryUpdate,
14
- } from "./handlers.js";
15
15
 
16
- // ── memory_manage ────────────────────────────────────────────────────
16
+ // ── remember ────────────────────────────────────────────────────────
17
17
 
18
- class MemoryManageTool implements Tool {
19
- name = "memory_manage";
20
- description = memoryManageDefinition.description;
18
+ class RememberTool implements Tool {
19
+ name = "remember";
20
+ description = graphRememberDefinition.description;
21
21
  category = "memory";
22
22
  defaultRiskLevel = RiskLevel.Low;
23
23
 
24
24
  getDefinition(): ToolDefinition {
25
- return memoryManageDefinition;
25
+ return graphRememberDefinition;
26
26
  }
27
27
 
28
28
  async execute(
29
29
  input: Record<string, unknown>,
30
30
  context: ToolContext,
31
31
  ): Promise<ToolExecutionResult> {
32
- const config = getConfig();
33
- switch (input.op) {
34
- case "save":
35
- return handleMemorySave(
36
- input,
37
- config,
38
- context.conversationId,
39
- context.requestId,
40
- context.memoryScopeId,
41
- );
42
- case "update":
43
- return handleMemoryUpdate(input, config, context.memoryScopeId);
44
- case "delete":
45
- return handleMemoryDelete(input, config, context.memoryScopeId);
46
- default:
47
- return {
48
- content: `Error: unknown op "${input.op}". Must be one of: save, update, delete`,
49
- isError: true,
50
- };
51
- }
32
+ const result = handleRemember(
33
+ input as unknown as RememberInput,
34
+ context.conversationId,
35
+ context.memoryScopeId ?? "default",
36
+ );
37
+ return {
38
+ content: result.message,
39
+ isError: !result.success,
40
+ };
52
41
  }
53
42
  }
54
43
 
55
- // ── memory_recall ────────────────────────────────────────────────────
44
+ // ── recall ──────────────────────────────────────────────────────────
56
45
 
57
- class MemoryRecallTool implements Tool {
58
- name = "memory_recall";
59
- description = memoryRecallDefinition.description;
46
+ class RecallTool implements Tool {
47
+ name = "recall";
48
+ description = graphRecallDefinition.description;
60
49
  category = "memory";
61
50
  defaultRiskLevel = RiskLevel.Low;
62
51
 
63
52
  getDefinition(): ToolDefinition {
64
- return memoryRecallDefinition;
53
+ return graphRecallDefinition;
65
54
  }
66
55
 
67
56
  async execute(
@@ -69,16 +58,44 @@ class MemoryRecallTool implements Tool {
69
58
  context: ToolContext,
70
59
  ): Promise<ToolExecutionResult> {
71
60
  const config = getConfig();
72
- return handleMemoryRecall(
73
- input,
61
+ const result = await handleRecall(
62
+ input as unknown as RecallInput,
74
63
  config,
75
- context.memoryScopeId,
76
- context.conversationId,
64
+ context.memoryScopeId ?? "default",
77
65
  );
66
+
67
+ if (result.results.length === 0) {
68
+ return { content: "No results found.", isError: false };
69
+ }
70
+
71
+ const formatted = result.results
72
+ .map((r) => {
73
+ const ts = formatTimestamp(r.created);
74
+ const meta =
75
+ result.mode === "memory"
76
+ ? `[${r.type}] ${ts} (confidence: ${r.confidence.toFixed(2)}, score: ${r.score.toFixed(3)})`
77
+ : `[archive] ${ts}`;
78
+ return `${meta}\n${r.content}`;
79
+ })
80
+ .join("\n\n---\n\n");
81
+
82
+ return { content: formatted, isError: false };
78
83
  }
79
84
  }
80
85
 
86
+ // ── Helpers ─────────────────────────────────────────────────────────
87
+
88
+ function formatTimestamp(epochMs: number): string {
89
+ const d = new Date(epochMs);
90
+ const mm = String(d.getMonth() + 1).padStart(2, "0");
91
+ const dd = String(d.getDate()).padStart(2, "0");
92
+ const yy = String(d.getFullYear()).slice(-2);
93
+ const hh = String(d.getHours()).padStart(2, "0");
94
+ const min = String(d.getMinutes()).padStart(2, "0");
95
+ return `${mm}/${dd}/${yy} ${hh}:${min}`;
96
+ }
97
+
81
98
  // ── Exported tool instances ──────────────────────────────────────────
82
99
 
83
- export const memoryManageTool = new MemoryManageTool();
84
- export const memoryRecallTool = new MemoryRecallTool();
100
+ export const rememberTool = new RememberTool();
101
+ export const recallTool = new RecallTool();
@@ -8,6 +8,7 @@ import {
8
8
  } from "../permissions/checker.js";
9
9
  import type { PermissionPrompter } from "../permissions/prompter.js";
10
10
  import { addRule } from "../permissions/trust-store.js";
11
+ import { RiskLevel } from "../permissions/types.js";
11
12
  import {
12
13
  getEffectiveMode,
13
14
  setConversationMode,
@@ -137,24 +138,6 @@ export class PermissionChecker {
137
138
  }
138
139
 
139
140
  if (result.decision === "prompt") {
140
- // dangerouslySkipPermissions: when enabled, auto-approve all prompts
141
- // without user interaction. Deny rules are still respected (they
142
- // return before reaching this block).
143
- //
144
- // Note: unlike guardian auto-approve and temporary overrides below,
145
- // this intentionally does NOT check `context.requireFreshApproval`.
146
- // The setting is designed to skip ALL interactive prompts
147
- // unconditionally — it is an explicit operator opt-out from the
148
- // permission system, so requireFreshApproval does not apply.
149
- const cfg = getConfig();
150
- if (cfg.permissions.dangerouslySkipPermissions) {
151
- log.info(
152
- { toolName: name, riskLevel },
153
- "dangerouslySkipPermissions active — auto-approving without prompt",
154
- );
155
- return { allowed: true, decision: "dangerously_skip_permissions", riskLevel };
156
- }
157
-
158
141
  // Guardian-trust sessions (e.g. scheduled jobs, reminders) should be
159
142
  // able to use bundled tools without interactive approval. The guardian
160
143
  // is the owner - prompting makes no sense when there is no client.
@@ -163,6 +146,10 @@ export class PermissionChecker {
163
146
  // Exception: inline-command skill loads (skill_load_dynamic:*) must
164
147
  // never be silently auto-approved — they execute embedded commands
165
148
  // and require explicit human review or a pinned trust rule.
149
+ // Exception: high-risk tools (e.g. destructive shell commands, writes
150
+ // to sensitive paths) are denied — unattended sessions must not
151
+ // auto-approve operations that could cause significant damage if
152
+ // triggered by prompt injection from untrusted content.
166
153
  const isDynamicSkillLoad =
167
154
  result.matchedRule?.pattern.startsWith("skill_load_dynamic:") ===
168
155
  true;
@@ -170,7 +157,8 @@ export class PermissionChecker {
170
157
  context.isInteractive === false &&
171
158
  context.trustClass === "guardian" &&
172
159
  !context.requireFreshApproval &&
173
- !isDynamicSkillLoad
160
+ !isDynamicSkillLoad &&
161
+ riskLevel !== RiskLevel.High
174
162
  ) {
175
163
  log.info(
176
164
  { toolName: name, riskLevel },
@@ -1,8 +1,6 @@
1
- import { execFileSync } from "node:child_process";
2
- import { readFileSync, statSync, unlinkSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
1
+ import { readFileSync, statSync } from "node:fs";
5
2
 
3
+ import { optimizeImageForTransport } from "../../../agent/image-optimize.js";
6
4
  import type { ImageContent } from "../../../providers/types.js";
7
5
  import type { ToolExecutionResult } from "../../types.js";
8
6
 
@@ -17,12 +15,6 @@ export const IMAGE_EXTENSIONS = new Set([
17
15
  const MAX_SIZE_BYTES = 20 * 1024 * 1024; // 20 MB — LLM API transport limit (post-optimization)
18
16
  const MAX_SOURCE_SIZE_BYTES = 100 * 1024 * 1024; // 100 MB — pre-optimization guard
19
17
 
20
- // Images above this threshold get auto-optimized via sips (macOS) to avoid
21
- // sending multi-MB base64 payloads to the LLM API.
22
- const OPTIMIZE_THRESHOLD_BYTES = 1 * 1024 * 1024; // 1 MB
23
- const OPTIMIZE_MAX_DIMENSION = 1568; // Anthropic's recommended max
24
- const OPTIMIZE_JPEG_QUALITY = 80;
25
-
26
18
  /**
27
19
  * Detect the actual image format from the first bytes of the buffer.
28
20
  * Returns the MIME type, or null if unrecognised.
@@ -69,36 +61,6 @@ function detectMediaType(buf: Buffer): string | null {
69
61
  return null;
70
62
  }
71
63
 
72
- /**
73
- * Use macOS `sips` to resize and convert an image to JPEG.
74
- * Returns the path to the optimized temp file, or null if sips is unavailable.
75
- */
76
- function optimizeWithSips(srcPath: string): string | null {
77
- const tmpPath = join(tmpdir(), `vellum-view-image-${Date.now()}.jpg`);
78
- try {
79
- execFileSync(
80
- "sips",
81
- [
82
- "--resampleHeightWidthMax",
83
- String(OPTIMIZE_MAX_DIMENSION),
84
- "-s",
85
- "format",
86
- "jpeg",
87
- "-s",
88
- "formatOptions",
89
- String(OPTIMIZE_JPEG_QUALITY),
90
- srcPath,
91
- "--out",
92
- tmpPath,
93
- ],
94
- { stdio: "pipe", timeout: 15_000 },
95
- );
96
- return tmpPath;
97
- } catch {
98
- return null;
99
- }
100
- }
101
-
102
64
  /**
103
65
  * Read an image file from disk, optionally optimize it, and return a
104
66
  * ToolExecutionResult with base64-encoded image content blocks.
@@ -130,51 +92,11 @@ export function readImageFile(resolvedPath: string): ToolExecutionResult {
130
92
  }
131
93
 
132
94
  let buffer: Buffer;
133
- let optimized = false;
134
- let tmpPath: string | null = null;
135
-
136
95
  try {
137
- if (stat.size > OPTIMIZE_THRESHOLD_BYTES) {
138
- tmpPath = optimizeWithSips(resolvedPath);
139
- if (tmpPath) {
140
- buffer = readFileSync(tmpPath) as Buffer;
141
- optimized = true;
142
- } else {
143
- // sips unavailable — fast-fail if original file exceeds the transport limit
144
- if (stat.size > MAX_SIZE_BYTES) {
145
- const sizeMB = (stat.size / (1024 * 1024)).toFixed(1);
146
- return {
147
- content: `Error: image too large (${sizeMB} MB). Maximum is 20 MB. Image optimization (sips) is unavailable on this platform.`,
148
- isError: true,
149
- };
150
- }
151
- buffer = readFileSync(resolvedPath) as Buffer;
152
- }
153
- } else {
154
- buffer = readFileSync(resolvedPath) as Buffer;
155
- }
96
+ buffer = readFileSync(resolvedPath) as Buffer;
156
97
  } catch (err) {
157
98
  const msg = err instanceof Error ? err.message : String(err);
158
99
  return { content: `Error reading file: ${msg}`, isError: true };
159
- } finally {
160
- if (tmpPath) {
161
- try {
162
- unlinkSync(tmpPath);
163
- } catch {
164
- /* ignore cleanup errors */
165
- }
166
- }
167
- }
168
-
169
- if (buffer.length > MAX_SIZE_BYTES) {
170
- const sizeMB = (buffer.length / (1024 * 1024)).toFixed(1);
171
- const msg = optimized
172
- ? `Error: image too large after optimization (${sizeMB} MB). Maximum is 20 MB.`
173
- : `Error: image too large (${sizeMB} MB). Maximum is 20 MB.`;
174
- return {
175
- content: msg,
176
- isError: true,
177
- };
178
100
  }
179
101
 
180
102
  // Detect actual format from magic bytes - never trust the file extension
@@ -187,25 +109,40 @@ export function readImageFile(resolvedPath: string): ToolExecutionResult {
187
109
  };
188
110
  }
189
111
 
190
- const base64Data = buffer.toString("base64");
112
+ // Optimize before size-checking — oversized images may compress under the limit.
113
+ const rawBase64 = buffer.toString("base64");
114
+ const { data: base64Data, mediaType: finalType } =
115
+ optimizeImageForTransport(rawBase64, detectedType);
116
+ const optimized = base64Data !== rawBase64;
117
+
118
+ const optimizedBytes = optimized
119
+ ? Math.ceil((base64Data.length * 3) / 4)
120
+ : buffer.length;
121
+ if (optimizedBytes > MAX_SIZE_BYTES) {
122
+ const sizeMB = (optimizedBytes / (1024 * 1024)).toFixed(1);
123
+ return {
124
+ content: `Error: image too large (${sizeMB} MB). Maximum is 20 MB even after optimization.`,
125
+ isError: true,
126
+ };
127
+ }
191
128
 
192
129
  const imageBlock: ImageContent = {
193
130
  type: "image" as const,
194
131
  source: {
195
132
  type: "base64" as const,
196
- media_type: detectedType,
133
+ media_type: finalType,
197
134
  data: base64Data,
198
135
  },
199
136
  };
200
137
 
201
138
  const sizeSuffix = optimized
202
139
  ? ` (optimized from ${(stat.size / 1024).toFixed(0)} KB to ${(
203
- buffer.length / 1024
140
+ optimizedBytes / 1024
204
141
  ).toFixed(0)} KB)`
205
142
  : "";
206
143
 
207
144
  return {
208
- content: `Image loaded: ${resolvedPath} (${buffer.length} bytes, ${detectedType})${sizeSuffix}`,
145
+ content: `Image loaded: ${resolvedPath} (${optimizedBytes} bytes, ${finalType})${sizeSuffix}`,
209
146
  isError: false,
210
147
  contentBlocks: [imageBlock],
211
148
  };
@@ -40,7 +40,7 @@ export async function runSkillToolScript(
40
40
  context: ToolContext,
41
41
  options?: RunSkillToolScriptOptions,
42
42
  ): Promise<ToolExecutionResult> {
43
- if (options?.target === "sandbox") {
43
+ if (options?.target === "sandbox" && !options?.bundled) {
44
44
  return runSkillToolScriptSandbox(skillDir, executorPath, input, context, {
45
45
  timeoutMs: options.timeoutMs,
46
46
  expectedSkillVersionHash: options.expectedSkillVersionHash,
@@ -35,6 +35,7 @@ const SAFE_ENV_VARS = [
35
35
  "CES_CREDENTIAL_URL",
36
36
  "CES_MANAGED_MODE",
37
37
  "IS_CONTAINERIZED",
38
+ "IS_PLATFORM",
38
39
  "CES_SERVICE_TOKEN",
39
40
  ] as const;
40
41
 
@@ -18,7 +18,7 @@ import { credentialStoreTool } from "./credentials/vault.js";
18
18
  import { fileEditTool } from "./filesystem/edit.js";
19
19
  import { fileReadTool } from "./filesystem/read.js";
20
20
  import { fileWriteTool } from "./filesystem/write.js";
21
- import { memoryManageTool, memoryRecallTool } from "./memory/register.js";
21
+ import { recallTool, rememberTool } from "./memory/register.js";
22
22
  import { webFetchTool } from "./network/web-fetch.js";
23
23
  import { webSearchTool } from "./network/web-search.js";
24
24
  import { skillExecuteTool } from "./skills/execute.js";
@@ -82,8 +82,8 @@ export const explicitTools: Tool[] = [
82
82
  skillLoadTool,
83
83
  requestSystemPermissionTool,
84
84
  // Always-explicit tools
85
- memoryManageTool,
86
- memoryRecallTool,
85
+ rememberTool,
86
+ recallTool,
87
87
  credentialStoreTool,
88
88
  ];
89
89
 
@@ -1,15 +1,30 @@
1
- import { isLinux, isMacOS } from "./platform.js";
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import { getLogger } from "./logger.js";
5
+ import { getSignalsDir } from "./platform.js";
6
+
7
+ const log = getLogger("browser");
2
8
 
3
9
  /**
4
- * Open a URL in the user's default browser, falling back to printing the URL
5
- * to stderr on unsupported platforms.
10
+ * Open a URL on the user's host machine.
11
+ *
12
+ * Writes an `open_url` event to the `signals/emit-event` file so that the
13
+ * daemon's ConfigWatcher picks it up and publishes it to connected clients
14
+ * (e.g. the Swift macOS app) via the assistant event hub.
6
15
  */
7
- export function openInBrowser(url: string): void {
8
- if (isMacOS()) {
9
- Bun.spawn(["open", url], { stdout: "ignore", stderr: "ignore" });
10
- } else if (isLinux()) {
11
- Bun.spawn(["xdg-open", url], { stdout: "ignore", stderr: "ignore" });
12
- } else {
13
- process.stderr.write(`Open this URL to authorize:\n\n${url}\n`);
16
+ export async function openInHostBrowser(url: string): Promise<void> {
17
+ try {
18
+ const signalsDir = getSignalsDir();
19
+ mkdirSync(signalsDir, { recursive: true });
20
+ writeFileSync(
21
+ join(signalsDir, "emit-event"),
22
+ JSON.stringify({ type: "open_url", url }),
23
+ );
24
+ } catch (err) {
25
+ log.warn(
26
+ { error: err instanceof Error ? err.message : String(err) },
27
+ "Failed to write open_url signal",
28
+ );
14
29
  }
15
30
  }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Shared helper for locating or JIT-installing a standalone `bun` binary.
3
+ *
4
+ * Several subsystems (package resolver, hook runner, browser runtime,
5
+ * credential execution, embedding runtime) need to spawn `bun` as a child
6
+ * process. Inside a `bun build --compile` binary, `process.execPath` is the
7
+ * compiled app — not the bun CLI — and the user may not have bun on PATH.
8
+ *
9
+ * This module checks well-known locations first, and if none is found it
10
+ * downloads a pinned release from GitHub into $VELLUM_WORKSPACE_DIR/bin/.
11
+ */
12
+
13
+ import {
14
+ chmodSync,
15
+ existsSync,
16
+ mkdirSync,
17
+ renameSync,
18
+ rmSync,
19
+ writeFileSync,
20
+ } from "node:fs";
21
+ import { arch, homedir, platform } from "node:os";
22
+ import { basename, join } from "node:path";
23
+
24
+ import { getLogger } from "./logger.js";
25
+ import { getBinDir } from "./platform.js";
26
+
27
+ const log = getLogger("bun-runtime");
28
+
29
+ /** Pinned bun version to download when no system bun is available. */
30
+ const BUN_VERSION = "1.2.0";
31
+
32
+ /** Module-level cache so we only resolve/download once per process. */
33
+ let cachedBunPath: string | undefined;
34
+
35
+ /** In-flight download promise to deduplicate concurrent callers. */
36
+ let inflightDownload: Promise<string> | undefined;
37
+
38
+ /**
39
+ * Return a path to a usable `bun` binary, downloading one if necessary.
40
+ *
41
+ * Resolution order:
42
+ * 1. `process.execPath` if it IS the bun CLI (dev mode)
43
+ * 2. Previously downloaded copy at $VELLUM_WORKSPACE_DIR/bin/bun
44
+ * 3. Common install locations (~/.bun/bin/bun, /opt/homebrew/bin/bun, etc.)
45
+ * 4. `Bun.which("bun")` (PATH lookup)
46
+ * 5. Download from GitHub releases into $VELLUM_WORKSPACE_DIR/bin/
47
+ */
48
+ export async function ensureBun(): Promise<string> {
49
+ if (cachedBunPath && existsSync(cachedBunPath)) {
50
+ return cachedBunPath;
51
+ }
52
+
53
+ const found = findBun();
54
+ if (found) {
55
+ cachedBunPath = found;
56
+ return found;
57
+ }
58
+
59
+ // No bun found anywhere — download it.
60
+ // Use an in-flight promise to deduplicate concurrent callers.
61
+ if (!inflightDownload) {
62
+ log.info("No bun binary found, downloading…");
63
+ const binDir = getBinDir();
64
+ inflightDownload = downloadBun(binDir).finally(() => {
65
+ inflightDownload = undefined;
66
+ });
67
+ }
68
+ const downloaded = await inflightDownload;
69
+ cachedBunPath = downloaded;
70
+ return downloaded;
71
+ }
72
+
73
+ /**
74
+ * Synchronous check for an already-available bun binary.
75
+ * Returns the path if found, undefined otherwise. Does NOT download.
76
+ */
77
+ export function findBun(): string | undefined {
78
+ // 1. process.execPath if it is the bun CLI itself (dev mode)
79
+ const execBase = basename(process.execPath);
80
+ if (execBase === "bun" || execBase === "bun.exe") {
81
+ return process.execPath;
82
+ }
83
+
84
+ // 2. Previously downloaded copy
85
+ const downloaded = join(getBinDir(), "bun");
86
+ if (existsSync(downloaded)) return downloaded;
87
+
88
+ // 3. Common install locations
89
+ const home = homedir();
90
+ for (const p of [
91
+ join(home, ".bun", "bin", "bun"),
92
+ "/opt/homebrew/bin/bun",
93
+ "/usr/local/bin/bun",
94
+ ]) {
95
+ if (existsSync(p)) return p;
96
+ }
97
+
98
+ // 4. PATH lookup
99
+ const which = Bun.which("bun");
100
+ if (which) return which;
101
+
102
+ return undefined;
103
+ }
104
+
105
+ /**
106
+ * Download a pinned bun release into the given directory.
107
+ * Returns the absolute path to the downloaded binary.
108
+ */
109
+ async function downloadBun(installDir: string): Promise<string> {
110
+ const os = platform();
111
+ const cpu = arch() === "arm64" ? "aarch64" : arch();
112
+ const target = `${os}-${cpu}`;
113
+ const url = `https://github.com/oven-sh/bun/releases/download/bun-v${BUN_VERSION}/bun-${target}.zip`;
114
+
115
+ log.info({ url, target, bunVersion: BUN_VERSION }, "Downloading bun binary");
116
+
117
+ const response = await fetch(url, { redirect: "follow" });
118
+ if (!response.ok) {
119
+ throw new Error(
120
+ `Failed to download bun: ${response.status} ${response.statusText}`,
121
+ );
122
+ }
123
+
124
+ const zipData = await response.arrayBuffer();
125
+ mkdirSync(installDir, { recursive: true });
126
+
127
+ const tmpZip = join(installDir, `bun-download-${Date.now()}.zip`);
128
+ writeFileSync(tmpZip, Buffer.from(zipData));
129
+
130
+ try {
131
+ const proc = Bun.spawn({
132
+ cmd: ["unzip", "-o", tmpZip, "-d", installDir],
133
+ stdout: "ignore",
134
+ stderr: "pipe",
135
+ });
136
+ await proc.exited;
137
+ if (proc.exitCode !== 0) {
138
+ const stderr = await new Response(proc.stderr).text();
139
+ throw new Error(`Failed to extract bun zip: ${stderr}`);
140
+ }
141
+
142
+ // Move binary from bun-{target}/bun to installDir/bun
143
+ const extractedBun = join(installDir, `bun-${target}`, "bun");
144
+ const finalPath = join(installDir, "bun");
145
+ if (existsSync(extractedBun)) {
146
+ // Remove old binary first to avoid "Text file busy" on some systems
147
+ if (existsSync(finalPath)) {
148
+ rmSync(finalPath);
149
+ }
150
+ renameSync(extractedBun, finalPath);
151
+ rmSync(join(installDir, `bun-${target}`), {
152
+ recursive: true,
153
+ force: true,
154
+ });
155
+ } else if (!existsSync(finalPath)) {
156
+ throw new Error(
157
+ `Bun binary not found at expected path after extraction: ${extractedBun}`,
158
+ );
159
+ }
160
+
161
+ chmodSync(finalPath, 0o755);
162
+
163
+ log.info({ path: finalPath }, "Bun binary downloaded successfully");
164
+ return finalPath;
165
+ } finally {
166
+ try {
167
+ rmSync(tmpZip);
168
+ } catch {
169
+ /* ignore cleanup failure */
170
+ }
171
+ }
172
+ }