@vellumai/assistant 0.11.4 → 0.11.5-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 (358) hide show
  1. package/AGENTS.md +2 -2
  2. package/ARCHITECTURE.md +29 -4
  3. package/README.md +1 -1
  4. package/docs/architecture/memory.md +17 -5
  5. package/docs/architecture/security.md +96 -152
  6. package/docs/guardian-request-flow.md +13 -2
  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__/url-normalization.test.ts +135 -0
  9. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  10. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  11. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  12. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  13. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  14. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  15. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
  16. package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +7 -14
  17. package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
  18. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +29 -31
  19. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  20. package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
  21. package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
  22. package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
  23. package/openapi.yaml +193 -3
  24. package/package.json +1 -1
  25. package/src/__tests__/anthropic-provider.test.ts +10 -3
  26. package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
  27. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  28. package/src/__tests__/channel-approval-routes.test.ts +4 -0
  29. package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -6
  30. package/src/__tests__/channel-reply-delivery.test.ts +26 -13
  31. package/src/__tests__/checker.test.ts +20 -314
  32. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
  33. package/src/__tests__/client-os-metadata-persistence.test.ts +16 -0
  34. package/src/__tests__/compactor-retained-image-validation.test.ts +142 -0
  35. package/src/__tests__/container-cpu-sampler.test.ts +153 -0
  36. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
  37. package/src/__tests__/conversation-attachments.test.ts +0 -1
  38. package/src/__tests__/conversation-error.test.ts +17 -0
  39. package/src/__tests__/conversation-lifecycle.test.ts +20 -26
  40. package/src/__tests__/conversation-pairing.test.ts +186 -0
  41. package/src/__tests__/conversation-runtime-assembly.test.ts +21 -2
  42. package/src/__tests__/credential-broker-server-use.test.ts +24 -5
  43. package/src/__tests__/credential-routes.test.ts +22 -3
  44. package/src/__tests__/credential-security-invariants.test.ts +2 -1
  45. package/src/__tests__/daemon-credential-client.test.ts +88 -0
  46. package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
  47. package/src/__tests__/dm-backfill.test.ts +63 -0
  48. package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
  49. package/src/__tests__/edit-propagation.test.ts +107 -4
  50. package/src/__tests__/events-client-registration.test.ts +28 -0
  51. package/src/__tests__/file-write-tool.test.ts +4 -2
  52. package/src/__tests__/guardian-prompt-notice-privacy.test.ts +133 -0
  53. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +143 -97
  54. package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
  55. package/src/__tests__/host-proxy-interface.test.ts +11 -1
  56. package/src/__tests__/host-shell-tool.test.ts +23 -4
  57. package/src/__tests__/image-conversion.test.ts +143 -1
  58. package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
  59. package/src/__tests__/input-repairs.test.ts +207 -0
  60. package/src/__tests__/live-workspace-guard.test.ts +75 -0
  61. package/src/__tests__/mcp-abort-signal.test.ts +1 -1
  62. package/src/__tests__/mcp-client-auth.test.ts +1 -1
  63. package/src/__tests__/mcp-tool-annotations-risk.test.ts +1 -1
  64. package/src/__tests__/media-resolve-image-validation.test.ts +310 -0
  65. package/src/__tests__/mtime-cache.test.ts +2 -0
  66. package/src/__tests__/notification-vellum-adapter.test.ts +124 -1
  67. package/src/__tests__/openai-provider.test.ts +22 -0
  68. package/src/__tests__/personal-memory-auth-bypass.test.ts +22 -6
  69. package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
  70. package/src/__tests__/platform.test.ts +16 -1
  71. package/src/__tests__/plugin-api-resolve-credential.test.ts +22 -13
  72. package/src/__tests__/plugin-api-shim.test.ts +5 -0
  73. package/src/__tests__/plugin-api-store-credential.test.ts +268 -0
  74. package/src/__tests__/plugin-config-data-migration.test.ts +8 -1
  75. package/src/__tests__/plugin-disabled-state.test.ts +2 -0
  76. package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
  77. package/src/__tests__/plugin-execution-context.test.ts +73 -0
  78. package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -1
  79. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +0 -1
  80. package/src/__tests__/reaction-persistence.test.ts +200 -7
  81. package/src/__tests__/require-fresh-approval.test.ts +0 -4
  82. package/src/__tests__/resource-pressure-guard.test.ts +428 -0
  83. package/src/__tests__/resource-pressure-routes.test.ts +113 -0
  84. package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
  85. package/src/__tests__/run-conversation-turn-persistence.test.ts +27 -1
  86. package/src/__tests__/secret-routes-platform-proxy.test.ts +7 -0
  87. package/src/__tests__/skill-tool-factory.test.ts +161 -0
  88. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  89. package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
  90. package/src/__tests__/tool-executor.test.ts +63 -38
  91. package/src/__tests__/tool-policy.test.ts +97 -1
  92. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +7 -4
  93. package/src/__tests__/user-plugin-loader.test.ts +2 -0
  94. package/src/__tests__/validate-input.test.ts +243 -7
  95. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  96. package/src/acp/__tests__/acp-claude-oauth.test.ts +97 -29
  97. package/src/acp/__tests__/prepare-agent-env.test.ts +376 -153
  98. package/src/acp/acp-claude-oauth.ts +38 -21
  99. package/src/acp/prepare-agent-env.ts +146 -55
  100. package/src/agent/loop-tool-dedup.test.ts +161 -0
  101. package/src/agent/loop.ts +68 -22
  102. package/src/api/constants/app-tools.ts +34 -0
  103. package/src/api/events/resource-pressure-status-changed.ts +53 -0
  104. package/src/api/index.ts +19 -0
  105. package/src/api/responses/resource-pressure-status.ts +25 -0
  106. package/src/approvals/guardian-channel-delivery.ts +70 -6
  107. package/src/approvals/guardian-request-resolvers.ts +32 -66
  108. package/src/channels/__tests__/message-audience.test.ts +49 -0
  109. package/src/channels/__tests__/types.test.ts +17 -3
  110. package/src/channels/message-audience.ts +40 -0
  111. package/src/channels/types.ts +16 -12
  112. package/src/cli/__tests__/catalog-search-help.test.ts +50 -0
  113. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +31 -0
  114. package/src/cli/commands/__tests__/conversations-search.test.ts +289 -0
  115. package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
  116. package/src/cli/commands/__tests__/inference-providers.test.ts +68 -0
  117. package/src/cli/commands/__tests__/keys.test.ts +89 -8
  118. package/src/cli/commands/__tests__/plugins.test.ts +57 -1
  119. package/src/cli/commands/channel-verification-sessions.help.ts +11 -9
  120. package/src/cli/commands/channel-verification-sessions.ts +11 -21
  121. package/src/cli/commands/conversations.help.ts +34 -0
  122. package/src/cli/commands/conversations.ts +125 -0
  123. package/src/cli/commands/inference-providers.ts +9 -4
  124. package/src/cli/commands/inference.help.ts +9 -4
  125. package/src/cli/commands/keys.help.ts +13 -1
  126. package/src/cli/commands/keys.ts +26 -15
  127. package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
  128. package/src/cli/commands/memory/index.help.ts +41 -27
  129. package/src/cli/commands/memory/index.ts +2 -0
  130. package/src/cli/commands/memory/memory-v2.ts +58 -54
  131. package/src/cli/commands/memory/memory-validate.ts +18 -0
  132. package/src/cli/commands/monitoring.ts +1 -0
  133. package/src/cli/commands/plugins.help.ts +28 -31
  134. package/src/cli/commands/plugins.ts +10 -0
  135. package/src/cli/commands/skills.help.ts +13 -16
  136. package/src/cli/commands/trust.ts +3 -14
  137. package/src/cli/lib/__tests__/install-from-github.test.ts +38 -0
  138. package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +34 -0
  139. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +32 -1
  140. package/src/cli/lib/__tests__/toggle-plugin.test.ts +2 -1
  141. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +64 -0
  142. package/src/cli/lib/bundled-marketplace.json +13 -0
  143. package/src/cli/lib/daemon-credential-client.ts +25 -3
  144. package/src/cli/lib/install-from-github.ts +35 -24
  145. package/src/cli/lib/merge-plugin-tree.ts +22 -4
  146. package/src/cli/lib/plugin-surfaces.ts +27 -0
  147. package/src/config/feature-flag-registry.json +35 -19
  148. package/src/config/webhook-routing.ts +8 -0
  149. package/src/context/compactor.ts +31 -2
  150. package/src/daemon/__tests__/provider-rejection-log-fields.test.ts +272 -0
  151. package/src/daemon/conversation-agent-loop-handlers.ts +4 -1
  152. package/src/daemon/conversation-error.ts +13 -0
  153. package/src/daemon/conversation-messaging.ts +22 -2
  154. package/src/daemon/conversation-process.ts +11 -0
  155. package/src/daemon/conversation-store.ts +10 -0
  156. package/src/daemon/conversation-surfaces.ts +21 -8
  157. package/src/daemon/conversation.ts +12 -10
  158. package/src/daemon/lifecycle.ts +6 -2
  159. package/src/daemon/message-types/conversations.ts +5 -7
  160. package/src/daemon/provider-rejection-log-fields.ts +124 -0
  161. package/src/daemon/resource-pressure-guard-lifecycle.ts +66 -0
  162. package/src/daemon/resource-pressure-guard.ts +387 -0
  163. package/src/daemon/shutdown-handlers.ts +2 -0
  164. package/src/daemon/startup-error.ts +16 -0
  165. package/src/daemon/trust-context.ts +14 -10
  166. package/src/daemon/unsendable-image-notice.ts +76 -0
  167. package/src/hooks/registry.ts +65 -51
  168. package/src/ipc/__tests__/socket-path.test.ts +15 -7
  169. package/src/ipc/gateway-client.test.ts +1 -1
  170. package/src/ipc/gateway-client.ts +14 -21
  171. package/src/ipc/socket-cleanup.ts +2 -11
  172. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +1 -1
  173. package/src/messaging/provider-message-metadata.ts +128 -0
  174. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +116 -68
  175. package/src/messaging/providers/channel-transport.ts +90 -13
  176. package/src/messaging/providers/discord/send.ts +16 -0
  177. package/src/messaging/providers/discord/transport.ts +11 -1
  178. package/src/messaging/providers/index.ts +109 -16
  179. package/src/messaging/providers/slack/message-metadata.ts +45 -0
  180. package/src/messaging/providers/slack/render-transcript.ts +1 -4
  181. package/src/messaging/providers/slack/send.test.ts +6 -9
  182. package/src/messaging/providers/slack/send.ts +40 -28
  183. package/src/messaging/providers/slack/transport.ts +22 -26
  184. package/src/messaging/providers/telegram-bot/send.test.ts +2 -8
  185. package/src/messaging/providers/telegram-bot/transport.ts +3 -6
  186. package/src/messaging/read-provider-metadata.test.ts +157 -0
  187. package/src/messaging/read-provider-metadata.ts +51 -0
  188. package/src/notifications/__tests__/assistant-reply-producer.test.ts +94 -0
  189. package/src/notifications/__tests__/edit-notification.test.ts +174 -2
  190. package/src/notifications/__tests__/home-feed-side-effect.test.ts +536 -4
  191. package/src/notifications/adapters/macos.ts +55 -0
  192. package/src/notifications/adapters/slack.ts +10 -5
  193. package/src/notifications/assistant-reply-producer.ts +37 -4
  194. package/src/notifications/conversation-pairing.ts +111 -21
  195. package/src/notifications/edit-notification.ts +38 -8
  196. package/src/notifications/emit-signal.ts +12 -14
  197. package/src/notifications/home-feed-side-effect.ts +218 -15
  198. package/src/notifications/types.ts +5 -0
  199. package/src/permissions/AGENTS.md +16 -0
  200. package/src/permissions/checker.test.ts +75 -122
  201. package/src/permissions/checker.ts +44 -560
  202. package/src/permissions/confirmation-guardian-request.test.ts +28 -3
  203. package/src/permissions/confirmation-guardian-request.ts +5 -1
  204. package/src/persistence/conversation-crud.ts +23 -20
  205. package/src/persistence/conversation-queries.ts +14 -1
  206. package/src/persistence/conversation-types.ts +22 -0
  207. package/src/persistence/delivery-crud.ts +122 -15
  208. package/src/plugin-api/__tests__/import-graph-partial-mock.test.ts +67 -0
  209. package/src/plugin-api/conversation-turn.ts +27 -0
  210. package/src/plugin-api/credential-scope.test.ts +15 -0
  211. package/src/plugin-api/credential-scope.ts +14 -0
  212. package/src/plugin-api/index.ts +19 -1
  213. package/src/plugin-api/resolve-credential.ts +15 -10
  214. package/src/plugin-api/store-credential.ts +148 -0
  215. package/src/plugin-api/system-card.ts +36 -0
  216. package/src/plugin-api/vision-support.test.ts +82 -0
  217. package/src/plugin-api/vision-support.ts +14 -2
  218. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +361 -110
  219. package/src/plugins/defaults/image-fallback/__tests__/vision-recovery.test.ts +4 -0
  220. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +58 -0
  221. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +64 -23
  222. package/src/plugins/defaults/image-recovery/detect.ts +24 -1
  223. package/src/plugins/defaults/main.ts +15 -0
  224. package/src/plugins/defaults/memory/AGENTS.md +11 -3
  225. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
  226. package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +9 -12
  227. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
  228. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
  229. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +114 -0
  230. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
  231. package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
  232. package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
  233. package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
  234. package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
  235. package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
  236. package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +1 -61
  237. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +68 -6
  238. package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
  239. package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
  240. package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
  241. package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
  242. package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
  243. package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
  244. package/src/plugins/defaults/memory/substrate/static-context.ts +0 -29
  245. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +3 -1
  246. package/src/plugins/defaults/memory/v3/card.ts +9 -9
  247. package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
  248. package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
  249. package/src/plugins/defaults/memory/v3/edge.ts +13 -57
  250. package/src/plugins/mtime-cache.ts +1 -1
  251. package/src/plugins/pipeline.ts +14 -7
  252. package/src/plugins/plugin-execution-context.ts +35 -11
  253. package/src/plugins/plugin-tree-walk.ts +63 -4
  254. package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
  255. package/src/providers/anthropic/client.ts +332 -241
  256. package/src/providers/connection-resolution.ts +2 -1
  257. package/src/providers/content-blocks.ts +22 -0
  258. package/src/providers/gemini/client.ts +5 -2
  259. package/src/providers/inference/__tests__/adapter-factory-litellm.test.ts +47 -1
  260. package/src/providers/inference/__tests__/adapter-factory-ollama.test.ts +83 -0
  261. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +98 -1
  262. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +38 -0
  263. package/src/providers/inference/__tests__/base-url-security.test.ts +10 -0
  264. package/src/providers/inference/__tests__/connections-ollama.test.ts +90 -0
  265. package/src/providers/inference/__tests__/missing-credential-guard.test.ts +117 -0
  266. package/src/providers/inference/adapter-factory.ts +33 -2
  267. package/src/providers/inference/auth.ts +13 -2
  268. package/src/providers/inference/credential-usage.ts +37 -0
  269. package/src/providers/inference/missing-credential-guard.ts +110 -0
  270. package/src/providers/inference/resolve-auth.ts +7 -7
  271. package/src/providers/media-resolve.ts +176 -15
  272. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +576 -46
  273. package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
  274. package/src/providers/openai/chat-completions-provider.ts +322 -42
  275. package/src/routes/route-host-protocol.ts +7 -0
  276. package/src/routes/worker.ts +31 -10
  277. package/src/runtime/AGENTS.md +35 -0
  278. package/src/runtime/__tests__/runtime-http-port-collision.test.ts +131 -0
  279. package/src/runtime/__tests__/web-presence.test.ts +234 -0
  280. package/src/runtime/assistant-event-hub.ts +38 -0
  281. package/src/runtime/channel-reply-delivery.ts +54 -31
  282. package/src/runtime/channel-retry-sweep.ts +6 -4
  283. package/src/runtime/effective-capabilities.test.ts +19 -0
  284. package/src/runtime/effective-capabilities.ts +25 -0
  285. package/src/runtime/guardian-reply-router.ts +6 -2
  286. package/src/runtime/http-errors.ts +1 -0
  287. package/src/runtime/http-server.ts +20 -5
  288. package/src/runtime/routes/__tests__/client-routes.test.ts +150 -0
  289. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +133 -0
  290. package/src/runtime/routes/__tests__/credential-delete-in-use.test.ts +155 -0
  291. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +52 -1
  292. package/src/runtime/routes/__tests__/monitoring-routes.test.ts +1 -0
  293. package/src/runtime/routes/__tests__/pending-interactions-route.test.ts +175 -0
  294. package/src/runtime/routes/__tests__/plugins-routes.test.ts +88 -35
  295. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
  296. package/src/runtime/routes/__tests__/system-card-turn-termination.test.ts +107 -0
  297. package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
  298. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +75 -4
  299. package/src/runtime/routes/approval-routes.ts +37 -4
  300. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +16 -22
  301. package/src/runtime/routes/canned-message-complete.ts +68 -29
  302. package/src/runtime/routes/client-routes.ts +113 -0
  303. package/src/runtime/routes/conversation-list-routes.ts +22 -7
  304. package/src/runtime/routes/conversation-management-routes.ts +15 -9
  305. package/src/runtime/routes/conversation-routes.ts +36 -22
  306. package/src/runtime/routes/credential-in-use.ts +85 -0
  307. package/src/runtime/routes/credential-routes.ts +55 -85
  308. package/src/runtime/routes/guardian-approval-interception.ts +22 -22
  309. package/src/runtime/routes/guardian-approval-reply-helpers.ts +14 -12
  310. package/src/runtime/routes/identity-routes.ts +5 -121
  311. package/src/runtime/routes/inbound-message-handler.ts +71 -27
  312. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +16 -17
  313. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +77 -50
  314. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -97
  315. package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -77
  316. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +17 -8
  317. package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -7
  318. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -70
  319. package/src/runtime/routes/index.ts +2 -0
  320. package/src/runtime/routes/inference-provider-connection-routes.ts +9 -7
  321. package/src/runtime/routes/monitoring-routes.ts +9 -1
  322. package/src/runtime/routes/plugins-routes.ts +17 -5
  323. package/src/runtime/routes/resource-pressure-routes.ts +22 -0
  324. package/src/runtime/routes/secret-routes.ts +39 -8
  325. package/src/runtime/routes/settings-routes.ts +6 -6
  326. package/src/runtime/routes/surface-action-routes.ts +20 -19
  327. package/src/runtime/routes/user-route-dispatcher.ts +31 -2
  328. package/src/runtime/routes/user-route-resolution.ts +18 -1
  329. package/src/runtime/slack-reply-session.test.ts +23 -13
  330. package/src/runtime/slack-reply-session.ts +38 -55
  331. package/src/runtime/web-presence.ts +90 -0
  332. package/src/skills/validate-input.ts +177 -40
  333. package/src/subagent/__tests__/consult-context-gating.test.ts +6 -10
  334. package/src/subagent/consult-context.ts +7 -23
  335. package/src/tools/credentials/broker.ts +24 -79
  336. package/src/tools/credentials/ref-parse.ts +35 -0
  337. package/src/tools/credentials/resolve.ts +4 -10
  338. package/src/tools/credentials/store.ts +168 -0
  339. package/src/tools/credentials/tool-policy.ts +67 -0
  340. package/src/tools/executor.ts +53 -15
  341. package/src/tools/network/__tests__/web-search.test.ts +41 -1
  342. package/src/tools/network/url-safety.ts +9 -16
  343. package/src/tools/network/web-search.ts +21 -3
  344. package/src/tools/permission-checker.ts +43 -52
  345. package/src/tools/schema-transforms.ts +40 -5
  346. package/src/tools/shared/input-repairs.ts +160 -0
  347. package/src/tools/skills/skill-tool-factory.ts +18 -4
  348. package/src/tools/subagent/spawn.ts +0 -1
  349. package/src/tools/tool-approval-handler.ts +16 -10
  350. package/src/tools/tool-types.ts +26 -13
  351. package/src/tools/types.ts +6 -6
  352. package/src/util/__tests__/cgroup-memory.test.ts +3 -0
  353. package/src/util/cgroup-memory.ts +3 -0
  354. package/src/util/container-cpu-sampler.ts +250 -0
  355. package/src/util/image-conversion.ts +178 -14
  356. package/src/util/platform.ts +93 -10
  357. package/src/permissions/ipc-risk-types.ts +0 -143
  358. package/src/permissions/risk-types.ts +0 -76
@@ -1,13 +1,18 @@
1
+ import type {
2
+ RiskAllowlistOption,
3
+ RiskDirectoryScopeOption,
4
+ RiskPatternScopeOption,
5
+ } from "@vellumai/gateway-client";
6
+
1
7
  import { getIsContainerized } from "../config/env-registry.js";
2
8
  import { mapApprovalProvenance } from "../permissions/approval-provenance.js";
3
9
  import { buildChannelPermissionCellQuery } from "../permissions/channel-permission-query.js";
4
10
  import {
5
11
  check,
6
12
  classifyRisk,
7
- generateAllowlistOptions,
8
13
  generateScopeOptions,
9
- getCachedAssessment,
10
14
  isDynamicSkillLoadInvocation,
15
+ type RiskClassificationWithMeta,
11
16
  } from "../permissions/checker.js";
12
17
  import { getAutoApproveThreshold } from "../permissions/gateway-threshold-reader.js";
13
18
  import type { PermissionPrompter } from "../permissions/prompter.js";
@@ -37,19 +42,15 @@ export type PermissionDecision =
37
42
  decision: string;
38
43
  riskLevel: string;
39
44
  wasPrompted?: boolean;
40
- /** ID of the trust rule that matched this invocation (if any). Always set when a rule matched, even for non-classifier tools where riskMeta is absent. */
45
+ /** ID of the trust rule that matched this invocation (if any). */
41
46
  matchedTrustRuleId?: string;
42
- /** Risk metadata from the classifier assessment cache (when available). */
43
- riskMeta?: {
47
+ /** Risk metadata from the invocation's classification. */
48
+ riskMeta: {
44
49
  riskLevel: string;
45
50
  riskReason: string;
46
- riskScopeOptions: Array<{ pattern: string; label: string }>;
47
- riskAllowlistOptions?: Array<{
48
- label: string;
49
- description: string;
50
- pattern: string;
51
- }>;
52
- riskDirectoryScopeOptions?: Array<{ scope: string; label: string }>;
51
+ riskScopeOptions: RiskPatternScopeOption[];
52
+ riskAllowlistOptions?: RiskAllowlistOption[];
53
+ riskDirectoryScopeOptions?: RiskDirectoryScopeOption[];
53
54
  isContainerized?: boolean;
54
55
  };
55
56
  approvalMode?: ApprovalMode;
@@ -61,19 +62,15 @@ export type PermissionDecision =
61
62
  decision: string;
62
63
  riskLevel: string;
63
64
  content: string;
64
- /** ID of the trust rule that matched this invocation (if any). Always set when a rule matched, even for non-classifier tools where riskMeta is absent. */
65
+ /** ID of the trust rule that matched this invocation (if any). */
65
66
  matchedTrustRuleId?: string;
66
- /** Risk metadata from the classifier assessment cache (when available). */
67
- riskMeta?: {
67
+ /** Risk metadata from the invocation's classification. */
68
+ riskMeta: {
68
69
  riskLevel: string;
69
70
  riskReason: string;
70
- riskScopeOptions: Array<{ pattern: string; label: string }>;
71
- riskAllowlistOptions?: Array<{
72
- label: string;
73
- description: string;
74
- pattern: string;
75
- }>;
76
- riskDirectoryScopeOptions?: Array<{ scope: string; label: string }>;
71
+ riskScopeOptions: RiskPatternScopeOption[];
72
+ riskAllowlistOptions?: RiskAllowlistOption[];
73
+ riskDirectoryScopeOptions?: RiskDirectoryScopeOption[];
77
74
  isContainerized?: boolean;
78
75
  };
79
76
  approvalMode?: ApprovalMode;
@@ -89,10 +86,13 @@ export class PermissionChecker {
89
86
  }
90
87
 
91
88
  /**
92
- * Run risk classification, trust rule evaluation, and (if needed) user
93
- * prompting for a tool invocation. Returns whether the tool is allowed
94
- * to execute, along with the decision string and risk level for lifecycle
95
- * event reporting.
89
+ * Run trust rule evaluation and (if needed) user prompting for a tool
90
+ * invocation. Returns whether the tool is allowed to execute, along with
91
+ * the decision string and risk level for lifecycle event reporting.
92
+ *
93
+ * `classification` is the invocation's gateway classification when the
94
+ * executor already holds it (it classifies once, before its gates); absent
95
+ * that, the same input is classified here.
96
96
  */
97
97
  async checkPermission(
98
98
  name: string,
@@ -113,10 +113,11 @@ export class PermissionChecker {
113
113
  }
114
114
  | undefined
115
115
  >,
116
+ classification?: RiskClassificationWithMeta,
116
117
  ): Promise<PermissionDecision> {
117
118
  // Sandbox/host routing for the prompt comes from the tool's manifest.
118
119
  const executionTarget = resolveExecutionTarget(tool);
119
- const { level: risk, reason: riskReason } = await classifyRisk(
120
+ classification ??= await classifyRisk(
120
121
  name,
121
122
  input,
122
123
  context.workingDir,
@@ -124,26 +125,19 @@ export class PermissionChecker {
124
125
  undefined,
125
126
  context.signal,
126
127
  );
128
+ const { level: risk, reason: riskReason } = classification;
127
129
  const riskLevel: string = risk;
128
130
 
129
- // Look up the cached assessment to extract risk metadata for the tool result.
130
- // This is populated by classifyRisk() for classifier-backed tools (bash, file, web, skill).
131
- // For tools without classifiers (e.g. MCP tools), the cache returns undefined.
132
- const cachedAssessment = getCachedAssessment(name, input);
133
- const riskMeta = cachedAssessment
134
- ? {
135
- riskLevel: cachedAssessment.riskLevel,
136
- riskReason: cachedAssessment.reason,
137
- // Display ladder (regex patterns — internal only, not for save).
138
- riskScopeOptions: cachedAssessment.scopeOptions,
139
- // Save ladder (Minimatch globs — what the gateway matches against).
140
- // Populated for classifiers that produce allowlist options
141
- // (bash, file, skill); undefined otherwise.
142
- riskAllowlistOptions: cachedAssessment.allowlistOptions,
143
- riskDirectoryScopeOptions: cachedAssessment.directoryScopeOptions,
144
- isContainerized: getIsContainerized(),
145
- }
146
- : undefined;
131
+ const riskMeta = {
132
+ riskLevel: classification.level,
133
+ riskReason: classification.reason,
134
+ // Display ladder: bash only, internal, never persisted as a rule.
135
+ riskScopeOptions: classification.scopeOptions,
136
+ // Save ladder: the patterns the gateway matches a rule by, exactly.
137
+ riskAllowlistOptions: classification.allowlistOptions,
138
+ riskDirectoryScopeOptions: classification.directoryScopeOptions,
139
+ isContainerized: getIsContainerized(),
140
+ };
147
141
 
148
142
  // Wrap the rest of permission evaluation so that any exception
149
143
  // carries the classified risk level back to the caller. Without
@@ -158,6 +152,7 @@ export class PermissionChecker {
158
152
  policyContext,
159
153
  undefined,
160
154
  context.signal,
155
+ classification,
161
156
  );
162
157
 
163
158
  // Every threshold read for this invocation must consult the same
@@ -240,7 +235,7 @@ export class PermissionChecker {
240
235
  if (
241
236
  context.isInteractive === false &&
242
237
  isDynamicSkillLoadInvocation(name, input) &&
243
- getCachedAssessment(name, input)?.matchType !== "user_rule"
238
+ classification.matchType !== "user_rule"
244
239
  ) {
245
240
  log.info(
246
241
  { toolName: name, riskLevel },
@@ -385,11 +380,7 @@ export class PermissionChecker {
385
380
  context.workingDir,
386
381
  );
387
382
  const promptOptions = {
388
- allowlistOptions: await generateAllowlistOptions(
389
- name,
390
- input,
391
- context.signal,
392
- ),
383
+ allowlistOptions: classification.allowlistOptions ?? [],
393
384
  scopeOptions: generateScopeOptions(context.workingDir, name),
394
385
  persistentDecisionsAllowed: !context.requireFreshApproval,
395
386
  };
@@ -410,7 +401,7 @@ export class PermissionChecker {
410
401
  context.toolUseId,
411
402
  riskReason,
412
403
  getIsContainerized(),
413
- cachedAssessment?.directoryScopeOptions,
404
+ classification.directoryScopeOptions,
414
405
  );
415
406
 
416
407
  const decision = response.decision;
@@ -6,6 +6,45 @@ import type { ToolDefinition } from "../providers/types.js";
6
6
  */
7
7
  export const ACTIVITY_SKIP_SET = new Set<string>();
8
8
 
9
+ /** The status field injected into every advertised tool input schema. */
10
+ export const ACTIVITY_FIELD = "activity";
11
+
12
+ const ACTIVITY_PROPERTY = {
13
+ type: "string",
14
+ description:
15
+ "Brief, natural description of what you're doing, shown as a live status update (e.g. 'Checking your project settings')",
16
+ };
17
+
18
+ /**
19
+ * Add the injected `activity` property to a schema, so a validator checking a
20
+ * call against the tool's own schema accepts the field the advertised schema
21
+ * asked the model to send.
22
+ *
23
+ * `injectActivityField` rewrites the definitions the model sees, not the
24
+ * manifest a skill tool validates against, so without this the model is
25
+ * offered a field its own tool then rejects as unknown. The property is added
26
+ * but never the `required` entry: the advertised copy asks for it, and a call
27
+ * that leaves it out is still a call the tool can serve.
28
+ */
29
+ export function withActivityProperty(
30
+ schema: Record<string, unknown> | undefined,
31
+ ): Record<string, unknown> | undefined {
32
+ if (!schema || schema.type !== "object") {
33
+ return schema;
34
+ }
35
+ const properties = schema.properties;
36
+ if (typeof properties !== "object" || properties === null) {
37
+ return schema;
38
+ }
39
+ if (schemaDefinesProperty(schema, ACTIVITY_FIELD)) {
40
+ return schema;
41
+ }
42
+ return {
43
+ ...schema,
44
+ properties: { ...properties, [ACTIVITY_FIELD]: ACTIVITY_PROPERTY },
45
+ };
46
+ }
47
+
9
48
  /**
10
49
  * Injects an `activity` string property into each tool definition's input
11
50
  * schema, unless the tool is in the skip set, already has an activity field,
@@ -46,11 +85,7 @@ export function injectActivityField(
46
85
  // Deep clone to avoid mutating shared refs
47
86
  const newProperties = {
48
87
  ...properties,
49
- activity: {
50
- type: "string",
51
- description:
52
- "Brief, natural description of what you're doing, shown as a live status update (e.g. 'Checking your project settings')",
53
- },
88
+ [ACTIVITY_FIELD]: ACTIVITY_PROPERTY,
54
89
  };
55
90
  const existingRequired = Array.isArray(schema.required)
56
91
  ? [...schema.required, "activity"]
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Pre-validation repairs for bundled tool calls whose arguments arrive in a
3
+ * shape the tool did not declare but whose intent is unambiguous.
4
+ *
5
+ * The sibling module `input-misuse.ts` answers a misused parameter shape with
6
+ * a better error message. This one answers the shapes we can act on instead:
7
+ * the call carries what the tool needs, spelled the way the surrounding prose
8
+ * asks for it rather than the way the schema declares it, so rewriting it is
9
+ * closer to the caller's intent than rejecting it. Repairs run before
10
+ * `validateInputAgainstSchema`, so a repaired call validates on its merits and
11
+ * anything left unrepaired keeps its normal error.
12
+ *
13
+ * Generic, schema-derivable coercions (a string holding a JSON array, one
14
+ * element where a list was expected) belong in `skills/validate-input.ts`.
15
+ * What lives here is knowledge of a specific tool's contract that no schema
16
+ * states.
17
+ *
18
+ * Rules describe the first-party tools that ship in `bundled-skills/`, and
19
+ * tool names are not reserved: a managed, workspace, extra, or plugin skill
20
+ * may define its own `scaffold_managed_skill` with a different contract. The
21
+ * `bundled` prefix on the export is the reminder that callers must establish
22
+ * bundled provenance before applying a repair.
23
+ */
24
+
25
+ import { isPlainObject } from "../../util/object.js";
26
+
27
+ interface ToolInputRepairRules {
28
+ /**
29
+ * Parameter spellings the tool accepts as another parameter's name.
30
+ *
31
+ * Each entry is a name the prose around the tool uses for a parameter the
32
+ * schema declares under a different one, and models follow prose over
33
+ * schema. `scaffold_managed_skill` declares `body_markdown` while the
34
+ * skill-authoring prose talks throughout about writing "the body"; the
35
+ * retrospective prompt tells the model to call `find_similar_skills` with a
36
+ * short description, which the schema declares as `goal`.
37
+ *
38
+ * An alias applies only when the canonical parameter is absent, so a call
39
+ * that spells the parameter correctly is never overwritten.
40
+ */
41
+ aliases?: Readonly<Record<string, string>>;
42
+ /** Whether the tool's `files` parameter also reads a path-keyed map. */
43
+ filesMap?: boolean;
44
+ }
45
+
46
+ const REPAIR_RULES: Readonly<Record<string, ToolInputRepairRules>> = {
47
+ scaffold_managed_skill: {
48
+ aliases: {
49
+ body: "body_markdown",
50
+ content: "body_markdown",
51
+ title: "name",
52
+ summary: "description",
53
+ },
54
+ filesMap: true,
55
+ },
56
+ find_similar_skills: {
57
+ aliases: { description: "goal", query: "goal" },
58
+ },
59
+ };
60
+
61
+ /** The properties one `files` entry declares. */
62
+ const FILE_ENTRY_KEYS: ReadonlySet<string> = new Set([
63
+ "path",
64
+ "content",
65
+ "copy_from",
66
+ ]);
67
+
68
+ /** The properties a `files` entry may carry besides its path. */
69
+ const FILE_BYTES_KEYS: ReadonlySet<string> = new Set(["content", "copy_from"]);
70
+
71
+ /**
72
+ * Read a `files` object written as a map from path to contents, the shape
73
+ * models reach for when asked for companion files keyed by where they go:
74
+ * `{"references/failure-modes.md": "..."}`, or with the entry spelled out as
75
+ * `{"scripts/run.sh": {"copy_from": "/abs/path"}}`.
76
+ *
77
+ * Returns the declared array shape, or `undefined` when any entry is not
78
+ * readable as one file, in which case the whole value is left alone: a partial
79
+ * reading would drop files the caller asked for without saying so. Guessing
80
+ * which path wins for an entry that names its own is a guess about intent
81
+ * rather than a repair, so those are left too.
82
+ */
83
+ function filesMapToEntries(
84
+ map: Record<string, unknown>,
85
+ ): unknown[] | undefined {
86
+ const entries = Object.entries(map);
87
+ // An object spelling out one entry's own fields is a single file, not a map
88
+ // of them. Reading it as a map would turn its field names into paths.
89
+ if (
90
+ entries.length === 0 ||
91
+ entries.every(([key]) => FILE_ENTRY_KEYS.has(key))
92
+ ) {
93
+ return undefined;
94
+ }
95
+ const files: Record<string, unknown>[] = [];
96
+ for (const [path, entry] of entries) {
97
+ if (!path.trim()) {
98
+ return undefined;
99
+ }
100
+ if (typeof entry === "string") {
101
+ files.push({ path, content: entry });
102
+ continue;
103
+ }
104
+ if (!isPlainObject(entry)) {
105
+ return undefined;
106
+ }
107
+ const keys = Object.keys(entry);
108
+ if (keys.length === 0 || !keys.every((key) => FILE_BYTES_KEYS.has(key))) {
109
+ return undefined;
110
+ }
111
+ files.push({ path, ...entry });
112
+ }
113
+ return files;
114
+ }
115
+
116
+ /**
117
+ * Rewrite a bundled tool's input into the shape its schema declares, when the
118
+ * arguments say what was meant unambiguously.
119
+ *
120
+ * Only call this for a tool that came from a bundled skill. `toolName` alone
121
+ * does not establish that.
122
+ *
123
+ * Pure: returns a new object when a repair applies, otherwise returns `input`
124
+ * unchanged. Never mutates `input`.
125
+ */
126
+ export function bundledToolInputRepairs(
127
+ toolName: string,
128
+ input: Record<string, unknown>,
129
+ ): Record<string, unknown> {
130
+ const rules = REPAIR_RULES[toolName];
131
+ if (!rules) {
132
+ return input;
133
+ }
134
+ let repaired: Record<string, unknown> | undefined;
135
+
136
+ for (const [alias, canonical] of Object.entries(rules.aliases ?? {})) {
137
+ if (!(alias in input) || canonical in input) {
138
+ continue;
139
+ }
140
+ repaired ??= { ...input };
141
+ repaired[canonical] = repaired[alias];
142
+ delete repaired[alias];
143
+ }
144
+
145
+ const files = input.files;
146
+ if (rules.filesMap && isPlainObject(files)) {
147
+ const entries = filesMapToEntries(files);
148
+ if (entries) {
149
+ repaired ??= { ...input };
150
+ repaired.files = entries;
151
+ }
152
+ }
153
+
154
+ return repaired ?? input;
155
+ }
156
+
157
+ /** Every alias a bundled `toolName` accepts, for drift guards. */
158
+ export function bundledToolInputAliases(toolName: string): string[] {
159
+ return Object.keys(REPAIR_RULES[toolName]?.aliases ?? {});
160
+ }
@@ -1,11 +1,14 @@
1
1
  import type { SkillToolEntry } from "../../config/skills.js";
2
2
  import { RiskLevel } from "../../permissions/types.js";
3
3
  import {
4
+ coerceArrayShapes,
4
5
  coerceStringBooleans,
5
6
  coerceStringNumbers,
6
7
  validateInputAgainstSchema,
7
8
  } from "../../skills/validate-input.js";
9
+ import { withActivityProperty } from "../schema-transforms.js";
8
10
  import { bundledToolInputMisuseMessage } from "../shared/input-misuse.js";
11
+ import { bundledToolInputRepairs } from "../shared/input-repairs.js";
9
12
  import type { ExecutionTarget } from "../tool-types.js";
10
13
  import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
11
14
  import { runSkillToolScript } from "./skill-script-runner.js";
@@ -43,11 +46,22 @@ export function createSkillTool(
43
46
  input: Record<string, unknown>,
44
47
  context: ToolContext,
45
48
  ): Promise<ToolExecutionResult> {
46
- const schema = entry.input_schema as Record<string, unknown> | undefined;
47
- const coercedInput = coerceStringNumbers(
48
- coerceStringBooleans(input, schema),
49
- schema,
49
+ // Validate against the schema the model was actually shown: tool
50
+ // definitions carry an injected `activity` field the manifest does not
51
+ // declare, and a call that fills it must not be rejected as unknown.
52
+ const schema = withActivityProperty(
53
+ entry.input_schema as Record<string, unknown> | undefined,
50
54
  );
55
+ // Tool-specific repairs first: they rewrite keys and shapes the schema
56
+ // does not describe, and the generic coercions below then see the
57
+ // declared parameter names. Repairs describe first-party tools, so only
58
+ // bundled skills consult them.
59
+ const repairedInput = bundled
60
+ ? bundledToolInputRepairs(entry.name, input)
61
+ : input;
62
+ const withBooleans = coerceStringBooleans(repairedInput, schema);
63
+ const withNumbers = coerceStringNumbers(withBooleans, schema);
64
+ const coercedInput = coerceArrayShapes(withNumbers, schema);
51
65
  const validation = validateInputAgainstSchema(
52
66
  entry.name,
53
67
  coercedInput,
@@ -595,7 +595,6 @@ async function runAdvisorConsult(args: {
595
595
  workingDir: context.workingDir,
596
596
  allowedToolNames: context.allowedToolNames,
597
597
  trustClass: context.trustClass,
598
- sourceChannel: context.executionChannel,
599
598
  enabledPluginSet: context.enabledPluginSet,
600
599
  // The parent's warm per-turn catalog keeps the synchronous on-disk
601
600
  // catalog scan out of the consult path.
@@ -136,23 +136,29 @@ const TC_GRANT_WAIT_INTERVAL_MS = 500;
136
136
  export const TC_GRANT_WAIT_MAX_MS = 60_000;
137
137
 
138
138
  /**
139
- * Resolve the wait budget for an escalated tool grant.
139
+ * Resolve how long one approval decision stays open, in milliseconds.
140
140
  *
141
- * A guardian answering an escalated tool call is making the same decision as a
142
- * local user answering a permission prompt, so both paths spend the same
141
+ * Every actor deciding a gated tool call is making the same decision as a
142
+ * local user answering a permission prompt, so every path spends the same
143
143
  * budget: `timeouts.permissionTimeoutSec` (read by `permissions/prompter.ts`).
144
- * If anything, this path needs the larger share of it: the prompter's user
145
- * already has the prompt on screen, while the guardian is notified
146
- * out-of-band and has to context-switch before deciding.
144
+ * If anything, an off-channel path needs the larger share of it: the
145
+ * prompter's user already has the prompt on screen, while a guardian is
146
+ * notified out-of-band and has to context-switch before deciding.
147
147
  *
148
148
  * Falls back to {@link TC_GRANT_WAIT_MAX_MS} rather than the tool-execution
149
149
  * default on a non-positive value, so a bad config can never collapse the
150
150
  * window to zero and auto-deny every escalation.
151
151
  *
152
- * Exported because the grant resolver sizes its `inline_wait_active` staleness
153
- * threshold off this same budget: if the two drift, an approval arriving while
154
- * a waiter is still live gets misread as a dead waiter and the requester is
155
- * told to retry a call that is about to resume on its own.
152
+ * This is the one owner of that budget, and every clock measuring the same
153
+ * window reads it here rather than restating the number:
154
+ *
155
+ * - the inline grant wait, which spends it directly;
156
+ * - the grant resolver's `inline_wait_active` staleness threshold, because if
157
+ * the two drift, an approval arriving while a waiter is still live gets
158
+ * misread as a dead waiter and the requester is told to retry a call that is
159
+ * about to resume on its own;
160
+ * - the `tool_approval` row deadline, so the card stops offering a decision at
161
+ * the same moment the prompt stops waiting for one.
156
162
  */
157
163
  export function resolveInlineGrantWaitMs(): number {
158
164
  return safeTimeoutMs(
@@ -5,9 +5,10 @@
5
5
  * Pure type-level declarations only (+ the `RiskLevel` enum, which is a
6
6
  * value). No runtime helpers live here — the assistant keeps all behavior
7
7
  * functions in `assistant/src/tools/` and re-exports the types from this
8
- * file. This module imports nothing, so it can sit at the bottom of the
9
- * import graph and be consumed by `tools/types.ts`, `providers/types.ts`,
10
- * and `permissions/types.ts` without creating cycles.
8
+ * file. This module imports nothing from `assistant/src` (only type-only
9
+ * wire shapes from `@vellumai/gateway-client`), so it can sit at the bottom
10
+ * of the import graph and be consumed by `tools/types.ts`,
11
+ * `providers/types.ts`, and `permissions/types.ts` without creating cycles.
11
12
  *
12
13
  * Heavy daemon-internal references (CES client, host-proxy classes, trust
13
14
  * classifications, interface IDs, content blocks, CES `ApprovalRequired`)
@@ -25,6 +26,12 @@
25
26
  // Simple type-level declarations — moved in full
26
27
  // ---------------------------------------------------------------------------
27
28
 
29
+ import type {
30
+ RiskAllowlistOption,
31
+ RiskDirectoryScopeOption,
32
+ RiskPatternScopeOption,
33
+ } from "@vellumai/gateway-client";
34
+
28
35
  export type ExecutionTarget = "sandbox" | "host";
29
36
 
30
37
  /** The kind of extension that owns a tool. Core tools have no owner. */
@@ -49,6 +56,14 @@ export enum RiskLevel {
49
56
  High = "high",
50
57
  }
51
58
 
59
+ /**
60
+ * `riskLevel` recorded on a `tool_invocations` audit row when the call's risk
61
+ * was never classified (classification aborted, or the gateway was
62
+ * unreachable, before any decision was reached). Distinct from every
63
+ * {@link RiskLevel} so a reader can tell "not assessed" from "assessed as low".
64
+ */
65
+ export const RISK_LEVEL_UNCLASSIFIED = "unclassified";
66
+
52
67
  export interface ToolDefinition {
53
68
  name: string;
54
69
  description: string;
@@ -162,7 +177,7 @@ export interface ToolExecutionResult {
162
177
  /** Whether the daemon is running in a containerized (Docker) environment. */
163
178
  isContainerized?: boolean;
164
179
  /** Scope options ladder for the rule editor (narrowest to broadest). */
165
- riskScopeOptions?: Array<{ pattern: string; label: string }>;
180
+ riskScopeOptions?: RiskPatternScopeOption[];
166
181
  }
167
182
 
168
183
  export type ProxyToolResolver = (
@@ -174,16 +189,14 @@ export type ProxyToolResolver = (
174
189
  // Permission prompt option ladders
175
190
  // ---------------------------------------------------------------------------
176
191
 
177
- export interface AllowlistOption {
178
- label: string;
179
- description: string;
180
- pattern: string;
181
- }
192
+ /** The prompt's "always allow" ladder entry: the gateway's wire shape. */
193
+ export type AllowlistOption = RiskAllowlistOption;
182
194
 
183
- export interface ScopeOption {
184
- label: string;
185
- scope: string;
186
- }
195
+ /**
196
+ * A directory-scope ladder entry (`scope` is a path glob or `everywhere`);
197
+ * the same wire shape the gateway emits as `directoryScopeOptions`.
198
+ */
199
+ export type ScopeOption = RiskDirectoryScopeOption;
187
200
 
188
201
  // ---------------------------------------------------------------------------
189
202
  // Tool context
@@ -1,3 +1,7 @@
1
+ import type {
2
+ RiskAllowlistOption,
3
+ RiskDirectoryScopeOption,
4
+ } from "@vellumai/gateway-client";
1
5
  import { z } from "zod";
2
6
 
3
7
  import type { AnsweredQuestion } from "../api/events/question-answered.js";
@@ -124,13 +128,9 @@ export interface ToolExecutionResult {
124
128
  * wildcards) — what the gateway actually matches against. Mirrors
125
129
  * the `allowlistOptions` field on `ConfirmationRequest` SSE events.
126
130
  */
127
- riskAllowlistOptions?: Array<{
128
- label: string;
129
- description: string;
130
- pattern: string;
131
- }>;
131
+ riskAllowlistOptions?: RiskAllowlistOption[];
132
132
  /** Directory scope ladder for the rule editor (narrowest to broadest). */
133
- riskDirectoryScopeOptions?: Array<{ scope: string; label: string }>;
133
+ riskDirectoryScopeOptions?: RiskDirectoryScopeOption[];
134
134
  /** Structured activity metadata for client rendering (web search, web fetch, etc).
135
135
  * Populated by daemon-internal tools; plugins must not set this. */
136
136
  activityMetadata?: ToolActivityMetadata;
@@ -19,6 +19,7 @@ vmalloc 0
19
19
  shmem 8192
20
20
  zswap 0
21
21
  zswapped 0
22
+ inactive_file 1073741824
22
23
  file_mapped 209715200
23
24
  file_dirty 135168
24
25
  file_writeback 0
@@ -38,6 +39,7 @@ describe("parseMemoryStat", () => {
38
39
  expect(stat).toEqual({
39
40
  anonBytes: 2147483648,
40
41
  fileBytes: 1610612736,
42
+ inactiveFileBytes: 1073741824,
41
43
  kernelBytes: 943718400,
42
44
  slabReclaimableBytes: 838860800,
43
45
  slabUnreclaimableBytes: 104857600,
@@ -72,6 +74,7 @@ describe("parseMemoryStat", () => {
72
74
  expect(parseMemoryStat("")).toEqual({
73
75
  anonBytes: null,
74
76
  fileBytes: null,
77
+ inactiveFileBytes: null,
75
78
  kernelBytes: null,
76
79
  slabReclaimableBytes: null,
77
80
  slabUnreclaimableBytes: null,
@@ -134,6 +134,8 @@ export interface ContainerMemoryStat {
134
134
  fileBytes: number | null;
135
135
  /** Total kernel memory charged to the cgroup (includes slab). */
136
136
  kernelBytes: number | null;
137
+ /** File-backed pages on the inactive LRU: readily reclaimable cache. */
138
+ inactiveFileBytes: number | null;
137
139
  /** Slab memory the kernel can reclaim under pressure (dentries, inodes). */
138
140
  slabReclaimableBytes: number | null;
139
141
  /** Slab memory pinned until explicitly freed. */
@@ -172,6 +174,7 @@ export function parseMemoryStat(raw: string): ContainerMemoryStat {
172
174
  return {
173
175
  anonBytes,
174
176
  fileBytes,
177
+ inactiveFileBytes: counts.inactive_file ?? null,
175
178
  kernelBytes: counts.kernel ?? null,
176
179
  slabReclaimableBytes,
177
180
  slabUnreclaimableBytes,