@vellumai/assistant 0.8.4 → 0.8.6

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 (802) hide show
  1. package/AGENTS.md +33 -1
  2. package/ARCHITECTURE.md +3 -3
  3. package/bunfig.toml +6 -1
  4. package/docs/browser-use-architecture-phase2.md +1 -1
  5. package/docs/credential-execution-service.md +6 -6
  6. package/docs/plugins.md +4 -3
  7. package/knip.json +2 -1
  8. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
  9. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
  10. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
  11. package/openapi.yaml +2748 -216
  12. package/package.json +1 -1
  13. package/src/__tests__/actor-token-service.test.ts +3 -2
  14. package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
  15. package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
  16. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
  17. package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
  18. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  19. package/src/__tests__/annotate-risk-options.test.ts +1 -0
  20. package/src/__tests__/anthropic-provider.test.ts +34 -37
  21. package/src/__tests__/approval-cascade.test.ts +1 -0
  22. package/src/__tests__/approval-routes-http.test.ts +9 -13
  23. package/src/__tests__/assert-not-live-db.ts +79 -0
  24. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  25. package/src/__tests__/assistant-feature-flags-integration.test.ts +12 -28
  26. package/src/__tests__/audit-log-rotation.test.ts +72 -18
  27. package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
  28. package/src/__tests__/background-workers-disk-pressure.test.ts +8 -11
  29. package/src/__tests__/browser-skill-endstate.test.ts +3 -3
  30. package/src/__tests__/btw-routes.test.ts +5 -5
  31. package/src/__tests__/call-controller.test.ts +3 -3
  32. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  33. package/src/__tests__/channel-approval-routes.test.ts +3 -2
  34. package/src/__tests__/channel-guardian.test.ts +6 -5
  35. package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
  36. package/src/__tests__/channel-reply-delivery.test.ts +35 -0
  37. package/src/__tests__/channel-retry-sweep.test.ts +320 -3
  38. package/src/__tests__/checker.test.ts +18 -27
  39. package/src/__tests__/compaction-events.test.ts +2 -0
  40. package/src/__tests__/compaction-trail-store.test.ts +264 -0
  41. package/src/__tests__/compactor-call-site-logging.test.ts +215 -0
  42. package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
  43. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -16
  44. package/src/__tests__/computer-use-tools.test.ts +14 -18
  45. package/src/__tests__/config-loader-backfill.test.ts +13 -28
  46. package/src/__tests__/config-loader-corrupt.test.ts +5 -5
  47. package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
  48. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
  49. package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
  50. package/src/__tests__/config-schema.test.ts +10 -10
  51. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  52. package/src/__tests__/connection-model-compat.test.ts +83 -0
  53. package/src/__tests__/contacts-tools.test.ts +3 -2
  54. package/src/__tests__/context-token-estimator.test.ts +22 -0
  55. package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
  56. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -1
  57. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
  58. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -1
  59. package/src/__tests__/conversation-agent-loop-overflow.test.ts +231 -2
  60. package/src/__tests__/conversation-agent-loop.test.ts +581 -54
  61. package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
  62. package/src/__tests__/conversation-app-control-instantiation.test.ts +31 -24
  63. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
  64. package/src/__tests__/conversation-attention-store.test.ts +101 -0
  65. package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
  66. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  67. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
  68. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  69. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  70. package/src/__tests__/conversation-error.test.ts +61 -0
  71. package/src/__tests__/conversation-fork-crud.test.ts +239 -15
  72. package/src/__tests__/conversation-fork-route.test.ts +3 -2
  73. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  74. package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
  75. package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
  76. package/src/__tests__/conversation-lifecycle.test.ts +53 -11
  77. package/src/__tests__/conversation-list-source.test.ts +3 -2
  78. package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
  79. package/src/__tests__/{conversation-load-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +14 -13
  80. package/src/__tests__/conversation-pairing.test.ts +53 -0
  81. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
  82. package/src/__tests__/conversation-process-callsite.test.ts +1 -0
  83. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  84. package/src/__tests__/conversation-queue.test.ts +333 -291
  85. package/src/__tests__/conversation-routes-disk-view.test.ts +112 -18
  86. package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
  87. package/src/__tests__/conversation-routes-slash-commands.test.ts +68 -2
  88. package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
  89. package/src/__tests__/conversation-skill-tools.test.ts +40 -147
  90. package/src/__tests__/conversation-slash-queue.test.ts +84 -32
  91. package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
  92. package/src/__tests__/conversation-speed-override.test.ts +1 -0
  93. package/src/__tests__/conversation-store.test.ts +1 -1
  94. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
  95. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
  96. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
  97. package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
  98. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
  99. package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
  100. package/src/__tests__/conversation-sync-tags.test.ts +218 -35
  101. package/src/__tests__/conversation-title-service.test.ts +1 -0
  102. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
  103. package/src/__tests__/conversation-usage.test.ts +1 -0
  104. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
  105. package/src/__tests__/conversation-workspace-injection.test.ts +6 -1
  106. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -1
  107. package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
  108. package/src/__tests__/credential-broker-server-use.test.ts +5 -5
  109. package/src/__tests__/credential-execution-client.test.ts +72 -1
  110. package/src/__tests__/credential-execution-feature-gates.test.ts +19 -19
  111. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  112. package/src/__tests__/credential-health-service.test.ts +252 -3
  113. package/src/__tests__/credential-security-invariants.test.ts +6 -5
  114. package/src/__tests__/credential-vault-unit.test.ts +21 -21
  115. package/src/__tests__/credential-vault.test.ts +5 -5
  116. package/src/__tests__/cross-provider-web-search.test.ts +56 -2
  117. package/src/__tests__/db-connection-isolation.test.ts +7 -6
  118. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
  119. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
  120. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
  121. package/src/__tests__/db-test-helpers.ts +58 -0
  122. package/src/__tests__/disk-pressure-guard.test.ts +58 -41
  123. package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
  124. package/src/__tests__/disk-pressure-routes.test.ts +0 -33
  125. package/src/__tests__/disk-pressure-tools.test.ts +0 -4
  126. package/src/__tests__/dm-persistence.test.ts +26 -40
  127. package/src/__tests__/document-create-dedupe.test.ts +189 -0
  128. package/src/__tests__/document-find-replace.test.ts +3 -2
  129. package/src/__tests__/document-tool-security.test.ts +81 -2
  130. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  131. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
  132. package/src/__tests__/email-html-renderer.test.ts +12 -0
  133. package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
  134. package/src/__tests__/encrypted-store.test.ts +11 -9
  135. package/src/__tests__/feature-flag-test-helpers.ts +53 -0
  136. package/src/__tests__/filing-service.test.ts +1 -0
  137. package/src/__tests__/first-greeting.test.ts +62 -12
  138. package/src/__tests__/gateway-flag-listener.test.ts +236 -0
  139. package/src/__tests__/gemini-provider.test.ts +104 -0
  140. package/src/__tests__/guardian-action-sweep.test.ts +3 -2
  141. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  142. package/src/__tests__/guardian-outbound-http.test.ts +10 -7
  143. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
  144. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -1
  145. package/src/__tests__/heartbeat-disk-pressure.test.ts +5 -0
  146. package/src/__tests__/heartbeat-service.test.ts +5 -0
  147. package/src/__tests__/helpers/mock-logger.ts +26 -0
  148. package/src/__tests__/host-bash-routes.test.ts +1 -0
  149. package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
  150. package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
  151. package/src/__tests__/host-shell-tool.test.ts +6 -5
  152. package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
  153. package/src/__tests__/http-conversation-lineage.test.ts +3 -2
  154. package/src/__tests__/http-user-message-parity.test.ts +29 -7
  155. package/src/__tests__/identity-intro-cache.test.ts +133 -22
  156. package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
  157. package/src/__tests__/inference-profile-reaper.test.ts +3 -2
  158. package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
  159. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  160. package/src/__tests__/injector-disk-pressure.test.ts +3 -17
  161. package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
  162. package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
  163. package/src/__tests__/list-messages-tool-merge.test.ts +70 -11
  164. package/src/__tests__/llm-context-normalization.test.ts +42 -0
  165. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  166. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  167. package/src/__tests__/llm-resolver.test.ts +408 -9
  168. package/src/__tests__/llm-schema.test.ts +1 -1
  169. package/src/__tests__/llm-usage-store.test.ts +66 -0
  170. package/src/__tests__/logger.test.ts +89 -0
  171. package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
  172. package/src/__tests__/mcp-abort-signal.test.ts +16 -2
  173. package/src/__tests__/mcp-client-auth.test.ts +14 -0
  174. package/src/__tests__/media-generate-image.test.ts +31 -0
  175. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  176. package/src/__tests__/messaging-send-tool.test.ts +1 -0
  177. package/src/__tests__/migration-import-from-url.test.ts +3 -3
  178. package/src/__tests__/mock-gateway-ipc.ts +18 -2
  179. package/src/__tests__/model-intents.test.ts +4 -6
  180. package/src/__tests__/native-web-search.test.ts +30 -2
  181. package/src/__tests__/notification-deep-link.test.ts +62 -0
  182. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  183. package/src/__tests__/oauth-commands-routes.test.ts +37 -0
  184. package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
  185. package/src/__tests__/oauth-store.test.ts +3 -2
  186. package/src/__tests__/onboarding-template-contract.test.ts +4 -3
  187. package/src/__tests__/openai-provider.test.ts +54 -9
  188. package/src/__tests__/openai-responses-provider.test.ts +176 -14
  189. package/src/__tests__/openrouter-provider-only.test.ts +27 -5
  190. package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
  191. package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
  192. package/src/__tests__/persistence-pipeline.test.ts +139 -1
  193. package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
  194. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  195. package/src/__tests__/platform.test.ts +2 -2
  196. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  197. package/src/__tests__/plugin-bootstrap.test.ts +11 -13
  198. package/src/__tests__/plugin-tool-contribution.test.ts +50 -40
  199. package/src/__tests__/plugin-types.test.ts +3 -2
  200. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  201. package/src/__tests__/pricing.test.ts +12 -0
  202. package/src/__tests__/process-message-background-slack.test.ts +21 -16
  203. package/src/__tests__/process-message-display-content.test.ts +19 -22
  204. package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
  205. package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
  206. package/src/__tests__/provider-registry-ollama.test.ts +45 -22
  207. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  208. package/src/__tests__/recording-handler.test.ts +1 -0
  209. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
  210. package/src/__tests__/registry.test.ts +84 -84
  211. package/src/__tests__/relay-server.test.ts +10 -10
  212. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  213. package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
  214. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  215. package/src/__tests__/schedule-store.test.ts +16 -1
  216. package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
  217. package/src/__tests__/secret-ingress-http.test.ts +5 -1
  218. package/src/__tests__/secure-keys.test.ts +3 -3
  219. package/src/__tests__/send-endpoint-busy.test.ts +81 -42
  220. package/src/__tests__/server-history-render.test.ts +4 -1
  221. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  222. package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
  223. package/src/__tests__/skill-feature-flags.test.ts +16 -18
  224. package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
  225. package/src/__tests__/skill-projection-feature-flag.test.ts +48 -37
  226. package/src/__tests__/skill-projection.benchmark.test.ts +7 -13
  227. package/src/__tests__/skill-tool-factory.test.ts +97 -96
  228. package/src/__tests__/slack-channel-config.test.ts +3 -3
  229. package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
  230. package/src/__tests__/subagent-disposal.test.ts +27 -8
  231. package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
  232. package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
  233. package/src/__tests__/subagent-manager-notify.test.ts +20 -8
  234. package/src/__tests__/subagent-notify-parent.test.ts +6 -5
  235. package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
  236. package/src/__tests__/subagent-tools.test.ts +2 -1
  237. package/src/__tests__/suggestion-routes.test.ts +2 -0
  238. package/src/__tests__/sync-message-contract.test.ts +59 -0
  239. package/src/__tests__/system-prompt.test.ts +183 -131
  240. package/src/__tests__/terminal-tools.test.ts +1 -1
  241. package/src/__tests__/test-preload-verifier.ts +68 -0
  242. package/src/__tests__/test-preload.ts +32 -39
  243. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  244. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  245. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  246. package/src/__tests__/tool-executor-lifecycle-events.test.ts +35 -12
  247. package/src/__tests__/tool-executor.test.ts +64 -72
  248. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  249. package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
  250. package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
  251. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  252. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  253. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  254. package/src/__tests__/twilio-routes.test.ts +3 -2
  255. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  256. package/src/__tests__/usage-routes.test.ts +3 -0
  257. package/src/__tests__/validate-input.test.ts +381 -0
  258. package/src/__tests__/verification-control-plane-policy.test.ts +3 -2
  259. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
  260. package/src/__tests__/voice-session-bridge.test.ts +37 -28
  261. package/src/__tests__/workspace-git-service.test.ts +6 -5
  262. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  263. package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
  264. package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
  265. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  266. package/src/acp/prepare-agent-env.ts +78 -0
  267. package/src/acp/session-manager.ts +6 -7
  268. package/src/agent/loop.ts +88 -0
  269. package/src/api/README.md +127 -0
  270. package/src/api/constants/call-sites.ts +27 -0
  271. package/src/api/events/assistant-outbound-attachment.ts +51 -0
  272. package/src/api/events/assistant-text-delta.ts +32 -0
  273. package/src/api/events/assistant-turn-start.ts +33 -0
  274. package/src/api/events/document-comment-created.ts +48 -0
  275. package/src/api/events/document-comment-deleted.ts +24 -0
  276. package/src/api/events/document-comment-reopened.ts +25 -0
  277. package/src/api/events/document-comment-resolved.ts +27 -0
  278. package/src/api/events/generation-cancelled.ts +24 -0
  279. package/src/api/events/generation-handoff.ts +41 -0
  280. package/src/api/events/message-complete.ts +42 -0
  281. package/src/api/events/open-url.ts +30 -0
  282. package/src/api/events/relationship-state-updated.ts +25 -0
  283. package/src/api/events/tool-use-start.ts +32 -0
  284. package/src/api/index.ts +129 -0
  285. package/src/api/package.json +10 -0
  286. package/src/api/responses/llm-context-response.ts +39 -0
  287. package/src/api/responses/llm-request-log-entry.ts +93 -0
  288. package/src/api/responses/memory-recall-log.ts +65 -0
  289. package/src/api/responses/memory-v2-activation-log.ts +78 -0
  290. package/src/background-wake/background-wake-routes.test.ts +868 -0
  291. package/src/background-wake/platform-client.test.ts +308 -0
  292. package/src/background-wake/platform-client.ts +167 -0
  293. package/src/background-wake/publisher.ts +91 -0
  294. package/src/background-wake/runtime-registry.ts +24 -0
  295. package/src/background-wake/wake-intent-hooks.test.ts +282 -0
  296. package/src/calls/guardian-dispatch.ts +1 -0
  297. package/src/calls/voice-session-bridge.ts +4 -4
  298. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  299. package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
  300. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  301. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  302. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  303. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  304. package/src/cli/commands/__tests__/memory-v2.test.ts +1 -0
  305. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  306. package/src/cli/commands/__tests__/notifications.test.ts +184 -40
  307. package/src/cli/commands/browser.ts +247 -0
  308. package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
  309. package/src/cli/commands/channels/index.ts +229 -0
  310. package/src/cli/commands/domain.ts +91 -41
  311. package/src/cli/commands/inference.ts +93 -40
  312. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  313. package/src/cli/commands/memory-v2.ts +176 -1
  314. package/src/cli/commands/memory-v3-render.ts +491 -0
  315. package/src/cli/commands/memory-v3.ts +567 -0
  316. package/src/cli/commands/notifications.ts +365 -55
  317. package/src/cli/lib/open-browser.ts +7 -2
  318. package/src/cli/program.ts +4 -0
  319. package/src/config/assistant-feature-flags.ts +39 -46
  320. package/src/config/bundled-skills/document-editor/SKILL.md +16 -3
  321. package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
  322. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  323. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  324. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  325. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  326. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  327. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  328. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  329. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  330. package/src/config/bundled-skills/schedule/SKILL.md +1 -1
  331. package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
  332. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
  333. package/src/config/bundled-tool-registry.ts +2 -0
  334. package/src/config/call-site-defaults.ts +8 -7
  335. package/src/config/feature-flag-cache.ts +86 -0
  336. package/src/config/feature-flag-registry.json +33 -17
  337. package/src/config/llm-context-resolution.ts +10 -1
  338. package/src/config/llm-resolver.ts +121 -15
  339. package/src/config/loader.ts +4 -5
  340. package/src/config/schemas/__tests__/memory-v2.test.ts +228 -1
  341. package/src/config/schemas/call-site-catalog.ts +21 -7
  342. package/src/config/schemas/heartbeat.ts +1 -1
  343. package/src/config/schemas/llm.ts +102 -2
  344. package/src/config/schemas/memory-v2.ts +272 -0
  345. package/src/config/schemas/memory.ts +2 -1
  346. package/src/config/schemas/services.ts +6 -2
  347. package/src/config/seed-inference-profiles.ts +36 -16
  348. package/src/context/compactor.ts +52 -0
  349. package/src/context/token-estimator.ts +10 -5
  350. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  351. package/src/conversations/message-consolidation.ts +404 -0
  352. package/src/credential-execution/executable-discovery.ts +40 -0
  353. package/src/credential-execution/process-manager.ts +6 -2
  354. package/src/credential-health/credential-health-service.ts +125 -40
  355. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
  356. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
  357. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +2 -3
  358. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
  359. package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
  360. package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
  361. package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
  362. package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
  363. package/src/daemon/conversation-agent-loop-handlers.ts +390 -80
  364. package/src/daemon/conversation-agent-loop.ts +244 -90
  365. package/src/daemon/conversation-error.ts +64 -6
  366. package/src/daemon/conversation-lifecycle.ts +27 -22
  367. package/src/daemon/conversation-messaging.ts +84 -43
  368. package/src/daemon/conversation-process.ts +74 -37
  369. package/src/daemon/conversation-runtime-assembly.ts +38 -17
  370. package/src/daemon/conversation-skill-tools.ts +14 -30
  371. package/src/daemon/conversation-surfaces.ts +69 -34
  372. package/src/daemon/conversation-tool-setup.ts +77 -32
  373. package/src/daemon/conversation-usage.ts +2 -0
  374. package/src/daemon/conversation.ts +40 -75
  375. package/src/daemon/daemon-control.ts +1 -1
  376. package/src/daemon/daemon-skill-host.ts +9 -2
  377. package/src/daemon/disk-pressure-guard.ts +39 -29
  378. package/src/daemon/first-greeting.ts +31 -13
  379. package/src/daemon/handlers/config-model.test.ts +1 -0
  380. package/src/daemon/handlers/conversations.ts +11 -3
  381. package/src/daemon/handlers/shared.ts +6 -1
  382. package/src/daemon/host-browser-proxy.ts +5 -5
  383. package/src/daemon/host-cu-proxy.ts +4 -4
  384. package/src/daemon/host-file-proxy.ts +4 -4
  385. package/src/daemon/host-proxy-base.ts +4 -4
  386. package/src/daemon/host-transfer-proxy.ts +10 -10
  387. package/src/daemon/lifecycle.ts +29 -26
  388. package/src/daemon/mcp-reload-service.ts +1 -1
  389. package/src/daemon/meet-manifest-loader.ts +11 -24
  390. package/src/daemon/message-types/conversations.ts +22 -27
  391. package/src/daemon/message-types/document-comments.ts +8 -44
  392. package/src/daemon/message-types/home.ts +2 -14
  393. package/src/daemon/message-types/integrations.ts +2 -7
  394. package/src/daemon/message-types/messages.ts +25 -48
  395. package/src/daemon/message-types/subagents.ts +6 -0
  396. package/src/daemon/message-types/sync.ts +14 -0
  397. package/src/daemon/process-message.ts +9 -9
  398. package/src/daemon/providers-setup.ts +1 -1
  399. package/src/daemon/server.ts +16 -0
  400. package/src/daemon/shutdown-handlers.ts +24 -5
  401. package/src/daemon/switch-inference-profile-tool.ts +62 -0
  402. package/src/daemon/tool-setup-types.ts +7 -0
  403. package/src/daemon/wake-target-adapter.ts +10 -0
  404. package/src/documents/document-store.ts +38 -0
  405. package/src/export/__tests__/transcript-formatter.test.ts +1 -0
  406. package/src/heartbeat/__tests__/heartbeat-service.test.ts +30 -1
  407. package/src/heartbeat/heartbeat-service.ts +63 -0
  408. package/src/home/__tests__/feed-writer.test.ts +161 -0
  409. package/src/home/__tests__/post-connect-feed.test.ts +1 -0
  410. package/src/home/__tests__/suggested-prompts.test.ts +55 -59
  411. package/src/home/feed-writer.ts +146 -7
  412. package/src/home/home-greeting.ts +0 -9
  413. package/src/home/suggested-prompts.ts +27 -154
  414. package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
  415. package/src/ipc/gateway-client.test.ts +4 -1
  416. package/src/ipc/gateway-flag-listener.ts +123 -0
  417. package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
  418. package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
  419. package/src/ipc/skill-routes/memory.ts +4 -3
  420. package/src/ipc/skill-routes/registries.ts +35 -40
  421. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  422. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  423. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +242 -0
  424. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  425. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
  426. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
  427. package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
  428. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
  429. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
  430. package/src/memory/auto-analysis-enqueue.ts +5 -1
  431. package/src/memory/conversation-attention-store.ts +17 -3
  432. package/src/memory/conversation-crud.ts +423 -182
  433. package/src/memory/conversation-starters-cadence.ts +3 -1
  434. package/src/memory/conversation-title-service.ts +19 -3
  435. package/src/memory/db-async-query.ts +214 -0
  436. package/src/memory/db-connection.ts +29 -19
  437. package/src/memory/db-init.ts +14 -0
  438. package/src/memory/db-maintenance.ts +30 -21
  439. package/src/memory/db-singleton.ts +77 -0
  440. package/src/memory/delivery-channels.ts +82 -0
  441. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
  442. package/src/memory/graph/bootstrap.ts +8 -1
  443. package/src/memory/graph/capability-seed.ts +7 -3
  444. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  445. package/src/memory/graph/extraction.ts +1 -5
  446. package/src/memory/graph/graph-search.ts +7 -1
  447. package/src/memory/graph/retriever.test.ts +3 -3
  448. package/src/memory/indexer.ts +28 -18
  449. package/src/memory/job-handlers/cleanup.ts +76 -18
  450. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  451. package/src/memory/job-handlers/embedding.test.ts +3 -2
  452. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
  453. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  454. package/src/memory/jobs-store.ts +14 -0
  455. package/src/memory/jobs-worker.ts +66 -22
  456. package/src/memory/llm-request-log-source-clickhouse.ts +122 -2
  457. package/src/memory/llm-request-log-source-local.ts +31 -0
  458. package/src/memory/llm-request-log-source.ts +40 -2
  459. package/src/memory/llm-request-log-store.ts +228 -1
  460. package/src/memory/llm-usage-store.ts +24 -0
  461. package/src/memory/memory-retrospective-enqueue.ts +8 -1
  462. package/src/memory/memory-retrospective-job.ts +5 -0
  463. package/src/memory/memory-v2-activation-log-store.ts +110 -7
  464. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  465. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  466. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  467. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  468. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  469. package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
  470. package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
  471. package/src/memory/migrations/index.ts +19 -0
  472. package/src/memory/migrations/registry.ts +33 -0
  473. package/src/memory/schema/conversations.ts +10 -2
  474. package/src/memory/schema/inference.ts +0 -1
  475. package/src/memory/schema/infrastructure.ts +21 -0
  476. package/src/memory/tool-usage-store.ts +36 -8
  477. package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
  478. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  479. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  480. package/src/memory/v2/__tests__/harness-metrics.test.ts +83 -0
  481. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  482. package/src/memory/v2/__tests__/harness-replay-input.test.ts +230 -0
  483. package/src/memory/v2/__tests__/harness-runner.test.ts +135 -0
  484. package/src/memory/v2/__tests__/injection.test.ts +127 -98
  485. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  486. package/src/memory/v2/__tests__/router.test.ts +171 -3
  487. package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
  488. package/src/memory/v2/harness/compare.ts +57 -0
  489. package/src/memory/v2/harness/metrics.ts +128 -0
  490. package/src/memory/v2/harness/oracle.ts +145 -0
  491. package/src/memory/v2/harness/replay-input.ts +240 -0
  492. package/src/memory/v2/harness/retriever.ts +74 -0
  493. package/src/memory/v2/harness/router-retriever.ts +43 -0
  494. package/src/memory/v2/harness/runner.ts +112 -0
  495. package/src/memory/v2/harness/trace.ts +64 -0
  496. package/src/memory/v2/injection.ts +21 -15
  497. package/src/memory/v2/prompts/router.ts +26 -1
  498. package/src/memory/v2/qdrant.ts +14 -2
  499. package/src/memory/v2/router.ts +171 -18
  500. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  501. package/src/memory/v3/__tests__/consolidation-job.test.ts +466 -0
  502. package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
  503. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  504. package/src/memory/v3/__tests__/edges.test.ts +706 -0
  505. package/src/memory/v3/__tests__/filter.test.ts +560 -0
  506. package/src/memory/v3/__tests__/gate.test.ts +637 -0
  507. package/src/memory/v3/__tests__/index-composition.test.ts +291 -0
  508. package/src/memory/v3/__tests__/loop.test.ts +775 -0
  509. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  510. package/src/memory/v3/__tests__/scouts.test.ts +489 -0
  511. package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
  512. package/src/memory/v3/__tests__/shadow-middleware.test.ts +398 -0
  513. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  514. package/src/memory/v3/__tests__/traversal.test.ts +508 -0
  515. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  516. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  517. package/src/memory/v3/__tests__/tree-walk.test.ts +784 -0
  518. package/src/memory/v3/__tests__/validate.test.ts +277 -0
  519. package/src/memory/v3/auto-edges.ts +223 -0
  520. package/src/memory/v3/coactivation-store.ts +124 -0
  521. package/src/memory/v3/consolidation-job.ts +323 -0
  522. package/src/memory/v3/coretrieval-seed.ts +240 -0
  523. package/src/memory/v3/edge-learning-job.ts +160 -0
  524. package/src/memory/v3/edges.ts +286 -0
  525. package/src/memory/v3/filter.ts +286 -0
  526. package/src/memory/v3/gate.ts +349 -0
  527. package/src/memory/v3/index-composition.ts +126 -0
  528. package/src/memory/v3/llm-capture.ts +46 -0
  529. package/src/memory/v3/loop.ts +430 -0
  530. package/src/memory/v3/maintenance.ts +144 -0
  531. package/src/memory/v3/prompt-context.ts +33 -0
  532. package/src/memory/v3/prompts/consolidation.ts +458 -0
  533. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  534. package/src/memory/v3/retriever.ts +33 -0
  535. package/src/memory/v3/scouts.ts +431 -0
  536. package/src/memory/v3/shadow-diff.ts +287 -0
  537. package/src/memory/v3/shadow-middleware.ts +347 -0
  538. package/src/memory/v3/traversal.ts +211 -0
  539. package/src/memory/v3/tree-index.ts +237 -0
  540. package/src/memory/v3/tree-store.ts +394 -0
  541. package/src/memory/v3/tree-walk.ts +356 -0
  542. package/src/memory/v3/types.ts +65 -0
  543. package/src/memory/v3/validate.ts +323 -0
  544. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
  545. package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
  546. package/src/notifications/adapters/macos.ts +18 -1
  547. package/src/notifications/adapters/platform.ts +1 -1
  548. package/src/notifications/adapters/slack.ts +45 -11
  549. package/src/notifications/broadcaster.ts +114 -63
  550. package/src/notifications/conversation-pairing.ts +23 -3
  551. package/src/notifications/decision-engine.ts +1 -4
  552. package/src/notifications/decisions-store.ts +32 -1
  553. package/src/notifications/deliveries-store.ts +45 -0
  554. package/src/notifications/edit-notification.ts +201 -0
  555. package/src/notifications/emit-signal.ts +40 -50
  556. package/src/notifications/signal.ts +10 -0
  557. package/src/notifications/types.ts +37 -0
  558. package/src/oauth/byo-connection.test.ts +67 -3
  559. package/src/oauth/byo-connection.ts +32 -5
  560. package/src/oauth/connect-orchestrator.ts +9 -0
  561. package/src/oauth/connection-resolver.test.ts +76 -0
  562. package/src/oauth/connection-resolver.ts +49 -10
  563. package/src/oauth/manual-token-connection.ts +51 -3
  564. package/src/oauth/seed-providers.ts +3 -0
  565. package/src/permissions/approval-policy.test.ts +19 -5
  566. package/src/permissions/approval-policy.ts +14 -3
  567. package/src/permissions/checker.ts +21 -8
  568. package/src/permissions/prompter.ts +3 -3
  569. package/src/permissions/question-prompter.ts +5 -2
  570. package/src/permissions/secret-prompter.ts +2 -2
  571. package/src/platform/client.test.ts +24 -1
  572. package/src/platform/client.ts +8 -0
  573. package/src/platform/feature-gate.ts +15 -0
  574. package/src/plugin-api/index.ts +4 -0
  575. package/src/plugin-api/types.ts +7 -33
  576. package/src/plugins/defaults/index.ts +6 -0
  577. package/src/plugins/defaults/injectors.ts +20 -19
  578. package/src/plugins/defaults/persistence.ts +25 -6
  579. package/src/plugins/external-plugin-loader.ts +5 -68
  580. package/src/plugins/types.ts +68 -29
  581. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  582. package/src/proactive-artifact/job.test.ts +1 -0
  583. package/src/prompts/__tests__/system-prompt.test.ts +4 -4
  584. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  585. package/src/prompts/persona-resolver.ts +36 -21
  586. package/src/prompts/sections.ts +39 -7
  587. package/src/prompts/system-prompt.ts +84 -221
  588. package/src/prompts/template-detection.ts +10 -4
  589. package/src/prompts/templates/BOOTSTRAP.md +9 -13
  590. package/src/prompts/templates/IDENTITY.md +0 -2
  591. package/src/prompts/templates/system-sections.ts +230 -8
  592. package/src/providers/__tests__/connection-model-compat.test.ts +233 -0
  593. package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
  594. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  595. package/src/providers/anthropic/client.ts +32 -66
  596. package/src/providers/call-site-routing.ts +42 -6
  597. package/src/providers/connection-model-compat.ts +61 -0
  598. package/src/providers/connection-resolution.ts +47 -14
  599. package/src/providers/fireworks/client.ts +1 -0
  600. package/src/providers/gemini/client.ts +70 -6
  601. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
  602. package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
  603. package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
  604. package/src/providers/inference/adapter-factory.ts +3 -0
  605. package/src/providers/inference/auth.ts +0 -8
  606. package/src/providers/inference/connections.ts +3 -66
  607. package/src/providers/inference/resolve-auth.ts +2 -3
  608. package/src/providers/minimax/client.ts +106 -0
  609. package/src/providers/model-catalog.ts +78 -1
  610. package/src/providers/model-intents.ts +4 -4
  611. package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
  612. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
  613. package/src/providers/openai/chat-completions-provider.ts +116 -15
  614. package/src/providers/openai/codex-models.ts +20 -0
  615. package/src/providers/openai/responses-provider.ts +87 -30
  616. package/src/providers/openrouter/client.ts +13 -8
  617. package/src/providers/provider-send-message.ts +20 -5
  618. package/src/providers/registry.ts +48 -8
  619. package/src/providers/retry.ts +50 -7
  620. package/src/providers/search-provider-catalog.ts +17 -9
  621. package/src/providers/thinking-config.ts +26 -1
  622. package/src/providers/types.ts +9 -0
  623. package/src/providers/usage-tracking.ts +2 -0
  624. package/src/runtime/AGENTS.md +2 -2
  625. package/src/runtime/__tests__/agent-wake.test.ts +1 -0
  626. package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
  627. package/src/runtime/access-request-helper.ts +1 -0
  628. package/src/runtime/agent-wake.ts +1 -0
  629. package/src/runtime/assistant-event-hub.ts +76 -6
  630. package/src/runtime/auth/route-policy.ts +46 -0
  631. package/src/runtime/btw-sidechain.ts +0 -6
  632. package/src/runtime/channel-readiness-service.ts +68 -0
  633. package/src/runtime/channel-reply-delivery.ts +23 -0
  634. package/src/runtime/channel-retry-sweep.ts +47 -14
  635. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  636. package/src/runtime/http-types.ts +0 -2
  637. package/src/runtime/migrations/vbundle-builder.ts +12 -4
  638. package/src/runtime/pending-interactions.ts +0 -1
  639. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
  640. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
  641. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +204 -0
  642. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  643. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
  644. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
  645. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +76 -9
  646. package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
  647. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  648. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
  649. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
  650. package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
  651. package/src/runtime/routes/acp-routes-list.test.ts +3 -0
  652. package/src/runtime/routes/acp-routes.test.ts +255 -6
  653. package/src/runtime/routes/acp-routes.ts +8 -1
  654. package/src/runtime/routes/app-management-routes.ts +111 -4
  655. package/src/runtime/routes/avatar-routes.ts +10 -10
  656. package/src/runtime/routes/background-wake-routes.ts +356 -0
  657. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  658. package/src/runtime/routes/btw-routes.ts +4 -10
  659. package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
  660. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  661. package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
  662. package/src/runtime/routes/conversation-list-routes.ts +159 -4
  663. package/src/runtime/routes/conversation-management-routes.ts +108 -26
  664. package/src/runtime/routes/conversation-query-routes.ts +200 -44
  665. package/src/runtime/routes/conversation-routes.ts +409 -521
  666. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  667. package/src/runtime/routes/conversations-import-routes.ts +19 -6
  668. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  669. package/src/runtime/routes/documents-routes.ts +10 -1
  670. package/src/runtime/routes/domain-routes.ts +60 -10
  671. package/src/runtime/routes/email-routes.ts +5 -2
  672. package/src/runtime/routes/events-routes.ts +54 -10
  673. package/src/runtime/routes/group-routes.ts +35 -8
  674. package/src/runtime/routes/home-feed-routes.ts +129 -0
  675. package/src/runtime/routes/host-browser-routes.ts +10 -2
  676. package/src/runtime/routes/host-cu-routes.ts +2 -2
  677. package/src/runtime/routes/identity-intro-cache.ts +61 -16
  678. package/src/runtime/routes/identity-routes.ts +30 -9
  679. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  680. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
  681. package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
  682. package/src/runtime/routes/index.ts +10 -0
  683. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  684. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  685. package/src/runtime/routes/inference-provider-connection-routes.ts +5 -26
  686. package/src/runtime/routes/integrations/vercel.ts +15 -0
  687. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  688. package/src/runtime/routes/llm-context-normalization.ts +7 -2
  689. package/src/runtime/routes/memory-item-routes.ts +8 -3
  690. package/src/runtime/routes/memory-v2-routes.ts +215 -5
  691. package/src/runtime/routes/memory-v3-routes.ts +474 -0
  692. package/src/runtime/routes/migration-routes.ts +32 -28
  693. package/src/runtime/routes/notification-routes.ts +63 -1
  694. package/src/runtime/routes/oauth-commands-routes.ts +6 -1
  695. package/src/runtime/routes/plugins-routes.ts +337 -0
  696. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  697. package/src/runtime/routes/secret-routes.ts +25 -5
  698. package/src/runtime/routes/settings-routes.ts +12 -11
  699. package/src/runtime/routes/slack-channel-routes.ts +5 -4
  700. package/src/runtime/routes/surface-action-routes.ts +1 -38
  701. package/src/runtime/routes/surface-content-routes.ts +12 -5
  702. package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
  703. package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
  704. package/src/runtime/routes/workspace-routes.ts +25 -10
  705. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
  706. package/src/runtime/slack-dm-text-delivery.ts +177 -0
  707. package/src/runtime/sync/resource-sync-events.ts +106 -38
  708. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  709. package/src/runtime/sync/sync-publisher.ts +2 -1
  710. package/src/runtime/tool-grant-request-helper.ts +1 -0
  711. package/src/runtime/verification-outbound-actions.ts +73 -1
  712. package/src/schedule/schedule-store.ts +8 -1
  713. package/src/schedule/scheduler.ts +111 -15
  714. package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
  715. package/src/security/encrypted-store.ts +7 -16
  716. package/src/security/store-path-override.ts +61 -0
  717. package/src/signals/user-message.ts +5 -8
  718. package/src/skills/validate-input.ts +177 -0
  719. package/src/subagent/manager.ts +13 -13
  720. package/src/subagent/types.ts +6 -0
  721. package/src/tasks/tool-sanitizer.ts +2 -2
  722. package/src/telemetry/types.ts +12 -0
  723. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  724. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  725. package/src/tools/acp/spawn.test.ts +119 -0
  726. package/src/tools/acp/spawn.ts +15 -2
  727. package/src/tools/apps/definitions.ts +36 -28
  728. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  729. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  730. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
  731. package/src/tools/browser/__tests__/pinned-tabs.test.ts +70 -0
  732. package/src/tools/browser/browser-execution.ts +16 -3
  733. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  734. package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
  735. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
  736. package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
  737. package/src/tools/browser/cdp-client/factory.ts +100 -17
  738. package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
  739. package/src/tools/browser/cdp-client/types.ts +65 -0
  740. package/src/tools/browser/pinned-tabs.ts +96 -40
  741. package/src/tools/computer-use/definitions.ts +282 -336
  742. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  743. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  744. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  745. package/src/tools/credentials/vault.ts +3 -9
  746. package/src/tools/document/document-tool.ts +189 -7
  747. package/src/tools/execution-target.ts +18 -23
  748. package/src/tools/executor.ts +24 -56
  749. package/src/tools/filesystem/edit.ts +3 -9
  750. package/src/tools/filesystem/list.ts +3 -9
  751. package/src/tools/filesystem/read.ts +3 -9
  752. package/src/tools/filesystem/write.ts +3 -9
  753. package/src/tools/host-filesystem/edit.test.ts +1 -0
  754. package/src/tools/host-filesystem/edit.ts +3 -9
  755. package/src/tools/host-filesystem/read.test.ts +1 -0
  756. package/src/tools/host-filesystem/read.ts +3 -9
  757. package/src/tools/host-filesystem/transfer.test.ts +31 -6
  758. package/src/tools/host-filesystem/transfer.ts +3 -9
  759. package/src/tools/host-filesystem/write.test.ts +1 -0
  760. package/src/tools/host-filesystem/write.ts +3 -9
  761. package/src/tools/host-terminal/host-shell.ts +3 -9
  762. package/src/tools/mcp/mcp-tool-factory.ts +1 -10
  763. package/src/tools/memory/register.test.ts +1 -1
  764. package/src/tools/memory/register.ts +4 -9
  765. package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
  766. package/src/tools/network/__tests__/web-search.test.ts +211 -3
  767. package/src/tools/network/managed-search-proxy.ts +183 -0
  768. package/src/tools/network/web-fetch.ts +3 -9
  769. package/src/tools/network/web-search.ts +224 -76
  770. package/src/tools/policy-context.ts +3 -1
  771. package/src/tools/registry.ts +150 -123
  772. package/src/tools/schedule/create.ts +1 -1
  773. package/src/tools/schema-transforms.ts +1 -1
  774. package/src/tools/skills/execute.ts +3 -9
  775. package/src/tools/skills/load.ts +3 -9
  776. package/src/tools/skills/skill-tool-factory.ts +18 -44
  777. package/src/tools/subagent/notify-parent.ts +3 -9
  778. package/src/tools/subagent/spawn.ts +3 -0
  779. package/src/tools/system/request-permission.ts +3 -9
  780. package/src/tools/terminal/shell.ts +3 -9
  781. package/src/tools/tool-approval-handler.ts +10 -4
  782. package/src/tools/tool-defaults.ts +94 -0
  783. package/src/tools/tool-name-aliases.ts +72 -14
  784. package/src/tools/types.ts +32 -101
  785. package/src/tools/ui-surface/definitions.ts +104 -108
  786. package/src/types/onboarding-context.ts +6 -0
  787. package/src/usage/attribution.ts +32 -1
  788. package/src/usage/pricing.ts +23 -0
  789. package/src/usage/types.ts +12 -0
  790. package/src/util/browser.ts +7 -2
  791. package/src/util/logger.ts +16 -7
  792. package/src/util/platform.ts +7 -2
  793. package/src/util/sqlite3-runtime.ts +65 -0
  794. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  795. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  796. package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
  797. package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
  798. package/src/workspace/migrations/registry.ts +6 -0
  799. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  800. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  801. package/src/daemon/query-complexity-router.ts +0 -75
  802. package/src/prompts/cache-boundary.ts +0 -8
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Shared helper for resolving the conversation that owns a surface.
3
+ *
4
+ * Used by both `surface-action-routes` (POST /v1/surface-actions) and
5
+ * `surface-content-routes` (GET /v1/surfaces/:surfaceId) so the
6
+ * in-memory-miss → DB-scan → rehydrate flow stays in one place.
7
+ *
8
+ * Why this exists: surfaces live on the in-memory `Conversation` object
9
+ * (`surfaceState` is rebuilt from `ui_surface` blocks in message
10
+ * history by `restoreSurfaceStateFromHistory()` whenever a Conversation
11
+ * is constructed). A bare `findConversation` lookup 404s after daemon
12
+ * restart or LRU eviction even though the surface data is still in the
13
+ * SQLite `messages` table. The DB scan below uses the surfaceId itself
14
+ * as the existence check so `getOrCreateConversation` can't be tricked
15
+ * into materializing a phantom conversation for any caller-supplied id.
16
+ */
17
+ import type { Conversation } from "../../daemon/conversation.js";
18
+ import {
19
+ findConversation,
20
+ findConversationBySurfaceId,
21
+ getOrCreateConversation,
22
+ } from "../../daemon/conversation-store.js";
23
+ import { rawGet } from "../../memory/raw-query.js";
24
+
25
+ /**
26
+ * Resolve the {@link Conversation} that owns the given surface.
27
+ *
28
+ * Lookup order:
29
+ * 1. In-memory map keyed by `conversationId` (or by `surfaceId` when no
30
+ * id is supplied).
31
+ * 2. SQLite `messages` table — find the conversation whose history
32
+ * contains a `ui_surface` block with this `surfaceId`. The result is
33
+ * validated against the caller's `conversationId` (when supplied) so
34
+ * a mismatched pair returns `undefined` rather than silently
35
+ * re-routing to a different conversation.
36
+ * 3. `getOrCreateConversation` rehydrates the row, which triggers
37
+ * `restoreSurfaceStateFromHistory()` and repopulates `surfaceState`.
38
+ *
39
+ * Returns `undefined` when neither lookup nor DB scan turns up a
40
+ * matching conversation. Callers are expected to translate that into
41
+ * the route-appropriate 404.
42
+ */
43
+ export async function resolveSurfaceConversation(
44
+ conversationId: string | null | undefined,
45
+ surfaceId: string,
46
+ ): Promise<Conversation | undefined> {
47
+ const found = conversationId
48
+ ? findConversation(conversationId)
49
+ : findConversationBySurfaceId(surfaceId);
50
+ if (found) return found;
51
+
52
+ // Escape LIKE wildcards so a `surfaceId` like "%" or "_" can't match
53
+ // unrelated rows.
54
+ const escaped = surfaceId.replace(/[\\%_]/g, "\\$&");
55
+ const row = rawGet<{ conversation_id: string }>(
56
+ `SELECT conversation_id FROM messages
57
+ WHERE content LIKE ? ESCAPE '\\'
58
+ ORDER BY created_at DESC
59
+ LIMIT 1`,
60
+ `%"surfaceId":"${escaped}"%`,
61
+ );
62
+ if (!row) return undefined;
63
+ if (conversationId && conversationId !== row.conversation_id) return undefined;
64
+ return await getOrCreateConversation(row.conversation_id);
65
+ }
@@ -5,6 +5,7 @@
5
5
  import { z } from "zod";
6
6
 
7
7
  import { destroyActiveConversation } from "../../daemon/conversation-store.js";
8
+ import { stripConversationIds } from "../../home/feed-writer.js";
8
9
  import {
9
10
  countConversationsByScheduleJobId,
10
11
  getConversation,
@@ -54,6 +55,8 @@ async function handleWipeConversation({ body = {} }: RouteHandlerArgs) {
54
55
  });
55
56
  }
56
57
 
58
+ void stripConversationIds(conversationId);
59
+
57
60
  return {
58
61
  wiped: true,
59
62
  unsupersededItems: 0,
@@ -59,9 +59,12 @@ function isSoundsWorkspacePath(path: string): boolean {
59
59
  );
60
60
  }
61
61
 
62
- function publishSoundsConfigUpdatedForPaths(paths: string[]): void {
62
+ function publishSoundsConfigUpdatedForPaths(
63
+ paths: string[],
64
+ originClientId?: string,
65
+ ): void {
63
66
  if (paths.some(isSoundsWorkspacePath)) {
64
- publishSoundsConfigUpdated();
67
+ publishSoundsConfigUpdated(originClientId);
65
68
  }
66
69
  }
67
70
 
@@ -263,7 +266,7 @@ function handleWorkspaceFileContent({
263
266
  // POST /v1/workspace/write — create or overwrite a file
264
267
  // ---------------------------------------------------------------------------
265
268
 
266
- function handleWorkspaceWrite({ body }: RouteHandlerArgs) {
269
+ function handleWorkspaceWrite({ body, headers }: RouteHandlerArgs) {
267
270
  const path = body?.path as string | undefined;
268
271
  const content = body?.content as string | undefined;
269
272
  const encoding = body?.encoding as string | undefined;
@@ -292,7 +295,10 @@ function handleWorkspaceWrite({ body }: RouteHandlerArgs) {
292
295
 
293
296
  mkdirSync(dirname(resolved), { recursive: true });
294
297
  writeFileSync(resolved, buffer);
295
- publishSoundsConfigUpdatedForPaths([path]);
298
+ publishSoundsConfigUpdatedForPaths(
299
+ [path],
300
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
301
+ );
296
302
 
297
303
  return { path, size: buffer.byteLength };
298
304
  }
@@ -301,7 +307,7 @@ function handleWorkspaceWrite({ body }: RouteHandlerArgs) {
301
307
  // POST /v1/workspace/mkdir — create directories
302
308
  // ---------------------------------------------------------------------------
303
309
 
304
- function handleWorkspaceMkdir({ body }: RouteHandlerArgs) {
310
+ function handleWorkspaceMkdir({ body, headers }: RouteHandlerArgs) {
305
311
  const path = body?.path as string | undefined;
306
312
  if (!path) {
307
313
  throw new BadRequestError("path is required");
@@ -320,7 +326,10 @@ function handleWorkspaceMkdir({ body }: RouteHandlerArgs) {
320
326
  }
321
327
 
322
328
  mkdirSync(resolved, { recursive: true });
323
- publishSoundsConfigUpdatedForPaths([path]);
329
+ publishSoundsConfigUpdatedForPaths(
330
+ [path],
331
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
332
+ );
324
333
  return { path };
325
334
  }
326
335
 
@@ -328,7 +337,7 @@ function handleWorkspaceMkdir({ body }: RouteHandlerArgs) {
328
337
  // POST /v1/workspace/rename — rename/move files and directories
329
338
  // ---------------------------------------------------------------------------
330
339
 
331
- function handleWorkspaceRename({ body }: RouteHandlerArgs) {
340
+ function handleWorkspaceRename({ body, headers }: RouteHandlerArgs) {
332
341
  const oldPath = body?.oldPath as string | undefined;
333
342
  const newPath = body?.newPath as string | undefined;
334
343
  if (!oldPath || !newPath) {
@@ -360,7 +369,10 @@ function handleWorkspaceRename({ body }: RouteHandlerArgs) {
360
369
 
361
370
  mkdirSync(dirname(resolvedNew), { recursive: true });
362
371
  renameSync(resolvedOld, resolvedNew);
363
- publishSoundsConfigUpdatedForPaths([oldPath, newPath]);
372
+ publishSoundsConfigUpdatedForPaths(
373
+ [oldPath, newPath],
374
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
375
+ );
364
376
  return { oldPath, newPath };
365
377
  }
366
378
 
@@ -368,7 +380,7 @@ function handleWorkspaceRename({ body }: RouteHandlerArgs) {
368
380
  // POST /v1/workspace/delete — delete files and directories
369
381
  // ---------------------------------------------------------------------------
370
382
 
371
- function handleWorkspaceDelete({ body }: RouteHandlerArgs) {
383
+ function handleWorkspaceDelete({ body, headers }: RouteHandlerArgs) {
372
384
  const path = body?.path as string | undefined;
373
385
  if (!path) {
374
386
  throw new BadRequestError("path is required");
@@ -388,7 +400,10 @@ function handleWorkspaceDelete({ body }: RouteHandlerArgs) {
388
400
  }
389
401
 
390
402
  rmSync(resolved, { recursive: true, force: true });
391
- publishSoundsConfigUpdatedForPaths([path]);
403
+ publishSoundsConfigUpdatedForPaths(
404
+ [path],
405
+ headers?.["x-vellum-client-id"]?.trim() || undefined,
406
+ );
392
407
  return { success: true };
393
408
  }
394
409
 
@@ -46,6 +46,7 @@ mock.module("../../../memory/conversation-crud.js", () => ({
46
46
  addMessage: mockAddMessage,
47
47
  findAnalysisConversationFor: mockFindAnalysisConversationFor,
48
48
  getConversationSource: mockGetConversationSource,
49
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
49
50
  }));
50
51
 
51
52
  mock.module("../../../export/transcript-formatter.js", () => ({
@@ -80,6 +81,7 @@ const testHub = new AssistantEventHub();
80
81
  mock.module("../../assistant-event-hub.js", () => ({
81
82
  AssistantEventHub,
82
83
  assistantEventHub: testHub,
84
+ broadcastMessage: async () => {},
83
85
  }));
84
86
 
85
87
  import { analyzeConversation } from "../analyze-conversation.js";
@@ -0,0 +1,177 @@
1
+ import type { ChannelId } from "../channels/types.js";
2
+ import type { ServerMessage } from "../daemon/message-protocol.js";
3
+ import { getLogger } from "../util/logger.js";
4
+ import { deliverChannelReply } from "./gateway-client.js";
5
+
6
+ const log = getLogger("runtime-http");
7
+
8
+ const NO_RESPONSE_INLINE_RE = /<no_response\s*\/?>/gi;
9
+
10
+ export function isSlackDeliveryCallbackUrl(replyCallbackUrl?: string): boolean {
11
+ if (!replyCallbackUrl) return false;
12
+ try {
13
+ return new URL(replyCallbackUrl).pathname.endsWith("/deliver/slack");
14
+ } catch {
15
+ return replyCallbackUrl.endsWith("/deliver/slack");
16
+ }
17
+ }
18
+
19
+ export function shouldDeliverSlackDmTextResponses(params: {
20
+ sourceChannel: ChannelId;
21
+ chatType?: string;
22
+ replyCallbackUrl?: string;
23
+ }): boolean {
24
+ return (
25
+ params.sourceChannel === "slack" &&
26
+ params.chatType === "im" &&
27
+ isSlackDeliveryCallbackUrl(params.replyCallbackUrl)
28
+ );
29
+ }
30
+
31
+ export type SlackDmTextDeliveryController = {
32
+ observeEvent: (msg: ServerMessage) => void;
33
+ waitForPendingDeliveries: () => Promise<void>;
34
+ getFinalDeliveryResumeOptions: (
35
+ messageId: string | undefined,
36
+ ) => { startFromSegment: number; messageTs?: string } | undefined;
37
+ };
38
+
39
+ export function createSlackDmTextDeliveryController(params: {
40
+ sourceChannel: ChannelId;
41
+ chatType?: string;
42
+ replyCallbackUrl?: string;
43
+ chatId: string;
44
+ assistantId?: string;
45
+ deliveredTextResponseIndexes?: readonly number[];
46
+ onTextResponseDelivered?: (
47
+ responseIndex: number,
48
+ reason: "before_tool" | "message_complete",
49
+ ) => void;
50
+ }): SlackDmTextDeliveryController | undefined {
51
+ const { replyCallbackUrl } = params;
52
+ if (!shouldDeliverSlackDmTextResponses(params) || !replyCallbackUrl) {
53
+ return undefined;
54
+ }
55
+
56
+ const deliveredTextResponseIndexes = new Set(
57
+ params.deliveredTextResponseIndexes ?? [],
58
+ );
59
+ const messageIdToResponseIndexes = new Map<string, number[]>();
60
+ const responseIndexToMessageTs = new Map<number, string>();
61
+ let textResponseIndex = 0;
62
+ let pendingText = "";
63
+ let currentMessageResponseIndexes: number[] = [];
64
+ let deliveryChain = Promise.resolve();
65
+
66
+ const associateCurrentMessageResponses = (
67
+ messageId: string | undefined,
68
+ ): void => {
69
+ if (!messageId || currentMessageResponseIndexes.length === 0) return;
70
+ const responseIndexes = messageIdToResponseIndexes.get(messageId) ?? [];
71
+ for (const responseIndex of currentMessageResponseIndexes) {
72
+ if (!responseIndexes.includes(responseIndex)) {
73
+ responseIndexes.push(responseIndex);
74
+ }
75
+ }
76
+ messageIdToResponseIndexes.set(messageId, responseIndexes);
77
+ currentMessageResponseIndexes = [];
78
+ };
79
+
80
+ const flushPendingText = (
81
+ reason: "before_tool" | "message_complete",
82
+ ): void => {
83
+ const text = pendingText;
84
+ pendingText = "";
85
+
86
+ const deliverableText = text.replace(NO_RESPONSE_INLINE_RE, "").trim();
87
+ if (deliverableText.length === 0) return;
88
+
89
+ textResponseIndex += 1;
90
+ const currentResponseIndex = textResponseIndex;
91
+ currentMessageResponseIndexes.push(currentResponseIndex);
92
+ if (deliveredTextResponseIndexes.has(currentResponseIndex)) return;
93
+
94
+ deliveryChain = deliveryChain
95
+ .catch(() => undefined)
96
+ .then(async () => {
97
+ let result: Awaited<ReturnType<typeof deliverChannelReply>>;
98
+ try {
99
+ result = await deliverChannelReply(replyCallbackUrl, {
100
+ chatId: params.chatId,
101
+ text: deliverableText,
102
+ assistantId: params.assistantId,
103
+ useBlocks: true,
104
+ });
105
+ } catch (err) {
106
+ log.warn(
107
+ { err, chatId: params.chatId },
108
+ "Failed to deliver intermediate Slack DM assistant text",
109
+ );
110
+ return;
111
+ }
112
+
113
+ if (result.ts) {
114
+ responseIndexToMessageTs.set(currentResponseIndex, result.ts);
115
+ }
116
+ deliveredTextResponseIndexes.add(currentResponseIndex);
117
+ try {
118
+ params.onTextResponseDelivered?.(currentResponseIndex, reason);
119
+ } catch (err) {
120
+ log.warn(
121
+ { err, chatId: params.chatId, responseIndex: currentResponseIndex },
122
+ "Failed to persist intermediate Slack DM assistant text progress",
123
+ );
124
+ }
125
+ });
126
+ };
127
+
128
+ return {
129
+ observeEvent(msg) {
130
+ if (msg.type === "assistant_text_delta") {
131
+ pendingText += msg.text;
132
+ return;
133
+ }
134
+
135
+ if (msg.type === "message_complete") {
136
+ flushPendingText("message_complete");
137
+ if (typeof msg.messageId === "string") {
138
+ associateCurrentMessageResponses(msg.messageId);
139
+ }
140
+ currentMessageResponseIndexes = [];
141
+ return;
142
+ }
143
+
144
+ if (msg.type === "tool_use_start") {
145
+ flushPendingText("before_tool");
146
+ }
147
+ },
148
+ waitForPendingDeliveries: () => deliveryChain,
149
+ getFinalDeliveryResumeOptions: (messageId) => {
150
+ if (typeof messageId !== "string") {
151
+ return undefined;
152
+ }
153
+ const responseIndexes = messageIdToResponseIndexes.get(messageId) ?? [];
154
+ let deliveredPrefixCount = 0;
155
+ for (const responseIndex of responseIndexes) {
156
+ if (!deliveredTextResponseIndexes.has(responseIndex)) break;
157
+ deliveredPrefixCount += 1;
158
+ }
159
+ if (deliveredPrefixCount === 0) return undefined;
160
+
161
+ const firstLiveResponseIndex = responseIndexes[0];
162
+ const allTextResponsesDelivered =
163
+ responseIndexes.length > 0 &&
164
+ responseIndexes.every((responseIndex) =>
165
+ deliveredTextResponseIndexes.has(responseIndex),
166
+ );
167
+ const messageTs =
168
+ allTextResponsesDelivered && firstLiveResponseIndex !== undefined
169
+ ? responseIndexToMessageTs.get(firstLiveResponseIndex)
170
+ : undefined;
171
+ return {
172
+ startFromSegment: deliveredPrefixCount,
173
+ ...(messageTs ? { messageTs } : {}),
174
+ };
175
+ },
176
+ };
177
+ }
@@ -9,15 +9,18 @@ import { getAvatarImagePath } from "../../util/platform.js";
9
9
  import { broadcastMessage } from "../assistant-event-hub.js";
10
10
  import { publishSyncInvalidation } from "./sync-publisher.js";
11
11
 
12
- export function publishAvatarChanged(): void {
12
+ export function publishAvatarChanged(originClientId?: string): void {
13
13
  broadcastMessage({
14
14
  type: "avatar_updated",
15
15
  avatarPath: getAvatarImagePath(),
16
16
  });
17
- void publishSyncInvalidation([SYNC_TAGS.assistantAvatar]);
17
+ void publishSyncInvalidation([SYNC_TAGS.assistantAvatar], originClientId);
18
18
  }
19
19
 
20
- export function publishIdentityChanged(fields: IdentityFields): void {
20
+ export function publishIdentityChanged(
21
+ fields: IdentityFields,
22
+ originClientId?: string,
23
+ ): void {
21
24
  broadcastMessage({
22
25
  type: "identity_changed",
23
26
  name: fields.name,
@@ -26,59 +29,112 @@ export function publishIdentityChanged(fields: IdentityFields): void {
26
29
  emoji: fields.emoji,
27
30
  home: fields.home,
28
31
  });
29
- void publishSyncInvalidation([SYNC_TAGS.assistantIdentity]);
32
+ void publishSyncInvalidation([SYNC_TAGS.assistantIdentity], originClientId);
30
33
  }
31
34
 
32
- export function publishConfigChanged(): void {
35
+ export function publishConfigChanged(originClientId?: string): void {
33
36
  broadcastMessage({ type: "config_changed" });
34
- void publishSyncInvalidation([SYNC_TAGS.assistantConfig]);
37
+ void publishSyncInvalidation([SYNC_TAGS.assistantConfig], originClientId);
35
38
  }
36
39
 
37
- export function publishSoundsConfigUpdated(): void {
40
+ export function publishSoundsConfigUpdated(originClientId?: string): void {
38
41
  broadcastMessage({ type: "sounds_config_updated" });
39
- void publishSyncInvalidation([SYNC_TAGS.assistantSounds]);
42
+ void publishSyncInvalidation([SYNC_TAGS.assistantSounds], originClientId);
40
43
  }
41
44
 
42
- export function publishSchedulesChanged(): void {
43
- void publishSyncInvalidation([SYNC_TAGS.assistantSchedules]);
45
+ export function publishSchedulesChanged(originClientId?: string): void {
46
+ void publishSyncInvalidation([SYNC_TAGS.assistantSchedules], originClientId);
47
+ }
48
+
49
+ /**
50
+ * Reasons that change the *shape* of the conversation list — a row is
51
+ * added, removed, or its position changes. These require web clients to
52
+ * refetch the paginated list because the row patch path (`refreshConversationRow`)
53
+ * only handles a single known id. Reasons not in this set are *content-only*
54
+ * changes to an existing row (e.g. `seen_changed`, `renamed`) and are
55
+ * delivered exclusively via the per-conversation `sync_changed` tag, which
56
+ * web consumes by GET-and-patching the single row.
57
+ */
58
+ const SHAPE_CHANGING_REASONS: ReadonlySet<ConversationListInvalidatedReason> =
59
+ new Set(["created", "deleted", "reordered"]);
60
+
61
+ /**
62
+ * Publish the legacy `conversation_list_invalidated` broadcast to macOS
63
+ * subscribers only.
64
+ *
65
+ * Web consumes `sync_changed` (`conversationsList` for shape changes,
66
+ * `conversation:<id>:metadata` for content changes) directly and patches
67
+ * the cached list in place — see `useConversationSync` for the consumer
68
+ * side. macOS (`ConversationRestorer.swift`) still listens for the typed
69
+ * broadcast.
70
+ *
71
+ * TODO(electron-cutover): remove this helper and all callers once macOS
72
+ * migrates to the Electron client and consumes `sync_changed` directly.
73
+ * At that point the `conversation_list_invalidated` message type can be
74
+ * retired entirely.
75
+ */
76
+ function broadcastConversationListInvalidatedToMacos(
77
+ reason: ConversationListInvalidatedReason,
78
+ ): void {
79
+ broadcastMessage(
80
+ {
81
+ type: "conversation_list_invalidated",
82
+ reason,
83
+ },
84
+ undefined,
85
+ { targetInterfaceId: "macos" },
86
+ );
44
87
  }
45
88
 
46
89
  export function publishConversationListChanged(
47
90
  reason: ConversationListInvalidatedReason,
91
+ originClientId?: string,
48
92
  ): void {
49
- broadcastMessage({
50
- type: "conversation_list_invalidated",
51
- reason,
52
- });
53
- void publishSyncInvalidation([SYNC_TAGS.conversationsList]);
93
+ broadcastConversationListInvalidatedToMacos(reason);
94
+ void publishSyncInvalidation([SYNC_TAGS.conversationsList], originClientId);
54
95
  }
55
96
 
56
97
  export function publishConversationMessagesChanged(
57
98
  conversationId: string,
99
+ originClientId?: string,
58
100
  ): void {
59
- void publishSyncInvalidation([conversationMessagesSyncTag(conversationId)]);
101
+ void publishSyncInvalidation(
102
+ [conversationMessagesSyncTag(conversationId)],
103
+ originClientId,
104
+ );
60
105
  }
61
106
 
62
107
  export function publishConversationListAndMetadataChanged(
63
108
  reason: ConversationListInvalidatedReason,
64
109
  conversationIds: string | string[],
110
+ originClientId?: string,
65
111
  ): void {
66
112
  const ids = Array.isArray(conversationIds)
67
113
  ? conversationIds
68
114
  : [conversationIds];
69
- broadcastMessage({
70
- type: "conversation_list_invalidated",
71
- reason,
72
- });
73
- void publishSyncInvalidation([
74
- SYNC_TAGS.conversationsList,
75
- ...ids.map((conversationId) => conversationMetadataSyncTag(conversationId)),
76
- ]);
115
+ broadcastConversationListInvalidatedToMacos(reason);
116
+
117
+ // Shape-changing reasons (`created`, `deleted`, `reordered`) add or
118
+ // remove rows or change the order of the paginated window — web must
119
+ // refetch the list, so include the `conversationsList` umbrella tag.
120
+ // Content-only reasons (`renamed`, `seen_changed`) modify an existing
121
+ // row; web consumes the per-conversation metadata tag and GET-and-
122
+ // patches the single row, avoiding the full paginated list drain
123
+ // (`limit=50&offset=0..N` × foreground + background — ~14 requests
124
+ // per write at a few hundred conversations).
125
+ const tags: string[] = ids.map((conversationId) =>
126
+ conversationMetadataSyncTag(conversationId),
127
+ );
128
+ if (SHAPE_CHANGING_REASONS.has(reason)) {
129
+ tags.unshift(SYNC_TAGS.conversationsList);
130
+ }
131
+ void publishSyncInvalidation(tags, originClientId);
77
132
  }
78
133
 
79
134
  export function publishConversationTitleChanged(
80
135
  conversationId: string,
81
136
  title: string,
137
+ originClientId?: string,
82
138
  ): void {
83
139
  broadcastMessage(
84
140
  {
@@ -88,18 +144,27 @@ export function publishConversationTitleChanged(
88
144
  },
89
145
  conversationId,
90
146
  );
91
- void publishSyncInvalidation([
92
- SYNC_TAGS.conversationsList,
93
- conversationMetadataSyncTag(conversationId),
94
- ]);
147
+ // Renames are content-only — the paired typed `conversation_title_updated`
148
+ // event already carries the new title and patches the row in place on
149
+ // web; macOS receives the per-interface `conversation_list_invalidated`
150
+ // emitted from `broadcastMessage` (see `assistant-event-hub.ts`). The
151
+ // `sync_changed` metadata tag is included as a belt-and-suspenders signal
152
+ // for any sibling-tab consumer that missed the typed event.
153
+ void publishSyncInvalidation(
154
+ [conversationMetadataSyncTag(conversationId)],
155
+ originClientId,
156
+ );
95
157
  }
96
158
 
97
- export function publishConversationInferenceProfileChanged(params: {
98
- conversationId: string;
99
- profile: string | null;
100
- sessionId?: string | null;
101
- expiresAt?: number | null;
102
- }): void {
159
+ export function publishConversationInferenceProfileChanged(
160
+ params: {
161
+ conversationId: string;
162
+ profile: string | null;
163
+ sessionId?: string | null;
164
+ expiresAt?: number | null;
165
+ },
166
+ originClientId?: string,
167
+ ): void {
103
168
  broadcastMessage(
104
169
  {
105
170
  type: "conversation_inference_profile_updated",
@@ -110,8 +175,11 @@ export function publishConversationInferenceProfileChanged(params: {
110
175
  },
111
176
  params.conversationId,
112
177
  );
113
- void publishSyncInvalidation([
114
- SYNC_TAGS.conversationsList,
115
- conversationMetadataSyncTag(params.conversationId),
116
- ]);
178
+ void publishSyncInvalidation(
179
+ [
180
+ SYNC_TAGS.conversationsList,
181
+ conversationMetadataSyncTag(params.conversationId),
182
+ ],
183
+ originClientId,
184
+ );
117
185
  }
@@ -102,4 +102,53 @@ describe("sync publisher", () => {
102
102
  subscription.dispose();
103
103
  }
104
104
  });
105
+
106
+ test("forwards originClientId when provided", async () => {
107
+ const received: AssistantEvent[] = [];
108
+ const subscription = assistantEventHub.subscribe({
109
+ type: "process",
110
+ callback: (event) => {
111
+ received.push(event);
112
+ },
113
+ });
114
+
115
+ try {
116
+ const message = await publishSyncInvalidation(
117
+ [SYNC_TAGS.assistantAvatar],
118
+ "client-abc",
119
+ );
120
+
121
+ await waitFor(() => received.length === 1);
122
+
123
+ expect(message).toEqual({
124
+ type: "sync_changed",
125
+ tags: [SYNC_TAGS.assistantAvatar],
126
+ originClientId: "client-abc",
127
+ });
128
+ expect(received[0].message).toEqual(message);
129
+ } finally {
130
+ subscription.dispose();
131
+ }
132
+ });
133
+
134
+ test("omits originClientId when not provided", async () => {
135
+ const received: AssistantEvent[] = [];
136
+ const subscription = assistantEventHub.subscribe({
137
+ type: "process",
138
+ callback: (event) => {
139
+ received.push(event);
140
+ },
141
+ });
142
+
143
+ try {
144
+ const message = await publishSyncInvalidation([SYNC_TAGS.assistantAvatar]);
145
+
146
+ await waitFor(() => received.length === 1);
147
+
148
+ expect("originClientId" in message).toBe(false);
149
+ expect(received[0].message).toEqual(message);
150
+ } finally {
151
+ subscription.dispose();
152
+ }
153
+ });
105
154
  });
@@ -10,8 +10,9 @@ const log = getLogger("sync-publisher");
10
10
 
11
11
  export async function publishSyncInvalidation(
12
12
  tags: SyncInvalidationTag[],
13
+ originClientId?: string,
13
14
  ): Promise<SyncChangedMessage> {
14
- const message = buildSyncChangedMessage(tags);
15
+ const message = buildSyncChangedMessage(tags, originClientId);
15
16
  try {
16
17
  broadcastMessage(message);
17
18
  } catch (err) {
@@ -147,6 +147,7 @@ export function createOrReuseToolGrantRequest(
147
147
  sourceEventName: "guardian.question",
148
148
  sourceChannel: sourceChannel as NotificationSourceChannel,
149
149
  sourceContextId: conversationId,
150
+ requiresConversation: true,
150
151
  attentionHints: {
151
152
  requiresAction: true,
152
153
  urgency: "high",