@vellumai/assistant 0.7.1 → 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 (739) hide show
  1. package/ARCHITECTURE.md +48 -50
  2. package/Dockerfile +1 -0
  3. package/README.md +1 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
  5. package/bun.lock +26 -26
  6. package/docs/architecture/memory.md +5 -2
  7. package/docs/architecture/security.md +20 -0
  8. package/docs/plugins.md +7 -9
  9. package/knip.json +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  11. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +52 -5
  12. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  13. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  15. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  16. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  17. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  18. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  19. package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
  20. package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
  21. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  22. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  23. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  24. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  25. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  26. package/openapi.yaml +1020 -40
  27. package/package.json +6 -3
  28. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  29. package/src/__tests__/app-bundler.test.ts +170 -1
  30. package/src/__tests__/app-control-flow.test.ts +384 -0
  31. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  32. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  33. package/src/__tests__/app-executors.test.ts +30 -43
  34. package/src/__tests__/approval-routes-http.test.ts +23 -6
  35. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  36. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  37. package/src/__tests__/assistant-event-hub.test.ts +157 -2
  38. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -7
  39. package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
  40. package/src/__tests__/background-shell-host-bash.test.ts +14 -15
  41. package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
  42. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  43. package/src/__tests__/btw-routes.test.ts +13 -4
  44. package/src/__tests__/call-controller.test.ts +49 -1
  45. package/src/__tests__/call-conversation-messages.test.ts +8 -2
  46. package/src/__tests__/call-domain.test.ts +0 -2
  47. package/src/__tests__/call-routes-http.test.ts +0 -2
  48. package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
  49. package/src/__tests__/channel-readiness-service.test.ts +62 -2
  50. package/src/__tests__/checker.test.ts +3 -4
  51. package/src/__tests__/config-loader-backfill.test.ts +461 -147
  52. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  53. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  54. package/src/__tests__/config-schema.test.ts +1 -0
  55. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  56. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +20 -11
  57. package/src/__tests__/config-watcher.test.ts +142 -71
  58. package/src/__tests__/context-search-agent-runner.test.ts +61 -3
  59. package/src/__tests__/context-search-conversations-source.test.ts +0 -24
  60. package/src/__tests__/context-search-fanout.test.ts +0 -1
  61. package/src/__tests__/context-search-memory-source.test.ts +3 -7
  62. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
  63. package/src/__tests__/context-search-pkb-source.test.ts +0 -1
  64. package/src/__tests__/context-search-workspace-source.test.ts +0 -1
  65. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  66. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
  67. package/src/__tests__/conversation-agent-loop.test.ts +454 -5
  68. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  69. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  70. package/src/__tests__/conversation-error.test.ts +150 -3
  71. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  72. package/src/__tests__/conversation-lifecycle.test.ts +36 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  74. package/src/__tests__/conversation-process-callsite.test.ts +43 -0
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  76. package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
  77. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
  78. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  79. package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
  80. package/src/__tests__/conversation-slash-commands.test.ts +0 -4
  81. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  82. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  83. package/src/__tests__/conversation-store.test.ts +0 -18
  84. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  85. package/src/__tests__/conversation-surfaces-app-control.test.ts +328 -0
  86. package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
  87. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
  88. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  89. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  90. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  91. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  92. package/src/__tests__/credentials-cli.test.ts +12 -12
  93. package/src/__tests__/cu-unified-flow.test.ts +351 -23
  94. package/src/__tests__/daemon-credential-client.test.ts +101 -19
  95. package/src/__tests__/date-context.test.ts +164 -2
  96. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  97. package/src/__tests__/disk-pressure-guard.test.ts +262 -0
  98. package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
  99. package/src/__tests__/disk-pressure-policy.test.ts +241 -0
  100. package/src/__tests__/disk-pressure-routes.test.ts +379 -0
  101. package/src/__tests__/disk-pressure-tools.test.ts +277 -0
  102. package/src/__tests__/disk-usage.test.ts +150 -0
  103. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  104. package/src/__tests__/events-client-registration.test.ts +52 -0
  105. package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
  106. package/src/__tests__/file-write-tool.test.ts +4 -10
  107. package/src/__tests__/filing-service.test.ts +3 -4
  108. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  109. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  110. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
  111. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
  112. package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
  113. package/src/__tests__/heartbeat-service.test.ts +968 -2
  114. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  115. package/src/__tests__/host-app-control-proxy.test.ts +772 -0
  116. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  117. package/src/__tests__/host-bash-proxy.test.ts +439 -47
  118. package/src/__tests__/host-bash-routes.test.ts +459 -0
  119. package/src/__tests__/host-browser-proxy.test.ts +24 -22
  120. package/src/__tests__/host-browser-routes.test.ts +39 -13
  121. package/src/__tests__/host-cu-proxy.test.ts +248 -52
  122. package/src/__tests__/host-cu-routes-targeted.test.ts +429 -0
  123. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  124. package/src/__tests__/host-file-proxy-targeted.test.ts +378 -0
  125. package/src/__tests__/host-file-proxy.test.ts +301 -45
  126. package/src/__tests__/host-file-read-tool.test.ts +17 -0
  127. package/src/__tests__/host-file-routes-targeted.test.ts +420 -0
  128. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  129. package/src/__tests__/host-proxy-base.test.ts +312 -0
  130. package/src/__tests__/host-shell-tool.test.ts +22 -4
  131. package/src/__tests__/host-transfer-proxy-targeted.test.ts +932 -0
  132. package/src/__tests__/host-transfer-proxy.test.ts +121 -22
  133. package/src/__tests__/host-transfer-routes-targeted.test.ts +662 -0
  134. package/src/__tests__/http-user-message-parity.test.ts +108 -1
  135. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  136. package/src/__tests__/identity-routes.test.ts +103 -1
  137. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  138. package/src/__tests__/injector-chain.test.ts +18 -6
  139. package/src/__tests__/injector-disk-pressure.test.ts +224 -0
  140. package/src/__tests__/inline-command-runner.test.ts +0 -1
  141. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
  142. package/src/__tests__/integration-status.test.ts +85 -5
  143. package/src/__tests__/intent-routing.test.ts +0 -1
  144. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  145. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  146. package/src/__tests__/managed-profile-guard.test.ts +18 -0
  147. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
  148. package/src/__tests__/mcp-abort-signal.test.ts +130 -0
  149. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  150. package/src/__tests__/mcp-cli.test.ts +338 -2
  151. package/src/__tests__/memory-admin-recall.test.ts +3 -11
  152. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  153. package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
  154. package/src/__tests__/migration-import-commit-http.test.ts +108 -2
  155. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  156. package/src/__tests__/normalize-onboarding.test.ts +180 -0
  157. package/src/__tests__/oauth-cli.test.ts +0 -2
  158. package/src/__tests__/oauth-connect-routes.test.ts +316 -0
  159. package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
  160. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  161. package/src/__tests__/onboarding-persona-write.test.ts +308 -0
  162. package/src/__tests__/openai-provider.test.ts +45 -8
  163. package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
  164. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  165. package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
  166. package/src/__tests__/platform-callback-registration.test.ts +21 -4
  167. package/src/__tests__/platform.test.ts +2 -1
  168. package/src/__tests__/playbook-execution.test.ts +0 -43
  169. package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
  170. package/src/__tests__/prechat-onboarding-contract.test.ts +214 -25
  171. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  172. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  173. package/src/__tests__/provider-tool-name.test.ts +23 -0
  174. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  175. package/src/__tests__/relay-server.test.ts +15 -4
  176. package/src/__tests__/require-fresh-approval.test.ts +0 -1
  177. package/src/__tests__/retry-backoff.test.ts +87 -0
  178. package/src/__tests__/runtime-events-sse.test.ts +2 -2
  179. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  180. package/src/__tests__/schedule-retry.test.ts +715 -0
  181. package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
  182. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  183. package/src/__tests__/secret-ingress-http.test.ts +1 -1
  184. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  185. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
  186. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  187. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  188. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  189. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  190. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  191. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
  192. package/src/__tests__/slack-channel-config.test.ts +9 -14
  193. package/src/__tests__/suggestion-routes.test.ts +46 -0
  194. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  195. package/src/__tests__/system-prompt.test.ts +0 -1
  196. package/src/__tests__/telegram-config.test.ts +0 -1
  197. package/src/__tests__/test-preload.ts +8 -0
  198. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  199. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  200. package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
  201. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
  202. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  203. package/src/__tests__/tool-executor.test.ts +0 -1
  204. package/src/__tests__/twilio-config.test.ts +3 -16
  205. package/src/__tests__/twilio-routes.test.ts +3 -5
  206. package/src/__tests__/twilio-validation.test.ts +93 -0
  207. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
  208. package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
  209. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  210. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  211. package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
  212. package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
  213. package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
  214. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  215. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  216. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
  217. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  218. package/src/approvals/guardian-decision-primitive.ts +13 -0
  219. package/src/approvals/guardian-request-resolvers.ts +16 -17
  220. package/src/backup/__tests__/paths.test.ts +0 -22
  221. package/src/backup/__tests__/restore.test.ts +51 -151
  222. package/src/backup/paths.ts +2 -18
  223. package/src/backup/restore.ts +107 -231
  224. package/src/backup/snapshot-lock.ts +2 -27
  225. package/src/bundler/app-bundler.ts +51 -3
  226. package/src/bundler/compiler-tools.ts +3 -2
  227. package/src/calls/call-conversation-messages.ts +46 -10
  228. package/src/calls/relay-server.ts +4 -44
  229. package/src/calls/twilio-config.ts +2 -17
  230. package/src/calls/twilio-rest.ts +33 -105
  231. package/src/calls/twilio-routes.ts +11 -12
  232. package/src/channels/types.ts +8 -7
  233. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  234. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  235. package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
  236. package/src/cli/commands/__tests__/webhooks.test.ts +0 -5
  237. package/src/cli/commands/backup.ts +6 -331
  238. package/src/cli/commands/bash.ts +35 -108
  239. package/src/cli/commands/clients.ts +36 -37
  240. package/src/cli/commands/contacts.ts +137 -25
  241. package/src/cli/commands/conversations.ts +2 -5
  242. package/src/cli/commands/credentials.ts +71 -7
  243. package/src/cli/commands/domain.ts +66 -15
  244. package/src/cli/commands/gateway.ts +183 -0
  245. package/src/cli/commands/keys.ts +9 -6
  246. package/src/cli/commands/mcp.ts +116 -156
  247. package/src/cli/commands/memory-v2.ts +303 -7
  248. package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
  249. package/src/cli/commands/oauth/connect.ts +127 -1
  250. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -4
  251. package/src/cli/commands/platform/__tests__/connect.test.ts +7 -3
  252. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -3
  253. package/src/cli/commands/platform/__tests__/status.test.ts +116 -21
  254. package/src/cli/commands/platform/disconnect.ts +5 -4
  255. package/src/cli/commands/platform/index.ts +16 -25
  256. package/src/cli/commands/status.ts +57 -0
  257. package/src/cli/lib/daemon-credential-client.ts +110 -28
  258. package/src/cli/program.ts +6 -2
  259. package/src/config/assistant-feature-flags.ts +79 -12
  260. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  261. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  262. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  263. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  264. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  265. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  266. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  267. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  268. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  269. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  270. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  271. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  272. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  273. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  274. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  275. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  276. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  277. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  278. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  279. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  280. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  281. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  282. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  283. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  284. package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
  285. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
  286. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  287. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +25 -4
  288. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  289. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
  290. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
  291. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  292. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
  293. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  294. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  295. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  296. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  297. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  298. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  299. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  300. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  301. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  302. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  303. package/src/config/bundled-tool-registry.ts +21 -0
  304. package/src/config/env-registry.ts +0 -2
  305. package/src/config/env.ts +19 -20
  306. package/src/config/feature-flag-registry.json +47 -135
  307. package/src/config/loader.ts +197 -104
  308. package/src/config/sanitize-for-transfer.ts +2 -0
  309. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  310. package/src/config/schemas/__tests__/memory-v2.test.ts +17 -9
  311. package/src/config/schemas/call-site-catalog.ts +14 -0
  312. package/src/config/schemas/calls.ts +0 -9
  313. package/src/config/schemas/channels.ts +0 -5
  314. package/src/config/schemas/heartbeat.ts +64 -1
  315. package/src/config/schemas/ingress.ts +10 -6
  316. package/src/config/schemas/llm.ts +7 -10
  317. package/src/config/schemas/memory-lifecycle.ts +90 -24
  318. package/src/config/schemas/memory-v2.ts +121 -13
  319. package/src/config/schemas/platform.ts +49 -3
  320. package/src/config/schemas/services.ts +29 -15
  321. package/src/config/schemas/skills.ts +0 -6
  322. package/src/config/seed-inference-profiles.ts +230 -33
  323. package/src/contacts/contact-store.ts +0 -55
  324. package/src/contacts/contacts-write.ts +0 -27
  325. package/src/context/window-manager.ts +1 -2
  326. package/src/credential-execution/feature-gates.ts +10 -10
  327. package/src/credential-execution/process-manager.ts +12 -41
  328. package/src/daemon/__tests__/conversation-tool-setup.test.ts +187 -5
  329. package/src/daemon/assistant-attachments.ts +4 -4
  330. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  331. package/src/daemon/config-watcher.ts +89 -60
  332. package/src/daemon/conversation-agent-loop-handlers.ts +27 -3
  333. package/src/daemon/conversation-agent-loop.ts +202 -61
  334. package/src/daemon/conversation-error.ts +87 -15
  335. package/src/daemon/conversation-lifecycle.ts +9 -4
  336. package/src/daemon/conversation-process.ts +24 -11
  337. package/src/daemon/conversation-runtime-assembly.ts +28 -2
  338. package/src/daemon/conversation-store.ts +2 -2
  339. package/src/daemon/conversation-surfaces.ts +305 -4
  340. package/src/daemon/conversation-tool-setup.ts +66 -62
  341. package/src/daemon/conversation.ts +38 -24
  342. package/src/daemon/date-context.ts +71 -22
  343. package/src/daemon/disk-pressure-background-gate.ts +73 -0
  344. package/src/daemon/disk-pressure-guard.ts +343 -0
  345. package/src/daemon/disk-pressure-policy.ts +163 -0
  346. package/src/daemon/doordash-steps.ts +1 -1
  347. package/src/daemon/handlers/shared.ts +4 -2
  348. package/src/daemon/handlers/skills.ts +3 -4
  349. package/src/daemon/host-app-control-proxy.ts +389 -0
  350. package/src/daemon/host-bash-proxy.ts +117 -82
  351. package/src/daemon/host-browser-proxy.ts +67 -82
  352. package/src/daemon/host-cu-proxy.ts +127 -86
  353. package/src/daemon/host-file-proxy.ts +129 -69
  354. package/src/daemon/host-proxy-base.ts +294 -0
  355. package/src/daemon/host-proxy-preactivation.ts +82 -0
  356. package/src/daemon/host-transfer-proxy.ts +338 -129
  357. package/src/daemon/lifecycle.ts +194 -145
  358. package/src/daemon/meet-host-supervisor.ts +4 -4
  359. package/src/daemon/meet-manifest-loader.ts +0 -1
  360. package/src/daemon/memory-v2-startup.ts +14 -4
  361. package/src/daemon/message-protocol.ts +6 -8
  362. package/src/daemon/message-types/contacts.ts +23 -1
  363. package/src/daemon/message-types/conversations.ts +15 -8
  364. package/src/daemon/message-types/disk-pressure.ts +9 -0
  365. package/src/daemon/message-types/host-app-control.ts +150 -0
  366. package/src/daemon/message-types/host-bash.ts +4 -0
  367. package/src/daemon/message-types/host-cu.ts +2 -0
  368. package/src/daemon/message-types/host-file.ts +4 -0
  369. package/src/daemon/message-types/host-transfer.ts +3 -0
  370. package/src/daemon/message-types/messages.ts +3 -0
  371. package/src/daemon/message-types/schedules.ts +8 -3
  372. package/src/daemon/message-types/skills.ts +2 -2
  373. package/src/daemon/process-message.ts +18 -1
  374. package/src/daemon/profiler-run-store.ts +5 -5
  375. package/src/daemon/shutdown-handlers.ts +0 -3
  376. package/src/daemon/tool-setup-types.ts +51 -0
  377. package/src/daemon/tool-side-effects.ts +1 -1
  378. package/src/documents/document-store.ts +85 -0
  379. package/src/events/tool-audit-listener.ts +2 -1
  380. package/src/filing/filing-service.ts +30 -5
  381. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +24 -23
  382. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +252 -0
  383. package/src/heartbeat/heartbeat-run-store.ts +249 -0
  384. package/src/heartbeat/heartbeat-service.ts +459 -54
  385. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  386. package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
  387. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  388. package/src/home/feed-scheduler.ts +18 -0
  389. package/src/home/post-connect-feed.ts +68 -0
  390. package/src/home/relationship-state-writer.ts +17 -92
  391. package/src/home/suggested-prompts.ts +46 -10
  392. package/src/inbound/platform-callback-registration.ts +8 -15
  393. package/src/inbound/public-ingress-urls.ts +32 -34
  394. package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
  395. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  396. package/src/ipc/assistant-server.ts +70 -3
  397. package/src/ipc/cli-client.ts +32 -1
  398. package/src/ipc/gateway-client.ts +37 -3
  399. package/src/live-voice/live-voice-archive.ts +4 -4
  400. package/src/live-voice/live-voice-metrics.ts +10 -10
  401. package/src/live-voice/protocol.ts +5 -7
  402. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  403. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  404. package/src/mcp/mcp-auth-state.ts +133 -0
  405. package/src/mcp/mcp-oauth-provider.ts +19 -0
  406. package/src/media/image-service.ts +1 -7
  407. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
  408. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  409. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
  412. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  413. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  414. package/src/memory/admin.ts +5 -9
  415. package/src/memory/anisotropy.test.ts +247 -0
  416. package/src/memory/anisotropy.ts +443 -0
  417. package/src/memory/auto-analysis-constants.ts +17 -0
  418. package/src/memory/auto-analysis-guard.ts +5 -15
  419. package/src/memory/canonical-guardian-store.ts +7 -7
  420. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  421. package/src/memory/context-search/agent-protocol.ts +6 -6
  422. package/src/memory/context-search/agent-runner.ts +51 -9
  423. package/src/memory/context-search/sources/conversations.ts +2 -11
  424. package/src/memory/context-search/sources/memory-v2.ts +22 -9
  425. package/src/memory/context-search/sources/memory.ts +0 -1
  426. package/src/memory/context-search/types.ts +0 -1
  427. package/src/memory/conversation-crud.ts +5 -13
  428. package/src/memory/conversation-key-store.ts +2 -15
  429. package/src/memory/db-init.ts +6 -0
  430. package/src/memory/embedding-backend.ts +9 -21
  431. package/src/memory/embedding-runtime-manager.ts +119 -5
  432. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +81 -25
  433. package/src/memory/graph/conversation-graph-memory.ts +43 -78
  434. package/src/memory/graph/extraction.ts +1 -3
  435. package/src/memory/graph/graph-search.test.ts +10 -67
  436. package/src/memory/graph/graph-search.ts +9 -20
  437. package/src/memory/graph/retriever.test.ts +6 -0
  438. package/src/memory/graph/retriever.ts +34 -10
  439. package/src/memory/graph/tools.ts +1 -1
  440. package/src/memory/indexer.ts +54 -45
  441. package/src/memory/job-handlers/backfill.ts +2 -11
  442. package/src/memory/job-handlers/cleanup.ts +43 -0
  443. package/src/memory/job-handlers/embedding.ts +6 -8
  444. package/src/memory/job-handlers/summarization.ts +2 -7
  445. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  446. package/src/memory/jobs/embed-concept-page.ts +28 -2
  447. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  448. package/src/memory/jobs-store.ts +114 -22
  449. package/src/memory/jobs-worker.ts +193 -106
  450. package/src/memory/memory-v2-activation-log-store.ts +33 -15
  451. package/src/memory/memory-v2-concept-frequency.ts +169 -0
  452. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  453. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  454. package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
  455. package/src/memory/migrations/index.ts +6 -0
  456. package/src/memory/migrations/registry.ts +8 -0
  457. package/src/memory/pkb/pkb-search.test.ts +6 -0
  458. package/src/memory/pkb/pkb-search.ts +7 -0
  459. package/src/memory/qdrant-client.ts +49 -32
  460. package/src/memory/rerank-local.ts +374 -0
  461. package/src/memory/schema/infrastructure.ts +15 -0
  462. package/src/memory/search/semantic.ts +13 -67
  463. package/src/memory/sparse-tokenize.ts +49 -0
  464. package/src/memory/trace-event-store.ts +1 -17
  465. package/src/memory/v2/__tests__/activation.test.ts +387 -344
  466. package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
  467. package/src/memory/v2/__tests__/injection.test.ts +181 -169
  468. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
  469. package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
  470. package/src/memory/v2/__tests__/reranker.test.ts +338 -0
  471. package/src/memory/v2/__tests__/sim.test.ts +154 -188
  472. package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
  473. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  474. package/src/memory/v2/__tests__/static-context.test.ts +76 -2
  475. package/src/memory/v2/activation.ts +213 -239
  476. package/src/memory/v2/consolidation-job.ts +65 -17
  477. package/src/memory/v2/constants.ts +7 -0
  478. package/src/memory/v2/injection.ts +123 -103
  479. package/src/memory/v2/prompts/consolidation.ts +348 -92
  480. package/src/memory/v2/qdrant.ts +198 -1
  481. package/src/memory/v2/reranker.ts +177 -0
  482. package/src/memory/v2/sim.ts +113 -77
  483. package/src/memory/v2/skill-content.ts +4 -3
  484. package/src/memory/v2/skill-store.ts +91 -53
  485. package/src/memory/v2/sparse-bm25.ts +245 -0
  486. package/src/memory/v2/static-context.ts +28 -5
  487. package/src/memory/v2/types.ts +10 -10
  488. package/src/messaging/providers/gmail/types.ts +0 -49
  489. package/src/messaging/providers/slack/adapter.ts +1 -31
  490. package/src/messaging/providers/slack/types.ts +0 -32
  491. package/src/notifications/README.md +10 -10
  492. package/src/notifications/broadcaster.ts +1 -1
  493. package/src/notifications/copy-composer.ts +13 -0
  494. package/src/notifications/guardian-question-mode.ts +5 -5
  495. package/src/notifications/signal.ts +4 -0
  496. package/src/oauth/AGENTS.md +3 -1
  497. package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
  498. package/src/oauth/connect-orchestrator.ts +6 -0
  499. package/src/oauth/connection-resolver.test.ts +66 -1
  500. package/src/oauth/connection-resolver.ts +55 -1
  501. package/src/oauth/credential-token-resolver.ts +1 -3
  502. package/src/oauth/manual-token-connection.ts +0 -4
  503. package/src/oauth/oauth-connect-state.ts +77 -0
  504. package/src/oauth/seed-providers.ts +58 -1
  505. package/src/outbound-proxy/index.ts +1 -37
  506. package/src/outbound-proxy/logging.ts +1 -1
  507. package/src/outbound-proxy/policy.ts +6 -5
  508. package/src/outbound-proxy/router.ts +2 -1
  509. package/src/permissions/approval-policy.test.ts +6 -275
  510. package/src/permissions/approval-policy.ts +0 -51
  511. package/src/permissions/checker.test.ts +0 -1
  512. package/src/permissions/checker.ts +3 -17
  513. package/src/permissions/gateway-threshold-reader.ts +2 -0
  514. package/src/permissions/prompter.ts +34 -1
  515. package/src/permissions/secret-prompter.ts +6 -2
  516. package/src/plugins/defaults/injectors.ts +35 -2
  517. package/src/plugins/defaults/memory-retrieval.ts +5 -6
  518. package/src/plugins/types.ts +7 -0
  519. package/src/proactive-artifact/aux-message-injector.ts +74 -0
  520. package/src/proactive-artifact/decision.test.ts +226 -0
  521. package/src/proactive-artifact/decision.ts +165 -0
  522. package/src/proactive-artifact/index.ts +7 -0
  523. package/src/proactive-artifact/job.test.ts +867 -0
  524. package/src/proactive-artifact/job.ts +352 -0
  525. package/src/proactive-artifact/message-copy.ts +41 -0
  526. package/src/proactive-artifact/trigger-state.test.ts +277 -0
  527. package/src/proactive-artifact/trigger-state.ts +119 -0
  528. package/src/prompts/bootstrap-cleanup.ts +27 -0
  529. package/src/prompts/normalize-onboarding.ts +80 -0
  530. package/src/prompts/persona-resolver.ts +101 -9
  531. package/src/prompts/system-prompt.ts +23 -24
  532. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  533. package/src/prompts/templates/SOUL.md +13 -1
  534. package/src/providers/__tests__/retry-callsite.test.ts +222 -1
  535. package/src/providers/model-intents.ts +7 -0
  536. package/src/providers/openrouter/client.ts +8 -0
  537. package/src/providers/retry.ts +50 -0
  538. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  539. package/src/providers/types.ts +1 -0
  540. package/src/runtime/__tests__/agent-wake.test.ts +456 -3
  541. package/src/runtime/agent-wake.ts +238 -100
  542. package/src/runtime/assistant-event-hub.ts +151 -99
  543. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  544. package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
  545. package/src/runtime/auth/middleware.ts +0 -96
  546. package/src/runtime/auth/route-policy.ts +32 -0
  547. package/src/runtime/auth/same-actor.ts +216 -0
  548. package/src/runtime/btw-sidechain.ts +2 -3
  549. package/src/runtime/channel-invite-transport.ts +2 -48
  550. package/src/runtime/channel-invite-transports/email.ts +1 -1
  551. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  552. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  553. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  554. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  555. package/src/runtime/channel-invite-types.ts +54 -0
  556. package/src/runtime/channel-readiness-service.ts +32 -13
  557. package/src/runtime/channel-retry-sweep.ts +65 -1
  558. package/src/runtime/guardian-reply-router.ts +10 -0
  559. package/src/runtime/http-server.ts +3 -329
  560. package/src/runtime/http-types.ts +0 -5
  561. package/src/runtime/local-actor-identity.ts +52 -11
  562. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  563. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  564. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  565. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
  566. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  567. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  568. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  569. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  570. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  571. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
  572. package/src/runtime/migrations/migration-transport.ts +7 -7
  573. package/src/runtime/migrations/vbundle-builder.ts +327 -60
  574. package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
  575. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  576. package/src/runtime/migrations/vbundle-importer.ts +245 -68
  577. package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
  578. package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
  579. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  580. package/src/runtime/migrations/vbundle-validator.ts +114 -0
  581. package/src/runtime/pending-interactions.ts +43 -9
  582. package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
  583. package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
  584. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -5
  585. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  586. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  587. package/src/runtime/routes/approval-interception-types.ts +13 -0
  588. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  589. package/src/runtime/routes/backup-routes.ts +15 -38
  590. package/src/runtime/routes/btw-routes.ts +14 -37
  591. package/src/runtime/routes/client-routes.ts +21 -2
  592. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  593. package/src/runtime/routes/contact-routes.ts +0 -25
  594. package/src/runtime/routes/conversation-query-routes.ts +36 -1
  595. package/src/runtime/routes/conversation-routes.ts +65 -39
  596. package/src/runtime/routes/debug-bash-routes.ts +163 -0
  597. package/src/runtime/routes/disk-pressure-routes.ts +121 -0
  598. package/src/runtime/routes/document-pdf-renderer.ts +169 -0
  599. package/src/runtime/routes/documents-routes.ts +32 -75
  600. package/src/runtime/routes/errors.ts +19 -4
  601. package/src/runtime/routes/events-routes.ts +38 -0
  602. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  603. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  604. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  605. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  606. package/src/runtime/routes/host-bash-routes.ts +56 -6
  607. package/src/runtime/routes/host-browser-routes.ts +108 -13
  608. package/src/runtime/routes/host-cu-routes.ts +66 -9
  609. package/src/runtime/routes/host-file-routes.ts +54 -5
  610. package/src/runtime/routes/host-transfer-routes.ts +122 -19
  611. package/src/runtime/routes/http-adapter.ts +1 -0
  612. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  613. package/src/runtime/routes/identity-routes.ts +21 -180
  614. package/src/runtime/routes/inbound-message-handler.ts +78 -21
  615. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
  616. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  617. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
  618. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  619. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  620. package/src/runtime/routes/index.ts +14 -0
  621. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  622. package/src/runtime/routes/memory-item-routes.test.ts +41 -15
  623. package/src/runtime/routes/memory-item-routes.ts +10 -12
  624. package/src/runtime/routes/memory-v2-routes.ts +474 -1
  625. package/src/runtime/routes/migration-routes.ts +96 -0
  626. package/src/runtime/routes/oauth-connect-routes.ts +153 -0
  627. package/src/runtime/routes/schedule-routes.ts +7 -0
  628. package/src/runtime/verification-outbound-actions.ts +4 -4
  629. package/src/runtime/verification-templates.ts +4 -7
  630. package/src/schedule/integration-status.ts +66 -2
  631. package/src/schedule/recurrence-engine.ts +4 -1
  632. package/src/schedule/retry-backoff.ts +18 -0
  633. package/src/schedule/retry-policy.ts +82 -0
  634. package/src/schedule/run-script.ts +37 -5
  635. package/src/schedule/schedule-recovery.ts +64 -0
  636. package/src/schedule/schedule-store.ts +106 -2
  637. package/src/schedule/scheduler-types.ts +25 -0
  638. package/src/schedule/scheduler.ts +83 -39
  639. package/src/security/encrypted-store.ts +2 -0
  640. package/src/security/oauth-callback-registry.ts +8 -0
  641. package/src/security/secure-keys.ts +55 -0
  642. package/src/sequence/analytics.ts +5 -5
  643. package/src/sequence/engine.ts +1 -1
  644. package/src/skills/catalog-files.ts +2 -8
  645. package/src/skills/include-graph.ts +5 -5
  646. package/src/skills/remote-skill-policy.ts +10 -16
  647. package/src/skills/skill-file-provider.ts +1 -1
  648. package/src/skills/skill-file-types.ts +13 -0
  649. package/src/skills/skillssh-audit-types.ts +28 -0
  650. package/src/skills/skillssh-registry.ts +8 -21
  651. package/src/subagent/index.ts +1 -7
  652. package/src/subagent/manager.ts +1 -15
  653. package/src/tasks/task-runner.ts +0 -1
  654. package/src/tasks/task-store.ts +0 -3
  655. package/src/telemetry/types.ts +2 -0
  656. package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
  657. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  658. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  659. package/src/tools/apps/executors.ts +56 -69
  660. package/src/tools/background-tool-registry.ts +17 -3
  661. package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
  662. package/src/tools/browser/browser-execution.ts +2 -2
  663. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
  664. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  665. package/src/tools/browser/cdp-client/factory.ts +23 -24
  666. package/src/tools/browser/cdp-client/index.ts +1 -14
  667. package/src/tools/computer-use/definitions.ts +42 -20
  668. package/src/tools/executor.ts +2 -0
  669. package/src/tools/host-filesystem/edit.test.ts +151 -0
  670. package/src/tools/host-filesystem/edit.ts +68 -0
  671. package/src/tools/host-filesystem/read.test.ts +129 -0
  672. package/src/tools/host-filesystem/read.ts +68 -0
  673. package/src/tools/host-filesystem/transfer.test.ts +127 -2
  674. package/src/tools/host-filesystem/transfer.ts +78 -3
  675. package/src/tools/host-filesystem/write.test.ts +134 -0
  676. package/src/tools/host-filesystem/write.ts +68 -0
  677. package/src/tools/host-terminal/host-shell.ts +66 -1
  678. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  679. package/src/tools/memory/register.test.ts +12 -9
  680. package/src/tools/memory/register.ts +1 -2
  681. package/src/tools/provider-tool-name.ts +28 -0
  682. package/src/tools/registry.ts +30 -9
  683. package/src/tools/schedule/create.ts +6 -0
  684. package/src/tools/schedule/list.ts +2 -0
  685. package/src/tools/schedule/update.ts +10 -0
  686. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  687. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  688. package/src/tools/skills/load.ts +0 -32
  689. package/src/tools/terminal/shell.ts +9 -1
  690. package/src/tools/tool-approval-handler.ts +32 -11
  691. package/src/tools/types.ts +28 -2
  692. package/src/tts/provider-catalog.ts +3 -5
  693. package/src/usage/pricing.ts +1 -1
  694. package/src/util/disk-usage.ts +138 -0
  695. package/src/util/platform.ts +21 -11
  696. package/src/util/process-liveness.ts +26 -0
  697. package/src/workspace/hatched-date.ts +86 -0
  698. package/src/workspace/heartbeat-service.ts +19 -0
  699. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  700. package/src/workspace/migrations/006-services-config.ts +8 -5
  701. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  702. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  703. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  704. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  705. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  706. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  707. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
  708. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  709. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
  710. package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
  711. package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
  712. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
  713. package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
  714. package/src/workspace/migrations/AGENTS.md +1 -1
  715. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  716. package/src/workspace/migrations/registry.ts +8 -0
  717. package/src/workspace/migrations/utils.ts +21 -0
  718. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
  719. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
  720. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
  721. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
  722. package/src/__tests__/twilio-rest.test.ts +0 -34
  723. package/src/backup/__tests__/backup-key.test.ts +0 -152
  724. package/src/backup/__tests__/backup-worker.test.ts +0 -782
  725. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  726. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  727. package/src/backup/backup-key.ts +0 -137
  728. package/src/backup/backup-worker.ts +0 -472
  729. package/src/backup/offsite-writer.ts +0 -222
  730. package/src/backup/stream-crypt.ts +0 -263
  731. package/src/daemon/message-types/pairing.ts +0 -58
  732. package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
  733. package/src/memory/v2/skill-qdrant.ts +0 -395
  734. package/src/outbound-proxy/config.ts +0 -20
  735. package/src/outbound-proxy/health.ts +0 -18
  736. package/src/outbound-proxy/types.ts +0 -150
  737. package/src/runtime/capability-tokens.ts +0 -190
  738. package/src/signals/bash.ts +0 -198
  739. package/src/signals/mcp-reload.ts +0 -18
@@ -9,29 +9,40 @@ import {
9
9
  assistantEventHub,
10
10
  broadcastMessage,
11
11
  } from "../runtime/assistant-event-hub.js";
12
+ import {
13
+ ambiguousSameUserError,
14
+ enforceSameActorOrErrorResult,
15
+ pickSameUserAutoResolve,
16
+ } from "../runtime/auth/same-actor.js";
12
17
  import * as pendingInteractions from "../runtime/pending-interactions.js";
13
18
  import type { ToolExecutionResult } from "../tools/types.js";
14
19
  import { AssistantError, ErrorCode } from "../util/errors.js";
15
20
  import { getLogger } from "../util/logger.js";
16
- import type { ServerMessage } from "./message-protocol.js";
17
21
 
18
22
  const log = getLogger("host-transfer-proxy");
19
23
 
20
- interface PendingTransfer {
21
- resolve: (result: ToolExecutionResult) => void;
22
- reject: (err: Error) => void;
23
- timer: ReturnType<typeof setTimeout>;
24
+ /**
25
+ * Lightweight entry for the transfers map (keyed by transferId).
26
+ * Points back to the requestId so route handlers can correlate
27
+ * content endpoints with the pending interaction.
28
+ */
29
+ interface TransferEntry {
24
30
  requestId: string;
25
31
  transferId: string;
26
- conversationId: string;
27
32
  direction: "to_host" | "to_sandbox";
28
33
  filePath: string;
29
34
  overwrite?: boolean;
30
35
  sizeBytes?: number;
31
36
  sha256?: string;
32
37
  fileBuffer?: Buffer;
33
- /** Detach the abort listener from the caller's signal. No-op when no signal was passed. */
34
- detachAbort: () => void;
38
+ targetClientId?: string;
39
+ /**
40
+ * Snapshot of `targetClientId`'s `actorPrincipalId` taken at registration
41
+ * time. Persisted so the GET/PUT content routes compare against a stable
42
+ * value rather than the live hub — the target client's SSE subscription
43
+ * may briefly disconnect between dispatch and content fetch/upload.
44
+ */
45
+ targetActorPrincipalId?: string;
35
46
  }
36
47
 
37
48
  /**
@@ -82,10 +93,22 @@ export class HostTransferProxy {
82
93
  HostTransferProxy._instance = null;
83
94
  }
84
95
 
85
- /** Pending transfers keyed by requestId (for resolution from client results). */
86
- private pending = new Map<string, PendingTransfer>();
87
96
  /** Pending transfers keyed by transferId (for content endpoint lookups). */
88
- private transfers = new Map<string, PendingTransfer>();
97
+ private transfers = new Map<string, TransferEntry>();
98
+ /**
99
+ * Briefly retains size/sha256 of a just-consumed transfer so the GET-content
100
+ * route's `resolveResponseHeaders` callback (which the HTTP adapter invokes
101
+ * AFTER the request handler) can still set `Content-Length` and
102
+ * `X-Transfer-SHA256` headers. Without this, the handler's `getTransferContent`
103
+ * call deletes the entry before the header resolver runs, and the resolver
104
+ * silently falls back to default headers — meaning the documented response
105
+ * headers were never actually sent. Entries here self-clear on read; a 30s
106
+ * fallback timer prevents long-term retention if the resolver never runs.
107
+ */
108
+ private justConsumedMetadata = new Map<
109
+ string,
110
+ { sizeBytes: number; sha256: string }
111
+ >();
89
112
 
90
113
  /**
91
114
  * Whether a client with `host_file` capability is connected.
@@ -97,10 +120,6 @@ export class HostTransferProxy {
97
120
  );
98
121
  }
99
122
 
100
- private send(msg: ServerMessage): void {
101
- broadcastMessage(msg, undefined, { targetCapability: "host_file" });
102
- }
103
-
104
123
  /**
105
124
  * Request a file transfer from the sandbox to the host machine.
106
125
  *
@@ -114,20 +133,63 @@ export class HostTransferProxy {
114
133
  destPath: string;
115
134
  overwrite: boolean;
116
135
  conversationId: string;
136
+ targetClientId?: string;
117
137
  },
118
138
  signal?: AbortSignal,
139
+ // Principal ID of the actor on whose behalf this request is initiated.
140
+ sourceActorPrincipalId?: string,
119
141
  ): Promise<ToolExecutionResult> {
120
142
  if (signal?.aborted) {
121
143
  return Promise.resolve({ content: "Aborted", isError: true });
122
144
  }
123
145
 
146
+ let resolvedTargetClientId: string | undefined = input.targetClientId;
147
+ if (resolvedTargetClientId != null) {
148
+ const client = assistantEventHub.getClientById(resolvedTargetClientId);
149
+ if (!client) {
150
+ return Promise.resolve({
151
+ content: `No connected client with id '${resolvedTargetClientId}' supports host_file. Run \`assistant clients list --capability host_file\` to see available clients.`,
152
+ isError: true,
153
+ });
154
+ }
155
+ if (!client.capabilities.includes("host_file")) {
156
+ return Promise.resolve({
157
+ content: `Client '${resolvedTargetClientId}' does not support host_file. Run \`assistant clients list --capability host_file\` to see available clients.`,
158
+ isError: true,
159
+ });
160
+ }
161
+ } else {
162
+ // Auto-resolve to the unique same-user client; reject ambiguous
163
+ // (multi-machine) cases so a single targeted-style transfer cannot
164
+ // fan out across the user's machines.
165
+ const resolved = pickSameUserAutoResolve({
166
+ hub: assistantEventHub,
167
+ capability: "host_file",
168
+ sourceActorPrincipalId,
169
+ });
170
+ if (resolved.kind === "ambiguous") {
171
+ return Promise.resolve(ambiguousSameUserError("host_file"));
172
+ }
173
+ resolvedTargetClientId =
174
+ resolved.kind === "match" ? resolved.clientId : undefined;
175
+ }
176
+
177
+ if (resolvedTargetClientId != null) {
178
+ const rejection = enforceSameActorOrErrorResult({
179
+ hub: assistantEventHub,
180
+ sourceActorPrincipalId,
181
+ targetClientId: resolvedTargetClientId,
182
+ op: "host_transfer",
183
+ });
184
+ if (rejection != null) return Promise.resolve(rejection);
185
+ }
186
+
124
187
  const requestId = uuid();
125
188
  const transferId = uuid();
126
189
 
127
190
  return new Promise<ToolExecutionResult>((resolve, reject) => {
128
191
  readFile(input.sourcePath)
129
192
  .then((fileBuffer) => {
130
- // Check again after async read in case signal fired during I/O.
131
193
  if (signal?.aborted) {
132
194
  resolve({ content: "Aborted", isError: true });
133
195
  return;
@@ -142,37 +204,40 @@ export class HostTransferProxy {
142
204
  let detachAbort: () => void = () => {};
143
205
 
144
206
  const timer = setTimeout(() => {
145
- this.pending.delete(requestId);
146
207
  this.transfers.delete(transferId);
147
- detachAbort();
148
208
  pendingInteractions.resolve(requestId);
149
209
  log.warn(
150
210
  { requestId, transferId, direction: "to_host" },
151
211
  "Host transfer proxy request timed out",
152
212
  );
153
213
  resolve({
154
- content:
155
- "Host transfer proxy timed out waiting for client response",
214
+ content: resolvedTargetClientId
215
+ ? `Host transfer proxy timed out waiting for response from client '${resolvedTargetClientId}'`
216
+ : "Host transfer proxy timed out waiting for client response",
156
217
  isError: true,
157
218
  });
158
219
  }, timeoutMs);
159
220
 
160
221
  if (signal) {
161
222
  const onAbort = () => {
162
- if (this.pending.has(requestId)) {
163
- clearTimeout(timer);
164
- this.pending.delete(requestId);
223
+ if (pendingInteractions.get(requestId)) {
165
224
  this.transfers.delete(transferId);
166
- detachAbort();
167
225
  pendingInteractions.resolve(requestId);
168
226
  try {
169
- this.send({
170
- type: "host_transfer_cancel",
171
- requestId,
172
- conversationId: input.conversationId,
173
- });
227
+ broadcastMessage(
228
+ {
229
+ type: "host_transfer_cancel",
230
+ requestId,
231
+ conversationId: input.conversationId,
232
+ ...(resolvedTargetClientId != null
233
+ ? { targetClientId: resolvedTargetClientId }
234
+ : {}),
235
+ },
236
+ input.conversationId,
237
+ { targetClientId: resolvedTargetClientId },
238
+ );
174
239
  } catch {
175
- // Best-effort cancel notification — connection may already be closed.
240
+ // Best-effort cancel notification
176
241
  }
177
242
  resolve({ content: "Aborted", isError: true });
178
243
  }
@@ -181,40 +246,61 @@ export class HostTransferProxy {
181
246
  detachAbort = () => signal.removeEventListener("abort", onAbort);
182
247
  }
183
248
 
184
- const entry: PendingTransfer = {
185
- resolve,
186
- reject,
187
- timer,
249
+ this.transfers.set(transferId, {
188
250
  requestId,
189
251
  transferId,
190
- conversationId: input.conversationId,
191
252
  direction: "to_host",
192
253
  filePath: input.destPath,
193
254
  sizeBytes,
194
255
  sha256,
195
256
  fileBuffer,
257
+ targetClientId: resolvedTargetClientId,
258
+ targetActorPrincipalId:
259
+ resolvedTargetClientId != null
260
+ ? assistantEventHub.getActorPrincipalIdForClient(
261
+ resolvedTargetClientId,
262
+ )
263
+ : undefined,
264
+ });
265
+
266
+ pendingInteractions.register(requestId, {
267
+ conversationId: input.conversationId,
268
+ kind: "host_transfer",
269
+ targetClientId: resolvedTargetClientId,
270
+ targetActorPrincipalId:
271
+ resolvedTargetClientId != null
272
+ ? assistantEventHub.getActorPrincipalIdForClient(
273
+ resolvedTargetClientId,
274
+ )
275
+ : undefined,
276
+ rpcResolve: resolve,
277
+ rpcReject: reject,
278
+ timer,
196
279
  detachAbort,
197
- };
198
- this.pending.set(requestId, entry);
199
- this.transfers.set(transferId, entry);
280
+ metadata: { transferId },
281
+ });
200
282
 
201
283
  try {
202
- this.send({
203
- type: "host_transfer_request",
204
- requestId,
205
- conversationId: input.conversationId,
206
- direction: "to_host",
207
- transferId,
208
- destPath: input.destPath,
209
- sizeBytes,
210
- sha256,
211
- overwrite: input.overwrite,
212
- });
284
+ broadcastMessage(
285
+ {
286
+ type: "host_transfer_request",
287
+ requestId,
288
+ conversationId: input.conversationId,
289
+ direction: "to_host",
290
+ transferId,
291
+ destPath: input.destPath,
292
+ sizeBytes,
293
+ sha256,
294
+ overwrite: input.overwrite,
295
+ ...(resolvedTargetClientId != null
296
+ ? { targetClientId: resolvedTargetClientId }
297
+ : {}),
298
+ },
299
+ input.conversationId,
300
+ { targetClientId: resolvedTargetClientId },
301
+ );
213
302
  } catch (err) {
214
- clearTimeout(timer);
215
- this.pending.delete(requestId);
216
303
  this.transfers.delete(transferId);
217
- detachAbort();
218
304
  pendingInteractions.resolve(requestId);
219
305
  log.warn(
220
306
  { requestId, transferId, err },
@@ -249,13 +335,57 @@ export class HostTransferProxy {
249
335
  destPath: string;
250
336
  overwrite?: boolean;
251
337
  conversationId: string;
338
+ targetClientId?: string;
252
339
  },
253
340
  signal?: AbortSignal,
341
+ // Principal ID of the actor on whose behalf this request is initiated.
342
+ sourceActorPrincipalId?: string,
254
343
  ): Promise<ToolExecutionResult> {
255
344
  if (signal?.aborted) {
256
345
  return Promise.resolve({ content: "Aborted", isError: true });
257
346
  }
258
347
 
348
+ let resolvedTargetClientId: string | undefined = input.targetClientId;
349
+ if (resolvedTargetClientId != null) {
350
+ const client = assistantEventHub.getClientById(resolvedTargetClientId);
351
+ if (!client) {
352
+ return Promise.resolve({
353
+ content: `No connected client with id '${resolvedTargetClientId}' supports host_file. Run \`assistant clients list --capability host_file\` to see available clients.`,
354
+ isError: true,
355
+ });
356
+ }
357
+ if (!client.capabilities.includes("host_file")) {
358
+ return Promise.resolve({
359
+ content: `Client '${resolvedTargetClientId}' does not support host_file. Run \`assistant clients list --capability host_file\` to see available clients.`,
360
+ isError: true,
361
+ });
362
+ }
363
+ } else {
364
+ // Auto-resolve to the unique same-user client; reject ambiguous
365
+ // (multi-machine) cases so a single targeted-style transfer cannot
366
+ // fan out across the user's machines.
367
+ const resolved = pickSameUserAutoResolve({
368
+ hub: assistantEventHub,
369
+ capability: "host_file",
370
+ sourceActorPrincipalId,
371
+ });
372
+ if (resolved.kind === "ambiguous") {
373
+ return Promise.resolve(ambiguousSameUserError("host_file"));
374
+ }
375
+ resolvedTargetClientId =
376
+ resolved.kind === "match" ? resolved.clientId : undefined;
377
+ }
378
+
379
+ if (resolvedTargetClientId != null) {
380
+ const rejection = enforceSameActorOrErrorResult({
381
+ hub: assistantEventHub,
382
+ sourceActorPrincipalId,
383
+ targetClientId: resolvedTargetClientId,
384
+ op: "host_transfer",
385
+ });
386
+ if (rejection != null) return Promise.resolve(rejection);
387
+ }
388
+
259
389
  const requestId = uuid();
260
390
  const transferId = uuid();
261
391
 
@@ -265,36 +395,40 @@ export class HostTransferProxy {
265
395
  let detachAbort: () => void = () => {};
266
396
 
267
397
  const timer = setTimeout(() => {
268
- this.pending.delete(requestId);
269
398
  this.transfers.delete(transferId);
270
- detachAbort();
271
399
  pendingInteractions.resolve(requestId);
272
400
  log.warn(
273
401
  { requestId, transferId, direction: "to_sandbox" },
274
402
  "Host transfer proxy request timed out",
275
403
  );
276
404
  resolve({
277
- content: "Host transfer proxy timed out waiting for client response",
405
+ content: resolvedTargetClientId
406
+ ? `Host transfer proxy timed out waiting for response from client '${resolvedTargetClientId}'`
407
+ : "Host transfer proxy timed out waiting for client response",
278
408
  isError: true,
279
409
  });
280
410
  }, timeoutMs);
281
411
 
282
412
  if (signal) {
283
413
  const onAbort = () => {
284
- if (this.pending.has(requestId)) {
285
- clearTimeout(timer);
286
- this.pending.delete(requestId);
414
+ if (pendingInteractions.get(requestId)) {
287
415
  this.transfers.delete(transferId);
288
- detachAbort();
289
416
  pendingInteractions.resolve(requestId);
290
417
  try {
291
- this.send({
292
- type: "host_transfer_cancel",
293
- requestId,
294
- conversationId: input.conversationId,
295
- });
418
+ broadcastMessage(
419
+ {
420
+ type: "host_transfer_cancel",
421
+ requestId,
422
+ conversationId: input.conversationId,
423
+ ...(resolvedTargetClientId != null
424
+ ? { targetClientId: resolvedTargetClientId }
425
+ : {}),
426
+ },
427
+ input.conversationId,
428
+ { targetClientId: resolvedTargetClientId },
429
+ );
296
430
  } catch {
297
- // Best-effort cancel notification — connection may already be closed.
431
+ // Best-effort cancel notification
298
432
  }
299
433
  resolve({ content: "Aborted", isError: true });
300
434
  }
@@ -303,35 +437,56 @@ export class HostTransferProxy {
303
437
  detachAbort = () => signal.removeEventListener("abort", onAbort);
304
438
  }
305
439
 
306
- const entry: PendingTransfer = {
307
- resolve,
308
- reject,
309
- timer,
440
+ this.transfers.set(transferId, {
310
441
  requestId,
311
442
  transferId,
312
- conversationId: input.conversationId,
313
443
  direction: "to_sandbox",
314
444
  filePath: input.destPath,
315
445
  overwrite: input.overwrite,
446
+ targetClientId: resolvedTargetClientId,
447
+ targetActorPrincipalId:
448
+ resolvedTargetClientId != null
449
+ ? assistantEventHub.getActorPrincipalIdForClient(
450
+ resolvedTargetClientId,
451
+ )
452
+ : undefined,
453
+ });
454
+
455
+ pendingInteractions.register(requestId, {
456
+ conversationId: input.conversationId,
457
+ kind: "host_transfer",
458
+ targetClientId: resolvedTargetClientId,
459
+ targetActorPrincipalId:
460
+ resolvedTargetClientId != null
461
+ ? assistantEventHub.getActorPrincipalIdForClient(
462
+ resolvedTargetClientId,
463
+ )
464
+ : undefined,
465
+ rpcResolve: resolve,
466
+ rpcReject: reject,
467
+ timer,
316
468
  detachAbort,
317
- };
318
- this.pending.set(requestId, entry);
319
- this.transfers.set(transferId, entry);
469
+ metadata: { transferId },
470
+ });
320
471
 
321
472
  try {
322
- this.send({
323
- type: "host_transfer_request",
324
- requestId,
325
- conversationId: input.conversationId,
326
- direction: "to_sandbox",
327
- transferId,
328
- sourcePath: input.sourcePath,
329
- });
473
+ broadcastMessage(
474
+ {
475
+ type: "host_transfer_request",
476
+ requestId,
477
+ conversationId: input.conversationId,
478
+ direction: "to_sandbox",
479
+ transferId,
480
+ sourcePath: input.sourcePath,
481
+ ...(resolvedTargetClientId != null
482
+ ? { targetClientId: resolvedTargetClientId }
483
+ : {}),
484
+ },
485
+ input.conversationId,
486
+ { targetClientId: resolvedTargetClientId },
487
+ );
330
488
  } catch (err) {
331
- clearTimeout(timer);
332
- this.pending.delete(requestId);
333
489
  this.transfers.delete(transferId);
334
- detachAbort();
335
490
  pendingInteractions.resolve(requestId);
336
491
  log.warn(
337
492
  { requestId, transferId, err },
@@ -353,23 +508,21 @@ export class HostTransferProxy {
353
508
  errorMessage?: string;
354
509
  },
355
510
  ): void {
356
- const entry = this.pending.get(requestId);
357
- if (!entry) {
511
+ const interaction = pendingInteractions.resolve(requestId);
512
+ if (!interaction?.rpcResolve) {
358
513
  log.warn({ requestId }, "No pending host transfer request for response");
359
514
  return;
360
515
  }
361
- clearTimeout(entry.timer);
362
- entry.detachAbort();
363
- this.pending.delete(requestId);
364
- this.transfers.delete(entry.transferId);
516
+ const transferId = interaction.metadata?.transferId as string | undefined;
517
+ if (transferId) this.transfers.delete(transferId);
365
518
 
366
519
  if (result.isError) {
367
- entry.resolve({
520
+ interaction.rpcResolve({
368
521
  content: result.errorMessage ?? "Host transfer failed",
369
522
  isError: true,
370
523
  });
371
524
  } else {
372
- entry.resolve({
525
+ interaction.rpcResolve({
373
526
  content: `File transferred successfully${result.bytesWritten != null ? ` (${result.bytesWritten} bytes)` : ""}`,
374
527
  isError: false,
375
528
  });
@@ -394,8 +547,21 @@ export class HostTransferProxy {
394
547
  ) {
395
548
  return null;
396
549
  }
397
- // Single-use: consume the transfer from the transfers map.
398
- // The pending map entry stays alive for the result resolution.
550
+ // Stash size/sha256 so the GET-content route's `resolveResponseHeaders`
551
+ // callback can still set `Content-Length` and `X-Transfer-SHA256` on the
552
+ // response. The HTTP adapter invokes the handler (this method) BEFORE the
553
+ // response-header resolver, so without this stash the resolver sees a
554
+ // deleted entry and silently falls back to default headers.
555
+ this.justConsumedMetadata.set(transferId, {
556
+ sizeBytes: entry.sizeBytes,
557
+ sha256: entry.sha256,
558
+ });
559
+ // Fallback cleanup: if the resolver never reads (e.g., handler error after
560
+ // consume, request abort), drop the metadata after a short grace window.
561
+ // `unref()` so the timer never holds the process open.
562
+ setTimeout(() => {
563
+ this.justConsumedMetadata.delete(transferId);
564
+ }, 30_000).unref?.();
399
565
  this.transfers.delete(transferId);
400
566
  return {
401
567
  buffer: entry.fileBuffer,
@@ -404,6 +570,23 @@ export class HostTransferProxy {
404
570
  };
405
571
  }
406
572
 
573
+ /**
574
+ * Returns and clears the size/sha256 metadata for a transfer that was just
575
+ * consumed by `getTransferContent`. Intended for use by the GET-content
576
+ * route's `resolveResponseHeaders` callback to populate `Content-Length` and
577
+ * `X-Transfer-SHA256` response headers. Returns null if no metadata is
578
+ * cached (e.g., transfer was never consumed, or already read by a previous
579
+ * resolver call).
580
+ */
581
+ takeJustConsumedTransferMetadata(
582
+ transferId: string,
583
+ ): { sizeBytes: number; sha256: string } | null {
584
+ const meta = this.justConsumedMetadata.get(transferId);
585
+ if (!meta) return null;
586
+ this.justConsumedMetadata.delete(transferId);
587
+ return meta;
588
+ }
589
+
407
590
  /**
408
591
  * Receive file content from the client for a to_sandbox transfer (the PUT content endpoint).
409
592
  *
@@ -437,29 +620,25 @@ export class HostTransferProxy {
437
620
 
438
621
  const { requestId } = entry;
439
622
 
440
- // Enforce overwrite policy before writing.
441
623
  if (entry.overwrite !== true && existsSync(entry.filePath)) {
442
624
  const errorMsg = `Destination file already exists: ${entry.filePath}. Set overwrite to true to replace it.`;
443
- clearTimeout(entry.timer);
444
- entry.detachAbort();
445
- this.pending.delete(requestId);
625
+ const interaction = pendingInteractions.resolve(requestId);
446
626
  this.transfers.delete(transferId);
447
- entry.resolve({ content: errorMsg, isError: true });
627
+ interaction?.rpcResolve?.({ content: errorMsg, isError: true });
448
628
  return { accepted: false, error: errorMsg };
449
629
  }
450
630
 
451
631
  const cleanup = () => {
452
- clearTimeout(entry.timer);
453
- entry.detachAbort();
454
- this.pending.delete(requestId);
632
+ pendingInteractions.resolve(requestId);
455
633
  this.transfers.delete(transferId);
456
634
  };
457
635
 
458
636
  try {
459
637
  await mkdir(dirname(entry.filePath), { recursive: true });
460
638
  await writeFile(entry.filePath, data);
639
+ const interaction = pendingInteractions.get(requestId);
461
640
  cleanup();
462
- entry.resolve({
641
+ interaction?.rpcResolve?.({
463
642
  content: `File received and written to ${entry.filePath} (${data.length} bytes)`,
464
643
  isError: false,
465
644
  });
@@ -470,31 +649,37 @@ export class HostTransferProxy {
470
649
  { transferId, filePath: entry.filePath, err },
471
650
  "Failed to write received transfer content",
472
651
  );
652
+ const interaction = pendingInteractions.get(requestId);
473
653
  cleanup();
474
- entry.resolve({ content: errorMsg, isError: true });
654
+ interaction?.rpcResolve?.({ content: errorMsg, isError: true });
475
655
  return { accepted: false, error: errorMsg };
476
656
  }
477
657
  }
478
658
 
479
659
  /** Cancel a pending transfer by requestId. */
480
660
  cancel(requestId: string): void {
481
- const entry = this.pending.get(requestId);
482
- if (!entry) return;
483
- clearTimeout(entry.timer);
484
- entry.detachAbort();
485
- this.pending.delete(requestId);
486
- this.transfers.delete(entry.transferId);
661
+ const interaction = pendingInteractions.get(requestId);
662
+ if (!interaction) return;
663
+ const transferId = interaction.metadata?.transferId as string | undefined;
664
+ if (transferId) this.transfers.delete(transferId);
487
665
  pendingInteractions.resolve(requestId);
488
666
  try {
489
- this.send({
490
- type: "host_transfer_cancel",
491
- requestId,
492
- conversationId: entry.conversationId,
493
- });
667
+ broadcastMessage(
668
+ {
669
+ type: "host_transfer_cancel",
670
+ requestId,
671
+ conversationId: interaction.conversationId,
672
+ ...(interaction.targetClientId != null
673
+ ? { targetClientId: interaction.targetClientId }
674
+ : {}),
675
+ },
676
+ interaction.conversationId,
677
+ { targetClientId: interaction.targetClientId },
678
+ );
494
679
  } catch {
495
- // Best-effort cancel notification — connection may already be closed.
680
+ // Best-effort cancel notification
496
681
  }
497
- entry.resolve({ content: "Transfer cancelled", isError: true });
682
+ interaction.rpcResolve?.({ content: "Transfer cancelled", isError: true });
498
683
  }
499
684
 
500
685
  hasPendingTransfer(transferId: string): boolean {
@@ -511,28 +696,52 @@ export class HostTransferProxy {
511
696
  return entry?.requestId ?? null;
512
697
  }
513
698
 
699
+ /**
700
+ * Look up the targetClientId for a given transferId without consuming the entry.
701
+ * Routes call this to verify ownership without affecting the transfer state.
702
+ * Returns null when untargeted (no validation needed).
703
+ */
704
+ getTargetClientIdForTransfer(transferId: string): string | null {
705
+ return this.transfers.get(transferId)?.targetClientId ?? null;
706
+ }
707
+
708
+ /**
709
+ * Look up the persisted `targetActorPrincipalId` for a given transferId
710
+ * without consuming the entry. Routes call this for the same-actor
711
+ * binding check so it's stable across brief SSE reconnects.
712
+ */
713
+ getTargetActorPrincipalIdForTransfer(transferId: string): string | undefined {
714
+ return this.transfers.get(transferId)?.targetActorPrincipalId;
715
+ }
716
+
514
717
  dispose(): void {
515
- for (const [requestId, entry] of this.pending) {
516
- clearTimeout(entry.timer);
517
- entry.detachAbort();
518
- pendingInteractions.resolve(requestId);
718
+ for (const entry of pendingInteractions.getByKind("host_transfer")) {
719
+ const transferId = entry.metadata?.transferId as string | undefined;
720
+ if (transferId) this.transfers.delete(transferId);
721
+ pendingInteractions.resolve(entry.requestId);
519
722
  try {
520
- this.send({
723
+ broadcastMessage(
724
+ {
521
725
  type: "host_transfer_cancel",
522
- requestId,
726
+ requestId: entry.requestId,
523
727
  conversationId: entry.conversationId,
524
- });
525
- } catch {
526
- // Best-effort cancel notification — connection may already be closed.
527
- }
528
- entry.reject(
728
+ ...(entry.targetClientId != null
729
+ ? { targetClientId: entry.targetClientId }
730
+ : {}),
731
+ },
732
+ entry.conversationId,
733
+ { targetClientId: entry.targetClientId },
734
+ );
735
+ } catch {
736
+ // Best-effort cancel notification
737
+ }
738
+ entry.rpcReject?.(
529
739
  new AssistantError(
530
740
  "Host transfer proxy disposed",
531
741
  ErrorCode.INTERNAL_ERROR,
532
742
  ),
533
743
  );
534
744
  }
535
- this.pending.clear();
536
745
  this.transfers.clear();
537
746
  }
538
747
  }