@vellumai/assistant 0.10.12 → 0.11.0-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 (809) 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 +264 -14
  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__/app-conversation-ids-backfill.test.ts +33 -2
  39. package/src/__tests__/app-conversation-ids.test.ts +204 -0
  40. package/src/__tests__/approval-cascade.test.ts +5 -5
  41. package/src/__tests__/approval-routes-http.test.ts +3 -3
  42. package/src/__tests__/ask-question-resolver.test.ts +207 -0
  43. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +16 -16
  44. package/src/__tests__/assistant-event-hub-targeted.test.ts +13 -11
  45. package/src/__tests__/assistant-event-hub.test.ts +13 -11
  46. package/src/__tests__/assistant-event.test.ts +12 -9
  47. package/src/__tests__/assistant-feature-flag-guard.test.ts +3 -3
  48. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +1 -1
  49. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -58
  50. package/src/__tests__/assistant-stream-state.test.ts +17 -7
  51. package/src/__tests__/avatar-identity-sync.test.ts +3 -3
  52. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
  53. package/src/__tests__/call-conversation-messages.test.ts +134 -18
  54. package/src/__tests__/call-start-guardian-guard.test.ts +27 -0
  55. package/src/__tests__/channel-approvals.test.ts +0 -27
  56. package/src/__tests__/channel-guardian.test.ts +85 -512
  57. package/src/__tests__/channel-readiness-slack-remote.test.ts +151 -3
  58. package/src/__tests__/channel-retry-sweep.test.ts +88 -1
  59. package/src/__tests__/channel-setup-panel-ack.test.ts +12 -9
  60. package/src/__tests__/chat-reveal-guard-priming.test.ts +31 -34
  61. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +2 -2
  62. package/src/__tests__/compaction-events.test.ts +8 -8
  63. package/src/__tests__/config-loader-platform-defaults.test.ts +54 -28
  64. package/src/__tests__/config-model-image-provider.test.ts +20 -0
  65. package/src/__tests__/config-schema-memory-substrate.test.ts +306 -0
  66. package/src/__tests__/config-schema.test.ts +14 -2
  67. package/src/__tests__/config-set-platform-guard.test.ts +11 -12
  68. package/src/__tests__/config-sounds-sync.test.ts +4 -4
  69. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +5 -0
  70. package/src/__tests__/context-search-memory-source.test.ts +1 -1
  71. package/src/__tests__/context-search-memory-v2-source.test.ts +6 -6
  72. package/src/__tests__/context-token-estimator.test.ts +54 -1
  73. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +12 -3
  74. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +13 -4
  75. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +4 -4
  76. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -1
  77. package/src/__tests__/conversation-agent-loop-overflow.test.ts +22 -13
  78. package/src/__tests__/conversation-agent-loop.test.ts +39 -30
  79. package/src/__tests__/conversation-confirmation-signals.test.ts +14 -14
  80. package/src/__tests__/conversation-evictor.test.ts +49 -0
  81. package/src/__tests__/conversation-fork-crud.test.ts +1 -1
  82. package/src/__tests__/conversation-group-tools.test.ts +279 -0
  83. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  84. package/src/__tests__/conversation-key-store-disk-view.test.ts +5 -5
  85. package/src/__tests__/conversation-lineage.test.ts +235 -0
  86. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +5 -5
  87. package/src/__tests__/conversation-message-sync-tags.test.ts +4 -4
  88. package/src/__tests__/conversation-queue.test.ts +81 -81
  89. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +8 -1
  90. package/src/__tests__/conversation-routes-hidden-queue.test.ts +8 -1
  91. package/src/__tests__/conversation-routes-slash-commands.test.ts +10 -1
  92. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -2
  93. package/src/__tests__/conversation-slash-queue.test.ts +11 -11
  94. package/src/__tests__/conversation-slash-unknown.test.ts +2 -2
  95. package/src/__tests__/conversation-speed-override.test.ts +2 -2
  96. package/src/__tests__/conversation-summarize-route.test.ts +9 -0
  97. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +18 -16
  98. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +17 -17
  99. package/src/__tests__/conversation-surfaces-app-open.test.ts +7 -4
  100. package/src/__tests__/conversation-surfaces-data-persist.test.ts +7 -7
  101. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +9 -9
  102. package/src/__tests__/conversation-surfaces-standalone.test.ts +12 -12
  103. package/src/__tests__/conversation-surfaces-state-update.test.ts +8 -5
  104. package/src/__tests__/conversation-surfaces-table-action.test.ts +6 -3
  105. package/src/__tests__/conversation-surfaces-task-progress.test.ts +46 -46
  106. package/src/__tests__/conversation-sync-tags.test.ts +5 -5
  107. package/src/__tests__/conversation-wait-for-idle.test.ts +2 -2
  108. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
  109. package/src/__tests__/conversation-workspace-injection.test.ts +0 -3
  110. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -3
  111. package/src/__tests__/copy-composer-tc-templates.test.ts +3 -131
  112. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  113. package/src/__tests__/daemon-assistant-events.test.ts +14 -15
  114. package/src/__tests__/db-test-helpers.ts +13 -27
  115. package/src/__tests__/disk-pressure-routes.test.ts +12 -3
  116. package/src/__tests__/document-tool-security.test.ts +95 -0
  117. package/src/__tests__/drain-kick-guard.test.ts +232 -0
  118. package/src/__tests__/dynamic-skill-background-guard.test.ts +19 -6
  119. package/src/__tests__/emit-event-signal.test.ts +5 -6
  120. package/src/__tests__/encrypted-store-test-helpers.ts +10 -20
  121. package/src/__tests__/events-tail-route.test.ts +6 -4
  122. package/src/__tests__/feature-flag-test-helpers.ts +10 -20
  123. package/src/__tests__/file-edit-tool.test.ts +24 -4
  124. package/src/__tests__/file-list-tool.test.ts +2 -1
  125. package/src/__tests__/file-read-tool.test.ts +62 -10
  126. package/src/__tests__/file-write-tool.test.ts +24 -5
  127. package/src/__tests__/followup-tools.test.ts +58 -0
  128. package/src/__tests__/gateway-threshold-reader-mock.ts +99 -0
  129. package/src/__tests__/graph-extraction-event-date.test.ts +1 -1
  130. package/src/__tests__/guardian-question-mode.test.ts +42 -3
  131. package/src/__tests__/guardian-reply-router-answer-mode.test.ts +283 -0
  132. package/src/__tests__/guardian-vellum-destination-pinning.test.ts +221 -0
  133. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  134. package/src/__tests__/heartbeat-service.test.ts +1 -0
  135. package/src/__tests__/helpers/native-web-search-harness.ts +10 -10
  136. package/src/__tests__/host-browser-proxy.test.ts +1 -1
  137. package/src/__tests__/host-file-edit-tool.test.ts +3 -3
  138. package/src/__tests__/host-file-read-tool.test.ts +2 -2
  139. package/src/__tests__/host-file-write-tool.test.ts +7 -3
  140. package/src/__tests__/host-shell-tool.test.ts +17 -5
  141. package/src/__tests__/host-transfer-pending-interactions.test.ts +8 -8
  142. package/src/__tests__/image-credentials.test.ts +65 -8
  143. package/src/__tests__/injection-block.test.ts +4 -4
  144. package/src/__tests__/injector-chain.test.ts +1 -1
  145. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  146. package/src/__tests__/injector-registry-order-guard.test.ts +4 -9
  147. package/src/__tests__/injector-v3-suppression.test.ts +6 -4
  148. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +27 -28
  149. package/src/__tests__/list-messages-page-latest.test.ts +2 -2
  150. package/src/__tests__/llm-usage-store.test.ts +67 -4
  151. package/src/__tests__/log-redact.test.ts +18 -0
  152. package/src/__tests__/managed-profile-guard.test.ts +27 -0
  153. package/src/__tests__/managed-skill-lifecycle.test.ts +2 -2
  154. package/src/__tests__/media-generate-image.test.ts +62 -11
  155. package/src/__tests__/memory-identity-context-parity.test.ts +1 -1
  156. package/src/__tests__/memory-jobs-worker-lanes.test.ts +9 -1
  157. package/src/__tests__/memory-retrieval-hook.test.ts +4 -4
  158. package/src/__tests__/notification-decision-strategy.test.ts +115 -11
  159. package/src/__tests__/notification-deep-link.test.ts +12 -12
  160. package/src/__tests__/notification-vellum-adapter.test.ts +8 -8
  161. package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
  162. package/src/__tests__/path-policy.test.ts +315 -0
  163. package/src/__tests__/pending-interactions-resolved-event.test.ts +6 -6
  164. package/src/__tests__/persistence-layering-guard.test.ts +2 -2
  165. package/src/__tests__/pkb-autoinject.test.ts +1 -1
  166. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -0
  167. package/src/__tests__/platform-callback-registration.test.ts +10 -10
  168. package/src/__tests__/plugin-event-hub-facade.test.ts +22 -15
  169. package/src/__tests__/plugin-import-boundary-guard.test.ts +15 -15
  170. package/src/__tests__/processing-flag-persist-failure.test.ts +0 -4
  171. package/src/__tests__/provider-platform-proxy-integration.test.ts +0 -1
  172. package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
  173. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +5 -5
  174. package/src/__tests__/require-fresh-approval.test.ts +38 -38
  175. package/src/__tests__/resolve-app-id.test.ts +32 -0
  176. package/src/__tests__/run-due-schedules.test.ts +72 -1
  177. package/src/__tests__/runtime-events-sse-parity.test.ts +11 -10
  178. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  179. package/src/__tests__/schedule-routes.test.ts +44 -5
  180. package/src/__tests__/schedule-store.test.ts +3 -3
  181. package/src/__tests__/schedule-tools.test.ts +176 -0
  182. package/src/__tests__/secret-prompt-log-hygiene.test.ts +3 -3
  183. package/src/__tests__/secret-prompter-channel-fallback.test.ts +3 -3
  184. package/src/__tests__/secret-response-routing.test.ts +3 -3
  185. package/src/__tests__/secret-routes-platform-proxy.test.ts +4 -7
  186. package/src/__tests__/secret-scanner.test.ts +36 -0
  187. package/src/__tests__/send-endpoint-busy.test.ts +7 -7
  188. package/src/__tests__/slack-required-scopes-mirror.test.ts +81 -0
  189. package/src/__tests__/starter-task-flow.test.ts +26 -3
  190. package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
  191. package/src/__tests__/subagent-disposal.test.ts +40 -11
  192. package/src/__tests__/subagent-fork-notifications.test.ts +4 -4
  193. package/src/__tests__/subagent-fork-prompt-role.test.ts +3 -3
  194. package/src/__tests__/subagent-fork-spawn.test.ts +4 -4
  195. package/src/__tests__/subagent-manager-notify.test.ts +73 -14
  196. package/src/__tests__/subagent-notify-parent.test.ts +48 -4
  197. package/src/__tests__/subagent-spawn-and-await.test.ts +62 -14
  198. package/src/__tests__/subagent-tools.test.ts +64 -0
  199. package/src/__tests__/sync-message-contract.test.ts +3 -3
  200. package/src/__tests__/terminal-tools.test.ts +12 -3
  201. package/src/__tests__/test-preload.ts +9 -0
  202. package/src/__tests__/tool-approval-handler.test.ts +587 -43
  203. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +7 -4
  204. package/src/__tests__/tool-executor.test.ts +116 -0
  205. package/src/__tests__/tool-grant-request-escalation.test.ts +5 -0
  206. package/src/__tests__/tool-preview-lifecycle.test.ts +32 -29
  207. package/src/__tests__/tool-result-metadata-plumbing.test.ts +5 -5
  208. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  209. package/src/__tests__/tool-start-timestamp.test.ts +4 -4
  210. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -22
  211. package/src/__tests__/ui-choice-copy-surfaces.test.ts +13 -13
  212. package/src/__tests__/ui-work-result-surface.test.ts +3 -3
  213. package/src/__tests__/voice-scoped-grant-consumer.test.ts +6 -6
  214. package/src/__tests__/voice-session-bridge.test.ts +44 -44
  215. package/src/__tests__/workspace-migration-134-image-generation-mode-to-provider.test.ts +284 -0
  216. package/src/__tests__/workspace-policy.test.ts +482 -2
  217. package/src/acp/__tests__/client-handler.test.ts +3 -3
  218. package/src/acp/__tests__/session-manager-persistence.test.ts +10 -10
  219. package/src/acp/__tests__/session-manager-resume.test.ts +7 -7
  220. package/src/acp/client-handler.ts +3 -3
  221. package/src/acp/session-manager.ts +8 -8
  222. package/src/api/events/subagent-event.ts +2 -2
  223. package/src/api/responses/memory-v2-activation-log.ts +2 -2
  224. package/src/api/responses/subagent-detail.ts +13 -0
  225. package/src/approvals/AGENTS.md +2 -0
  226. package/src/approvals/guardian-request-resolvers.ts +118 -24
  227. package/src/apps/app-store.ts +95 -4
  228. package/src/calls/__tests__/voice-control-protocol.test.ts +57 -0
  229. package/src/calls/__tests__/voice-session-bridge.test.ts +229 -7
  230. package/src/calls/__tests__/voice-triage-escalate.test.ts +3 -4
  231. package/src/calls/call-controller.ts +27 -27
  232. package/src/calls/call-conversation-messages.ts +58 -18
  233. package/src/calls/voice-control-protocol.ts +56 -0
  234. package/src/calls/voice-session-bridge.ts +178 -65
  235. package/src/calls/voice-triage-escalate.ts +2 -3
  236. package/src/channels/config.ts +8 -0
  237. package/src/channels/types.ts +1 -0
  238. package/src/cli/commands/config.ts +49 -13
  239. package/src/cli/commands/memory/index.help.ts +4 -2
  240. package/src/cli/commands/memory/memory-retrospective.ts +5 -0
  241. package/src/cli/commands/webhooks.help.ts +9 -4
  242. package/src/cli/lib/bundled-marketplace.json +12 -0
  243. package/src/cli.ts +2 -109
  244. package/src/config/__tests__/deployment-context-defaults.test.ts +9 -0
  245. package/src/config/__tests__/substrate-twin-shadowing.test.ts +191 -0
  246. package/src/config/assistant-feature-flags.ts +1 -1
  247. package/src/config/bundled-skills/conversation-groups/SKILL.md +29 -0
  248. package/src/config/bundled-skills/conversation-groups/TOOLS.json +58 -0
  249. package/src/config/bundled-skills/conversation-groups/tools/group-create.ts +12 -0
  250. package/src/config/bundled-skills/conversation-groups/tools/group-list.ts +12 -0
  251. package/src/config/bundled-skills/conversation-groups/tools/move-to-group.ts +12 -0
  252. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +13 -7
  253. package/src/config/bundled-skills/schedule/SKILL.md +2 -0
  254. package/src/config/feature-flag-cache.ts +6 -16
  255. package/src/config/feature-flag-registry.json +14 -38
  256. package/src/config/loader.ts +7 -1
  257. package/src/config/memory-tier.ts +15 -10
  258. package/src/config/memory-v3-gate.test.ts +278 -1
  259. package/src/config/memory-v3-gate.ts +88 -26
  260. package/src/config/raw-config-utils.ts +1 -1
  261. package/src/config/schemas/__tests__/live-voice.test.ts +27 -16
  262. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  263. package/src/config/schemas/live-voice.ts +33 -7
  264. package/src/config/schemas/llm.ts +1 -0
  265. package/src/config/schemas/memory-retrospective.ts +13 -0
  266. package/src/config/schemas/memory-substrate.ts +183 -0
  267. package/src/config/schemas/memory-v2.ts +3 -2
  268. package/src/config/schemas/memory-v3.ts +11 -4
  269. package/src/config/schemas/memory.ts +35 -1
  270. package/src/config/schemas/services.ts +10 -2
  271. package/src/config/substrate-twin-shadowing.ts +195 -0
  272. package/src/config/webhook-routing.ts +67 -0
  273. package/src/context/compactor.ts +10 -3
  274. package/src/context/token-estimator.ts +21 -0
  275. package/src/daemon/__tests__/channel-ui-capability.test.ts +85 -0
  276. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +3 -3
  277. package/src/daemon/__tests__/embedding-reconcile.test.ts +3 -3
  278. package/src/daemon/__tests__/inference-profile-notification.test.ts +3 -6
  279. package/src/daemon/__tests__/native-web-search-metadata.test.ts +5 -5
  280. package/src/daemon/__tests__/web-search-status-text.test.ts +2 -2
  281. package/src/daemon/channel-ui-capability.ts +70 -1
  282. package/src/daemon/conversation-agent-loop-handlers.ts +4 -4
  283. package/src/daemon/conversation-agent-loop.ts +12 -5
  284. package/src/daemon/conversation-evictor.ts +26 -4
  285. package/src/daemon/conversation-launch.ts +11 -14
  286. package/src/daemon/conversation-lineage.ts +76 -0
  287. package/src/daemon/conversation-messaging.ts +14 -14
  288. package/src/daemon/conversation-notifiers.ts +2 -2
  289. package/src/daemon/conversation-process.ts +133 -21
  290. package/src/daemon/conversation-queue-manager.ts +7 -7
  291. package/src/daemon/conversation-runtime-assembly.ts +16 -0
  292. package/src/daemon/conversation-store.ts +11 -3
  293. package/src/daemon/conversation-surfaces.ts +8 -14
  294. package/src/daemon/conversation-tool-setup.ts +13 -7
  295. package/src/daemon/conversation-usage.ts +12 -11
  296. package/src/daemon/conversation.ts +38 -15
  297. package/src/daemon/disk-pressure-guard.ts +5 -12
  298. package/src/daemon/embedding-reconcile.ts +14 -9
  299. package/src/daemon/handlers/config-channels.ts +40 -134
  300. package/src/daemon/handlers/config-model.ts +15 -7
  301. package/src/daemon/handlers/conversations.ts +4 -2
  302. package/src/daemon/handlers/shared.ts +29 -0
  303. package/src/daemon/host-proxy-base.ts +4 -4
  304. package/src/daemon/lifecycle.ts +13 -0
  305. package/src/daemon/message-protocol.ts +8 -144
  306. package/src/daemon/message-types/computer-use.ts +0 -12
  307. package/src/daemon/message-types/conversations.ts +9 -345
  308. package/src/daemon/message-types/host-app-control.ts +0 -9
  309. package/src/daemon/message-types/host-browser.ts +0 -7
  310. package/src/daemon/message-types/host-ui-snapshot.ts +0 -7
  311. package/src/daemon/message-types/messages.ts +0 -48
  312. package/src/daemon/message-types/notifications.ts +0 -7
  313. package/src/daemon/message-types/skills.ts +0 -5
  314. package/src/daemon/message-types/surfaces.ts +0 -9
  315. package/src/daemon/message-types/sync.ts +0 -2
  316. package/src/daemon/process-message.ts +5 -5
  317. package/src/daemon/skill-memory-refresh.ts +5 -5
  318. package/src/daemon/tool-side-effects.ts +32 -16
  319. package/src/daemon/trust-context.ts +1 -1
  320. package/src/daemon/wake-conversation-ops.ts +4 -4
  321. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +100 -7
  322. package/src/heartbeat/__tests__/heartbeat-service.test.ts +67 -0
  323. package/src/heartbeat/heartbeat-run-store.ts +81 -4
  324. package/src/heartbeat/heartbeat-service.ts +32 -1
  325. package/src/home/__tests__/feed-writer.test.ts +7 -7
  326. package/src/home/__tests__/home-content-refresh.test.ts +3 -0
  327. package/src/home/__tests__/suggested-prompts.test.ts +1 -0
  328. package/src/home/feed-writer.ts +6 -13
  329. package/src/home/home-content-refresh.ts +6 -9
  330. package/src/home/relationship-state-writer.ts +5 -12
  331. package/src/home/suggested-prompts-cache.ts +6 -19
  332. package/src/ipc/__tests__/events-publish-client.test.ts +67 -0
  333. package/src/ipc/events-publish-client.ts +44 -0
  334. package/src/ipc/routes/__tests__/conversation-sync-ipc-routes.test.ts +2 -2
  335. package/src/ipc/routes/__tests__/events-ipc-routes.test.ts +38 -9
  336. package/src/ipc/routes/events-ipc-routes.ts +11 -31
  337. package/src/live-voice/__tests__/front-decision.test.ts +4 -176
  338. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +276 -68
  339. package/src/live-voice/__tests__/live-voice-continuation-fork-hydration.test.ts +286 -0
  340. package/src/live-voice/__tests__/live-voice-events.test.ts +6 -3
  341. package/src/live-voice/__tests__/live-voice-progress.test.ts +185 -46
  342. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +24 -59
  343. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +38 -54
  344. package/src/live-voice/__tests__/live-voice-vad.test.ts +1154 -636
  345. package/src/live-voice/front-decision.ts +5 -155
  346. package/src/live-voice/live-voice-metrics.ts +4 -1
  347. package/src/live-voice/live-voice-session.ts +1288 -439
  348. package/src/live-voice/progress-phrases.ts +17 -0
  349. package/src/live-voice/protocol.ts +15 -0
  350. package/src/media/app-icon-generator.ts +15 -8
  351. package/src/media/avatar-router.ts +9 -5
  352. package/src/media/image-credentials.ts +42 -10
  353. package/src/media/image-service.ts +1 -13
  354. package/src/media/types.ts +26 -3
  355. package/src/notifications/AGENTS.md +2 -0
  356. package/src/notifications/__tests__/broadcaster.test.ts +95 -0
  357. package/src/notifications/adapters/macos.ts +3 -3
  358. package/src/notifications/broadcaster.ts +57 -0
  359. package/src/notifications/copy-composer.ts +0 -15
  360. package/src/notifications/decision-engine.ts +21 -22
  361. package/src/notifications/guardian-question-mode.ts +57 -2
  362. package/src/notifications/home-feed-side-effect.ts +4 -0
  363. package/src/notifications/signal.ts +6 -4
  364. package/src/notifications/trusted-contact-payloads.ts +3 -4
  365. package/src/notifications/vellum-card-affinity.ts +39 -0
  366. package/src/oauth/AGENTS.md +1 -1
  367. package/src/permissions/channel-permission-query.test.ts +69 -0
  368. package/src/permissions/channel-permission-query.ts +73 -1
  369. package/src/permissions/checker.test.ts +298 -15
  370. package/src/permissions/checker.ts +102 -36
  371. package/src/permissions/confirmation-guardian-request.test.ts +2 -2
  372. package/src/permissions/confirmation-guardian-request.ts +2 -2
  373. package/src/permissions/gateway-threshold-reader.test.ts +224 -17
  374. package/src/permissions/gateway-threshold-reader.ts +82 -10
  375. package/src/permissions/ipc-risk-types.ts +8 -0
  376. package/src/permissions/prompter.ts +5 -5
  377. package/src/permissions/question-guardian-request.test.ts +222 -0
  378. package/src/permissions/question-guardian-request.ts +179 -0
  379. package/src/permissions/question-prompter.test.ts +8 -8
  380. package/src/permissions/question-prompter.ts +18 -0
  381. package/src/permissions/secret-prompter.ts +2 -4
  382. package/src/permissions/workspace-policy.ts +269 -34
  383. package/src/persistence/__tests__/lifecycle-quiesce.test.ts +82 -0
  384. package/src/persistence/__tests__/message-content-file.test.ts +58 -3
  385. package/src/persistence/conversation-crud.ts +93 -0
  386. package/src/persistence/conversation-key-store.ts +63 -0
  387. package/src/persistence/conversation-parent.ts +27 -0
  388. package/src/persistence/db-async-query.ts +1 -1
  389. package/src/persistence/db-singleton.ts +14 -27
  390. package/src/persistence/delivery-crud.ts +45 -0
  391. package/src/persistence/embeddings/embedding-backend.ts +2 -1
  392. package/src/persistence/embeddings/embedding-identity.ts +7 -3
  393. package/src/persistence/job-utils.ts +32 -27
  394. package/src/persistence/jobs-store.ts +92 -3
  395. package/src/persistence/lifecycle-quiesce.ts +80 -0
  396. package/src/persistence/llm-usage-store.ts +45 -8
  397. package/src/persistence/message-content-file.ts +4 -4
  398. package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +1 -1
  399. package/src/persistence/migrations/351-schedule-skill-script-handoff.ts +39 -0
  400. package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.test.ts +83 -0
  401. package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.ts +36 -0
  402. package/src/persistence/migrations/353-add-llm-usage-conversation-type.test.ts +110 -0
  403. package/src/persistence/migrations/353-add-llm-usage-conversation-type.ts +49 -0
  404. package/src/persistence/migrations/354-backfill-app-conversation-lineage.ts +41 -0
  405. package/src/persistence/schema/infrastructure.ts +11 -0
  406. package/src/persistence/steps.ts +9 -1
  407. package/src/plugin-api/__tests__/publish-event-forwarding.test.ts +113 -0
  408. package/src/plugin-api/__tests__/publish-event.test.ts +57 -0
  409. package/src/plugin-api/conversation-turn.ts +4 -4
  410. package/src/plugin-api/event-hub-facade.ts +15 -6
  411. package/src/plugin-api/index.ts +10 -4
  412. package/src/plugin-api/publish-event.ts +36 -0
  413. package/src/plugins/AGENTS.md +2 -0
  414. package/src/plugins/defaults/compaction/window-manager.ts +9 -0
  415. package/src/plugins/defaults/index.ts +9 -13
  416. package/src/plugins/defaults/memory/AGENTS.md +775 -0
  417. package/src/plugins/defaults/memory/__tests__/capability-seed-embed-gate.test.ts +186 -0
  418. package/src/plugins/defaults/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +1 -1
  419. package/src/plugins/defaults/memory/__tests__/indexer-tier-dispatch.test.ts +129 -0
  420. package/src/plugins/defaults/memory/__tests__/jobs-worker-quiesce-gate.test.ts +91 -0
  421. package/src/plugins/defaults/memory/__tests__/jobs-worker-v1-graph-substrate-noop.test.ts +342 -0
  422. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +9 -1
  423. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +36 -1
  424. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-sweep-defer.test.ts +9 -1
  425. package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +2 -2
  426. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +44 -10
  427. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +151 -10
  428. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1155 -0
  429. package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
  430. package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -3
  431. package/src/plugins/defaults/memory/__tests__/tools-delete-memory-page.test.ts +1 -1
  432. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +71 -35
  433. package/src/plugins/defaults/memory/context-search/sources/memory.ts +5 -1
  434. package/src/plugins/defaults/memory/fork-conversation-memory.ts +4 -4
  435. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +80 -10
  436. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +1 -1
  437. package/src/plugins/defaults/memory/graph/capability-seed.ts +24 -10
  438. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +123 -49
  439. package/src/plugins/defaults/memory/graph/graph-search.ts +6 -118
  440. package/src/plugins/defaults/memory/graph/in-context-tracker.test.ts +173 -0
  441. package/src/plugins/defaults/memory/graph/in-context-tracker.ts +109 -0
  442. package/src/plugins/defaults/memory/graph/store.ts +1 -0
  443. package/src/plugins/defaults/memory/graph/tool-handlers.test.ts +1 -1
  444. package/src/plugins/defaults/memory/graph/tool-handlers.ts +5 -2
  445. package/src/plugins/defaults/memory/graph-topology/__tests__/build-memory-graph.test.ts +1 -1
  446. package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +6 -9
  447. package/src/plugins/defaults/memory/hooks/__tests__/user-prompt-submit.test.ts +30 -16
  448. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +18 -14
  449. package/src/plugins/defaults/memory/indexer.ts +146 -89
  450. package/src/plugins/defaults/memory/injectors.ts +86 -41
  451. package/src/plugins/defaults/memory/job-handlers.ts +130 -39
  452. package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +2 -2
  453. package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +22 -10
  454. package/src/plugins/defaults/memory/jobs-worker.ts +279 -208
  455. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +4 -2
  456. package/src/plugins/defaults/memory/memory-retrospective-job.ts +40 -3
  457. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +99 -11
  458. package/src/plugins/defaults/memory/src/__tests__/memory-v2-routes.test.ts +5 -3
  459. package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +3 -4
  460. package/src/plugins/defaults/memory/src/memory-graph-routes.ts +2 -1
  461. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +7 -5
  462. package/src/plugins/defaults/memory/src/memory-item-routes.ts +51 -19
  463. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +31 -20
  464. package/src/plugins/defaults/memory/startup.ts +58 -21
  465. package/src/plugins/defaults/memory/substrate/__tests__/boot-maintenance.test.ts +335 -0
  466. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/cli-command-store.test.ts +14 -8
  467. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-job.test.ts +51 -21
  468. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/edge-index.test.ts +1 -1
  469. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/frontmatter-sweep.test.ts +3 -3
  470. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-index.test.ts +1 -1
  471. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-store.test.ts +1 -1
  472. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/prompts-consolidation.test.ts +2 -2
  473. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/qdrant.test.ts +23 -14
  474. package/src/plugins/defaults/memory/substrate/__tests__/reembed-job.test.ts +262 -0
  475. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sim.test.ts +9 -12
  476. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-content.test.ts +2 -2
  477. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-store.test.ts +9 -9
  478. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sparse-bm25.test.ts +12 -5
  479. package/src/plugins/defaults/memory/substrate/__tests__/spread.test.ts +276 -0
  480. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/static-context.test.ts +17 -8
  481. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sweep-job.test.ts +9 -9
  482. package/src/plugins/defaults/memory/{v3/substrate/memory-v2-startup.ts → substrate/boot-maintenance.ts} +43 -24
  483. package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-store.ts +13 -8
  484. package/src/plugins/defaults/memory/{v3/substrate → substrate}/consolidation-job.ts +51 -27
  485. package/src/plugins/defaults/memory/{v3/substrate → substrate}/constants.ts +1 -0
  486. package/src/plugins/defaults/memory/{v3/substrate → substrate}/edge-index.ts +28 -9
  487. package/src/plugins/defaults/memory/{v3/substrate → substrate}/frontmatter-sweep.ts +14 -7
  488. package/src/plugins/defaults/memory/{v3/substrate → substrate}/injected-block-slugs.ts +9 -3
  489. package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-index.ts +29 -10
  490. package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-store.ts +35 -12
  491. package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/consolidation.ts +14 -8
  492. package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/sweep.ts +4 -1
  493. package/src/plugins/defaults/memory/{v3/substrate → substrate}/qdrant.ts +96 -36
  494. package/src/plugins/defaults/memory/substrate/reembed-job.ts +54 -0
  495. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sim.ts +26 -15
  496. package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-content.ts +1 -1
  497. package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-store.ts +13 -8
  498. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sparse-bm25.ts +27 -10
  499. package/src/plugins/defaults/memory/substrate/spread.ts +165 -0
  500. package/src/plugins/defaults/memory/{v3/substrate → substrate}/static-context.ts +12 -7
  501. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sweep-job.ts +20 -15
  502. package/src/plugins/defaults/memory/substrate/tuning.ts +93 -0
  503. package/src/plugins/defaults/memory/{v3/substrate → substrate}/types.ts +7 -4
  504. package/src/plugins/defaults/memory/tools.test.ts +1 -1
  505. package/src/plugins/defaults/memory/tools.ts +1 -1
  506. package/src/plugins/defaults/memory/v1/README.md +5 -0
  507. package/src/plugins/defaults/memory/{__tests__ → v1/__tests__}/filing-jobs.test.ts +4 -4
  508. package/src/plugins/defaults/memory/{filing-jobs.ts → v1/filing-jobs.ts} +3 -3
  509. package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.test.ts +68 -6
  510. package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.ts +40 -21
  511. package/src/plugins/defaults/memory/{graph → v1/graph}/consolidation.ts +14 -14
  512. package/src/plugins/defaults/memory/{graph → v1/graph}/decay.test.ts +1 -1
  513. package/src/plugins/defaults/memory/{graph → v1/graph}/decay.ts +3 -3
  514. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction-job.ts +5 -5
  515. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.test.ts +1 -1
  516. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.ts +20 -14
  517. package/src/plugins/defaults/memory/{graph → v1/graph}/graph-search.test.ts +3 -3
  518. package/src/plugins/defaults/memory/v1/graph/graph-search.ts +123 -0
  519. package/src/plugins/defaults/memory/{graph → v1/graph}/injection.test.ts +1 -118
  520. package/src/plugins/defaults/memory/{graph → v1/graph}/injection.ts +9 -111
  521. package/src/plugins/defaults/memory/{graph → v1/graph}/narrative.ts +6 -6
  522. package/src/plugins/defaults/memory/{graph → v1/graph}/pattern-scan.ts +5 -5
  523. package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.test.ts +135 -42
  524. package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.ts +40 -22
  525. package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.test.ts +1 -1
  526. package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.ts +1 -1
  527. package/src/plugins/defaults/memory/{graph → v1/graph}/serendipity.ts +1 -1
  528. package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.test.ts +1 -1
  529. package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.ts +1 -1
  530. package/src/plugins/defaults/memory/{identity-context.ts → v1/identity-context.ts} +4 -4
  531. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/backfill.ts +6 -6
  532. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.test.ts +6 -6
  533. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.ts +6 -6
  534. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/index-maintenance.ts +8 -8
  535. package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.test.ts +7 -7
  536. package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.ts +5 -5
  537. package/src/plugins/defaults/memory/{pkb → v1/pkb}/autoinject.ts +1 -1
  538. package/src/plugins/defaults/memory/{pkb → v1/pkb}/context.ts +2 -2
  539. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.test.ts +3 -3
  540. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.ts +2 -2
  541. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.test.ts +3 -3
  542. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.ts +2 -2
  543. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.test.ts +3 -3
  544. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.ts +6 -6
  545. package/src/plugins/defaults/memory/{pkb → v1/pkb}/types.ts +3 -5
  546. package/src/plugins/defaults/memory/{pkb-schedule.ts → v1/pkb-schedule.ts} +2 -2
  547. package/src/plugins/defaults/memory/{search/semantic.ts → v1/semantic-search.ts} +1 -1
  548. package/src/plugins/defaults/memory/v2/__tests__/activation-store.test.ts +1 -1
  549. package/src/plugins/defaults/memory/v2/__tests__/activation.test.ts +11 -274
  550. package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +9 -131
  551. package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +1 -1
  552. package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +1 -1
  553. package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
  554. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +14 -10
  555. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +7 -5
  556. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +12 -6
  557. package/src/plugins/defaults/memory/{memory-v2-activation-log-store.ts → v2/activation-log-store.ts} +2 -2
  558. package/src/plugins/defaults/memory/v2/activation-store.ts +22 -8
  559. package/src/plugins/defaults/memory/v2/activation.ts +30 -163
  560. package/src/plugins/defaults/memory/v2/backfill-jobs.ts +7 -54
  561. package/src/plugins/defaults/memory/{memory-v2-concept-frequency.ts → v2/concept-frequency.ts} +3 -3
  562. package/src/plugins/defaults/memory/v2/harness/oracle.ts +1 -1
  563. package/src/plugins/defaults/memory/v2/harness/replay-input.ts +2 -2
  564. package/src/plugins/defaults/memory/v2/harness/retriever.ts +1 -1
  565. package/src/plugins/defaults/memory/v2/injection.ts +36 -26
  566. package/src/plugins/defaults/memory/v2/migration.ts +2 -2
  567. package/src/plugins/defaults/memory/{rerank-local.ts → v2/rerank-local.ts} +44 -18
  568. package/src/plugins/defaults/memory/v2/reranker.ts +29 -11
  569. package/src/plugins/defaults/memory/v2/router.ts +38 -15
  570. package/src/plugins/defaults/memory/v3/__tests__/candidate-match.test.ts +5 -3
  571. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +21 -8
  572. package/src/plugins/defaults/memory/v3/__tests__/edge.test.ts +1 -1
  573. package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +1 -1
  574. package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +4 -1
  575. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +181 -3
  576. package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +3 -0
  577. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +14 -5
  578. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +40 -50
  579. package/src/plugins/defaults/memory/v3/__tests__/tuning-profile.test.ts +1 -0
  580. package/src/plugins/defaults/memory/v3/candidate-match.ts +2 -2
  581. package/src/plugins/defaults/memory/v3/capabilities.ts +6 -4
  582. package/src/plugins/defaults/memory/v3/card.ts +25 -9
  583. package/src/plugins/defaults/memory/v3/edge.ts +52 -18
  584. package/src/plugins/defaults/memory/v3/gate.ts +4 -4
  585. package/src/plugins/defaults/memory/v3/injector.ts +10 -3
  586. package/src/plugins/defaults/memory/v3/maintain-job.ts +3 -3
  587. package/src/plugins/defaults/memory/v3/orchestrate.ts +100 -18
  588. package/src/plugins/defaults/memory/v3/page-content.ts +26 -10
  589. package/src/plugins/defaults/memory/v3/prune.ts +40 -16
  590. package/src/plugins/defaults/memory/v3/selection-log-store.ts +34 -12
  591. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +9 -13
  592. package/src/plugins/defaults/memory/v3/span-query.test.ts +86 -0
  593. package/src/plugins/defaults/memory/v3/span-query.ts +71 -0
  594. package/src/plugins/defaults/memory/v3/tuning-profile.ts +3 -0
  595. package/src/plugins/defaults/memory/v3/types.ts +4 -1
  596. package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +2 -2
  597. package/src/plugins/defaults/memory/validation.ts +1 -1
  598. package/src/plugins/defaults/memory/worker.ts +2 -1
  599. package/src/plugins/defaults/platform-hosted/__tests__/reengage.test.ts +104 -12
  600. package/src/plugins/defaults/platform-hosted/routes/reengage.ts +104 -12
  601. package/src/plugins/types.ts +2 -2
  602. package/src/prompts/sections.ts +4 -16
  603. package/src/providers/__tests__/registry-native-web-search.test.ts +47 -2
  604. package/src/providers/anthropic/client.ts +15 -6
  605. package/src/providers/content-block-schema.ts +26 -0
  606. package/src/providers/inference/__tests__/connections-credential-normalize.test.ts +87 -0
  607. package/src/providers/inference/adapter-factory.ts +6 -0
  608. package/src/providers/inference/connections.ts +30 -14
  609. package/src/providers/model-catalog.ts +77 -0
  610. package/src/providers/openai/__tests__/chat-completions-input-audio.test.ts +260 -0
  611. package/src/providers/openai/chat-completions-provider.ts +65 -17
  612. package/src/providers/openai/input-audio.ts +76 -0
  613. package/src/providers/openrouter/client.ts +0 -2
  614. package/src/providers/platform-proxy/constants.ts +4 -0
  615. package/src/providers/poolside/client.ts +42 -0
  616. package/src/providers/registry.ts +40 -8
  617. package/src/providers/retry.ts +2 -0
  618. package/src/providers/types.ts +39 -1
  619. package/src/providers/vercel-ai-gateway/client.ts +0 -2
  620. package/src/runtime/AGENTS.md +7 -5
  621. package/src/runtime/__tests__/question-request-guardian-bridge.test.ts +173 -0
  622. package/src/runtime/__tests__/question-resolution.test.ts +111 -0
  623. package/src/runtime/access-request-helper.ts +7 -15
  624. package/src/runtime/assistant-event-hub.ts +43 -31
  625. package/src/runtime/assistant-event-publish-options.ts +31 -0
  626. package/src/runtime/assistant-event.ts +19 -30
  627. package/src/runtime/assistant-stream-state.ts +4 -4
  628. package/src/runtime/channel-approvals.ts +0 -25
  629. package/src/runtime/channel-readiness-service.ts +99 -40
  630. package/src/runtime/channel-retry-sweep.ts +38 -15
  631. package/src/runtime/confirmation-request-guardian-bridge.ts +4 -0
  632. package/src/runtime/guardian-reply-router.ts +108 -0
  633. package/src/runtime/http-server.ts +8 -0
  634. package/src/runtime/http-types.ts +2 -2
  635. package/src/runtime/process-role.ts +42 -0
  636. package/src/runtime/question-request-guardian-bridge.ts +184 -0
  637. package/src/runtime/question-resolution.ts +153 -0
  638. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +6 -2
  639. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -1
  640. package/src/runtime/routes/__tests__/subagents-routes.test.ts +250 -0
  641. package/src/runtime/routes/__tests__/webhook-routes.test.ts +201 -0
  642. package/src/runtime/routes/acp-routes.ts +2 -2
  643. package/src/runtime/routes/bookmark-routes.ts +3 -15
  644. package/src/runtime/routes/canned-message-complete.ts +2 -2
  645. package/src/runtime/routes/consolidation-routes.ts +8 -2
  646. package/src/runtime/routes/conversation-list-routes.ts +3 -19
  647. package/src/runtime/routes/conversation-management-routes.ts +1 -5
  648. package/src/runtime/routes/conversation-query-routes.ts +52 -8
  649. package/src/runtime/routes/conversation-routes.ts +36 -22
  650. package/src/runtime/routes/credential-request-routes.ts +0 -1
  651. package/src/runtime/routes/filing-routes.ts +7 -7
  652. package/src/runtime/routes/global-search-routes.ts +1 -1
  653. package/src/runtime/routes/guardian-approval-prompt.ts +2 -2
  654. package/src/runtime/routes/image-generation-routes.ts +12 -9
  655. package/src/runtime/routes/inbound-message-handler.ts +17 -0
  656. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +50 -0
  657. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +19 -0
  658. package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -4
  659. package/src/runtime/routes/inbound-stages/inbound-content-prep.test.ts +129 -0
  660. package/src/runtime/routes/inbound-stages/inbound-content-prep.ts +141 -9
  661. package/src/runtime/routes/index.ts +2 -0
  662. package/src/runtime/routes/lifecycle-routes.ts +199 -0
  663. package/src/runtime/routes/platform-routes.ts +3 -8
  664. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +7 -7
  665. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +5 -5
  666. package/src/runtime/routes/question-routes.ts +34 -87
  667. package/src/runtime/routes/secret-routes.ts +11 -1
  668. package/src/runtime/routes/settings-routes.ts +8 -18
  669. package/src/runtime/routes/subagents-routes.ts +35 -8
  670. package/src/runtime/routes/upgrade-broadcast-routes.ts +4 -5
  671. package/src/runtime/routes/webhook-routes.ts +89 -30
  672. package/src/runtime/routes/workspace-routes.test.ts +7 -4
  673. package/src/runtime/slack-reply-session.test.ts +12 -12
  674. package/src/runtime/slack-reply-session.ts +17 -17
  675. package/src/runtime/sync/sync-publisher.test.ts +7 -5
  676. package/src/runtime/tool-grant-request-helper.ts +4 -0
  677. package/src/schedule/schedule-store.ts +70 -0
  678. package/src/schedule/scheduler.ts +27 -0
  679. package/src/security/AGENTS.md +1 -1
  680. package/src/security/credential-key.ts +17 -0
  681. package/src/security/secret-ingress.ts +14 -105
  682. package/src/security/secret-patterns.ts +8 -139
  683. package/src/security/secret-scanner.ts +8 -3
  684. package/src/security/store-path-override.ts +6 -16
  685. package/src/sequence/store.ts +8 -0
  686. package/src/signals/emit-event.ts +5 -10
  687. package/src/signals/event-stream.ts +20 -10
  688. package/src/subagent/manager.ts +76 -25
  689. package/src/subagent/notify.ts +8 -0
  690. package/src/subagent/types.ts +13 -3
  691. package/src/telegram/__tests__/webhook-health.test.ts +442 -0
  692. package/src/telegram/webhook-health.ts +478 -0
  693. package/src/telemetry/AGENTS.md +6 -0
  694. package/src/telemetry/memory-corpus-size.test.ts +129 -0
  695. package/src/telemetry/memory-corpus-size.ts +184 -0
  696. package/src/telemetry/memory-tier-reporter.test.ts +67 -2
  697. package/src/telemetry/memory-tier-reporter.ts +30 -3
  698. package/src/tools/__tests__/conversation-group-tool-input-schemas.test.ts +61 -0
  699. package/src/tools/__tests__/document-tool-input-schemas.test.ts +103 -0
  700. package/src/tools/__tests__/followup-call-acp-tool-input-schemas.test.ts +125 -0
  701. package/src/tools/__tests__/schedule-tool-input-schemas.test.ts +83 -0
  702. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +116 -0
  703. package/src/tools/__tests__/tool-input-schemas.test.ts +192 -0
  704. package/src/tools/__tests__/tool-schema-drift-harness.ts +142 -0
  705. package/src/tools/acp/abort.ts +21 -1
  706. package/src/tools/acp/context.ts +5 -5
  707. package/src/tools/acp/spawn.test.ts +15 -5
  708. package/src/tools/acp/spawn.ts +26 -3
  709. package/src/tools/acp/status.ts +20 -1
  710. package/src/tools/acp/steer.test.ts +20 -0
  711. package/src/tools/acp/steer.ts +23 -2
  712. package/src/tools/apps/resolve-app-id.ts +15 -3
  713. package/src/tools/ask-question/ask-question-tool.test.ts +65 -0
  714. package/src/tools/ask-question/ask-question-tool.ts +68 -92
  715. package/src/tools/browser/browser-screencast.ts +6 -6
  716. package/src/tools/calls/call-end.ts +24 -3
  717. package/src/tools/calls/call-start.ts +35 -11
  718. package/src/tools/calls/call-status.ts +20 -1
  719. package/src/tools/conversation-groups/group_create.ts +63 -0
  720. package/src/tools/conversation-groups/group_list.ts +20 -0
  721. package/src/tools/conversation-groups/group_shared.ts +52 -0
  722. package/src/tools/conversation-groups/move_to_group.ts +106 -0
  723. package/src/tools/document/document-comment-tool.test.ts +49 -0
  724. package/src/tools/document/document-comment-tool.ts +45 -6
  725. package/src/tools/document/document-tool.ts +142 -24
  726. package/src/tools/executor.ts +27 -13
  727. package/src/tools/filesystem/edit.ts +62 -60
  728. package/src/tools/filesystem/list.ts +36 -29
  729. package/src/tools/filesystem/read.ts +56 -39
  730. package/src/tools/filesystem/write.ts +44 -38
  731. package/src/tools/followups/followup_create.ts +41 -12
  732. package/src/tools/followups/followup_list.ts +34 -6
  733. package/src/tools/followups/followup_resolve.ts +26 -4
  734. package/src/tools/host-filesystem/edit.ts +50 -60
  735. package/src/tools/host-filesystem/read.ts +45 -39
  736. package/src/tools/host-filesystem/write.ts +31 -36
  737. package/src/tools/host-terminal/host-shell.ts +76 -62
  738. package/src/tools/policy-context.ts +27 -10
  739. package/src/tools/schedule/create.ts +76 -33
  740. package/src/tools/schedule/delete.ts +21 -2
  741. package/src/tools/schedule/list.ts +25 -3
  742. package/src/tools/schedule/update.ts +105 -48
  743. package/src/tools/shared/filesystem/path-policy.ts +246 -40
  744. package/src/tools/shared/zod-tool-schema.ts +117 -0
  745. package/src/tools/subagent/abort.ts +12 -4
  746. package/src/tools/subagent/consult-deadline.ts +9 -3
  747. package/src/tools/subagent/message.ts +21 -5
  748. package/src/tools/subagent/notify-parent.ts +44 -23
  749. package/src/tools/subagent/read.ts +15 -4
  750. package/src/tools/subagent/resolve.ts +26 -4
  751. package/src/tools/subagent/spawn.ts +37 -13
  752. package/src/tools/subagent/status.ts +12 -4
  753. package/src/tools/system/request-permission.ts +35 -26
  754. package/src/tools/terminal/shell.ts +68 -55
  755. package/src/tools/tool-approval-handler.ts +327 -53
  756. package/src/tools/tool-input-schemas.ts +85 -0
  757. package/src/tools/tool-types.ts +7 -0
  758. package/src/tools/types.ts +8 -0
  759. package/src/tools/workflows/manage-workflows.ts +30 -2
  760. package/src/tools/workflows/run-workflow.test.ts +54 -2
  761. package/src/tools/workflows/run-workflow.ts +32 -4
  762. package/src/util/fs-symlinks.ts +30 -0
  763. package/src/util/log-redact.ts +7 -3
  764. package/src/util/platform.ts +15 -0
  765. package/src/vellum-assistant-namespace.d.ts +80 -0
  766. package/src/watcher/watcher-store.ts +8 -0
  767. package/src/workflows/leaf-runner.test.ts +104 -2
  768. package/src/workflows/leaf-runner.ts +31 -6
  769. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +2 -2
  770. package/src/workspace/migrations/134-image-generation-mode-to-provider.ts +128 -0
  771. package/src/workspace/migrations/135-copy-substrate-tunables.ts +248 -0
  772. package/src/workspace/migrations/__tests__/135-copy-substrate-tunables.test.ts +446 -0
  773. package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +2 -2
  774. package/src/workspace/migrations/registry.ts +4 -0
  775. package/tsconfig.plugin-api.json +1 -1
  776. package/src/__tests__/memory-retrieval-budget.test.ts +0 -49
  777. package/src/__tests__/secret-patterns.test.ts +0 -27
  778. package/src/config/__tests__/proc-to-skills.test.ts +0 -21
  779. package/src/config/memory-tier.test.ts +0 -44
  780. package/src/daemon/message-types/acp.ts +0 -20
  781. package/src/daemon/message-types/apps.ts +0 -11
  782. package/src/daemon/message-types/background-tools.ts +0 -14
  783. package/src/daemon/message-types/bookmarks.ts +0 -13
  784. package/src/daemon/message-types/contacts.ts +0 -13
  785. package/src/daemon/message-types/document-comments.ts +0 -14
  786. package/src/daemon/message-types/documents.ts +0 -13
  787. package/src/daemon/message-types/home.ts +0 -15
  788. package/src/daemon/message-types/host-bash.ts +0 -12
  789. package/src/daemon/message-types/host-cu.ts +0 -10
  790. package/src/daemon/message-types/host-file.ts +0 -12
  791. package/src/daemon/message-types/host-transfer.ts +0 -12
  792. package/src/daemon/message-types/integrations.ts +0 -90
  793. package/src/daemon/message-types/memory.ts +0 -10
  794. package/src/daemon/message-types/schedules.ts +0 -14
  795. package/src/daemon/message-types/settings.ts +0 -17
  796. package/src/daemon/message-types/subagents.ts +0 -63
  797. package/src/daemon/message-types/upgrades.ts +0 -14
  798. package/src/daemon/message-types/workflows.ts +0 -25
  799. package/src/daemon/message-types/workspace.ts +0 -137
  800. package/src/live-voice/ack-phrases.ts +0 -58
  801. package/src/plugins/defaults/memory/retrieval-budget.ts +0 -29
  802. package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +0 -69
  803. package/src/plugins/defaults/memory/v3/gate-flag.ts +0 -20
  804. package/src/plugins/defaults/memory/v3/substrate/__tests__/memory-v2-startup.test.ts +0 -86
  805. package/src/plugins/defaults/memory/v3/substrate/memory-v2-startup.test.ts +0 -205
  806. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/concept-page-frontmatter-schema.test.ts +0 -0
  807. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-prompt-flag-gating-guard.test.ts +0 -0
  808. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/injected-block-slugs.test.ts +0 -0
  809. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-content.ts +0 -0
@@ -1,5 +1,11 @@
1
1
  import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
+ import {
4
+ installThresholdReaderMock,
5
+ resetThresholdReaderMock,
6
+ thresholdReaderMock,
7
+ } from "./gateway-threshold-reader-mock.js";
8
+
3
9
  const testDir = process.env.VELLUM_WORKSPACE_DIR!;
4
10
 
5
11
  // Mock verification control-plane policy -- not targeting control-plane by default
@@ -22,22 +28,75 @@ const fakeTool = {
22
28
  execute: async () => ({ content: "ok", isError: false }),
23
29
  };
24
30
 
31
+ /** Same tool class as `fakeTool`, but reaching the guardian's own machine. */
32
+ const fakeHostTool = {
33
+ ...fakeTool,
34
+ name: "host_bash",
35
+ executionTarget: "host" as const,
36
+ };
37
+
38
+ /**
39
+ * A skill shadowing a core side-effect name. A novel third-party tool name is
40
+ * not a side-effect tool at all, so it never reaches the floor — shadowing is
41
+ * the case where an unvetted manifest lands on a liftable invocation.
42
+ */
43
+ const fakeSkillTool = {
44
+ ...fakeTool,
45
+ name: "document_create",
46
+ category: "documents",
47
+ };
48
+
49
+ const fakeTools: Record<string, typeof fakeTool> = {
50
+ bash: fakeTool,
51
+ host_bash: fakeHostTool,
52
+ document_create: fakeSkillTool,
53
+ acme_send: { ...fakeTool, name: "acme_send", category: "messaging" },
54
+ ws_deploy: { ...fakeTool, name: "ws_deploy", category: "workspace" },
55
+ mcp_lookup: { ...fakeTool, name: "mcp_lookup", category: "mcp" },
56
+ file_write: { ...fakeTool, name: "file_write", category: "filesystem" },
57
+ web_fetch: { ...fakeTool, name: "web_fetch", category: "network" },
58
+ };
59
+
60
+ /** Registry ownership per tool — drives the extension-owned gate checks. */
61
+ const toolOwners: Record<string, { kind: string; id: string }> = {
62
+ document_create: { kind: "skill", id: "some-skill" },
63
+ acme_send: { kind: "skill", id: "some-skill" },
64
+ ws_deploy: { kind: "workspace", id: "tools/ws-deploy.ts" },
65
+ mcp_lookup: { kind: "mcp", id: "some-server" },
66
+ };
67
+
68
+ /**
69
+ * Per-test owner override for `file_write`, for the workspace-override-of-a-
70
+ * core-name case. `undefined` = unowned built-in, the lift tests' baseline.
71
+ */
72
+ let fileWriteOwner: { kind: string; id: string } | undefined;
73
+
25
74
  mock.module("../tools/registry.js", () => ({
26
- getTool: (name: string) => (name === "bash" ? fakeTool : undefined),
27
- resolveTool: (name: string) => (name === "bash" ? fakeTool : undefined),
28
- getAllTools: () => [fakeTool],
75
+ getTool: (name: string) => fakeTools[name],
76
+ resolveTool: (name: string) => fakeTools[name],
77
+ getAllTools: () => Object.values(fakeTools),
78
+ getToolOwner: (name: string) =>
79
+ name === "file_write" && fileWriteOwner ? fileWriteOwner : toolOwners[name],
29
80
  }));
30
81
 
31
82
  // Mock the dynamic-skill predicate so isSensitiveTool's skill_load branch is
32
83
  // exercised without a real skill catalog: "dynamic-skill" is an inline-command
33
84
  // load, anything else is plain.
85
+ /** Whether the owning skill of the tool under test reports as first-party. */
86
+ let skillOwnerBundled = false;
87
+
34
88
  mock.module("../permissions/checker.js", () => ({
35
89
  isDynamicSkillLoadInvocation: (
36
90
  _name: string,
37
91
  input: Record<string, unknown>,
38
92
  ) => input?.skill === "dynamic-skill",
93
+ isToolOwnerSkillBundled: () => skillOwnerBundled,
39
94
  }));
40
95
 
96
+ // The channel permission-matrix cell is a gateway IPC call; the shared mock
97
+ // makes it per-test controllable and counts lookups.
98
+ installThresholdReaderMock();
99
+
41
100
  // Capture tool-audit terminal calls so tests can assert on denied/error outcomes
42
101
  // the way they previously asserted on emitted lifecycle events.
43
102
  const auditCalls = {
@@ -60,6 +119,10 @@ function resetAuditCalls(): void {
60
119
  auditCalls.prompted.length = 0;
61
120
  }
62
121
 
122
+ import { mkdtempSync, rmSync } from "node:fs";
123
+ import { tmpdir } from "node:os";
124
+ import { join } from "node:path";
125
+
63
126
  import {
64
127
  mintGrantFromDecision,
65
128
  type MintGrantParams,
@@ -71,8 +134,8 @@ import { scopedApprovalGrants } from "../persistence/schema/index.js";
71
134
  import { computeToolApprovalDigest } from "../security/tool-approval-digest.js";
72
135
  import {
73
136
  type ApprovalCellThreshold,
74
- isSensitiveTool,
75
137
  resolveSensitiveToolDecision,
138
+ sensitiveToolReach,
76
139
  ToolApprovalHandler,
77
140
  } from "../tools/tool-approval-handler.js";
78
141
  import type { ToolContext } from "../tools/types.js";
@@ -528,36 +591,100 @@ describe("ToolApprovalHandler / pre-exec gate grant check", () => {
528
591
  });
529
592
  });
530
593
 
531
- describe("isSensitiveTool", () => {
532
- test("sensitivity is a property of the tool and execution target", () => {
533
- // Side-effect tools are sensitive wherever they run.
534
- expect(isSensitiveTool("bash", "sandbox")).toBe(true);
535
- expect(isSensitiveTool("file_write", "sandbox")).toBe(true);
536
- // Read-only tools are sensitive only when they execute on the host.
537
- expect(isSensitiveTool("web_search", "host")).toBe(true);
538
- expect(isSensitiveTool("web_search", "sandbox")).toBe(false);
539
- // UI surface tools are exempt even on the host target.
540
- expect(isSensitiveTool("ui_show", "host")).toBe(false);
541
- expect(isSensitiveTool("ui_update", "host")).toBe(false);
542
- expect(isSensitiveTool("ui_dismiss", "host")).toBe(false);
543
- });
544
-
545
- test("an inline-command (dynamic) skill_load is sensitive; a plain one is not", () => {
594
+ describe("sensitiveToolReach", () => {
595
+ test("reach is a property of the tool and execution target", () => {
596
+ // Side-effect tools reach the sandbox wherever they run…
597
+ expect(sensitiveToolReach("bash", "sandbox")).toBe("sandbox");
598
+ expect(sensitiveToolReach("file_write", "sandbox")).toBe("sandbox");
599
+ // …read-only tools reach only when they execute on the host…
600
+ expect(sensitiveToolReach("web_search", "host")).toBe("host");
601
+ expect(sensitiveToolReach("web_search", "sandbox")).toBe("none");
602
+ // …and UI surface tools are exempt even on the host target.
603
+ expect(sensitiveToolReach("ui_show", "host")).toBe("none");
604
+ expect(sensitiveToolReach("ui_update", "host")).toBe("none");
605
+ expect(sensitiveToolReach("ui_dismiss", "host")).toBe("none");
606
+ });
607
+
608
+ test("an inline-command (dynamic) skill_load reaches the host; a plain one is not sensitive", () => {
546
609
  // skill_load is not a side-effect tool, but a load that executes embedded
547
610
  // shell at load time must pass through the capability floor — so a
548
611
  // non-guardian's dynamic load escalates to the guardian, Full-access-proof.
549
612
  expect(
550
- isSensitiveTool("skill_load", "sandbox", { skill: "dynamic-skill" }),
551
- ).toBe(true);
613
+ sensitiveToolReach("skill_load", "sandbox", { skill: "dynamic-skill" }),
614
+ ).toBe("host");
552
615
  expect(
553
- isSensitiveTool("skill_load", "sandbox", { skill: "plain-skill" }),
554
- ).toBe(false);
616
+ sensitiveToolReach("skill_load", "sandbox", { skill: "plain-skill" }),
617
+ ).toBe("none");
555
618
  // Without input, skill_load falls back to the name/target rule.
556
- expect(isSensitiveTool("skill_load", "sandbox")).toBe(false);
619
+ expect(sensitiveToolReach("skill_load", "sandbox")).toBe("none");
620
+ });
621
+
622
+ test("an out-of-workspace file_read reaches the host; an in-workspace one is not sensitive", () => {
623
+ const workingDir = mkdtempSync(join(tmpdir(), "sensitive-tool-test-"));
624
+ try {
625
+ // Out-of-workspace file access is host-equivalent: the host-fallback
626
+ // path policy executes the escape, so it carries the host capability
627
+ // floor even for the read-only sandbox tool.
628
+ expect(
629
+ sensitiveToolReach(
630
+ "file_read",
631
+ "sandbox",
632
+ { path: "/etc/hosts" },
633
+ workingDir,
634
+ ),
635
+ ).toBe("host");
636
+ expect(
637
+ sensitiveToolReach(
638
+ "file_read",
639
+ "sandbox",
640
+ { path: "notes.txt" },
641
+ workingDir,
642
+ ),
643
+ ).toBe("none");
644
+ // `path` is the executed field — a benign `file_path` must not mask it.
645
+ expect(
646
+ sensitiveToolReach(
647
+ "file_read",
648
+ "sandbox",
649
+ { path: "/etc/hosts", file_path: "notes.txt" },
650
+ workingDir,
651
+ ),
652
+ ).toBe("host");
653
+ // Container-style /workspace paths remap to the workspace.
654
+ expect(
655
+ sensitiveToolReach(
656
+ "file_read",
657
+ "sandbox",
658
+ { path: "/workspace/notes.txt" },
659
+ workingDir,
660
+ ),
661
+ ).toBe("none");
662
+ // Without a workingDir the boundary is unknown — name/target rule only.
663
+ expect(
664
+ sensitiveToolReach("file_read", "sandbox", { path: "/etc/hosts" }),
665
+ ).toBe("none");
666
+ // Containerized installs keep the hard execution boundary, so the
667
+ // escape never executes and does not need the floor.
668
+ process.env.IS_CONTAINERIZED = "true";
669
+ try {
670
+ expect(
671
+ sensitiveToolReach(
672
+ "file_read",
673
+ "sandbox",
674
+ { path: "/etc/hosts" },
675
+ workingDir,
676
+ ),
677
+ ).toBe("none");
678
+ } finally {
679
+ delete process.env.IS_CONTAINERIZED;
680
+ }
681
+ } finally {
682
+ rmSync(workingDir, { recursive: true, force: true });
683
+ }
557
684
  });
558
685
  });
559
686
 
560
- describe("resolveSensitiveToolDecision / CapabilitySet floor invariant", () => {
687
+ describe("resolveSensitiveToolDecision / CapabilitySet floor × approval cell", () => {
561
688
  const cellThresholds: Array<ApprovalCellThreshold | undefined> = [
562
689
  undefined,
563
690
  "none",
@@ -565,24 +692,58 @@ describe("resolveSensitiveToolDecision / CapabilitySet floor invariant", () => {
565
692
  "medium",
566
693
  "high",
567
694
  ];
568
- const riskLevels = ["low", "medium", "high"];
695
+ /** The cells that authorize something, and so can lift the floor. */
696
+ const liftingThresholds: ApprovalCellThreshold[] = ["low", "medium", "high"];
697
+
698
+ test("no cell and a none cell both leave the escalate floor standing", () => {
699
+ for (const cellThreshold of [undefined, "none"] as const) {
700
+ expect(
701
+ resolveSensitiveToolDecision({
702
+ reach: "sandbox",
703
+ cellThreshold,
704
+ sensitiveToolApproval: "escalate-and-wait",
705
+ }),
706
+ ).toBe("escalate-and-wait");
707
+ }
708
+ });
569
709
 
570
- test("no cell threshold or risk level lifts the floor for non-self actors", () => {
710
+ test("a cell that authorizes something lifts the escalate floor", () => {
711
+ for (const cellThreshold of liftingThresholds) {
712
+ expect(
713
+ resolveSensitiveToolDecision({
714
+ reach: "sandbox",
715
+ cellThreshold,
716
+ sensitiveToolApproval: "escalate-and-wait",
717
+ }),
718
+ ).toBe("proceed");
719
+ }
720
+ });
721
+
722
+ // A room-level posture says what the assistant may do in that room. It is
723
+ // never a grant of the owner's own machine or accounts, so no cell at any
724
+ // cascade level reaches past the sandbox.
725
+ test("host reach is never lifted, at any cell threshold", () => {
571
726
  for (const cellThreshold of cellThresholds) {
572
- for (const riskLevel of riskLevels) {
573
- expect(
574
- resolveSensitiveToolDecision({
575
- sensitive: true,
576
- cellThreshold,
577
- riskLevel,
578
- sensitiveToolApproval: "escalate-and-wait",
579
- }),
580
- ).toBe("escalate-and-wait");
727
+ expect(
728
+ resolveSensitiveToolDecision({
729
+ reach: "host",
730
+ cellThreshold,
731
+ sensitiveToolApproval: "escalate-and-wait",
732
+ }),
733
+ ).toBe("escalate-and-wait");
734
+ }
735
+ });
736
+
737
+ // An actor with no established identity has no cell to stand on: the matrix
738
+ // is keyed by contact type, and "unknown" is the absence of one. No cell at
739
+ // any cascade level may turn that into permission to act.
740
+ test("deny is absolute — no cell threshold lifts it", () => {
741
+ for (const cellThreshold of cellThresholds) {
742
+ for (const reach of ["sandbox", "host"] as const) {
581
743
  expect(
582
744
  resolveSensitiveToolDecision({
583
- sensitive: true,
745
+ reach,
584
746
  cellThreshold,
585
- riskLevel,
586
747
  sensitiveToolApproval: "deny",
587
748
  }),
588
749
  ).toBe("deny");
@@ -592,12 +753,11 @@ describe("resolveSensitiveToolDecision / CapabilitySet floor invariant", () => {
592
753
 
593
754
  test("self capability proceeds for sensitive tools (lane-B policy governs downstream)", () => {
594
755
  for (const cellThreshold of cellThresholds) {
595
- for (const riskLevel of riskLevels) {
756
+ for (const reach of ["sandbox", "host"] as const) {
596
757
  expect(
597
758
  resolveSensitiveToolDecision({
598
- sensitive: true,
759
+ reach,
599
760
  cellThreshold,
600
- riskLevel,
601
761
  sensitiveToolApproval: "self",
602
762
  }),
603
763
  ).toBe("proceed");
@@ -613,9 +773,8 @@ describe("resolveSensitiveToolDecision / CapabilitySet floor invariant", () => {
613
773
  ] as const) {
614
774
  expect(
615
775
  resolveSensitiveToolDecision({
616
- sensitive: false,
776
+ reach: "none",
617
777
  cellThreshold: undefined,
618
- riskLevel: "high",
619
778
  sensitiveToolApproval,
620
779
  }),
621
780
  ).toBe("proceed");
@@ -623,6 +782,391 @@ describe("resolveSensitiveToolDecision / CapabilitySet floor invariant", () => {
623
782
  });
624
783
  });
625
784
 
785
+ describe("ToolApprovalHandler / approval cell lifts the sensitive-tool floor", () => {
786
+ const handler = new ToolApprovalHandler();
787
+ /** An ordinary workspace write: sandbox reach, and nothing excludes it. */
788
+ const toolName = "file_write";
789
+ const input = { path: "notes/todo.md", content: "x" };
790
+
791
+ /**
792
+ * A contact in a room, with no `requesterExternalUserId` — escalation needs
793
+ * one, so when the floor stands the gate takes the generic denial path
794
+ * instead of reaching for the guardian-request machinery. That keeps these
795
+ * tests on the gate's own decision.
796
+ */
797
+ function channelContext(overrides: Partial<ToolContext> = {}): ToolContext {
798
+ return makeContext({
799
+ trustClass: "trusted_contact",
800
+ executionChannel: "telegram",
801
+ channelPermissionChannelId: "C-room",
802
+ ...overrides,
803
+ });
804
+ }
805
+
806
+ function cell(threshold: string) {
807
+ return { ok: true, resolved: { threshold, scope: "channel" } } as const;
808
+ }
809
+
810
+ beforeEach(() => {
811
+ clearTables();
812
+ resetAuditCalls();
813
+ resetThresholdReaderMock();
814
+ skillOwnerBundled = false;
815
+ fileWriteOwner = undefined;
816
+ });
817
+
818
+ test.each(["low", "medium", "high"])(
819
+ "a %s cell lifts the floor — no scoped grant required",
820
+ async (threshold) => {
821
+ thresholdReaderMock.cell = cell(threshold);
822
+
823
+ const result = await handler.checkPreExecutionGates(
824
+ toolName,
825
+ input,
826
+ channelContext(),
827
+ "low",
828
+ Date.now(),
829
+ );
830
+
831
+ expect(result.allowed).toBe(true);
832
+ if (!result.allowed) {
833
+ return;
834
+ }
835
+ // Not "approved via a grant" — the gate stepped out of the grant
836
+ // mechanism entirely and handed off to the risk/threshold policy.
837
+ expect(result.grantConsumed).toBeFalsy();
838
+ expect(auditCalls.denied.length).toBe(0);
839
+ },
840
+ );
841
+
842
+ test("a none cell authorizes nothing — the floor stands", async () => {
843
+ thresholdReaderMock.cell = cell("none");
844
+
845
+ const result = await handler.checkPreExecutionGates(
846
+ toolName,
847
+ input,
848
+ channelContext(),
849
+ "low",
850
+ Date.now(),
851
+ );
852
+
853
+ expect(result.allowed).toBe(false);
854
+ if (result.allowed) {
855
+ return;
856
+ }
857
+ expect(result.result.content).toContain("requires guardian approval");
858
+ });
859
+
860
+ // Fail closed: an unreadable cell is indistinguishable from a strict one, so
861
+ // a gateway outage must never widen what a channel actor may do.
862
+ test("a failed cell lookup does not lift the floor", async () => {
863
+ thresholdReaderMock.cell = { ok: false };
864
+
865
+ const result = await handler.checkPreExecutionGates(
866
+ toolName,
867
+ input,
868
+ channelContext(),
869
+ "low",
870
+ Date.now(),
871
+ );
872
+
873
+ expect(result.allowed).toBe(false);
874
+ });
875
+
876
+ // The matrix is keyed by contact type, and "unknown" is the absence of one.
877
+ test("an unknown actor stays fail-closed even under a full-access cell", async () => {
878
+ thresholdReaderMock.cell = cell("high");
879
+
880
+ const result = await handler.checkPreExecutionGates(
881
+ toolName,
882
+ input,
883
+ channelContext({ trustClass: "unknown" }),
884
+ "low",
885
+ Date.now(),
886
+ );
887
+
888
+ expect(result.allowed).toBe(false);
889
+ if (result.allowed) {
890
+ return;
891
+ }
892
+ expect(result.result.content).toContain("verified channel identity");
893
+ // Nothing to resolve: no cell can lift an absolute deny.
894
+ expect(thresholdReaderMock.cellLookups).toBe(0);
895
+ });
896
+
897
+ // The cell says what the assistant may do in a room, not what a contact may
898
+ // do to the owner's machine. `host_bash` is the same tool class as `bash`
899
+ // and the same Full-access cell — only the reach differs.
900
+ test("a full-access cell does not lift a host-reach tool", async () => {
901
+ thresholdReaderMock.cell = cell("high");
902
+
903
+ const result = await handler.checkPreExecutionGates(
904
+ "host_bash",
905
+ { command: "ls" },
906
+ channelContext(),
907
+ "low",
908
+ Date.now(),
909
+ );
910
+
911
+ expect(result.allowed).toBe(false);
912
+ if (result.allowed) {
913
+ return;
914
+ }
915
+ expect(result.result.content).toContain("requires guardian approval");
916
+ // Host reach is decided before the cell matters, so nothing is looked up.
917
+ expect(thresholdReaderMock.cellLookups).toBe(0);
918
+ });
919
+
920
+ // Each of these is a way back out of the sandbox, so a cell that lifted any
921
+ // one of them would lift the others by the back door. Excluding only some
922
+ // would read as safe while leaving the path open.
923
+ describe("what no cell lifts, even at Full access", () => {
924
+ beforeEach(() => {
925
+ thresholdReaderMock.cell = cell("high");
926
+ });
927
+
928
+ async function expectFloored(
929
+ toolName: string,
930
+ toolInput: Record<string, unknown>,
931
+ ) {
932
+ const result = await handler.checkPreExecutionGates(
933
+ toolName,
934
+ toolInput,
935
+ channelContext(),
936
+ "low",
937
+ Date.now(),
938
+ );
939
+ expect(result.allowed).toBe(false);
940
+ if (result.allowed) {
941
+ return;
942
+ }
943
+ expect(result.result.content).toContain("requires guardian approval");
944
+ // Excluded before the cell matters, so nothing is looked up.
945
+ expect(thresholdReaderMock.cellLookups).toBe(0);
946
+ }
947
+
948
+ // Running code in the workspace is how you write everything else in it.
949
+ test("sandbox bash", async () => {
950
+ await expectFloored("bash", { command: "ls" });
951
+ });
952
+
953
+ test.each([
954
+ ["hooks", "hooks/on-message.ts"],
955
+ ["plugins", "plugins/acme/register.ts"],
956
+ ["skills", "skills/acme/SKILL.md"],
957
+ ["tools", "tools/acme.ts"],
958
+ ["routes", "routes/acme.ts"],
959
+ ["workflows", "workflows/acme.ts"],
960
+ ])("a write into %s/ — code the daemon runs later", async (_dir, path) => {
961
+ await expectFloored("file_write", { path, content: "x" });
962
+ });
963
+
964
+ // Prompt surfaces are instructions the daemon obeys — rewriting them is
965
+ // the same delegation as planting code, one layer up.
966
+ test.each([
967
+ ["the assistant's own instructions", "SOUL.md"],
968
+ ["its identity", "IDENTITY.md"],
969
+ ["a per-user context file", "users/someone.md"],
970
+ ["a per-channel context file", "channels/general.md"],
971
+ [
972
+ "a system-section override",
973
+ "prompts/system/10a-non-guardian-boundary.md",
974
+ ],
975
+ ])("a write to %s — %s", async (_label, path) => {
976
+ await expectFloored("file_write", { path, content: "x" });
977
+ });
978
+
979
+ // Nothing reviewed an unvetted manifest, so the risk it claims about
980
+ // itself must not be what decides whether a room may run it unattended.
981
+ test("an unvetted skill shadowing a core side-effect tool", async () => {
982
+ skillOwnerBundled = false;
983
+ await expectFloored("document_create", { title: "x" });
984
+ });
985
+
986
+ // A novel name is in no side-effect list, so without the unvetted check it
987
+ // would not be gated at all — the case the shadowing guard alone misses.
988
+ test("an unvetted skill tool with a name of its own", async () => {
989
+ skillOwnerBundled = false;
990
+ await expectFloored("acme_send", { to: "someone" });
991
+ });
992
+
993
+ // Workspace-owned tools are dynamic-imported on-disk code with no
994
+ // bundled tier — unvetted by definition, whatever the bundled flag says.
995
+ test("a workspace-owned tool with a name of its own", async () => {
996
+ skillOwnerBundled = true;
997
+ await expectFloored("ws_deploy", { target: "prod" });
998
+ });
999
+
1000
+ // A workspace tool registered over a delegable core name must not
1001
+ // inherit that name's liftability — the owner decides, not the name.
1002
+ test("a workspace override of a delegable core tool", async () => {
1003
+ fileWriteOwner = { kind: "workspace", id: "tools/file-write.ts" };
1004
+ await expectFloored("file_write", {
1005
+ path: "notes/todo.md",
1006
+ content: "x",
1007
+ });
1008
+ });
1009
+
1010
+ // MCP tools are floored as host reach; this pins that the unvetted
1011
+ // allowlist catches them independently, so the floor does not hinge on
1012
+ // the host stamp alone.
1013
+ test("an MCP-owned tool, even without the host target", async () => {
1014
+ await expectFloored("mcp_lookup", { query: "q" });
1015
+ });
1016
+
1017
+ // The private network is the guardian's machine: the daemon's own HTTP
1018
+ // surface, the gateway, whatever else is listening there.
1019
+ test("web_fetch reaching the private network", async () => {
1020
+ await expectFloored("web_fetch", {
1021
+ url: "http://localhost:7821/",
1022
+ allow_private_network: true,
1023
+ });
1024
+ });
1025
+ });
1026
+
1027
+ test("a public web_fetch is still lifted", async () => {
1028
+ thresholdReaderMock.cell = cell("low");
1029
+
1030
+ const result = await handler.checkPreExecutionGates(
1031
+ "web_fetch",
1032
+ { url: "https://example.com/" },
1033
+ channelContext(),
1034
+ "low",
1035
+ Date.now(),
1036
+ );
1037
+
1038
+ expect(result.allowed).toBe(true);
1039
+ });
1040
+
1041
+ // A successful cascade walk that finds no cell resolves the room's
1042
+ // default — Conservative — so an unconfigured room behaves exactly as the
1043
+ // picker and legend present it. (The mock's reset state IS the successful
1044
+ // no-cell resolution.)
1045
+ test("an unconfigured room lifts at the Conservative default", async () => {
1046
+ const result = await handler.checkPreExecutionGates(
1047
+ "file_write",
1048
+ { path: "notes/todo.md", content: "x" },
1049
+ channelContext(),
1050
+ "low",
1051
+ Date.now(),
1052
+ );
1053
+
1054
+ expect(result.allowed).toBe(true);
1055
+ expect(thresholdReaderMock.cellLookups).toBe(1);
1056
+ });
1057
+
1058
+ // The room default is the owner's global setting collapsed — a Strict
1059
+ // global yields Strict rooms, so nothing lifts.
1060
+ test("a Strict global keeps unconfigured rooms on the floor", async () => {
1061
+ thresholdReaderMock.roomDefault = "none";
1062
+
1063
+ const result = await handler.checkPreExecutionGates(
1064
+ "file_write",
1065
+ { path: "notes/todo.md", content: "x" },
1066
+ channelContext(),
1067
+ "low",
1068
+ Date.now(),
1069
+ );
1070
+
1071
+ expect(result.allowed).toBe(false);
1072
+ });
1073
+
1074
+ // An unreadable global lifts nothing — the default derives from it, so
1075
+ // without it the floor stands.
1076
+ test("an unreadable global keeps unconfigured rooms on the floor", async () => {
1077
+ thresholdReaderMock.roomDefault = undefined;
1078
+
1079
+ const result = await handler.checkPreExecutionGates(
1080
+ "file_write",
1081
+ { path: "notes/todo.md", content: "x" },
1082
+ channelContext(),
1083
+ "low",
1084
+ Date.now(),
1085
+ );
1086
+
1087
+ expect(result.allowed).toBe(false);
1088
+ });
1089
+
1090
+ // A write whose target cannot be resolved is never liftable — without a
1091
+ // workingDir the sink check cannot see where the write lands, and it must
1092
+ // fail closed rather than be skipped.
1093
+ test("a write with no workingDir stays floored at any cell", async () => {
1094
+ thresholdReaderMock.cell = cell("high");
1095
+
1096
+ const result = await handler.checkPreExecutionGates(
1097
+ "file_write",
1098
+ { path: "hooks/evil.ts", content: "x" },
1099
+ channelContext({ workingDir: undefined }),
1100
+ "low",
1101
+ Date.now(),
1102
+ );
1103
+
1104
+ expect(result.allowed).toBe(false);
1105
+ expect(thresholdReaderMock.cellLookups).toBe(0);
1106
+ });
1107
+
1108
+ // The exclusions are about provenance and reach, not about naming: an
1109
+ // ordinary workspace write is still delegable.
1110
+ test("an ordinary workspace file write is still lifted", async () => {
1111
+ thresholdReaderMock.cell = cell("high");
1112
+
1113
+ const result = await handler.checkPreExecutionGates(
1114
+ "file_write",
1115
+ { path: "notes/todo.md", content: "x" },
1116
+ channelContext(),
1117
+ "low",
1118
+ Date.now(),
1119
+ );
1120
+
1121
+ expect(result.allowed).toBe(true);
1122
+ if (!result.allowed) {
1123
+ return;
1124
+ }
1125
+ expect(result.grantConsumed).toBeFalsy();
1126
+ });
1127
+
1128
+ test("a bundled skill's side-effect tool is still lifted", async () => {
1129
+ thresholdReaderMock.cell = cell("high");
1130
+ skillOwnerBundled = true;
1131
+
1132
+ const result = await handler.checkPreExecutionGates(
1133
+ "document_create",
1134
+ { title: "x" },
1135
+ channelContext(),
1136
+ "low",
1137
+ Date.now(),
1138
+ );
1139
+
1140
+ expect(result.allowed).toBe(true);
1141
+ });
1142
+
1143
+ test("a guardian never pays for the cell lookup", async () => {
1144
+ const result = await handler.checkPreExecutionGates(
1145
+ toolName,
1146
+ input,
1147
+ channelContext({ trustClass: "guardian" }),
1148
+ "low",
1149
+ Date.now(),
1150
+ );
1151
+
1152
+ expect(result.allowed).toBe(true);
1153
+ expect(thresholdReaderMock.cellLookups).toBe(0);
1154
+ });
1155
+
1156
+ test("a turn with no channel coordinates skips the lookup", async () => {
1157
+ const result = await handler.checkPreExecutionGates(
1158
+ toolName,
1159
+ input,
1160
+ makeContext({ trustClass: "trusted_contact" }),
1161
+ "low",
1162
+ Date.now(),
1163
+ );
1164
+
1165
+ expect(result.allowed).toBe(false);
1166
+ expect(thresholdReaderMock.cellLookups).toBe(0);
1167
+ });
1168
+ });
1169
+
626
1170
  describe("ToolApprovalHandler / unparseable tool args gate", () => {
627
1171
  const handler = new ToolApprovalHandler();
628
1172