@vellumai/assistant 0.10.12 → 0.11.0-staging.1

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 (776) hide show
  1. package/AGENTS.md +1 -1
  2. package/ARCHITECTURE.md +4 -5
  3. package/README.md +1 -1
  4. package/docs/architecture/memory.md +60 -23
  5. package/docs/error-handling.md +3 -3
  6. package/docs/guardian-request-flow.md +112 -0
  7. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  8. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
  9. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
  10. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
  11. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
  12. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/app.d.ts +28 -0
  13. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/app.d.ts.map +1 -1
  14. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.d.ts +2 -2
  15. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.d.ts.map +1 -1
  16. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.js.map +1 -1
  17. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/message.d.ts +2 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/message.d.ts.map +1 -1
  19. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/package.json +1 -1
  20. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
  23. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
  24. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
  25. package/node_modules/@vellumai/gateway-client/package.json +1 -1
  26. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +6 -0
  27. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +34 -0
  28. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  29. package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
  30. package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
  31. package/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
  32. package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
  33. package/openapi.yaml +246 -10
  34. package/package.json +2 -2
  35. package/src/__tests__/acp-session.test.ts +3 -3
  36. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +3 -0
  37. package/src/__tests__/anthropic-provider.test.ts +40 -0
  38. package/src/__tests__/approval-cascade.test.ts +5 -5
  39. package/src/__tests__/approval-routes-http.test.ts +3 -3
  40. package/src/__tests__/ask-question-resolver.test.ts +207 -0
  41. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +16 -16
  42. package/src/__tests__/assistant-event-hub-targeted.test.ts +13 -11
  43. package/src/__tests__/assistant-event-hub.test.ts +13 -11
  44. package/src/__tests__/assistant-event.test.ts +12 -9
  45. package/src/__tests__/assistant-feature-flag-guard.test.ts +3 -3
  46. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +1 -1
  47. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -58
  48. package/src/__tests__/assistant-stream-state.test.ts +17 -7
  49. package/src/__tests__/avatar-identity-sync.test.ts +3 -3
  50. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
  51. package/src/__tests__/call-conversation-messages.test.ts +134 -18
  52. package/src/__tests__/call-start-guardian-guard.test.ts +27 -0
  53. package/src/__tests__/channel-approvals.test.ts +0 -27
  54. package/src/__tests__/channel-guardian.test.ts +85 -512
  55. package/src/__tests__/channel-readiness-slack-remote.test.ts +151 -3
  56. package/src/__tests__/channel-retry-sweep.test.ts +88 -1
  57. package/src/__tests__/channel-setup-panel-ack.test.ts +12 -9
  58. package/src/__tests__/chat-reveal-guard-priming.test.ts +31 -34
  59. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +2 -2
  60. package/src/__tests__/compaction-events.test.ts +8 -8
  61. package/src/__tests__/config-loader-platform-defaults.test.ts +54 -28
  62. package/src/__tests__/config-model-image-provider.test.ts +20 -0
  63. package/src/__tests__/config-schema-memory-substrate.test.ts +306 -0
  64. package/src/__tests__/config-schema.test.ts +14 -2
  65. package/src/__tests__/config-set-platform-guard.test.ts +11 -12
  66. package/src/__tests__/config-sounds-sync.test.ts +4 -4
  67. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +5 -0
  68. package/src/__tests__/context-search-memory-source.test.ts +1 -1
  69. package/src/__tests__/context-search-memory-v2-source.test.ts +6 -6
  70. package/src/__tests__/context-token-estimator.test.ts +54 -1
  71. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +12 -3
  72. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +13 -4
  73. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +4 -4
  74. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -1
  75. package/src/__tests__/conversation-agent-loop-overflow.test.ts +22 -13
  76. package/src/__tests__/conversation-agent-loop.test.ts +39 -30
  77. package/src/__tests__/conversation-confirmation-signals.test.ts +14 -14
  78. package/src/__tests__/conversation-evictor.test.ts +49 -0
  79. package/src/__tests__/conversation-fork-crud.test.ts +1 -1
  80. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  81. package/src/__tests__/conversation-key-store-disk-view.test.ts +5 -5
  82. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +5 -5
  83. package/src/__tests__/conversation-message-sync-tags.test.ts +4 -4
  84. package/src/__tests__/conversation-queue.test.ts +81 -81
  85. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +8 -1
  86. package/src/__tests__/conversation-routes-hidden-queue.test.ts +8 -1
  87. package/src/__tests__/conversation-routes-slash-commands.test.ts +10 -1
  88. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -2
  89. package/src/__tests__/conversation-slash-queue.test.ts +11 -11
  90. package/src/__tests__/conversation-slash-unknown.test.ts +2 -2
  91. package/src/__tests__/conversation-speed-override.test.ts +2 -2
  92. package/src/__tests__/conversation-summarize-route.test.ts +9 -0
  93. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +18 -16
  94. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +17 -17
  95. package/src/__tests__/conversation-surfaces-app-open.test.ts +7 -4
  96. package/src/__tests__/conversation-surfaces-data-persist.test.ts +7 -7
  97. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +9 -9
  98. package/src/__tests__/conversation-surfaces-standalone.test.ts +12 -12
  99. package/src/__tests__/conversation-surfaces-state-update.test.ts +8 -5
  100. package/src/__tests__/conversation-surfaces-table-action.test.ts +6 -3
  101. package/src/__tests__/conversation-surfaces-task-progress.test.ts +46 -46
  102. package/src/__tests__/conversation-sync-tags.test.ts +5 -5
  103. package/src/__tests__/conversation-wait-for-idle.test.ts +2 -2
  104. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
  105. package/src/__tests__/conversation-workspace-injection.test.ts +0 -3
  106. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -3
  107. package/src/__tests__/copy-composer-tc-templates.test.ts +3 -131
  108. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  109. package/src/__tests__/daemon-assistant-events.test.ts +14 -15
  110. package/src/__tests__/db-test-helpers.ts +13 -27
  111. package/src/__tests__/disk-pressure-routes.test.ts +12 -3
  112. package/src/__tests__/document-tool-security.test.ts +95 -0
  113. package/src/__tests__/drain-kick-guard.test.ts +232 -0
  114. package/src/__tests__/dynamic-skill-background-guard.test.ts +19 -6
  115. package/src/__tests__/emit-event-signal.test.ts +5 -6
  116. package/src/__tests__/encrypted-store-test-helpers.ts +10 -20
  117. package/src/__tests__/events-tail-route.test.ts +6 -4
  118. package/src/__tests__/feature-flag-test-helpers.ts +10 -20
  119. package/src/__tests__/file-edit-tool.test.ts +24 -4
  120. package/src/__tests__/file-list-tool.test.ts +2 -1
  121. package/src/__tests__/file-read-tool.test.ts +62 -10
  122. package/src/__tests__/file-write-tool.test.ts +24 -5
  123. package/src/__tests__/followup-tools.test.ts +58 -0
  124. package/src/__tests__/gateway-threshold-reader-mock.ts +99 -0
  125. package/src/__tests__/graph-extraction-event-date.test.ts +1 -1
  126. package/src/__tests__/guardian-question-mode.test.ts +42 -3
  127. package/src/__tests__/guardian-reply-router-answer-mode.test.ts +283 -0
  128. package/src/__tests__/guardian-vellum-destination-pinning.test.ts +221 -0
  129. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  130. package/src/__tests__/heartbeat-service.test.ts +1 -0
  131. package/src/__tests__/helpers/native-web-search-harness.ts +10 -10
  132. package/src/__tests__/host-browser-proxy.test.ts +1 -1
  133. package/src/__tests__/host-file-edit-tool.test.ts +3 -3
  134. package/src/__tests__/host-file-read-tool.test.ts +2 -2
  135. package/src/__tests__/host-file-write-tool.test.ts +7 -3
  136. package/src/__tests__/host-shell-tool.test.ts +17 -5
  137. package/src/__tests__/host-transfer-pending-interactions.test.ts +8 -8
  138. package/src/__tests__/image-credentials.test.ts +65 -8
  139. package/src/__tests__/injection-block.test.ts +4 -4
  140. package/src/__tests__/injector-chain.test.ts +1 -1
  141. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  142. package/src/__tests__/injector-registry-order-guard.test.ts +4 -9
  143. package/src/__tests__/injector-v3-suppression.test.ts +6 -4
  144. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +27 -28
  145. package/src/__tests__/list-messages-page-latest.test.ts +2 -2
  146. package/src/__tests__/llm-usage-store.test.ts +67 -4
  147. package/src/__tests__/log-redact.test.ts +18 -0
  148. package/src/__tests__/managed-profile-guard.test.ts +27 -0
  149. package/src/__tests__/managed-skill-lifecycle.test.ts +2 -2
  150. package/src/__tests__/media-generate-image.test.ts +62 -11
  151. package/src/__tests__/memory-identity-context-parity.test.ts +1 -1
  152. package/src/__tests__/memory-jobs-worker-lanes.test.ts +9 -1
  153. package/src/__tests__/memory-retrieval-hook.test.ts +4 -4
  154. package/src/__tests__/notification-decision-strategy.test.ts +115 -11
  155. package/src/__tests__/notification-deep-link.test.ts +12 -12
  156. package/src/__tests__/notification-vellum-adapter.test.ts +8 -8
  157. package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
  158. package/src/__tests__/path-policy.test.ts +315 -0
  159. package/src/__tests__/pending-interactions-resolved-event.test.ts +6 -6
  160. package/src/__tests__/persistence-layering-guard.test.ts +2 -2
  161. package/src/__tests__/pkb-autoinject.test.ts +1 -1
  162. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -0
  163. package/src/__tests__/plugin-event-hub-facade.test.ts +22 -15
  164. package/src/__tests__/plugin-import-boundary-guard.test.ts +15 -15
  165. package/src/__tests__/processing-flag-persist-failure.test.ts +0 -4
  166. package/src/__tests__/provider-platform-proxy-integration.test.ts +0 -1
  167. package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
  168. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +5 -5
  169. package/src/__tests__/require-fresh-approval.test.ts +38 -38
  170. package/src/__tests__/run-due-schedules.test.ts +72 -1
  171. package/src/__tests__/runtime-events-sse-parity.test.ts +11 -10
  172. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  173. package/src/__tests__/schedule-routes.test.ts +44 -5
  174. package/src/__tests__/schedule-store.test.ts +3 -3
  175. package/src/__tests__/schedule-tools.test.ts +176 -0
  176. package/src/__tests__/secret-prompt-log-hygiene.test.ts +3 -3
  177. package/src/__tests__/secret-prompter-channel-fallback.test.ts +3 -3
  178. package/src/__tests__/secret-response-routing.test.ts +3 -3
  179. package/src/__tests__/secret-routes-platform-proxy.test.ts +4 -7
  180. package/src/__tests__/secret-scanner.test.ts +36 -0
  181. package/src/__tests__/send-endpoint-busy.test.ts +7 -7
  182. package/src/__tests__/slack-required-scopes-mirror.test.ts +81 -0
  183. package/src/__tests__/starter-task-flow.test.ts +6 -3
  184. package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
  185. package/src/__tests__/subagent-disposal.test.ts +40 -11
  186. package/src/__tests__/subagent-fork-notifications.test.ts +4 -4
  187. package/src/__tests__/subagent-fork-prompt-role.test.ts +3 -3
  188. package/src/__tests__/subagent-fork-spawn.test.ts +4 -4
  189. package/src/__tests__/subagent-manager-notify.test.ts +73 -14
  190. package/src/__tests__/subagent-notify-parent.test.ts +48 -4
  191. package/src/__tests__/subagent-spawn-and-await.test.ts +62 -14
  192. package/src/__tests__/subagent-tools.test.ts +64 -0
  193. package/src/__tests__/sync-message-contract.test.ts +3 -3
  194. package/src/__tests__/terminal-tools.test.ts +12 -3
  195. package/src/__tests__/test-preload.ts +9 -0
  196. package/src/__tests__/tool-approval-handler.test.ts +583 -43
  197. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +7 -4
  198. package/src/__tests__/tool-executor.test.ts +116 -0
  199. package/src/__tests__/tool-grant-request-escalation.test.ts +5 -0
  200. package/src/__tests__/tool-preview-lifecycle.test.ts +32 -29
  201. package/src/__tests__/tool-result-metadata-plumbing.test.ts +5 -5
  202. package/src/__tests__/tool-start-timestamp.test.ts +4 -4
  203. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -22
  204. package/src/__tests__/ui-choice-copy-surfaces.test.ts +13 -13
  205. package/src/__tests__/ui-work-result-surface.test.ts +3 -3
  206. package/src/__tests__/voice-scoped-grant-consumer.test.ts +6 -6
  207. package/src/__tests__/voice-session-bridge.test.ts +44 -44
  208. package/src/__tests__/workspace-migration-134-image-generation-mode-to-provider.test.ts +284 -0
  209. package/src/__tests__/workspace-policy.test.ts +399 -0
  210. package/src/acp/__tests__/client-handler.test.ts +3 -3
  211. package/src/acp/__tests__/session-manager-persistence.test.ts +10 -10
  212. package/src/acp/__tests__/session-manager-resume.test.ts +7 -7
  213. package/src/acp/client-handler.ts +3 -3
  214. package/src/acp/session-manager.ts +8 -8
  215. package/src/api/events/subagent-event.ts +2 -2
  216. package/src/api/responses/memory-v2-activation-log.ts +2 -2
  217. package/src/approvals/AGENTS.md +2 -0
  218. package/src/approvals/guardian-request-resolvers.ts +118 -24
  219. package/src/calls/__tests__/voice-control-protocol.test.ts +57 -0
  220. package/src/calls/__tests__/voice-session-bridge.test.ts +158 -4
  221. package/src/calls/__tests__/voice-triage-escalate.test.ts +3 -4
  222. package/src/calls/call-controller.ts +27 -27
  223. package/src/calls/call-conversation-messages.ts +58 -18
  224. package/src/calls/voice-control-protocol.ts +56 -0
  225. package/src/calls/voice-session-bridge.ts +156 -58
  226. package/src/calls/voice-triage-escalate.ts +2 -3
  227. package/src/channels/config.ts +8 -0
  228. package/src/channels/types.ts +1 -0
  229. package/src/cli/commands/config.ts +49 -13
  230. package/src/cli/commands/memory/index.help.ts +4 -2
  231. package/src/cli/commands/memory/memory-retrospective.ts +5 -0
  232. package/src/cli/lib/bundled-marketplace.json +12 -0
  233. package/src/cli.ts +2 -109
  234. package/src/config/__tests__/deployment-context-defaults.test.ts +9 -0
  235. package/src/config/__tests__/substrate-twin-shadowing.test.ts +191 -0
  236. package/src/config/assistant-feature-flags.ts +1 -1
  237. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +13 -7
  238. package/src/config/feature-flag-cache.ts +6 -16
  239. package/src/config/feature-flag-registry.json +14 -30
  240. package/src/config/loader.ts +7 -1
  241. package/src/config/memory-tier.ts +15 -10
  242. package/src/config/memory-v3-gate.test.ts +278 -1
  243. package/src/config/memory-v3-gate.ts +88 -26
  244. package/src/config/raw-config-utils.ts +1 -1
  245. package/src/config/schemas/__tests__/live-voice.test.ts +27 -16
  246. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  247. package/src/config/schemas/live-voice.ts +33 -7
  248. package/src/config/schemas/llm.ts +1 -0
  249. package/src/config/schemas/memory-retrospective.ts +13 -0
  250. package/src/config/schemas/memory-substrate.ts +183 -0
  251. package/src/config/schemas/memory-v2.ts +3 -2
  252. package/src/config/schemas/memory-v3.ts +11 -4
  253. package/src/config/schemas/memory.ts +35 -1
  254. package/src/config/schemas/services.ts +10 -2
  255. package/src/config/substrate-twin-shadowing.ts +195 -0
  256. package/src/config/webhook-routing.ts +67 -0
  257. package/src/context/compactor.ts +10 -3
  258. package/src/context/token-estimator.ts +21 -0
  259. package/src/daemon/__tests__/channel-ui-capability.test.ts +85 -0
  260. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +3 -3
  261. package/src/daemon/__tests__/embedding-reconcile.test.ts +3 -3
  262. package/src/daemon/__tests__/inference-profile-notification.test.ts +3 -6
  263. package/src/daemon/__tests__/native-web-search-metadata.test.ts +5 -5
  264. package/src/daemon/__tests__/web-search-status-text.test.ts +2 -2
  265. package/src/daemon/channel-ui-capability.ts +70 -1
  266. package/src/daemon/conversation-agent-loop-handlers.ts +4 -4
  267. package/src/daemon/conversation-agent-loop.ts +12 -5
  268. package/src/daemon/conversation-evictor.ts +26 -4
  269. package/src/daemon/conversation-launch.ts +11 -14
  270. package/src/daemon/conversation-messaging.ts +14 -14
  271. package/src/daemon/conversation-notifiers.ts +2 -2
  272. package/src/daemon/conversation-process.ts +133 -21
  273. package/src/daemon/conversation-queue-manager.ts +7 -7
  274. package/src/daemon/conversation-runtime-assembly.ts +16 -0
  275. package/src/daemon/conversation-store.ts +11 -3
  276. package/src/daemon/conversation-surfaces.ts +4 -4
  277. package/src/daemon/conversation-tool-setup.ts +13 -7
  278. package/src/daemon/conversation-usage.ts +12 -11
  279. package/src/daemon/conversation.ts +38 -15
  280. package/src/daemon/disk-pressure-guard.ts +5 -12
  281. package/src/daemon/embedding-reconcile.ts +14 -9
  282. package/src/daemon/handlers/config-channels.ts +40 -134
  283. package/src/daemon/handlers/config-model.ts +15 -7
  284. package/src/daemon/handlers/conversations.ts +4 -2
  285. package/src/daemon/handlers/shared.ts +29 -0
  286. package/src/daemon/host-proxy-base.ts +4 -4
  287. package/src/daemon/lifecycle.ts +13 -0
  288. package/src/daemon/message-protocol.ts +8 -144
  289. package/src/daemon/message-types/computer-use.ts +0 -12
  290. package/src/daemon/message-types/conversations.ts +9 -345
  291. package/src/daemon/message-types/host-app-control.ts +0 -9
  292. package/src/daemon/message-types/host-browser.ts +0 -7
  293. package/src/daemon/message-types/host-ui-snapshot.ts +0 -7
  294. package/src/daemon/message-types/messages.ts +0 -48
  295. package/src/daemon/message-types/notifications.ts +0 -7
  296. package/src/daemon/message-types/skills.ts +0 -5
  297. package/src/daemon/message-types/surfaces.ts +0 -9
  298. package/src/daemon/message-types/sync.ts +0 -2
  299. package/src/daemon/process-message.ts +5 -5
  300. package/src/daemon/skill-memory-refresh.ts +5 -5
  301. package/src/daemon/tool-side-effects.ts +13 -13
  302. package/src/daemon/trust-context.ts +1 -1
  303. package/src/daemon/wake-conversation-ops.ts +4 -4
  304. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +100 -7
  305. package/src/heartbeat/__tests__/heartbeat-service.test.ts +67 -0
  306. package/src/heartbeat/heartbeat-run-store.ts +81 -4
  307. package/src/heartbeat/heartbeat-service.ts +32 -1
  308. package/src/home/__tests__/feed-writer.test.ts +7 -7
  309. package/src/home/__tests__/home-content-refresh.test.ts +3 -0
  310. package/src/home/__tests__/suggested-prompts.test.ts +1 -0
  311. package/src/home/feed-writer.ts +6 -13
  312. package/src/home/home-content-refresh.ts +6 -9
  313. package/src/home/relationship-state-writer.ts +5 -12
  314. package/src/home/suggested-prompts-cache.ts +6 -19
  315. package/src/ipc/__tests__/events-publish-client.test.ts +67 -0
  316. package/src/ipc/events-publish-client.ts +44 -0
  317. package/src/ipc/routes/__tests__/conversation-sync-ipc-routes.test.ts +2 -2
  318. package/src/ipc/routes/__tests__/events-ipc-routes.test.ts +38 -9
  319. package/src/ipc/routes/events-ipc-routes.ts +11 -31
  320. package/src/live-voice/__tests__/front-decision.test.ts +4 -176
  321. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +276 -68
  322. package/src/live-voice/__tests__/live-voice-events.test.ts +6 -3
  323. package/src/live-voice/__tests__/live-voice-progress.test.ts +185 -46
  324. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +24 -59
  325. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +38 -54
  326. package/src/live-voice/__tests__/live-voice-vad.test.ts +218 -422
  327. package/src/live-voice/front-decision.ts +5 -155
  328. package/src/live-voice/live-voice-metrics.ts +4 -1
  329. package/src/live-voice/live-voice-session.ts +650 -333
  330. package/src/live-voice/progress-phrases.ts +17 -0
  331. package/src/live-voice/protocol.ts +15 -0
  332. package/src/media/app-icon-generator.ts +15 -8
  333. package/src/media/avatar-router.ts +9 -5
  334. package/src/media/image-credentials.ts +42 -10
  335. package/src/media/image-service.ts +1 -13
  336. package/src/media/types.ts +26 -3
  337. package/src/notifications/AGENTS.md +2 -0
  338. package/src/notifications/__tests__/broadcaster.test.ts +95 -0
  339. package/src/notifications/adapters/macos.ts +3 -3
  340. package/src/notifications/broadcaster.ts +57 -0
  341. package/src/notifications/copy-composer.ts +0 -15
  342. package/src/notifications/decision-engine.ts +21 -22
  343. package/src/notifications/guardian-question-mode.ts +57 -2
  344. package/src/notifications/home-feed-side-effect.ts +4 -0
  345. package/src/notifications/signal.ts +6 -4
  346. package/src/notifications/trusted-contact-payloads.ts +3 -4
  347. package/src/notifications/vellum-card-affinity.ts +39 -0
  348. package/src/oauth/AGENTS.md +1 -1
  349. package/src/permissions/channel-permission-query.test.ts +69 -0
  350. package/src/permissions/channel-permission-query.ts +73 -1
  351. package/src/permissions/checker.test.ts +85 -9
  352. package/src/permissions/checker.ts +17 -22
  353. package/src/permissions/confirmation-guardian-request.test.ts +2 -2
  354. package/src/permissions/confirmation-guardian-request.ts +2 -2
  355. package/src/permissions/gateway-threshold-reader.test.ts +224 -17
  356. package/src/permissions/gateway-threshold-reader.ts +82 -10
  357. package/src/permissions/ipc-risk-types.ts +8 -0
  358. package/src/permissions/prompter.ts +5 -5
  359. package/src/permissions/question-guardian-request.test.ts +222 -0
  360. package/src/permissions/question-guardian-request.ts +179 -0
  361. package/src/permissions/question-prompter.test.ts +8 -8
  362. package/src/permissions/question-prompter.ts +18 -0
  363. package/src/permissions/secret-prompter.ts +2 -4
  364. package/src/permissions/workspace-policy.ts +236 -34
  365. package/src/persistence/__tests__/lifecycle-quiesce.test.ts +82 -0
  366. package/src/persistence/__tests__/message-content-file.test.ts +58 -3
  367. package/src/persistence/conversation-crud.ts +93 -0
  368. package/src/persistence/conversation-key-store.ts +63 -0
  369. package/src/persistence/db-async-query.ts +1 -1
  370. package/src/persistence/db-singleton.ts +14 -27
  371. package/src/persistence/delivery-crud.ts +45 -0
  372. package/src/persistence/embeddings/embedding-backend.ts +2 -1
  373. package/src/persistence/embeddings/embedding-identity.ts +7 -3
  374. package/src/persistence/job-utils.ts +32 -27
  375. package/src/persistence/jobs-store.ts +92 -3
  376. package/src/persistence/lifecycle-quiesce.ts +80 -0
  377. package/src/persistence/llm-usage-store.ts +45 -8
  378. package/src/persistence/message-content-file.ts +4 -4
  379. package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +1 -1
  380. package/src/persistence/migrations/351-schedule-skill-script-handoff.ts +39 -0
  381. package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.test.ts +83 -0
  382. package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.ts +36 -0
  383. package/src/persistence/migrations/353-add-llm-usage-conversation-type.test.ts +110 -0
  384. package/src/persistence/migrations/353-add-llm-usage-conversation-type.ts +49 -0
  385. package/src/persistence/schema/infrastructure.ts +11 -0
  386. package/src/persistence/steps.ts +7 -1
  387. package/src/plugin-api/__tests__/publish-event-forwarding.test.ts +113 -0
  388. package/src/plugin-api/__tests__/publish-event.test.ts +57 -0
  389. package/src/plugin-api/conversation-turn.ts +4 -4
  390. package/src/plugin-api/event-hub-facade.ts +15 -6
  391. package/src/plugin-api/index.ts +10 -4
  392. package/src/plugin-api/publish-event.ts +36 -0
  393. package/src/plugins/AGENTS.md +2 -0
  394. package/src/plugins/defaults/compaction/window-manager.ts +9 -0
  395. package/src/plugins/defaults/index.ts +9 -13
  396. package/src/plugins/defaults/memory/AGENTS.md +775 -0
  397. package/src/plugins/defaults/memory/__tests__/capability-seed-embed-gate.test.ts +186 -0
  398. package/src/plugins/defaults/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +1 -1
  399. package/src/plugins/defaults/memory/__tests__/indexer-tier-dispatch.test.ts +129 -0
  400. package/src/plugins/defaults/memory/__tests__/jobs-worker-quiesce-gate.test.ts +91 -0
  401. package/src/plugins/defaults/memory/__tests__/jobs-worker-v1-graph-substrate-noop.test.ts +342 -0
  402. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +9 -1
  403. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +36 -1
  404. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-sweep-defer.test.ts +9 -1
  405. package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +2 -2
  406. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +44 -10
  407. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +151 -10
  408. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1155 -0
  409. package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
  410. package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -3
  411. package/src/plugins/defaults/memory/__tests__/tools-delete-memory-page.test.ts +1 -1
  412. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +71 -35
  413. package/src/plugins/defaults/memory/context-search/sources/memory.ts +5 -1
  414. package/src/plugins/defaults/memory/fork-conversation-memory.ts +4 -4
  415. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +80 -10
  416. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +1 -1
  417. package/src/plugins/defaults/memory/graph/capability-seed.ts +24 -10
  418. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +123 -49
  419. package/src/plugins/defaults/memory/graph/graph-search.ts +6 -118
  420. package/src/plugins/defaults/memory/graph/in-context-tracker.test.ts +173 -0
  421. package/src/plugins/defaults/memory/graph/in-context-tracker.ts +109 -0
  422. package/src/plugins/defaults/memory/graph/store.ts +1 -0
  423. package/src/plugins/defaults/memory/graph/tool-handlers.test.ts +1 -1
  424. package/src/plugins/defaults/memory/graph/tool-handlers.ts +5 -2
  425. package/src/plugins/defaults/memory/graph-topology/__tests__/build-memory-graph.test.ts +1 -1
  426. package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +6 -9
  427. package/src/plugins/defaults/memory/hooks/__tests__/user-prompt-submit.test.ts +30 -16
  428. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +18 -14
  429. package/src/plugins/defaults/memory/indexer.ts +146 -89
  430. package/src/plugins/defaults/memory/injectors.ts +86 -41
  431. package/src/plugins/defaults/memory/job-handlers.ts +130 -39
  432. package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +2 -2
  433. package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +22 -10
  434. package/src/plugins/defaults/memory/jobs-worker.ts +279 -208
  435. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +4 -2
  436. package/src/plugins/defaults/memory/memory-retrospective-job.ts +40 -3
  437. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +99 -11
  438. package/src/plugins/defaults/memory/src/__tests__/memory-v2-routes.test.ts +5 -3
  439. package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +3 -4
  440. package/src/plugins/defaults/memory/src/memory-graph-routes.ts +2 -1
  441. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +7 -5
  442. package/src/plugins/defaults/memory/src/memory-item-routes.ts +51 -19
  443. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +31 -20
  444. package/src/plugins/defaults/memory/startup.ts +58 -21
  445. package/src/plugins/defaults/memory/substrate/__tests__/boot-maintenance.test.ts +335 -0
  446. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/cli-command-store.test.ts +14 -8
  447. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-job.test.ts +51 -21
  448. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/edge-index.test.ts +1 -1
  449. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/frontmatter-sweep.test.ts +3 -3
  450. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-index.test.ts +1 -1
  451. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-store.test.ts +1 -1
  452. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/prompts-consolidation.test.ts +2 -2
  453. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/qdrant.test.ts +23 -14
  454. package/src/plugins/defaults/memory/substrate/__tests__/reembed-job.test.ts +262 -0
  455. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sim.test.ts +9 -12
  456. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-content.test.ts +2 -2
  457. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-store.test.ts +9 -9
  458. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sparse-bm25.test.ts +12 -5
  459. package/src/plugins/defaults/memory/substrate/__tests__/spread.test.ts +276 -0
  460. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/static-context.test.ts +17 -8
  461. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sweep-job.test.ts +9 -9
  462. package/src/plugins/defaults/memory/{v3/substrate/memory-v2-startup.ts → substrate/boot-maintenance.ts} +43 -24
  463. package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-store.ts +13 -8
  464. package/src/plugins/defaults/memory/{v3/substrate → substrate}/consolidation-job.ts +51 -27
  465. package/src/plugins/defaults/memory/{v3/substrate → substrate}/constants.ts +1 -0
  466. package/src/plugins/defaults/memory/{v3/substrate → substrate}/edge-index.ts +28 -9
  467. package/src/plugins/defaults/memory/{v3/substrate → substrate}/frontmatter-sweep.ts +14 -7
  468. package/src/plugins/defaults/memory/{v3/substrate → substrate}/injected-block-slugs.ts +9 -3
  469. package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-index.ts +29 -10
  470. package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-store.ts +35 -12
  471. package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/consolidation.ts +14 -8
  472. package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/sweep.ts +4 -1
  473. package/src/plugins/defaults/memory/{v3/substrate → substrate}/qdrant.ts +96 -36
  474. package/src/plugins/defaults/memory/substrate/reembed-job.ts +54 -0
  475. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sim.ts +26 -15
  476. package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-content.ts +1 -1
  477. package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-store.ts +13 -8
  478. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sparse-bm25.ts +27 -10
  479. package/src/plugins/defaults/memory/substrate/spread.ts +165 -0
  480. package/src/plugins/defaults/memory/{v3/substrate → substrate}/static-context.ts +12 -7
  481. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sweep-job.ts +20 -15
  482. package/src/plugins/defaults/memory/substrate/tuning.ts +93 -0
  483. package/src/plugins/defaults/memory/{v3/substrate → substrate}/types.ts +7 -4
  484. package/src/plugins/defaults/memory/tools.test.ts +1 -1
  485. package/src/plugins/defaults/memory/tools.ts +1 -1
  486. package/src/plugins/defaults/memory/v1/README.md +5 -0
  487. package/src/plugins/defaults/memory/{__tests__ → v1/__tests__}/filing-jobs.test.ts +4 -4
  488. package/src/plugins/defaults/memory/{filing-jobs.ts → v1/filing-jobs.ts} +3 -3
  489. package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.test.ts +68 -6
  490. package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.ts +40 -21
  491. package/src/plugins/defaults/memory/{graph → v1/graph}/consolidation.ts +14 -14
  492. package/src/plugins/defaults/memory/{graph → v1/graph}/decay.test.ts +1 -1
  493. package/src/plugins/defaults/memory/{graph → v1/graph}/decay.ts +3 -3
  494. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction-job.ts +5 -5
  495. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.test.ts +1 -1
  496. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.ts +20 -14
  497. package/src/plugins/defaults/memory/{graph → v1/graph}/graph-search.test.ts +3 -3
  498. package/src/plugins/defaults/memory/v1/graph/graph-search.ts +123 -0
  499. package/src/plugins/defaults/memory/{graph → v1/graph}/injection.test.ts +1 -118
  500. package/src/plugins/defaults/memory/{graph → v1/graph}/injection.ts +9 -111
  501. package/src/plugins/defaults/memory/{graph → v1/graph}/narrative.ts +6 -6
  502. package/src/plugins/defaults/memory/{graph → v1/graph}/pattern-scan.ts +5 -5
  503. package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.test.ts +135 -42
  504. package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.ts +40 -22
  505. package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.test.ts +1 -1
  506. package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.ts +1 -1
  507. package/src/plugins/defaults/memory/{graph → v1/graph}/serendipity.ts +1 -1
  508. package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.test.ts +1 -1
  509. package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.ts +1 -1
  510. package/src/plugins/defaults/memory/{identity-context.ts → v1/identity-context.ts} +4 -4
  511. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/backfill.ts +6 -6
  512. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.test.ts +6 -6
  513. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.ts +6 -6
  514. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/index-maintenance.ts +8 -8
  515. package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.test.ts +7 -7
  516. package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.ts +5 -5
  517. package/src/plugins/defaults/memory/{pkb → v1/pkb}/autoinject.ts +1 -1
  518. package/src/plugins/defaults/memory/{pkb → v1/pkb}/context.ts +2 -2
  519. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.test.ts +3 -3
  520. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.ts +2 -2
  521. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.test.ts +3 -3
  522. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.ts +2 -2
  523. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.test.ts +3 -3
  524. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.ts +6 -6
  525. package/src/plugins/defaults/memory/{pkb → v1/pkb}/types.ts +3 -5
  526. package/src/plugins/defaults/memory/{pkb-schedule.ts → v1/pkb-schedule.ts} +2 -2
  527. package/src/plugins/defaults/memory/{search/semantic.ts → v1/semantic-search.ts} +1 -1
  528. package/src/plugins/defaults/memory/v2/__tests__/activation-store.test.ts +1 -1
  529. package/src/plugins/defaults/memory/v2/__tests__/activation.test.ts +11 -274
  530. package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +9 -131
  531. package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +1 -1
  532. package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +1 -1
  533. package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
  534. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +14 -10
  535. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +7 -5
  536. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +12 -6
  537. package/src/plugins/defaults/memory/{memory-v2-activation-log-store.ts → v2/activation-log-store.ts} +2 -2
  538. package/src/plugins/defaults/memory/v2/activation-store.ts +22 -8
  539. package/src/plugins/defaults/memory/v2/activation.ts +30 -163
  540. package/src/plugins/defaults/memory/v2/backfill-jobs.ts +7 -54
  541. package/src/plugins/defaults/memory/{memory-v2-concept-frequency.ts → v2/concept-frequency.ts} +3 -3
  542. package/src/plugins/defaults/memory/v2/harness/oracle.ts +1 -1
  543. package/src/plugins/defaults/memory/v2/harness/replay-input.ts +2 -2
  544. package/src/plugins/defaults/memory/v2/harness/retriever.ts +1 -1
  545. package/src/plugins/defaults/memory/v2/injection.ts +36 -26
  546. package/src/plugins/defaults/memory/v2/migration.ts +2 -2
  547. package/src/plugins/defaults/memory/{rerank-local.ts → v2/rerank-local.ts} +44 -18
  548. package/src/plugins/defaults/memory/v2/reranker.ts +29 -11
  549. package/src/plugins/defaults/memory/v2/router.ts +38 -15
  550. package/src/plugins/defaults/memory/v3/__tests__/candidate-match.test.ts +5 -3
  551. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +21 -8
  552. package/src/plugins/defaults/memory/v3/__tests__/edge.test.ts +1 -1
  553. package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +1 -1
  554. package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +4 -1
  555. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +181 -3
  556. package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +3 -0
  557. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +14 -5
  558. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +40 -50
  559. package/src/plugins/defaults/memory/v3/__tests__/tuning-profile.test.ts +1 -0
  560. package/src/plugins/defaults/memory/v3/candidate-match.ts +2 -2
  561. package/src/plugins/defaults/memory/v3/capabilities.ts +6 -4
  562. package/src/plugins/defaults/memory/v3/card.ts +25 -9
  563. package/src/plugins/defaults/memory/v3/edge.ts +52 -18
  564. package/src/plugins/defaults/memory/v3/gate.ts +4 -4
  565. package/src/plugins/defaults/memory/v3/injector.ts +10 -3
  566. package/src/plugins/defaults/memory/v3/maintain-job.ts +3 -3
  567. package/src/plugins/defaults/memory/v3/orchestrate.ts +100 -18
  568. package/src/plugins/defaults/memory/v3/page-content.ts +26 -10
  569. package/src/plugins/defaults/memory/v3/prune.ts +40 -16
  570. package/src/plugins/defaults/memory/v3/selection-log-store.ts +34 -12
  571. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +9 -13
  572. package/src/plugins/defaults/memory/v3/span-query.test.ts +86 -0
  573. package/src/plugins/defaults/memory/v3/span-query.ts +71 -0
  574. package/src/plugins/defaults/memory/v3/tuning-profile.ts +3 -0
  575. package/src/plugins/defaults/memory/v3/types.ts +4 -1
  576. package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +2 -2
  577. package/src/plugins/defaults/memory/validation.ts +1 -1
  578. package/src/plugins/defaults/memory/worker.ts +2 -1
  579. package/src/plugins/defaults/platform-hosted/__tests__/reengage.test.ts +104 -12
  580. package/src/plugins/defaults/platform-hosted/routes/reengage.ts +104 -12
  581. package/src/plugins/types.ts +2 -2
  582. package/src/providers/__tests__/registry-native-web-search.test.ts +47 -2
  583. package/src/providers/anthropic/client.ts +15 -6
  584. package/src/providers/content-block-schema.ts +26 -0
  585. package/src/providers/inference/__tests__/connections-credential-normalize.test.ts +87 -0
  586. package/src/providers/inference/adapter-factory.ts +6 -0
  587. package/src/providers/inference/connections.ts +30 -14
  588. package/src/providers/model-catalog.ts +77 -0
  589. package/src/providers/openai/__tests__/chat-completions-input-audio.test.ts +260 -0
  590. package/src/providers/openai/chat-completions-provider.ts +65 -17
  591. package/src/providers/openai/input-audio.ts +76 -0
  592. package/src/providers/openrouter/client.ts +0 -2
  593. package/src/providers/platform-proxy/constants.ts +4 -0
  594. package/src/providers/poolside/client.ts +42 -0
  595. package/src/providers/registry.ts +40 -8
  596. package/src/providers/retry.ts +2 -0
  597. package/src/providers/types.ts +39 -1
  598. package/src/providers/vercel-ai-gateway/client.ts +0 -2
  599. package/src/runtime/AGENTS.md +7 -5
  600. package/src/runtime/__tests__/question-request-guardian-bridge.test.ts +173 -0
  601. package/src/runtime/__tests__/question-resolution.test.ts +111 -0
  602. package/src/runtime/access-request-helper.ts +7 -15
  603. package/src/runtime/assistant-event-hub.ts +43 -31
  604. package/src/runtime/assistant-event-publish-options.ts +31 -0
  605. package/src/runtime/assistant-event.ts +19 -30
  606. package/src/runtime/assistant-stream-state.ts +4 -4
  607. package/src/runtime/channel-approvals.ts +0 -25
  608. package/src/runtime/channel-readiness-service.ts +99 -40
  609. package/src/runtime/channel-retry-sweep.ts +38 -15
  610. package/src/runtime/confirmation-request-guardian-bridge.ts +4 -0
  611. package/src/runtime/guardian-reply-router.ts +108 -0
  612. package/src/runtime/http-server.ts +8 -0
  613. package/src/runtime/http-types.ts +2 -2
  614. package/src/runtime/process-role.ts +42 -0
  615. package/src/runtime/question-request-guardian-bridge.ts +184 -0
  616. package/src/runtime/question-resolution.ts +153 -0
  617. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +6 -2
  618. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -1
  619. package/src/runtime/routes/acp-routes.ts +2 -2
  620. package/src/runtime/routes/bookmark-routes.ts +3 -15
  621. package/src/runtime/routes/canned-message-complete.ts +2 -2
  622. package/src/runtime/routes/consolidation-routes.ts +8 -2
  623. package/src/runtime/routes/conversation-list-routes.ts +3 -19
  624. package/src/runtime/routes/conversation-management-routes.ts +1 -5
  625. package/src/runtime/routes/conversation-query-routes.ts +52 -8
  626. package/src/runtime/routes/conversation-routes.ts +36 -22
  627. package/src/runtime/routes/credential-request-routes.ts +0 -1
  628. package/src/runtime/routes/filing-routes.ts +7 -7
  629. package/src/runtime/routes/global-search-routes.ts +1 -1
  630. package/src/runtime/routes/guardian-approval-prompt.ts +2 -2
  631. package/src/runtime/routes/image-generation-routes.ts +12 -9
  632. package/src/runtime/routes/inbound-message-handler.ts +17 -0
  633. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +50 -0
  634. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +19 -0
  635. package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -4
  636. package/src/runtime/routes/inbound-stages/inbound-content-prep.test.ts +129 -0
  637. package/src/runtime/routes/inbound-stages/inbound-content-prep.ts +141 -9
  638. package/src/runtime/routes/index.ts +2 -0
  639. package/src/runtime/routes/lifecycle-routes.ts +199 -0
  640. package/src/runtime/routes/platform-routes.ts +3 -8
  641. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +7 -7
  642. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +5 -5
  643. package/src/runtime/routes/question-routes.ts +34 -87
  644. package/src/runtime/routes/secret-routes.ts +11 -1
  645. package/src/runtime/routes/settings-routes.ts +8 -18
  646. package/src/runtime/routes/upgrade-broadcast-routes.ts +4 -5
  647. package/src/runtime/routes/workspace-routes.test.ts +7 -4
  648. package/src/runtime/slack-reply-session.test.ts +12 -12
  649. package/src/runtime/slack-reply-session.ts +17 -17
  650. package/src/runtime/sync/sync-publisher.test.ts +7 -5
  651. package/src/runtime/tool-grant-request-helper.ts +4 -0
  652. package/src/schedule/schedule-store.ts +70 -0
  653. package/src/schedule/scheduler.ts +27 -0
  654. package/src/security/AGENTS.md +1 -1
  655. package/src/security/credential-key.ts +17 -0
  656. package/src/security/secret-ingress.ts +14 -105
  657. package/src/security/secret-patterns.ts +8 -139
  658. package/src/security/secret-scanner.ts +8 -3
  659. package/src/security/store-path-override.ts +6 -16
  660. package/src/sequence/store.ts +8 -0
  661. package/src/signals/emit-event.ts +5 -10
  662. package/src/signals/event-stream.ts +20 -10
  663. package/src/subagent/manager.ts +76 -25
  664. package/src/subagent/notify.ts +8 -0
  665. package/src/subagent/types.ts +13 -3
  666. package/src/telegram/__tests__/webhook-health.test.ts +442 -0
  667. package/src/telegram/webhook-health.ts +478 -0
  668. package/src/telemetry/AGENTS.md +6 -0
  669. package/src/telemetry/memory-corpus-size.test.ts +129 -0
  670. package/src/telemetry/memory-corpus-size.ts +184 -0
  671. package/src/telemetry/memory-tier-reporter.test.ts +67 -2
  672. package/src/telemetry/memory-tier-reporter.ts +30 -3
  673. package/src/tools/__tests__/document-tool-input-schemas.test.ts +103 -0
  674. package/src/tools/__tests__/followup-call-acp-tool-input-schemas.test.ts +125 -0
  675. package/src/tools/__tests__/schedule-tool-input-schemas.test.ts +83 -0
  676. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +116 -0
  677. package/src/tools/__tests__/tool-input-schemas.test.ts +192 -0
  678. package/src/tools/__tests__/tool-schema-drift-harness.ts +142 -0
  679. package/src/tools/acp/abort.ts +21 -1
  680. package/src/tools/acp/context.ts +5 -5
  681. package/src/tools/acp/spawn.test.ts +15 -5
  682. package/src/tools/acp/spawn.ts +26 -3
  683. package/src/tools/acp/status.ts +20 -1
  684. package/src/tools/acp/steer.test.ts +20 -0
  685. package/src/tools/acp/steer.ts +23 -2
  686. package/src/tools/ask-question/ask-question-tool.test.ts +65 -0
  687. package/src/tools/ask-question/ask-question-tool.ts +68 -92
  688. package/src/tools/browser/browser-screencast.ts +6 -6
  689. package/src/tools/calls/call-end.ts +24 -3
  690. package/src/tools/calls/call-start.ts +35 -11
  691. package/src/tools/calls/call-status.ts +20 -1
  692. package/src/tools/document/document-comment-tool.test.ts +49 -0
  693. package/src/tools/document/document-comment-tool.ts +45 -6
  694. package/src/tools/document/document-tool.ts +142 -24
  695. package/src/tools/executor.ts +27 -13
  696. package/src/tools/filesystem/edit.ts +62 -60
  697. package/src/tools/filesystem/list.ts +36 -29
  698. package/src/tools/filesystem/read.ts +56 -39
  699. package/src/tools/filesystem/write.ts +44 -38
  700. package/src/tools/followups/followup_create.ts +41 -12
  701. package/src/tools/followups/followup_list.ts +34 -6
  702. package/src/tools/followups/followup_resolve.ts +26 -4
  703. package/src/tools/host-filesystem/edit.ts +50 -60
  704. package/src/tools/host-filesystem/read.ts +45 -39
  705. package/src/tools/host-filesystem/write.ts +31 -36
  706. package/src/tools/host-terminal/host-shell.ts +76 -62
  707. package/src/tools/policy-context.ts +27 -10
  708. package/src/tools/schedule/create.ts +76 -33
  709. package/src/tools/schedule/delete.ts +21 -2
  710. package/src/tools/schedule/list.ts +25 -3
  711. package/src/tools/schedule/update.ts +105 -48
  712. package/src/tools/shared/filesystem/path-policy.ts +246 -40
  713. package/src/tools/shared/zod-tool-schema.ts +117 -0
  714. package/src/tools/subagent/abort.ts +12 -4
  715. package/src/tools/subagent/consult-deadline.ts +9 -3
  716. package/src/tools/subagent/message.ts +21 -5
  717. package/src/tools/subagent/notify-parent.ts +44 -23
  718. package/src/tools/subagent/read.ts +15 -4
  719. package/src/tools/subagent/resolve.ts +26 -4
  720. package/src/tools/subagent/spawn.ts +37 -13
  721. package/src/tools/subagent/status.ts +12 -4
  722. package/src/tools/system/request-permission.ts +35 -26
  723. package/src/tools/terminal/shell.ts +68 -55
  724. package/src/tools/tool-approval-handler.ts +327 -53
  725. package/src/tools/tool-input-schemas.ts +85 -0
  726. package/src/tools/tool-types.ts +7 -0
  727. package/src/tools/types.ts +8 -0
  728. package/src/tools/workflows/manage-workflows.ts +30 -2
  729. package/src/tools/workflows/run-workflow.test.ts +54 -2
  730. package/src/tools/workflows/run-workflow.ts +32 -4
  731. package/src/util/fs-symlinks.ts +30 -0
  732. package/src/util/log-redact.ts +7 -3
  733. package/src/vellum-assistant-namespace.d.ts +80 -0
  734. package/src/watcher/watcher-store.ts +8 -0
  735. package/src/workflows/leaf-runner.test.ts +104 -2
  736. package/src/workflows/leaf-runner.ts +31 -6
  737. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +2 -2
  738. package/src/workspace/migrations/134-image-generation-mode-to-provider.ts +128 -0
  739. package/src/workspace/migrations/135-copy-substrate-tunables.ts +248 -0
  740. package/src/workspace/migrations/__tests__/135-copy-substrate-tunables.test.ts +446 -0
  741. package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +2 -2
  742. package/src/workspace/migrations/registry.ts +4 -0
  743. package/src/__tests__/memory-retrieval-budget.test.ts +0 -49
  744. package/src/__tests__/secret-patterns.test.ts +0 -27
  745. package/src/config/__tests__/proc-to-skills.test.ts +0 -21
  746. package/src/config/memory-tier.test.ts +0 -44
  747. package/src/daemon/message-types/acp.ts +0 -20
  748. package/src/daemon/message-types/apps.ts +0 -11
  749. package/src/daemon/message-types/background-tools.ts +0 -14
  750. package/src/daemon/message-types/bookmarks.ts +0 -13
  751. package/src/daemon/message-types/contacts.ts +0 -13
  752. package/src/daemon/message-types/document-comments.ts +0 -14
  753. package/src/daemon/message-types/documents.ts +0 -13
  754. package/src/daemon/message-types/home.ts +0 -15
  755. package/src/daemon/message-types/host-bash.ts +0 -12
  756. package/src/daemon/message-types/host-cu.ts +0 -10
  757. package/src/daemon/message-types/host-file.ts +0 -12
  758. package/src/daemon/message-types/host-transfer.ts +0 -12
  759. package/src/daemon/message-types/integrations.ts +0 -90
  760. package/src/daemon/message-types/memory.ts +0 -10
  761. package/src/daemon/message-types/schedules.ts +0 -14
  762. package/src/daemon/message-types/settings.ts +0 -17
  763. package/src/daemon/message-types/subagents.ts +0 -63
  764. package/src/daemon/message-types/upgrades.ts +0 -14
  765. package/src/daemon/message-types/workflows.ts +0 -25
  766. package/src/daemon/message-types/workspace.ts +0 -137
  767. package/src/live-voice/ack-phrases.ts +0 -58
  768. package/src/plugins/defaults/memory/retrieval-budget.ts +0 -29
  769. package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +0 -69
  770. package/src/plugins/defaults/memory/v3/gate-flag.ts +0 -20
  771. package/src/plugins/defaults/memory/v3/substrate/__tests__/memory-v2-startup.test.ts +0 -86
  772. package/src/plugins/defaults/memory/v3/substrate/memory-v2-startup.test.ts +0 -205
  773. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/concept-page-frontmatter-schema.test.ts +0 -0
  774. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-prompt-flag-gating-guard.test.ts +0 -0
  775. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/injected-block-slugs.test.ts +0 -0
  776. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-content.ts +0 -0
@@ -75,9 +75,19 @@ const GuardianQuestionPayloadBaseSchema = z.object({
75
75
  export const PendingQuestionPayloadSchema =
76
76
  GuardianQuestionPayloadBaseSchema.extend({
77
77
  requestKind: z.literal("pending_question"),
78
- callSessionId: z.string().min(1),
79
- activeGuardianRequestCount: z.number(),
78
+ /** Present only for voice-call questions; absent for ask_question prompts. */
79
+ callSessionId: z.string().min(1).optional(),
80
+ activeGuardianRequestCount: z.number().optional(),
80
81
  toolName: z.string().optional(),
82
+ /**
83
+ * Structured answer options for an ask_question prompt (2–4 entries).
84
+ * When present, the broadcaster renders them as tappable option actions
85
+ * (see {@link buildQuestionOptionActionId}); absent payloads render as
86
+ * plain text with request-code reply instructions.
87
+ */
88
+ options: z
89
+ .array(z.object({ id: z.string().min(1), label: z.string().min(1) }))
90
+ .optional(),
81
91
  });
82
92
 
83
93
  /**
@@ -221,6 +231,51 @@ export function buildToolApprovalSourceView(
221
231
  };
222
232
  }
223
233
 
234
+ // ── Answer-option action tokens ─────────────────────────────────────────
235
+
236
+ /**
237
+ * Action-id scheme for answer-mode option buttons on a `pending_question`
238
+ * card. The broadcaster builds card actions with these ids (so every channel
239
+ * adapter renders them without knowing they're question options), the reply
240
+ * router recognizes a tapped id as an answer selection rather than an
241
+ * approval action, and the question resolver maps the index back to the
242
+ * pending interaction's option. Index-based (not the raw option id) so the
243
+ * channel callback stays small and the LLM-supplied option id never rides
244
+ * the wire.
245
+ */
246
+ export const QUESTION_SKIP_ACTION_ID = "answer_skip";
247
+
248
+ /** Action id for the option at `index` on a question card. */
249
+ export function buildQuestionOptionActionId(index: number): string {
250
+ return `answer_${index}`;
251
+ }
252
+
253
+ export type QuestionAnswerSelection =
254
+ | { kind: "option"; index: number }
255
+ | { kind: "skip" };
256
+
257
+ /**
258
+ * Parse an action token from a question card. Returns `null` for anything
259
+ * that is not an answer-option token (including ordinary approval actions),
260
+ * so callers can fall through to approval handling.
261
+ */
262
+ export function parseQuestionAnswerActionId(
263
+ token: string,
264
+ ): QuestionAnswerSelection | null {
265
+ if (token === QUESTION_SKIP_ACTION_ID) {
266
+ return { kind: "skip" };
267
+ }
268
+ const match = /^answer_(\d+)$/.exec(token);
269
+ if (!match) {
270
+ return null;
271
+ }
272
+ const index = Number(match[1]);
273
+ if (!Number.isInteger(index) || index < 0) {
274
+ return null;
275
+ }
276
+ return { kind: "option", index };
277
+ }
278
+
224
279
  interface GuardianRequestModeInput {
225
280
  kind: unknown;
226
281
  toolName?: unknown;
@@ -159,6 +159,7 @@ const EVENT_CATEGORY_MAP: Record<string, FeedItemCategory> = {
159
159
  "guardian.question": "security",
160
160
  "guardian.channel_activation": "security",
161
161
  "ingress.access_request": "security",
162
+ "telegram.webhook_health_alert": "system",
162
163
  };
163
164
 
164
165
  function deriveCategory(signal: NotificationSignal): FeedItemCategory {
@@ -269,6 +270,9 @@ const NOTEWORTHY_EVENT_NAMES: ReadonlySet<string> = new Set([
269
270
  "guardian.channel_activation",
270
271
  "ingress.access_request",
271
272
  "credential.health_alert",
273
+ // A dark messaging channel is inbox-worthy: the guardian may be waiting on
274
+ // replies that are silently queueing at Telegram.
275
+ "telegram.webhook_health_alert",
272
276
  ]);
273
277
 
274
278
  function deriveNoteworthy(signal: NotificationSignal): boolean {
@@ -25,6 +25,7 @@ export const NOTIFICATION_SOURCE_CHANNELS = [
25
25
  { id: "email", description: "Email channel" },
26
26
  { id: "platform", description: "Platform-managed channel" },
27
27
  { id: "a2a", description: "Agent-to-agent protocol channel" },
28
+ { id: "discord", description: "Discord channel" },
28
29
  { id: "scheduler", description: "Scheduled task runner (reminders, cron)" },
29
30
  { id: "watcher", description: "File/event watcher subsystem" },
30
31
  ] as const;
@@ -82,10 +83,6 @@ export const NOTIFICATION_SOURCE_EVENT_NAMES = [
82
83
  id: "ingress.trusted_contact.guardian_decision",
83
84
  description: "Guardian decided on trusted contact request",
84
85
  },
85
- {
86
- id: "ingress.trusted_contact.denied",
87
- description: "Trusted contact request denied",
88
- },
89
86
  {
90
87
  id: "ingress.trusted_contact.verification_sent",
91
88
  description: "Verification sent to trusted contact",
@@ -125,6 +122,11 @@ export const NOTIFICATION_SOURCE_EVENT_NAMES = [
125
122
  description:
126
123
  "OAuth credential health issue detected (expired, revoked, missing scopes)",
127
124
  },
125
+ {
126
+ id: "telegram.webhook_health_alert",
127
+ description:
128
+ "Telegram webhook is not delivering (unregistered, or failing per getWebhookInfo)",
129
+ },
128
130
  ] as const;
129
131
 
130
132
  export type NotificationSourceEventName =
@@ -31,10 +31,9 @@ const TrustedContactIdentitySchema = z.object({
31
31
  });
32
32
 
33
33
  /**
34
- * Payload for `ingress.trusted_contact.guardian_decision` and
35
- * `ingress.trusted_contact.denied` — the guardian's verdict on an access
36
- * request. The deny path emits both events from one object; the approve path
37
- * emits `guardian_decision` with `decision: "approved"` (identical shape).
34
+ * Payload for `ingress.trusted_contact.guardian_decision` — the guardian's
35
+ * verdict on an access request. `decision` distinguishes the deny path from
36
+ * an approve (identical shape).
38
37
  */
39
38
  export const TrustedContactDecisionPayloadSchema =
40
39
  TrustedContactIdentitySchema.extend({
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Shared vellum-card conversation pin for guardian-request producers.
3
+ *
4
+ * Guardian cards (access requests, tool grants, tool approvals, questions)
5
+ * that know their originating conversation pass this affinity fragment to
6
+ * `emitNotificationSignal` so the in-app (vellum) card lands inside that
7
+ * conversation instead of one the decision engine picks. The metadata mirrors
8
+ * the target's `source` because `pairDeliveryWithConversation` reuses a
9
+ * conversation only when its source matches the signal's (inbound
10
+ * conversations default to "user"); a stale/missing target falls back to a
11
+ * fresh conversation via the same pairing path.
12
+ */
13
+
14
+ import { getConversation } from "../persistence/conversation-crud.js";
15
+
16
+ export interface VellumCardAffinity {
17
+ conversationAffinityHint: { vellum: string };
18
+ conversationMetadata: { source: string };
19
+ }
20
+
21
+ /**
22
+ * Build the emit-signal affinity fragment pinning the vellum card to
23
+ * `destinationConversationId`, or `undefined` when the producer has no
24
+ * originating conversation (callers spread the result:
25
+ * `...(buildVellumCardAffinity(id) ?? {})`).
26
+ */
27
+ export function buildVellumCardAffinity(
28
+ destinationConversationId: string | undefined,
29
+ ): VellumCardAffinity | undefined {
30
+ if (!destinationConversationId) {
31
+ return undefined;
32
+ }
33
+ return {
34
+ conversationAffinityHint: { vellum: destinationConversationId },
35
+ conversationMetadata: {
36
+ source: getConversation(destinationConversationId)?.source ?? "user",
37
+ },
38
+ };
39
+ }
@@ -39,7 +39,7 @@ The `logoUrl` field in `seed-providers.ts` is the source of truth for a provider
39
39
 
40
40
  For brands Simple Icons doesn't host (e.g. Salesforce, which Simple Icons removed for trademark reasons), use the `glincker/thesvg` source via jsDelivr — `https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/<key>/default.svg`. The recognised `logoUrl` prefixes are enforced by `oauth-provider-seed-logos.test.ts`; if you need a third source, extend that allowlist.
41
41
 
42
- ### 5. Secret patterns (if applicable) — `../security/secret-patterns.ts`
42
+ ### 5. Secret patterns (if applicable) — `packages/service-contracts/src/secret-detection.ts`
43
43
 
44
44
  If the provider issues API keys with a recognizable prefix (e.g. `acme_sk_`), add a `PREFIX_PATTERNS` entry. OAuth-only services with opaque access tokens do not need one. See `../security/AGENTS.md` for details.
45
45
 
@@ -0,0 +1,69 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import {
4
+ collapseChannelThresholdForContact,
5
+ effectiveChannelCellThreshold,
6
+ } from "./channel-permission-query.js";
7
+
8
+ describe("collapseChannelThresholdForContact", () => {
9
+ test.each([
10
+ ["none", "none"],
11
+ ["low", "low"],
12
+ ["medium", "low"],
13
+ ["high", "low"],
14
+ ] as const)("%s collapses to %s", (input, expected) => {
15
+ expect(collapseChannelThresholdForContact(input)).toBe(expected);
16
+ });
17
+ });
18
+
19
+ describe("effectiveChannelCellThreshold", () => {
20
+ const resolved = (threshold: "none" | "low" | "medium" | "high") => ({
21
+ ok: true as const,
22
+ resolved: { threshold },
23
+ });
24
+ const noCell = { ok: true as const, resolved: null };
25
+ const failed = { ok: false as const };
26
+
27
+ test("a transport failure authorizes nothing, for every contact type", () => {
28
+ for (const contactType of [
29
+ "guardian",
30
+ "trusted_contact",
31
+ "unverified_contact",
32
+ "unknown",
33
+ ] as const) {
34
+ expect(
35
+ effectiveChannelCellThreshold(failed, contactType, "low"),
36
+ ).toBeUndefined();
37
+ }
38
+ });
39
+
40
+ test("a contact's resolved cell is collapsed", () => {
41
+ expect(
42
+ effectiveChannelCellThreshold(resolved("high"), "trusted_contact", "low"),
43
+ ).toBe("low");
44
+ expect(
45
+ effectiveChannelCellThreshold(resolved("none"), "trusted_contact", "low"),
46
+ ).toBe("none");
47
+ });
48
+
49
+ test("a contact with no cell gets the caller-derived room default", () => {
50
+ expect(
51
+ effectiveChannelCellThreshold(noCell, "trusted_contact", "low"),
52
+ ).toBe("low");
53
+ expect(
54
+ effectiveChannelCellThreshold(noCell, "trusted_contact", "none"),
55
+ ).toBe("none");
56
+ expect(
57
+ effectiveChannelCellThreshold(noCell, "trusted_contact", undefined),
58
+ ).toBeUndefined();
59
+ });
60
+
61
+ test("guardian queries pass through raw and ignore the room default", () => {
62
+ expect(
63
+ effectiveChannelCellThreshold(resolved("high"), "guardian", "low"),
64
+ ).toBe("high");
65
+ expect(
66
+ effectiveChannelCellThreshold(noCell, "guardian", "low"),
67
+ ).toBeUndefined();
68
+ });
69
+ });
@@ -13,10 +13,25 @@ import {
13
13
  isChannelConversationType,
14
14
  isTrustClass,
15
15
  type ResolveChannelPermissionRequest,
16
+ type ResolvedChannelPermission,
17
+ type RiskThreshold,
16
18
  } from "@vellumai/gateway-client";
17
19
 
18
20
  import type { PolicyContext } from "./types.js";
19
21
 
22
+ /**
23
+ * The fields a cell query is derived from — a subset of {@link PolicyContext}
24
+ * so a caller holding only a turn's channel coordinates (the sensitive-tool
25
+ * gate, which runs before a policy context exists) can build the same query.
26
+ */
27
+ export type ChannelPermissionCoordinates = Pick<
28
+ PolicyContext,
29
+ | "sourceChannel"
30
+ | "trustClass"
31
+ | "channelConversationType"
32
+ | "channelExternalId"
33
+ >;
34
+
20
35
  /**
21
36
  * Build the permission-matrix cell query for a permission decision: the
22
37
  * channel coordinates of the turn plus the actor's contact-type. Returns
@@ -26,7 +41,7 @@ import type { PolicyContext } from "./types.js";
26
41
  * from the conversation override / global defaults as before.
27
42
  */
28
43
  export function buildChannelPermissionCellQuery(
29
- policyContext?: PolicyContext,
44
+ policyContext?: ChannelPermissionCoordinates,
30
45
  ): ResolveChannelPermissionRequest | undefined {
31
46
  const adapter = policyContext?.sourceChannel;
32
47
  const trustClass = policyContext?.trustClass;
@@ -44,3 +59,60 @@ export function buildChannelPermissionCellQuery(
44
59
  contactType: trustClass,
45
60
  };
46
61
  }
62
+
63
+ /**
64
+ * Collapse a threshold to the two levels a channel distinguishes for
65
+ * non-guardian contact types: `none` is itself, everything else is `low`.
66
+ * Applied to stored cells and to the global default a cell-less room
67
+ * inherits alike; the picker applies the same collapse for display (web
68
+ * `channelTierBehavesAs`), so a room can never behave wider than the level
69
+ * displayed for it.
70
+ */
71
+ export function collapseChannelThresholdForContact(
72
+ threshold: RiskThreshold,
73
+ ): RiskThreshold {
74
+ return threshold === "none" ? "none" : "low";
75
+ }
76
+
77
+ /**
78
+ * The threshold a cell resolution actually authorizes for a contact type.
79
+ * The single rule every cell consumer applies — the sensitive-tool gate,
80
+ * the threshold cascade, and the pre-prompt refresh — kept in this leaf
81
+ * module so tests that stub the IPC lookup still exercise it.
82
+ *
83
+ * For non-guardian contact types, a resolved cell authorizes its collapsed
84
+ * threshold ({@link collapseChannelThresholdForContact}), and a successful
85
+ * walk with no cell at any level authorizes `noCellDefault` — the room
86
+ * default the caller derives from the owner's global setting, already
87
+ * collapsed. Callers that cannot derive one pass `undefined`, which keeps
88
+ * the caller's fail-safe path in charge.
89
+ *
90
+ * Guardian queries pass through untouched — a resolved cell keeps its raw
91
+ * threshold and no-cell returns `undefined` (fall through to the global
92
+ * thresholds): the channel setting governs other people in the room, never
93
+ * the guardian's own lane.
94
+ *
95
+ * A transport failure (`ok: false`) is `undefined`: an unreachable gateway
96
+ * must never widen what a channel actor may do.
97
+ */
98
+ export function effectiveChannelCellThreshold(
99
+ cell:
100
+ | {
101
+ ok: true;
102
+ resolved: Pick<ResolvedChannelPermission, "threshold"> | null;
103
+ }
104
+ | { ok: false },
105
+ contactType: ResolveChannelPermissionRequest["contactType"],
106
+ noCellDefault: RiskThreshold | undefined,
107
+ ): RiskThreshold | undefined {
108
+ if (!cell.ok) {
109
+ return undefined;
110
+ }
111
+ if (contactType === "guardian") {
112
+ return cell.resolved?.threshold;
113
+ }
114
+ if (!cell.resolved) {
115
+ return noCellDefault;
116
+ }
117
+ return collapseChannelThresholdForContact(cell.resolved.threshold);
118
+ }
@@ -15,12 +15,14 @@ mock.module("../config/assistant-feature-flags.js", () => ({
15
15
  }));
16
16
 
17
17
  // `buildPolicyContext` (used by the integration tests below) precomputes the
18
- // proc-to-skills gate via `isProcToSkillsActive`. Drive it through this slot so
19
- // a test can put the production threading path in the active / inactive state.
20
- let mockProcToSkillsActive = true;
18
+ // proc-to-skills gate via `isV3TierActive`. Drive it through this slot so a
19
+ // test can put the production threading path in the active / inactive state.
20
+ let mockV3TierActive = true;
21
21
  mock.module("../config/memory-v3-gate.js", () => ({
22
- isProcToSkillsActive: () => mockProcToSkillsActive,
23
- isMemoryV3Live: () => mockProcToSkillsActive,
22
+ isMemoryEnabled: (config?: { memory?: { enabled?: boolean } }) =>
23
+ config?.memory?.enabled !== false,
24
+ isV3TierActive: () => mockV3TierActive,
25
+ isMemoryV3Live: () => mockV3TierActive,
24
26
  usesConceptPageMemory: (memory?: {
25
27
  enabled?: boolean;
26
28
  v2?: { enabled?: boolean };
@@ -115,10 +117,14 @@ mock.module("./trust-store.js", () => ({
115
117
  onRulesChanged: () => {},
116
118
  }));
117
119
 
118
- // Mock workspace policy.
120
+ // Mock workspace policy. Spread the real module so pure path helpers
121
+ // (resolveSandboxBase) keep their real behavior for param building.
122
+ const realWorkspacePolicy = await import("./workspace-policy.js");
119
123
  let mockIsPathWithinWorkspaceRoot = true;
120
124
  mock.module("./workspace-policy.js", () => ({
125
+ ...realWorkspacePolicy,
121
126
  isWorkspaceScopedInvocation: () => false,
127
+ isOutOfWorkspaceFileInvocation: () => false,
122
128
  isPathWithinWorkspaceRoot: () => mockIsPathWithinWorkspaceRoot,
123
129
  }));
124
130
 
@@ -143,9 +149,13 @@ mock.module("../tools/network/url-safety.js", () => ({
143
149
  import type { ClassificationResult } from "./ipc-risk-types.js";
144
150
 
145
151
  let mockIpcClassifyRiskResult: ClassificationResult | undefined;
152
+ let lastClassifyRiskParams: Record<string, unknown> | undefined;
146
153
 
147
154
  mock.module("../ipc/gateway-client.js", () => ({
148
- ipcClassifyRisk: async () => mockIpcClassifyRiskResult,
155
+ ipcClassifyRisk: async (params: Record<string, unknown>) => {
156
+ lastClassifyRiskParams = params;
157
+ return mockIpcClassifyRiskResult;
158
+ },
149
159
  ipcCall: async () => undefined,
150
160
  ipcCallPersistent: async () => undefined,
151
161
  resetPersistentClient: () => {},
@@ -155,6 +165,7 @@ mock.module("../ipc/gateway-client.js", () => ({
155
165
 
156
166
  import {
157
167
  mkdtempSync,
168
+ realpathSync,
158
169
  rmSync,
159
170
  symlinkSync,
160
171
  unlinkSync,
@@ -180,9 +191,10 @@ describe("Permission Checker (gateway IPC)", () => {
180
191
  beforeEach(() => {
181
192
  mockIsContainerized = false;
182
193
  mockIpcClassifyRiskResult = undefined;
194
+ lastClassifyRiskParams = undefined;
183
195
  mockCachedThreshold = "low";
184
196
  mockRefreshedThreshold = null;
185
- mockProcToSkillsActive = true;
197
+ mockV3TierActive = true;
186
198
  thresholdCallLog.length = 0;
187
199
  });
188
200
 
@@ -246,6 +258,70 @@ describe("Permission Checker (gateway IPC)", () => {
246
258
  );
247
259
  });
248
260
 
261
+ test("sends canonicalized boundary params for sandbox file tools", async () => {
262
+ mockIpcClassifyRiskResult = {
263
+ risk: "medium",
264
+ reason: "File write outside the workspace",
265
+ matchType: "registry",
266
+ scopeOptions: [],
267
+ };
268
+ const workingDir = mkdtempSync(join(tmpdir(), "checker-boundary-"));
269
+ try {
270
+ await classifyRisk(
271
+ "file_write",
272
+ { path: "/tmp/checker-boundary-outside.txt" },
273
+ workingDir,
274
+ );
275
+ expect(lastClassifyRiskParams?.isContainerized).toBe(false);
276
+ // The boundary is canonicalized so the gateway compares canonical
277
+ // against canonical (macOS tmpdir lives behind a /var symlink).
278
+ expect(lastClassifyRiskParams?.resolvedWorkingDir).toBe(
279
+ realpathSync(workingDir),
280
+ );
281
+ } finally {
282
+ rmSync(workingDir, { recursive: true, force: true });
283
+ }
284
+ });
285
+
286
+ test("classifies a dangling symlink by its destination", async () => {
287
+ mockIpcClassifyRiskResult = {
288
+ risk: "medium",
289
+ reason: "File write outside the workspace",
290
+ matchType: "registry",
291
+ scopeOptions: [],
292
+ };
293
+ const workingDir = realpathSync(
294
+ mkdtempSync(join(tmpdir(), "checker-dangling-")),
295
+ );
296
+ const outside = realpathSync(
297
+ mkdtempSync(join(tmpdir(), "checker-dangling-out-")),
298
+ );
299
+ try {
300
+ const destination = join(outside, "not-yet.txt");
301
+ symlinkSync(destination, join(workingDir, "dangle"));
302
+ await classifyRisk("file_write", { path: "dangle" }, workingDir);
303
+ // The destination does not exist, but a write through the link
304
+ // creates it — classification must see the destination.
305
+ expect(lastClassifyRiskParams?.resolvedPath).toBe(destination);
306
+ } finally {
307
+ rmSync(workingDir, { recursive: true, force: true });
308
+ rmSync(outside, { recursive: true, force: true });
309
+ }
310
+ });
311
+
312
+ test("omits the canonicalized boundary for host file tools", async () => {
313
+ mockIpcClassifyRiskResult = {
314
+ risk: "medium",
315
+ reason: "Host file write (default)",
316
+ matchType: "registry",
317
+ scopeOptions: [],
318
+ };
319
+ await classifyRisk("host_file_write", {
320
+ path: "/tmp/checker-boundary-host.txt",
321
+ });
322
+ expect(lastClassifyRiskParams?.resolvedWorkingDir).toBeUndefined();
323
+ });
324
+
249
325
  test("caches results for identical inputs", async () => {
250
326
  mockIpcClassifyRiskResult = {
251
327
  risk: "low",
@@ -1085,7 +1161,7 @@ describe("Permission Checker (gateway IPC)", () => {
1085
1161
  // Same retrospective ToolContext, but the feature is inactive (flag off
1086
1162
  // or v3 not live). buildPolicyContext stamps `procToSkillsActive: false`,
1087
1163
  // so the grant is dead and the high-risk scaffold prompts.
1088
- mockProcToSkillsActive = false;
1164
+ mockV3TierActive = false;
1089
1165
  mockIpcClassifyRiskResult = {
1090
1166
  risk: "high",
1091
1167
  reason: "Skill scaffold",
@@ -53,6 +53,7 @@ import {
53
53
  import {
54
54
  isPathWithinWorkspaceRoot,
55
55
  isWorkspaceScopedInvocation,
56
+ resolveSandboxBase,
56
57
  } from "./workspace-policy.js";
57
58
 
58
59
  // ── Risk classification cache ────────────────────────────────────────────────
@@ -155,7 +156,7 @@ function fileToolFsStateKey(
155
156
  return undefined;
156
157
  }
157
158
  const resolved = resolveFileToolPaths(toolName, input, workingDir);
158
- return `${resolved.resolvedPath ?? ""}\0${resolved.resolvedTransferDestPath ?? ""}`;
159
+ return `${resolved.resolvedPath ?? ""}\0${resolved.resolvedTransferDestPath ?? ""}\0${resolved.resolvedWorkingDir ?? ""}`;
159
160
  }
160
161
 
161
162
  /** Clear the risk classification cache. Called when trust rules change. Exported for test setup. */
@@ -210,7 +211,7 @@ function resolveSkillIdAndHash(
210
211
  * registry (`getToolOwner(name)`) rather than read from the `Tool` object,
211
212
  * since ownership lives on the registry, not on the tool itself.
212
213
  */
213
- function isToolOwnerSkillBundled(tool: Tool | undefined): boolean {
214
+ export function isToolOwnerSkillBundled(tool: Tool | undefined): boolean {
214
215
  if (!tool) {
215
216
  return false;
216
217
  }
@@ -389,25 +390,6 @@ function buildFileContext(): FileContext {
389
390
  * filesystem this process cannot see (e.g. host_file paths proxied to a remote
390
391
  * client), so this never regresses below today's lexical behavior.
391
392
  */
392
- // The Docker sandbox mounts the workspace at /workspace, and the model emits
393
- // container-scoped paths (e.g. "/workspace/tools/evil.ts") even on local turns.
394
- // Mirror the gateway's resolveSandboxPath remap so the symlink-resolved path we
395
- // forward lines up with the gateway's lexical fallback and the protected dirs.
396
- const CONTAINER_WORKSPACE_PREFIX = "/workspace/";
397
- const CONTAINER_WORKSPACE_EXACT = "/workspace";
398
-
399
- function resolveSandboxBase(rawPath: string, workingDir: string): string {
400
- let effectivePath = rawPath;
401
- if (!rawPath.startsWith(workingDir + "/") && rawPath !== workingDir) {
402
- if (rawPath.startsWith(CONTAINER_WORKSPACE_PREFIX)) {
403
- effectivePath = rawPath.slice(CONTAINER_WORKSPACE_PREFIX.length);
404
- } else if (rawPath === CONTAINER_WORKSPACE_EXACT) {
405
- effectivePath = ".";
406
- }
407
- }
408
- return resolve(workingDir, effectivePath);
409
- }
410
-
411
393
  function resolveClassificationPath(
412
394
  filePath: string,
413
395
  workingDir: string,
@@ -441,6 +423,13 @@ interface FileToolResolution {
441
423
  effectiveWorkingDir: string;
442
424
  isHostTool: boolean;
443
425
  resolvedPath?: string;
426
+ /**
427
+ * Symlink-canonicalized working dir for sandbox file tools, paired with
428
+ * `resolvedPath` so the gateway's workspace-boundary check compares
429
+ * canonical against canonical (a symlinked workspace prefix, e.g. macOS
430
+ * /var → /private/var, must not read as an escape). Unset for host tools.
431
+ */
432
+ resolvedWorkingDir?: string;
444
433
  transferSandboxDestPath?: string;
445
434
  transferSandboxWorkingDir?: string;
446
435
  resolvedTransferDestPath?: string;
@@ -490,6 +479,9 @@ function resolveFileToolPaths(
490
479
  effectiveWorkingDir,
491
480
  isHostTool,
492
481
  ),
482
+ resolvedWorkingDir: isHostTool
483
+ ? undefined
484
+ : resolveRealPath(effectiveWorkingDir),
493
485
  transferSandboxDestPath,
494
486
  transferSandboxWorkingDir,
495
487
  // The to_sandbox destination is a workspace write — symlink-resolve it too
@@ -573,7 +565,9 @@ function buildClassifyRiskParams(
573
565
  tool: toolName,
574
566
  path: resolved.filePath,
575
567
  resolvedPath: resolved.resolvedPath,
568
+ resolvedWorkingDir: resolved.resolvedWorkingDir,
576
569
  workingDir: resolved.effectiveWorkingDir,
570
+ isContainerized: getIsContainerized(),
577
571
  fileContext: buildFileContext(),
578
572
  transferSandboxDestPath: resolved.transferSandboxDestPath,
579
573
  transferSandboxWorkingDir: resolved.transferSandboxWorkingDir,
@@ -797,7 +791,8 @@ export async function classifyRisk(
797
791
  // prompt. The grant resolves these tools to ALLOW non-interactively, and ONLY
798
792
  // when all of these hold:
799
793
  // - procedural-memory-as-skills is active (`policyContext.procToSkillsActive`,
800
- // precomputed by buildPolicyContext: memory-v3 is live),
794
+ // precomputed by buildPolicyContext: the v3 tier is active — memory is on
795
+ // and memory-v3 is live),
801
796
  // - the turn is the retrospective background source — guardian trust, `vellum`
802
797
  // source channel, `memory_retrospective` origin (set in
803
798
  // memory-retrospective-job.ts).
@@ -50,7 +50,7 @@ mock.module("../runtime/confirmation-request-guardian-bridge.js", () => ({
50
50
  },
51
51
  }));
52
52
 
53
- import type { ServerMessage } from "../daemon/message-protocol.js";
53
+ import type { AssistantEvent } from "../api/index.js";
54
54
  import { createGuardianRequestForConfirmation } from "./confirmation-guardian-request.js";
55
55
 
56
56
  const MSG = {
@@ -59,7 +59,7 @@ const MSG = {
59
59
  toolName: "Bash",
60
60
  input: { command: "ls" },
61
61
  riskLevel: "medium",
62
- } as unknown as ServerMessage & { type: "confirmation_request" };
62
+ } as unknown as AssistantEvent & { type: "confirmation_request" };
63
63
 
64
64
  describe("createGuardianRequestForConfirmation", () => {
65
65
  beforeEach(() => {
@@ -17,7 +17,7 @@
17
17
  * therefore the emitters — stays cheap and free of import-time side effects.
18
18
  */
19
19
 
20
- import type { ServerMessage } from "../daemon/message-protocol.js";
20
+ import type { ConfirmationRequestEvent } from "../api/index.js";
21
21
  import { IntegrityError } from "../util/errors.js";
22
22
  import { getLogger } from "../util/logger.js";
23
23
 
@@ -30,7 +30,7 @@ const log = getLogger("confirmation-guardian-request");
30
30
  * never thrown.
31
31
  */
32
32
  export async function createGuardianRequestForConfirmation(
33
- msg: ServerMessage & { type: "confirmation_request" },
33
+ msg: ConfirmationRequestEvent,
34
34
  conversationId: string,
35
35
  opts?: {
36
36
  /**