@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
@@ -11,6 +11,7 @@ import { getConfig } from "../../../config/loader.js";
11
11
  import { HostBrowserProxy } from "../../../daemon/host-browser-proxy.js";
12
12
  import { getLogger } from "../../../util/logger.js";
13
13
  import type { ToolContext } from "../../types.js";
14
+ import { getPinnedTab } from "../pinned-tabs.js";
14
15
  import { createCdpInspectClient } from "./cdp-inspect-client.js";
15
16
  import { CdpError } from "./errors.js";
16
17
  import { createExtensionCdpClient } from "./extension-cdp-client.js";
@@ -22,6 +23,7 @@ import type {
22
23
  CdpClient,
23
24
  CdpClientKind,
24
25
  ScopedCdpClient,
26
+ TabInfo,
25
27
  } from "./types.js";
26
28
 
27
29
  const log = getLogger("cdp-factory");
@@ -222,7 +224,12 @@ export function buildPinnedCandidateList(
222
224
  const client = createExtensionCdpClient(
223
225
  hostBrowserProxy,
224
226
  conversationId,
225
- undefined,
227
+ // Pass clientId to scope the pin lookup to this specific
228
+ // extension install. When a targetClientId is provided
229
+ // the pin is fetched for that client; otherwise falls back
230
+ // to the __default__ slot which is set by older callers
231
+ // without clientId awareness.
232
+ getPinnedTab(conversationId, targetClientId),
226
233
  sourceActorPrincipalId,
227
234
  targetClientId,
228
235
  );
@@ -330,10 +337,13 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
330
337
  kind: "extension",
331
338
  reason: `target_client_id override: ${targetClientId}`,
332
339
  create() {
340
+ // Explicit target_client_id override → look up the pin scoped
341
+ // to this specific client. This is safe because targetClientId
342
+ // and the pin were both recorded for the same extension install.
333
343
  const client = createExtensionCdpClient(
334
344
  hostBrowserProxy,
335
345
  conversationId,
336
- undefined,
346
+ getPinnedTab(conversationId, targetClientId),
337
347
  sourceActorPrincipalId,
338
348
  targetClientId,
339
349
  );
@@ -358,7 +368,11 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
358
368
  const client = createExtensionCdpClient(
359
369
  hostBrowserProxy,
360
370
  conversationId,
361
- undefined,
371
+ // targetClientId is always undefined here — this code path
372
+ // only runs when targetClientId is null (the early-return
373
+ // above handles the non-null case). Use the no-clientId
374
+ // lookup which returns the first pin for auto-routing.
375
+ getPinnedTab(conversationId),
362
376
  sourceActorPrincipalId,
363
377
  targetClientId,
364
378
  );
@@ -484,6 +498,16 @@ export function buildChainedClient(
484
498
  kind: CdpClientKind;
485
499
  manager: BrowserSessionManager;
486
500
  sessionId: string;
501
+ /**
502
+ * Reference to the underlying CdpClient (returned from
503
+ * `candidate.create()`). Held so callers can reach methods that
504
+ * aren't routed through `manager.send()` — specifically
505
+ * {@link CdpClient.setCdpSessionId}, which re-targets follow-on
506
+ * CDP commands at a specific tab/target. Without this we'd have
507
+ * no way to call setCdpSessionId on the materialised client
508
+ * since `backend` only exposes the send/dispose surface.
509
+ */
510
+ client: CdpClient;
487
511
  } | null = null;
488
512
 
489
513
  /** Set to true after the first successful CDP command. */
@@ -491,6 +515,17 @@ export function buildChainedClient(
491
515
 
492
516
  let disposed = false;
493
517
 
518
+ /**
519
+ * setCdpSessionId may be called BEFORE the first send (i.e. before
520
+ * `active` is populated). When that happens we stash the value
521
+ * here and apply it to `active.client` as soon as a backend becomes
522
+ * sticky. In the current --new-tab flow this can't trigger (the
523
+ * createTab send establishes sticky first, then setCdpSessionId is
524
+ * called), but supporting the pre-sticky case keeps the contract
525
+ * simple for future callers.
526
+ */
527
+ let pendingCdpSessionId: string | undefined;
528
+
494
529
  /**
495
530
  * Track all materialised backends so dispose() can tear them all
496
531
  * down, even ones that were tried and failed before the sticky
@@ -545,6 +580,16 @@ export function buildChainedClient(
545
580
  active = established;
546
581
  sticky = true;
547
582
  currentKind = established.kind;
583
+ // Flush any pre-sticky setCdpSessionId call onto the
584
+ // freshly-materialised client. See pendingCdpSessionId
585
+ // comment above for why this exists.
586
+ if (
587
+ pendingCdpSessionId !== undefined &&
588
+ established.client.setCdpSessionId
589
+ ) {
590
+ established.client.setCdpSessionId(pendingCdpSessionId);
591
+ pendingCdpSessionId = undefined;
592
+ }
548
593
  },
549
594
  () => disposed,
550
595
  conversationId,
@@ -561,6 +606,115 @@ export function buildChainedClient(
561
606
  materialisedManagers.length = 0;
562
607
  active = null;
563
608
  },
609
+
610
+ /**
611
+ * Re-target follow-on CDP commands at a specific tab/target by
612
+ * updating the underlying client's `cdpSessionId`. The navigate
613
+ * executor calls this after `Vellum.createTab` returns so the
614
+ * subsequent `Page.navigate` (and every command on this
615
+ * conversation thereafter) routes to the new tab instead of the
616
+ * currently-active tab.
617
+ *
618
+ * Behaviour by state:
619
+ * - Sticky backend already established → forward to
620
+ * `active.client.setCdpSessionId` if the underlying client
621
+ * implements it (extension does; local/cdp-inspect don't and
622
+ * the optional chain no-ops).
623
+ * - No sticky backend yet → stash the value; it gets applied
624
+ * in the `onEstablished` callback when the first send walks
625
+ * the candidate list.
626
+ */
627
+ setCdpSessionId(cdpSessionId: string | undefined): void {
628
+ if (active?.client.setCdpSessionId) {
629
+ active.client.setCdpSessionId(cdpSessionId);
630
+ return;
631
+ }
632
+ pendingCdpSessionId = cdpSessionId;
633
+ },
634
+
635
+ async listTabs(): Promise<TabInfo[]> {
636
+ if (sticky && active?.client.listTabs) {
637
+ return active.client.listTabs();
638
+ }
639
+ if (sticky) {
640
+ throw new CdpError(
641
+ "transport_error",
642
+ "listTabs is not supported by the current backend (extension backend required)",
643
+ );
644
+ }
645
+ // Fresh client: route through the failover walk so the extension
646
+ // backend is selected automatically. The Vellum.listTabs pseudo-method
647
+ // is handled by the extension dispatcher before chrome.debugger.sendCommand.
648
+ const result = await scopedClient.send<{ tabs?: TabInfo[] }>("Vellum.listTabs", {});
649
+ if (!active?.client.listTabs) {
650
+ // Backend became sticky but isn't an extension client — not supported.
651
+ throw new CdpError(
652
+ "transport_error",
653
+ "listTabs is not supported by the current backend (extension backend required)",
654
+ );
655
+ }
656
+ return Array.isArray(result?.tabs) ? result.tabs : [];
657
+ },
658
+
659
+ async selectTab(tabId: number): Promise<{
660
+ tabId?: number;
661
+ windowId?: number;
662
+ url?: string;
663
+ title?: string;
664
+ clientId?: string;
665
+ }> {
666
+ if (sticky && active?.client.selectTab) {
667
+ return active.client.selectTab(tabId);
668
+ }
669
+ if (sticky) {
670
+ throw new CdpError(
671
+ "transport_error",
672
+ "selectTab is not supported by the current backend (extension backend required)",
673
+ );
674
+ }
675
+ const result = await scopedClient.send<{
676
+ tabId?: number;
677
+ windowId?: number;
678
+ url?: string;
679
+ title?: string;
680
+ clientId?: string;
681
+ }>("Vellum.selectTab", { tabId });
682
+ if (!active?.client.selectTab) {
683
+ throw new CdpError(
684
+ "transport_error",
685
+ "selectTab is not supported by the current backend (extension backend required)",
686
+ );
687
+ }
688
+ return result;
689
+ },
690
+
691
+ async closeTab(tabId: number): Promise<{
692
+ closed: boolean;
693
+ tabId: number;
694
+ clientId?: string;
695
+ }> {
696
+ if (sticky && active?.client.closeTab) {
697
+ return active.client.closeTab(tabId);
698
+ }
699
+ if (sticky) {
700
+ throw new CdpError(
701
+ "transport_error",
702
+ "closeTab is not supported by the current backend (extension backend required)",
703
+ );
704
+ }
705
+ const result = await scopedClient.send<{
706
+ closed: boolean;
707
+ tabId: number;
708
+ clientId?: string;
709
+ }>("Vellum.closeTab", { tabId });
710
+ if (!active?.client.closeTab) {
711
+ throw new CdpError(
712
+ "transport_error",
713
+ "closeTab is not supported by the current backend (extension backend required)",
714
+ );
715
+ }
716
+ return result;
717
+ },
564
718
  };
565
719
 
566
720
  return scopedClient;
@@ -591,6 +745,7 @@ async function sendWithFailover<T>(
591
745
  kind: CdpClientKind;
592
746
  manager: BrowserSessionManager;
593
747
  sessionId: string;
748
+ client: CdpClient;
594
749
  }) => void,
595
750
  isDisposed: () => boolean,
596
751
  conversationId: string,
@@ -619,9 +774,16 @@ async function sendWithFailover<T>(
619
774
  );
620
775
 
621
776
  let backend: BrowserBackend;
777
+ let underlyingClient: CdpClient;
622
778
  try {
623
779
  const created = candidate.create();
624
780
  backend = created.backend;
781
+ // Hold the underlying CdpClient so we can forward
782
+ // setCdpSessionId calls to it after the backend becomes
783
+ // sticky. Without this the scopedClient's setCdpSessionId
784
+ // method has no way to reach the materialised client (the
785
+ // BrowserSessionManager only exposes a send/dispose surface).
786
+ underlyingClient = created.client;
625
787
  } catch (err) {
626
788
  // Backend construction failed -- treat as transport error and
627
789
  // try the next candidate.
@@ -810,7 +972,12 @@ async function sendWithFailover<T>(
810
972
  { conversationId, candidateKind: candidate.kind, method },
811
973
  "CDP factory: candidate succeeded, backend is now sticky",
812
974
  );
813
- onEstablished({ kind: candidate.kind, manager, sessionId: session.id });
975
+ onEstablished({
976
+ kind: candidate.kind,
977
+ manager,
978
+ sessionId: session.id,
979
+ client: underlyingClient,
980
+ });
814
981
  return envelope.result as T;
815
982
  }
816
983
 
@@ -156,6 +156,27 @@ export class LocalCdpClient implements ScopedCdpClient {
156
156
  }
157
157
  }
158
158
 
159
+ /**
160
+ * LocalCdpClient doesn't support re-targeting to a specific tab/session.
161
+ * The local Chromium instance manages all tabs globally, not per-client.
162
+ * This method is a no-op to satisfy the {@link ScopedCdpClient} interface.
163
+ */
164
+ setCdpSessionId(): void {
165
+ // no-op
166
+ }
167
+
168
+ async listTabs(): Promise<never> {
169
+ throw new CdpError("transport_error", "listTabs is not supported by the local backend (extension backend required)");
170
+ }
171
+
172
+ async selectTab(_tabId: number): Promise<never> {
173
+ throw new CdpError("transport_error", "selectTab is not supported by the local backend (extension backend required)");
174
+ }
175
+
176
+ async closeTab(_tabId: number): Promise<never> {
177
+ throw new CdpError("transport_error", "closeTab is not supported by the local backend (extension backend required)");
178
+ }
179
+
159
180
  dispose(): void {
160
181
  if (this.disposed) return;
161
182
  this.disposed = true;
@@ -10,6 +10,16 @@
10
10
 
11
11
  import type { BrowserBackend } from "../../../browser-session/types.js";
12
12
 
13
+ /** Shape of a single Chrome tab as returned by Vellum.listTabs. */
14
+ export interface TabInfo {
15
+ tabId?: number;
16
+ windowId?: number;
17
+ url?: string;
18
+ title?: string;
19
+ active: boolean;
20
+ pinned: boolean;
21
+ }
22
+
13
23
  export interface CdpClient {
14
24
  /**
15
25
  * Send a CDP command and await the result. `method` must be a
@@ -34,6 +44,52 @@ export interface CdpClient {
34
44
  * is allowed but should surface as an error.
35
45
  */
36
46
  dispose(): void;
47
+
48
+ /**
49
+ * Update the `cdpSessionId` used on subsequent {@link CdpClient.send}
50
+ * calls. Backends that don't multiplex commands across multiple
51
+ * targets (local Playwright, cdp-inspect) may implement this as a
52
+ * no-op. The extension backend uses this after opening a new tab
53
+ * (via the `Vellum.createTab` pseudo-CDP method) to route
54
+ * follow-on commands to the freshly-created tab instead of the
55
+ * currently-active one.
56
+ *
57
+ * Pass `undefined` to clear an existing pinned session and revert
58
+ * to default routing (i.e. dispatcher resolves the active tab).
59
+ * Used in the `Vellum.createTab` no-tabId fallback path to avoid
60
+ * sending follow-on commands to a stale/dead tab when the previous
61
+ * pin is no longer valid.
62
+ *
63
+ * Optional — callers should null-check before invoking.
64
+ */
65
+ setCdpSessionId?(cdpSessionId: string | undefined): void;
66
+
67
+ /**
68
+ * List all open browser tabs. Extension backend only — returns
69
+ * `{ tabId, windowId, url, title, active, pinned }[]`.
70
+ * Optional — callers must null-check before invoking.
71
+ */
72
+ listTabs?(): Promise<TabInfo[]>;
73
+
74
+ /**
75
+ * Select (activate) an existing tab. Extension backend only. Optional.
76
+ */
77
+ selectTab?(tabId: number): Promise<{
78
+ tabId?: number;
79
+ windowId?: number;
80
+ url?: string;
81
+ title?: string;
82
+ clientId?: string;
83
+ }>;
84
+
85
+ /**
86
+ * Close a browser tab by ID. Extension backend only. Optional.
87
+ */
88
+ closeTab?(tabId: number): Promise<{
89
+ closed: boolean;
90
+ tabId: number;
91
+ clientId?: string;
92
+ }>;
37
93
  }
38
94
 
39
95
  /**
@@ -97,6 +153,51 @@ export interface ScopedCdpClient extends CdpClient {
97
153
  readonly kind: CdpClientKind;
98
154
  /** Stable conversation id this client is bound to. */
99
155
  readonly conversationId: string;
156
+ /**
157
+ * Re-target follow-on CDP commands at a specific tab/target. Calling
158
+ * this updates the underlying client's `cdpSessionId`. This is used by
159
+ * the navigator executor after `Vellum.createTab` returns to ensure the
160
+ * subsequent `Page.navigate` and all follow-on commands on this
161
+ * conversation route to the newly-created tab instead of the
162
+ * previously-active tab.
163
+ *
164
+ * Pass `undefined` to clear an existing pinned session on the chained
165
+ * client and on the underlying client (if it supports the method).
166
+ * Used in the `Vellum.createTab` no-tabId fallback path.
167
+ *
168
+ * If the underlying client doesn't implement this method (e.g., local
169
+ * or cdp-inspect clients), the call is silently ignored via optional
170
+ * chaining.
171
+ */
172
+ setCdpSessionId(cdpSessionId: string | undefined): void;
173
+
174
+ /**
175
+ * List all open browser tabs. Throws with code "transport_error" if
176
+ * the current backend does not support tab listing.
177
+ */
178
+ listTabs(): Promise<TabInfo[]>;
179
+
180
+ /**
181
+ * Select (activate) an existing tab. Throws if backend doesn't support it.
182
+ */
183
+ selectTab(tabId: number): Promise<{
184
+ tabId?: number;
185
+ windowId?: number;
186
+ url?: string;
187
+ title?: string;
188
+ clientId?: string;
189
+ }>;
190
+
191
+ /**
192
+ * Close a browser tab by ID. Throws if backend doesn't support it.
193
+ * The optional `clientId` identifies which extension client actually
194
+ * closed the tab — used to scope pin cleanup in multi-client setups.
195
+ */
196
+ closeTab(tabId: number): Promise<{
197
+ closed: boolean;
198
+ tabId: number;
199
+ clientId?: string;
200
+ }>;
100
201
  }
101
202
 
102
203
  /**
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Per-conversation, per-client pinned-tab store for the Chrome extension
3
+ * browser backend.
4
+ *
5
+ * Pin store key is (conversationId, clientId) → tabId. This scopes pins
6
+ * to a specific extension instance so that closing a tab on clientA does
7
+ * not clear clientB's pin to a tab with the same numeric ID on a
8
+ * different Chrome instance (issue #31361).
9
+ *
10
+ * Persistence is process-lifetime (in-memory only). The daemon is a
11
+ * single process and all CLI invocations land in it via IPC, so a
12
+ * module-level Map is sufficient. A pin is cleared when the extension
13
+ * reports the underlying CDP target as invalidated via
14
+ * `host_browser_session_invalidated`.
15
+ */
16
+
17
+ import { log } from "../../cli/logger.js";
18
+
19
+ const pinnedTabs = new Map<string, Map<string, string>>();
20
+
21
+ /**
22
+ * Record a tabId as the pinned tab for the given conversation and optional
23
+ * client. The tabId is stored as a string because it travels on the wire
24
+ * as `cdpSessionId` (a string-typed field on the host-browser envelope).
25
+ */
26
+ export function setPinnedTab(
27
+ conversationId: string,
28
+ tabId: string,
29
+ clientId?: string,
30
+ ): void {
31
+ if (!conversationId || !tabId) return;
32
+ const key = clientId ?? "__default__";
33
+ let inner = pinnedTabs.get(conversationId);
34
+ if (!inner) {
35
+ inner = new Map();
36
+ pinnedTabs.set(conversationId, inner);
37
+ }
38
+ inner.set(key, tabId);
39
+ log.debug(
40
+ { conversationId, clientId, tabId },
41
+ "Pinned extension tab for conversation",
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Return the tabId pinned to the given conversation and optional client,
47
+ * or undefined if no pin exists.
48
+ *
49
+ * When `clientId` is provided, returns the pin for that client first,
50
+ * falling back to the `__default__` slot. When no `clientId` is given,
51
+ * returns the first entry (best-guess for auto-routing).
52
+ */
53
+ export function getPinnedTab(
54
+ conversationId: string,
55
+ clientId?: string,
56
+ ): string | undefined {
57
+ if (!conversationId) return undefined;
58
+ const inner = pinnedTabs.get(conversationId);
59
+ if (!inner) return undefined;
60
+ if (clientId !== undefined) {
61
+ return inner.get(clientId) ?? inner.get("__default__");
62
+ }
63
+ // No clientId: return the first entry (best-guess for auto-routing)
64
+ const first = inner.values().next();
65
+ return first.done ? undefined : first.value;
66
+ }
67
+
68
+ /**
69
+ * Clear the pin for the given conversation and optional client. Idempotent
70
+ * — clearing a non-existent pin is a no-op.
71
+ *
72
+ * When `clientId` is provided, only clears that client's slot. When
73
+ * omitted, clears all client slots for the conversation.
74
+ */
75
+ export function clearPinnedTab(
76
+ conversationId: string,
77
+ clientId?: string,
78
+ ): void {
79
+ if (!conversationId) return;
80
+ const inner = pinnedTabs.get(conversationId);
81
+ if (!inner) return;
82
+ if (clientId !== undefined) {
83
+ if (inner.delete(clientId)) {
84
+ log.debug({ conversationId, clientId }, "Cleared pinned extension tab");
85
+ }
86
+ if (inner.size === 0) pinnedTabs.delete(conversationId);
87
+ } else {
88
+ // Clear all clients for this conversation
89
+ if (pinnedTabs.delete(conversationId)) {
90
+ log.debug(
91
+ { conversationId },
92
+ "Cleared all pinned extension tabs for conversation",
93
+ );
94
+ }
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Clear every pin pointing at a given tabId across all conversations.
100
+ * Used when the extension reports a target as invalidated (tab closed,
101
+ * crashed, navigated away from a debuggable URL, etc.) so we don't
102
+ * keep routing to a dead tab.
103
+ *
104
+ * When `clientId` is provided, only clears the slot for that client.
105
+ * When omitted, clears all entries pointing at this tabId (backward compat).
106
+ *
107
+ * Returns the number of slots cleared.
108
+ */
109
+ export function clearPinnedTabByTabId(tabId: string, clientId?: string): number {
110
+ if (!tabId) return 0;
111
+ let cleared = 0;
112
+ for (const [conversationId, inner] of pinnedTabs.entries()) {
113
+ if (clientId !== undefined) {
114
+ // Only clear the specific client's slot if its tabId matches
115
+ if (inner.get(clientId) === tabId) {
116
+ inner.delete(clientId);
117
+ cleared++;
118
+ log.debug(
119
+ { conversationId, clientId, tabId },
120
+ "Cleared pinned extension tab due to invalidation",
121
+ );
122
+ }
123
+ } else {
124
+ // Backward compat: clear all entries pointing at this tabId
125
+ for (const [cid, pinned] of inner.entries()) {
126
+ if (pinned === tabId) {
127
+ inner.delete(cid);
128
+ cleared++;
129
+ log.debug(
130
+ { conversationId, clientId: cid, tabId },
131
+ "Cleared pinned extension tab due to invalidation",
132
+ );
133
+ }
134
+ }
135
+ }
136
+ if (inner.size === 0) pinnedTabs.delete(conversationId);
137
+ }
138
+ return cleared;
139
+ }
140
+
141
+ /**
142
+ * Reset the entire pin store. Test-only.
143
+ */
144
+ export function __resetPinnedTabsForTests(): void {
145
+ pinnedTabs.clear();
146
+ }