@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
@@ -92,45 +92,35 @@ mock.module("../skills/tool-manifest.js", () => ({
92
92
  }));
93
93
 
94
94
  mock.module("../tools/skills/skill-tool-factory.js", () => ({
95
+ // Mirrors the real factory: no skillId in/out — ownership is recorded by
96
+ // the registry at `registerSkillTools(skillId, tools)` time.
95
97
  createSkillToolsFromManifest: (
96
98
  entries: SkillToolManifest["tools"],
97
- skillId: string,
98
99
  _skillDir: string,
99
- versionHash: string,
100
- bundled?: boolean,
100
+ _versionHash: string,
101
+ _bundled?: boolean,
101
102
  ): Tool[] => {
102
103
  return entries.map((entry) => ({
103
104
  name: entry.name,
104
105
  description: entry.description,
105
106
  category: entry.category,
106
107
  defaultRiskLevel: RiskLevel.Medium,
107
- origin: "skill" as const,
108
- ownerSkillId: skillId,
109
- ownerSkillVersionHash: versionHash,
110
- ownerSkillBundled: bundled ?? undefined,
111
- getDefinition: () => ({
112
- name: entry.name,
113
- description: entry.description,
114
- input_schema: entry.input_schema as object,
115
- }),
108
+ executionTarget: "sandbox" as const,
109
+ input_schema: entry.input_schema as object,
116
110
  execute: async () => ({ content: "", isError: false }),
117
111
  }));
118
112
  },
119
113
  }));
120
114
 
121
115
  mock.module("../tools/registry.js", () => ({
122
- registerSkillTools: (tools: Tool[]) => {
123
- const skillIds = new Set<string>();
124
- for (const tool of tools) {
125
- const skillId = tool.ownerSkillId!;
126
- skillIds.add(skillId);
127
- const existing = mockRegisteredTools.get(skillId) ?? [];
128
- existing.push(tool);
129
- mockRegisteredTools.set(skillId, existing);
130
- }
131
- for (const id of skillIds) {
132
- mockSkillRefCount.set(id, (mockSkillRefCount.get(id) ?? 0) + 1);
133
- }
116
+ // Matches the new signature: `registerSkillTools(skillId, tools)`. The
117
+ // skillId comes from the caller (conversation-skill-tools) and is the
118
+ // sole source of truth for ownership.
119
+ registerSkillTools: (skillId: string, tools: Tool[]) => {
120
+ const existing = mockRegisteredTools.get(skillId) ?? [];
121
+ existing.push(...tools);
122
+ mockRegisteredTools.set(skillId, existing);
123
+ mockSkillRefCount.set(skillId, (mockSkillRefCount.get(skillId) ?? 0) + 1);
134
124
  return tools;
135
125
  },
136
126
  unregisterSkillTools: (skillId: string) => {
@@ -154,6 +144,22 @@ mock.module("../tools/registry.js", () => ({
154
144
  }
155
145
  return found;
156
146
  },
147
+ // Mirrors the registry's `ownersByName` accessor: the mock derives the
148
+ // owning skillId from `mockRegisteredTools` (which is keyed by skillId)
149
+ // and reports it back as the `OwnerInfo` shape production callers expect.
150
+ getToolOwner: (
151
+ name: string,
152
+ ): { kind: "skill" | "plugin" | "mcp"; id: string } | undefined => {
153
+ let ownerSkillId: string | undefined;
154
+ for (const [skillId, tools] of mockRegisteredTools.entries()) {
155
+ for (const tool of tools) {
156
+ if (tool.name === name) ownerSkillId = skillId;
157
+ }
158
+ }
159
+ return ownerSkillId === undefined
160
+ ? undefined
161
+ : { kind: "skill", id: ownerSkillId };
162
+ },
157
163
  getSkillToolNames: () => {
158
164
  const names: string[] = [];
159
165
  for (const tools of mockRegisteredTools.values()) {
@@ -1733,11 +1739,11 @@ describe("bundled skill: app-builder", () => {
1733
1739
  expect(tools).toBeDefined();
1734
1740
  expect(tools!.length).toBe(4);
1735
1741
 
1736
- // All tools should have skill origin metadata
1737
- for (const tool of tools!) {
1738
- expect(tool.origin).toBe("skill");
1739
- expect(tool.ownerSkillId).toBe("app-builder");
1740
- }
1742
+ // Ownership is asserted by the fact that
1743
+ // `mockRegisteredTools.get("app-builder")` returned the tools — i.e. the
1744
+ // mock `registerSkillTools(skillId, tools)` was called with skillId
1745
+ // "app-builder", which is what the registry would record in production.
1746
+ // The Tool object itself no longer carries a kind/origin field.
1741
1747
  });
1742
1748
  });
1743
1749
 
@@ -2232,7 +2238,7 @@ describe("hash change re-prompt regressions (PR 35)", () => {
2232
2238
  expect(sessionState.get("oncall")).toBe("v2:oncall-edited");
2233
2239
  });
2234
2240
 
2235
- test("registered tools carry updated ownerSkillId after hash change re-registration", () => {
2241
+ test("registered tools carry updated owner after hash change re-registration", () => {
2236
2242
  mockCatalog = [makeSkill("deploy")];
2237
2243
  mockManifests = { deploy: makeManifest(["deploy_run"]) };
2238
2244
  mockVersionHashes = { deploy: "v1:pre-edit" };
@@ -2241,12 +2247,14 @@ describe("hash change re-prompt regressions (PR 35)", () => {
2241
2247
  ...skillLoadMessages('<loaded_skill id="deploy" />'),
2242
2248
  ];
2243
2249
 
2244
- // Turn 1
2250
+ // Turn 1: ownership is asserted by the mock registry's keying — the
2251
+ // tools landing under skillId "deploy" in `mockRegisteredTools` means
2252
+ // `registerSkillTools("deploy", tools)` was called, which is the only
2253
+ // path that records ownership in the real registry.
2245
2254
  projectSkillTools(history, { previouslyActiveSkillIds: sessionState });
2246
2255
  const toolsV1 = mockRegisteredTools.get("deploy");
2247
2256
  expect(toolsV1).toBeDefined();
2248
2257
  expect(toolsV1!.length).toBe(1);
2249
- expect(toolsV1![0].ownerSkillId).toBe("deploy");
2250
2258
 
2251
2259
  // Edit
2252
2260
  mockVersionHashes = { deploy: "v2:post-edit" };
@@ -2256,121 +2264,6 @@ describe("hash change re-prompt regressions (PR 35)", () => {
2256
2264
  const toolsV2 = mockRegisteredTools.get("deploy");
2257
2265
  expect(toolsV2).toBeDefined();
2258
2266
  expect(toolsV2!.length).toBeGreaterThanOrEqual(1);
2259
- expect(toolsV2![0].ownerSkillId).toBe("deploy");
2260
- });
2261
- });
2262
-
2263
- // ---------------------------------------------------------------------------
2264
- // Version hash plumbing regression tests
2265
- // Verify that createSkillToolsFromManifest receives the computed hash and
2266
- // that projected tools carry ownerSkillVersionHash, which downstream
2267
- // components (executor.ts) use to build policy context.
2268
- // ---------------------------------------------------------------------------
2269
-
2270
- describe("version hash plumbing to projected tools", () => {
2271
- let sessionState: Map<string, string>;
2272
-
2273
- beforeEach(() => {
2274
- mockCatalog = [];
2275
- mockManifests = {};
2276
- mockRegisteredTools = new Map();
2277
- mockUnregisteredSkillIds = [];
2278
- mockSkillRefCount = new Map();
2279
- mockVersionHashes = {};
2280
- mockVersionHashErrors = new Set();
2281
- sessionState = new Map<string, string>();
2282
- });
2283
-
2284
- test("projected tools carry ownerSkillVersionHash matching the computed hash", () => {
2285
- mockCatalog = [makeSkill("deploy")];
2286
- mockManifests = { deploy: makeManifest(["deploy_run", "deploy_status"]) };
2287
- mockVersionHashes = { deploy: "v1:secure-hash-abc" };
2288
-
2289
- const history: Message[] = [
2290
- ...skillLoadMessages('<loaded_skill id="deploy" />'),
2291
- ];
2292
-
2293
- projectSkillTools(history, { previouslyActiveSkillIds: sessionState });
2294
-
2295
- const tools = mockRegisteredTools.get("deploy");
2296
- expect(tools).toBeDefined();
2297
- expect(tools!.length).toBe(2);
2298
-
2299
- // Every tool created for this skill must carry the version hash
2300
- for (const tool of tools!) {
2301
- expect(tool.ownerSkillVersionHash).toBe("v1:secure-hash-abc");
2302
- }
2303
- });
2304
-
2305
- test("after hash change re-registration, new tools carry the updated hash", () => {
2306
- mockCatalog = [makeSkill("deploy")];
2307
- mockManifests = { deploy: makeManifest(["deploy_run"]) };
2308
- mockVersionHashes = { deploy: "v1:hash-before" };
2309
-
2310
- const history: Message[] = [
2311
- ...skillLoadMessages('<loaded_skill id="deploy" />'),
2312
- ];
2313
-
2314
- // Turn 1: register with original hash
2315
- projectSkillTools(history, { previouslyActiveSkillIds: sessionState });
2316
- const toolsV1 = mockRegisteredTools.get("deploy");
2317
- expect(toolsV1).toBeDefined();
2318
- expect(toolsV1![0].ownerSkillVersionHash).toBe("v1:hash-before");
2319
-
2320
- // Simulate file edit — hash changes
2321
- mockVersionHashes = { deploy: "v2:hash-after" };
2322
-
2323
- // Turn 2: re-registration with new hash
2324
- projectSkillTools(history, { previouslyActiveSkillIds: sessionState });
2325
- const toolsV2 = mockRegisteredTools.get("deploy");
2326
- expect(toolsV2).toBeDefined();
2327
-
2328
- // The most recently registered tool should carry the new hash
2329
- const lastTool = toolsV2![toolsV2!.length - 1];
2330
- expect(lastTool.ownerSkillVersionHash).toBe("v2:hash-after");
2331
- });
2332
-
2333
- test("tools for multiple co-active skills each carry their own version hash", () => {
2334
- mockCatalog = [makeSkill("deploy"), makeSkill("oncall")];
2335
- mockManifests = {
2336
- deploy: makeManifest(["deploy_run"]),
2337
- oncall: makeManifest(["oncall_page"]),
2338
- };
2339
- mockVersionHashes = {
2340
- deploy: "v1:deploy-hash-123",
2341
- oncall: "v1:oncall-hash-456",
2342
- };
2343
-
2344
- const history: Message[] = [
2345
- ...skillLoadMessages('<loaded_skill id="deploy" />'),
2346
- ...skillLoadMessages('<loaded_skill id="oncall" />'),
2347
- ];
2348
-
2349
- projectSkillTools(history, { previouslyActiveSkillIds: sessionState });
2350
-
2351
- const deployTools = mockRegisteredTools.get("deploy");
2352
- expect(deployTools).toBeDefined();
2353
- expect(deployTools![0].ownerSkillVersionHash).toBe("v1:deploy-hash-123");
2354
-
2355
- const oncallTools = mockRegisteredTools.get("oncall");
2356
- expect(oncallTools).toBeDefined();
2357
- expect(oncallTools![0].ownerSkillVersionHash).toBe("v1:oncall-hash-456");
2358
- });
2359
-
2360
- test("default hash is used and plumbed when no explicit hash override is set", () => {
2361
- mockCatalog = [makeSkill("deploy")];
2362
- mockManifests = { deploy: makeManifest(["deploy_run"]) };
2363
- // No mockVersionHashes override — mock returns 'v1:default-hash-deploy'
2364
-
2365
- const history: Message[] = [
2366
- ...skillLoadMessages('<loaded_skill id="deploy" />'),
2367
- ];
2368
-
2369
- projectSkillTools(history, { previouslyActiveSkillIds: sessionState });
2370
-
2371
- const tools = mockRegisteredTools.get("deploy");
2372
- expect(tools).toBeDefined();
2373
- expect(tools![0].ownerSkillVersionHash).toBe("v1:default-hash-deploy");
2374
2267
  });
2375
2268
  });
2376
2269
 
@@ -135,6 +135,8 @@ mock.module("../memory/conversation-crud.js", () => ({
135
135
  updateConversationTitle: () => {},
136
136
  getMessageById: () => null,
137
137
  getLastUserTimestampBefore: () => 0,
138
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
139
+ updateMessageContent: mock(() => {}),
138
140
  }));
139
141
 
140
142
  mock.module("../memory/conversation-queries.js", () => ({
@@ -204,7 +206,7 @@ mock.module("../config/skill-state.js", () => ({
204
206
  interface PendingRun {
205
207
  resolve: (history: Message[]) => void;
206
208
  messages: Message[];
207
- onEvent: (event: AgentEvent) => void;
209
+ onEvent: (event: AgentEvent) => void | Promise<void>;
208
210
  }
209
211
 
210
212
  let pendingRuns: PendingRun[] = [];
@@ -223,7 +225,7 @@ mock.module("../agent/loop.js", () => ({
223
225
  }
224
226
  async run(
225
227
  messages: Message[],
226
- onEvent: (event: AgentEvent) => void,
228
+ onEvent: (event: AgentEvent) => void | Promise<void>,
227
229
  _signal?: AbortSignal,
228
230
  _requestId?: string,
229
231
  _onCheckpoint?: (
@@ -333,21 +335,24 @@ async function waitForPendingRun(
333
335
  }
334
336
  }
335
337
 
336
- function resolveRun(index: number) {
338
+ async function resolveRun(index: number) {
337
339
  const run = pendingRuns[index];
338
340
  if (!run) throw new Error(`No pending run at index ${index}`);
339
341
  const assistantMsg: Message = {
340
342
  role: "assistant",
341
343
  content: [{ type: "text", text: `reply-${index}` }],
342
344
  };
343
- run.onEvent({
345
+ // Prime the assistant row anchor — production code emits this from
346
+ // `AgentLoop.run` just before `provider.sendMessage`.
347
+ await run.onEvent({ type: "llm_call_started" });
348
+ await run.onEvent({
344
349
  type: "usage",
345
350
  inputTokens: 10,
346
351
  outputTokens: 5,
347
352
  model: "mock",
348
353
  providerDurationMs: 100,
349
354
  });
350
- run.onEvent({ type: "message_complete", message: assistantMsg });
355
+ await run.onEvent({ type: "message_complete", message: assistantMsg });
351
356
  run.resolve([...run.messages, assistantMsg]);
352
357
  }
353
358
 
@@ -398,17 +403,20 @@ describe("Conversation queue — slash-like messages pass through to agent loop"
398
403
 
399
404
  // Enqueue a slash-like passthrough and a normal passthrough after it.
400
405
  // Both resolve to passthrough, so the batch builder groups them into one run.
401
- conversation.enqueueMessage(
402
- "/not-a-skill",
403
- [],
404
- (e) => eventsSlash.push(e),
405
- "req-slash",
406
- );
407
- conversation.enqueueMessage("msg-3", [], (e) => events3.push(e), "req-3");
406
+ conversation.enqueueMessage({
407
+ content: "/not-a-skill",
408
+ onEvent: (e) => eventsSlash.push(e),
409
+ requestId: "req-slash",
410
+ });
411
+ conversation.enqueueMessage({
412
+ content: "msg-3",
413
+ onEvent: (e) => events3.push(e),
414
+ requestId: "req-3",
415
+ });
408
416
  expect(conversation.getQueueDepth()).toBe(2);
409
417
 
410
418
  // Complete first run — drain pulls both queued messages into one batched run.
411
- resolveRun(0);
419
+ await resolveRun(0);
412
420
  await p1;
413
421
  await waitForPendingRun(2);
414
422
 
@@ -419,8 +427,46 @@ describe("Conversation queue — slash-like messages pass through to agent loop"
419
427
  // Exactly 2 runs total: msg-1 + batched [/not-a-skill, msg-3].
420
428
  expect(pendingRuns.length).toBe(2);
421
429
 
430
+ await resolveRun(1);
431
+ await new Promise((r) => setTimeout(r, 50));
432
+ });
433
+
434
+ test("batched queued messages with the same event sink do not duplicate assistant stream events", async () => {
435
+ const conversation = makeConversation();
436
+ await conversation.loadFromDb();
437
+
438
+ const sharedEvents: ServerMessage[] = [];
439
+ const sharedOnEvent = (event: ServerMessage) => sharedEvents.push(event);
440
+
441
+ const p1 = conversation.processMessage("msg-1", [], () => {}, "req-1");
442
+ await waitForPendingRun(1);
443
+
444
+ conversation.enqueueMessage({
445
+ content: "msg-2",
446
+ onEvent: sharedOnEvent,
447
+ requestId: "req-2",
448
+ });
449
+ conversation.enqueueMessage({
450
+ content: "msg-3",
451
+ onEvent: sharedOnEvent,
452
+ requestId: "req-3",
453
+ });
454
+
455
+ resolveRun(0);
456
+ await p1;
457
+ await waitForPendingRun(2);
458
+
459
+ expect(
460
+ sharedEvents.filter((event) => event.type === "message_dequeued"),
461
+ ).toHaveLength(2);
462
+
463
+ sharedEvents.length = 0;
422
464
  resolveRun(1);
423
465
  await new Promise((r) => setTimeout(r, 50));
466
+
467
+ expect(
468
+ sharedEvents.filter((event) => event.type === "message_complete"),
469
+ ).toHaveLength(1);
424
470
  });
425
471
 
426
472
  test("queued skill-name slash passes through as-is", async () => {
@@ -440,15 +486,14 @@ describe("Conversation queue — slash-like messages pass through to agent loop"
440
486
  await waitForPendingRun(1);
441
487
 
442
488
  // Enqueue a slash command that matches a skill name — still passes through
443
- conversation.enqueueMessage(
444
- "/start-the-day",
445
- [],
446
- (e) => eventsSlash.push(e),
447
- "req-slash",
448
- );
489
+ conversation.enqueueMessage({
490
+ content: "/start-the-day",
491
+ onEvent: (e) => eventsSlash.push(e),
492
+ requestId: "req-slash",
493
+ });
449
494
 
450
495
  // Complete first run — triggers drain
451
- resolveRun(0);
496
+ await resolveRun(0);
452
497
  await p1;
453
498
  await waitForPendingRun(2);
454
499
 
@@ -463,7 +508,7 @@ describe("Conversation queue — slash-like messages pass through to agent loop"
463
508
  // Content passes through as-is — no rewriting
464
509
  expect(text).toContain("/start-the-day");
465
510
 
466
- resolveRun(1);
511
+ await resolveRun(1);
467
512
  await new Promise((r) => setTimeout(r, 50));
468
513
  });
469
514
 
@@ -483,18 +528,25 @@ describe("Conversation queue — slash-like messages pass through to agent loop"
483
528
  // batch builder stops at "hi" (length-1 batch → drainSingleMessage). Then
484
529
  // /compact takes its short-circuit path (no new runAgentLoop), and "bye"
485
530
  // drains as its own run.
486
- conversation.enqueueMessage("hi", [], (e) => eventsHi.push(e), "req-hi");
487
- conversation.enqueueMessage(
488
- "/compact",
489
- [],
490
- (e) => eventsCompact.push(e),
491
- "req-compact",
492
- );
493
- conversation.enqueueMessage("bye", [], (e) => eventsBye.push(e), "req-bye");
531
+ conversation.enqueueMessage({
532
+ content: "hi",
533
+ onEvent: (e) => eventsHi.push(e),
534
+ requestId: "req-hi",
535
+ });
536
+ conversation.enqueueMessage({
537
+ content: "/compact",
538
+ onEvent: (e) => eventsCompact.push(e),
539
+ requestId: "req-compact",
540
+ });
541
+ conversation.enqueueMessage({
542
+ content: "bye",
543
+ onEvent: (e) => eventsBye.push(e),
544
+ requestId: "req-bye",
545
+ });
494
546
  expect(conversation.getQueueDepth()).toBe(3);
495
547
 
496
548
  // Resolve msg-1 → drain pulls only "hi" (batch builder stops at /compact).
497
- resolveRun(0);
549
+ await resolveRun(0);
498
550
  await p1;
499
551
  await waitForPendingRun(2);
500
552
 
@@ -503,14 +555,14 @@ describe("Conversation queue — slash-like messages pass through to agent loop"
503
555
 
504
556
  // Resolve "hi" → /compact short-circuits without a new runAgentLoop, then
505
557
  // drains "bye" as its own run.
506
- resolveRun(1);
558
+ await resolveRun(1);
507
559
  await waitForPendingRun(3);
508
560
 
509
561
  expect(eventsCompact.some((e) => e.type === "message_complete")).toBe(true);
510
562
  expect(eventsBye.some((e) => e.type === "message_dequeued")).toBe(true);
511
563
  expect(pendingRuns.length).toBe(3);
512
564
 
513
- resolveRun(2);
565
+ await resolveRun(2);
514
566
  await new Promise((r) => setTimeout(r, 50));
515
567
  });
516
568
 
@@ -136,6 +136,8 @@ mock.module("../memory/conversation-crud.js", () => ({
136
136
  updateConversationTitle: () => {},
137
137
  getMessageById: () => null,
138
138
  getLastUserTimestampBefore: () => 0,
139
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
140
+ updateMessageContent: mock(() => {}),
139
141
  }));
140
142
 
141
143
  mock.module("../memory/conversation-queries.js", () => ({
@@ -254,6 +256,9 @@ mock.module("../agent/loop.js", () => ({
254
256
  checkpoint: CheckpointInfo,
255
257
  ) => CheckpointDecision | Promise<CheckpointDecision>,
256
258
  ): Promise<Message[]> {
259
+ // Prime the assistant row anchor — production code emits this from
260
+ // `AgentLoop.run` just before `provider.sendMessage`.
261
+ await onEvent({ type: "llm_call_started" });
257
262
  agentLoopRunCalled = true;
258
263
  const assistantMsg: Message = {
259
264
  role: "assistant",
@@ -150,6 +150,7 @@ mock.module("../memory/conversation-crud.js", () => ({
150
150
  addMessage: () => ({ id: `msg-${Date.now()}` }),
151
151
  updateConversationUsage: () => {},
152
152
  updateConversationTitle: () => {},
153
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
153
154
  }));
154
155
 
155
156
  mock.module("../memory/conversation-queries.js", () => ({
@@ -334,7 +334,7 @@ describe("attachment orphan cleanup", () => {
334
334
  const stored = uploadAttachment("doc.pdf", "application/pdf", "JVBER");
335
335
  linkAttachmentToMessage(msg.id, stored.id, 0);
336
336
 
337
- clearAll();
337
+ await clearAll();
338
338
 
339
339
  const raw = (
340
340
  getDb() as unknown as {
@@ -182,6 +182,52 @@ describe("surface action delivery to assistant", () => {
182
182
  );
183
183
  });
184
184
 
185
+ test("history-restored relay action uses stored prompt data and can complete the surface", async () => {
186
+ const ctx = makeContext();
187
+ const surfaceId = "max-token-surface";
188
+ ctx.surfaceState.set(surfaceId, {
189
+ surfaceType: "card",
190
+ data: {
191
+ title: "Response limit reached",
192
+ body: "Continue from where the assistant stopped.",
193
+ },
194
+ actions: [
195
+ {
196
+ id: "relay_prompt",
197
+ label: "Continue",
198
+ style: "primary",
199
+ data: {
200
+ prompt: "Continue from where you stopped.",
201
+ _completeSurface: true,
202
+ _completionSummary: "Continue",
203
+ },
204
+ },
205
+ ],
206
+ });
207
+
208
+ await handleSurfaceAction(ctx, surfaceId, "relay_prompt");
209
+
210
+ expect(ctx.processMessageCalls).toHaveLength(1);
211
+ expect(ctx.processMessageCalls[0]!.content).toBe(
212
+ "Continue from where you stopped.",
213
+ );
214
+ expect(
215
+ broadcastedMessages.some(
216
+ (msg) =>
217
+ msg.type === "ui_surface_complete" &&
218
+ msg.surfaceId === surfaceId &&
219
+ msg.summary === "Continue",
220
+ ),
221
+ ).toBe(true);
222
+ expect(
223
+ broadcastedMessages.some(
224
+ (msg) =>
225
+ msg.type === "user_message_echo" &&
226
+ msg.text === "Continue from where you stopped.",
227
+ ),
228
+ ).toBe(true);
229
+ });
230
+
185
231
  test("action on history-restored surface (no pending) still processes", async () => {
186
232
  const sent: ServerMessage[] = [];
187
233
  const ctx = makeContext(sent);
@@ -29,6 +29,7 @@ mock.module("../memory/conversation-crud.js", () => ({
29
29
  getMessages: (conversationId: string) => getMessagesImpl(conversationId),
30
30
  updateMessageContent: (id: string, content: string) =>
31
31
  updateMessageContentSpy(id, content),
32
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
32
33
  }));
33
34
 
34
35
  // Imports must come AFTER mock.module so the surface module picks up
@@ -72,9 +72,12 @@ function createMockContext(
72
72
  hostCuProxy: undefined,
73
73
  hasNoClient: overrides?.hasNoClient ?? false,
74
74
  isProcessing: () => false,
75
- enqueueMessage: (content, _attachments, _onEvent, requestId) => {
76
- const resolvedId = requestId ?? "mock-request-id";
77
- enqueuedMessages.push({ content, requestId: resolvedId });
75
+ enqueueMessage: (options) => {
76
+ const resolvedId = options.requestId ?? "mock-request-id";
77
+ enqueuedMessages.push({
78
+ content: options.content,
79
+ requestId: resolvedId,
80
+ });
78
81
  return { queued: false, requestId: resolvedId };
79
82
  },
80
83
  getQueueDepth: () => 0,
@@ -63,9 +63,12 @@ function createMockContext(
63
63
  hostCuProxy: undefined,
64
64
  hasNoClient: overrides?.hasNoClient ?? false,
65
65
  isProcessing: () => false,
66
- enqueueMessage: (content, _attachments, _onEvent, requestId) => {
67
- const resolvedId = requestId ?? "mock-request-id";
68
- enqueuedMessages.push({ content, requestId: resolvedId });
66
+ enqueueMessage: (options) => {
67
+ const resolvedId = options.requestId ?? "mock-request-id";
68
+ enqueuedMessages.push({
69
+ content: options.content,
70
+ requestId: resolvedId,
71
+ });
69
72
  return { queued: false, requestId: resolvedId };
70
73
  },
71
74
  getQueueDepth: () => 0,
@@ -45,9 +45,9 @@ function makeContext(opts?: {
45
45
  surfaceActionRequestIds: new Set<string>(),
46
46
  currentTurnSurfaces: [],
47
47
  isProcessing: () => false,
48
- enqueueMessage: (content, _attachments, _onEvent, requestId) => {
49
- const resolvedId = requestId ?? "mock-request-id";
50
- enqueueCalls.push({ content, requestId: resolvedId });
48
+ enqueueMessage: (options) => {
49
+ const resolvedId = options.requestId ?? "mock-request-id";
50
+ enqueueCalls.push({ content: options.content, requestId: resolvedId });
51
51
  return { queued: false, requestId: resolvedId };
52
52
  },
53
53
  getQueueDepth: () => 0,
@@ -64,25 +64,15 @@ function makeContext(): SurfaceConversationContext & {
64
64
  surfaceActionRequestIds: new Set<string>(),
65
65
  currentTurnSurfaces: [],
66
66
  isProcessing: () => false,
67
- enqueueMessage: (
68
- content,
69
- attachments,
70
- _onEvent,
71
- requestId,
72
- surfaceId,
73
- _currentPage,
74
- _metadata,
75
- _options,
76
- displayContent,
77
- ) => {
67
+ enqueueMessage: (options) => {
78
68
  enqueueCalls.push({
79
- content,
80
- requestId: requestId ?? "enq-req",
81
- attachments,
82
- surfaceId,
83
- displayContent,
69
+ content: options.content,
70
+ requestId: options.requestId ?? "enq-req",
71
+ attachments: options.attachments ?? [],
72
+ surfaceId: options.activeSurfaceId,
73
+ displayContent: options.displayContent,
84
74
  });
85
- return { queued: false, requestId: requestId ?? "enq-req" };
75
+ return { queued: false, requestId: options.requestId ?? "enq-req" };
86
76
  },
87
77
  getQueueDepth: () => 0,
88
78
  processMessage: async (