@vellumai/assistant 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (666) hide show
  1. package/ARCHITECTURE.md +6 -7
  2. package/Dockerfile +1 -0
  3. package/README.md +2 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
  5. package/bun.lock +3 -0
  6. package/docs/architecture/security.md +18 -16
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  9. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
  10. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  11. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  12. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  13. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  14. package/node_modules/@vellumai/slack-text/package.json +18 -0
  15. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  16. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  17. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  18. package/openapi.yaml +294 -107
  19. package/package.json +4 -2
  20. package/scripts/generate-openapi.ts +16 -111
  21. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  22. package/src/__tests__/anthropic-provider.test.ts +56 -13
  23. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  24. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  25. package/src/__tests__/approval-cascade.test.ts +0 -15
  26. package/src/__tests__/approval-routes-http.test.ts +6 -17
  27. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  28. package/src/__tests__/assistant-event.test.ts +0 -5
  29. package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
  30. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  31. package/src/__tests__/background-shell-host-bash.test.ts +34 -43
  32. package/src/__tests__/call-controller.test.ts +1 -1
  33. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  34. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  35. package/src/__tests__/channel-approvals.test.ts +25 -17
  36. package/src/__tests__/channel-guardian.test.ts +100 -146
  37. package/src/__tests__/checker.test.ts +20 -34
  38. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  39. package/src/__tests__/compaction-events.test.ts +2 -0
  40. package/src/__tests__/config-schema.test.ts +6 -48
  41. package/src/__tests__/config-watcher.test.ts +12 -0
  42. package/src/__tests__/connection-policy.test.ts +1 -52
  43. package/src/__tests__/contacts-write.test.ts +2 -64
  44. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  45. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  46. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  47. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  48. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  49. package/src/__tests__/context-window-manager.test.ts +46 -0
  50. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  51. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  52. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  53. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  54. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  55. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  56. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  57. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  58. package/src/__tests__/conversation-lifecycle.test.ts +4 -4
  59. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  60. package/src/__tests__/conversation-queue.test.ts +3 -8
  61. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
  62. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
  63. package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
  64. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  65. package/src/__tests__/conversation-slash-commands.test.ts +24 -4
  66. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  68. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  69. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  70. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  71. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  72. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  73. package/src/__tests__/conversation-usage.test.ts +253 -3
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  75. package/src/__tests__/credential-health-service.test.ts +68 -0
  76. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  77. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  78. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  79. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  80. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  81. package/src/__tests__/daemon-credential-client.test.ts +4 -1
  82. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  83. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  84. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  85. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  86. package/src/__tests__/document-conversations.test.ts +332 -0
  87. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  88. package/src/__tests__/emit-event-signal.test.ts +4 -6
  89. package/src/__tests__/events-client-registration.test.ts +193 -49
  90. package/src/__tests__/filing-service.test.ts +58 -7
  91. package/src/__tests__/first-greeting.test.ts +156 -150
  92. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  93. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  94. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  95. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  96. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  97. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  98. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  99. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
  100. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
  101. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  102. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  103. package/src/__tests__/heartbeat-service.test.ts +289 -7
  104. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  105. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  106. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  107. package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
  108. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
  109. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  110. package/src/__tests__/host-browser-routes.test.ts +45 -75
  111. package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
  112. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  113. package/src/__tests__/host-file-proxy.test.ts +44 -98
  114. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  115. package/src/__tests__/host-shell-tool.test.ts +33 -68
  116. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  117. package/src/__tests__/host-transfer-proxy.test.ts +43 -53
  118. package/src/__tests__/http-user-message-parity.test.ts +0 -6
  119. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  120. package/src/__tests__/injector-chain.test.ts +10 -5
  121. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  122. package/src/__tests__/inline-command-runner.test.ts +0 -66
  123. package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
  124. package/src/__tests__/install-skill-routing.test.ts +1 -13
  125. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  126. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  127. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  128. package/src/__tests__/llm-resolver.test.ts +80 -12
  129. package/src/__tests__/llm-usage-store.test.ts +269 -4
  130. package/src/__tests__/log-export-routes.test.ts +89 -0
  131. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  132. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  133. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  134. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  135. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  136. package/src/__tests__/migration-export-http.test.ts +33 -26
  137. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  138. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  139. package/src/__tests__/migration-import-commit-http.test.ts +66 -21
  140. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  141. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  142. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  143. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  144. package/src/__tests__/migration-transport.test.ts +115 -23
  145. package/src/__tests__/migration-validate-http.test.ts +105 -80
  146. package/src/__tests__/migration-wizard.test.ts +133 -27
  147. package/src/__tests__/non-member-access-request.test.ts +1 -1
  148. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  149. package/src/__tests__/oauth-store.test.ts +19 -0
  150. package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
  151. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  152. package/src/__tests__/pricing.test.ts +68 -4
  153. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  154. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  155. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  156. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  157. package/src/__tests__/reaction-persistence.test.ts +9 -6
  158. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  159. package/src/__tests__/recording-handler.test.ts +64 -81
  160. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  161. package/src/__tests__/relay-server.test.ts +18 -13
  162. package/src/__tests__/require-fresh-approval.test.ts +13 -22
  163. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  164. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  165. package/src/__tests__/runtime-events-sse.test.ts +3 -12
  166. package/src/__tests__/search-skills-unified.test.ts +9 -15
  167. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  168. package/src/__tests__/secret-ingress-http.test.ts +0 -4
  169. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  170. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  171. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  172. package/src/__tests__/secret-response-routing.test.ts +29 -15
  173. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  174. package/src/__tests__/secret-scanner.test.ts +2 -545
  175. package/src/__tests__/send-endpoint-busy.test.ts +9 -24
  176. package/src/__tests__/settings-routes.test.ts +1 -1
  177. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  178. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  179. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  180. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  181. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  182. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  183. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  184. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  185. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  186. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  187. package/src/__tests__/system-prompt.test.ts +115 -13
  188. package/src/__tests__/terminal-tools.test.ts +0 -89
  189. package/src/__tests__/thread-backfill.test.ts +945 -31
  190. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  191. package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
  192. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  193. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  194. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
  195. package/src/__tests__/tool-executor.test.ts +12 -19
  196. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  197. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  198. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  199. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  200. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  201. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  202. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  203. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  204. package/src/__tests__/usage-attribution.test.ts +247 -0
  205. package/src/__tests__/usage-cli.test.ts +143 -0
  206. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  207. package/src/__tests__/usage-routes.test.ts +150 -0
  208. package/src/__tests__/validation-results-screen.test.ts +39 -16
  209. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  210. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
  211. package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
  212. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  213. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  214. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  215. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  216. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  217. package/src/acp/index.ts +0 -15
  218. package/src/acp/session-manager.ts +37 -34
  219. package/src/agent/loop.ts +16 -1
  220. package/src/approvals/AGENTS.md +4 -0
  221. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  222. package/src/approvals/guardian-request-resolvers.ts +10 -2
  223. package/src/backup/__tests__/backup-worker.test.ts +36 -8
  224. package/src/backup/__tests__/paths.test.ts +2 -2
  225. package/src/backup/__tests__/restore.test.ts +45 -28
  226. package/src/backup/backup-worker.ts +36 -2
  227. package/src/backup/paths.ts +9 -6
  228. package/src/browser-session/events.ts +0 -9
  229. package/src/calls/call-store.ts +1 -34
  230. package/src/calls/guardian-question-copy.ts +0 -108
  231. package/src/calls/relay-server.ts +0 -24
  232. package/src/calls/twilio-rest.ts +0 -38
  233. package/src/calls/twilio-routes.ts +1 -1
  234. package/src/calls/voice-session-bridge.ts +7 -38
  235. package/src/channels/types.ts +1 -36
  236. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  237. package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
  238. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  239. package/src/cli/commands/backup.ts +4 -4
  240. package/src/cli/commands/cache-fs.ts +8 -0
  241. package/src/cli/commands/cache.ts +153 -82
  242. package/src/cli/commands/clients.ts +63 -5
  243. package/src/cli/commands/completions.ts +3 -3
  244. package/src/cli/commands/contacts.ts +231 -76
  245. package/src/cli/commands/keys.ts +4 -1
  246. package/src/cli/commands/memory-v2.ts +24 -52
  247. package/src/cli/commands/oauth/shared.ts +2 -29
  248. package/src/cli/commands/pending.ts +102 -0
  249. package/src/cli/commands/skills.ts +77 -35
  250. package/src/cli/commands/trust.ts +70 -430
  251. package/src/cli/commands/usage.ts +25 -16
  252. package/src/cli/lib/daemon-credential-client.ts +14 -0
  253. package/src/cli/program.ts +2 -0
  254. package/src/cli.ts +0 -21
  255. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  256. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  257. package/src/config/env-registry.ts +12 -2
  258. package/src/config/env.ts +3 -14
  259. package/src/config/feature-flag-registry.json +30 -30
  260. package/src/config/llm-callsite-catalog.ts +12 -0
  261. package/src/config/llm-context-resolution.ts +80 -0
  262. package/src/config/llm-resolver.ts +58 -22
  263. package/src/config/loader.ts +3 -3
  264. package/src/config/schema.ts +2 -158
  265. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  266. package/src/config/schemas/call-site-catalog.ts +271 -0
  267. package/src/config/schemas/calls.ts +5 -5
  268. package/src/config/schemas/inference.ts +1 -1
  269. package/src/config/schemas/ingress.ts +1 -1
  270. package/src/config/schemas/llm.ts +31 -3
  271. package/src/config/schemas/memory-retrieval.ts +2 -2
  272. package/src/config/schemas/memory-v2.ts +9 -0
  273. package/src/config/schemas/security.ts +1 -42
  274. package/src/config/schemas/services.ts +6 -6
  275. package/src/config/schemas/skills.ts +5 -5
  276. package/src/config/schemas/tts.ts +1 -1
  277. package/src/config/seed-inference-profiles.ts +117 -0
  278. package/src/config/skills.ts +0 -90
  279. package/src/config/types.ts +3 -6
  280. package/src/contacts/contact-store.ts +0 -17
  281. package/src/contacts/contacts-write.ts +1 -105
  282. package/src/context/window-manager.ts +44 -5
  283. package/src/credential-execution/process-manager.ts +34 -10
  284. package/src/credential-health/credential-health-service.ts +21 -16
  285. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  286. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  287. package/src/daemon/connection-policy.ts +1 -26
  288. package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
  289. package/src/daemon/conversation-agent-loop.ts +277 -36
  290. package/src/daemon/conversation-history.ts +8 -8
  291. package/src/daemon/conversation-launch.ts +20 -135
  292. package/src/daemon/conversation-lifecycle.ts +1 -1
  293. package/src/daemon/conversation-messaging.ts +1 -0
  294. package/src/daemon/conversation-process.ts +83 -163
  295. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  296. package/src/daemon/conversation-slash.ts +47 -5
  297. package/src/daemon/conversation-store.ts +7 -31
  298. package/src/daemon/conversation-surfaces.ts +22 -28
  299. package/src/daemon/conversation-tool-setup.ts +3 -33
  300. package/src/daemon/conversation-usage.ts +36 -0
  301. package/src/daemon/conversation.ts +117 -233
  302. package/src/daemon/daemon-control.ts +3 -71
  303. package/src/daemon/daemon-skill-host.ts +8 -11
  304. package/src/daemon/dictation-profile-store.ts +2 -26
  305. package/src/daemon/first-greeting.ts +44 -156
  306. package/src/daemon/handlers/config-channels.ts +12 -12
  307. package/src/daemon/handlers/config-ingress.ts +4 -165
  308. package/src/daemon/handlers/config-model.ts +1 -1
  309. package/src/daemon/handlers/config-voice.ts +0 -42
  310. package/src/daemon/handlers/conversations.ts +11 -190
  311. package/src/daemon/handlers/recording.ts +26 -158
  312. package/src/daemon/handlers/shared.ts +23 -71
  313. package/src/daemon/handlers/skills.ts +42 -93
  314. package/src/daemon/host-bash-proxy.ts +67 -45
  315. package/src/daemon/host-browser-proxy.ts +65 -27
  316. package/src/daemon/host-cu-proxy.ts +40 -39
  317. package/src/daemon/host-file-proxy.ts +58 -37
  318. package/src/daemon/host-transfer-proxy.ts +84 -46
  319. package/src/daemon/lifecycle.ts +49 -15
  320. package/src/daemon/message-types/conversations.ts +7 -0
  321. package/src/daemon/message-types/host-bash.ts +1 -0
  322. package/src/daemon/message-types/host-cu.ts +1 -0
  323. package/src/daemon/message-types/host-file.ts +1 -0
  324. package/src/daemon/message-types/host-transfer.ts +1 -0
  325. package/src/daemon/message-types/messages.ts +10 -9
  326. package/src/daemon/message-types/workspace.ts +1 -1
  327. package/src/daemon/process-message.ts +102 -239
  328. package/src/daemon/server.ts +13 -462
  329. package/src/daemon/shutdown-handlers.ts +2 -2
  330. package/src/daemon/tool-side-effects.ts +125 -107
  331. package/src/daemon/trust-context.ts +13 -0
  332. package/src/daemon/wake-target-adapter.ts +4 -9
  333. package/src/events/domain-events.ts +0 -8
  334. package/src/events/tool-audit-listener.ts +3 -1
  335. package/src/events/tool-domain-event-publisher.ts +0 -10
  336. package/src/events/tool-metrics-listener.ts +0 -17
  337. package/src/events/tool-trace-listener.ts +0 -14
  338. package/src/filing/filing-service.ts +13 -1
  339. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
  340. package/src/heartbeat/heartbeat-service.ts +23 -5
  341. package/src/home/__tests__/feed-writer.test.ts +0 -4
  342. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  343. package/src/home/feed-writer.ts +1 -2
  344. package/src/home/relationship-state-writer.ts +16 -3
  345. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  346. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  347. package/src/ipc/assistant-server.ts +3 -10
  348. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  349. package/src/ipc/routes/route-adapter.ts +1 -1
  350. package/src/ipc/routes/trust-rules.test.ts +0 -95
  351. package/src/ipc/skill-ipc-types.ts +41 -0
  352. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  353. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  354. package/src/ipc/skill-routes/events.ts +12 -23
  355. package/src/ipc/skill-routes/identity.ts +4 -17
  356. package/src/ipc/skill-routes/index.ts +1 -1
  357. package/src/ipc/skill-server.ts +6 -39
  358. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  359. package/src/live-voice/protocol.ts +4 -13
  360. package/src/mcp/manager.ts +0 -5
  361. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  362. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  363. package/src/memory/app-git-service.ts +0 -32
  364. package/src/memory/app-store.ts +154 -0
  365. package/src/memory/attachments-store.ts +6 -0
  366. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  367. package/src/memory/context-search/sources/memory.ts +5 -0
  368. package/src/memory/context-search/sources/pkb.ts +10 -1
  369. package/src/memory/context-search/sources/workspace.ts +3 -2
  370. package/src/memory/conversation-crud.ts +29 -4
  371. package/src/memory/conversation-disk-view.ts +1 -5
  372. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  373. package/src/memory/db-connection.ts +62 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +3 -21
  376. package/src/memory/embedding-gemini.ts +0 -2
  377. package/src/memory/embedding-local.ts +6 -6
  378. package/src/memory/embedding-ollama.ts +6 -6
  379. package/src/memory/embedding-openai.ts +6 -6
  380. package/src/memory/embedding-types.ts +21 -0
  381. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
  382. package/src/memory/graph/conversation-graph-memory.ts +35 -13
  383. package/src/memory/graph/injection.test.ts +2 -2
  384. package/src/memory/graph/injection.ts +1 -1
  385. package/src/memory/guardian-action-store.ts +0 -83
  386. package/src/memory/guardian-approvals.ts +0 -48
  387. package/src/memory/indexer.ts +1 -15
  388. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  389. package/src/memory/job-utils.ts +0 -6
  390. package/src/memory/jobs-store.ts +0 -1
  391. package/src/memory/jobs-worker.ts +2 -16
  392. package/src/memory/llm-request-log-store.ts +0 -41
  393. package/src/memory/llm-usage-store.ts +129 -43
  394. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  395. package/src/memory/migrations/233-document-conversations.ts +54 -0
  396. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  397. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  398. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  399. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  400. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  401. package/src/memory/migrations/index.ts +14 -0
  402. package/src/memory/migrations/registry.ts +24 -0
  403. package/src/memory/raw-query.ts +2 -68
  404. package/src/memory/schema/conversations.ts +7 -0
  405. package/src/memory/schema/infrastructure.ts +25 -0
  406. package/src/memory/search/semantic.ts +5 -16
  407. package/src/memory/tool-usage-store.ts +2 -0
  408. package/src/memory/usage-buckets.ts +40 -1
  409. package/src/memory/usage-grouped-buckets.ts +127 -0
  410. package/src/memory/v2/__tests__/activation.test.ts +289 -90
  411. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  412. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  413. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  414. package/src/memory/v2/__tests__/injection.test.ts +384 -15
  415. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  416. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  417. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  418. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  419. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  420. package/src/memory/v2/activation.ts +168 -97
  421. package/src/memory/v2/backfill-jobs.ts +15 -100
  422. package/src/memory/v2/consolidation-job.ts +14 -12
  423. package/src/memory/v2/edge-index.ts +191 -0
  424. package/src/memory/v2/injection.ts +182 -58
  425. package/src/memory/v2/migration.ts +57 -64
  426. package/src/memory/v2/now-text.ts +2 -3
  427. package/src/memory/v2/page-store.ts +168 -31
  428. package/src/memory/v2/prompts/consolidation.ts +118 -42
  429. package/src/memory/v2/prompts/sweep.ts +3 -3
  430. package/src/memory/v2/skill-store.ts +55 -7
  431. package/src/memory/v2/static-context.ts +62 -0
  432. package/src/memory/v2/types.ts +10 -20
  433. package/src/memory/validation.ts +0 -11
  434. package/src/messaging/draft-store.ts +0 -6
  435. package/src/messaging/provider-types.ts +8 -0
  436. package/src/messaging/provider.ts +7 -0
  437. package/src/messaging/providers/gmail/client.ts +1 -121
  438. package/src/messaging/providers/outlook/client.ts +0 -73
  439. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  440. package/src/messaging/providers/slack/adapter.ts +122 -21
  441. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  442. package/src/messaging/providers/slack/backfill.ts +89 -11
  443. package/src/messaging/providers/slack/client.ts +10 -124
  444. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  445. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  446. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  447. package/src/messaging/providers/slack/types.ts +1 -0
  448. package/src/oauth/connection-resolver.test.ts +8 -0
  449. package/src/oauth/connection-resolver.ts +8 -16
  450. package/src/oauth/credential-token-resolver.ts +97 -0
  451. package/src/oauth/manual-token-connection.ts +30 -34
  452. package/src/oauth/oauth-store.ts +6 -4
  453. package/src/outbound-proxy/certs.ts +0 -7
  454. package/src/outbound-proxy/config.ts +0 -74
  455. package/src/outbound-proxy/health.ts +0 -44
  456. package/src/outbound-proxy/index.ts +0 -22
  457. package/src/permissions/approval-provenance.test.ts +184 -0
  458. package/src/permissions/approval-provenance.ts +70 -0
  459. package/src/permissions/checker.ts +4 -1
  460. package/src/permissions/gateway-threshold-reader.ts +4 -1
  461. package/src/permissions/prompter.ts +9 -2
  462. package/src/permissions/secret-prompter.ts +21 -48
  463. package/src/permissions/types.ts +33 -0
  464. package/src/permissions/workspace-policy.ts +0 -5
  465. package/src/platform/sync-identity.ts +0 -8
  466. package/src/plugins/defaults/injectors.ts +69 -2
  467. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  468. package/src/plugins/types.ts +8 -0
  469. package/src/prompts/system-prompt.ts +34 -70
  470. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  471. package/src/prompts/update-bulletin-job.ts +2 -0
  472. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  473. package/src/providers/anthropic/client.ts +72 -33
  474. package/src/providers/call-site-routing.ts +42 -3
  475. package/src/providers/gemini/client.ts +18 -2
  476. package/src/providers/managed-proxy/context.ts +0 -5
  477. package/src/providers/model-catalog.ts +105 -19
  478. package/src/providers/openai/chat-completions-provider.ts +6 -0
  479. package/src/providers/openai/responses-provider.ts +7 -1
  480. package/src/providers/provider-send-message.ts +45 -2
  481. package/src/providers/ratelimit.ts +7 -2
  482. package/src/providers/registry.ts +14 -9
  483. package/src/providers/retry.ts +96 -8
  484. package/src/providers/types.ts +13 -0
  485. package/src/providers/usage-tracking.ts +96 -0
  486. package/src/runtime/AGENTS.md +10 -6
  487. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  488. package/src/runtime/agent-wake.ts +39 -2
  489. package/src/runtime/assistant-event-hub.ts +541 -45
  490. package/src/runtime/assistant-event.ts +1 -6
  491. package/src/runtime/auth/context.ts +0 -9
  492. package/src/runtime/auth/middleware.ts +1 -1
  493. package/src/runtime/auth/route-policy.ts +11 -9
  494. package/src/runtime/auth/token-service.ts +0 -11
  495. package/src/runtime/channel-approvals.ts +6 -2
  496. package/src/runtime/channel-verification-service.ts +3 -5
  497. package/src/runtime/http-errors.ts +0 -34
  498. package/src/runtime/http-router.ts +6 -3
  499. package/src/runtime/http-server.ts +22 -82
  500. package/src/runtime/http-types.ts +5 -0
  501. package/src/runtime/interactive-ui.ts +0 -1
  502. package/src/runtime/middleware/auth.ts +0 -20
  503. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  504. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  505. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  506. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  507. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  508. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  509. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  510. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  511. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  512. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  513. package/src/runtime/migrations/migration-transport.ts +46 -13
  514. package/src/runtime/migrations/migration-wizard.ts +2 -2
  515. package/src/runtime/migrations/origin-mode.ts +40 -0
  516. package/src/runtime/migrations/vbundle-builder.ts +133 -79
  517. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  518. package/src/runtime/migrations/vbundle-importer.ts +7 -7
  519. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  520. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
  521. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  522. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  523. package/src/runtime/pending-interactions.ts +13 -4
  524. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  525. package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
  526. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  527. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  528. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  529. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  530. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  531. package/src/runtime/routes/acp-routes.test.ts +0 -3
  532. package/src/runtime/routes/acp-routes.ts +3 -7
  533. package/src/runtime/routes/app-management-routes.ts +18 -9
  534. package/src/runtime/routes/approval-routes.ts +55 -14
  535. package/src/runtime/routes/avatar-routes.ts +3 -5
  536. package/src/runtime/routes/browser-routes.ts +1 -15
  537. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  538. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  539. package/src/runtime/routes/channel-route-shared.ts +2 -28
  540. package/src/runtime/routes/client-routes.ts +45 -12
  541. package/src/runtime/routes/consolidation-routes.ts +115 -0
  542. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  543. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  544. package/src/runtime/routes/conversation-query-routes.ts +120 -8
  545. package/src/runtime/routes/conversation-routes.ts +44 -528
  546. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  547. package/src/runtime/routes/documents-routes.ts +53 -18
  548. package/src/runtime/routes/events-routes.ts +59 -91
  549. package/src/runtime/routes/filing-routes.ts +18 -1
  550. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  551. package/src/runtime/routes/host-bash-routes.ts +3 -2
  552. package/src/runtime/routes/host-browser-routes.ts +9 -33
  553. package/src/runtime/routes/host-cu-routes.ts +6 -1
  554. package/src/runtime/routes/host-file-routes.ts +3 -2
  555. package/src/runtime/routes/host-transfer-routes.ts +11 -15
  556. package/src/runtime/routes/identity-routes.ts +78 -6
  557. package/src/runtime/routes/inbound-message-handler.ts +580 -137
  558. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
  559. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  560. package/src/runtime/routes/index.ts +4 -0
  561. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  562. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  563. package/src/runtime/routes/memory-v2-routes.ts +10 -15
  564. package/src/runtime/routes/migration-routes.ts +188 -31
  565. package/src/runtime/routes/playground/guard.ts +1 -1
  566. package/src/runtime/routes/playground/index.ts +0 -2
  567. package/src/runtime/routes/recording-routes.ts +4 -24
  568. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  569. package/src/runtime/routes/schedule-routes.ts +3 -6
  570. package/src/runtime/routes/secret-routes.ts +87 -18
  571. package/src/runtime/routes/settings-routes.ts +29 -28
  572. package/src/runtime/routes/skills-routes.ts +12 -31
  573. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  574. package/src/runtime/routes/task-routes.ts +6 -6
  575. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  576. package/src/runtime/routes/types.ts +4 -4
  577. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  578. package/src/runtime/routes/usage-routes.ts +87 -10
  579. package/src/runtime/routes/user-routes.ts +17 -31
  580. package/src/runtime/routes/work-items-routes.ts +1 -4
  581. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  582. package/src/runtime/services/analyze-conversation.ts +7 -17
  583. package/src/runtime/services/conversation-serializer.ts +2 -4
  584. package/src/runtime/verification-outbound-actions.ts +1 -1
  585. package/src/runtime/verification-rate-limiter.ts +1 -1
  586. package/src/schedule/schedule-store.ts +0 -16
  587. package/src/security/secret-scanner.ts +14 -547
  588. package/src/security/secure-keys.ts +31 -11
  589. package/src/security/token-manager.ts +7 -3
  590. package/src/signals/cancel.ts +16 -25
  591. package/src/signals/conversation-undo.ts +2 -27
  592. package/src/signals/emit-event.ts +1 -2
  593. package/src/signals/user-message.ts +108 -22
  594. package/src/skills/catalog-install.ts +1 -0
  595. package/src/skills/clawhub.ts +2 -2
  596. package/src/skills/inline-command-runner.ts +1 -7
  597. package/src/subagent/manager.ts +67 -84
  598. package/src/tasks/task-store.ts +1 -28
  599. package/src/telemetry/types.ts +6 -0
  600. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  601. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  602. package/src/tools/acp/spawn.test.ts +1 -2
  603. package/src/tools/acp/steer.test.ts +1 -2
  604. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  605. package/src/tools/browser/browser-execution.ts +31 -147
  606. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  607. package/src/tools/browser/cdp-client/factory.ts +48 -76
  608. package/src/tools/browser/cdp-client/index.ts +1 -14
  609. package/src/tools/executor.ts +44 -31
  610. package/src/tools/host-filesystem/edit.ts +3 -2
  611. package/src/tools/host-filesystem/read.ts +3 -2
  612. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  613. package/src/tools/host-filesystem/transfer.ts +4 -3
  614. package/src/tools/host-filesystem/write.ts +3 -2
  615. package/src/tools/host-terminal/host-shell.ts +4 -3
  616. package/src/tools/network/script-proxy/index.ts +1 -10
  617. package/src/tools/permission-checker.ts +66 -1
  618. package/src/tools/skills/sandbox-runner.ts +1 -6
  619. package/src/tools/skills/skill-tool-factory.ts +32 -0
  620. package/src/tools/terminal/safe-env.ts +1 -0
  621. package/src/tools/terminal/shell.ts +2 -78
  622. package/src/tools/types.ts +12 -39
  623. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  624. package/src/tts/provider-catalog.ts +1 -1
  625. package/src/usage/actors.ts +2 -1
  626. package/src/usage/attribution.ts +185 -0
  627. package/src/usage/pricing.ts +166 -0
  628. package/src/usage/types.ts +14 -0
  629. package/src/util/json.ts +13 -0
  630. package/src/util/logger.ts +3 -3
  631. package/src/util/pricing.ts +50 -3
  632. package/src/work-items/work-item-runner.ts +15 -42
  633. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  634. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  635. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  636. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  637. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  638. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  639. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  640. package/src/workspace/migrations/registry.ts +8 -0
  641. package/src/workspace/provider-commit-message-generator.ts +3 -3
  642. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  643. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  644. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  645. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  646. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  647. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  648. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  649. package/src/context/__tests__/microcompact.test.ts +0 -805
  650. package/src/context/microcompact.ts +0 -443
  651. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  652. package/src/events/tool-notification-listener.ts +0 -17
  653. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  654. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  655. package/src/memory/v2/edges.ts +0 -217
  656. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  657. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  658. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  659. package/src/runtime/chrome-extension-registry.ts +0 -368
  660. package/src/runtime/client-registry.ts +0 -254
  661. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  662. package/src/tools/secret-detection-handler.ts +0 -269
  663. package/src/tools/terminal/backends/native.ts +0 -327
  664. package/src/tools/terminal/backends/types.ts +0 -37
  665. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  666. package/src/tools/terminal/sandbox.ts +0 -40
@@ -0,0 +1,151 @@
1
+ import { existsSync, rmSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
5
+
6
+ import {
7
+ addAppConversationId,
8
+ createApp,
9
+ getApp,
10
+ listAppsByConversation,
11
+ } from "../memory/app-store.js";
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // Helpers
15
+ // ---------------------------------------------------------------------------
16
+
17
+ let testDataDir: string;
18
+
19
+ function freshTempDir(): string {
20
+ return join(
21
+ tmpdir(),
22
+ `vellum-app-conv-id-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
23
+ );
24
+ }
25
+
26
+ function makeAppParams(name: string) {
27
+ return {
28
+ name,
29
+ schemaJson: "{}",
30
+ htmlDefinition: "<h1>Hello</h1>",
31
+ };
32
+ }
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Setup / teardown
36
+ // ---------------------------------------------------------------------------
37
+
38
+ beforeEach(() => {
39
+ testDataDir = freshTempDir();
40
+ process.env.VELLUM_WORKSPACE_DIR = testDataDir;
41
+ });
42
+
43
+ afterEach(() => {
44
+ if (existsSync(testDataDir)) {
45
+ rmSync(testDataDir, { recursive: true, force: true });
46
+ }
47
+ });
48
+
49
+ // ---------------------------------------------------------------------------
50
+ // addAppConversationId
51
+ // ---------------------------------------------------------------------------
52
+
53
+ describe("addAppConversationId", () => {
54
+ test("appends conversationId and returns true", () => {
55
+ const app = createApp(makeAppParams("Test App"));
56
+ const result = addAppConversationId(app.id, "conv-abc");
57
+ expect(result).toBe(true);
58
+
59
+ const loaded = getApp(app.id);
60
+ expect(loaded?.conversationIds).toEqual(["conv-abc"]);
61
+ });
62
+
63
+ test("deduplicates — returns false when conversationId already present", () => {
64
+ const app = createApp(makeAppParams("Test App"));
65
+ addAppConversationId(app.id, "conv-abc");
66
+ const result = addAppConversationId(app.id, "conv-abc");
67
+ expect(result).toBe(false);
68
+
69
+ const loaded = getApp(app.id);
70
+ expect(loaded?.conversationIds).toEqual(["conv-abc"]);
71
+ });
72
+
73
+ test("returns false for non-existent app", () => {
74
+ const result = addAppConversationId("nonexistent-id", "conv-abc");
75
+ expect(result).toBe(false);
76
+ });
77
+
78
+ test("does not change updatedAt", () => {
79
+ const app = createApp(makeAppParams("Test App"));
80
+ const originalUpdatedAt = app.updatedAt;
81
+
82
+ // Wait a tick so Date.now() would differ if updatedAt were bumped
83
+ const before = Date.now();
84
+ while (Date.now() === before) {
85
+ // busy-wait for at least 1ms
86
+ }
87
+
88
+ addAppConversationId(app.id, "conv-abc");
89
+
90
+ const loaded = getApp(app.id);
91
+ expect(loaded?.updatedAt).toBe(originalUpdatedAt);
92
+ });
93
+
94
+ test("initializes conversationIds from undefined", () => {
95
+ const app = createApp(makeAppParams("Fresh App"));
96
+ // Verify the app has no conversationIds initially
97
+ const initial = getApp(app.id);
98
+ expect(initial?.conversationIds).toBeUndefined();
99
+
100
+ addAppConversationId(app.id, "conv-xyz");
101
+
102
+ const loaded = getApp(app.id);
103
+ expect(loaded?.conversationIds).toEqual(["conv-xyz"]);
104
+ });
105
+
106
+ test("appends multiple distinct conversationIds", () => {
107
+ const app = createApp(makeAppParams("Multi Conv App"));
108
+ addAppConversationId(app.id, "conv-1");
109
+ addAppConversationId(app.id, "conv-2");
110
+ addAppConversationId(app.id, "conv-3");
111
+
112
+ const loaded = getApp(app.id);
113
+ expect(loaded?.conversationIds).toEqual(["conv-1", "conv-2", "conv-3"]);
114
+ });
115
+ });
116
+
117
+ // ---------------------------------------------------------------------------
118
+ // listAppsByConversation
119
+ // ---------------------------------------------------------------------------
120
+
121
+ describe("listAppsByConversation", () => {
122
+ test("filters apps by conversationId", () => {
123
+ const app1 = createApp(makeAppParams("App One"));
124
+ const app2 = createApp(makeAppParams("App Two"));
125
+ createApp(makeAppParams("App Three"));
126
+
127
+ addAppConversationId(app1.id, "conv-shared");
128
+ addAppConversationId(app2.id, "conv-shared");
129
+ addAppConversationId(app1.id, "conv-only-one");
130
+
131
+ const shared = listAppsByConversation("conv-shared");
132
+ expect(shared).toHaveLength(2);
133
+ const ids = shared.map((a) => a.id).sort();
134
+ expect(ids).toEqual([app1.id, app2.id].sort());
135
+
136
+ const onlyOne = listAppsByConversation("conv-only-one");
137
+ expect(onlyOne).toHaveLength(1);
138
+ expect(onlyOne[0].id).toBe(app1.id);
139
+ });
140
+
141
+ test("returns empty array for unknown conversationId", () => {
142
+ createApp(makeAppParams("Some App"));
143
+ const result = listAppsByConversation("conv-nonexistent");
144
+ expect(result).toEqual([]);
145
+ });
146
+
147
+ test("returns empty array when no apps exist", () => {
148
+ const result = listAppsByConversation("conv-any");
149
+ expect(result).toEqual([]);
150
+ });
151
+ });
@@ -313,13 +313,11 @@ function seedPendingConfirmation(
313
313
  * confirmation details.
314
314
  */
315
315
  function registerPendingInteraction(
316
- conversation: Conversation,
317
316
  requestId: string,
318
317
  conversationId: string,
319
318
  confirmationDetails?: ConfirmationDetails,
320
319
  ): void {
321
320
  pendingInteractions.register(requestId, {
322
- conversation,
323
321
  conversationId,
324
322
  kind: "confirmation",
325
323
  confirmationDetails,
@@ -349,12 +347,6 @@ beforeEach(() => {
349
347
  // ---------------------------------------------------------------------------
350
348
 
351
349
  describe("approval cascading", () => {
352
-
353
-
354
-
355
-
356
-
357
-
358
350
  test("allow (one-time) does NOT cascade", () => {
359
351
  const emitted: ServerMessage[] = [];
360
352
  const conversationObj = makeConversation(
@@ -366,13 +358,11 @@ describe("approval cascading", () => {
366
358
  seedPendingConfirmation(conversationObj, "req-2");
367
359
 
368
360
  registerPendingInteraction(
369
- conversationObj,
370
361
  "req-1",
371
362
  CONV_ID,
372
363
  makeConfirmationDetails(["bash:echo hello"]),
373
364
  );
374
365
  registerPendingInteraction(
375
- conversationObj,
376
366
  "req-2",
377
367
  CONV_ID,
378
368
  makeConfirmationDetails(["bash:echo world"]),
@@ -402,13 +392,11 @@ describe("approval cascading", () => {
402
392
  seedPendingConfirmation(conversationObj, "req-2");
403
393
 
404
394
  registerPendingInteraction(
405
- conversationObj,
406
395
  "req-1",
407
396
  CONV_ID,
408
397
  makeConfirmationDetails(["bash:echo hello"]),
409
398
  );
410
399
  registerPendingInteraction(
411
- conversationObj,
412
400
  "req-2",
413
401
  CONV_ID,
414
402
  makeConfirmationDetails(["bash:echo world"]),
@@ -427,7 +415,6 @@ describe("approval cascading", () => {
427
415
  expect(confirmMsgs[0].requestId).toBe("req-1");
428
416
  });
429
417
 
430
-
431
418
  test("already-resolved request handled gracefully", () => {
432
419
  const emitted: ServerMessage[] = [];
433
420
  const conversationObj = makeConversation(
@@ -439,7 +426,6 @@ describe("approval cascading", () => {
439
426
  seedPendingConfirmation(conversationObj, "req-stale");
440
427
 
441
428
  registerPendingInteraction(
442
- conversationObj,
443
429
  "req-primary",
444
430
  CONV_ID,
445
431
  makeConfirmationDetails(["bash:echo primary"]),
@@ -448,7 +434,6 @@ describe("approval cascading", () => {
448
434
  // in the prompter. We'll remove it from the prompter before cascading
449
435
  // reaches it to simulate a stale/already-resolved request.
450
436
  registerPendingInteraction(
451
- conversationObj,
452
437
  "req-stale",
453
438
  CONV_ID,
454
439
  makeConfirmationDetails(["bash:echo stale"]),
@@ -120,6 +120,11 @@ mock.module("../permissions/trust-store.js", () => ({
120
120
  let _conversationFactory: (() => Conversation) | undefined;
121
121
 
122
122
  mock.module("../daemon/conversation-store.js", () => ({
123
+ findConversation: () => {
124
+ // Return the current test session for any conversation ID lookup.
125
+ if (!_conversationFactory) return undefined;
126
+ return _conversationFactory();
127
+ },
123
128
  getOrCreateConversation: async () => {
124
129
  if (!_conversationFactory)
125
130
  throw new Error("_conversationFactory not set in test");
@@ -171,11 +176,7 @@ function makeIdleSession(opts?: {
171
176
  getMessages: () => [],
172
177
  usageStats: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
173
178
  updateClient: () => {},
174
- setHostBashProxy: () => {},
175
179
  setHostBrowserProxy: () => {},
176
- setHostFileProxy: () => {},
177
- setHostTransferProxy: () => {},
178
- getHostTransferProxy: () => undefined,
179
180
  setHostCuProxy: () => {},
180
181
  addPreactivatedSkillId: () => {},
181
182
  enqueueMessage: () => ({ queued: false, requestId: "noop" }),
@@ -238,11 +239,7 @@ function makeConfirmationEmittingSession(opts?: {
238
239
  getMessages: () => [],
239
240
  usageStats: { inputTokens: 0, outputTokens: 0, estimatedCost: 0 },
240
241
  updateClient: () => {},
241
- setHostBashProxy: () => {},
242
242
  setHostBrowserProxy: () => {},
243
- setHostFileProxy: () => {},
244
- setHostTransferProxy: () => {},
245
- getHostTransferProxy: () => undefined,
246
243
  setHostCuProxy: () => {},
247
244
  addPreactivatedSkillId: () => {},
248
245
  enqueueMessage: () => ({ queued: false, requestId: "noop" }),
@@ -257,6 +254,7 @@ function makeConfirmationEmittingSession(opts?: {
257
254
  onEvent({
258
255
  type: "confirmation_request",
259
256
  requestId: reqId,
257
+ conversationId: "conv-auto",
260
258
  toolName: tool,
261
259
  input: { command: "ls" },
262
260
  riskLevel: "medium",
@@ -335,7 +333,6 @@ describe("standalone approval endpoints — HTTP layer", () => {
335
333
 
336
334
  // Manually register a pending interaction
337
335
  pendingInteractions.register("req-abc", {
338
- conversation: session,
339
336
  conversationId: "conv-1",
340
337
  kind: "confirmation",
341
338
  confirmationDetails: {
@@ -384,7 +381,6 @@ describe("standalone approval endpoints — HTTP layer", () => {
384
381
  await startServer(() => session);
385
382
 
386
383
  pendingInteractions.register("req-once", {
387
- conversation: session,
388
384
  conversationId: "conv-1",
389
385
  kind: "confirmation",
390
386
  });
@@ -427,7 +423,6 @@ describe("standalone approval endpoints — HTTP layer", () => {
427
423
  await startServer(() => session);
428
424
 
429
425
  pendingInteractions.register("req-1", {
430
- conversation: session,
431
426
  conversationId: "conv-1",
432
427
  kind: "confirmation",
433
428
  confirmationDetails: {
@@ -462,7 +457,6 @@ describe("standalone approval endpoints — HTTP layer", () => {
462
457
  await startServer(() => session);
463
458
 
464
459
  pendingInteractions.register("req-host-access", {
465
- conversation: session,
466
460
  conversationId: "conv-1",
467
461
  kind: "confirmation",
468
462
  confirmationDetails: {
@@ -500,7 +494,6 @@ describe("standalone approval endpoints — HTTP layer", () => {
500
494
  await startServer(() => session);
501
495
 
502
496
  pendingInteractions.register("req-v2-invalid", {
503
- conversation: session,
504
497
  conversationId: "conv-1",
505
498
  kind: "confirmation",
506
499
  confirmationDetails: {
@@ -549,7 +542,6 @@ describe("standalone approval endpoints — HTTP layer", () => {
549
542
  await startServer(() => session);
550
543
 
551
544
  pendingInteractions.register("secret-req-1", {
552
- conversation: session,
553
545
  conversationId: "conv-1",
554
546
  kind: "secret",
555
547
  });
@@ -691,17 +683,14 @@ describe("standalone approval endpoints — HTTP layer", () => {
691
683
  await startServer(() => session);
692
684
 
693
685
  pendingInteractions.register("req-a", {
694
- conversation: session,
695
686
  conversationId: "conv-x",
696
687
  kind: "confirmation",
697
688
  });
698
689
  pendingInteractions.register("req-b", {
699
- conversation: session,
700
690
  conversationId: "conv-x",
701
691
  kind: "secret",
702
692
  });
703
693
  pendingInteractions.register("req-c", {
704
- conversation: session,
705
694
  conversationId: "conv-y",
706
695
  kind: "confirmation",
707
696
  });
@@ -6,7 +6,6 @@ import { AssistantEventHub } from "../runtime/assistant-event-hub.js";
6
6
  function makeEvent(overrides: Partial<AssistantEvent> = {}): AssistantEvent {
7
7
  return {
8
8
  id: "evt_test",
9
- assistantId: "ast_1",
10
9
  conversationId: "sess_1",
11
10
  emittedAt: "2026-02-18T00:00:00.000Z",
12
11
  message: {
@@ -25,8 +24,11 @@ describe("AssistantEventHub — fanout", () => {
25
24
  const hub = new AssistantEventHub();
26
25
  const received: AssistantEvent[] = [];
27
26
 
28
- hub.subscribe({ assistantId: "ast_1" }, (e) => {
29
- received.push(e);
27
+ hub.subscribe({
28
+ type: "process",
29
+ callback: (e) => {
30
+ received.push(e);
31
+ },
30
32
  });
31
33
  await hub.publish(makeEvent());
32
34
 
@@ -38,14 +40,23 @@ describe("AssistantEventHub — fanout", () => {
38
40
  const hub = new AssistantEventHub();
39
41
  const order: string[] = [];
40
42
 
41
- hub.subscribe({ assistantId: "ast_1" }, () => {
42
- order.push("first");
43
+ hub.subscribe({
44
+ type: "process",
45
+ callback: () => {
46
+ order.push("first");
47
+ },
43
48
  });
44
- hub.subscribe({ assistantId: "ast_1" }, () => {
45
- order.push("second");
49
+ hub.subscribe({
50
+ type: "process",
51
+ callback: () => {
52
+ order.push("second");
53
+ },
46
54
  });
47
- hub.subscribe({ assistantId: "ast_1" }, () => {
48
- order.push("third");
55
+ hub.subscribe({
56
+ type: "process",
57
+ callback: () => {
58
+ order.push("third");
59
+ },
49
60
  });
50
61
 
51
62
  await hub.publish(makeEvent());
@@ -53,28 +64,24 @@ describe("AssistantEventHub — fanout", () => {
53
64
  expect(order).toEqual(["first", "second", "third"]);
54
65
  });
55
66
 
56
- test("does not deliver event to subscriber for a different assistantId", async () => {
57
- const hub = new AssistantEventHub();
58
- const received: AssistantEvent[] = [];
59
-
60
- hub.subscribe({ assistantId: "ast_OTHER" }, (e) => {
61
- received.push(e);
62
- });
63
- await hub.publish(makeEvent({ assistantId: "ast_1" }));
64
-
65
- expect(received).toHaveLength(0);
66
- });
67
-
68
67
  test("conversationId filter further restricts delivery", async () => {
69
68
  const hub = new AssistantEventHub();
70
69
  const receivedA: AssistantEvent[] = [];
71
70
  const receivedB: AssistantEvent[] = [];
72
71
 
73
- hub.subscribe({ assistantId: "ast_1", conversationId: "sess_A" }, (e) => {
74
- receivedA.push(e);
72
+ hub.subscribe({
73
+ type: "process",
74
+ filter: { conversationId: "sess_A" },
75
+ callback: (e) => {
76
+ receivedA.push(e);
77
+ },
75
78
  });
76
- hub.subscribe({ assistantId: "ast_1", conversationId: "sess_B" }, (e) => {
77
- receivedB.push(e);
79
+ hub.subscribe({
80
+ type: "process",
81
+ filter: { conversationId: "sess_B" },
82
+ callback: (e) => {
83
+ receivedB.push(e);
84
+ },
78
85
  });
79
86
 
80
87
  await hub.publish(makeEvent({ conversationId: "sess_A" }));
@@ -83,12 +90,15 @@ describe("AssistantEventHub — fanout", () => {
83
90
  expect(receivedB).toHaveLength(0);
84
91
  });
85
92
 
86
- test("subscriber without conversationId filter receives all sessions for that assistant", async () => {
93
+ test("subscriber without conversationId filter receives all conversations", async () => {
87
94
  const hub = new AssistantEventHub();
88
95
  const received: AssistantEvent[] = [];
89
96
 
90
- hub.subscribe({ assistantId: "ast_1" }, (e) => {
91
- received.push(e);
97
+ hub.subscribe({
98
+ type: "process",
99
+ callback: (e) => {
100
+ received.push(e);
101
+ },
92
102
  });
93
103
 
94
104
  await hub.publish(makeEvent({ conversationId: "sess_A" }));
@@ -103,13 +113,12 @@ describe("AssistantEventHub — fanout", () => {
103
113
  await expect(hub.publish(makeEvent())).resolves.toBeUndefined();
104
114
  });
105
115
 
106
- test("hasSubscribersForEvent returns true for assistant-wide subscribers", () => {
116
+ test("hasSubscribersForEvent returns true for unscoped subscribers", () => {
107
117
  const hub = new AssistantEventHub();
108
- hub.subscribe({ assistantId: "ast_1" }, () => {});
118
+ hub.subscribe({ type: "process", callback: () => {} });
109
119
 
110
120
  expect(
111
121
  hub.hasSubscribersForEvent({
112
- assistantId: "ast_1",
113
122
  conversationId: "sess_A",
114
123
  }),
115
124
  ).toBe(true);
@@ -117,17 +126,19 @@ describe("AssistantEventHub — fanout", () => {
117
126
 
118
127
  test("hasSubscribersForEvent honors conversation scoping", () => {
119
128
  const hub = new AssistantEventHub();
120
- hub.subscribe({ assistantId: "ast_1", conversationId: "sess_A" }, () => {});
129
+ hub.subscribe({
130
+ type: "process",
131
+ filter: { conversationId: "sess_A" },
132
+ callback: () => {},
133
+ });
121
134
 
122
135
  expect(
123
136
  hub.hasSubscribersForEvent({
124
- assistantId: "ast_1",
125
137
  conversationId: "sess_A",
126
138
  }),
127
139
  ).toBe(true);
128
140
  expect(
129
141
  hub.hasSubscribersForEvent({
130
- assistantId: "ast_1",
131
142
  conversationId: "sess_B",
132
143
  }),
133
144
  ).toBe(false);
@@ -141,46 +152,49 @@ describe("AssistantEventHub — unsubscribe cleanup", () => {
141
152
  const hub = new AssistantEventHub();
142
153
  const received: AssistantEvent[] = [];
143
154
 
144
- const sub = hub.subscribe({ assistantId: "ast_1" }, (e) => {
145
- received.push(e);
155
+ const s = hub.subscribe({
156
+ type: "process",
157
+ callback: (e) => {
158
+ received.push(e);
159
+ },
146
160
  });
147
161
  await hub.publish(makeEvent());
148
162
  expect(received).toHaveLength(1);
149
163
 
150
- sub.dispose();
164
+ s.dispose();
151
165
  await hub.publish(makeEvent());
152
166
  expect(received).toHaveLength(1); // no new events
153
167
  });
154
168
 
155
169
  test("dispose is idempotent", () => {
156
170
  const hub = new AssistantEventHub();
157
- const sub = hub.subscribe({ assistantId: "ast_1" }, () => {});
171
+ const s = hub.subscribe({ type: "process", callback: () => {} });
158
172
 
159
- sub.dispose();
160
- sub.dispose(); // must not throw
161
- expect(sub.active).toBe(false);
173
+ s.dispose();
174
+ s.dispose(); // must not throw
175
+ expect(s.active).toBe(false);
162
176
  });
163
177
 
164
178
  test("active reflects subscription state", () => {
165
179
  const hub = new AssistantEventHub();
166
- const sub = hub.subscribe({ assistantId: "ast_1" }, () => {});
167
- expect(sub.active).toBe(true);
180
+ const s = hub.subscribe({ type: "process", callback: () => {} });
181
+ expect(s.active).toBe(true);
168
182
 
169
- sub.dispose();
170
- expect(sub.active).toBe(false);
183
+ s.dispose();
184
+ expect(s.active).toBe(false);
171
185
  });
172
186
 
173
187
  test("subscriberCount reflects live subscriptions only", () => {
174
188
  const hub = new AssistantEventHub();
175
189
 
176
- const sub1 = hub.subscribe({ assistantId: "ast_1" }, () => {});
177
- const sub2 = hub.subscribe({ assistantId: "ast_1" }, () => {});
190
+ const s1 = hub.subscribe({ type: "process", callback: () => {} });
191
+ const s2 = hub.subscribe({ type: "process", callback: () => {} });
178
192
  expect(hub.subscriberCount()).toBe(2);
179
193
 
180
- sub1.dispose();
194
+ s1.dispose();
181
195
  expect(hub.subscriberCount()).toBe(1);
182
196
 
183
- sub2.dispose();
197
+ s2.dispose();
184
198
  expect(hub.subscriberCount()).toBe(0);
185
199
  });
186
200
 
@@ -189,14 +203,20 @@ describe("AssistantEventHub — unsubscribe cleanup", () => {
189
203
  const received1: AssistantEvent[] = [];
190
204
  const received2: AssistantEvent[] = [];
191
205
 
192
- const sub1 = hub.subscribe({ assistantId: "ast_1" }, (e) => {
193
- received1.push(e);
206
+ const s1 = hub.subscribe({
207
+ type: "process",
208
+ callback: (e) => {
209
+ received1.push(e);
210
+ },
194
211
  });
195
- hub.subscribe({ assistantId: "ast_1" }, (e) => {
196
- received2.push(e);
212
+ hub.subscribe({
213
+ type: "process",
214
+ callback: (e) => {
215
+ received2.push(e);
216
+ },
197
217
  });
198
218
 
199
- sub1.dispose();
219
+ s1.dispose();
200
220
  await hub.publish(makeEvent());
201
221
 
202
222
  expect(received1).toHaveLength(0);
@@ -211,11 +231,17 @@ describe("AssistantEventHub — exception isolation", () => {
211
231
  const hub = new AssistantEventHub();
212
232
  let secondCalled = false;
213
233
 
214
- hub.subscribe({ assistantId: "ast_1" }, () => {
215
- throw new Error("subscriber boom");
234
+ hub.subscribe({
235
+ type: "process",
236
+ callback: () => {
237
+ throw new Error("subscriber boom");
238
+ },
216
239
  });
217
- hub.subscribe({ assistantId: "ast_1" }, () => {
218
- secondCalled = true;
240
+ hub.subscribe({
241
+ type: "process",
242
+ callback: () => {
243
+ secondCalled = true;
244
+ },
219
245
  });
220
246
 
221
247
  await expect(hub.publish(makeEvent())).rejects.toBeInstanceOf(
@@ -227,11 +253,17 @@ describe("AssistantEventHub — exception isolation", () => {
227
253
  test("all subscriber errors are collected into AggregateError", async () => {
228
254
  const hub = new AssistantEventHub();
229
255
 
230
- hub.subscribe({ assistantId: "ast_1" }, () => {
231
- throw new Error("err-1");
256
+ hub.subscribe({
257
+ type: "process",
258
+ callback: () => {
259
+ throw new Error("err-1");
260
+ },
232
261
  });
233
- hub.subscribe({ assistantId: "ast_1" }, () => {
234
- throw new Error("err-2");
262
+ hub.subscribe({
263
+ type: "process",
264
+ callback: () => {
265
+ throw new Error("err-2");
266
+ },
235
267
  });
236
268
 
237
269
  const caught = await hub.publish(makeEvent()).catch((e) => e);
@@ -244,11 +276,17 @@ describe("AssistantEventHub — exception isolation", () => {
244
276
  const hub = new AssistantEventHub();
245
277
  let syncRan = false;
246
278
 
247
- hub.subscribe({ assistantId: "ast_1" }, async () => {
248
- throw new Error("async-err");
279
+ hub.subscribe({
280
+ type: "process",
281
+ callback: async () => {
282
+ throw new Error("async-err");
283
+ },
249
284
  });
250
- hub.subscribe({ assistantId: "ast_1" }, () => {
251
- syncRan = true;
285
+ hub.subscribe({
286
+ type: "process",
287
+ callback: () => {
288
+ syncRan = true;
289
+ },
252
290
  });
253
291
 
254
292
  const caught = await hub.publish(makeEvent()).catch((e) => e);
@@ -259,7 +297,7 @@ describe("AssistantEventHub — exception isolation", () => {
259
297
 
260
298
  test("publish resolves when all subscribers succeed", async () => {
261
299
  const hub = new AssistantEventHub();
262
- hub.subscribe({ assistantId: "ast_1" }, () => {});
300
+ hub.subscribe({ type: "process", callback: () => {} });
263
301
  await expect(hub.publish(makeEvent())).resolves.toBeUndefined();
264
302
  });
265
303
  });
@@ -271,11 +309,16 @@ describe("AssistantEventHub — re-entrancy / snapshot isolation", () => {
271
309
  const hub = new AssistantEventHub();
272
310
  const lateReceived: AssistantEvent[] = [];
273
311
 
274
- hub.subscribe({ assistantId: "ast_1" }, () => {
275
- // Add a new subscriber mid-fanout
276
- hub.subscribe({ assistantId: "ast_1" }, (e) => {
277
- lateReceived.push(e);
278
- });
312
+ hub.subscribe({
313
+ type: "process",
314
+ callback: () => {
315
+ hub.subscribe({
316
+ type: "process",
317
+ callback: (e) => {
318
+ lateReceived.push(e);
319
+ },
320
+ });
321
+ },
279
322
  });
280
323
 
281
324
  await hub.publish(makeEvent());
@@ -287,14 +330,20 @@ describe("AssistantEventHub — re-entrancy / snapshot isolation", () => {
287
330
  test("subscriber that disposes itself mid-publish does not affect remaining subscribers", async () => {
288
331
  const hub = new AssistantEventHub();
289
332
  const received: AssistantEvent[] = [];
290
- let sub: ReturnType<typeof hub.subscribe>;
333
+ let s: ReturnType<typeof hub.subscribe>;
291
334
 
292
335
  // eslint-disable-next-line prefer-const
293
- sub = hub.subscribe({ assistantId: "ast_1" }, () => {
294
- sub.dispose();
336
+ s = hub.subscribe({
337
+ type: "process",
338
+ callback: () => {
339
+ s.dispose();
340
+ },
295
341
  });
296
- hub.subscribe({ assistantId: "ast_1" }, (e) => {
297
- received.push(e);
342
+ hub.subscribe({
343
+ type: "process",
344
+ callback: (e) => {
345
+ received.push(e);
346
+ },
298
347
  });
299
348
 
300
349
  await hub.publish(makeEvent());