@vellumai/assistant 0.8.3 → 0.8.5

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 (665) hide show
  1. package/ARCHITECTURE.md +2 -2
  2. package/docker-entrypoint.sh +0 -1
  3. package/docs/browser-use-architecture-phase2.md +1 -1
  4. package/knip.json +2 -1
  5. package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
  6. package/openapi.yaml +1492 -100
  7. package/package.json +1 -1
  8. package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
  9. package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
  10. package/src/__tests__/agent-loop.test.ts +88 -3
  11. package/src/__tests__/anthropic-provider.test.ts +302 -33
  12. package/src/__tests__/approval-cascade.test.ts +1 -1
  13. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  14. package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
  15. package/src/__tests__/audit-log-rotation.test.ts +70 -16
  16. package/src/__tests__/background-workers-disk-pressure.test.ts +4 -3
  17. package/src/__tests__/btw-routes.test.ts +2 -3
  18. package/src/__tests__/call-controller.test.ts +0 -1
  19. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  20. package/src/__tests__/channel-delivery-store.test.ts +193 -0
  21. package/src/__tests__/channel-guardian.test.ts +3 -3
  22. package/src/__tests__/channel-reply-delivery.test.ts +284 -5
  23. package/src/__tests__/channel-retry-sweep.test.ts +274 -1
  24. package/src/__tests__/checker.test.ts +6 -15
  25. package/src/__tests__/compaction-events.test.ts +2 -1
  26. package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
  27. package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
  28. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
  29. package/src/__tests__/computer-use-tools.test.ts +2 -4
  30. package/src/__tests__/config-watcher.test.ts +1 -1
  31. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  32. package/src/__tests__/context-token-estimator.test.ts +91 -1
  33. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
  34. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
  35. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +55 -4
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +228 -8
  37. package/src/__tests__/conversation-agent-loop.test.ts +188 -129
  38. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
  39. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
  40. package/src/__tests__/conversation-clean-command.test.ts +137 -0
  41. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  42. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
  43. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  44. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  45. package/src/__tests__/conversation-error.test.ts +31 -0
  46. package/src/__tests__/conversation-fork-crud.test.ts +324 -0
  47. package/src/__tests__/conversation-lifecycle.test.ts +53 -12
  48. package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
  49. package/src/__tests__/conversation-load-history-stripped.test.ts +279 -0
  50. package/src/__tests__/conversation-pairing.test.ts +2 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +1 -1
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -1
  53. package/src/__tests__/conversation-queue.test.ts +1 -1
  54. package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
  56. package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
  57. package/src/__tests__/conversation-seed-composer.test.ts +66 -4
  58. package/src/__tests__/conversation-skill-tools.test.ts +2 -5
  59. package/src/__tests__/conversation-slash-commands.test.ts +36 -8
  60. package/src/__tests__/conversation-slash-queue.test.ts +1 -1
  61. package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
  62. package/src/__tests__/conversation-speed-override.test.ts +1 -1
  63. package/src/__tests__/conversation-store.test.ts +1 -1
  64. package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
  65. package/src/__tests__/conversation-sync-tags.test.ts +99 -32
  66. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -1
  67. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  68. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  69. package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
  70. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  71. package/src/__tests__/credential-security-invariants.test.ts +7 -0
  72. package/src/__tests__/credential-vault-unit.test.ts +2 -2
  73. package/src/__tests__/cu-unified-flow.test.ts +10 -1
  74. package/src/__tests__/dm-backfill.test.ts +64 -0
  75. package/src/__tests__/dm-persistence.test.ts +33 -0
  76. package/src/__tests__/document-find-replace.test.ts +501 -0
  77. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  78. package/src/__tests__/email-html-renderer.test.ts +12 -0
  79. package/src/__tests__/first-greeting.test.ts +23 -2
  80. package/src/__tests__/gateway-flag-listener.test.ts +237 -0
  81. package/src/__tests__/gemini-provider.test.ts +78 -0
  82. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  83. package/src/__tests__/guardian-outbound-http.test.ts +7 -5
  84. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
  85. package/src/__tests__/headless-browser-navigate.test.ts +172 -0
  86. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
  87. package/src/__tests__/heartbeat-service.test.ts +4 -0
  88. package/src/__tests__/host-bash-proxy.test.ts +6 -0
  89. package/src/__tests__/host-browser-proxy.test.ts +10 -0
  90. package/src/__tests__/host-cu-proxy.test.ts +8 -1
  91. package/src/__tests__/host-file-proxy.test.ts +8 -1
  92. package/src/__tests__/host-shell-tool.test.ts +1 -1
  93. package/src/__tests__/host-transfer-proxy.test.ts +8 -1
  94. package/src/__tests__/identity-routes.test.ts +57 -0
  95. package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
  96. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  97. package/src/__tests__/injector-chain.test.ts +2 -0
  98. package/src/__tests__/injector-document-comments.test.ts +378 -0
  99. package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
  100. package/src/__tests__/list-messages-attachments.test.ts +21 -17
  101. package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
  102. package/src/__tests__/list-messages-page-latest.test.ts +130 -14
  103. package/src/__tests__/list-messages-tool-merge.test.ts +77 -17
  104. package/src/__tests__/llm-context-normalization.test.ts +0 -2
  105. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  106. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  107. package/src/__tests__/llm-resolver.test.ts +161 -9
  108. package/src/__tests__/llm-usage-store.test.ts +66 -0
  109. package/src/__tests__/log-export-routes.test.ts +99 -2
  110. package/src/__tests__/logger.test.ts +89 -0
  111. package/src/__tests__/mcp-abort-signal.test.ts +2 -2
  112. package/src/__tests__/media-generate-image.test.ts +31 -0
  113. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  114. package/src/__tests__/message-queue-steer.test.ts +114 -0
  115. package/src/__tests__/model-intents.test.ts +2 -4
  116. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  117. package/src/__tests__/onboarding-template-contract.test.ts +1 -1
  118. package/src/__tests__/openai-provider.test.ts +151 -0
  119. package/src/__tests__/openai-responses-provider.test.ts +118 -16
  120. package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
  121. package/src/__tests__/pending-interactions-resolved-event.test.ts +189 -0
  122. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  123. package/src/__tests__/platform.test.ts +2 -5
  124. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  125. package/src/__tests__/plugin-bootstrap.test.ts +2 -2
  126. package/src/__tests__/plugin-source-watcher.test.ts +302 -0
  127. package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
  128. package/src/__tests__/plugin-types.test.ts +3 -2
  129. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  130. package/src/__tests__/pricing.test.ts +12 -0
  131. package/src/__tests__/process-message-background-slack.test.ts +1 -51
  132. package/src/__tests__/process-message-display-content.test.ts +21 -16
  133. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  134. package/src/__tests__/registry.test.ts +2 -8
  135. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  136. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  137. package/src/__tests__/server-history-render.test.ts +83 -4
  138. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  139. package/src/__tests__/skill-feature-flags.test.ts +2 -2
  140. package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
  141. package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
  142. package/src/__tests__/skill-tool-factory.test.ts +1 -1
  143. package/src/__tests__/steer-tool-repair.test.ts +249 -0
  144. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  145. package/src/__tests__/suggestion-routes.test.ts +1 -0
  146. package/src/__tests__/sync-message-contract.test.ts +59 -0
  147. package/src/__tests__/system-prompt.test.ts +161 -124
  148. package/src/__tests__/terminal-tools.test.ts +12 -2
  149. package/src/__tests__/thinking-block-replay.test.ts +113 -0
  150. package/src/__tests__/thread-backfill.test.ts +370 -22
  151. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  152. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  153. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  154. package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
  155. package/src/__tests__/tool-executor.test.ts +89 -53
  156. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  157. package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
  158. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  159. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  160. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  161. package/src/__tests__/twilio-routes.test.ts +1 -1
  162. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  163. package/src/__tests__/usage-routes.test.ts +3 -0
  164. package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
  165. package/src/__tests__/web-fetch.test.ts +2 -2
  166. package/src/__tests__/workspace-git-service.test.ts +94 -10
  167. package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
  168. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  169. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  170. package/src/acp/prepare-agent-env.ts +78 -0
  171. package/src/acp/session-manager.ts +1 -1
  172. package/src/agent/attachments.ts +1 -0
  173. package/src/agent/loop.ts +65 -20
  174. package/src/api/README.md +5 -0
  175. package/src/api/index.ts +4 -0
  176. package/src/api/package.json +10 -0
  177. package/src/background-wake/background-wake-routes.test.ts +233 -0
  178. package/src/background-wake/next-wake.test.ts +289 -0
  179. package/src/background-wake/next-wake.ts +172 -0
  180. package/src/background-wake/runtime-registry.ts +24 -0
  181. package/src/browser/operations.ts +15 -0
  182. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  183. package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
  184. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  185. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  186. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  187. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  188. package/src/cli/commands/__tests__/memory-v2.test.ts +10 -12
  189. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  190. package/src/cli/commands/browser.ts +247 -0
  191. package/src/cli/commands/conversations.ts +128 -1
  192. package/src/cli/commands/domain.ts +91 -41
  193. package/src/cli/commands/inference-providers.ts +147 -1
  194. package/src/cli/commands/inference.ts +93 -40
  195. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  196. package/src/cli/commands/memory-v2.ts +483 -0
  197. package/src/cli/commands/memory-v3-render.ts +344 -0
  198. package/src/cli/commands/memory-v3.ts +316 -0
  199. package/src/cli/commands/notifications.ts +24 -2
  200. package/src/cli/program.ts +2 -0
  201. package/src/cli/utils/conversation-id.ts +17 -5
  202. package/src/config/assistant-feature-flags.ts +21 -9
  203. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  204. package/src/config/bundled-skills/document-editor/SKILL.md +124 -0
  205. package/src/config/bundled-skills/document-editor/TOOLS.json +258 -0
  206. package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
  207. package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
  208. package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
  209. package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
  210. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  211. package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
  212. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  213. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  214. package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
  215. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  216. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  217. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  218. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  219. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  220. package/src/config/bundled-skills/schedule/SKILL.md +8 -0
  221. package/src/config/bundled-tool-registry.ts +24 -12
  222. package/src/config/call-site-defaults.ts +20 -0
  223. package/src/config/feature-flag-registry.json +115 -3
  224. package/src/config/llm-resolver.ts +16 -2
  225. package/src/config/schemas/__tests__/memory-v2.test.ts +217 -1
  226. package/src/config/schemas/call-site-catalog.ts +35 -0
  227. package/src/config/schemas/llm.ts +14 -0
  228. package/src/config/schemas/memory-v2.ts +294 -1
  229. package/src/config/schemas/memory.ts +2 -1
  230. package/src/context/compactor.ts +60 -1
  231. package/src/context/token-estimator.ts +47 -4
  232. package/src/context/window-manager.ts +25 -0
  233. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  234. package/src/conversations/message-consolidation.ts +404 -0
  235. package/src/credential-health/credential-health-service.ts +34 -19
  236. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
  237. package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
  238. package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
  239. package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
  240. package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
  241. package/src/daemon/conversation-agent-loop-handlers.ts +155 -36
  242. package/src/daemon/conversation-agent-loop.ts +307 -88
  243. package/src/daemon/conversation-error.ts +31 -1
  244. package/src/daemon/conversation-lifecycle.ts +149 -118
  245. package/src/daemon/conversation-messaging.ts +3 -0
  246. package/src/daemon/conversation-process.ts +273 -0
  247. package/src/daemon/conversation-queue-manager.ts +14 -0
  248. package/src/daemon/conversation-runtime-assembly.ts +145 -84
  249. package/src/daemon/conversation-slash.ts +37 -5
  250. package/src/daemon/conversation-surfaces.ts +45 -2
  251. package/src/daemon/conversation-tool-setup.ts +70 -3
  252. package/src/daemon/conversation-usage.ts +2 -0
  253. package/src/daemon/conversation.ts +54 -32
  254. package/src/daemon/disk-pressure-guard.ts +14 -2
  255. package/src/daemon/first-greeting.ts +10 -0
  256. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
  257. package/src/daemon/handlers/config-a2a.ts +160 -0
  258. package/src/daemon/handlers/config-model.test.ts +2 -0
  259. package/src/daemon/handlers/conversations.ts +90 -3
  260. package/src/daemon/handlers/shared.ts +92 -29
  261. package/src/daemon/host-bash-proxy.ts +1 -1
  262. package/src/daemon/host-browser-proxy.ts +5 -5
  263. package/src/daemon/host-cu-proxy.ts +5 -5
  264. package/src/daemon/host-file-proxy.ts +5 -5
  265. package/src/daemon/host-proxy-base.ts +4 -4
  266. package/src/daemon/host-transfer-proxy.ts +11 -11
  267. package/src/daemon/lifecycle.ts +40 -23
  268. package/src/daemon/meet-manifest-loader.ts +1 -7
  269. package/src/daemon/message-protocol.ts +4 -0
  270. package/src/daemon/message-types/conversations.ts +14 -9
  271. package/src/daemon/message-types/document-comments.ts +50 -0
  272. package/src/daemon/message-types/home.ts +1 -13
  273. package/src/daemon/message-types/messages.ts +66 -7
  274. package/src/daemon/message-types/surfaces.ts +3 -1
  275. package/src/daemon/message-types/sync.ts +14 -0
  276. package/src/daemon/message-types/web-activity.ts +57 -0
  277. package/src/daemon/plugin-source-watcher.ts +135 -3
  278. package/src/daemon/process-message.ts +69 -12
  279. package/src/daemon/shutdown-handlers.ts +24 -5
  280. package/src/daemon/switch-inference-profile-tool.ts +52 -0
  281. package/src/daemon/tool-setup-types.ts +13 -0
  282. package/src/daemon/trust-context.ts +6 -0
  283. package/src/documents/document-comments-store.test.ts +338 -0
  284. package/src/documents/document-comments-store.ts +237 -0
  285. package/src/documents/document-store.ts +202 -0
  286. package/src/events/relationship-state-updated.ts +25 -0
  287. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -2
  288. package/src/heartbeat/heartbeat-service.ts +1 -0
  289. package/src/home/__tests__/suggested-prompts.test.ts +33 -2
  290. package/src/home/feed-types.ts +6 -1
  291. package/src/home/home-content-refresh.ts +52 -0
  292. package/src/home/home-greeting-cache.ts +69 -0
  293. package/src/home/home-greeting.ts +85 -0
  294. package/src/home/suggested-prompts.ts +168 -9
  295. package/src/ipc/gateway-flag-listener.ts +123 -0
  296. package/src/ipc/skill-routes/registries.ts +8 -12
  297. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  298. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  299. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
  300. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  301. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
  302. package/src/memory/__tests__/memory-retrospective-job.test.ts +327 -6
  303. package/src/memory/auto-analysis-enqueue.ts +5 -1
  304. package/src/memory/conversation-crud.ts +191 -100
  305. package/src/memory/conversation-starters-cadence.ts +3 -1
  306. package/src/memory/conversation-title-service.ts +19 -3
  307. package/src/memory/db-async-query.ts +214 -0
  308. package/src/memory/db-init.ts +26 -0
  309. package/src/memory/db-maintenance.ts +30 -21
  310. package/src/memory/delivery-crud.ts +41 -0
  311. package/src/memory/delivery-status.ts +141 -15
  312. package/src/memory/external-conversation-store.ts +32 -1
  313. package/src/memory/graph/bootstrap.ts +8 -1
  314. package/src/memory/graph/capability-seed.ts +7 -3
  315. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  316. package/src/memory/graph/extraction.ts +1 -5
  317. package/src/memory/graph/graph-search.ts +7 -1
  318. package/src/memory/indexer.ts +28 -18
  319. package/src/memory/job-handlers/cleanup.ts +76 -18
  320. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  321. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  322. package/src/memory/jobs-store.ts +14 -0
  323. package/src/memory/jobs-worker.ts +68 -15
  324. package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
  325. package/src/memory/llm-request-log-source-local.ts +7 -0
  326. package/src/memory/llm-request-log-source.ts +9 -2
  327. package/src/memory/llm-request-log-store.ts +43 -1
  328. package/src/memory/llm-usage-store.ts +24 -0
  329. package/src/memory/memory-retrospective-constants.ts +28 -0
  330. package/src/memory/memory-retrospective-enqueue.ts +11 -3
  331. package/src/memory/memory-retrospective-job.ts +413 -18
  332. package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
  333. package/src/memory/memory-v2-activation-log-store.ts +41 -14
  334. package/src/memory/migrations/100-core-tables.ts +1 -0
  335. package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
  336. package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
  337. package/src/memory/migrations/253-document-comments.ts +47 -0
  338. package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
  339. package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
  340. package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
  341. package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
  342. package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
  343. package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
  344. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  345. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  346. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  347. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  348. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  349. package/src/memory/migrations/index.ts +34 -0
  350. package/src/memory/migrations/registry.ts +58 -0
  351. package/src/memory/onboarding-events-store.ts +7 -0
  352. package/src/memory/schema/calls.ts +1 -0
  353. package/src/memory/schema/conversations.ts +3 -0
  354. package/src/memory/schema/infrastructure.ts +22 -0
  355. package/src/memory/tool-usage-store.ts +36 -8
  356. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  357. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  358. package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
  359. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  360. package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
  361. package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
  362. package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
  363. package/src/memory/v2/__tests__/injection.test.ts +158 -112
  364. package/src/memory/v2/__tests__/page-index.test.ts +365 -1
  365. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  366. package/src/memory/v2/__tests__/router.test.ts +660 -4
  367. package/src/memory/v2/consolidation-job.ts +14 -0
  368. package/src/memory/v2/harness/compare.ts +57 -0
  369. package/src/memory/v2/harness/metrics.ts +124 -0
  370. package/src/memory/v2/harness/oracle.ts +145 -0
  371. package/src/memory/v2/harness/replay-input.ts +224 -0
  372. package/src/memory/v2/harness/retriever.ts +74 -0
  373. package/src/memory/v2/harness/router-retriever.ts +43 -0
  374. package/src/memory/v2/harness/runner.ts +106 -0
  375. package/src/memory/v2/harness/trace.ts +58 -0
  376. package/src/memory/v2/injection-events.ts +101 -0
  377. package/src/memory/v2/injection.ts +42 -25
  378. package/src/memory/v2/page-index.ts +209 -7
  379. package/src/memory/v2/page-store.ts +18 -0
  380. package/src/memory/v2/prompts/router.ts +26 -1
  381. package/src/memory/v2/qdrant.ts +14 -2
  382. package/src/memory/v2/router.ts +369 -62
  383. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  384. package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
  385. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  386. package/src/memory/v3/__tests__/edges.test.ts +563 -0
  387. package/src/memory/v3/__tests__/filter.test.ts +512 -0
  388. package/src/memory/v3/__tests__/gate.test.ts +574 -0
  389. package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
  390. package/src/memory/v3/__tests__/loop.test.ts +530 -0
  391. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  392. package/src/memory/v3/__tests__/scouts.test.ts +440 -0
  393. package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
  394. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  395. package/src/memory/v3/__tests__/traversal.test.ts +469 -0
  396. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  397. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  398. package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
  399. package/src/memory/v3/__tests__/validate.test.ts +245 -0
  400. package/src/memory/v3/auto-edges.ts +223 -0
  401. package/src/memory/v3/coactivation-store.ts +124 -0
  402. package/src/memory/v3/consolidation-job.ts +323 -0
  403. package/src/memory/v3/edge-learning-job.ts +160 -0
  404. package/src/memory/v3/edges.ts +249 -0
  405. package/src/memory/v3/filter.ts +281 -0
  406. package/src/memory/v3/gate.ts +334 -0
  407. package/src/memory/v3/index-composition.ts +113 -0
  408. package/src/memory/v3/llm-capture.ts +46 -0
  409. package/src/memory/v3/loop.ts +382 -0
  410. package/src/memory/v3/maintenance.ts +144 -0
  411. package/src/memory/v3/prompt-context.ts +33 -0
  412. package/src/memory/v3/prompts/consolidation.ts +458 -0
  413. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  414. package/src/memory/v3/retriever.ts +33 -0
  415. package/src/memory/v3/scouts.ts +420 -0
  416. package/src/memory/v3/shadow-middleware.ts +305 -0
  417. package/src/memory/v3/traversal.ts +206 -0
  418. package/src/memory/v3/tree-index.ts +237 -0
  419. package/src/memory/v3/tree-store.ts +394 -0
  420. package/src/memory/v3/tree-walk.ts +351 -0
  421. package/src/memory/v3/types.ts +65 -0
  422. package/src/memory/v3/validate.ts +300 -0
  423. package/src/messaging/providers/index.ts +7 -1
  424. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
  425. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
  426. package/src/messaging/providers/slack/adapter.ts +178 -25
  427. package/src/messaging/providers/slack/api.test.ts +54 -0
  428. package/src/messaging/providers/slack/api.ts +119 -3
  429. package/src/messaging/providers/slack/client.ts +12 -0
  430. package/src/messaging/providers/slack/deep-link.ts +20 -1
  431. package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
  432. package/src/messaging/providers/slack/message-metadata.ts +156 -0
  433. package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
  434. package/src/messaging/providers/slack/render-transcript.ts +176 -49
  435. package/src/messaging/providers/slack/send.test.ts +77 -0
  436. package/src/messaging/providers/slack/send.ts +8 -2
  437. package/src/messaging/providers/slack/types.ts +14 -0
  438. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
  439. package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
  440. package/src/notifications/adapters/macos.ts +18 -1
  441. package/src/notifications/adapters/platform.ts +1 -1
  442. package/src/notifications/conversation-seed-composer.ts +14 -2
  443. package/src/notifications/decision-engine.ts +1 -4
  444. package/src/notifications/deferred-emit.ts +135 -0
  445. package/src/notifications/emit-signal.ts +38 -50
  446. package/src/notifications/home-feed-side-effect.ts +60 -30
  447. package/src/oauth/connect-orchestrator.ts +3 -0
  448. package/src/oauth/credential-token-resolver.ts +2 -0
  449. package/src/oauth/manual-token-connection.ts +19 -0
  450. package/src/oauth/oauth-store.ts +12 -0
  451. package/src/oauth/seed-providers.ts +22 -0
  452. package/src/permissions/prompter.ts +8 -5
  453. package/src/permissions/question-prompter.ts +5 -2
  454. package/src/permissions/secret-prompter.ts +6 -3
  455. package/src/plugin-api/index.ts +4 -0
  456. package/src/plugin-api/types.ts +7 -33
  457. package/src/plugins/defaults/index.ts +6 -0
  458. package/src/plugins/defaults/injectors.ts +100 -20
  459. package/src/plugins/external-plugin-loader.ts +5 -68
  460. package/src/plugins/types.ts +11 -16
  461. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  462. package/src/prompts/__tests__/system-prompt.test.ts +46 -2
  463. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  464. package/src/prompts/normalize-onboarding.ts +40 -0
  465. package/src/prompts/persona-resolver.ts +36 -21
  466. package/src/prompts/sections.ts +69 -19
  467. package/src/prompts/system-prompt.ts +118 -216
  468. package/src/prompts/template-detection.ts +37 -0
  469. package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
  470. package/src/prompts/templates/BOOTSTRAP.md +10 -2
  471. package/src/prompts/templates/VOICE.md +3 -0
  472. package/src/prompts/templates/system-sections.ts +281 -9
  473. package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
  474. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  475. package/src/providers/anthropic/client.ts +159 -66
  476. package/src/providers/call-site-routing.ts +14 -2
  477. package/src/providers/connection-model-compat.ts +38 -0
  478. package/src/providers/connection-resolution.ts +16 -2
  479. package/src/providers/fireworks/client.ts +20 -2
  480. package/src/providers/gemini/client.ts +49 -6
  481. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
  482. package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
  483. package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
  484. package/src/providers/inference/adapter-factory.ts +18 -1
  485. package/src/providers/inference/auth.ts +3 -3
  486. package/src/providers/inference/codex-token-refresh.ts +128 -0
  487. package/src/providers/inference/resolve-auth.ts +49 -6
  488. package/src/providers/minimax/client.ts +106 -0
  489. package/src/providers/model-catalog.ts +91 -1
  490. package/src/providers/model-intents.ts +1 -1
  491. package/src/providers/openai/chat-completions-provider.ts +63 -23
  492. package/src/providers/openai/codex-models.ts +18 -0
  493. package/src/providers/openai/responses-provider.ts +86 -23
  494. package/src/providers/openrouter/client.ts +5 -1
  495. package/src/providers/provider-send-message.ts +7 -1
  496. package/src/providers/retry.ts +34 -3
  497. package/src/providers/thinking-config.ts +26 -1
  498. package/src/providers/types.ts +25 -0
  499. package/src/providers/usage-tracking.ts +2 -0
  500. package/src/runtime/AGENTS.md +2 -2
  501. package/src/runtime/__tests__/agent-wake.test.ts +214 -0
  502. package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
  503. package/src/runtime/agent-wake.ts +152 -56
  504. package/src/runtime/assistant-event-hub.ts +76 -6
  505. package/src/runtime/auth/route-policy.ts +43 -3
  506. package/src/runtime/background-job-runner.ts +26 -0
  507. package/src/runtime/btw-sidechain.ts +0 -6
  508. package/src/runtime/channel-reply-delivery.ts +182 -47
  509. package/src/runtime/channel-retry-sweep.ts +141 -16
  510. package/src/runtime/http-types.ts +7 -6
  511. package/src/runtime/migrations/vbundle-builder.ts +10 -3
  512. package/src/runtime/pending-interactions.ts +50 -8
  513. package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
  514. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +161 -1
  515. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
  516. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +290 -0
  517. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  518. package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
  519. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
  520. package/src/runtime/routes/acp-routes.test.ts +255 -6
  521. package/src/runtime/routes/acp-routes.ts +8 -1
  522. package/src/runtime/routes/approval-routes.ts +4 -1
  523. package/src/runtime/routes/avatar-routes.ts +10 -10
  524. package/src/runtime/routes/background-wake-routes.ts +188 -0
  525. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  526. package/src/runtime/routes/btw-routes.ts +0 -6
  527. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
  528. package/src/runtime/routes/content-source-routes.ts +78 -0
  529. package/src/runtime/routes/conversation-cli-routes.ts +147 -2
  530. package/src/runtime/routes/conversation-list-routes.ts +12 -4
  531. package/src/runtime/routes/conversation-management-routes.ts +77 -20
  532. package/src/runtime/routes/conversation-query-routes.ts +196 -31
  533. package/src/runtime/routes/conversation-routes.ts +472 -425
  534. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  535. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  536. package/src/runtime/routes/document-comments-routes.ts +287 -0
  537. package/src/runtime/routes/documents-routes.ts +33 -0
  538. package/src/runtime/routes/domain-routes.ts +60 -10
  539. package/src/runtime/routes/email-routes.ts +5 -2
  540. package/src/runtime/routes/events-routes.ts +54 -10
  541. package/src/runtime/routes/group-routes.ts +24 -8
  542. package/src/runtime/routes/home-feed-routes.ts +6 -3
  543. package/src/runtime/routes/host-app-control-routes.ts +1 -1
  544. package/src/runtime/routes/host-browser-routes.ts +17 -2
  545. package/src/runtime/routes/host-cu-routes.ts +2 -2
  546. package/src/runtime/routes/identity-routes.ts +21 -0
  547. package/src/runtime/routes/inbound-message-handler.ts +288 -58
  548. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  549. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
  550. package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
  551. package/src/runtime/routes/index.ts +20 -4
  552. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  553. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  554. package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
  555. package/src/runtime/routes/integrations/a2a.ts +60 -1
  556. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  557. package/src/runtime/routes/log-export-routes.ts +39 -0
  558. package/src/runtime/routes/memory-item-routes.ts +8 -3
  559. package/src/runtime/routes/memory-v2-routes.ts +427 -0
  560. package/src/runtime/routes/memory-v3-routes.ts +316 -0
  561. package/src/runtime/routes/migration-routes.ts +21 -24
  562. package/src/runtime/routes/notification-routes.ts +19 -2
  563. package/src/runtime/routes/plugins-routes.ts +337 -0
  564. package/src/runtime/routes/question-routes.ts +4 -1
  565. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  566. package/src/runtime/routes/sanity-routes.ts +159 -0
  567. package/src/runtime/routes/secret-routes.ts +25 -5
  568. package/src/runtime/routes/settings-routes.ts +12 -11
  569. package/src/runtime/routes/slack-channel-routes.ts +188 -0
  570. package/src/runtime/routes/workspace-routes.ts +25 -10
  571. package/src/runtime/services/conversation-serializer.ts +30 -4
  572. package/src/runtime/sync/resource-sync-events.ts +106 -38
  573. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  574. package/src/runtime/sync/sync-publisher.ts +2 -1
  575. package/src/runtime/verification-outbound-actions.ts +73 -1
  576. package/src/schedule/integration-status.ts +3 -1
  577. package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
  578. package/src/security/oauth2-device-code.ts +307 -0
  579. package/src/security/oauth2.ts +26 -9
  580. package/src/security/secure-keys.ts +5 -0
  581. package/src/skills/catalog-install.ts +6 -2
  582. package/src/telemetry/types.ts +12 -0
  583. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  584. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  585. package/src/tools/acp/spawn.test.ts +119 -0
  586. package/src/tools/acp/spawn.ts +15 -2
  587. package/src/tools/apps/definitions.ts +2 -8
  588. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  589. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  590. package/src/tools/browser/__tests__/pinned-tabs.test.ts +150 -0
  591. package/src/tools/browser/browser-execution.ts +106 -0
  592. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  593. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
  594. package/src/tools/browser/cdp-client/__tests__/types.test.ts +4 -0
  595. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +22 -0
  596. package/src/tools/browser/cdp-client/extension-cdp-client.ts +42 -2
  597. package/src/tools/browser/cdp-client/factory.ts +171 -4
  598. package/src/tools/browser/cdp-client/local-cdp-client.ts +21 -0
  599. package/src/tools/browser/cdp-client/types.ts +101 -0
  600. package/src/tools/browser/pinned-tabs.ts +146 -0
  601. package/src/tools/computer-use/definitions.ts +22 -78
  602. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  603. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  604. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  605. package/src/tools/credentials/vault.ts +3 -9
  606. package/src/tools/document/document-comment-tool.test.ts +379 -0
  607. package/src/tools/document/document-comment-tool.ts +156 -0
  608. package/src/tools/document/document-tool.ts +187 -2
  609. package/src/tools/execution-target.ts +21 -23
  610. package/src/tools/executor.ts +6 -1
  611. package/src/tools/filesystem/edit.ts +3 -9
  612. package/src/tools/filesystem/list.ts +3 -9
  613. package/src/tools/filesystem/read.ts +3 -9
  614. package/src/tools/filesystem/write.ts +3 -9
  615. package/src/tools/host-filesystem/edit.ts +3 -9
  616. package/src/tools/host-filesystem/read.ts +3 -9
  617. package/src/tools/host-filesystem/transfer.ts +3 -9
  618. package/src/tools/host-filesystem/write.ts +3 -9
  619. package/src/tools/host-terminal/host-shell.ts +3 -9
  620. package/src/tools/mcp/mcp-tool-factory.ts +1 -8
  621. package/src/tools/memory/register.test.ts +1 -1
  622. package/src/tools/memory/register.ts +4 -9
  623. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
  624. package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
  625. package/src/tools/network/domain-normalize.ts +17 -0
  626. package/src/tools/network/web-fetch.ts +216 -73
  627. package/src/tools/network/web-search.ts +216 -98
  628. package/src/tools/registry.ts +7 -23
  629. package/src/tools/schema-transforms.ts +1 -1
  630. package/src/tools/skills/execute.ts +3 -9
  631. package/src/tools/skills/load.ts +3 -9
  632. package/src/tools/skills/skill-tool-factory.ts +1 -8
  633. package/src/tools/subagent/notify-parent.ts +3 -9
  634. package/src/tools/system/request-permission.ts +3 -9
  635. package/src/tools/terminal/safe-env.ts +3 -2
  636. package/src/tools/terminal/shell.ts +3 -9
  637. package/src/tools/tool-approval-handler.ts +19 -12
  638. package/src/tools/tool-defaults.ts +94 -0
  639. package/src/tools/types.ts +31 -98
  640. package/src/tools/ui-surface/definitions.ts +9 -23
  641. package/src/types/onboarding-context.ts +4 -0
  642. package/src/usage/pricing.ts +23 -0
  643. package/src/usage/types.ts +12 -0
  644. package/src/util/__tests__/favicon.test.ts +84 -0
  645. package/src/util/favicon.ts +40 -0
  646. package/src/util/logger.ts +16 -7
  647. package/src/util/platform.ts +7 -7
  648. package/src/util/sqlite3-runtime.ts +65 -0
  649. package/src/workspace/git-service.ts +75 -4
  650. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  651. package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
  652. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  653. package/src/workspace/migrations/registry.ts +4 -0
  654. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  655. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  656. package/src/config/bundled-skills/document/SKILL.md +0 -54
  657. package/src/config/bundled-skills/document/TOOLS.json +0 -106
  658. package/src/daemon/seed-files.ts +0 -18
  659. package/src/prompts/cache-boundary.ts +0 -8
  660. package/src/runtime/routes/interface-routes.ts +0 -43
  661. /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
  662. /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
  663. /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
  664. /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
  665. /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
@@ -0,0 +1,237 @@
1
+ import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
2
+ import { createServer, type Server, type Socket } from "node:net";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { afterEach,beforeEach, describe, expect, mock, test } from "bun:test";
6
+
7
+ // ---------------------------------------------------------------------------
8
+ // Isolated temp directory for the IPC socket
9
+ // ---------------------------------------------------------------------------
10
+ const testRoot = mkdtempSync(join(tmpdir(), "flag-listener-test-"));
11
+ const socketPath = join(testRoot, "gateway.sock");
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // Mock socket-path resolution to use our test socket
15
+ // ---------------------------------------------------------------------------
16
+ mock.module("../ipc/socket-path.js", () => ({
17
+ resolveIpcSocketPath: (_name: string) => ({
18
+ path: socketPath,
19
+ source: "workspace" as const,
20
+ }),
21
+ getAssistantSocketPath: () => join(testRoot, "assistant.sock"),
22
+ }));
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // Track calls to refreshOverridesFromGateway
26
+ // ---------------------------------------------------------------------------
27
+ let refreshCallCount = 0;
28
+
29
+ mock.module("../config/assistant-feature-flags.js", () => ({
30
+ refreshOverridesFromGateway: async () => {
31
+ refreshCallCount++;
32
+ },
33
+ initFeatureFlagOverrides: async () => {},
34
+ clearFeatureFlagOverridesCache: () => {},
35
+ isAssistantFeatureFlagEnabled: () => true,
36
+ _setOverridesForTesting: () => {},
37
+ }));
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Track calls to publishSyncInvalidation so we can assert the listener
41
+ // fans flag changes out onto the SSE hub.
42
+ // ---------------------------------------------------------------------------
43
+ let publishedTagSets: string[][] = [];
44
+
45
+ mock.module("../runtime/sync/sync-publisher.js", () => ({
46
+ publishSyncInvalidation: async (tags: string[]) => {
47
+ publishedTagSets.push([...tags]);
48
+ return { type: "sync_changed", tags };
49
+ },
50
+ }));
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // Dynamic imports (after mock.module)
54
+ // ---------------------------------------------------------------------------
55
+ const { startGatewayFlagListener, stopGatewayFlagListener } = await import(
56
+ "../ipc/gateway-flag-listener.js"
57
+ );
58
+
59
+ // ---------------------------------------------------------------------------
60
+ // Helpers
61
+ // ---------------------------------------------------------------------------
62
+
63
+ function createTestServer(): {
64
+ server: Server;
65
+ clients: Set<Socket>;
66
+ emit: (event: string, data?: unknown) => void;
67
+ waitForClient: () => Promise<Socket>;
68
+ } {
69
+ const clients = new Set<Socket>();
70
+ const clientWaiters: Array<(socket: Socket) => void> = [];
71
+
72
+ const server = createServer((socket) => {
73
+ clients.add(socket);
74
+ socket.on("close", () => clients.delete(socket));
75
+ const waiter = clientWaiters.shift();
76
+ if (waiter) waiter(socket);
77
+ });
78
+
79
+ return {
80
+ server,
81
+ clients,
82
+ emit: (event: string, data?: unknown) => {
83
+ const payload = JSON.stringify({ event, data }) + "\n";
84
+ for (const client of clients) {
85
+ if (!client.destroyed) client.write(payload);
86
+ }
87
+ },
88
+ waitForClient: () =>
89
+ new Promise((resolve) => {
90
+ if (clients.size > 0) {
91
+ resolve(clients.values().next().value!);
92
+ return;
93
+ }
94
+ clientWaiters.push(resolve);
95
+ }),
96
+ };
97
+ }
98
+
99
+ // ---------------------------------------------------------------------------
100
+ // Tests
101
+ // ---------------------------------------------------------------------------
102
+ describe("gateway-flag-listener", () => {
103
+ let testServer: ReturnType<typeof createTestServer>;
104
+
105
+ beforeEach(() => {
106
+ mkdirSync(testRoot, { recursive: true });
107
+ refreshCallCount = 0;
108
+ publishedTagSets = [];
109
+ testServer = createTestServer();
110
+ });
111
+
112
+ afterEach(async () => {
113
+ stopGatewayFlagListener();
114
+ await new Promise<void>((resolve) => {
115
+ for (const client of testServer.clients) {
116
+ if (!client.destroyed) client.destroy();
117
+ }
118
+ testServer.server.close(() => resolve());
119
+ });
120
+ try {
121
+ rmSync(socketPath, { force: true });
122
+ } catch {
123
+ // best effort
124
+ }
125
+ });
126
+
127
+ test("refreshes flag cache on connect and on feature_flags_changed event", async () => {
128
+ await new Promise<void>((resolve) => {
129
+ testServer.server.listen(socketPath, resolve);
130
+ });
131
+
132
+ startGatewayFlagListener();
133
+ await testServer.waitForClient();
134
+ await new Promise((r) => setTimeout(r, 100));
135
+
136
+ expect(refreshCallCount).toBe(1);
137
+
138
+ testServer.emit("feature_flags_changed");
139
+ await new Promise((r) => setTimeout(r, 100));
140
+
141
+ expect(refreshCallCount).toBe(2);
142
+ });
143
+
144
+ test("broadcasts feature-flags sync_changed when flags change", async () => {
145
+ await new Promise<void>((resolve) => {
146
+ testServer.server.listen(socketPath, resolve);
147
+ });
148
+
149
+ startGatewayFlagListener();
150
+ await testServer.waitForClient();
151
+ await new Promise((r) => setTimeout(r, 100));
152
+
153
+ // Connect refresh should not broadcast — only an actual change does.
154
+ expect(publishedTagSets.length).toBe(0);
155
+
156
+ testServer.emit("feature_flags_changed");
157
+ await new Promise((r) => setTimeout(r, 100));
158
+
159
+ expect(publishedTagSets.length).toBe(1);
160
+ expect(publishedTagSets[0]).toEqual([
161
+ "feature-flags:client",
162
+ "feature-flags:assistant",
163
+ ]);
164
+ });
165
+
166
+ test("ignores non-flag events", async () => {
167
+ await new Promise<void>((resolve) => {
168
+ testServer.server.listen(socketPath, resolve);
169
+ });
170
+
171
+ startGatewayFlagListener();
172
+ await testServer.waitForClient();
173
+ await new Promise((r) => setTimeout(r, 100));
174
+
175
+ const countAfterConnect = refreshCallCount;
176
+
177
+ testServer.emit("some_other_event");
178
+ await new Promise((r) => setTimeout(r, 100));
179
+
180
+ expect(refreshCallCount).toBe(countAfterConnect);
181
+ });
182
+
183
+ test("reconnects on disconnect and handles events on new connection", async () => {
184
+ await new Promise<void>((resolve) => {
185
+ testServer.server.listen(socketPath, resolve);
186
+ });
187
+
188
+ startGatewayFlagListener();
189
+ const firstClient = await testServer.waitForClient();
190
+
191
+ // Wait for the close event to propagate back to the server before
192
+ // setting up the next waitForClient — otherwise waitForClient might
193
+ // resolve with the old (now-destroyed) socket that is still in the set.
194
+ await new Promise<void>((resolve) => {
195
+ firstClient.on("close", resolve);
196
+ firstClient.destroy();
197
+ });
198
+
199
+ // Wait for reconnect (initial backoff is 1s)
200
+ const secondClient = await Promise.race([
201
+ testServer.waitForClient(),
202
+ new Promise<null>((r) => setTimeout(() => r(null), 3000)),
203
+ ]);
204
+
205
+ expect(secondClient).not.toBeNull();
206
+
207
+ await new Promise((r) => setTimeout(r, 100));
208
+ const countAfterReconnect = refreshCallCount;
209
+ expect(countAfterReconnect).toBeGreaterThan(0);
210
+
211
+ const payload =
212
+ JSON.stringify({ event: "feature_flags_changed" }) + "\n";
213
+ secondClient!.write(payload);
214
+ await new Promise((r) => setTimeout(r, 200));
215
+
216
+ expect(refreshCallCount).toBe(countAfterReconnect + 1);
217
+ });
218
+
219
+ test("stopGatewayFlagListener cleans up and does not reconnect", async () => {
220
+ await new Promise<void>((resolve) => {
221
+ testServer.server.listen(socketPath, resolve);
222
+ });
223
+
224
+ startGatewayFlagListener();
225
+ await testServer.waitForClient();
226
+
227
+ stopGatewayFlagListener();
228
+ await new Promise((r) => setTimeout(r, 50));
229
+
230
+ const initialClientCount = testServer.clients.size;
231
+
232
+ // Wait past reconnect backoff — should not reconnect
233
+ await new Promise((r) => setTimeout(r, 1500));
234
+
235
+ expect(testServer.clients.size).toBeLessThanOrEqual(initialClientCount);
236
+ });
237
+ });
@@ -75,6 +75,12 @@ mock.module("@google/genai", () => ({
75
75
  };
76
76
  },
77
77
  ApiError: FakeApiError,
78
+ ThinkingLevel: {
79
+ MINIMAL: "MINIMAL",
80
+ LOW: "LOW",
81
+ MEDIUM: "MEDIUM",
82
+ HIGH: "HIGH",
83
+ },
78
84
  }));
79
85
 
80
86
  // Import after mocking
@@ -223,6 +229,78 @@ describe("GeminiProvider", () => {
223
229
  expect(config.systemInstruction).toBe("You are a helpful assistant.");
224
230
  });
225
231
 
232
+ // -----------------------------------------------------------------------
233
+ // Thinking config
234
+ // -----------------------------------------------------------------------
235
+ test("omits thinkingConfig when no thinking config is supplied", async () => {
236
+ fakeChunks = [textChunk("OK"), finishChunk("STOP", 10, 2)];
237
+
238
+ await provider.sendMessage([
239
+ { role: "user", content: [{ type: "text", text: "Hi" }] },
240
+ ]);
241
+
242
+ const config = lastStreamParams!.config as Record<string, unknown>;
243
+ expect(config.thinkingConfig).toBeUndefined();
244
+ });
245
+
246
+ test("maps wire { type: 'adaptive', level, streamThinking } to Gemini thinkingConfig", async () => {
247
+ fakeChunks = [textChunk("OK"), finishChunk("STOP", 10, 2)];
248
+
249
+ await provider.sendMessage(
250
+ [{ role: "user", content: [{ type: "text", text: "Hi" }] }],
251
+ undefined,
252
+ undefined,
253
+ {
254
+ config: {
255
+ thinking: {
256
+ type: "adaptive",
257
+ level: "high",
258
+ streamThinking: false,
259
+ },
260
+ },
261
+ },
262
+ );
263
+
264
+ const config = lastStreamParams!.config as Record<string, unknown>;
265
+ expect(config.thinkingConfig).toEqual({
266
+ thinkingLevel: "HIGH",
267
+ includeThoughts: false,
268
+ });
269
+ });
270
+
271
+ test("maps wire { type: 'disabled' } to MINIMAL thinking level", async () => {
272
+ fakeChunks = [textChunk("OK"), finishChunk("STOP", 10, 2)];
273
+
274
+ await provider.sendMessage(
275
+ [{ role: "user", content: [{ type: "text", text: "Hi" }] }],
276
+ undefined,
277
+ undefined,
278
+ { config: { thinking: { type: "disabled" } } },
279
+ );
280
+
281
+ const config = lastStreamParams!.config as Record<string, unknown>;
282
+ expect(config.thinkingConfig).toEqual({
283
+ thinkingLevel: "MINIMAL",
284
+ includeThoughts: false,
285
+ });
286
+ });
287
+
288
+ test("omits thinkingConfig when wire shape is adaptive with no extras", async () => {
289
+ fakeChunks = [textChunk("OK"), finishChunk("STOP", 10, 2)];
290
+
291
+ await provider.sendMessage(
292
+ [{ role: "user", content: [{ type: "text", text: "Hi" }] }],
293
+ undefined,
294
+ undefined,
295
+ { config: { thinking: { type: "adaptive" } } },
296
+ );
297
+
298
+ const config = lastStreamParams!.config as Record<string, unknown>;
299
+ // No level/streamThinking → omit so Google's per-model default applies
300
+ // (Gemini 3.x defaults to "medium" with dynamic thinking).
301
+ expect(config.thinkingConfig).toBeUndefined();
302
+ });
303
+
226
304
  // -----------------------------------------------------------------------
227
305
  // Tool definitions
228
306
  // -----------------------------------------------------------------------
@@ -56,7 +56,6 @@ mock.module("../notifications/emit-signal.js", () => ({
56
56
  }
57
57
  return mockEmitResult;
58
58
  },
59
- registerBroadcastFn: () => {},
60
59
  }));
61
60
 
62
61
  import {
@@ -280,11 +280,13 @@ describe("startOutbound", () => {
280
280
  expect(voiceCallInitCalls.length).toBe(1);
281
281
  });
282
282
 
283
- test("unsupported channel returns unsupported_channel", async () => {
284
- // Cast to bypass type checking for test purposes
285
- const result = await startOutbound({ channel: "email" as never });
286
- expect(result.success).toBe(false);
287
- expect(result.error).toBe("unsupported_channel");
283
+ test("email channel creates outbound session", async () => {
284
+ const result = await startOutbound({
285
+ channel: "email",
286
+ destination: "user@example.com",
287
+ });
288
+ expect(result.success).toBe(true);
289
+ expect(result.channel).toBe("email");
288
290
  });
289
291
  });
290
292
 
@@ -193,6 +193,6 @@ describe("handleConfirmationResponse canonical status sync", () => {
193
193
  // Canonical status sync is now handled inside Conversation.handleConfirmationResponse,
194
194
  // which this test mocks out — so the handler itself no longer calls resolveCanonicalGuardianRequest.
195
195
  expect(resolveCanonicalGuardianRequestMock).not.toHaveBeenCalled();
196
- expect(resolveMock).toHaveBeenCalledWith("req-confirm-allow");
196
+ expect(resolveMock).toHaveBeenCalledWith("req-confirm-allow", "approved");
197
197
  });
198
198
  });
@@ -27,6 +27,7 @@ let cdpSendHandler: (
27
27
  params?: Record<string, unknown>,
28
28
  ) => unknown = () => ({});
29
29
  let cdpDisposed = false;
30
+ let cdpSetSessionIdCalls: Array<string | undefined> = [];
30
31
 
31
32
  function makeFakeCdp(kind: "local" | "extension", conversationId: string) {
32
33
  return {
@@ -43,6 +44,12 @@ function makeFakeCdp(kind: "local" | "extension", conversationId: string) {
43
44
  dispose() {
44
45
  cdpDisposed = true;
45
46
  },
47
+ // Mirrors the optional method on the real CdpClient interface so
48
+ // the --new-tab path can be exercised end-to-end. Recorded for
49
+ // per-test assertions.
50
+ setCdpSessionId(cdpSessionId: string | undefined) {
51
+ cdpSetSessionIdCalls.push(cdpSessionId);
52
+ },
46
53
  };
47
54
  }
48
55
 
@@ -135,6 +142,7 @@ mock.module("../tools/network/url-safety.js", () => ({
135
142
  }));
136
143
 
137
144
  import { executeBrowserNavigate } from "../tools/browser/browser-execution.js";
145
+ import { __resetPinnedTabsForTests } from "../tools/browser/pinned-tabs.js";
138
146
  import type { ToolContext } from "../tools/types.js";
139
147
 
140
148
  const ctx: ToolContext = {
@@ -212,6 +220,7 @@ function resetCdp() {
212
220
  cdpSendCalls = [];
213
221
  cdpDisposed = false;
214
222
  cdpSendHandler = defaultCdpHandler;
223
+ cdpSetSessionIdCalls = [];
215
224
  }
216
225
 
217
226
  describe("executeBrowserNavigate", () => {
@@ -223,6 +232,7 @@ describe("executeBrowserNavigate", () => {
223
232
  resolveResult = {};
224
233
  resetMockPage();
225
234
  resetCdp();
235
+ __resetPinnedTabsForTests();
226
236
  });
227
237
 
228
238
  // ── Input validation ───────────────────────────────────────────
@@ -664,6 +674,168 @@ describe("executeBrowserNavigate", () => {
664
674
  expect(cdpDisposed).toBe(true);
665
675
  });
666
676
 
677
+ // ── --new-tab flag (extension path only) ──────────────────────
678
+
679
+ test("extension path with new_tab: true opens a fresh tab and pins it before Page.navigate", async () => {
680
+ parseUrlResult = new URL("https://example.com/page");
681
+ mockExtensionAvailable = true;
682
+
683
+ cdpSendHandler = (method, params) => {
684
+ if (method === "Vellum.createTab") return { tabId: "999" };
685
+ return defaultCdpHandler(method, params);
686
+ };
687
+
688
+ const result = await executeBrowserNavigate(
689
+ { url: "https://example.com/page", new_tab: true },
690
+ { ...ctx },
691
+ );
692
+
693
+ expect(result.isError).toBe(false);
694
+
695
+ // Vellum.createTab fired and fired BEFORE Page.navigate.
696
+ const createIdx = cdpSendCalls.findIndex(
697
+ (c) => c.method === "Vellum.createTab",
698
+ );
699
+ const navIdx = cdpSendCalls.findIndex((c) => c.method === "Page.navigate");
700
+ expect(createIdx).toBeGreaterThanOrEqual(0);
701
+ expect(navIdx).toBeGreaterThanOrEqual(0);
702
+ expect(createIdx).toBeLessThan(navIdx);
703
+
704
+ // setCdpSessionId was invoked with the returned tabId so the
705
+ // follow-on commands on this client route to the new tab.
706
+ expect(cdpSetSessionIdCalls).toContain("999");
707
+ });
708
+
709
+ test("new_tab: true on extension path with createTab failure aborts with a clear error", async () => {
710
+ parseUrlResult = new URL("https://example.com/page");
711
+ mockExtensionAvailable = true;
712
+
713
+ cdpSendHandler = (method, params) => {
714
+ if (method === "Vellum.createTab") {
715
+ throw new Error("createTab returned no tabId");
716
+ }
717
+ return defaultCdpHandler(method, params);
718
+ };
719
+
720
+ const result = await executeBrowserNavigate(
721
+ { url: "https://example.com/page", new_tab: true },
722
+ { ...ctx },
723
+ );
724
+
725
+ expect(result.isError).toBe(true);
726
+ expect(result.content).toContain("Failed to open a new tab");
727
+ // Page.navigate must NOT fire — that's exactly what --new-tab is
728
+ // supposed to prevent in the failure case (silent fallback to
729
+ // active-tab clobbering would defeat the purpose of the flag).
730
+ expect(cdpSendCalls.some((c) => c.method === "Page.navigate")).toBe(false);
731
+ // The createTab-failure path early-returns BEFORE the main
732
+ // try/finally that wraps the navigate flow, so the executor has to
733
+ // dispose the CDP client manually. Verifying here so future edits
734
+ // to that early-return don't silently regress the cleanup.
735
+ expect(cdpDisposed).toBe(true);
736
+ });
737
+
738
+ test("new_tab: true on extension path with no tabId in response clears live session and still continues", async () => {
739
+ // Defensive: dispatcher returns success but no tabId. The
740
+ // executor logs a warn, resets the live cdp session to undefined
741
+ // (so the follow-on Page.navigate routes to the active tab
742
+ // instead of any stale pin the cdp instance was constructed
743
+ // with), and proceeds. The navigate still runs (degraded
744
+ // behaviour but not a hard failure).
745
+ parseUrlResult = new URL("https://example.com/page");
746
+ mockExtensionAvailable = true;
747
+
748
+ cdpSendHandler = (method, params) => {
749
+ if (method === "Vellum.createTab") return {}; // no tabId
750
+ return defaultCdpHandler(method, params);
751
+ };
752
+
753
+ const result = await executeBrowserNavigate(
754
+ { url: "https://example.com/page", new_tab: true },
755
+ { ...ctx },
756
+ );
757
+
758
+ expect(result.isError).toBe(false);
759
+ // No new pin was set, BUT the live session was reset to undefined
760
+ // so the follow-on Page.navigate falls back to active-tab routing
761
+ // instead of any stale pin the cdp instance held at construction.
762
+ expect(cdpSetSessionIdCalls).toEqual([undefined]);
763
+ // Page.navigate still ran.
764
+ expect(cdpSendCalls.some((c) => c.method === "Page.navigate")).toBe(true);
765
+ });
766
+
767
+ test("new_tab: true with no tabId in response clears a pre-existing stale pin AND live session (regression)", async () => {
768
+ // Regression for the Codex round-2 findings (P2 + round-3 P1):
769
+ // when Vellum.createTab returns a malformed response with no
770
+ // tabId, the executor falls back to active-tab routing — but
771
+ // (a) the pin store still held the stale pin (round-2 P2 fix
772
+ // added clearPinnedTab), and (b) the LIVE cdp instance was
773
+ // already constructed with that stale cdpSessionId, so the
774
+ // follow-on Page.navigate would still route to the dead tab
775
+ // unless we reset the session on the cdp instance too (round-3
776
+ // P1 fix added cdp.setCdpSessionId(undefined)).
777
+ const { setPinnedTab, getPinnedTab } = await import(
778
+ "../tools/browser/pinned-tabs.js"
779
+ );
780
+ setPinnedTab(ctx.conversationId, "stale-pinned-tab-id");
781
+ expect(getPinnedTab(ctx.conversationId)).toBe("stale-pinned-tab-id");
782
+
783
+ parseUrlResult = new URL("https://example.com/page");
784
+ mockExtensionAvailable = true;
785
+
786
+ cdpSendHandler = (method, params) => {
787
+ if (method === "Vellum.createTab") return {}; // no tabId
788
+ return defaultCdpHandler(method, params);
789
+ };
790
+
791
+ const result = await executeBrowserNavigate(
792
+ { url: "https://example.com/page", new_tab: true },
793
+ { ...ctx },
794
+ );
795
+
796
+ expect(result.isError).toBe(false);
797
+ // (a) Pin store cleared.
798
+ expect(getPinnedTab(ctx.conversationId)).toBeUndefined();
799
+ // (b) Live cdp session reset (the fake records every
800
+ // setCdpSessionId arg; expect exactly one call with undefined).
801
+ expect(cdpSetSessionIdCalls).toEqual([undefined]);
802
+ });
803
+
804
+ test("new_tab: true on LOCAL path is a no-op (Playwright manages its own isolated browser)", async () => {
805
+ parseUrlResult = new URL("https://example.com/page");
806
+ mockExtensionAvailable = false; // local path
807
+
808
+ const result = await executeBrowserNavigate(
809
+ { url: "https://example.com/page", new_tab: true },
810
+ { ...ctx },
811
+ );
812
+
813
+ expect(result.isError).toBe(false);
814
+ // No Vellum.createTab was issued on the local path — the flag is
815
+ // silently ignored because Playwright opens its own browser and
816
+ // there's no user-tab to disturb.
817
+ expect(cdpSendCalls.some((c) => c.method === "Vellum.createTab")).toBe(
818
+ false,
819
+ );
820
+ expect(cdpSetSessionIdCalls).toEqual([]);
821
+ });
822
+
823
+ test("absence of new_tab leaves extension path untouched (no Vellum.createTab)", async () => {
824
+ parseUrlResult = new URL("https://example.com/page");
825
+ mockExtensionAvailable = true;
826
+
827
+ const result = await executeBrowserNavigate(
828
+ { url: "https://example.com/page" }, // no new_tab key at all
829
+ { ...ctx },
830
+ );
831
+
832
+ expect(result.isError).toBe(false);
833
+ expect(cdpSendCalls.some((c) => c.method === "Vellum.createTab")).toBe(
834
+ false,
835
+ );
836
+ expect(cdpSetSessionIdCalls).toEqual([]);
837
+ });
838
+
667
839
  // ── Defense-in-depth: post-navigation final URL check ─────────
668
840
 
669
841
  test("post-nav check blocks when final URL resolves to private target", async () => {
@@ -91,6 +91,10 @@ mock.module("../notifications/emit-signal.js", () => ({
91
91
  mock.module("../prompts/persona-resolver.js", () => ({
92
92
  GUARDIAN_PERSONA_TEMPLATE: "# User Profile\n",
93
93
  resolveGuardianPersona: () => "# User Profile\n",
94
+ // buildSystemPrompt now uses resolveUserSlug (for ctx) instead of
95
+ // resolvePersonaContext — give the mock a noop so the import
96
+ // doesn't fail.
97
+ resolveUserSlug: () => null,
94
98
  }));
95
99
 
96
100
  mock.module("../memory/conversation-title-service.js", () => ({
@@ -112,6 +112,10 @@ let mockGuardianPersona: string | null = null;
112
112
  mock.module("../prompts/persona-resolver.js", () => ({
113
113
  GUARDIAN_PERSONA_TEMPLATE,
114
114
  resolveGuardianPersona: () => mockGuardianPersona,
115
+ // buildSystemPrompt now uses resolveUserSlug (for ctx) instead of
116
+ // resolvePersonaContext — give the mock a noop so the import
117
+ // doesn't fail.
118
+ resolveUserSlug: () => null,
115
119
  }));
116
120
 
117
121
  // Mock conversation store
@@ -31,6 +31,12 @@ mock.module("../runtime/assistant-event-hub.js", () => ({
31
31
  _conversationId?: string,
32
32
  options?: unknown,
33
33
  ) => {
34
+ // `interaction_resolved` envelopes are emitted by the pending-interactions
35
+ // tracker for every resolution. They are orthogonal to the host-proxy
36
+ // wire messages these tests assert on, so swallow them here.
37
+ if ((msg as { type?: string } | null)?.type === "interaction_resolved") {
38
+ return;
39
+ }
34
40
  sentMessages.push(msg);
35
41
  sentMessageOptions.push(options);
36
42
  },
@@ -31,6 +31,13 @@ let mockClients: MockClient[] = [];
31
31
  mock.module("../runtime/assistant-event-hub.js", () => ({
32
32
  assistantEventHub: {
33
33
  publish: async (event: unknown, _options?: unknown) => {
34
+ // `interaction_resolved` envelopes are emitted by the
35
+ // pending-interactions tracker for every resolution. They are
36
+ // orthogonal to the host-browser wire messages these tests assert
37
+ // on, so swallow them here.
38
+ if ((event as { type?: string } | null)?.type === "interaction_resolved") {
39
+ return;
40
+ }
34
41
  publishedEvents.push(event);
35
42
  },
36
43
  getMostRecentClientByCapability: (cap: string) =>
@@ -41,6 +48,9 @@ mock.module("../runtime/assistant-event-hub.js", () => ({
41
48
  mockClients.find((c) => c.clientId === clientId)?.actorPrincipalId,
42
49
  },
43
50
  broadcastMessage: (msg: unknown) => {
51
+ if ((msg as { type?: string } | null)?.type === "interaction_resolved") {
52
+ return;
53
+ }
44
54
  publishedEvents.push(msg);
45
55
  },
46
56
  }));
@@ -10,7 +10,14 @@ type MockClient = {
10
10
  let mockClients: MockClient[] = [];
11
11
 
12
12
  mock.module("../runtime/assistant-event-hub.js", () => ({
13
- broadcastMessage: (msg: unknown) => sentMessages.push(msg),
13
+ broadcastMessage: (msg: unknown) => {
14
+ // Skip `interaction_resolved` envelopes — pending-interactions emits one
15
+ // on every resolve and these tests assert on host-proxy wire messages.
16
+ if ((msg as { type?: string } | null)?.type === "interaction_resolved") {
17
+ return;
18
+ }
19
+ sentMessages.push(msg);
20
+ },
14
21
  assistantEventHub: {
15
22
  getMostRecentClientByCapability: (cap: string) =>
16
23
  cap === "host_cu" && mockHasClient ? { id: "mock-client" } : null,
@@ -12,7 +12,14 @@ interface MockClient {
12
12
  let mockClients: MockClient[] = [];
13
13
 
14
14
  mock.module("../runtime/assistant-event-hub.js", () => ({
15
- broadcastMessage: (msg: unknown) => sentMessages.push(msg),
15
+ broadcastMessage: (msg: unknown) => {
16
+ // Skip `interaction_resolved` envelopes — pending-interactions emits one
17
+ // on every resolve and these tests assert on host-proxy wire messages.
18
+ if ((msg as { type?: string } | null)?.type === "interaction_resolved") {
19
+ return;
20
+ }
21
+ sentMessages.push(msg);
22
+ },
16
23
  assistantEventHub: {
17
24
  getMostRecentClientByCapability: (cap: string) => {
18
25
  if (mockClients.length > 0) {
@@ -264,7 +264,7 @@ describe("host_bash — baseline: no sandbox isolation", () => {
264
264
  // These tests lock that boundary so any accidental addition is caught.
265
265
 
266
266
  describe("host_bash — regression: no proxied-mode additions", () => {
267
- const definition = hostShellTool.getDefinition();
267
+ const definition = hostShellTool;
268
268
  const schemaProps = (definition.input_schema as Record<string, unknown>)
269
269
  .properties as Record<string, unknown>;
270
270