@vellumai/assistant 0.12.3-staging.1 → 0.12.3-staging.2

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 (560) hide show
  1. package/ARCHITECTURE.md +43 -29
  2. package/Dockerfile +63 -0
  3. package/docs/architecture/security.md +10 -5
  4. package/docs/architecture/turn-actor.md +2 -0
  5. package/docs/desktop-browser-cli.md +45 -4
  6. package/docs/live-voice-task-outcomes.md +100 -0
  7. package/docs/mode-sessions.md +183 -0
  8. package/docs/voice-input-diagnostics.md +58 -0
  9. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  10. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  11. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  12. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
  13. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  14. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  15. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
  16. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -1
  17. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +38 -7
  18. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +5 -6
  19. package/node_modules/@vellumai/service-contracts/package.json +2 -1
  20. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  21. package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
  22. package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
  23. package/openapi.yaml +665 -14
  24. package/package.json +1 -1
  25. package/scripts/smoke-desktop-browser-cli.ts +10 -26
  26. package/scripts/smoke-desktop-window-theme.ts +2 -3
  27. package/src/__tests__/agent-loop-output-hooks.test.ts +150 -1
  28. package/src/__tests__/agent-loop-provider-error-recording.test.ts +87 -19
  29. package/src/__tests__/annotate-activity-metadata.test.ts +3 -1
  30. package/src/__tests__/annotate-risk-options.test.ts +2 -0
  31. package/src/__tests__/answered-question-persistence.test.ts +2 -0
  32. package/src/__tests__/anthropic-gateway-shared.test.ts +22 -0
  33. package/src/__tests__/approval-message-composer.test.ts +1 -118
  34. package/src/__tests__/approval-routes-http.test.ts +3 -0
  35. package/src/__tests__/assistant-event-hub-connection-history.test.ts +111 -0
  36. package/src/__tests__/assistant-event-hub-targeted.test.ts +50 -0
  37. package/src/__tests__/assistant-event-targeting.test.ts +186 -0
  38. package/src/__tests__/assistant-stream-state.test.ts +29 -9
  39. package/src/__tests__/browser-fill-credential.test.ts +11 -22
  40. package/src/__tests__/btw-routes.test.ts +4 -1
  41. package/src/__tests__/build-persisted-content.test.ts +1 -1
  42. package/src/__tests__/call-conversation-messages.test.ts +5 -0
  43. package/src/__tests__/call-recovery.test.ts +7 -2
  44. package/src/__tests__/call-routes-http.test.ts +12 -0
  45. package/src/__tests__/call-store.test.ts +7 -2
  46. package/src/__tests__/channel-retry-sweep.test.ts +9 -0
  47. package/src/__tests__/chat-reveal-guard-priming.test.ts +2 -0
  48. package/src/__tests__/checker.test.ts +11 -3
  49. package/src/__tests__/client-os-metadata-persistence.test.ts +35 -1
  50. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +0 -25
  51. package/src/__tests__/computer-use-tools.test.ts +1 -233
  52. package/src/__tests__/config-model-image-provider.test.ts +39 -0
  53. package/src/__tests__/config-schema.test.ts +16 -0
  54. package/src/__tests__/config-watcher.test.ts +24 -0
  55. package/src/__tests__/context-search-agent-runner.test.ts +260 -1
  56. package/src/__tests__/context-search-fanout.test.ts +1 -1
  57. package/src/__tests__/context-search-types.test.ts +7 -7
  58. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +8 -2
  59. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +2 -0
  60. package/src/__tests__/conversation-agent-loop.test.ts +546 -16
  61. package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
  62. package/src/__tests__/conversation-evictor.test.ts +62 -37
  63. package/src/__tests__/conversation-history-boundary-repair-failure.test.ts +174 -0
  64. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +2 -0
  65. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
  66. package/src/__tests__/conversation-retry-route.test.ts +22 -0
  67. package/src/__tests__/conversation-routes-disk-view.test.ts +2 -0
  68. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +2 -0
  69. package/src/__tests__/conversation-routes-guardian-reply.test.ts +10 -0
  70. package/src/__tests__/conversation-routes-hidden-queue.test.ts +2 -0
  71. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
  72. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -0
  73. package/src/__tests__/conversation-surface-snapshots.test.ts +543 -0
  74. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +151 -0
  75. package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +63 -1
  76. package/src/__tests__/conversation-tool-setup-attribution.test.ts +23 -0
  77. package/src/__tests__/conversation-undo.test.ts +61 -0
  78. package/src/__tests__/credential-execution-client.test.ts +6 -6
  79. package/src/__tests__/credential-prompt-route.test.ts +35 -3
  80. package/src/__tests__/cu-unified-flow.test.ts +82 -1
  81. package/src/__tests__/db-mode-sessions-migration.test.ts +175 -0
  82. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -0
  83. package/src/__tests__/dm-backfill.test.ts +91 -1
  84. package/src/__tests__/document-create-route.test.ts +88 -0
  85. package/src/__tests__/document-sync-tags.test.ts +27 -0
  86. package/src/__tests__/emit-signal-routing-intent.test.ts +142 -2
  87. package/src/__tests__/events-tail-route.test.ts +25 -0
  88. package/src/__tests__/evict-conversations-for-reload.test.ts +57 -8
  89. package/src/__tests__/guardian-action-sweep.test.ts +16 -0
  90. package/src/__tests__/guardian-dispatch.test.ts +13 -0
  91. package/src/__tests__/headless-browser-interactions.test.ts +64 -20
  92. package/src/__tests__/heartbeat-service.test.ts +2 -59
  93. package/src/__tests__/helpers/mock-conversation.ts +21 -0
  94. package/src/__tests__/helpers/native-web-search-harness.ts +2 -0
  95. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +5 -0
  96. package/src/__tests__/host-cu-proxy.test.ts +46 -2
  97. package/src/__tests__/http-user-message-parity.test.ts +2 -0
  98. package/src/__tests__/image-credentials.test.ts +49 -0
  99. package/src/__tests__/image-service-dispatcher.test.ts +45 -0
  100. package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
  101. package/src/__tests__/interrupt-on-send.test.ts +57 -43
  102. package/src/__tests__/interrupt-turn-note.test.ts +5 -6
  103. package/src/__tests__/llm-catalog-parity.test.ts +2 -2
  104. package/src/__tests__/media-generate-image.test.ts +49 -1
  105. package/src/__tests__/message-provenance-contact-id.test.ts +69 -0
  106. package/src/__tests__/migration-export-to-gcs.test.ts +142 -0
  107. package/src/__tests__/mode-session-history.test.ts +245 -0
  108. package/src/__tests__/mode-session-recovery.test.ts +222 -0
  109. package/src/__tests__/mode-session-wire.test.ts +141 -0
  110. package/src/__tests__/notification-guardian-path.test.ts +7 -0
  111. package/src/__tests__/notification-telegram-adapter.test.ts +2 -2
  112. package/src/__tests__/notification-vellum-adapter.test.ts +34 -0
  113. package/src/__tests__/oauth-provider-serializer.test.ts +12 -0
  114. package/src/__tests__/oauth-providers-routes.test.ts +1 -0
  115. package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
  116. package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
  117. package/src/__tests__/plugin-api-provider.test.ts +5 -0
  118. package/src/__tests__/plugin-api-resolve-credential.test.ts +97 -0
  119. package/src/__tests__/plugin-import-boundary-guard.test.ts +9 -0
  120. package/src/__tests__/process-message-display-content.test.ts +56 -0
  121. package/src/__tests__/reaction-persistence.test.ts +5 -0
  122. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +25 -9
  123. package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
  124. package/src/__tests__/scripted-turn-metadata-persistence.test.ts +73 -0
  125. package/src/__tests__/secret-ingress-http.test.ts +2 -0
  126. package/src/__tests__/secure-keys.test.ts +43 -1
  127. package/src/__tests__/send-endpoint-busy.test.ts +163 -1
  128. package/src/__tests__/server-history-render.test.ts +91 -1
  129. package/src/__tests__/settings-routes.test.ts +50 -1
  130. package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
  131. package/src/__tests__/subagent-fork-notifications.test.ts +1 -2
  132. package/src/__tests__/subagent-manager-notify.test.ts +1 -2
  133. package/src/__tests__/subagent-notify-parent.test.ts +146 -39
  134. package/src/__tests__/subagent-notify-stale-rebuild.test.ts +2 -4
  135. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
  136. package/src/__tests__/thread-backfill.test.ts +53 -0
  137. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
  138. package/src/__tests__/tool-result-metadata-plumbing.test.ts +3 -1
  139. package/src/__tests__/tool-start-timestamp.test.ts +2 -0
  140. package/src/__tests__/twilio-routes.test.ts +1 -0
  141. package/src/__tests__/web-search-backend-failure.test.ts +1 -1
  142. package/src/activation/progress-store.test.ts +12 -7
  143. package/src/agent/loop.ts +99 -41
  144. package/src/api/events/assistant-turn-start.ts +3 -0
  145. package/src/api/events/generation-handoff.ts +2 -0
  146. package/src/api/events/message-complete.ts +2 -0
  147. package/src/api/events/notification-conversation-created.ts +14 -16
  148. package/src/api/events/notification-intent.ts +4 -2
  149. package/src/api/events/tool-result.ts +85 -0
  150. package/src/api/events/tool-use-start.ts +3 -0
  151. package/src/api/events/user-message-echo.ts +3 -0
  152. package/src/api/index.ts +31 -6
  153. package/src/api/mode-session.test.ts +131 -0
  154. package/src/api/mode-session.ts +148 -0
  155. package/src/api/remember-tool.ts +15 -0
  156. package/src/api/responses/conversation-message.ts +6 -0
  157. package/src/approvals/AGENTS.md +4 -2
  158. package/src/browser/__tests__/operations.test.ts +29 -0
  159. package/src/browser/operation-meta.ts +2 -1
  160. package/src/browser/operations.ts +29 -0
  161. package/src/browser/virtual-desktop-target.ts +2 -8
  162. package/src/bundler/bundle-signer.ts +1 -3
  163. package/src/calls/__tests__/barge-in-guard.test.ts +3 -0
  164. package/src/calls/__tests__/call-controller.test.ts +94 -0
  165. package/src/calls/__tests__/call-funnel-telemetry.test.ts +204 -0
  166. package/src/calls/__tests__/voice-control-protocol.test.ts +15 -0
  167. package/src/calls/__tests__/voice-escalation-judge.test.ts +209 -0
  168. package/src/calls/__tests__/voice-leg-coordinator.test.ts +168 -0
  169. package/src/{live-voice/__tests__/live-voice-metrics.test.ts → calls/__tests__/voice-metrics.test.ts} +32 -38
  170. package/src/calls/__tests__/voice-session-bridge.test.ts +576 -122
  171. package/src/calls/barge-in-guard.ts +5 -0
  172. package/src/calls/call-controller.ts +196 -1
  173. package/src/calls/call-domain.ts +4 -0
  174. package/src/calls/call-store.ts +87 -2
  175. package/src/calls/guardian-action-sweep.ts +22 -8
  176. package/src/calls/media-stream-audio-transcode.ts +1 -3
  177. package/src/calls/typesafe-noul.ts +156 -0
  178. package/src/calls/voice-control-protocol.ts +6 -0
  179. package/src/calls/voice-escalation-judge.ts +145 -0
  180. package/src/calls/voice-escalation-target.ts +10 -0
  181. package/src/calls/voice-leg-coordinator.ts +121 -3
  182. package/src/{live-voice/live-voice-metrics.ts → calls/voice-metrics.ts} +94 -87
  183. package/src/calls/voice-session-bridge.ts +256 -112
  184. package/src/calls/voice-triage-escalate.ts +7 -0
  185. package/src/cli/__tests__/roadmap-cli.test.ts +4 -41
  186. package/src/cli/commands/__tests__/notifications.test.ts +35 -10
  187. package/src/cli/commands/browser.help.ts +4 -5
  188. package/src/cli/commands/browser.ts +0 -1
  189. package/src/cli/commands/clients.help.ts +46 -0
  190. package/src/cli/commands/clients.ts +116 -0
  191. package/src/cli/commands/credentials.help.ts +6 -1
  192. package/src/cli/commands/notifications.help.ts +16 -2
  193. package/src/cli/commands/notifications.ts +30 -8
  194. package/src/cli/commands/roadmap.help.ts +18 -21
  195. package/src/cli/commands/roadmap.ts +4 -21
  196. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
  197. package/src/cli/lib/bundled-marketplace.json +84 -34
  198. package/src/cli/lib/plugin-marketplace.ts +8 -0
  199. package/src/cli/lib/publish-plugin.ts +1 -2
  200. package/src/config/__tests__/default-provider.test.ts +3 -1
  201. package/src/config/__tests__/memory-retrospective-schema.test.ts +14 -1
  202. package/src/config/bundled-skills/computer-use/SKILL.md +1 -1
  203. package/src/config/bundled-skills/computer-use/TOOLS.json +89 -1
  204. package/src/config/bundled-skills/image-studio/SKILL.md +17 -2
  205. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -11
  206. package/src/config/bundled-skills/sequences/TOOLS.json +1 -5
  207. package/src/config/call-site-defaults.ts +9 -0
  208. package/src/config/feature-flag-registry.json +16 -0
  209. package/src/config/profile-text-generation.test.ts +2 -2
  210. package/src/config/schemas/__tests__/tools.test.ts +31 -0
  211. package/src/config/schemas/call-site-catalog.ts +14 -0
  212. package/src/config/schemas/channels.ts +0 -18
  213. package/src/config/schemas/llm.ts +3 -1
  214. package/src/config/schemas/mcp.ts +2 -1
  215. package/src/config/schemas/memory-retrospective.ts +11 -2
  216. package/src/config/schemas/services.ts +15 -6
  217. package/src/config/schemas/tools.ts +10 -0
  218. package/src/config/session-groups-gate.ts +21 -0
  219. package/src/config/skills.ts +2 -6
  220. package/src/conversations/__tests__/message-consolidation.test.ts +149 -0
  221. package/src/conversations/message-consolidation.ts +102 -5
  222. package/src/credential-execution/ces-connect.test.ts +69 -0
  223. package/src/credential-execution/ces-connect.ts +115 -0
  224. package/src/credential-execution/ces-runtime.ts +55 -93
  225. package/src/credential-execution/executable-discovery.ts +1 -11
  226. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
  227. package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
  228. package/src/daemon/browser-mode-session.test.ts +402 -0
  229. package/src/daemon/browser-mode-session.ts +186 -0
  230. package/src/daemon/computer-use-mode-session.test.ts +210 -0
  231. package/src/daemon/computer-use-mode-session.ts +105 -0
  232. package/src/daemon/config-watcher.ts +10 -0
  233. package/src/daemon/conversation-agent-loop-handlers.ts +58 -10
  234. package/src/daemon/conversation-agent-loop.ts +219 -25
  235. package/src/daemon/conversation-evictor.ts +5 -24
  236. package/src/daemon/conversation-history.ts +10 -0
  237. package/src/daemon/conversation-interrupt-repair.ts +4 -43
  238. package/src/daemon/conversation-interrupt.ts +7 -11
  239. package/src/daemon/conversation-messaging.ts +58 -5
  240. package/src/daemon/conversation-mode-session.test.ts +1667 -0
  241. package/src/daemon/conversation-mode-session.ts +1008 -0
  242. package/src/daemon/conversation-process.ts +5 -0
  243. package/src/daemon/conversation-runtime-assembly.ts +10 -20
  244. package/src/daemon/conversation-skill-tools.ts +1 -0
  245. package/src/daemon/conversation-store.ts +4 -4
  246. package/src/daemon/conversation-surface-snapshots.ts +135 -0
  247. package/src/daemon/conversation-surfaces.ts +113 -5
  248. package/src/daemon/conversation-tool-setup.ts +8 -3
  249. package/src/daemon/conversation.ts +143 -41
  250. package/src/daemon/handlers/config-model.ts +7 -5
  251. package/src/daemon/handlers/shared.ts +55 -16
  252. package/src/daemon/host-cu-proxy.ts +51 -22
  253. package/src/daemon/lifecycle.ts +30 -13
  254. package/src/daemon/message-protocol.ts +0 -1
  255. package/src/daemon/message-provenance.ts +28 -4
  256. package/src/daemon/mode-session-startup-recovery.ts +23 -0
  257. package/src/daemon/mode-session-tracking.ts +54 -0
  258. package/src/daemon/process-message.ts +13 -4
  259. package/src/daemon/virtual-desktop-context.ts +21 -0
  260. package/src/desktop/__tests__/fake-desktop.ts +1 -0
  261. package/src/desktop/desktop-accessibility-script.ts +88 -0
  262. package/src/desktop/desktop-accessibility.test.ts +160 -0
  263. package/src/desktop/desktop-accessibility.ts +169 -0
  264. package/src/desktop/desktop-automation-lease.test.ts +76 -68
  265. package/src/desktop/desktop-automation-lease.ts +41 -50
  266. package/src/desktop/desktop-browser-endpoint.ts +4 -0
  267. package/src/desktop/desktop-computer-use-routing.test.ts +330 -0
  268. package/src/desktop/desktop-computer-use.test.ts +449 -0
  269. package/src/desktop/desktop-computer-use.ts +502 -0
  270. package/src/desktop/desktop-dependencies.ts +47 -293
  271. package/src/desktop/desktop-display.ts +2 -2
  272. package/src/desktop/desktop-panel-config.test.ts +13 -3
  273. package/src/desktop/desktop-panel-config.ts +109 -15
  274. package/src/desktop/desktop-session-manager.test.ts +69 -21
  275. package/src/desktop/desktop-session-manager.ts +76 -22
  276. package/src/desktop/desktop-stream-bridge.test.ts +11 -122
  277. package/src/desktop/desktop-stream-bridge.ts +6 -8
  278. package/src/desktop/desktop-window-theme.ts +5 -25
  279. package/src/desktop/virtual-desktop-feature.ts +52 -2
  280. package/src/desktop/virtual-desktop-platform.test.ts +5 -9
  281. package/src/documents/document-store.ts +23 -0
  282. package/src/heartbeat/__tests__/heartbeat-service.test.ts +22 -26
  283. package/src/heartbeat/heartbeat-service.ts +5 -33
  284. package/src/ipc/__tests__/browser-ipc.test.ts +215 -6
  285. package/src/ipc/assistant-server.ts +2 -0
  286. package/src/ipc/routes/__tests__/channel-reply-ipc-routes.test.ts +111 -0
  287. package/src/ipc/routes/channel-reply-ipc-routes.ts +73 -0
  288. package/src/live-voice/__tests__/continuation-judge.test.ts +151 -0
  289. package/src/live-voice/__tests__/live-activity-reporter.test.ts +154 -15
  290. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +743 -31
  291. package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +191 -10
  292. package/src/live-voice/__tests__/live-voice-session-groups-gate.test.ts +87 -0
  293. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +5 -1
  294. package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +41 -0
  295. package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +1017 -9
  296. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +224 -1
  297. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +101 -0
  298. package/src/live-voice/__tests__/live-voice-tts.test.ts +44 -0
  299. package/src/live-voice/__tests__/live-voice-vad.test.ts +939 -75
  300. package/src/live-voice/__tests__/microphone-idle-gate.test.ts +87 -0
  301. package/src/live-voice/__tests__/session-controls.test.ts +23 -0
  302. package/src/live-voice/__tests__/task-outcomes.test.ts +117 -0
  303. package/src/live-voice/__tests__/voice-input-diagnostics.test.ts +117 -0
  304. package/src/live-voice/camera-mode-session.test.ts +265 -0
  305. package/src/live-voice/camera-mode-session.ts +277 -0
  306. package/src/live-voice/continuation-judge.ts +123 -0
  307. package/src/live-voice/live-activity-reporter.ts +115 -6
  308. package/src/live-voice/live-voice-manager.ts +36 -1
  309. package/src/live-voice/live-voice-photo.ts +88 -7
  310. package/src/live-voice/live-voice-session-manager.ts +15 -0
  311. package/src/live-voice/live-voice-session.ts +1443 -747
  312. package/src/live-voice/live-voice-tts.ts +22 -4
  313. package/src/live-voice/microphone-idle-gate.ts +56 -0
  314. package/src/live-voice/protocol.ts +171 -4
  315. package/src/live-voice/session-controls.ts +11 -3
  316. package/src/live-voice/task-outcomes.ts +131 -0
  317. package/src/live-voice/voice-input-diagnostics.ts +117 -0
  318. package/src/mcp/__tests__/manager-tool-caps.test.ts +63 -18
  319. package/src/mcp/__tests__/tool-caps.test.ts +28 -1
  320. package/src/mcp/manager.ts +3 -0
  321. package/src/mcp/tool-caps.ts +12 -4
  322. package/src/media/__tests__/image-models.test.ts +58 -0
  323. package/src/media/image-credentials.ts +5 -0
  324. package/src/media/image-models.ts +52 -0
  325. package/src/media/image-service.ts +8 -0
  326. package/src/media/openrouter-image-service.test.ts +133 -0
  327. package/src/media/openrouter-image-service.ts +153 -0
  328. package/src/media/types.ts +1 -1
  329. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +65 -11
  330. package/src/messaging/providers/discord/send.ts +4 -17
  331. package/src/messaging/providers/discord/transport.ts +2 -2
  332. package/src/messaging/providers/outlook/client.ts +16 -22
  333. package/src/messaging/providers/telegram-bot/send.test.ts +236 -1
  334. package/src/messaging/providers/telegram-bot/send.ts +10 -7
  335. package/src/messaging/providers/telegram-bot/transport.ts +3 -10
  336. package/src/messaging/providers/whatsapp/send.test.ts +169 -4
  337. package/src/monitoring/__tests__/control.test.ts +17 -5
  338. package/src/monitoring/control.ts +15 -5
  339. package/src/notifications/AGENTS.md +1 -1
  340. package/src/notifications/README.md +83 -99
  341. package/src/notifications/__tests__/broadcaster.test.ts +1 -1
  342. package/src/notifications/__tests__/channel-allowlist.test.ts +39 -0
  343. package/src/notifications/__tests__/copy-composer.test.ts +1 -1
  344. package/src/notifications/__tests__/decision-engine.test.ts +79 -2
  345. package/src/notifications/__tests__/deterministic-checks.test.ts +10 -10
  346. package/src/notifications/__tests__/home-feed-side-effect.test.ts +93 -4
  347. package/src/notifications/__tests__/notification-utils.test.ts +18 -0
  348. package/src/notifications/adapters/macos.ts +37 -46
  349. package/src/notifications/broadcaster.ts +5 -6
  350. package/src/notifications/channel-allowlist.ts +44 -0
  351. package/src/notifications/copy-composer.ts +0 -23
  352. package/src/notifications/decision-engine.ts +24 -14
  353. package/src/notifications/deterministic-checks.ts +1 -1
  354. package/src/notifications/emit-signal.ts +123 -37
  355. package/src/notifications/home-feed-side-effect.ts +9 -7
  356. package/src/notifications/notification-utils.ts +19 -0
  357. package/src/notifications/signal.ts +4 -19
  358. package/src/notifications/types.ts +15 -0
  359. package/src/oauth/connection-resolver.ts +1 -2
  360. package/src/oauth/oauth-store.ts +1 -3
  361. package/src/oauth/provider-serializer.ts +7 -0
  362. package/src/oauth/seed-providers.ts +30 -0
  363. package/src/onboarding/onboarding-events-store.ts +99 -12
  364. package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
  365. package/src/persistence/client-connection-events-store.ts +377 -0
  366. package/src/persistence/conversation-crud.ts +55 -6
  367. package/src/persistence/conversation-mode-sessions.test.ts +424 -0
  368. package/src/persistence/conversation-mode-sessions.ts +460 -0
  369. package/src/persistence/conversation-queries.ts +6 -19
  370. package/src/persistence/llm-usage-store.ts +3 -9
  371. package/src/persistence/message-metadata.ts +25 -0
  372. package/src/persistence/migrations/381-create-conversation-mode-sessions.ts +41 -0
  373. package/src/persistence/migrations/382-create-client-connection-events.ts +40 -0
  374. package/src/persistence/migrations/__tests__/382-create-client-connection-events.test.ts +56 -0
  375. package/src/persistence/schema/conversations.ts +67 -0
  376. package/src/persistence/schema/infrastructure.ts +29 -0
  377. package/src/persistence/steps.ts +17 -0
  378. package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
  379. package/src/plugin-api/effective-context-window.ts +33 -0
  380. package/src/plugin-api/index.ts +24 -5
  381. package/src/plugin-api/plugin-name-env.ts +125 -0
  382. package/src/plugin-api/resolve-credential.ts +79 -20
  383. package/src/plugin-api/vision-support.test.ts +22 -0
  384. package/src/plugin-api/vision-support.ts +17 -5
  385. package/src/plugins/__tests__/active-plugin-env.test.ts +136 -0
  386. package/src/plugins/active-plugin-env.ts +51 -0
  387. package/src/plugins/defaults/index.ts +24 -0
  388. package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
  389. package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
  390. package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
  391. package/src/plugins/defaults/memory/context-search/agent-runner.ts +78 -22
  392. package/src/plugins/defaults/memory/context-search/format.ts +51 -7
  393. package/src/plugins/defaults/memory/context-search/limits.ts +10 -12
  394. package/src/plugins/defaults/memory/context-search/recall-input.ts +38 -0
  395. package/src/plugins/defaults/memory/context-search/search.ts +8 -14
  396. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +1 -0
  397. package/src/plugins/defaults/memory/context-search/types.ts +1 -11
  398. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
  399. package/src/plugins/defaults/memory/graph/tool-handlers.ts +12 -21
  400. package/src/plugins/defaults/memory/graph/tools.ts +35 -64
  401. package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
  402. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +5 -0
  403. package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
  404. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +2 -2
  405. package/src/plugins/defaults/memory/tools.test.ts +124 -9
  406. package/src/plugins/defaults/memory/tools.ts +38 -11
  407. package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +165 -27
  408. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
  409. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +46 -27
  410. package/src/plugins/defaults/memory/v3/orchestrate.ts +78 -38
  411. package/src/plugins/defaults/memory/v3/pool-log-store.ts +65 -79
  412. package/src/plugins/defaults/memory/v3/pool-select.test.ts +14 -5
  413. package/src/plugins/defaults/memory/v3/pool-select.ts +683 -44
  414. package/src/plugins/defaults/memory/worker-control.ts +15 -5
  415. package/src/plugins/defaults/task-progress/__tests__/registration.test.ts +70 -0
  416. package/src/plugins/defaults/task-progress/__tests__/task-progress-context.test.ts +380 -0
  417. package/src/plugins/defaults/task-progress/hooks/post-compact.ts +19 -0
  418. package/src/plugins/defaults/task-progress/hooks/user-prompt-submit.ts +24 -0
  419. package/src/plugins/defaults/task-progress/package.json +14 -0
  420. package/src/plugins/defaults/task-progress/src/apply-task-progress-context.ts +93 -0
  421. package/src/plugins/defaults/task-progress/src/format-task-progress-context.ts +67 -0
  422. package/src/providers/__tests__/context-overflow-error.test.ts +10 -0
  423. package/src/providers/__tests__/search-provider-catalog.test.ts +18 -0
  424. package/src/providers/anthropic/client.ts +10 -1
  425. package/src/providers/anthropic-gateway-shared.ts +6 -0
  426. package/src/providers/fetch-provider-catalog.ts +11 -0
  427. package/src/providers/gemini/client.ts +25 -8
  428. package/src/providers/inference/adapter-factory.ts +1 -1
  429. package/src/providers/jev/client.test.ts +10 -0
  430. package/src/providers/jev/client.ts +20 -4
  431. package/src/providers/model-catalog.ts +4 -3
  432. package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +94 -1
  433. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +106 -1
  434. package/src/providers/openai/__tests__/chat-template-flatten.test.ts +24 -0
  435. package/src/providers/openai/__tests__/google-thought-signature.test.ts +1 -2
  436. package/src/providers/openai/chat-completions-provider.ts +100 -29
  437. package/src/providers/openai/google-thought-signature.ts +0 -6
  438. package/src/providers/openai/responses-provider.ts +23 -1
  439. package/src/providers/ratelimit.ts +1 -3
  440. package/src/providers/search-provider-catalog.ts +24 -0
  441. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +24 -0
  442. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +7 -1
  443. package/src/providers/speech-to-text/__tests__/vellum-managed-realtime.test.ts +50 -1
  444. package/src/providers/speech-to-text/deepgram-flux-frames.ts +11 -0
  445. package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +13 -0
  446. package/src/providers/types.ts +5 -0
  447. package/src/routes/control.ts +7 -5
  448. package/src/runtime/AGENTS.md +4 -2
  449. package/src/runtime/actor-trust-resolver.ts +3 -3
  450. package/src/runtime/agent-wake.ts +1 -1
  451. package/src/runtime/approval-message-composer.ts +3 -69
  452. package/src/runtime/assistant-event-hub.ts +73 -75
  453. package/src/runtime/assistant-event-publish-options.ts +7 -0
  454. package/src/runtime/assistant-event-targeting.ts +79 -0
  455. package/src/runtime/assistant-stream-state.ts +13 -100
  456. package/src/runtime/background-job-runner.ts +5 -5
  457. package/src/runtime/channel-retry-sweep.ts +1 -0
  458. package/src/runtime/guardian-action-message-composer.ts +8 -161
  459. package/src/runtime/guardian-reply-router.ts +28 -32
  460. package/src/runtime/http-types.ts +6 -0
  461. package/src/runtime/message-composer-types.ts +3 -61
  462. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +67 -1
  463. package/src/runtime/migrations/vbundle-builder.ts +24 -1
  464. package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
  465. package/src/runtime/migrations/vbundle-import-policy.ts +10 -0
  466. package/src/runtime/migrations/vbundle-importer.ts +4 -1
  467. package/src/runtime/migrations/vbundle-streaming-importer.ts +4 -1
  468. package/src/runtime/migrations/vbundle-validator.ts +1 -0
  469. package/src/runtime/pending-interactions-mode-session.test.ts +62 -0
  470. package/src/runtime/pending-interactions.ts +29 -0
  471. package/src/runtime/routes/__tests__/client-history-routes.test.ts +104 -0
  472. package/src/runtime/routes/__tests__/image-generation-routes.test.ts +97 -0
  473. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +1 -1
  474. package/src/runtime/routes/__tests__/roadmap-routes.test.ts +29 -6
  475. package/src/runtime/routes/browser-context.ts +31 -11
  476. package/src/runtime/routes/browser-routes.ts +43 -4
  477. package/src/runtime/routes/btw-routes.ts +9 -4
  478. package/src/runtime/routes/client-routes.ts +108 -0
  479. package/src/runtime/routes/conversation-management-routes.ts +4 -1
  480. package/src/runtime/routes/conversation-routes.ts +113 -27
  481. package/src/runtime/routes/credential-prompt-routes.ts +4 -3
  482. package/src/runtime/routes/credential-routes.ts +1 -2
  483. package/src/runtime/routes/desktop-setup-routes.test.ts +9 -18
  484. package/src/runtime/routes/desktop-setup-routes.ts +4 -6
  485. package/src/runtime/routes/documents-routes.ts +51 -0
  486. package/src/runtime/routes/email-routes.ts +3 -7
  487. package/src/runtime/routes/events-routes.ts +75 -54
  488. package/src/runtime/routes/identity-routes.ts +1 -5
  489. package/src/runtime/routes/image-generation-routes.ts +8 -14
  490. package/src/runtime/routes/inbound-message-handler.ts +35 -38
  491. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.test.ts +168 -0
  492. package/src/runtime/routes/inbound-stages/backfill-sender-provenance.ts +96 -0
  493. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +38 -9
  494. package/src/runtime/routes/inbound-stages/background-dispatch.ts +2 -5
  495. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
  496. package/src/runtime/routes/llm-context-normalization.ts +1 -7
  497. package/src/runtime/routes/migration-routes.ts +73 -2
  498. package/src/runtime/routes/notification-routes.ts +10 -0
  499. package/src/runtime/routes/oauth-providers.ts +7 -0
  500. package/src/runtime/routes/plugins-routes.ts +6 -0
  501. package/src/runtime/routes/roadmap-routes.ts +47 -8
  502. package/src/runtime/routes/secret-routes.ts +1 -1
  503. package/src/runtime/routes/settings-routes.ts +10 -4
  504. package/src/runtime/routes/watcher-routes.ts +1 -3
  505. package/src/runtime/trust-class.test.ts +7 -6
  506. package/src/runtime/trust-class.ts +9 -17
  507. package/src/schedule/__tests__/worker-control.test.ts +36 -5
  508. package/src/schedule/worker-control.ts +15 -5
  509. package/src/security/secure-keys.ts +53 -103
  510. package/src/skills/clawhub.ts +3 -8
  511. package/src/skills/managed-store.ts +1 -5
  512. package/src/stt/types.ts +4 -0
  513. package/src/subagent/notify.ts +54 -34
  514. package/src/subagent/parent-notification.ts +6 -0
  515. package/src/telemetry/__tests__/phone-call-funnel.test.ts +72 -0
  516. package/src/telemetry/phone-call-funnel.ts +144 -0
  517. package/src/tools/__tests__/tool-schema-root-combinator-guard.test.ts +81 -0
  518. package/src/tools/ask-question/ask-question-tool.ts +6 -4
  519. package/src/tools/browser/browser-execution.ts +22 -59
  520. package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +561 -39
  521. package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +435 -39
  522. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +1 -8
  523. package/src/tools/client-os.ts +15 -0
  524. package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
  525. package/src/tools/computer-use/target.ts +42 -0
  526. package/src/tools/document/document-tool.ts +13 -18
  527. package/src/tools/execution-target.ts +14 -16
  528. package/src/tools/host-terminal/host-shell.ts +4 -1
  529. package/src/tools/network/__tests__/web-fetch-tinyfish.test.ts +250 -0
  530. package/src/tools/network/__tests__/web-search.test.ts +203 -0
  531. package/src/tools/network/web-fetch.ts +274 -7
  532. package/src/tools/network/web-search.ts +468 -6
  533. package/src/tools/permission-checker.ts +3 -3
  534. package/src/tools/policy-context.ts +3 -1
  535. package/src/tools/skills/load.ts +2 -1
  536. package/src/tools/skills/sandbox-runner.ts +11 -2
  537. package/src/tools/skills/skill-script-runner.ts +7 -0
  538. package/src/tools/skills/skill-tool-factory.ts +15 -1
  539. package/src/tools/terminal/__tests__/safe-env.test.ts +11 -0
  540. package/src/tools/terminal/safe-env.ts +4 -0
  541. package/src/tools/terminal/shell.ts +2 -0
  542. package/src/tools/tool-approval-handler.ts +5 -1
  543. package/src/tools/tool-types.ts +3 -3
  544. package/src/tools/types.ts +8 -2
  545. package/src/util/__tests__/worker-process-command.test.ts +5 -4
  546. package/src/util/abort-reasons.ts +18 -26
  547. package/src/util/canonicalize-identity.test.ts +21 -0
  548. package/src/util/canonicalize-identity.ts +16 -0
  549. package/src/util/errors.ts +13 -3
  550. package/src/util/provider-error-patterns.ts +3 -0
  551. package/src/util/worker-process.ts +77 -35
  552. package/src/workspace/migrations/157-add-desktop-files-launcher.ts +94 -0
  553. package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +4 -10
  554. package/src/workspace/migrations/__tests__/157-add-desktop-files-launcher.test.ts +113 -0
  555. package/src/workspace/migrations/registry.ts +2 -0
  556. package/src/__tests__/computer-use-window-schema.test.ts +0 -24
  557. package/src/api/events/heartbeat-alert.ts +0 -20
  558. package/src/daemon/message-types/web-activity.ts +0 -65
  559. package/src/desktop/desktop-dependencies.test.ts +0 -131
  560. package/src/tools/computer-use/definitions.ts +0 -607
@@ -2,14 +2,11 @@
2
2
  // Memory Tool definitions for agentic recall and remember.
3
3
  // ---------------------------------------------------------------------------
4
4
 
5
- import {
6
- ALL_RECALL_SOURCES,
7
- MAX_RECALL_MAX_RESULTS,
8
- MIN_RECALL_MAX_RESULTS,
9
- } from "../context-search/limits.js";
10
- import type { ToolDefinition } from "../llm-helpers.js";
5
+ import { toToolInputSchema } from "@vellumai/plugin-api";
11
6
 
12
- const RECALL_DEPTHS = ["fast", "standard", "deep"] as const;
7
+ import { RememberInputSchema } from "../../../../api/remember-tool.js";
8
+ import { RecallInputSchema } from "../context-search/recall-input.js";
9
+ import type { ToolDefinition } from "../llm-helpers.js";
13
10
 
14
11
  /**
15
12
  * Explicit local information search across memory, conversations, and
@@ -19,38 +16,7 @@ export const graphRecallDefinition = {
19
16
  name: "recall",
20
17
  description:
21
18
  'Search local information the moment you feel uncertain. Use recall for memory, past conversations, and workspace files — before you guess, before you ask, before you hedge. Auto-injection is incomplete by design; it surfaces patterns, not the specifics you need to answer well. If you catch yourself reaching for "I think", "I believe", "if I remember", "didn\'t we", "last time" — that\'s the signal. Recall. If a turn references someone, a place, a decision, a document, or prior work you should be able to find locally — recall. Call it multiple times per conversation if the turn warrants it. Be specific in your query for best results. Results reflect what was true when the memory was written — do not use recall alone to answer questions about current system state (account connections, watchers, service health); verify those with live checks.',
22
- input_schema: {
23
- type: "object",
24
- properties: {
25
- query: {
26
- type: "string",
27
- description:
28
- "What you're looking for. Be specific and descriptive: include the topic, person, project, decision, time period, or file clues when known.",
29
- },
30
- sources: {
31
- type: "array",
32
- items: {
33
- type: "string",
34
- enum: [...ALL_RECALL_SOURCES],
35
- },
36
- description:
37
- "Optional local sources to search. Omit to search memory, conversations, and workspace files.",
38
- },
39
- max_results: {
40
- type: "integer",
41
- minimum: MIN_RECALL_MAX_RESULTS,
42
- maximum: MAX_RECALL_MAX_RESULTS,
43
- description: "Maximum number of evidence items to return.",
44
- },
45
- depth: {
46
- type: "string",
47
- enum: [...RECALL_DEPTHS],
48
- description:
49
- "Search effort. Use fast for quick lookups, standard by default, and deep when the answer may require multiple local searches.",
50
- },
51
- },
52
- required: ["query"],
53
- },
19
+ input_schema: toToolInputSchema(RecallInputSchema),
54
20
  } satisfies ToolDefinition;
55
21
 
56
22
  /**
@@ -77,8 +43,9 @@ export const REMEMBER_PAGE_HINT_GUIDANCE =
77
43
  "When a fact relates to memory pages already in your context, reference the most specific ones inline as [[slug]] wikilinks — consolidation reads hinted pages first when filing the fact, which matters most for corrections (the hint names the page carrying the outdated fact). Hint only pages you have actually seen, and prefer specific pages over broad hubs.";
78
44
 
79
45
  /**
80
- * Build the `remember` input schema. `pageHints` reflects whether
81
- * concept-page memory is active and appends
46
+ * Build the `remember` input schema from {@link RememberInputSchema}, the one
47
+ * `execute` parses with, adding the descriptions the model reads.
48
+ * `pageHints` reflects whether concept-page memory is active and appends
82
49
  * {@link REMEMBER_PAGE_HINT_GUIDANCE} to the `content` description. It is a
83
50
  * thunk re-resolved on every read of that description: the registry's
84
51
  * finalized tool shares the returned schema object by reference, so a
@@ -87,29 +54,33 @@ export const REMEMBER_PAGE_HINT_GUIDANCE =
87
54
  */
88
55
  export function buildRememberInputSchema(options: {
89
56
  pageHints: () => boolean;
90
- }) {
91
- return {
92
- type: "object",
93
- properties: {
94
- content: {
95
- anyOf: [
96
- { type: "string" },
97
- { type: "array", items: { type: "string" }, minItems: 1 },
98
- ],
99
- get description(): string {
100
- return options.pageHints()
101
- ? `${REMEMBER_CONTENT_DESCRIPTION} ${REMEMBER_PAGE_HINT_GUIDANCE}`
102
- : REMEMBER_CONTENT_DESCRIPTION;
103
- },
104
- },
105
- finish_turn: {
106
- type: "boolean",
107
- description:
108
- "When you have nothing else to say and want to yield the turn you MUST set this to true. When true, your turn ends after this tool call. It's critical that you do this in order to avoid unnecessary LLM calls.",
109
- },
110
- },
111
- required: ["content"],
112
- };
57
+ }): Record<string, unknown> {
58
+ const schema = toToolInputSchema(
59
+ RememberInputSchema.extend({
60
+ content: RememberInputSchema.shape.content.describe(
61
+ REMEMBER_CONTENT_DESCRIPTION,
62
+ ),
63
+ finish_turn: RememberInputSchema.shape.finish_turn.describe(
64
+ "When you have nothing else to say and want to yield the turn you MUST set this to true. When true, your turn ends after this tool call. It's critical that you do this in order to avoid unnecessary LLM calls.",
65
+ ),
66
+ }),
67
+ );
68
+ const properties = schema.properties;
69
+ const content =
70
+ typeof properties === "object" && properties !== null
71
+ ? Reflect.get(properties, "content")
72
+ : undefined;
73
+ if (typeof content === "object" && content !== null) {
74
+ Object.defineProperty(content, "description", {
75
+ enumerable: true,
76
+ configurable: true,
77
+ get: (): string =>
78
+ options.pageHints()
79
+ ? `${REMEMBER_CONTENT_DESCRIPTION} ${REMEMBER_PAGE_HINT_GUIDANCE}`
80
+ : REMEMBER_CONTENT_DESCRIPTION,
81
+ });
82
+ }
83
+ return schema;
113
84
  }
114
85
 
115
86
  /**
@@ -23,7 +23,7 @@ import type { RouteDefinition } from "../../../../runtime/routes/types.js";
23
23
  import { getLogger } from "../logging.js";
24
24
  import { getWorkspaceDir } from "../paths.js";
25
25
  import { runMemoryEval } from "../v3-eval/eval-packets.js";
26
- import { type TallyResult, tallyVerdicts } from "../v3-eval/eval-tally.js";
26
+ import { tallyVerdicts } from "../v3-eval/eval-tally.js";
27
27
 
28
28
  const log = getLogger("memory-eval-routes");
29
29
 
@@ -138,12 +138,11 @@ export type MemoryEvalTallyResult = z.infer<typeof MemoryEvalTallyResultSchema>;
138
138
  */
139
139
  export function handleMemoryEvalTally(body: unknown): MemoryEvalTallyResult {
140
140
  const params = MemoryEvalTallyParamsSchema.parse(body ?? {});
141
- const result: TallyResult = tallyVerdicts(
141
+ return tallyVerdicts(
142
142
  params.verdicts,
143
143
  params.key,
144
144
  params.alpha !== undefined ? { alpha: params.alpha } : {},
145
145
  );
146
- return result;
147
146
  }
148
147
 
149
148
  const WRITE_POLICY: RoutePolicy = {
@@ -1199,6 +1199,11 @@ describe("Memory Item Routes", () => {
1199
1199
  const body = (await res.json()) as RememberBody;
1200
1200
  expect(body.success).toBe(true);
1201
1201
  expect(body.message.length).toBeGreaterThan(0);
1202
+ // Exactly the declared response fields: the handler's saved-facts list
1203
+ // stays on the tool path.
1204
+ expect(Object.keys(body).sort()).toEqual(
1205
+ ["message", "pendingNodeId", "success"].sort(),
1206
+ );
1202
1207
  });
1203
1208
 
1204
1209
  test("returns the pending node id of the appended entry", async () => {
@@ -1162,6 +1162,7 @@ export const ROUTES: RouteDefinition[] = [
1162
1162
  return result;
1163
1163
  }
1164
1164
  maybeEnqueueConsolidationForCreate(config);
1165
+ const created = { success: true, message: result.message };
1165
1166
 
1166
1167
  // Resolve the pending graph-node id of the entry just appended so the
1167
1168
  // client can fly the map to it. Matched by this request's content
@@ -1179,7 +1180,7 @@ export const ROUTES: RouteDefinition[] = [
1179
1180
  } catch (err) {
1180
1181
  log.warn({ err }, "Failed to resolve pending node id after create");
1181
1182
  }
1182
- return pendingNodeId ? { ...result, pendingNodeId } : result;
1183
+ return pendingNodeId ? { ...created, pendingNodeId } : created;
1183
1184
  },
1184
1185
  },
1185
1186
  ];
@@ -312,7 +312,7 @@ Cutoff timestamp for this run: \`${CUTOFF_PLACEHOLDER}\`. The entries for this p
312
312
  - Updated \`memory/threads.md\` (≤10000 chars)
313
313
  - Updated \`edges:\` frontmatter in any pages whose outgoing links changed
314
314
 
315
- How retrieval works: high-activation pages are loaded at the start of each turn. Activations spread along **directed** edges from source to target — activating A pulls in the pages A points at, but not the reverse. The immutable archive retains the entire buffer forever, so don't worry about losing information.
315
+ How retrieval works: high-activation pages are loaded at the start of each turn. Activations spread along **directed** edges from source to target: activating A pulls in the pages A points at, but not the reverse.
316
316
 
317
317
  ---
318
318
 
@@ -724,7 +724,7 @@ Three consequences:
724
724
 
725
725
  1. **The lead IS the card, and the fallback.** Write every lead as a standalone orientation: what this article is, the one or two facts that identify it, where it sits. If the lead only makes sense after reading the sections, the card is useless and so is the fallback. One to three short paragraphs.
726
726
  2. **Section names are navigation.** They appear on the selector's card as the table of contents and head every injected section. Name sections so future-you can tell from the name alone whether the answer lives there.
727
- 3. **Sections are the unit of growth and retrieval.** A fact filed in the right section of the right article is findable and arrives in context with its section (kept under the 6000-character chunk window, so the section travels whole); a fact buried mid-paragraph in an overlong lead is not. The immutable archive retains the entire buffer forever, so don't worry about losing information.
727
+ 3. **Sections are the unit of growth and retrieval.** A fact filed in the right section of the right article is findable and arrives in context with its section (kept under the 6000-character chunk window, so the section travels whole); a fact buried mid-paragraph in an overlong lead is not.
728
728
 
729
729
  ---
730
730
 
@@ -1,4 +1,4 @@
1
- import { mkdtempSync, readFileSync, rmSync } from "node:fs";
1
+ import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import {
@@ -11,7 +11,10 @@ import {
11
11
  test,
12
12
  } from "bun:test";
13
13
 
14
+ import { z } from "zod";
15
+
14
16
  import { setConfig } from "../../../__tests__/helpers/set-config.js";
17
+ import type { RecallMetadata } from "../../../api/events/tool-result.js";
15
18
  import type { ToolContext } from "../../../tools/types.js";
16
19
 
17
20
  let tmpWorkspace: string;
@@ -31,6 +34,14 @@ const recallCalls: Array<{
31
34
  context: Record<string, unknown>;
32
35
  }> = [];
33
36
  let recallContent = "agentic recall answer";
37
+ const recallActivity: RecallMetadata = {
38
+ query: "guardian recall",
39
+ depth: "standard",
40
+ sources: ["memory"],
41
+ answer: "agentic recall answer",
42
+ evidence: [],
43
+ searchedSources: [{ source: "memory", status: "searched", evidenceCount: 0 }],
44
+ };
34
45
 
35
46
  mock.module("./v1/jobs/embed-pkb-file.js", () => ({
36
47
  enqueuePkbIndexJob: (input: { pkbRoot: string; absPath: string }) => {
@@ -52,6 +63,7 @@ mock.module("./context-search/agent-runner.js", () => ({
52
63
  content: recallContent,
53
64
  answer: recallContent,
54
65
  evidence: [],
66
+ activity: recallActivity,
55
67
  debug: { mode: "agentic" },
56
68
  };
57
69
  },
@@ -146,6 +158,7 @@ describe("recallTool.execute", () => {
146
158
  expect(result).toEqual({
147
159
  content: "agentic recall answer",
148
160
  isError: false,
161
+ activityMetadata: { recall: recallActivity },
149
162
  });
150
163
  expect(recallCalls).toHaveLength(1);
151
164
  expect(recallCalls[0]?.input).toEqual({ query: "guardian recall" });
@@ -179,6 +192,7 @@ describe("recallTool.execute", () => {
179
192
  expect(result).toEqual({
180
193
  content: "agentic recall answer",
181
194
  isError: false,
195
+ activityMetadata: { recall: recallActivity },
182
196
  });
183
197
  expect(recallCalls).toHaveLength(1);
184
198
  expect(recallCalls[0]?.input).toEqual({
@@ -189,6 +203,37 @@ describe("recallTool.execute", () => {
189
203
  });
190
204
  });
191
205
 
206
+ test("refuses an unknown source before searching", async () => {
207
+ const result = await recallTool.execute(
208
+ { query: "launch notes", sources: ["calendar"] },
209
+ makeContext(),
210
+ );
211
+
212
+ expect(result.isError).toBe(true);
213
+ expect(result.content).toContain('Invalid input for tool "recall"');
214
+ expect(result.content).toContain("sources.0");
215
+ expect(recallCalls).toHaveLength(0);
216
+ });
217
+
218
+ test("reads null optionals as omitted and leaves max_results to the clamp", async () => {
219
+ await recallTool.execute(
220
+ {
221
+ query: "launch notes",
222
+ sources: null,
223
+ depth: null,
224
+ max_results: 50,
225
+ activity: "Looking up launch notes",
226
+ },
227
+ makeContext(),
228
+ );
229
+
230
+ expect(recallCalls[0]?.input).toEqual({
231
+ query: "launch notes",
232
+ max_results: 50,
233
+ activity: "Looking up launch notes",
234
+ });
235
+ });
236
+
192
237
  test("returns deterministic fallback content directly", async () => {
193
238
  recallContent = "Found evidence:\n\n- [workspace] fallback note";
194
239
 
@@ -200,6 +245,7 @@ describe("recallTool.execute", () => {
200
245
  expect(result).toEqual({
201
246
  content: "Found evidence:\n\n- [workspace] fallback note",
202
247
  isError: false,
248
+ activityMetadata: { recall: recallActivity },
203
249
  });
204
250
  });
205
251
 
@@ -305,6 +351,30 @@ describe("rememberTool.execute — buffer writes", () => {
305
351
  });
306
352
  });
307
353
 
354
+ describe("rememberTool.execute — memory access", () => {
355
+ test.each(["trusted_contact", "unverified_contact", "unknown"] as const)(
356
+ "refuses a %s write without touching the memory buffer",
357
+ async (trustClass) => {
358
+ const fact = `a claim made on a ${trustClass} turn`;
359
+ const result = await rememberTool.execute(
360
+ { content: fact, finish_turn: true },
361
+ makeContext({ trustClass }),
362
+ );
363
+
364
+ expect(result.isError).toBe(true);
365
+ expect(result.content).toContain("Not saved");
366
+ expect(result.activityMetadata).toBeUndefined();
367
+ // The turn continues so the model can relay the refusal.
368
+ expect(result.yieldToUser).toBeUndefined();
369
+ const bufferPath = join(tmpWorkspace, "memory", "buffer.md");
370
+ const buffer = existsSync(bufferPath)
371
+ ? readFileSync(bufferPath, "utf-8")
372
+ : "";
373
+ expect(buffer).not.toContain(fact);
374
+ },
375
+ );
376
+ });
377
+
308
378
  describe("rememberTool.execute — batch (array) content", () => {
309
379
  beforeEach(() => {
310
380
  enqueueCalls.length = 0;
@@ -313,10 +383,13 @@ describe("rememberTool.execute — batch (array) content", () => {
313
383
 
314
384
  test("records every fact from an array in the memory buffer", async () => {
315
385
  const result = await rememberTool.execute(
316
- { content: ["batch fact A", "batch fact B"] },
386
+ { content: [" batch fact A ", "batch fact B", " "] },
317
387
  makeContext(),
318
388
  );
319
389
  expect(result.isError).toBe(false);
390
+ expect(result.activityMetadata).toEqual({
391
+ remember: { facts: ["batch fact A", "batch fact B"] },
392
+ });
320
393
 
321
394
  const bufferContents = readFileSync(
322
395
  join(tmpWorkspace, "memory", "buffer.md"),
@@ -328,16 +401,58 @@ describe("rememberTool.execute — batch (array) content", () => {
328
401
  expect(enqueueCalls).toHaveLength(0);
329
402
  });
330
403
 
404
+ test("refuses a non-string fact without writing any of the batch", async () => {
405
+ const result = await rememberTool.execute(
406
+ { content: ["a fact beside a number", 42] },
407
+ makeContext(),
408
+ );
409
+
410
+ expect(result.isError).toBe(true);
411
+ expect(result.content).toContain('Invalid input for tool "remember"');
412
+ const bufferPath = join(tmpWorkspace, "memory", "buffer.md");
413
+ const buffer = existsSync(bufferPath)
414
+ ? readFileSync(bufferPath, "utf-8")
415
+ : "";
416
+ expect(buffer).not.toContain("a fact beside a number");
417
+ });
418
+
331
419
  test("rejects an all-blank array without writing or enqueueing", async () => {
332
420
  const result = await rememberTool.execute(
333
421
  { content: [" ", ""] },
334
422
  makeContext(),
335
423
  );
336
424
  expect(result.isError).toBe(true);
425
+ expect(result.activityMetadata).toBeUndefined();
337
426
  expect(enqueueCalls).toHaveLength(0);
338
427
  });
339
428
  });
340
429
 
430
+ /** The advertised `content` description, read as the provider serializes it. */
431
+ function contentDescription(schema: Record<string, unknown>): string {
432
+ return z
433
+ .object({
434
+ properties: z.object({ content: z.object({ description: z.string() }) }),
435
+ })
436
+ .parse(schema).properties.content.description;
437
+ }
438
+
439
+ describe("rememberTool definition", () => {
440
+ test("advertises the schema it parses with", () => {
441
+ const schema = rememberTool.input_schema;
442
+
443
+ expect(schema.required).toEqual(["content"]);
444
+ expect(schema.properties).toMatchObject({
445
+ content: {
446
+ anyOf: [
447
+ { type: "string" },
448
+ { type: "array", items: { type: "string" }, minItems: 1 },
449
+ ],
450
+ },
451
+ finish_turn: { type: "boolean" },
452
+ });
453
+ });
454
+ });
455
+
341
456
  describe("rememberTool definition — page-hint guidance gating", () => {
342
457
  // The rest of this file seeds the v2 flag off; restore that seed.
343
458
  afterAll(() => {
@@ -346,14 +461,14 @@ describe("rememberTool definition — page-hint guidance gating", () => {
346
461
 
347
462
  test("omits the [[slug]] hint guidance in v1/PKB mode", () => {
348
463
  setConfig("memory", { v2: { enabled: false } });
349
- expect(
350
- rememberTool.input_schema.properties.content.description,
351
- ).not.toContain("[[slug]]");
464
+ expect(contentDescription(rememberTool.input_schema)).not.toContain(
465
+ "[[slug]]",
466
+ );
352
467
  });
353
468
 
354
469
  test("includes the [[slug]] hint guidance under concept-page memory (v2)", () => {
355
470
  setConfig("memory", { v2: { enabled: true } });
356
- expect(rememberTool.input_schema.properties.content.description).toContain(
471
+ expect(contentDescription(rememberTool.input_schema)).toContain(
357
472
  "[[slug]] wikilinks",
358
473
  );
359
474
  // The gate must survive JSON serialization — that's how the schema
@@ -365,7 +480,7 @@ describe("rememberTool definition — page-hint guidance gating", () => {
365
480
 
366
481
  test("includes the [[slug]] hint guidance when v3 is live with the v2 flag off", () => {
367
482
  setConfig("memory", { v2: { enabled: false }, v3: { live: true } });
368
- expect(rememberTool.input_schema.properties.content.description).toContain(
483
+ expect(contentDescription(rememberTool.input_schema)).toContain(
369
484
  "[[slug]] wikilinks",
370
485
  );
371
486
  });
@@ -373,8 +488,8 @@ describe("rememberTool definition — page-hint guidance gating", () => {
373
488
  test("re-resolves against config on each read, without re-registration", () => {
374
489
  const schema = rememberTool.input_schema;
375
490
  setConfig("memory", { v2: { enabled: true } });
376
- expect(schema.properties.content.description).toContain("[[slug]]");
491
+ expect(contentDescription(schema)).toContain("[[slug]]");
377
492
  setConfig("memory", { v2: { enabled: false } });
378
- expect(schema.properties.content.description).not.toContain("[[slug]]");
493
+ expect(contentDescription(schema)).not.toContain("[[slug]]");
379
494
  });
380
495
  });
@@ -3,12 +3,14 @@
3
3
  *
4
4
  * Core, always-loaded tools registered via the host tool manifest
5
5
  * (`tools/tool-manifest.ts`), so they carry core/workspace-override precedence
6
- * and the `"memory"` tool category. Their implementations source from the
7
- * memory feature (`src/memory/*`).
6
+ * and the `"memory"` tool category. The host's central input check covers only
7
+ * tools it can import, which excludes a plugin's, so each tool here parses its
8
+ * own input.
8
9
  */
9
10
 
10
- import { throwIfCancelled } from "@vellumai/plugin-api";
11
+ import { invalidToolInputResult, throwIfCancelled } from "@vellumai/plugin-api";
11
12
 
13
+ import { RememberInputSchema } from "../../../api/remember-tool.js";
12
14
  import { getConfig, getConfigReadOnly } from "../../../config/loader.js";
13
15
  import { usesConceptPageMemory } from "../../../config/memory-v3-gate.js";
14
16
  import { RiskLevel } from "../../../permissions/types.js";
@@ -19,8 +21,8 @@ import type {
19
21
  ToolExecutionResult,
20
22
  } from "../../../tools/types.js";
21
23
  import { runAgenticRecall } from "./context-search/agent-runner.js";
22
- import type { RecallInput } from "./context-search/types.js";
23
- import { handleRemember, type RememberInput } from "./graph/tool-handlers.js";
24
+ import { RecallInputSchema } from "./context-search/recall-input.js";
25
+ import { handleRemember } from "./graph/tool-handlers.js";
24
26
  import {
25
27
  buildRememberInputSchema,
26
28
  graphRecallDefinition,
@@ -52,18 +54,35 @@ export const rememberTool = {
52
54
  input: Record<string, unknown>,
53
55
  context: ToolContext,
54
56
  ): Promise<ToolExecutionResult> {
55
- const typedInput = input as unknown as RememberInput;
56
57
  // The append below writes the memory buffer, so a cancelled turn stops here.
57
58
  throwIfCancelled(context);
59
+ if (!resolveCapabilities(context.trustClass).canAccessMemory) {
60
+ // No yield even when finish_turn is set: the model has to see this, so
61
+ // it never tells someone a fact was saved when it was not. An error, not
62
+ // a quiet no-op: a non-error `remember` result reads as a durable write to
63
+ // `memory-run-evidence`.
64
+ return {
65
+ content:
66
+ "Not saved: remember writes the guardian's long-term memory, which is only available on the guardian's own turns. Retrying will not help. Tell the person only if they asked you to remember this or you said you would.",
67
+ isError: true,
68
+ };
69
+ }
70
+ const parsed = RememberInputSchema.safeParse(input);
71
+ if (!parsed.success) {
72
+ return invalidToolInputResult("remember", parsed.error);
73
+ }
58
74
  const result = handleRemember(
59
- typedInput,
75
+ parsed.data,
60
76
  context.conversationId,
61
77
  getConfig(),
62
78
  );
63
79
  return {
64
80
  content: result.message,
65
81
  isError: !result.success,
66
- ...(typedInput.finish_turn === true ? { yieldToUser: true } : {}),
82
+ ...(result.success
83
+ ? { activityMetadata: { remember: { facts: result.facts } } }
84
+ : {}),
85
+ ...(parsed.data.finish_turn === true ? { yieldToUser: true } : {}),
67
86
  };
68
87
  },
69
88
  } satisfies ToolDefinition;
@@ -90,15 +109,23 @@ export const recallTool = {
90
109
  };
91
110
  }
92
111
 
112
+ const parsed = RecallInputSchema.safeParse(input);
113
+ if (!parsed.success) {
114
+ return invalidToolInputResult("recall", parsed.error);
115
+ }
93
116
  const config = getConfig();
94
- const result = await runAgenticRecall(input as unknown as RecallInput, {
117
+ const result = await runAgenticRecall(parsed.data, {
95
118
  workingDir: context.workingDir,
96
119
  conversationId: context.conversationId,
97
120
  config,
98
121
  signal: context.signal,
99
122
  });
100
123
 
101
- return { content: result.content, isError: false };
124
+ return {
125
+ content: result.content,
126
+ isError: false,
127
+ activityMetadata: { recall: result.activity },
128
+ };
102
129
  },
103
130
  } satisfies ToolDefinition;
104
131
 
@@ -127,7 +154,7 @@ export const recallTool = {
127
154
  export const deleteMemoryPageTool = {
128
155
  name: "delete_memory_page",
129
156
  description:
130
- "Delete one concept page from your memory wiki, addressed by slug (its path under `memory/concepts/` minus `.md`, e.g. `alice`, `people/alice`, `procs/git-flow`). Use during a consolidation/maintenance pass to retire a page you merged into another, renamed (write the new page, then delete the old slug), or dropped as a dead stub. Only concept pages can be deleted: the index files (`recent.md`, `essentials.md`, `threads.md`) are rewritten with file_write/file_edit, never deleted, and `buffer.md` is never written by you at all; the runtime removes the entries it handed you once the pass completes. Idempotent: deleting a slug that is already gone is not an error. The immutable archive retains buffer history, so removing a page never loses source facts.",
157
+ "Delete one concept page from your memory wiki, addressed by slug (its path under `memory/concepts/` minus `.md`, e.g. `alice`, `people/alice`, `procs/git-flow`). Use during a consolidation/maintenance pass to retire a page you merged into another, renamed (write the new page, then delete the old slug), or dropped as a dead stub. Only concept pages can be deleted: the index files (`recent.md`, `essentials.md`, `threads.md`) are rewritten with file_write/file_edit, never deleted, and `buffer.md` is never written by you at all; the runtime removes the entries it handed you once the pass completes. Idempotent: deleting a slug that is already gone is not an error.",
131
158
  category: "memory",
132
159
  executionTarget: "sandbox",
133
160
  defaultRiskLevel: RiskLevel.Low,