@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
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import type pino from "pino";
10
+ import { v4 as uuid } from "uuid";
10
11
 
11
12
  import type { AgentEvent } from "../agent/loop.js";
12
13
  import type {
@@ -16,12 +17,16 @@ import type {
16
17
  import { getConfig } from "../config/loader.js";
17
18
  import { recordEstimate } from "../context/estimator-calibration.js";
18
19
  import { getCalibrationProviderKey } from "../context/token-estimator.js";
20
+ import { projectAssistantMessage } from "../memory/conversation-attention-store.js";
19
21
  import {
22
+ deleteMessageById,
20
23
  getConversation,
21
24
  getMessageById,
25
+ messageMetadataSchema,
22
26
  provenanceFromTrustContext,
23
27
  updateMessageContent,
24
28
  } from "../memory/conversation-crud.js";
29
+ import { indexMessageNow } from "../memory/indexer.js";
25
30
  import {
26
31
  backfillMessageIdOnLogs,
27
32
  buildProviderErrorResponsePayload,
@@ -40,15 +45,20 @@ import { defaultPersistenceTerminal } from "../plugins/defaults/persistence.js";
40
45
  import { DEFAULT_TIMEOUTS, runPipeline } from "../plugins/pipeline.js";
41
46
  import { getMiddlewaresFor } from "../plugins/registry.js";
42
47
  import type {
43
- PersistAddResult,
44
48
  PersistArgs,
49
+ PersistReserveResult,
45
50
  PersistResult,
46
51
  TurnContext,
47
52
  } from "../plugins/types.js";
48
53
  import type { ContentBlock, ImageContent } from "../providers/types.js";
49
54
  import { isContextOverflowError } from "../providers/types.js";
55
+ import { publishSyncInvalidation } from "../runtime/sync/sync-publisher.js";
50
56
  import { redactSecrets } from "../security/secret-scanner.js";
51
57
  import { extractDomain } from "../tools/network/domain-normalize.js";
58
+ import {
59
+ buildPricingUsage,
60
+ resolveStructuredPricing,
61
+ } from "../usage/pricing.js";
52
62
  import { ProviderError } from "../util/errors.js";
53
63
  import { faviconUrlForDomain } from "../util/favicon.js";
54
64
  import { getLogger } from "../util/logger.js";
@@ -62,10 +72,17 @@ import {
62
72
  buildConversationErrorMessage,
63
73
  classifyConversationError,
64
74
  isContextTooLarge,
75
+ maxTokensReachedClassification,
65
76
  } from "./conversation-error.js";
66
77
  import { isProviderOrderingError } from "./conversation-slash.js";
67
78
  import { resolveTurnTimezoneContext } from "./date-context.js";
68
- import type { ServerMessage } from "./message-protocol.js";
79
+ import type {
80
+ CardSurfaceData,
81
+ ServerMessage,
82
+ SurfaceAction,
83
+ UiSurfaceShow,
84
+ } from "./message-protocol.js";
85
+ import { conversationMetadataSyncTag } from "./message-types/sync.js";
69
86
  import type {
70
87
  WebSearchMetadata,
71
88
  WebSearchResultItem,
@@ -144,12 +161,22 @@ export interface EventHandlerState {
144
161
  */
145
162
  contextTooLargeError: unknown;
146
163
  providerErrorUserMessage: string | null;
164
+ lastAssistantMessageId: string | undefined;
147
165
  /**
148
- * First persisted assistant row in this run; history keeps this id when it
149
- * merges tool-turn rows into one display bubble.
166
+ * True when `handleLlmCallStarted` has reserved an empty assistant row
167
+ * that has NOT yet been finalized via `handleMessageComplete`
168
+ * (`op:"updateContent"` + indexing + projection). Used by error/retry
169
+ * paths to detect a stranded reservation that must be cleaned up
170
+ * before the next LLM call reserves a fresh row — without it, every
171
+ * retryable failure (overflow, ordering, image overflow) and every
172
+ * terminal provider rejection would leak an empty assistant bubble
173
+ * into the transcript and mispoint downstream sync/projection.
174
+ *
175
+ * Cleared by `handleMessageComplete` on successful finalize, and by
176
+ * the synthetic-error branch in `conversation-agent-loop.ts` after it
177
+ * absorbs the reserved row into the error message.
150
178
  */
151
- firstAssistantMessageId: string | undefined;
152
- lastAssistantMessageId: string | undefined;
179
+ assistantRowAwaitingFinalization: boolean;
153
180
  readonly pendingToolResults: Map<string, PendingToolResult>;
154
181
  readonly persistedToolUseIds: Set<string>;
155
182
  readonly accumulatedDirectives: DirectiveRequest[];
@@ -249,8 +276,8 @@ export function createEventHandlerState(): EventHandlerState {
249
276
  imageTooLargeDetected: false,
250
277
  contextTooLargeError: null,
251
278
  providerErrorUserMessage: null,
252
- firstAssistantMessageId: undefined,
253
279
  lastAssistantMessageId: undefined,
280
+ assistantRowAwaitingFinalization: false,
254
281
  pendingToolResults: new Map(),
255
282
  persistedToolUseIds: new Set(),
256
283
  accumulatedDirectives: [],
@@ -275,12 +302,6 @@ export function createEventHandlerState(): EventHandlerState {
275
302
  };
276
303
  }
277
304
 
278
- export function getClientDisplayMessageId(
279
- state: EventHandlerState,
280
- ): string | undefined {
281
- return state.firstAssistantMessageId ?? state.lastAssistantMessageId;
282
- }
283
-
284
305
  // ── Shared Helper ────────────────────────────────────────────────────
285
306
 
286
307
  // providerNameOverride should be supplied when the caller already knows the
@@ -319,6 +340,9 @@ function emitLlmCallStartedIfNeeded(
319
340
  // tools the client discards it (extractCodePreview only handles app tools),
320
341
  // so we skip forwarding entirely to avoid transport/decode overhead.
321
342
  const APP_TOOL_NAMES = new Set(["app_create"]);
343
+ const MAX_TOKENS_CONTINUE_PROMPT =
344
+ "Continue from where you stopped. Do not repeat content you've already sent.";
345
+ const MAX_TOKENS_SURFACE_COMPLETION_SUMMARY = "Continue";
322
346
 
323
347
  // ── Friendly Tool Names ──────────────────────────────────────────────
324
348
 
@@ -401,6 +425,133 @@ function resolveAssistantReplyTimestampTimezone(
401
425
  }).effectiveTimezone;
402
426
  }
403
427
 
428
+ /**
429
+ * Assemble the metadata envelope written to the assistant message row.
430
+ *
431
+ * Stamped at reserve time (before `provider.sendMessage`) so the row carries
432
+ * channel provenance from the moment it lands in SQLite, mirroring the
433
+ * snapshot that handleMessageComplete used to compute at end-of-turn. All
434
+ * inputs (channel context, trust context, turnStartedAt) are stable across
435
+ * the LLM call, so building this once at reserve is equivalent to building
436
+ * it at complete. Slack reply rows further stamp a `slackMeta` sub-object —
437
+ * the `channelTs` field stays absent here and is back-filled by
438
+ * `deliverReplyViaCallback` after the gateway returns the ts.
439
+ */
440
+ function buildAssistantChannelMetadata(
441
+ state: EventHandlerState,
442
+ deps: EventHandlerDeps,
443
+ ): Record<string, unknown> {
444
+ const metadata: Record<string, unknown> = {
445
+ ...provenanceFromTrustContext(deps.ctx.trustContext),
446
+ userMessageChannel: deps.turnChannelContext.userMessageChannel,
447
+ assistantMessageChannel: deps.turnChannelContext.assistantMessageChannel,
448
+ userMessageInterface: deps.turnInterfaceContext.userMessageInterface,
449
+ assistantMessageInterface:
450
+ deps.turnInterfaceContext.assistantMessageInterface,
451
+ sentAt: state.turnStartedAt,
452
+ };
453
+
454
+ if (deps.turnChannelContext.assistantMessageChannel === "slack") {
455
+ const channelId = deps.ctx.trustContext?.requesterChatId;
456
+ if (channelId) {
457
+ const threadTs = getThreadTs(deps.ctx.conversationId);
458
+ const timestampTimezone = resolveAssistantReplyTimestampTimezone(
459
+ deps.ctx,
460
+ );
461
+ const timestampTimezoneLabel = formatSlackTimezoneLabel(
462
+ timestampTimezone,
463
+ { nowMs: state.turnStartedAt },
464
+ );
465
+ const partialSlackMeta: Partial<SlackMessageMetadata> = {
466
+ source: "slack",
467
+ eventKind: "message",
468
+ channelId,
469
+ ...(threadTs ? { threadTs } : {}),
470
+ timestampTimezone,
471
+ ...(timestampTimezoneLabel ? { timestampTimezoneLabel } : {}),
472
+ };
473
+ // `channelTs` is filled in by the post-send reconciliation step in
474
+ // `deliverReplyViaCallback`; cast through the Partial to satisfy
475
+ // the writer's type at this pre-send boundary.
476
+ metadata.slackMeta = writeSlackMetadata(
477
+ partialSlackMeta as SlackMessageMetadata,
478
+ );
479
+ }
480
+ }
481
+
482
+ return metadata;
483
+ }
484
+
485
+ /**
486
+ * Reserve an empty assistant row for the LLM call about to begin, stash
487
+ * its id on `state.lastAssistantMessageId`, and announce the boundary on
488
+ * the wire via `assistant_turn_start`.
489
+ *
490
+ * Awaited so the row exists and the client has the anchor id BEFORE any
491
+ * streaming delta arrives — every subsequent `deps.onEvent` in this LLM
492
+ * call stamps `messageId: state.lastAssistantMessageId`, and
493
+ * `handleMessageComplete` flushes the final content to the same row via
494
+ * `op: "updateContent"` instead of inserting a fresh one.
495
+ *
496
+ * Multi-LLM-call agent turns (LLM call → tool execution → LLM call) emit
497
+ * one `llm_call_started` per call, so each LLM call reserves its own row.
498
+ * The read-path `findDisplayTurnEndIndex` collapses consecutive assistant
499
+ * rows for the merged history view, matching today's per-call DB layout.
500
+ */
501
+ export async function handleLlmCallStarted(
502
+ state: EventHandlerState,
503
+ deps: EventHandlerDeps,
504
+ ): Promise<void> {
505
+ // Clean up an orphaned reservation from a previous LLM call in this run
506
+ // that errored before `message_complete` could finalize it. This covers
507
+ // the retryable paths (overflow, ordering, image overflow) where the
508
+ // agent loop re-enters with a fresh `run()` and reserves another row;
509
+ // without this delete the failed-attempt row stays in the transcript as
510
+ // an empty assistant bubble. The finalized-row case is filtered out via
511
+ // the `assistantRowAwaitingFinalization` flag — `handleMessageComplete`
512
+ // clears it after the successful `updateContent`, so the previous call's
513
+ // committed row is never touched here.
514
+ //
515
+ // Direct `deleteMessageById` (not via the `persistence` pipeline) is
516
+ // intentional: a never-finalized reservation has no segments, no
517
+ // attachments, and no observable history — undoing it isn't a real
518
+ // persistence event for plugins to react to, so routing through the
519
+ // pipeline would only widen the mock surface for no observability win.
520
+ if (state.assistantRowAwaitingFinalization && state.lastAssistantMessageId) {
521
+ try {
522
+ deleteMessageById(state.lastAssistantMessageId);
523
+ } catch (err) {
524
+ // Non-fatal: a leaked empty row is preferable to a turn-level throw.
525
+ deps.rlog.warn(
526
+ { err, messageId: state.lastAssistantMessageId },
527
+ "Failed to clean up stranded reserved assistant row before new reservation",
528
+ );
529
+ }
530
+ }
531
+
532
+ const metadata = buildAssistantChannelMetadata(state, deps);
533
+ const reserveResult = (await runPipeline<PersistArgs, PersistResult>(
534
+ "persistence",
535
+ getMiddlewaresFor("persistence"),
536
+ defaultPersistenceTerminal,
537
+ {
538
+ op: "reserve",
539
+ conversationId: deps.ctx.conversationId,
540
+ role: "assistant",
541
+ metadata,
542
+ },
543
+ buildHandlerTurnContext(deps),
544
+ DEFAULT_TIMEOUTS.persistence,
545
+ )) as PersistReserveResult;
546
+ state.lastAssistantMessageId = reserveResult.message.id;
547
+ state.assistantRowAwaitingFinalization = true;
548
+ deps.onEvent({
549
+ type: "assistant_turn_start",
550
+ messageId: reserveResult.message.id,
551
+ conversationId: deps.ctx.conversationId,
552
+ });
553
+ }
554
+
404
555
  // ── Individual Handlers ──────────────────────────────────────────────
405
556
 
406
557
  function handleTextDelta(
@@ -429,6 +580,7 @@ function handleTextDelta(
429
580
  type: "assistant_text_delta",
430
581
  text: drained.emitText,
431
582
  conversationId: deps.ctx.conversationId,
583
+ messageId: state.lastAssistantMessageId,
432
584
  });
433
585
  if (deps.shouldGenerateTitle) state.firstAssistantText += drained.emitText;
434
586
  }
@@ -466,6 +618,7 @@ function handleThinkingDelta(
466
618
  type: "assistant_thinking_delta",
467
619
  thinking: event.thinking,
468
620
  conversationId: deps.ctx.conversationId,
621
+ messageId: state.lastAssistantMessageId,
469
622
  });
470
623
  }
471
624
 
@@ -496,11 +649,12 @@ export function handleToolUse(
496
649
  input: event.input,
497
650
  conversationId: deps.ctx.conversationId,
498
651
  toolUseId: event.id,
652
+ messageId: state.lastAssistantMessageId,
499
653
  });
500
654
  }
501
655
 
502
656
  export function handleToolUsePreviewStart(
503
- _state: EventHandlerState,
657
+ state: EventHandlerState,
504
658
  deps: EventHandlerDeps,
505
659
  event: Extract<AgentEvent, { type: "tool_use_preview_start" }>,
506
660
  ): void {
@@ -509,6 +663,7 @@ export function handleToolUsePreviewStart(
509
663
  toolUseId: event.toolUseId,
510
664
  toolName: event.toolName,
511
665
  conversationId: deps.ctx.conversationId,
666
+ messageId: state.lastAssistantMessageId,
512
667
  });
513
668
  const statusText = `Preparing ${friendlyToolName(event.toolName)}...`;
514
669
  deps.ctx.emitActivityState(
@@ -521,7 +676,7 @@ export function handleToolUsePreviewStart(
521
676
  }
522
677
 
523
678
  function handleToolOutputChunk(
524
- _state: EventHandlerState,
679
+ state: EventHandlerState,
525
680
  deps: EventHandlerDeps,
526
681
  event: Extract<AgentEvent, { type: "tool_output_chunk" }>,
527
682
  ): void {
@@ -579,6 +734,7 @@ function handleToolOutputChunk(
579
734
  chunk: event.chunk,
580
735
  conversationId: deps.ctx.conversationId,
581
736
  toolUseId: event.toolUseId,
737
+ messageId: state.lastAssistantMessageId,
582
738
  subType: structured.subType,
583
739
  subToolName: structured.subToolName,
584
740
  subToolInput: structured.subToolInput,
@@ -591,12 +747,13 @@ function handleToolOutputChunk(
591
747
  chunk: event.chunk,
592
748
  conversationId: deps.ctx.conversationId,
593
749
  toolUseId: event.toolUseId,
750
+ messageId: state.lastAssistantMessageId,
594
751
  });
595
752
  }
596
753
  }
597
754
 
598
755
  export function handleInputJsonDelta(
599
- _state: EventHandlerState,
756
+ state: EventHandlerState,
600
757
  deps: EventHandlerDeps,
601
758
  event: Extract<AgentEvent, { type: "input_json_delta" }>,
602
759
  ): void {
@@ -610,6 +767,7 @@ export function handleInputJsonDelta(
610
767
  content: event.accumulatedJson,
611
768
  conversationId: deps.ctx.conversationId,
612
769
  toolUseId: event.toolUseId,
770
+ messageId: state.lastAssistantMessageId,
613
771
  });
614
772
  }
615
773
 
@@ -736,6 +894,7 @@ export function handleToolResult(
736
894
  diff: event.diff,
737
895
  status: event.status,
738
896
  conversationId: deps.ctx.conversationId,
897
+ messageId: state.lastAssistantMessageId,
739
898
  imageData: imageDataList?.[0],
740
899
  imageDataList,
741
900
  toolUseId: event.toolUseId,
@@ -915,6 +1074,69 @@ function handleError(
915
1074
  }
916
1075
  }
917
1076
 
1077
+ export function handleMaxTokensReached(
1078
+ _state: EventHandlerState,
1079
+ deps: EventHandlerDeps,
1080
+ event: Extract<AgentEvent, { type: "max_tokens_reached" }>,
1081
+ ): void {
1082
+ const classified = maxTokensReachedClassification();
1083
+ const surfaceId = `max_tokens_${uuid()}`;
1084
+ const data: CardSurfaceData = {
1085
+ title: "Response limit reached",
1086
+ subtitle: "The partial response above was saved.",
1087
+ body: classified.userMessage,
1088
+ };
1089
+ const actions: SurfaceAction[] = [
1090
+ {
1091
+ id: "relay_prompt",
1092
+ label: "Continue",
1093
+ style: "primary",
1094
+ data: {
1095
+ prompt: MAX_TOKENS_CONTINUE_PROMPT,
1096
+ _completeSurface: true,
1097
+ _completionSummary: MAX_TOKENS_SURFACE_COMPLETION_SUMMARY,
1098
+ },
1099
+ },
1100
+ ];
1101
+
1102
+ deps.ctx.surfaceState.set(surfaceId, {
1103
+ surfaceType: "card",
1104
+ title: data.title,
1105
+ data,
1106
+ actions,
1107
+ });
1108
+ deps.ctx.currentTurnSurfaces.push({
1109
+ surfaceId,
1110
+ surfaceType: "card",
1111
+ title: data.title,
1112
+ data,
1113
+ actions,
1114
+ display: "inline",
1115
+ persistent: true,
1116
+ });
1117
+
1118
+ deps.rlog.warn(
1119
+ {
1120
+ conversationId: deps.ctx.conversationId,
1121
+ stopReason: event.stopReason,
1122
+ surfaceId,
1123
+ },
1124
+ "Surfacing max-tokens continuation card",
1125
+ );
1126
+
1127
+ deps.onEvent({
1128
+ type: "ui_surface_show",
1129
+ conversationId: deps.ctx.conversationId,
1130
+ surfaceId,
1131
+ surfaceType: "card",
1132
+ title: data.title,
1133
+ data,
1134
+ actions,
1135
+ display: "inline",
1136
+ persistent: true,
1137
+ } as UiSurfaceShow);
1138
+ }
1139
+
918
1140
  export async function handleMessageComplete(
919
1141
  state: EventHandlerState,
920
1142
  deps: EventHandlerDeps,
@@ -929,6 +1151,7 @@ export async function handleMessageComplete(
929
1151
  type: "assistant_text_delta",
930
1152
  text: state.pendingDirectiveDisplayBuffer,
931
1153
  conversationId: deps.ctx.conversationId,
1154
+ messageId: state.lastAssistantMessageId,
932
1155
  });
933
1156
  if (deps.shouldGenerateTitle)
934
1157
  state.firstAssistantText += state.pendingDirectiveDisplayBuffer;
@@ -1035,52 +1258,6 @@ export async function handleMessageComplete(
1035
1258
  } as unknown as ContentBlock);
1036
1259
  }
1037
1260
 
1038
- const assistantChannelMetadata: Record<string, unknown> = {
1039
- ...provenanceFromTrustContext(deps.ctx.trustContext),
1040
- userMessageChannel: deps.turnChannelContext.userMessageChannel,
1041
- assistantMessageChannel: deps.turnChannelContext.assistantMessageChannel,
1042
- userMessageInterface: deps.turnInterfaceContext.userMessageInterface,
1043
- assistantMessageInterface:
1044
- deps.turnInterfaceContext.assistantMessageInterface,
1045
- sentAt: state.turnStartedAt,
1046
- };
1047
-
1048
- // When the assistant is replying through Slack, stamp a `slackMeta`
1049
- // sub-object so the transcript-rendering / thread-aware-context lookup
1050
- // can identify this row's thread without joining tables.
1051
- // Persistence happens BEFORE the Slack adapter sends the message, so
1052
- // Slack's authoritative `ts` (-> `channelTs`) is not yet known and is
1053
- // intentionally omitted here. The post-send reconciliation step in
1054
- // `deliverReplyViaCallback` writes `channelTs` back into this row once
1055
- // the gateway returns the Slack-assigned ts, restoring a fully-formed
1056
- // metadata envelope before any subsequent turn reads the row.
1057
- if (deps.turnChannelContext.assistantMessageChannel === "slack") {
1058
- const channelId = deps.ctx.trustContext?.requesterChatId;
1059
- if (channelId) {
1060
- const threadTs = getThreadTs(deps.ctx.conversationId);
1061
- const timestampTimezone = resolveAssistantReplyTimestampTimezone(
1062
- deps.ctx,
1063
- );
1064
- const timestampTimezoneLabel = formatSlackTimezoneLabel(
1065
- timestampTimezone,
1066
- { nowMs: state.turnStartedAt },
1067
- );
1068
- const partialSlackMeta: Partial<SlackMessageMetadata> = {
1069
- source: "slack",
1070
- eventKind: "message",
1071
- channelId,
1072
- ...(threadTs ? { threadTs } : {}),
1073
- timestampTimezone,
1074
- ...(timestampTimezoneLabel ? { timestampTimezoneLabel } : {}),
1075
- };
1076
- assistantChannelMetadata.slackMeta = writeSlackMetadata(
1077
- // `channelTs` is filled in by the post-send reconciliation step in
1078
- // `deliverReplyViaCallback`; cast through the Partial to satisfy
1079
- // the writer's type at this pre-send boundary.
1080
- partialSlackMeta as SlackMessageMetadata,
1081
- );
1082
- }
1083
- }
1084
1261
  // Redact known-pattern secrets from assistant text blocks before they are
1085
1262
  // written to durable storage. Non-text blocks (images, UI surfaces) pass
1086
1263
  // through unchanged. The live model history retains the original values.
@@ -1092,33 +1269,123 @@ export async function handleMessageComplete(
1092
1269
  return block;
1093
1270
  });
1094
1271
 
1095
- // Route the assistant-message persistence through the `persistence`
1096
- // pipeline. No `syncToDisk` here the orchestrator separately invokes
1097
- // `syncMessageToDisk` on `state.lastAssistantMessageId` after the loop
1098
- // completes (see `conversation-agent-loop.ts::syncLastAssistantMessageToDisk`).
1099
- const assistantPersistResult = (await runPipeline<PersistArgs, PersistResult>(
1272
+ // The row was reserved at `llm_call_started` (with channel metadata
1273
+ // stamped at that point) and `state.lastAssistantMessageId` carries its
1274
+ // id. Flush the final content via `updateContent` instead of inserting a
1275
+ // new row. No `syncToDisk` flag here — the orchestrator separately
1276
+ // invokes `syncMessageToDisk` on `state.lastAssistantMessageId` after
1277
+ // the loop completes (see
1278
+ // `conversation-agent-loop.ts::syncLastAssistantMessageToDisk`).
1279
+ const assistantMessageId = state.lastAssistantMessageId;
1280
+ if (!assistantMessageId) {
1281
+ throw new Error(
1282
+ "handleMessageComplete fired without a prior llm_call_started reserving an assistant row",
1283
+ );
1284
+ }
1285
+ const contentJson = JSON.stringify(contentForPersistence);
1286
+ await runPipeline<PersistArgs, PersistResult>(
1100
1287
  "persistence",
1101
1288
  getMiddlewaresFor("persistence"),
1102
1289
  defaultPersistenceTerminal,
1103
1290
  {
1104
- op: "add",
1105
- conversationId: deps.ctx.conversationId,
1106
- role: "assistant",
1107
- content: JSON.stringify(contentForPersistence),
1108
- metadata: assistantChannelMetadata,
1291
+ op: "updateContent",
1292
+ messageId: assistantMessageId,
1293
+ content: contentJson,
1109
1294
  },
1110
1295
  buildHandlerTurnContext(deps),
1111
1296
  DEFAULT_TIMEOUTS.persistence,
1112
- )) as PersistAddResult;
1113
- const assistantMsg = assistantPersistResult.message;
1114
- state.firstAssistantMessageId ??= assistantMsg.id;
1115
- state.lastAssistantMessageId = assistantMsg.id;
1297
+ );
1298
+ state.assistantRowAwaitingFinalization = false;
1299
+
1300
+ // ── Indexing + attention projection (restored from the pre-B3 `add` path) ──
1301
+ // `reserveMessage` + `updateMessageContent` are CRUD-only: they don't run
1302
+ // the memory indexer or the attention-cursor projector. The pre-B3 path
1303
+ // wrote the row via `addMessage`, which ran both as side-effects of the
1304
+ // insert. Calling them here keeps the assistant row's external state
1305
+ // (Qdrant segments, conversation attention cursor) in lockstep with the
1306
+ // finalized content. Both are non-fatal — a memory hiccup must not
1307
+ // escalate a successful generation into a turn-level throw. Indexing
1308
+ // intentionally fires AFTER `updateContent` succeeds so we never index
1309
+ // the empty reserved placeholder.
1310
+ const finalizedRow = getMessageById(
1311
+ assistantMessageId,
1312
+ deps.ctx.conversationId,
1313
+ );
1314
+ if (finalizedRow) {
1315
+ let provenanceTrustClass:
1316
+ | "guardian"
1317
+ | "trusted_contact"
1318
+ | "unknown"
1319
+ | undefined;
1320
+ let automated: boolean | undefined;
1321
+ if (finalizedRow.metadata) {
1322
+ try {
1323
+ const parsedMeta = messageMetadataSchema.safeParse(
1324
+ JSON.parse(finalizedRow.metadata),
1325
+ );
1326
+ if (parsedMeta.success) {
1327
+ provenanceTrustClass = parsedMeta.data.provenanceTrustClass;
1328
+ automated = parsedMeta.data.automated;
1329
+ }
1330
+ } catch {
1331
+ // Malformed metadata JSON — fall through with undefined fields,
1332
+ // matching the legacy behavior in `addMessage`.
1333
+ }
1334
+ }
1335
+ try {
1336
+ await indexMessageNow(
1337
+ {
1338
+ messageId: assistantMessageId,
1339
+ conversationId: deps.ctx.conversationId,
1340
+ role: "assistant",
1341
+ content: contentJson,
1342
+ createdAt: finalizedRow.createdAt,
1343
+ scopeId: "default",
1344
+ provenanceTrustClass,
1345
+ automated,
1346
+ },
1347
+ getConfig().memory,
1348
+ );
1349
+ } catch (err) {
1350
+ deps.rlog.warn(
1351
+ {
1352
+ err,
1353
+ conversationId: deps.ctx.conversationId,
1354
+ messageId: assistantMessageId,
1355
+ },
1356
+ "Failed to index assistant message for memory (non-fatal)",
1357
+ );
1358
+ }
1359
+ try {
1360
+ const attentionStateChanged = projectAssistantMessage({
1361
+ conversationId: deps.ctx.conversationId,
1362
+ messageId: assistantMessageId,
1363
+ messageAt: finalizedRow.createdAt,
1364
+ });
1365
+ if (attentionStateChanged) {
1366
+ void publishSyncInvalidation([
1367
+ conversationMetadataSyncTag(deps.ctx.conversationId),
1368
+ ]);
1369
+ }
1370
+ } catch (err) {
1371
+ deps.rlog.warn(
1372
+ {
1373
+ err,
1374
+ conversationId: deps.ctx.conversationId,
1375
+ messageId: assistantMessageId,
1376
+ },
1377
+ "Failed to project assistant message for attention tracking (non-fatal)",
1378
+ );
1379
+ }
1380
+ }
1116
1381
 
1117
1382
  // Backfill message_id on all LLM request logs from this turn.
1118
1383
  // The agent loop is single-threaded per conversation, so all rows with
1119
- // message_id IS NULL belong to the current turn.
1384
+ // message_id IS NULL belong to the current turn. The reserved id was
1385
+ // available before the LLM call ran but the logs are inserted DURING
1386
+ // the call, so the sweep still runs here.
1120
1387
  try {
1121
- backfillMessageIdOnLogs(deps.ctx.conversationId, assistantMsg.id);
1388
+ backfillMessageIdOnLogs(deps.ctx.conversationId, assistantMessageId);
1122
1389
  } catch (err) {
1123
1390
  deps.rlog.warn(
1124
1391
  { err },
@@ -1127,7 +1394,10 @@ export async function handleMessageComplete(
1127
1394
  }
1128
1395
 
1129
1396
  try {
1130
- backfillMemoryRecallLogMessageId(deps.ctx.conversationId, assistantMsg.id);
1397
+ backfillMemoryRecallLogMessageId(
1398
+ deps.ctx.conversationId,
1399
+ assistantMessageId,
1400
+ );
1131
1401
  } catch (err) {
1132
1402
  deps.rlog.warn(
1133
1403
  { err },
@@ -1138,7 +1408,7 @@ export async function handleMessageComplete(
1138
1408
  try {
1139
1409
  backfillMemoryV2ActivationMessageId(
1140
1410
  deps.ctx.conversationId,
1141
- assistantMsg.id,
1411
+ assistantMessageId,
1142
1412
  );
1143
1413
  } catch (err) {
1144
1414
  deps.rlog.warn(
@@ -1222,6 +1492,7 @@ function handleUsage(
1222
1492
  JSON.stringify(event.rawResponse),
1223
1493
  undefined,
1224
1494
  providerName,
1495
+ "mainAgent",
1225
1496
  );
1226
1497
  } catch (err) {
1227
1498
  deps.rlog.warn({ err }, "Failed to persist LLM request log (non-fatal)");
@@ -1248,6 +1519,36 @@ function handleUsage(
1248
1519
  },
1249
1520
  );
1250
1521
  state.llmCallStartedEmitted = false;
1522
+
1523
+ // Emit a lightweight per-call usage progress event so clients can show
1524
+ // live-updating token/cost metrics. This is a UI hint only — no DB writes.
1525
+ const pricingUsage = buildPricingUsage({
1526
+ providerName,
1527
+ model: event.model,
1528
+ inputTokens: event.inputTokens,
1529
+ outputTokens: event.outputTokens,
1530
+ cacheCreationInputTokens: event.cacheCreationInputTokens,
1531
+ cacheReadInputTokens: event.cacheReadInputTokens,
1532
+ rawResponse: event.rawResponse,
1533
+ });
1534
+ const pricing = resolveStructuredPricing(
1535
+ providerName,
1536
+ event.model,
1537
+ pricingUsage,
1538
+ );
1539
+ const estimatedCost =
1540
+ pricing.pricingStatus === "priced" && pricing.estimatedCostUsd != null
1541
+ ? pricing.estimatedCostUsd
1542
+ : 0;
1543
+
1544
+ deps.onEvent({
1545
+ type: "usage_progress",
1546
+ conversationId: deps.ctx.conversationId,
1547
+ inputTokens: event.inputTokens,
1548
+ outputTokens: event.outputTokens,
1549
+ estimatedCost,
1550
+ model: event.model,
1551
+ });
1251
1552
  }
1252
1553
 
1253
1554
  /**
@@ -1287,6 +1588,7 @@ function handleProviderError(
1287
1588
  JSON.stringify(buildProviderErrorResponsePayload(event.error)),
1288
1589
  undefined,
1289
1590
  event.actualProvider,
1591
+ "mainAgent",
1290
1592
  );
1291
1593
  } catch (err) {
1292
1594
  deps.rlog.warn(
@@ -1306,6 +1608,9 @@ export async function dispatchAgentEvent(
1306
1608
  ): Promise<void> {
1307
1609
  try {
1308
1610
  switch (event.type) {
1611
+ case "llm_call_started":
1612
+ await handleLlmCallStarted(state, deps);
1613
+ break;
1309
1614
  case "text_delta":
1310
1615
  handleTextDelta(state, deps, event);
1311
1616
  break;
@@ -1346,6 +1651,7 @@ export async function dispatchAgentEvent(
1346
1651
  input: event.input,
1347
1652
  conversationId: deps.ctx.conversationId,
1348
1653
  toolUseId: event.toolUseId,
1654
+ messageId: state.lastAssistantMessageId,
1349
1655
  });
1350
1656
  break;
1351
1657
  }
@@ -1425,6 +1731,7 @@ export async function dispatchAgentEvent(
1425
1731
  isError: event.isError,
1426
1732
  conversationId: deps.ctx.conversationId,
1427
1733
  toolUseId: event.toolUseId,
1734
+ messageId: state.lastAssistantMessageId,
1428
1735
  ...(metadata ? { activityMetadata: { webSearch: metadata } } : {}),
1429
1736
  });
1430
1737
  break;
@@ -1432,6 +1739,9 @@ export async function dispatchAgentEvent(
1432
1739
  case "error":
1433
1740
  handleError(state, deps, event);
1434
1741
  break;
1742
+ case "max_tokens_reached":
1743
+ handleMaxTokensReached(state, deps, event);
1744
+ break;
1435
1745
  case "provider_error":
1436
1746
  handleProviderError(deps, event);
1437
1747
  break;