@vellumai/assistant 0.8.5 → 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 (544) hide show
  1. package/AGENTS.md +33 -1
  2. package/ARCHITECTURE.md +1 -1
  3. package/bunfig.toml +6 -1
  4. package/docs/credential-execution-service.md +6 -6
  5. package/docs/plugins.md +4 -3
  6. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
  7. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
  8. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
  9. package/openapi.yaml +1900 -166
  10. package/package.json +1 -1
  11. package/src/__tests__/actor-token-service.test.ts +3 -2
  12. package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
  13. package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
  14. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
  15. package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
  16. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  17. package/src/__tests__/annotate-risk-options.test.ts +1 -0
  18. package/src/__tests__/approval-cascade.test.ts +1 -0
  19. package/src/__tests__/approval-routes-http.test.ts +9 -13
  20. package/src/__tests__/assert-not-live-db.ts +79 -0
  21. package/src/__tests__/assistant-feature-flags-integration.test.ts +9 -25
  22. package/src/__tests__/audit-log-rotation.test.ts +2 -2
  23. package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
  24. package/src/__tests__/background-workers-disk-pressure.test.ts +5 -8
  25. package/src/__tests__/browser-skill-endstate.test.ts +3 -3
  26. package/src/__tests__/btw-routes.test.ts +3 -2
  27. package/src/__tests__/call-controller.test.ts +3 -2
  28. package/src/__tests__/channel-approval-routes.test.ts +3 -2
  29. package/src/__tests__/channel-guardian.test.ts +3 -2
  30. package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
  31. package/src/__tests__/channel-reply-delivery.test.ts +35 -0
  32. package/src/__tests__/channel-retry-sweep.test.ts +320 -3
  33. package/src/__tests__/checker.test.ts +12 -12
  34. package/src/__tests__/compaction-events.test.ts +1 -0
  35. package/src/__tests__/compaction-trail-store.test.ts +264 -0
  36. package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
  37. package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
  38. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
  39. package/src/__tests__/computer-use-tools.test.ts +12 -14
  40. package/src/__tests__/config-loader-backfill.test.ts +13 -28
  41. package/src/__tests__/config-loader-corrupt.test.ts +5 -5
  42. package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
  43. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
  44. package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
  45. package/src/__tests__/config-schema.test.ts +10 -10
  46. package/src/__tests__/connection-model-compat.test.ts +83 -0
  47. package/src/__tests__/contacts-tools.test.ts +3 -2
  48. package/src/__tests__/context-token-estimator.test.ts +22 -0
  49. package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
  50. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
  51. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
  52. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  53. package/src/__tests__/conversation-agent-loop-overflow.test.ts +34 -0
  54. package/src/__tests__/conversation-agent-loop.test.ts +488 -2
  55. package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
  56. package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
  57. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
  58. package/src/__tests__/conversation-attention-store.test.ts +101 -0
  59. package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
  60. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
  61. package/src/__tests__/conversation-error.test.ts +30 -0
  62. package/src/__tests__/conversation-fork-crud.test.ts +69 -8
  63. package/src/__tests__/conversation-fork-route.test.ts +3 -2
  64. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  65. package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
  66. package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
  67. package/src/__tests__/conversation-lifecycle.test.ts +1 -0
  68. package/src/__tests__/conversation-list-source.test.ts +3 -2
  69. package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
  70. package/src/__tests__/conversation-load-history-stripped.test.ts +1 -0
  71. package/src/__tests__/conversation-pairing.test.ts +53 -0
  72. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
  73. package/src/__tests__/conversation-process-callsite.test.ts +1 -0
  74. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -0
  75. package/src/__tests__/conversation-queue.test.ts +333 -291
  76. package/src/__tests__/conversation-routes-disk-view.test.ts +3 -18
  77. package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
  78. package/src/__tests__/conversation-routes-slash-commands.test.ts +33 -2
  79. package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
  80. package/src/__tests__/conversation-skill-tools.test.ts +38 -142
  81. package/src/__tests__/conversation-slash-queue.test.ts +84 -32
  82. package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
  83. package/src/__tests__/conversation-speed-override.test.ts +1 -0
  84. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
  85. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
  86. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
  87. package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
  88. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
  89. package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
  90. package/src/__tests__/conversation-sync-tags.test.ts +128 -12
  91. package/src/__tests__/conversation-title-service.test.ts +1 -0
  92. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
  93. package/src/__tests__/conversation-usage.test.ts +1 -0
  94. package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
  95. package/src/__tests__/conversation-workspace-injection.test.ts +5 -0
  96. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -0
  97. package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
  98. package/src/__tests__/credential-broker-server-use.test.ts +5 -5
  99. package/src/__tests__/credential-execution-client.test.ts +72 -1
  100. package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
  101. package/src/__tests__/credential-health-service.test.ts +252 -3
  102. package/src/__tests__/credential-security-invariants.test.ts +5 -5
  103. package/src/__tests__/credential-vault-unit.test.ts +19 -19
  104. package/src/__tests__/credential-vault.test.ts +5 -5
  105. package/src/__tests__/cross-provider-web-search.test.ts +56 -2
  106. package/src/__tests__/db-connection-isolation.test.ts +7 -6
  107. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
  108. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
  109. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
  110. package/src/__tests__/db-test-helpers.ts +58 -0
  111. package/src/__tests__/disk-pressure-guard.test.ts +58 -41
  112. package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
  113. package/src/__tests__/disk-pressure-routes.test.ts +0 -33
  114. package/src/__tests__/disk-pressure-tools.test.ts +0 -4
  115. package/src/__tests__/dm-persistence.test.ts +26 -40
  116. package/src/__tests__/document-create-dedupe.test.ts +189 -0
  117. package/src/__tests__/document-find-replace.test.ts +3 -2
  118. package/src/__tests__/document-tool-security.test.ts +81 -2
  119. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
  120. package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
  121. package/src/__tests__/encrypted-store.test.ts +11 -9
  122. package/src/__tests__/feature-flag-test-helpers.ts +53 -0
  123. package/src/__tests__/filing-service.test.ts +1 -0
  124. package/src/__tests__/first-greeting.test.ts +62 -12
  125. package/src/__tests__/gateway-flag-listener.test.ts +0 -1
  126. package/src/__tests__/gemini-provider.test.ts +26 -0
  127. package/src/__tests__/guardian-action-sweep.test.ts +3 -2
  128. package/src/__tests__/guardian-outbound-http.test.ts +3 -2
  129. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
  130. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -0
  131. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  132. package/src/__tests__/heartbeat-service.test.ts +1 -0
  133. package/src/__tests__/helpers/mock-logger.ts +26 -0
  134. package/src/__tests__/host-bash-routes.test.ts +1 -0
  135. package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
  136. package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
  137. package/src/__tests__/host-shell-tool.test.ts +5 -4
  138. package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
  139. package/src/__tests__/http-conversation-lineage.test.ts +3 -2
  140. package/src/__tests__/http-user-message-parity.test.ts +29 -7
  141. package/src/__tests__/identity-intro-cache.test.ts +133 -22
  142. package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
  143. package/src/__tests__/inference-profile-reaper.test.ts +3 -2
  144. package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
  145. package/src/__tests__/injector-disk-pressure.test.ts +3 -17
  146. package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
  147. package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
  148. package/src/__tests__/llm-context-normalization.test.ts +42 -0
  149. package/src/__tests__/llm-resolver.test.ts +331 -0
  150. package/src/__tests__/llm-schema.test.ts +1 -1
  151. package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
  152. package/src/__tests__/mcp-abort-signal.test.ts +14 -0
  153. package/src/__tests__/mcp-client-auth.test.ts +14 -0
  154. package/src/__tests__/messaging-send-tool.test.ts +1 -0
  155. package/src/__tests__/migration-import-from-url.test.ts +3 -3
  156. package/src/__tests__/mock-gateway-ipc.ts +18 -2
  157. package/src/__tests__/model-intents.test.ts +3 -3
  158. package/src/__tests__/native-web-search.test.ts +30 -2
  159. package/src/__tests__/notification-deep-link.test.ts +62 -0
  160. package/src/__tests__/oauth-commands-routes.test.ts +37 -0
  161. package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
  162. package/src/__tests__/oauth-store.test.ts +3 -2
  163. package/src/__tests__/onboarding-template-contract.test.ts +3 -2
  164. package/src/__tests__/openai-provider.test.ts +8 -9
  165. package/src/__tests__/openai-responses-provider.test.ts +70 -10
  166. package/src/__tests__/openrouter-provider-only.test.ts +27 -5
  167. package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
  168. package/src/__tests__/persistence-pipeline.test.ts +139 -1
  169. package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
  170. package/src/__tests__/plugin-bootstrap.test.ts +9 -11
  171. package/src/__tests__/plugin-tool-contribution.test.ts +41 -38
  172. package/src/__tests__/process-message-background-slack.test.ts +21 -16
  173. package/src/__tests__/process-message-display-content.test.ts +19 -22
  174. package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
  175. package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
  176. package/src/__tests__/provider-registry-ollama.test.ts +45 -22
  177. package/src/__tests__/recording-handler.test.ts +1 -0
  178. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
  179. package/src/__tests__/registry.test.ts +82 -76
  180. package/src/__tests__/relay-server.test.ts +10 -10
  181. package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
  182. package/src/__tests__/schedule-store.test.ts +16 -1
  183. package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
  184. package/src/__tests__/secret-ingress-http.test.ts +5 -1
  185. package/src/__tests__/secure-keys.test.ts +3 -3
  186. package/src/__tests__/send-endpoint-busy.test.ts +81 -42
  187. package/src/__tests__/server-history-render.test.ts +4 -1
  188. package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
  189. package/src/__tests__/skill-feature-flags.test.ts +14 -16
  190. package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
  191. package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
  192. package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
  193. package/src/__tests__/skill-tool-factory.test.ts +96 -95
  194. package/src/__tests__/slack-channel-config.test.ts +3 -3
  195. package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
  196. package/src/__tests__/subagent-disposal.test.ts +27 -8
  197. package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
  198. package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
  199. package/src/__tests__/subagent-manager-notify.test.ts +20 -8
  200. package/src/__tests__/subagent-notify-parent.test.ts +5 -4
  201. package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
  202. package/src/__tests__/subagent-tools.test.ts +2 -1
  203. package/src/__tests__/suggestion-routes.test.ts +1 -0
  204. package/src/__tests__/system-prompt.test.ts +38 -0
  205. package/src/__tests__/test-preload-verifier.ts +68 -0
  206. package/src/__tests__/test-preload.ts +32 -39
  207. package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
  208. package/src/__tests__/tool-executor.test.ts +55 -10
  209. package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
  210. package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
  211. package/src/__tests__/twilio-routes.test.ts +3 -2
  212. package/src/__tests__/validate-input.test.ts +381 -0
  213. package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
  214. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
  215. package/src/__tests__/voice-session-bridge.test.ts +37 -28
  216. package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
  217. package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
  218. package/src/acp/session-manager.ts +5 -6
  219. package/src/agent/loop.ts +80 -0
  220. package/src/api/README.md +124 -2
  221. package/src/api/constants/call-sites.ts +27 -0
  222. package/src/api/events/assistant-outbound-attachment.ts +51 -0
  223. package/src/api/events/assistant-text-delta.ts +32 -0
  224. package/src/api/events/assistant-turn-start.ts +33 -0
  225. package/src/api/events/document-comment-created.ts +48 -0
  226. package/src/api/events/document-comment-deleted.ts +24 -0
  227. package/src/api/events/document-comment-reopened.ts +25 -0
  228. package/src/api/events/document-comment-resolved.ts +27 -0
  229. package/src/api/events/generation-cancelled.ts +24 -0
  230. package/src/api/events/generation-handoff.ts +41 -0
  231. package/src/api/events/message-complete.ts +42 -0
  232. package/src/api/events/open-url.ts +30 -0
  233. package/src/{events → api/events}/relationship-state-updated.ts +3 -3
  234. package/src/api/events/tool-use-start.ts +32 -0
  235. package/src/api/index.ts +128 -3
  236. package/src/api/responses/llm-context-response.ts +39 -0
  237. package/src/api/responses/llm-request-log-entry.ts +93 -0
  238. package/src/api/responses/memory-recall-log.ts +65 -0
  239. package/src/api/responses/memory-v2-activation-log.ts +78 -0
  240. package/src/background-wake/background-wake-routes.test.ts +687 -52
  241. package/src/background-wake/platform-client.test.ts +308 -0
  242. package/src/background-wake/platform-client.ts +167 -0
  243. package/src/background-wake/publisher.ts +91 -0
  244. package/src/background-wake/runtime-registry.ts +2 -2
  245. package/src/background-wake/wake-intent-hooks.test.ts +282 -0
  246. package/src/calls/guardian-dispatch.ts +1 -0
  247. package/src/calls/voice-session-bridge.ts +4 -4
  248. package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
  249. package/src/cli/commands/__tests__/notifications.test.ts +184 -40
  250. package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
  251. package/src/cli/commands/channels/index.ts +229 -0
  252. package/src/cli/commands/memory-v3-render.ts +147 -0
  253. package/src/cli/commands/memory-v3.ts +255 -4
  254. package/src/cli/commands/notifications.ts +365 -55
  255. package/src/cli/lib/open-browser.ts +7 -2
  256. package/src/cli/program.ts +2 -0
  257. package/src/config/assistant-feature-flags.ts +23 -42
  258. package/src/config/bundled-skills/document-editor/SKILL.md +5 -1
  259. package/src/config/bundled-skills/schedule/SKILL.md +1 -1
  260. package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
  261. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
  262. package/src/config/call-site-defaults.ts +1 -1
  263. package/src/config/feature-flag-cache.ts +86 -0
  264. package/src/config/feature-flag-registry.json +17 -17
  265. package/src/config/llm-context-resolution.ts +10 -1
  266. package/src/config/llm-resolver.ts +121 -15
  267. package/src/config/loader.ts +4 -5
  268. package/src/config/schemas/__tests__/memory-v2.test.ts +15 -0
  269. package/src/config/schemas/heartbeat.ts +1 -1
  270. package/src/config/schemas/llm.ts +90 -1
  271. package/src/config/schemas/memory-v2.ts +26 -0
  272. package/src/config/schemas/services.ts +6 -2
  273. package/src/config/seed-inference-profiles.ts +36 -16
  274. package/src/context/token-estimator.ts +10 -5
  275. package/src/credential-execution/executable-discovery.ts +40 -0
  276. package/src/credential-execution/process-manager.ts +6 -2
  277. package/src/credential-health/credential-health-service.ts +125 -40
  278. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
  279. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
  280. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
  281. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
  282. package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
  283. package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
  284. package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
  285. package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
  286. package/src/daemon/conversation-agent-loop-handlers.ts +389 -68
  287. package/src/daemon/conversation-agent-loop.ts +132 -28
  288. package/src/daemon/conversation-error.ts +33 -5
  289. package/src/daemon/conversation-messaging.ts +84 -43
  290. package/src/daemon/conversation-process.ts +74 -37
  291. package/src/daemon/conversation-runtime-assembly.ts +29 -9
  292. package/src/daemon/conversation-skill-tools.ts +14 -30
  293. package/src/daemon/conversation-surfaces.ts +69 -34
  294. package/src/daemon/conversation-tool-setup.ts +33 -48
  295. package/src/daemon/conversation.ts +26 -46
  296. package/src/daemon/daemon-control.ts +1 -1
  297. package/src/daemon/daemon-skill-host.ts +9 -2
  298. package/src/daemon/disk-pressure-guard.ts +27 -29
  299. package/src/daemon/first-greeting.ts +31 -13
  300. package/src/daemon/handlers/shared.ts +6 -1
  301. package/src/daemon/lifecycle.ts +12 -12
  302. package/src/daemon/mcp-reload-service.ts +1 -1
  303. package/src/daemon/meet-manifest-loader.ts +10 -17
  304. package/src/daemon/message-types/conversations.ts +20 -22
  305. package/src/daemon/message-types/document-comments.ts +8 -44
  306. package/src/daemon/message-types/home.ts +2 -2
  307. package/src/daemon/message-types/integrations.ts +2 -7
  308. package/src/daemon/message-types/messages.ts +23 -38
  309. package/src/daemon/message-types/subagents.ts +6 -0
  310. package/src/daemon/process-message.ts +9 -9
  311. package/src/daemon/providers-setup.ts +1 -1
  312. package/src/daemon/server.ts +16 -0
  313. package/src/daemon/switch-inference-profile-tool.ts +13 -3
  314. package/src/daemon/tool-setup-types.ts +0 -6
  315. package/src/daemon/wake-target-adapter.ts +10 -0
  316. package/src/documents/document-store.ts +38 -0
  317. package/src/export/__tests__/transcript-formatter.test.ts +1 -0
  318. package/src/heartbeat/__tests__/heartbeat-service.test.ts +29 -0
  319. package/src/heartbeat/heartbeat-service.ts +63 -0
  320. package/src/home/__tests__/feed-writer.test.ts +161 -0
  321. package/src/home/__tests__/post-connect-feed.test.ts +1 -0
  322. package/src/home/__tests__/suggested-prompts.test.ts +55 -59
  323. package/src/home/feed-writer.ts +146 -7
  324. package/src/home/suggested-prompts.ts +27 -145
  325. package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
  326. package/src/ipc/gateway-client.test.ts +4 -1
  327. package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
  328. package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
  329. package/src/ipc/skill-routes/memory.ts +4 -3
  330. package/src/ipc/skill-routes/registries.ts +28 -29
  331. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
  332. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
  333. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
  334. package/src/memory/__tests__/memory-retrospective-job.test.ts +1 -0
  335. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
  336. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
  337. package/src/memory/conversation-attention-store.ts +17 -3
  338. package/src/memory/conversation-crud.ts +352 -112
  339. package/src/memory/db-connection.ts +29 -19
  340. package/src/memory/db-init.ts +4 -0
  341. package/src/memory/db-singleton.ts +77 -0
  342. package/src/memory/delivery-channels.ts +82 -0
  343. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
  344. package/src/memory/graph/retriever.test.ts +3 -3
  345. package/src/memory/job-handlers/embedding.test.ts +3 -2
  346. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
  347. package/src/memory/jobs-worker.ts +12 -1
  348. package/src/memory/llm-request-log-source-clickhouse.ts +80 -0
  349. package/src/memory/llm-request-log-source-local.ts +24 -0
  350. package/src/memory/llm-request-log-source.ts +31 -0
  351. package/src/memory/llm-request-log-store.ts +188 -3
  352. package/src/memory/memory-v2-activation-log-store.ts +95 -1
  353. package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
  354. package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
  355. package/src/memory/migrations/index.ts +2 -0
  356. package/src/memory/schema/conversations.ts +9 -1
  357. package/src/memory/schema/inference.ts +0 -1
  358. package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
  359. package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
  360. package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
  361. package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
  362. package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
  363. package/src/memory/v2/harness/metrics.ts +5 -1
  364. package/src/memory/v2/harness/replay-input.ts +19 -3
  365. package/src/memory/v2/harness/runner.ts +6 -0
  366. package/src/memory/v2/harness/trace.ts +6 -0
  367. package/src/memory/v3/__tests__/consolidation-job.test.ts +2 -4
  368. package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
  369. package/src/memory/v3/__tests__/edges.test.ts +144 -1
  370. package/src/memory/v3/__tests__/filter.test.ts +48 -0
  371. package/src/memory/v3/__tests__/gate.test.ts +96 -33
  372. package/src/memory/v3/__tests__/index-composition.test.ts +58 -0
  373. package/src/memory/v3/__tests__/loop.test.ts +250 -5
  374. package/src/memory/v3/__tests__/scouts.test.ts +49 -0
  375. package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
  376. package/src/memory/v3/__tests__/shadow-middleware.test.ts +88 -2
  377. package/src/memory/v3/__tests__/traversal.test.ts +39 -0
  378. package/src/memory/v3/__tests__/tree-walk.test.ts +77 -0
  379. package/src/memory/v3/__tests__/validate.test.ts +32 -0
  380. package/src/memory/v3/coretrieval-seed.ts +240 -0
  381. package/src/memory/v3/edges.ts +58 -21
  382. package/src/memory/v3/filter.ts +27 -22
  383. package/src/memory/v3/gate.ts +51 -36
  384. package/src/memory/v3/index-composition.ts +18 -5
  385. package/src/memory/v3/loop.ts +65 -17
  386. package/src/memory/v3/scouts.ts +15 -4
  387. package/src/memory/v3/shadow-diff.ts +287 -0
  388. package/src/memory/v3/shadow-middleware.ts +44 -2
  389. package/src/memory/v3/traversal.ts +6 -1
  390. package/src/memory/v3/tree-walk.ts +6 -1
  391. package/src/memory/v3/validate.ts +56 -33
  392. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
  393. package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
  394. package/src/notifications/adapters/slack.ts +45 -11
  395. package/src/notifications/broadcaster.ts +114 -63
  396. package/src/notifications/conversation-pairing.ts +23 -3
  397. package/src/notifications/decisions-store.ts +32 -1
  398. package/src/notifications/deliveries-store.ts +45 -0
  399. package/src/notifications/edit-notification.ts +201 -0
  400. package/src/notifications/emit-signal.ts +11 -1
  401. package/src/notifications/signal.ts +10 -0
  402. package/src/notifications/types.ts +37 -0
  403. package/src/oauth/byo-connection.test.ts +67 -3
  404. package/src/oauth/byo-connection.ts +32 -5
  405. package/src/oauth/connect-orchestrator.ts +9 -0
  406. package/src/oauth/connection-resolver.test.ts +76 -0
  407. package/src/oauth/connection-resolver.ts +49 -10
  408. package/src/oauth/manual-token-connection.ts +51 -3
  409. package/src/oauth/seed-providers.ts +3 -0
  410. package/src/permissions/approval-policy.test.ts +19 -5
  411. package/src/permissions/approval-policy.ts +14 -3
  412. package/src/permissions/checker.ts +21 -8
  413. package/src/platform/client.test.ts +24 -1
  414. package/src/platform/client.ts +8 -0
  415. package/src/platform/feature-gate.ts +15 -0
  416. package/src/plugins/defaults/injectors.ts +2 -8
  417. package/src/plugins/defaults/persistence.ts +25 -6
  418. package/src/plugins/types.ts +57 -13
  419. package/src/proactive-artifact/job.test.ts +1 -0
  420. package/src/prompts/__tests__/system-prompt.test.ts +4 -4
  421. package/src/prompts/system-prompt.ts +38 -40
  422. package/src/prompts/template-detection.ts +10 -4
  423. package/src/prompts/templates/BOOTSTRAP.md +7 -11
  424. package/src/prompts/templates/IDENTITY.md +0 -2
  425. package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
  426. package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
  427. package/src/providers/call-site-routing.ts +33 -9
  428. package/src/providers/connection-model-compat.ts +23 -0
  429. package/src/providers/connection-resolution.ts +39 -20
  430. package/src/providers/fireworks/client.ts +1 -0
  431. package/src/providers/gemini/client.ts +24 -3
  432. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
  433. package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
  434. package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
  435. package/src/providers/inference/auth.ts +0 -8
  436. package/src/providers/inference/connections.ts +3 -66
  437. package/src/providers/inference/resolve-auth.ts +2 -3
  438. package/src/providers/model-catalog.ts +35 -1
  439. package/src/providers/model-intents.ts +3 -3
  440. package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
  441. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
  442. package/src/providers/openai/chat-completions-provider.ts +110 -12
  443. package/src/providers/openai/codex-models.ts +2 -0
  444. package/src/providers/openai/responses-provider.ts +53 -53
  445. package/src/providers/openrouter/client.ts +13 -8
  446. package/src/providers/provider-send-message.ts +18 -9
  447. package/src/providers/registry.ts +48 -8
  448. package/src/providers/retry.ts +16 -4
  449. package/src/providers/search-provider-catalog.ts +17 -9
  450. package/src/providers/types.ts +9 -0
  451. package/src/runtime/__tests__/agent-wake.test.ts +1 -0
  452. package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
  453. package/src/runtime/access-request-helper.ts +1 -0
  454. package/src/runtime/auth/route-policy.ts +10 -0
  455. package/src/runtime/channel-readiness-service.ts +68 -0
  456. package/src/runtime/channel-reply-delivery.ts +23 -0
  457. package/src/runtime/channel-retry-sweep.ts +47 -14
  458. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  459. package/src/runtime/migrations/vbundle-builder.ts +3 -2
  460. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
  461. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
  462. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
  463. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  464. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
  465. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
  466. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +51 -3
  467. package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
  468. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
  469. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
  470. package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
  471. package/src/runtime/routes/acp-routes-list.test.ts +3 -0
  472. package/src/runtime/routes/app-management-routes.ts +111 -4
  473. package/src/runtime/routes/background-wake-routes.ts +188 -20
  474. package/src/runtime/routes/btw-routes.ts +4 -4
  475. package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
  476. package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
  477. package/src/runtime/routes/conversation-list-routes.ts +147 -0
  478. package/src/runtime/routes/conversation-management-routes.ts +39 -14
  479. package/src/runtime/routes/conversation-query-routes.ts +60 -10
  480. package/src/runtime/routes/conversation-routes.ts +186 -140
  481. package/src/runtime/routes/conversations-import-routes.ts +19 -6
  482. package/src/runtime/routes/documents-routes.ts +10 -1
  483. package/src/runtime/routes/group-routes.ts +11 -0
  484. package/src/runtime/routes/home-feed-routes.ts +129 -0
  485. package/src/runtime/routes/identity-intro-cache.ts +61 -16
  486. package/src/runtime/routes/identity-routes.ts +30 -9
  487. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
  488. package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
  489. package/src/runtime/routes/index.ts +2 -0
  490. package/src/runtime/routes/inference-provider-connection-routes.ts +5 -26
  491. package/src/runtime/routes/integrations/vercel.ts +15 -0
  492. package/src/runtime/routes/llm-context-normalization.ts +7 -2
  493. package/src/runtime/routes/memory-v3-routes.ts +160 -2
  494. package/src/runtime/routes/migration-routes.ts +20 -13
  495. package/src/runtime/routes/notification-routes.ts +63 -1
  496. package/src/runtime/routes/oauth-commands-routes.ts +6 -1
  497. package/src/runtime/routes/surface-action-routes.ts +1 -38
  498. package/src/runtime/routes/surface-content-routes.ts +12 -5
  499. package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
  500. package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
  501. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
  502. package/src/runtime/slack-dm-text-delivery.ts +177 -0
  503. package/src/runtime/sync/resource-sync-events.ts +1 -1
  504. package/src/runtime/tool-grant-request-helper.ts +1 -0
  505. package/src/schedule/schedule-store.ts +8 -1
  506. package/src/schedule/scheduler.ts +111 -15
  507. package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
  508. package/src/security/encrypted-store.ts +7 -16
  509. package/src/security/store-path-override.ts +61 -0
  510. package/src/signals/user-message.ts +5 -8
  511. package/src/skills/validate-input.ts +177 -0
  512. package/src/subagent/manager.ts +13 -13
  513. package/src/subagent/types.ts +6 -0
  514. package/src/tasks/tool-sanitizer.ts +2 -2
  515. package/src/tools/apps/definitions.ts +35 -21
  516. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
  517. package/src/tools/computer-use/definitions.ts +268 -266
  518. package/src/tools/document/document-tool.ts +131 -8
  519. package/src/tools/execution-target.ts +2 -5
  520. package/src/tools/executor.ts +18 -55
  521. package/src/tools/host-filesystem/edit.test.ts +1 -0
  522. package/src/tools/host-filesystem/read.test.ts +1 -0
  523. package/src/tools/host-filesystem/transfer.test.ts +31 -6
  524. package/src/tools/host-filesystem/write.test.ts +1 -0
  525. package/src/tools/mcp/mcp-tool-factory.ts +0 -2
  526. package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
  527. package/src/tools/network/__tests__/web-search.test.ts +211 -3
  528. package/src/tools/network/managed-search-proxy.ts +183 -0
  529. package/src/tools/network/web-search.ts +199 -44
  530. package/src/tools/policy-context.ts +3 -1
  531. package/src/tools/registry.ts +146 -103
  532. package/src/tools/schedule/create.ts +1 -1
  533. package/src/tools/skills/skill-tool-factory.ts +17 -36
  534. package/src/tools/subagent/spawn.ts +3 -0
  535. package/src/tools/tool-approval-handler.ts +10 -4
  536. package/src/tools/tool-name-aliases.ts +72 -14
  537. package/src/tools/types.ts +17 -15
  538. package/src/tools/ui-surface/definitions.ts +98 -86
  539. package/src/types/onboarding-context.ts +6 -0
  540. package/src/usage/attribution.ts +32 -1
  541. package/src/util/browser.ts +7 -2
  542. package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
  543. package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
  544. package/src/workspace/migrations/registry.ts +4 -0
@@ -1,14 +1,41 @@
1
1
  import { z } from "zod";
2
2
 
3
- import { computeNextBackgroundWakeIntent } from "../../background-wake/next-wake.js";
3
+ import {
4
+ type BackgroundWakeIntent,
5
+ computeNextBackgroundWakeIntent,
6
+ } from "../../background-wake/next-wake.js";
7
+ import type { BackgroundWakeRuntime } from "../../background-wake/runtime-registry.js";
4
8
  import { getBackgroundWakeRuntime } from "../../background-wake/runtime-registry.js";
9
+ import { getLogger } from "../../util/logger.js";
5
10
  import { BadRequestError, ServiceUnavailableError } from "./errors.js";
6
11
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
7
12
 
8
13
  const PREPARE_SLEEP_DEFER_WINDOW_MS = 60_000;
9
14
  const HEARTBEAT_DUE_TOLERANCE_MS = 1_000;
15
+ const MIN_DRAIN_START_BUDGET_MS = 5_000;
16
+ const LEASE_RENEW_INTERVAL_MS = 120_000;
17
+ const log = getLogger("background-wake-routes");
18
+
19
+ class DrainDeadlineElapsedError extends Error {
20
+ constructor() {
21
+ super("background wake lease deadline elapsed before starting work");
22
+ this.name = "DrainDeadlineElapsedError";
23
+ }
24
+ }
25
+
26
+ type RenewWakeLease = (leaseId: string) => Promise<unknown>;
27
+ type CompleteWakeLease = (args: {
28
+ leaseId: string;
29
+ status: "completed" | "failed" | "expired";
30
+ error?: string;
31
+ nextIntent?: BackgroundWakeIntent | null;
32
+ }) => Promise<unknown>;
10
33
 
11
34
  let computeWakeIntent = computeNextBackgroundWakeIntent;
35
+ let renewWakeLease: RenewWakeLease = defaultRenewWakeLease;
36
+ let completeWakeLease: CompleteWakeLease = defaultCompleteWakeLease;
37
+ const activeDrainLeases = new Set<string>();
38
+ const activeDrainPromises = new Set<Promise<void>>();
12
39
  const timestampInputSchema = z.union([z.number(), z.string()]);
13
40
 
14
41
  const wakeIntentSchema = z
@@ -66,7 +93,8 @@ function normalizeTimestamp(value: unknown): unknown {
66
93
  return Number.isFinite(parsed) ? parsed : value;
67
94
  }
68
95
 
69
- function parseDrainDueBody(body: Record<string, unknown>) {
96
+ type DrainDueRequest = z.infer<typeof normalizedDrainDueRequestSchema>;
97
+ function parseDrainDueBody(body: Record<string, unknown>): DrainDueRequest {
70
98
  const parsed = normalizedDrainDueRequestSchema.safeParse(
71
99
  normalizeDrainDueBody(body),
72
100
  );
@@ -78,6 +106,20 @@ function parseDrainDueBody(body: Record<string, unknown>) {
78
106
  return parsed.data;
79
107
  }
80
108
 
109
+ async function defaultRenewWakeLease(leaseId: string): Promise<unknown> {
110
+ const { renewBackgroundWakeLease } =
111
+ await import("../../background-wake/platform-client.js");
112
+ return renewBackgroundWakeLease(leaseId);
113
+ }
114
+
115
+ async function defaultCompleteWakeLease(
116
+ args: Parameters<CompleteWakeLease>[0],
117
+ ): Promise<unknown> {
118
+ const { completeBackgroundWakeLease } =
119
+ await import("../../background-wake/platform-client.js");
120
+ return completeBackgroundWakeLease(args);
121
+ }
122
+
81
123
  function handleGetIntent() {
82
124
  return { intent: computeWakeIntent() };
83
125
  }
@@ -102,28 +144,141 @@ async function handleDrainDue(body: Record<string, unknown>) {
102
144
  );
103
145
  }
104
146
 
105
- const now = Date.now();
106
- const heartbeatDue =
107
- runtime.heartbeat.nextRunAt != null &&
108
- runtime.heartbeat.nextRunAt <= now + HEARTBEAT_DUE_TOLERANCE_MS;
109
- const heartbeatRan = heartbeatDue ? await runtime.heartbeat.runOnce() : false;
110
- const scheduledCount = await runtime.scheduler.runOnce();
147
+ if (!activeDrainLeases.has(request.leaseId)) {
148
+ activeDrainLeases.add(request.leaseId);
149
+ const drainPromise = runDrainDueLease(request, runtime);
150
+ activeDrainPromises.add(drainPromise);
151
+ void drainPromise.finally(() => activeDrainPromises.delete(drainPromise));
152
+ }
111
153
 
112
154
  return {
155
+ accepted: true,
113
156
  leaseId: request.leaseId,
114
157
  reason: request.reason,
115
158
  sourceGeneration: request.sourceGeneration,
116
159
  startedAt: request.startedAt,
117
160
  deadlineAt: request.deadlineAt,
118
- counts: {
119
- heartbeat: heartbeatRan ? 1 : 0,
120
- scheduler: scheduledCount,
121
- total: (heartbeatRan ? 1 : 0) + scheduledCount,
122
- },
123
- nextIntent: computeWakeIntent(),
124
161
  };
125
162
  }
126
163
 
164
+ async function runDrainDueLease(
165
+ request: DrainDueRequest,
166
+ runtime: BackgroundWakeRuntime,
167
+ ): Promise<void> {
168
+ let renewTimer: ReturnType<typeof setInterval> | undefined;
169
+ try {
170
+ renewTimer = setInterval(() => {
171
+ void renewWakeLease(request.leaseId).catch(() => {});
172
+ }, LEASE_RENEW_INTERVAL_MS);
173
+ renewTimer.unref?.();
174
+
175
+ assertDrainCanStart(request.deadlineAt);
176
+ const result = await performDrainDue(request, runtime);
177
+ await reportLeaseCompletion({
178
+ leaseId: request.leaseId,
179
+ status: "completed",
180
+ nextIntent: result.nextIntent,
181
+ });
182
+ } catch (error) {
183
+ await reportLeaseCompletion({
184
+ leaseId: request.leaseId,
185
+ status: completionStatusForError(error),
186
+ error: error instanceof Error ? error.message : String(error),
187
+ nextIntent: computeWakeIntent(),
188
+ });
189
+ } finally {
190
+ if (renewTimer) clearInterval(renewTimer);
191
+ activeDrainLeases.delete(request.leaseId);
192
+ }
193
+ }
194
+
195
+ async function reportLeaseCompletion(
196
+ args: Parameters<CompleteWakeLease>[0],
197
+ ): Promise<void> {
198
+ try {
199
+ await completeWakeLease(args);
200
+ } catch (err) {
201
+ log.warn(
202
+ { err, leaseId: args.leaseId, status: args.status },
203
+ "Failed to report background wake lease completion",
204
+ );
205
+ }
206
+ }
207
+
208
+ async function performDrainDue(
209
+ request: DrainDueRequest,
210
+ runtime: BackgroundWakeRuntime,
211
+ ) {
212
+ const now = Date.now();
213
+ const currentIntent = computeWakeIntent(now);
214
+ const heartbeatDue = isHeartbeatTimerDue(runtime.heartbeat.nextRunAt, now);
215
+ const schedulerDue =
216
+ heartbeatDue ||
217
+ reasonIncludesSource(request.reason, "schedule") ||
218
+ intentHasDueSource(currentIntent, "schedule", now);
219
+
220
+ if (heartbeatDue) {
221
+ if (hasStartBudget(request.deadlineAt)) {
222
+ await runtime.heartbeat.runManagedWakeIfDue({
223
+ now,
224
+ toleranceMs: HEARTBEAT_DUE_TOLERANCE_MS,
225
+ scheduledFor: request.startedAt,
226
+ });
227
+ }
228
+ }
229
+
230
+ if (schedulerDue) {
231
+ await runtime.scheduler.runDueWorkOnce({
232
+ deadlineAt: request.deadlineAt,
233
+ minStartBudgetMs: MIN_DRAIN_START_BUDGET_MS,
234
+ includeStillPending: true,
235
+ });
236
+ }
237
+
238
+ const nextIntent = computeWakeIntent();
239
+
240
+ return {
241
+ nextIntent,
242
+ };
243
+ }
244
+
245
+ function assertDrainCanStart(deadlineAt: number): void {
246
+ if (deadlineAt <= Date.now()) {
247
+ throw new DrainDeadlineElapsedError();
248
+ }
249
+ }
250
+
251
+ function completionStatusForError(error: unknown): "failed" | "expired" {
252
+ return error instanceof DrainDeadlineElapsedError ? "expired" : "failed";
253
+ }
254
+
255
+ function reasonIncludesSource(
256
+ reason: string,
257
+ source: "heartbeat" | "schedule",
258
+ ): boolean {
259
+ return reason === "mixed" || reason === source;
260
+ }
261
+
262
+ function isHeartbeatTimerDue(nextRunAt: number | null, now: number): boolean {
263
+ return nextRunAt != null && nextRunAt <= now + HEARTBEAT_DUE_TOLERANCE_MS;
264
+ }
265
+
266
+ function intentHasDueSource(
267
+ intent: BackgroundWakeIntent | null,
268
+ source: "heartbeat" | "schedule",
269
+ now: number,
270
+ ): boolean {
271
+ return (
272
+ intent != null &&
273
+ intent.actualNextDueAt <= now + HEARTBEAT_DUE_TOLERANCE_MS &&
274
+ reasonIncludesSource(intent.reason, source)
275
+ );
276
+ }
277
+
278
+ function hasStartBudget(deadlineAt: number): boolean {
279
+ return deadlineAt - Date.now() >= MIN_DRAIN_START_BUDGET_MS;
280
+ }
281
+
127
282
  /** @internal Test helper for route-only tests. */
128
283
  export function setBackgroundWakeIntentComputerForTest(
129
284
  nextCompute: typeof computeNextBackgroundWakeIntent | null,
@@ -131,6 +286,24 @@ export function setBackgroundWakeIntentComputerForTest(
131
286
  computeWakeIntent = nextCompute ?? computeNextBackgroundWakeIntent;
132
287
  }
133
288
 
289
+ /** @internal Test helper for route-only tests. */
290
+ export function setBackgroundWakeLeaseClientForTest(
291
+ nextClient: {
292
+ renew: RenewWakeLease;
293
+ complete: CompleteWakeLease;
294
+ } | null,
295
+ ): void {
296
+ renewWakeLease = nextClient?.renew ?? defaultRenewWakeLease;
297
+ completeWakeLease = nextClient?.complete ?? defaultCompleteWakeLease;
298
+ }
299
+
300
+ /** @internal Test helper for route-only tests. */
301
+ export async function flushBackgroundWakeDrainsForTest(): Promise<void> {
302
+ while (activeDrainPromises.size > 0) {
303
+ await Promise.allSettled([...activeDrainPromises]);
304
+ }
305
+ }
306
+
134
307
  export const ROUTES: RouteDefinition[] = [
135
308
  {
136
309
  operationId: "getBackgroundWakeIntent",
@@ -171,17 +344,12 @@ export const ROUTES: RouteDefinition[] = [
171
344
  tags: ["background-wake"],
172
345
  requestBody: drainDueRequestSchema,
173
346
  responseBody: z.object({
347
+ accepted: z.boolean(),
174
348
  leaseId: z.string(),
175
349
  reason: z.string(),
176
350
  sourceGeneration: z.string(),
177
351
  startedAt: z.number(),
178
352
  deadlineAt: z.number(),
179
- counts: z.object({
180
- heartbeat: z.number(),
181
- scheduler: z.number(),
182
- total: z.number(),
183
- }),
184
- nextIntent: wakeIntentSchema,
185
353
  }),
186
354
  handler: ({ body }: RouteHandlerArgs) => handleDrainDue(body ?? {}),
187
355
  },
@@ -19,9 +19,9 @@ import { z } from "zod";
19
19
  import { getConfig } from "../../config/loader.js";
20
20
  import { readNowScratchpad } from "../../daemon/conversation-runtime-assembly.js";
21
21
  import { getOrCreateConversation } from "../../daemon/conversation-store.js";
22
- import { buildToolDefinitions } from "../../daemon/conversation-tool-setup.js";
23
22
  import { parseIdentityFields } from "../../daemon/handlers/identity.js";
24
23
  import { getConversationByKey } from "../../memory/conversation-key-store.js";
24
+ import { getAllToolDefinitions } from "../../tools/registry.js";
25
25
  import { getLogger } from "../../util/logger.js";
26
26
  import { getWorkspacePromptPath } from "../../util/platform.js";
27
27
  import { runBtwSidechain } from "../btw-sidechain.js";
@@ -77,7 +77,7 @@ async function handleBtw({
77
77
  fastText = `Hi, I'm ${fields.name}!`;
78
78
  }
79
79
  }
80
- fastText ??= getCachedIntro()?.text;
80
+ fastText ??= getCachedIntro()?.greetings[0];
81
81
  if (fastText) {
82
82
  log.debug("Returning identity intro fast-path");
83
83
  return new ReadableStream({
@@ -122,7 +122,7 @@ async function handleBtw({
122
122
  const result = await runBtwSidechain({
123
123
  content: effectiveContent,
124
124
  conversation,
125
- tools: buildToolDefinitions(),
125
+ tools: getAllToolDefinitions(),
126
126
  signal: abortSignal,
127
127
  ...(isGreeting ? { callSite: "emptyStateGreeting" as const } : {}),
128
128
  onEvent: (event) => {
@@ -146,7 +146,7 @@ async function handleBtw({
146
146
 
147
147
  if (isIntroRequest && result.text) {
148
148
  try {
149
- setCachedIntro(result.text);
149
+ setCachedIntro([result.text]);
150
150
  log.debug("Cached identity intro text");
151
151
  } catch {
152
152
  // Non-fatal — next request will regenerate.
@@ -9,8 +9,11 @@
9
9
  * errors, and build the success response.
10
10
  */
11
11
 
12
+ import { z } from "zod";
13
+
12
14
  import { analyzeConversation } from "../services/analyze-conversation.js";
13
15
  import { buildConversationDetailResponse } from "../services/conversation-serializer.js";
16
+ import { conversationSummarySchema } from "./conversation-list-routes.js";
14
17
  import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
15
18
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
16
19
 
@@ -60,6 +63,9 @@ export const ROUTES: RouteDefinition[] = [
60
63
  description:
61
64
  "Create a new conversation with a structured self-assessment of an existing conversation.",
62
65
  tags: ["conversations"],
66
+ responseBody: z.object({
67
+ conversation: conversationSummarySchema,
68
+ }),
63
69
  handler: handleAnalyzeConversation,
64
70
  },
65
71
  ];
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Route definitions for the per-conversation **compaction trail** view.
3
+ *
4
+ * GET /v1/conversations/:id/compaction?callId=…
5
+ *
6
+ * Reachable via the platform's `RuntimeProxyWildcardView` at
7
+ * `/v1/assistants/{assistantId}/conversations/{conversationId}/compaction/?callId=…`.
8
+ *
9
+ * # Scope
10
+ *
11
+ * Returns the set of `call_site = "compactionAgent"` rows in this
12
+ * conversation that ran in the **window between the previous real LLM
13
+ * call and the one identified by `callId`**, ordered chronologically.
14
+ * This is the data the Inspector's "Compaction" tab shows when you
15
+ * select a call in the rail: it answers "what did the compactor do to
16
+ * my context before *this specific* call?" — not "what has the
17
+ * compactor ever done in this conversation".
18
+ *
19
+ * The floor is resolved by walking back from the selected call to the
20
+ * most recent non-`compactionAgent` row in the same conversation. When
21
+ * the selected call is the *first* real call in the conversation,
22
+ * there is no floor and every preceding compaction is in scope.
23
+ *
24
+ * # Data model decision (in progress)
25
+ *
26
+ * Today the trail is projected from `llm_request_logs` rows alone — no
27
+ * `compaction_logs` table exists yet (#32055 remains a draft). This MVP
28
+ * route exists precisely to test whether the projected shape is enough.
29
+ * If real-world use surfaces UX needs that aren't in `llm_request_logs`
30
+ * (most likely: per-event duration, structured before/after counts,
31
+ * trigger reason), that becomes the concrete justification for the new
32
+ * table. Until then, missing fields surface as `null` and the Compaction
33
+ * tab renders `"Unavailable"` for them.
34
+ *
35
+ * In particular, `durationMs` is always `null` for now — the column
36
+ * doesn't exist on `llm_request_logs` and we deliberately ship the route
37
+ * without it to surface the gap in the UI.
38
+ */
39
+
40
+ import { z } from "zod";
41
+
42
+ import { getConversation } from "../../memory/conversation-crud.js";
43
+ import { getLlmRequestLogSource } from "../../memory/llm-request-log-source.js";
44
+ import type { LogRow } from "../../memory/llm-request-log-store.js";
45
+ import { BadRequestError, NotFoundError } from "./errors.js";
46
+ import {
47
+ type LlmContextSummary,
48
+ normalizeLlmContextPayloads,
49
+ } from "./llm-context-normalization.js";
50
+ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
51
+
52
+ /**
53
+ * Wire shape for a single compaction event. Mirrors the React Query
54
+ * response type at
55
+ * `apps/web/src/domains/chat/inspector/compaction-trail-types.ts`.
56
+ * Keep the two in sync — until the OpenAPI client generator picks up
57
+ * this route, the frontend type is hand-maintained.
58
+ */
59
+ export interface CompactionTrailEvent {
60
+ id: string;
61
+ createdAt: number;
62
+ model: string | null;
63
+ provider: string | null;
64
+ inputTokens: number | null;
65
+ outputTokens: number | null;
66
+ /**
67
+ * Per-call wall-clock latency, in milliseconds. **Always `null` for
68
+ * now** — `llm_request_logs` doesn't carry a duration column. Surfacing
69
+ * the gap in the UI is intentional: if engineers consistently miss
70
+ * having latency here, that's a concrete signal to extend the row
71
+ * (either as a column on `llm_request_logs` or on a dedicated
72
+ * `compaction_logs` table per the open data-model decision).
73
+ */
74
+ durationMs: number | null;
75
+ responsePreview: string | null;
76
+ requestMessageCount: number | null;
77
+ stopReason: string | null;
78
+ estimatedCostUsd: number | null;
79
+ }
80
+
81
+ export interface CompactionTrailResponse {
82
+ conversationId: string;
83
+ events: CompactionTrailEvent[];
84
+ }
85
+
86
+ const compactionTrailEventSchema = z.object({
87
+ id: z.string(),
88
+ createdAt: z.number(),
89
+ model: z.string().nullable(),
90
+ provider: z.string().nullable(),
91
+ inputTokens: z.number().nullable(),
92
+ outputTokens: z.number().nullable(),
93
+ durationMs: z.number().nullable(),
94
+ responsePreview: z.string().nullable(),
95
+ requestMessageCount: z.number().nullable(),
96
+ stopReason: z.string().nullable(),
97
+ estimatedCostUsd: z.number().nullable(),
98
+ });
99
+
100
+ const compactionTrailResponseSchema = z.object({
101
+ conversationId: z.string(),
102
+ events: z.array(compactionTrailEventSchema),
103
+ });
104
+
105
+ // ---------------------------------------------------------------------------
106
+ // Projection — LogRow → CompactionTrailEvent
107
+ // ---------------------------------------------------------------------------
108
+
109
+ function tryParseJson(value: string): unknown {
110
+ try {
111
+ return JSON.parse(value);
112
+ } catch {
113
+ return value;
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Project a raw `llm_request_logs` row into the compaction-trail wire
119
+ * shape. Reuses `normalizeLlmContextPayloads` so model/provider/token
120
+ * extraction stays consistent with what the rest of the inspector shows.
121
+ *
122
+ * Fields the normalizer can't derive (today: `durationMs`) land as
123
+ * `null` — see the `CompactionTrailEvent.durationMs` doc comment for the
124
+ * rationale.
125
+ *
126
+ * Exported only for unit tests; the route handler is the sole production
127
+ * caller.
128
+ */
129
+ export function projectLogRowToCompactionTrailEvent(
130
+ log: LogRow,
131
+ ): CompactionTrailEvent {
132
+ const normalized = normalizeLlmContextPayloads({
133
+ requestPayload: tryParseJson(log.requestPayload),
134
+ responsePayload: tryParseJson(log.responsePayload),
135
+ createdAt: log.createdAt,
136
+ });
137
+ const summary: LlmContextSummary | undefined = normalized.summary;
138
+ return {
139
+ id: log.id,
140
+ createdAt: log.createdAt,
141
+ model: summary?.model ?? null,
142
+ // Prefer the normalized provider (derived from payload shape) over
143
+ // the stored column. Stored `provider` is the originating call's
144
+ // own identifier and matches the normalizer in all cases we ship
145
+ // today, but the normalizer is the source-of-truth used by sibling
146
+ // inspector tabs — keep that alignment.
147
+ provider: summary?.provider ?? log.provider ?? null,
148
+ inputTokens: summary?.inputTokens ?? null,
149
+ outputTokens: summary?.outputTokens ?? null,
150
+ durationMs: null,
151
+ responsePreview: summary?.responsePreview ?? null,
152
+ requestMessageCount: summary?.requestMessageCount ?? null,
153
+ stopReason: summary?.stopReason ?? null,
154
+ estimatedCostUsd: summary?.estimatedCostUsd ?? null,
155
+ };
156
+ }
157
+
158
+ // ---------------------------------------------------------------------------
159
+ // Handler
160
+ // ---------------------------------------------------------------------------
161
+
162
+ async function handleGetCompactionTrail({
163
+ pathParams = {},
164
+ queryParams = {},
165
+ }: RouteHandlerArgs): Promise<CompactionTrailResponse> {
166
+ const conversationId = pathParams.id;
167
+ const callId = queryParams.callId;
168
+
169
+ if (!conversationId) {
170
+ throw new BadRequestError("conversation id path parameter is required");
171
+ }
172
+ if (!callId) {
173
+ throw new BadRequestError("callId query parameter is required");
174
+ }
175
+
176
+ // Verify the conversation exists before we touch the log source —
177
+ // a missing conversation should 404, not return an empty trail with
178
+ // no signal that the caller had the wrong id.
179
+ const conversation = getConversation(conversationId);
180
+ if (!conversation) {
181
+ throw new NotFoundError(`Conversation ${conversationId} not found`);
182
+ }
183
+
184
+ const source = await getLlmRequestLogSource();
185
+ const selectedCall = await source.getRequestLogById(callId);
186
+ if (!selectedCall) {
187
+ throw new NotFoundError(`LLM call ${callId} not found`);
188
+ }
189
+ if (selectedCall.conversationId !== conversationId) {
190
+ // Treat a cross-conversation callId as a bad request rather than
191
+ // silently filtering against the wrong conversation. The frontend
192
+ // always pairs (conversationId, callId) from the same rail, so a
193
+ // mismatch is a real client bug — surface it.
194
+ throw new BadRequestError(
195
+ `LLM call ${callId} does not belong to conversation ${conversationId}`,
196
+ );
197
+ }
198
+
199
+ // Resolve the window floor — the most recent non-`compactionAgent`
200
+ // call before the selected one. `null` means the selected call is the
201
+ // first real call in the conversation, so every preceding compaction
202
+ // is in scope. The store function applies the strict-`>` predicate
203
+ // (or drops it entirely on null), so the selected call's own
204
+ // `createdAt` is the only ceiling we pass.
205
+ const afterCreatedAt = await source.getPreviousNonCompactionCallCreatedAt(
206
+ conversationId,
207
+ selectedCall.createdAt,
208
+ );
209
+ const logs = await source.getCompactionLogsBetween(
210
+ conversationId,
211
+ afterCreatedAt,
212
+ selectedCall.createdAt,
213
+ );
214
+
215
+ return {
216
+ conversationId,
217
+ events: logs.map(projectLogRowToCompactionTrailEvent),
218
+ };
219
+ }
220
+
221
+ // ---------------------------------------------------------------------------
222
+ // Route registration
223
+ // ---------------------------------------------------------------------------
224
+
225
+ export const ROUTES: RouteDefinition[] = [
226
+ {
227
+ operationId: "conversations_compaction_trail_get",
228
+ endpoint: "conversations/:id/compaction",
229
+ method: "GET",
230
+ policyKey: "conversations/compaction",
231
+ summary: "Get the compaction trail leading up to an LLM call",
232
+ description:
233
+ "Return the chronological list of compaction events that ran in this conversation in the open window between the previous non-`compactionAgent` LLM call and the call identified by `callId`. Projected from `llm_request_logs` rows where `call_site = \"compactionAgent\"`. When the selected call is the first real call in the conversation, every preceding compaction is in scope. Drives the Inspector's Compaction tab.",
234
+ tags: ["conversations"],
235
+ pathParams: [
236
+ {
237
+ name: "id",
238
+ description: "Internal conversation identifier.",
239
+ },
240
+ ],
241
+ queryParams: [
242
+ {
243
+ name: "callId",
244
+ required: true,
245
+ schema: { type: "string" },
246
+ description:
247
+ "ID of the selected LLM call from the rail. Defines the chronological cutoff for the trail.",
248
+ },
249
+ ],
250
+ responseBody: compactionTrailResponseSchema,
251
+ additionalResponses: {
252
+ "400": {
253
+ description:
254
+ "Returned when the callId is missing or refers to a call in a different conversation.",
255
+ },
256
+ "404": {
257
+ description:
258
+ "Returned when the conversation or the referenced LLM call does not exist.",
259
+ },
260
+ },
261
+ handler: handleGetCompactionTrail,
262
+ },
263
+ ];