@vellumai/assistant 0.7.2 → 0.7.3

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 (347) hide show
  1. package/ARCHITECTURE.md +16 -1
  2. package/docs/architecture/memory.md +5 -2
  3. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
  4. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -9
  5. package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
  6. package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
  7. package/openapi.yaml +449 -22
  8. package/package.json +1 -1
  9. package/src/__tests__/app-control-flow.test.ts +21 -11
  10. package/src/__tests__/assistant-event-hub.test.ts +48 -0
  11. package/src/__tests__/assistant-event.test.ts +0 -10
  12. package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -7
  13. package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -0
  14. package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
  15. package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
  16. package/src/__tests__/call-conversation-messages.test.ts +8 -2
  17. package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
  18. package/src/__tests__/channel-readiness-service.test.ts +4 -2
  19. package/src/__tests__/config-loader-backfill.test.ts +379 -0
  20. package/src/__tests__/config-schema.test.ts +1 -0
  21. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +18 -9
  22. package/src/__tests__/config-watcher.test.ts +140 -69
  23. package/src/__tests__/context-search-agent-runner.test.ts +61 -3
  24. package/src/__tests__/context-search-conversations-source.test.ts +0 -24
  25. package/src/__tests__/context-search-fanout.test.ts +0 -1
  26. package/src/__tests__/context-search-memory-source.test.ts +3 -7
  27. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
  28. package/src/__tests__/context-search-pkb-source.test.ts +0 -1
  29. package/src/__tests__/context-search-workspace-source.test.ts +0 -1
  30. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  31. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
  32. package/src/__tests__/conversation-agent-loop.test.ts +454 -5
  33. package/src/__tests__/conversation-error.test.ts +150 -3
  34. package/src/__tests__/conversation-process-callsite.test.ts +43 -0
  35. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  36. package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
  37. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  38. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  39. package/src/__tests__/conversation-store.test.ts +0 -18
  40. package/src/__tests__/conversation-surfaces-app-control.test.ts +15 -4
  41. package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
  42. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
  43. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  44. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  45. package/src/__tests__/credentials-cli.test.ts +7 -0
  46. package/src/__tests__/cu-unified-flow.test.ts +176 -10
  47. package/src/__tests__/date-context.test.ts +164 -2
  48. package/src/__tests__/disk-pressure-guard.test.ts +262 -0
  49. package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
  50. package/src/__tests__/disk-pressure-policy.test.ts +241 -0
  51. package/src/__tests__/disk-pressure-routes.test.ts +379 -0
  52. package/src/__tests__/disk-pressure-tools.test.ts +277 -0
  53. package/src/__tests__/disk-usage.test.ts +150 -0
  54. package/src/__tests__/events-client-registration.test.ts +52 -0
  55. package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
  56. package/src/__tests__/file-write-tool.test.ts +4 -10
  57. package/src/__tests__/filing-service.test.ts +3 -4
  58. package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
  59. package/src/__tests__/heartbeat-service.test.ts +260 -11
  60. package/src/__tests__/host-app-control-proxy.test.ts +195 -25
  61. package/src/__tests__/host-bash-proxy.test.ts +227 -34
  62. package/src/__tests__/host-bash-routes.test.ts +178 -13
  63. package/src/__tests__/host-cu-proxy.test.ts +210 -3
  64. package/src/__tests__/host-cu-routes-targeted.test.ts +141 -12
  65. package/src/__tests__/host-file-proxy-targeted.test.ts +48 -9
  66. package/src/__tests__/host-file-proxy.test.ts +268 -6
  67. package/src/__tests__/host-file-routes-targeted.test.ts +175 -17
  68. package/src/__tests__/host-transfer-proxy-targeted.test.ts +408 -59
  69. package/src/__tests__/host-transfer-routes-targeted.test.ts +232 -17
  70. package/src/__tests__/http-user-message-parity.test.ts +107 -1
  71. package/src/__tests__/injector-chain.test.ts +18 -6
  72. package/src/__tests__/injector-disk-pressure.test.ts +224 -0
  73. package/src/__tests__/managed-profile-guard.test.ts +18 -0
  74. package/src/__tests__/mcp-abort-signal.test.ts +130 -0
  75. package/src/__tests__/memory-admin-recall.test.ts +3 -11
  76. package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
  77. package/src/__tests__/normalize-onboarding.test.ts +180 -0
  78. package/src/__tests__/oauth-connect-routes.test.ts +316 -0
  79. package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
  80. package/src/__tests__/onboarding-persona-write.test.ts +308 -0
  81. package/src/__tests__/openai-provider.test.ts +45 -8
  82. package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
  83. package/src/__tests__/platform-callback-registration.test.ts +21 -4
  84. package/src/__tests__/platform.test.ts +2 -1
  85. package/src/__tests__/playbook-execution.test.ts +0 -43
  86. package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
  87. package/src/__tests__/prechat-onboarding-contract.test.ts +214 -27
  88. package/src/__tests__/provider-tool-name.test.ts +23 -0
  89. package/src/__tests__/relay-server.test.ts +15 -4
  90. package/src/__tests__/runtime-events-sse.test.ts +4 -8
  91. package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
  92. package/src/__tests__/secret-ingress-http.test.ts +0 -1
  93. package/src/__tests__/suggestion-routes.test.ts +46 -0
  94. package/src/__tests__/twilio-validation.test.ts +2 -2
  95. package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
  96. package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
  97. package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
  98. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
  99. package/src/approvals/guardian-decision-primitive.ts +13 -0
  100. package/src/approvals/guardian-request-resolvers.ts +16 -17
  101. package/src/backup/snapshot-lock.ts +2 -27
  102. package/src/bundler/compiler-tools.ts +3 -2
  103. package/src/calls/call-conversation-messages.ts +46 -10
  104. package/src/cli/commands/__tests__/webhooks.test.ts +0 -4
  105. package/src/cli/commands/bash.ts +35 -108
  106. package/src/cli/commands/contacts.ts +64 -25
  107. package/src/cli/commands/credentials.ts +56 -0
  108. package/src/cli/commands/memory-v2.ts +7 -6
  109. package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
  110. package/src/cli/commands/oauth/connect.ts +127 -1
  111. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -3
  112. package/src/cli/commands/platform/__tests__/connect.test.ts +7 -1
  113. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
  114. package/src/cli/commands/platform/__tests__/status.test.ts +103 -6
  115. package/src/cli/commands/platform/index.ts +16 -7
  116. package/src/cli/commands/status.ts +57 -0
  117. package/src/cli/program.ts +4 -2
  118. package/src/config/assistant-feature-flags.ts +13 -3
  119. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
  120. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +13 -7
  121. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
  122. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
  123. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  124. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
  125. package/src/config/env.ts +0 -8
  126. package/src/config/feature-flag-registry.json +27 -3
  127. package/src/config/loader.ts +127 -8
  128. package/src/config/schemas/__tests__/memory-v2.test.ts +10 -5
  129. package/src/config/schemas/call-site-catalog.ts +14 -0
  130. package/src/config/schemas/channels.ts +0 -5
  131. package/src/config/schemas/heartbeat.ts +1 -1
  132. package/src/config/schemas/llm.ts +2 -0
  133. package/src/config/schemas/memory-lifecycle.ts +13 -0
  134. package/src/config/schemas/memory-v2.ts +75 -11
  135. package/src/config/schemas/platform.ts +43 -3
  136. package/src/config/schemas/services.ts +28 -0
  137. package/src/config/seed-inference-profiles.ts +230 -33
  138. package/src/contacts/contact-store.ts +0 -25
  139. package/src/daemon/__tests__/conversation-tool-setup.test.ts +86 -25
  140. package/src/daemon/assistant-attachments.ts +4 -4
  141. package/src/daemon/config-watcher.ts +85 -57
  142. package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
  143. package/src/daemon/conversation-agent-loop.ts +170 -33
  144. package/src/daemon/conversation-error.ts +87 -15
  145. package/src/daemon/conversation-lifecycle.ts +1 -3
  146. package/src/daemon/conversation-process.ts +8 -0
  147. package/src/daemon/conversation-runtime-assembly.ts +26 -0
  148. package/src/daemon/conversation-store.ts +2 -2
  149. package/src/daemon/conversation-surfaces.ts +195 -15
  150. package/src/daemon/conversation-tool-setup.ts +57 -14
  151. package/src/daemon/conversation.ts +17 -22
  152. package/src/daemon/date-context.ts +71 -22
  153. package/src/daemon/disk-pressure-background-gate.ts +73 -0
  154. package/src/daemon/disk-pressure-guard.ts +343 -0
  155. package/src/daemon/disk-pressure-policy.ts +163 -0
  156. package/src/daemon/handlers/shared.ts +0 -1
  157. package/src/daemon/handlers/skills.ts +3 -4
  158. package/src/daemon/host-app-control-proxy.ts +137 -41
  159. package/src/daemon/host-bash-proxy.ts +46 -21
  160. package/src/daemon/host-cu-proxy.ts +49 -3
  161. package/src/daemon/host-file-proxy.ts +43 -7
  162. package/src/daemon/host-transfer-proxy.ts +95 -4
  163. package/src/daemon/lifecycle.ts +79 -28
  164. package/src/daemon/meet-host-supervisor.ts +4 -4
  165. package/src/daemon/meet-manifest-loader.ts +0 -1
  166. package/src/daemon/memory-v2-startup.ts +14 -4
  167. package/src/daemon/message-protocol.ts +3 -0
  168. package/src/daemon/message-types/conversations.ts +4 -0
  169. package/src/daemon/message-types/disk-pressure.ts +9 -0
  170. package/src/daemon/message-types/messages.ts +3 -0
  171. package/src/daemon/profiler-run-store.ts +5 -5
  172. package/src/daemon/tool-setup-types.ts +2 -2
  173. package/src/documents/document-store.ts +85 -0
  174. package/src/filing/filing-service.ts +30 -5
  175. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +9 -16
  176. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +36 -0
  177. package/src/heartbeat/heartbeat-run-store.ts +13 -0
  178. package/src/heartbeat/heartbeat-service.ts +205 -31
  179. package/src/home/feed-scheduler.ts +18 -0
  180. package/src/inbound/platform-callback-registration.ts +8 -15
  181. package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
  182. package/src/ipc/assistant-server.ts +56 -2
  183. package/src/ipc/gateway-client.ts +37 -3
  184. package/src/live-voice/live-voice-archive.ts +4 -4
  185. package/src/live-voice/protocol.ts +5 -7
  186. package/src/media/image-service.ts +1 -7
  187. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
  188. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
  189. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
  190. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
  191. package/src/memory/admin.ts +5 -9
  192. package/src/memory/context-search/agent-runner.ts +19 -2
  193. package/src/memory/context-search/sources/conversations.ts +2 -11
  194. package/src/memory/context-search/sources/memory-v2.ts +5 -4
  195. package/src/memory/context-search/sources/memory.ts +0 -1
  196. package/src/memory/context-search/types.ts +0 -1
  197. package/src/memory/conversation-crud.ts +4 -12
  198. package/src/memory/db-init.ts +2 -0
  199. package/src/memory/embedding-runtime-manager.ts +119 -5
  200. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +32 -21
  201. package/src/memory/graph/conversation-graph-memory.ts +42 -54
  202. package/src/memory/graph/extraction.ts +1 -3
  203. package/src/memory/graph/graph-search.test.ts +10 -67
  204. package/src/memory/graph/graph-search.ts +1 -20
  205. package/src/memory/graph/retriever.test.ts +6 -0
  206. package/src/memory/graph/retriever.ts +6 -10
  207. package/src/memory/indexer.ts +54 -45
  208. package/src/memory/job-handlers/backfill.ts +2 -11
  209. package/src/memory/job-handlers/cleanup.ts +43 -0
  210. package/src/memory/job-handlers/embedding.ts +6 -8
  211. package/src/memory/job-handlers/summarization.ts +2 -7
  212. package/src/memory/jobs-store.ts +48 -0
  213. package/src/memory/jobs-worker.ts +81 -43
  214. package/src/memory/memory-v2-activation-log-store.ts +32 -14
  215. package/src/memory/memory-v2-concept-frequency.ts +169 -0
  216. package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
  217. package/src/memory/migrations/index.ts +1 -0
  218. package/src/memory/pkb/pkb-search.test.ts +6 -0
  219. package/src/memory/qdrant-client.ts +0 -13
  220. package/src/memory/rerank-local.ts +374 -0
  221. package/src/memory/search/semantic.ts +6 -67
  222. package/src/memory/trace-event-store.ts +1 -17
  223. package/src/memory/v2/__tests__/activation.test.ts +311 -250
  224. package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
  225. package/src/memory/v2/__tests__/injection.test.ts +157 -167
  226. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
  227. package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
  228. package/src/memory/v2/__tests__/reranker.test.ts +338 -0
  229. package/src/memory/v2/__tests__/sim.test.ts +5 -199
  230. package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
  231. package/src/memory/v2/__tests__/static-context.test.ts +76 -1
  232. package/src/memory/v2/activation.ts +149 -156
  233. package/src/memory/v2/consolidation-job.ts +62 -12
  234. package/src/memory/v2/injection.ts +47 -60
  235. package/src/memory/v2/prompts/consolidation.ts +36 -1
  236. package/src/memory/v2/qdrant.ts +99 -0
  237. package/src/memory/v2/reranker.ts +177 -0
  238. package/src/memory/v2/sim.ts +10 -84
  239. package/src/memory/v2/skill-content.ts +4 -3
  240. package/src/memory/v2/skill-store.ts +82 -59
  241. package/src/memory/v2/static-context.ts +22 -0
  242. package/src/memory/v2/types.ts +10 -10
  243. package/src/notifications/copy-composer.ts +13 -0
  244. package/src/notifications/signal.ts +4 -0
  245. package/src/oauth/AGENTS.md +3 -1
  246. package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
  247. package/src/oauth/connect-orchestrator.ts +2 -0
  248. package/src/oauth/connection-resolver.test.ts +66 -1
  249. package/src/oauth/connection-resolver.ts +55 -1
  250. package/src/oauth/oauth-connect-state.ts +77 -0
  251. package/src/oauth/seed-providers.ts +58 -1
  252. package/src/plugins/defaults/injectors.ts +35 -2
  253. package/src/plugins/defaults/memory-retrieval.ts +5 -6
  254. package/src/plugins/types.ts +7 -0
  255. package/src/proactive-artifact/aux-message-injector.ts +74 -0
  256. package/src/proactive-artifact/decision.test.ts +226 -0
  257. package/src/proactive-artifact/decision.ts +165 -0
  258. package/src/proactive-artifact/index.ts +7 -0
  259. package/src/proactive-artifact/job.test.ts +867 -0
  260. package/src/proactive-artifact/job.ts +352 -0
  261. package/src/proactive-artifact/message-copy.ts +41 -0
  262. package/src/proactive-artifact/trigger-state.test.ts +277 -0
  263. package/src/proactive-artifact/trigger-state.ts +119 -0
  264. package/src/prompts/normalize-onboarding.ts +80 -0
  265. package/src/prompts/persona-resolver.ts +101 -9
  266. package/src/prompts/system-prompt.ts +21 -7
  267. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  268. package/src/providers/__tests__/retry-callsite.test.ts +222 -1
  269. package/src/providers/model-intents.ts +7 -0
  270. package/src/providers/openrouter/client.ts +8 -0
  271. package/src/providers/retry.ts +50 -0
  272. package/src/providers/types.ts +1 -0
  273. package/src/runtime/__tests__/agent-wake.test.ts +456 -3
  274. package/src/runtime/agent-wake.ts +238 -100
  275. package/src/runtime/assistant-event-hub.ts +36 -6
  276. package/src/runtime/assistant-event.ts +0 -1
  277. package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
  278. package/src/runtime/auth/route-policy.ts +14 -1
  279. package/src/runtime/auth/same-actor.ts +216 -0
  280. package/src/runtime/channel-retry-sweep.ts +65 -1
  281. package/src/runtime/guardian-reply-router.ts +10 -0
  282. package/src/runtime/local-actor-identity.ts +52 -11
  283. package/src/runtime/pending-interactions.ts +8 -0
  284. package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
  285. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -5
  286. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  287. package/src/runtime/routes/client-routes.ts +20 -2
  288. package/src/runtime/routes/contact-routes.ts +0 -25
  289. package/src/runtime/routes/conversation-routes.ts +35 -26
  290. package/src/runtime/routes/debug-bash-routes.ts +163 -0
  291. package/src/runtime/routes/disk-pressure-routes.ts +121 -0
  292. package/src/runtime/routes/document-pdf-renderer.ts +6 -2
  293. package/src/runtime/routes/documents-routes.ts +2 -75
  294. package/src/runtime/routes/events-routes.ts +41 -9
  295. package/src/runtime/routes/host-bash-routes.ts +23 -3
  296. package/src/runtime/routes/host-cu-routes.ts +33 -6
  297. package/src/runtime/routes/host-file-routes.ts +32 -6
  298. package/src/runtime/routes/host-transfer-routes.ts +79 -16
  299. package/src/runtime/routes/identity-routes.ts +7 -138
  300. package/src/runtime/routes/inbound-message-handler.ts +77 -12
  301. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
  302. package/src/runtime/routes/index.ts +6 -0
  303. package/src/runtime/routes/memory-item-routes.test.ts +41 -15
  304. package/src/runtime/routes/memory-v2-routes.ts +33 -0
  305. package/src/runtime/routes/oauth-connect-routes.ts +153 -0
  306. package/src/runtime/verification-outbound-actions.ts +4 -4
  307. package/src/schedule/run-script.ts +37 -5
  308. package/src/schedule/scheduler.ts +20 -1
  309. package/src/security/encrypted-store.ts +2 -0
  310. package/src/security/secure-keys.ts +55 -0
  311. package/src/skills/remote-skill-policy.ts +4 -10
  312. package/src/subagent/index.ts +1 -7
  313. package/src/subagent/manager.ts +1 -15
  314. package/src/tasks/task-runner.ts +0 -1
  315. package/src/tasks/task-store.ts +0 -3
  316. package/src/tools/background-tool-registry.ts +17 -3
  317. package/src/tools/host-filesystem/edit.test.ts +151 -0
  318. package/src/tools/host-filesystem/edit.ts +43 -1
  319. package/src/tools/host-filesystem/read.test.ts +129 -0
  320. package/src/tools/host-filesystem/read.ts +43 -1
  321. package/src/tools/host-filesystem/transfer.test.ts +127 -2
  322. package/src/tools/host-filesystem/transfer.ts +56 -11
  323. package/src/tools/host-filesystem/write.test.ts +134 -0
  324. package/src/tools/host-filesystem/write.ts +43 -1
  325. package/src/tools/host-terminal/host-shell.ts +13 -6
  326. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  327. package/src/tools/memory/register.test.ts +12 -9
  328. package/src/tools/memory/register.ts +1 -2
  329. package/src/tools/provider-tool-name.ts +28 -0
  330. package/src/tools/registry.ts +30 -9
  331. package/src/tools/terminal/shell.ts +9 -1
  332. package/src/tools/tool-approval-handler.ts +31 -6
  333. package/src/tools/types.ts +24 -2
  334. package/src/tts/provider-catalog.ts +3 -5
  335. package/src/util/disk-usage.ts +138 -0
  336. package/src/util/platform.ts +21 -11
  337. package/src/util/process-liveness.ts +26 -0
  338. package/src/workspace/heartbeat-service.ts +19 -0
  339. package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
  340. package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
  341. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
  342. package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
  343. package/src/workspace/migrations/registry.ts +8 -0
  344. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
  345. package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
  346. package/src/memory/v2/skill-qdrant.ts +0 -404
  347. package/src/signals/bash.ts +0 -198
@@ -2,12 +2,22 @@ import { afterEach, describe, expect, jest, mock, test } from "bun:test";
2
2
 
3
3
  const sentMessages: unknown[] = [];
4
4
  let mockHasClient = false;
5
+ type MockClient = {
6
+ clientId: string;
7
+ capabilities: string[];
8
+ actorPrincipalId?: string;
9
+ };
10
+ let mockClients: MockClient[] = [];
5
11
 
6
12
  mock.module("../runtime/assistant-event-hub.js", () => ({
7
13
  broadcastMessage: (msg: unknown) => sentMessages.push(msg),
8
14
  assistantEventHub: {
9
15
  getMostRecentClientByCapability: (cap: string) =>
10
16
  cap === "host_cu" && mockHasClient ? { id: "mock-client" } : null,
17
+ getClientById: (id: string) =>
18
+ mockClients.find((c) => c.clientId === id) ?? undefined,
19
+ getActorPrincipalIdForClient: (id: string) =>
20
+ mockClients.find((c) => c.clientId === id)?.actorPrincipalId,
11
21
  },
12
22
  }));
13
23
 
@@ -21,6 +31,7 @@ describe("HostCuProxy", () => {
21
31
  function setup(maxSteps?: number) {
22
32
  sentMessages.length = 0;
23
33
  mockHasClient = false;
34
+ mockClients = [];
24
35
  pendingInteractions.clear();
25
36
  proxy = new HostCuProxy(maxSteps);
26
37
  }
@@ -974,7 +985,203 @@ describe("HostCuProxy", () => {
974
985
  });
975
986
  });
976
987
 
977
- // targetClientId validation lives at the surfaceProxyResolver layer (so an
978
- // invalid ID does not burn a step or pollute action history before being
979
- // rejected). See cu-unified-flow.test.ts for those tests.
988
+ // -------------------------------------------------------------------------
989
+ // targetClientId validation
990
+ //
991
+ // The surfaceProxyResolver layer validates first (so an invalid ID does
992
+ // not burn a step or pollute action history — see cu-unified-flow.test.ts
993
+ // for those tests). The proxy ALSO validates internally because it is
994
+ // exposed as a separately-callable API; these tests exercise that
995
+ // backstop along with the same-user enforcement.
996
+ // -------------------------------------------------------------------------
997
+
998
+ describe("targetClientId validation", () => {
999
+ test("rejects when targetClientId does not match any connected client", async () => {
1000
+ setup();
1001
+ mockClients = [
1002
+ {
1003
+ clientId: "real-client",
1004
+ capabilities: ["host_cu"],
1005
+ actorPrincipalId: "user-1",
1006
+ },
1007
+ ];
1008
+
1009
+ const result = await proxy.request(
1010
+ "computer_use_click",
1011
+ { element_id: 1 },
1012
+ "session-1",
1013
+ 1,
1014
+ undefined,
1015
+ undefined,
1016
+ "ghost-client",
1017
+ "user-1",
1018
+ );
1019
+
1020
+ expect(result.isError).toBe(true);
1021
+ expect(result.content).toContain("ghost-client");
1022
+ expect(result.content).toContain("host_cu");
1023
+ expect(sentMessages).toHaveLength(0);
1024
+ });
1025
+
1026
+ test("rejects when target client lacks host_cu capability", async () => {
1027
+ setup();
1028
+ mockClients = [
1029
+ {
1030
+ clientId: "no-cu-client",
1031
+ capabilities: ["host_bash"],
1032
+ actorPrincipalId: "user-1",
1033
+ },
1034
+ ];
1035
+
1036
+ const result = await proxy.request(
1037
+ "computer_use_click",
1038
+ { element_id: 1 },
1039
+ "session-1",
1040
+ 1,
1041
+ undefined,
1042
+ undefined,
1043
+ "no-cu-client",
1044
+ "user-1",
1045
+ );
1046
+
1047
+ expect(result.isError).toBe(true);
1048
+ expect(result.content).toContain("does not support host_cu");
1049
+ expect(sentMessages).toHaveLength(0);
1050
+ });
1051
+
1052
+ test("succeeds when caller and target share the same actor principal", async () => {
1053
+ setup();
1054
+ mockClients = [
1055
+ {
1056
+ clientId: "cu-client",
1057
+ capabilities: ["host_cu"],
1058
+ actorPrincipalId: "user-1",
1059
+ },
1060
+ ];
1061
+
1062
+ const resultPromise = proxy.request(
1063
+ "computer_use_click",
1064
+ { element_id: 1 },
1065
+ "session-1",
1066
+ 1,
1067
+ undefined,
1068
+ undefined,
1069
+ "cu-client",
1070
+ "user-1",
1071
+ );
1072
+
1073
+ expect(sentMessages).toHaveLength(1);
1074
+ const sent = sentMessages[0] as Record<string, unknown>;
1075
+ expect(sent.type).toBe("host_cu_request");
1076
+ expect(sent.targetClientId).toBe("cu-client");
1077
+
1078
+ proxy.processObservation(sent.requestId as string, { axTree: "ok" });
1079
+ const result = await resultPromise;
1080
+ expect(result.isError).toBe(false);
1081
+ });
1082
+
1083
+ test("rejects cross-user targeted request", async () => {
1084
+ setup();
1085
+ mockClients = [
1086
+ {
1087
+ clientId: "cu-client",
1088
+ capabilities: ["host_cu"],
1089
+ actorPrincipalId: "user-2",
1090
+ },
1091
+ ];
1092
+
1093
+ const result = await proxy.request(
1094
+ "computer_use_click",
1095
+ { element_id: 1 },
1096
+ "session-1",
1097
+ 1,
1098
+ undefined,
1099
+ undefined,
1100
+ "cu-client",
1101
+ "user-1",
1102
+ );
1103
+
1104
+ expect(result.isError).toBe(true);
1105
+ expect(result.content).toContain(
1106
+ "Submitting actor does not match the target client's actor",
1107
+ );
1108
+ expect(sentMessages).toHaveLength(0);
1109
+ });
1110
+
1111
+ test("rejects when source actor principal is missing", async () => {
1112
+ setup();
1113
+ mockClients = [
1114
+ {
1115
+ clientId: "cu-client",
1116
+ capabilities: ["host_cu"],
1117
+ actorPrincipalId: "user-1",
1118
+ },
1119
+ ];
1120
+
1121
+ const result = await proxy.request(
1122
+ "computer_use_click",
1123
+ { element_id: 1 },
1124
+ "session-1",
1125
+ 1,
1126
+ undefined,
1127
+ undefined,
1128
+ "cu-client",
1129
+ // sourceActorPrincipalId omitted
1130
+ );
1131
+
1132
+ expect(result.isError).toBe(true);
1133
+ expect(result.content).toContain(
1134
+ "Submitting actor does not match the target client's actor",
1135
+ );
1136
+ expect(sentMessages).toHaveLength(0);
1137
+ });
1138
+
1139
+ test("rejects when target actor principal is missing", async () => {
1140
+ setup();
1141
+ mockClients = [
1142
+ {
1143
+ clientId: "cu-client",
1144
+ capabilities: ["host_cu"],
1145
+ // actorPrincipalId omitted
1146
+ },
1147
+ ];
1148
+
1149
+ const result = await proxy.request(
1150
+ "computer_use_click",
1151
+ { element_id: 1 },
1152
+ "session-1",
1153
+ 1,
1154
+ undefined,
1155
+ undefined,
1156
+ "cu-client",
1157
+ "user-1",
1158
+ );
1159
+
1160
+ expect(result.isError).toBe(true);
1161
+ expect(result.content).toContain(
1162
+ "Submitting actor does not match the target client's actor",
1163
+ );
1164
+ expect(sentMessages).toHaveLength(0);
1165
+ });
1166
+
1167
+ test("untargeted request bypasses same-user check", async () => {
1168
+ setup();
1169
+ // No targetClientId, no sourceActorPrincipalId — flow proceeds.
1170
+ const resultPromise = proxy.request(
1171
+ "computer_use_click",
1172
+ { element_id: 1 },
1173
+ "session-1",
1174
+ 1,
1175
+ );
1176
+
1177
+ expect(sentMessages).toHaveLength(1);
1178
+ const sent = sentMessages[0] as Record<string, unknown>;
1179
+ expect(sent.type).toBe("host_cu_request");
1180
+ expect(sent.targetClientId).toBeUndefined();
1181
+
1182
+ proxy.processObservation(sent.requestId as string, { axTree: "ok" });
1183
+ const result = await resultPromise;
1184
+ expect(result.isError).toBe(false);
1185
+ });
1186
+ });
980
1187
  });
@@ -42,7 +42,6 @@ mock.module("../config/env.js", () => ({
42
42
  getPlatformOrganizationId: () => "test-org-id",
43
43
  setPlatformUserId: () => {},
44
44
  getPlatformUserId: () => "test-user-id",
45
- getPlatformInternalApiKey: () => "test-api-key",
46
45
  validateEnv: () => {},
47
46
  }));
48
47
 
@@ -71,19 +70,30 @@ interface CuResolveCall {
71
70
  const cuResolveSpy: CuResolveCall[] = [];
72
71
 
73
72
  // Controlled conversation map: conversationId → conversation object
74
- const conversationStore = new Map<string, { hostCuProxy?: { processObservation: (...args: unknown[]) => void } }>();
73
+ const conversationStore = new Map<
74
+ string,
75
+ { hostCuProxy?: { processObservation: (...args: unknown[]) => void } }
76
+ >();
75
77
 
76
78
  mock.module("../daemon/conversation-store.js", () => ({
77
- findConversation: (conversationId: string) => conversationStore.get(conversationId),
79
+ findConversation: (conversationId: string) =>
80
+ conversationStore.get(conversationId),
81
+ }));
82
+
83
+ // Controlled actor-principal map: clientId → actorPrincipalId
84
+ const actorPrincipalByClient = new Map<string, string>();
85
+
86
+ mock.module("../runtime/assistant-event-hub.js", () => ({
87
+ assistantEventHub: {
88
+ getActorPrincipalIdForClient: (clientId: string) =>
89
+ actorPrincipalByClient.get(clientId),
90
+ },
78
91
  }));
79
92
 
80
93
  // ── Real imports (after mocks) ──────────────────────────────────────────────
81
94
  // Use dynamic import to ensure the mocks above are applied before loading.
82
95
 
83
- import {
84
- BadRequestError,
85
- ForbiddenError,
86
- } from "../runtime/routes/errors.js";
96
+ import { BadRequestError, ForbiddenError } from "../runtime/routes/errors.js";
87
97
 
88
98
  const { ROUTES } = await import("../runtime/routes/host-cu-routes.js");
89
99
 
@@ -101,10 +111,16 @@ function registerPending(
101
111
  requestId: string,
102
112
  overrides: Partial<PendingInteraction> = {},
103
113
  ): void {
114
+ const targetActorPrincipalId =
115
+ overrides.targetActorPrincipalId ??
116
+ (overrides.targetClientId
117
+ ? actorPrincipalByClient.get(overrides.targetClientId)
118
+ : undefined);
104
119
  const entry: PendingInteraction = {
105
120
  conversationId: "conv-cu-1",
106
121
  kind: "host_cu",
107
122
  ...overrides,
123
+ targetActorPrincipalId,
108
124
  };
109
125
  pendingStore.set(requestId, entry);
110
126
  }
@@ -139,6 +155,7 @@ describe("handleHostCuResult — Phase 2 targetClientId guard", () => {
139
155
  beforeEach(() => {
140
156
  pendingStore.clear();
141
157
  conversationStore.clear();
158
+ actorPrincipalByClient.clear();
142
159
  resolvedIds.length = 0;
143
160
  cuResolveSpy.length = 0;
144
161
  // Default: register a conversation with a hostCuProxy
@@ -150,11 +167,15 @@ describe("handleHostCuResult — Phase 2 targetClientId guard", () => {
150
167
  describe("targeted + correct x-vellum-client-id header", () => {
151
168
  test("returns { accepted: true } and resolves the interaction", async () => {
152
169
  const requestId = "req-cu-targeted-match";
170
+ actorPrincipalByClient.set("client-A", "user-1");
153
171
  registerPending(requestId, { targetClientId: "client-A" });
154
172
 
155
173
  const result = await handleHostCuResult({
156
174
  body: cuBody(requestId),
157
- headers: { "x-vellum-client-id": "client-A" },
175
+ headers: {
176
+ "x-vellum-client-id": "client-A",
177
+ "x-vellum-actor-principal-id": "user-1",
178
+ },
158
179
  });
159
180
 
160
181
  expect(result).toEqual({ accepted: true });
@@ -165,11 +186,15 @@ describe("handleHostCuResult — Phase 2 targetClientId guard", () => {
165
186
 
166
187
  test("trims whitespace from header before comparing", async () => {
167
188
  const requestId = "req-cu-targeted-trim";
189
+ actorPrincipalByClient.set("client-A", "user-1");
168
190
  registerPending(requestId, { targetClientId: "client-A" });
169
191
 
170
192
  const result = await handleHostCuResult({
171
193
  body: cuBody(requestId),
172
- headers: { "x-vellum-client-id": " client-A " },
194
+ headers: {
195
+ "x-vellum-client-id": " client-A ",
196
+ "x-vellum-actor-principal-id": "user-1",
197
+ },
173
198
  });
174
199
 
175
200
  expect(result).toEqual({ accepted: true });
@@ -183,9 +208,9 @@ describe("handleHostCuResult — Phase 2 targetClientId guard", () => {
183
208
  const requestId = "req-cu-targeted-no-header";
184
209
  registerPending(requestId, { targetClientId: "client-A" });
185
210
 
186
- expect(() =>
187
- handleHostCuResult({ body: cuBody(requestId) }),
188
- ).toThrow(BadRequestError);
211
+ expect(() => handleHostCuResult({ body: cuBody(requestId) })).toThrow(
212
+ BadRequestError,
213
+ );
189
214
  });
190
215
 
191
216
  test("throws BadRequestError (400) when header is empty string", () => {
@@ -268,6 +293,110 @@ describe("handleHostCuResult — Phase 2 targetClientId guard", () => {
268
293
  });
269
294
  });
270
295
 
296
+ // ── 3b. Actor-principal-id (PR 7) — defense-in-depth ──────────────────────
297
+
298
+ describe("targeted + actor-principal-id binding", () => {
299
+ test("accepts when submitting actor matches target client's stored actor", async () => {
300
+ const requestId = "req-cu-actor-match";
301
+ actorPrincipalByClient.set("client-A", "user-1");
302
+ registerPending(requestId, { targetClientId: "client-A" });
303
+
304
+ const result = await handleHostCuResult({
305
+ body: cuBody(requestId),
306
+ headers: {
307
+ "x-vellum-client-id": "client-A",
308
+ "x-vellum-actor-principal-id": "user-1",
309
+ },
310
+ });
311
+
312
+ expect(result).toEqual({ accepted: true });
313
+ expect(cuResolveSpy).toHaveLength(1);
314
+ expect(resolvedIds).toContain(requestId);
315
+ });
316
+
317
+ test("throws ForbiddenError (403) when submitting actor does not match target client's actor", () => {
318
+ const requestId = "req-cu-actor-mismatch";
319
+ actorPrincipalByClient.set("client-A", "user-1");
320
+ registerPending(requestId, { targetClientId: "client-A" });
321
+
322
+ expect(() =>
323
+ handleHostCuResult({
324
+ body: cuBody(requestId),
325
+ headers: {
326
+ "x-vellum-client-id": "client-A",
327
+ "x-vellum-actor-principal-id": "user-2",
328
+ },
329
+ }),
330
+ ).toThrow(ForbiddenError);
331
+ });
332
+
333
+ test("interaction NOT consumed on 403 actor mismatch", () => {
334
+ const requestId = "req-cu-actor-mismatch-stays";
335
+ actorPrincipalByClient.set("client-A", "user-1");
336
+ registerPending(requestId, { targetClientId: "client-A" });
337
+
338
+ try {
339
+ handleHostCuResult({
340
+ body: cuBody(requestId),
341
+ headers: {
342
+ "x-vellum-client-id": "client-A",
343
+ "x-vellum-actor-principal-id": "user-2",
344
+ },
345
+ });
346
+ } catch {
347
+ // expected
348
+ }
349
+
350
+ expect(resolvedIds).not.toContain(requestId);
351
+ expect(pendingStore.has(requestId)).toBe(true);
352
+ });
353
+
354
+ test("throws ForbiddenError (403) when submitting actor header is missing", () => {
355
+ const requestId = "req-cu-actor-missing";
356
+ actorPrincipalByClient.set("client-A", "user-1");
357
+ registerPending(requestId, { targetClientId: "client-A" });
358
+
359
+ expect(() =>
360
+ handleHostCuResult({
361
+ body: cuBody(requestId),
362
+ headers: { "x-vellum-client-id": "client-A" },
363
+ }),
364
+ ).toThrow(ForbiddenError);
365
+ });
366
+
367
+ test("throws ForbiddenError (403) when target client has no stored actor principal id", () => {
368
+ const requestId = "req-cu-target-no-actor";
369
+ registerPending(requestId, { targetClientId: "client-A" });
370
+ // No actorPrincipalByClient entry for client-A.
371
+
372
+ expect(() =>
373
+ handleHostCuResult({
374
+ body: cuBody(requestId),
375
+ headers: {
376
+ "x-vellum-client-id": "client-A",
377
+ "x-vellum-actor-principal-id": "user-1",
378
+ },
379
+ }),
380
+ ).toThrow(ForbiddenError);
381
+ });
382
+
383
+ test("throws ForbiddenError (403) when submitting actor header is whitespace only", () => {
384
+ const requestId = "req-cu-actor-whitespace";
385
+ actorPrincipalByClient.set("client-A", "user-1");
386
+ registerPending(requestId, { targetClientId: "client-A" });
387
+
388
+ expect(() =>
389
+ handleHostCuResult({
390
+ body: cuBody(requestId),
391
+ headers: {
392
+ "x-vellum-client-id": "client-A",
393
+ "x-vellum-actor-principal-id": " ",
394
+ },
395
+ }),
396
+ ).toThrow(ForbiddenError);
397
+ });
398
+ });
399
+
271
400
  // ── 4. Untargeted — regression ────────────────────────────────────────────
272
401
 
273
402
  describe("untargeted request (no targetClientId)", () => {
@@ -14,11 +14,24 @@ const sentMessages: unknown[] = [];
14
14
  const sentMessageOptions: unknown[] = [];
15
15
  const resolvedInteractionIds: string[] = [];
16
16
  let mockHasClient = false;
17
- let mockCapableClients: Array<{ clientId: string; capabilities: string[] }> = [];
18
- let mockClientRegistry: Map<string, { clientId: string; capabilities: string[] }> = new Map();
17
+ type MockClient = {
18
+ clientId: string;
19
+ capabilities: string[];
20
+ actorPrincipalId?: string;
21
+ };
22
+ let mockCapableClients: Array<MockClient> = [];
23
+ let mockClientRegistry: Map<string, MockClient> = new Map();
24
+
25
+ // Pre-existing Phase 2 routing tests use a single user identity. The same-user
26
+ // check added in PR 3 is exercised separately in `host-file-proxy.test.ts`.
27
+ const TEST_PRINCIPAL = "test-user";
19
28
 
20
29
  mock.module("../runtime/assistant-event-hub.js", () => ({
21
- broadcastMessage: (msg: unknown, _conversationId?: string, options?: unknown) => {
30
+ broadcastMessage: (
31
+ msg: unknown,
32
+ _conversationId?: string,
33
+ options?: unknown,
34
+ ) => {
22
35
  sentMessages.push(msg);
23
36
  sentMessageOptions.push(options);
24
37
  },
@@ -27,6 +40,8 @@ mock.module("../runtime/assistant-event-hub.js", () => ({
27
40
  cap === "host_file" && mockHasClient ? { id: "mock-client" } : null,
28
41
  listClientsByCapability: (_cap: string) => mockCapableClients,
29
42
  getClientById: (clientId: string) => mockClientRegistry.get(clientId),
43
+ getActorPrincipalIdForClient: (clientId: string) =>
44
+ mockClientRegistry.get(clientId)?.actorPrincipalId,
30
45
  },
31
46
  }));
32
47
 
@@ -42,9 +57,10 @@ mock.module("../runtime/pending-interactions.js", () => ({
42
57
  return interaction;
43
58
  },
44
59
  get: (requestId: string) => pendingInteractionMap.get(requestId),
45
- getByKind: (_kind: string) => Array.from(pendingInteractionMap.entries())
46
- .filter(([, v]) => v.kind === _kind)
47
- .map(([requestId, v]) => ({ requestId, ...v })),
60
+ getByKind: (_kind: string) =>
61
+ Array.from(pendingInteractionMap.entries())
62
+ .filter(([, v]) => v.kind === _kind)
63
+ .map(([requestId, v]) => ({ requestId, ...v })),
48
64
  getByConversation: () => [],
49
65
  removeByConversation: () => {},
50
66
  }));
@@ -66,7 +82,11 @@ describe("HostFileProxy — targetClientId (Phase 2)", () => {
66
82
  }
67
83
 
68
84
  function setupSingleClient(clientId = "client-1") {
69
- const entry = { clientId, capabilities: ["host_file"] };
85
+ const entry: MockClient = {
86
+ clientId,
87
+ capabilities: ["host_file"],
88
+ actorPrincipalId: TEST_PRINCIPAL,
89
+ };
70
90
  mockCapableClients = [entry];
71
91
  mockClientRegistry.set(clientId, entry);
72
92
  }
@@ -75,6 +95,7 @@ describe("HostFileProxy — targetClientId (Phase 2)", () => {
75
95
  mockCapableClients = clientIds.map((id) => ({
76
96
  clientId: id,
77
97
  capabilities: ["host_file"],
98
+ actorPrincipalId: TEST_PRINCIPAL,
78
99
  }));
79
100
  for (const entry of mockCapableClients) {
80
101
  mockClientRegistry.set(entry.clientId, entry);
@@ -104,6 +125,9 @@ describe("HostFileProxy — targetClientId (Phase 2)", () => {
104
125
  targetClientId: "client-mac",
105
126
  },
106
127
  "session-1",
128
+ undefined,
129
+ undefined,
130
+ TEST_PRINCIPAL,
107
131
  );
108
132
 
109
133
  expect(sentMessages).toHaveLength(1);
@@ -140,7 +164,9 @@ describe("HostFileProxy — targetClientId (Phase 2)", () => {
140
164
 
141
165
  expect(result.isError).toBe(true);
142
166
  expect(result.content).toContain("client-unknown");
143
- expect(result.content).toContain("assistant clients list --capability host_file");
167
+ expect(result.content).toContain(
168
+ "assistant clients list --capability host_file",
169
+ );
144
170
  // No pending entry should have been created
145
171
  expect(sentMessages).toHaveLength(0);
146
172
  });
@@ -200,6 +226,9 @@ describe("HostFileProxy — targetClientId (Phase 2)", () => {
200
226
  const resultPromise = proxy.request(
201
227
  { operation: "read", path: "/tmp/file.txt" },
202
228
  "session-1",
229
+ undefined,
230
+ undefined,
231
+ TEST_PRINCIPAL,
203
232
  );
204
233
 
205
234
  expect(sentMessages).toHaveLength(1);
@@ -257,6 +286,8 @@ describe("HostFileProxy — targetClientId (Phase 2)", () => {
257
286
  { operation: "read", path: "/tmp/file.txt" },
258
287
  "session-1",
259
288
  controller.signal,
289
+ undefined,
290
+ TEST_PRINCIPAL,
260
291
  );
261
292
 
262
293
  const sent = sentMessages[0] as Record<string, unknown>;
@@ -273,7 +304,9 @@ describe("HostFileProxy — targetClientId (Phase 2)", () => {
273
304
  expect(cancelMsg.requestId).toBe(requestId);
274
305
  expect(cancelMsg.targetClientId).toBe("client-abc");
275
306
 
276
- const cancelOpts = sentMessageOptions[1] as Record<string, unknown> | undefined;
307
+ const cancelOpts = sentMessageOptions[1] as
308
+ | Record<string, unknown>
309
+ | undefined;
277
310
  expect(cancelOpts?.targetClientId).toBe("client-abc");
278
311
  });
279
312
  });
@@ -288,6 +321,9 @@ describe("HostFileProxy — targetClientId (Phase 2)", () => {
288
321
  const p = proxy.request(
289
322
  { operation: "read", path: "/tmp/file.txt" },
290
323
  "session-1",
324
+ undefined,
325
+ undefined,
326
+ TEST_PRINCIPAL,
291
327
  );
292
328
  p.catch(() => {}); // expected rejection on dispose
293
329
 
@@ -320,6 +356,9 @@ describe("HostFileProxy — targetClientId (Phase 2)", () => {
320
356
  const resultPromise = proxy.request(
321
357
  { operation: "read", path: "/tmp/slow.txt" },
322
358
  "session-1",
359
+ undefined,
360
+ undefined,
361
+ TEST_PRINCIPAL,
323
362
  );
324
363
 
325
364
  const sent = sentMessages[0] as Record<string, unknown>;