@vellumai/assistant 0.8.4 → 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (802) hide show
  1. package/AGENTS.md +33 -1
  2. package/ARCHITECTURE.md +3 -3
  3. package/bunfig.toml +6 -1
  4. package/docs/browser-use-architecture-phase2.md +1 -1
  5. package/docs/credential-execution-service.md +6 -6
  6. package/docs/plugins.md +4 -3
  7. package/knip.json +2 -1
  8. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
  9. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
  10. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
  11. package/openapi.yaml +2748 -216
  12. package/package.json +1 -1
  13. package/src/__tests__/actor-token-service.test.ts +3 -2
  14. package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
  15. package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
  16. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
  17. package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
  18. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
  19. package/src/__tests__/annotate-risk-options.test.ts +1 -0
  20. package/src/__tests__/anthropic-provider.test.ts +34 -37
  21. package/src/__tests__/approval-cascade.test.ts +1 -0
  22. package/src/__tests__/approval-routes-http.test.ts +9 -13
  23. package/src/__tests__/assert-not-live-db.ts +79 -0
  24. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
  25. package/src/__tests__/assistant-feature-flags-integration.test.ts +12 -28
  26. package/src/__tests__/audit-log-rotation.test.ts +72 -18
  27. package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
  28. package/src/__tests__/background-workers-disk-pressure.test.ts +8 -11
  29. package/src/__tests__/browser-skill-endstate.test.ts +3 -3
  30. package/src/__tests__/btw-routes.test.ts +5 -5
  31. package/src/__tests__/call-controller.test.ts +3 -3
  32. package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
  33. package/src/__tests__/channel-approval-routes.test.ts +3 -2
  34. package/src/__tests__/channel-guardian.test.ts +6 -5
  35. package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
  36. package/src/__tests__/channel-reply-delivery.test.ts +35 -0
  37. package/src/__tests__/channel-retry-sweep.test.ts +320 -3
  38. package/src/__tests__/checker.test.ts +18 -27
  39. package/src/__tests__/compaction-events.test.ts +2 -0
  40. package/src/__tests__/compaction-trail-store.test.ts +264 -0
  41. package/src/__tests__/compactor-call-site-logging.test.ts +215 -0
  42. package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
  43. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +12 -16
  44. package/src/__tests__/computer-use-tools.test.ts +14 -18
  45. package/src/__tests__/config-loader-backfill.test.ts +13 -28
  46. package/src/__tests__/config-loader-corrupt.test.ts +5 -5
  47. package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
  48. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
  49. package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
  50. package/src/__tests__/config-schema.test.ts +10 -10
  51. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
  52. package/src/__tests__/connection-model-compat.test.ts +83 -0
  53. package/src/__tests__/contacts-tools.test.ts +3 -2
  54. package/src/__tests__/context-token-estimator.test.ts +22 -0
  55. package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
  56. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -1
  57. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
  58. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -1
  59. package/src/__tests__/conversation-agent-loop-overflow.test.ts +231 -2
  60. package/src/__tests__/conversation-agent-loop.test.ts +581 -54
  61. package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
  62. package/src/__tests__/conversation-app-control-instantiation.test.ts +31 -24
  63. package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
  64. package/src/__tests__/conversation-attention-store.test.ts +101 -0
  65. package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
  66. package/src/__tests__/conversation-clear-safety.test.ts +25 -25
  67. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
  68. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
  69. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  70. package/src/__tests__/conversation-error.test.ts +61 -0
  71. package/src/__tests__/conversation-fork-crud.test.ts +239 -15
  72. package/src/__tests__/conversation-fork-route.test.ts +3 -2
  73. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  74. package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
  75. package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
  76. package/src/__tests__/conversation-lifecycle.test.ts +53 -11
  77. package/src/__tests__/conversation-list-source.test.ts +3 -2
  78. package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
  79. package/src/__tests__/{conversation-load-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +14 -13
  80. package/src/__tests__/conversation-pairing.test.ts +53 -0
  81. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
  82. package/src/__tests__/conversation-process-callsite.test.ts +1 -0
  83. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  84. package/src/__tests__/conversation-queue.test.ts +333 -291
  85. package/src/__tests__/conversation-routes-disk-view.test.ts +112 -18
  86. package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
  87. package/src/__tests__/conversation-routes-slash-commands.test.ts +68 -2
  88. package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
  89. package/src/__tests__/conversation-skill-tools.test.ts +40 -147
  90. package/src/__tests__/conversation-slash-queue.test.ts +84 -32
  91. package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
  92. package/src/__tests__/conversation-speed-override.test.ts +1 -0
  93. package/src/__tests__/conversation-store.test.ts +1 -1
  94. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
  95. package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
  96. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
  97. package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
  98. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
  99. package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
  100. package/src/__tests__/conversation-sync-tags.test.ts +218 -35
  101. package/src/__tests__/conversation-title-service.test.ts +1 -0
  102. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
  103. package/src/__tests__/conversation-usage.test.ts +1 -0
  104. package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
  105. package/src/__tests__/conversation-workspace-injection.test.ts +6 -1
  106. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -1
  107. package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
  108. package/src/__tests__/credential-broker-server-use.test.ts +5 -5
  109. package/src/__tests__/credential-execution-client.test.ts +72 -1
  110. package/src/__tests__/credential-execution-feature-gates.test.ts +19 -19
  111. package/src/__tests__/credential-execution-tools.test.ts +6 -6
  112. package/src/__tests__/credential-health-service.test.ts +252 -3
  113. package/src/__tests__/credential-security-invariants.test.ts +6 -5
  114. package/src/__tests__/credential-vault-unit.test.ts +21 -21
  115. package/src/__tests__/credential-vault.test.ts +5 -5
  116. package/src/__tests__/cross-provider-web-search.test.ts +56 -2
  117. package/src/__tests__/db-connection-isolation.test.ts +7 -6
  118. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
  119. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
  120. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
  121. package/src/__tests__/db-test-helpers.ts +58 -0
  122. package/src/__tests__/disk-pressure-guard.test.ts +58 -41
  123. package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
  124. package/src/__tests__/disk-pressure-routes.test.ts +0 -33
  125. package/src/__tests__/disk-pressure-tools.test.ts +0 -4
  126. package/src/__tests__/dm-persistence.test.ts +26 -40
  127. package/src/__tests__/document-create-dedupe.test.ts +189 -0
  128. package/src/__tests__/document-find-replace.test.ts +3 -2
  129. package/src/__tests__/document-tool-security.test.ts +81 -2
  130. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  131. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
  132. package/src/__tests__/email-html-renderer.test.ts +12 -0
  133. package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
  134. package/src/__tests__/encrypted-store.test.ts +11 -9
  135. package/src/__tests__/feature-flag-test-helpers.ts +53 -0
  136. package/src/__tests__/filing-service.test.ts +1 -0
  137. package/src/__tests__/first-greeting.test.ts +62 -12
  138. package/src/__tests__/gateway-flag-listener.test.ts +236 -0
  139. package/src/__tests__/gemini-provider.test.ts +104 -0
  140. package/src/__tests__/guardian-action-sweep.test.ts +3 -2
  141. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  142. package/src/__tests__/guardian-outbound-http.test.ts +10 -7
  143. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
  144. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -1
  145. package/src/__tests__/heartbeat-disk-pressure.test.ts +5 -0
  146. package/src/__tests__/heartbeat-service.test.ts +5 -0
  147. package/src/__tests__/helpers/mock-logger.ts +26 -0
  148. package/src/__tests__/host-bash-routes.test.ts +1 -0
  149. package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
  150. package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
  151. package/src/__tests__/host-shell-tool.test.ts +6 -5
  152. package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
  153. package/src/__tests__/http-conversation-lineage.test.ts +3 -2
  154. package/src/__tests__/http-user-message-parity.test.ts +29 -7
  155. package/src/__tests__/identity-intro-cache.test.ts +133 -22
  156. package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
  157. package/src/__tests__/inference-profile-reaper.test.ts +3 -2
  158. package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
  159. package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
  160. package/src/__tests__/injector-disk-pressure.test.ts +3 -17
  161. package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
  162. package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
  163. package/src/__tests__/list-messages-tool-merge.test.ts +70 -11
  164. package/src/__tests__/llm-context-normalization.test.ts +42 -0
  165. package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
  166. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
  167. package/src/__tests__/llm-resolver.test.ts +408 -9
  168. package/src/__tests__/llm-schema.test.ts +1 -1
  169. package/src/__tests__/llm-usage-store.test.ts +66 -0
  170. package/src/__tests__/logger.test.ts +89 -0
  171. package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
  172. package/src/__tests__/mcp-abort-signal.test.ts +16 -2
  173. package/src/__tests__/mcp-client-auth.test.ts +14 -0
  174. package/src/__tests__/media-generate-image.test.ts +31 -0
  175. package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
  176. package/src/__tests__/messaging-send-tool.test.ts +1 -0
  177. package/src/__tests__/migration-import-from-url.test.ts +3 -3
  178. package/src/__tests__/mock-gateway-ipc.ts +18 -2
  179. package/src/__tests__/model-intents.test.ts +4 -6
  180. package/src/__tests__/native-web-search.test.ts +30 -2
  181. package/src/__tests__/notification-deep-link.test.ts +62 -0
  182. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  183. package/src/__tests__/oauth-commands-routes.test.ts +37 -0
  184. package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
  185. package/src/__tests__/oauth-store.test.ts +3 -2
  186. package/src/__tests__/onboarding-template-contract.test.ts +4 -3
  187. package/src/__tests__/openai-provider.test.ts +54 -9
  188. package/src/__tests__/openai-responses-provider.test.ts +176 -14
  189. package/src/__tests__/openrouter-provider-only.test.ts +27 -5
  190. package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
  191. package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
  192. package/src/__tests__/persistence-pipeline.test.ts +139 -1
  193. package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
  194. package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
  195. package/src/__tests__/platform.test.ts +2 -2
  196. package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
  197. package/src/__tests__/plugin-bootstrap.test.ts +11 -13
  198. package/src/__tests__/plugin-tool-contribution.test.ts +50 -40
  199. package/src/__tests__/plugin-types.test.ts +3 -2
  200. package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
  201. package/src/__tests__/pricing.test.ts +12 -0
  202. package/src/__tests__/process-message-background-slack.test.ts +21 -16
  203. package/src/__tests__/process-message-display-content.test.ts +19 -22
  204. package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
  205. package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
  206. package/src/__tests__/provider-registry-ollama.test.ts +45 -22
  207. package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
  208. package/src/__tests__/recording-handler.test.ts +1 -0
  209. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
  210. package/src/__tests__/registry.test.ts +84 -84
  211. package/src/__tests__/relay-server.test.ts +10 -10
  212. package/src/__tests__/require-fresh-approval.test.ts +2 -2
  213. package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
  214. package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
  215. package/src/__tests__/schedule-store.test.ts +16 -1
  216. package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
  217. package/src/__tests__/secret-ingress-http.test.ts +5 -1
  218. package/src/__tests__/secure-keys.test.ts +3 -3
  219. package/src/__tests__/send-endpoint-busy.test.ts +81 -42
  220. package/src/__tests__/server-history-render.test.ts +4 -1
  221. package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
  222. package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
  223. package/src/__tests__/skill-feature-flags.test.ts +16 -18
  224. package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
  225. package/src/__tests__/skill-projection-feature-flag.test.ts +48 -37
  226. package/src/__tests__/skill-projection.benchmark.test.ts +7 -13
  227. package/src/__tests__/skill-tool-factory.test.ts +97 -96
  228. package/src/__tests__/slack-channel-config.test.ts +3 -3
  229. package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
  230. package/src/__tests__/subagent-disposal.test.ts +27 -8
  231. package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
  232. package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
  233. package/src/__tests__/subagent-manager-notify.test.ts +20 -8
  234. package/src/__tests__/subagent-notify-parent.test.ts +6 -5
  235. package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
  236. package/src/__tests__/subagent-tools.test.ts +2 -1
  237. package/src/__tests__/suggestion-routes.test.ts +2 -0
  238. package/src/__tests__/sync-message-contract.test.ts +59 -0
  239. package/src/__tests__/system-prompt.test.ts +183 -131
  240. package/src/__tests__/terminal-tools.test.ts +1 -1
  241. package/src/__tests__/test-preload-verifier.ts +68 -0
  242. package/src/__tests__/test-preload.ts +32 -39
  243. package/src/__tests__/tool-approval-handler.test.ts +1 -5
  244. package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
  245. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
  246. package/src/__tests__/tool-executor-lifecycle-events.test.ts +35 -12
  247. package/src/__tests__/tool-executor.test.ts +64 -72
  248. package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
  249. package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
  250. package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
  251. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  252. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
  253. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
  254. package/src/__tests__/twilio-routes.test.ts +3 -2
  255. package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
  256. package/src/__tests__/usage-routes.test.ts +3 -0
  257. package/src/__tests__/validate-input.test.ts +381 -0
  258. package/src/__tests__/verification-control-plane-policy.test.ts +3 -2
  259. package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
  260. package/src/__tests__/voice-session-bridge.test.ts +37 -28
  261. package/src/__tests__/workspace-git-service.test.ts +6 -5
  262. package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
  263. package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
  264. package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
  265. package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
  266. package/src/acp/prepare-agent-env.ts +78 -0
  267. package/src/acp/session-manager.ts +6 -7
  268. package/src/agent/loop.ts +88 -0
  269. package/src/api/README.md +127 -0
  270. package/src/api/constants/call-sites.ts +27 -0
  271. package/src/api/events/assistant-outbound-attachment.ts +51 -0
  272. package/src/api/events/assistant-text-delta.ts +32 -0
  273. package/src/api/events/assistant-turn-start.ts +33 -0
  274. package/src/api/events/document-comment-created.ts +48 -0
  275. package/src/api/events/document-comment-deleted.ts +24 -0
  276. package/src/api/events/document-comment-reopened.ts +25 -0
  277. package/src/api/events/document-comment-resolved.ts +27 -0
  278. package/src/api/events/generation-cancelled.ts +24 -0
  279. package/src/api/events/generation-handoff.ts +41 -0
  280. package/src/api/events/message-complete.ts +42 -0
  281. package/src/api/events/open-url.ts +30 -0
  282. package/src/api/events/relationship-state-updated.ts +25 -0
  283. package/src/api/events/tool-use-start.ts +32 -0
  284. package/src/api/index.ts +129 -0
  285. package/src/api/package.json +10 -0
  286. package/src/api/responses/llm-context-response.ts +39 -0
  287. package/src/api/responses/llm-request-log-entry.ts +93 -0
  288. package/src/api/responses/memory-recall-log.ts +65 -0
  289. package/src/api/responses/memory-v2-activation-log.ts +78 -0
  290. package/src/background-wake/background-wake-routes.test.ts +868 -0
  291. package/src/background-wake/platform-client.test.ts +308 -0
  292. package/src/background-wake/platform-client.ts +167 -0
  293. package/src/background-wake/publisher.ts +91 -0
  294. package/src/background-wake/runtime-registry.ts +24 -0
  295. package/src/background-wake/wake-intent-hooks.test.ts +282 -0
  296. package/src/calls/guardian-dispatch.ts +1 -0
  297. package/src/calls/voice-session-bridge.ts +4 -4
  298. package/src/cli/commands/__tests__/browser.test.ts +23 -5
  299. package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
  300. package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
  301. package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
  302. package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
  303. package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
  304. package/src/cli/commands/__tests__/memory-v2.test.ts +1 -0
  305. package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
  306. package/src/cli/commands/__tests__/notifications.test.ts +184 -40
  307. package/src/cli/commands/browser.ts +247 -0
  308. package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
  309. package/src/cli/commands/channels/index.ts +229 -0
  310. package/src/cli/commands/domain.ts +91 -41
  311. package/src/cli/commands/inference.ts +93 -40
  312. package/src/cli/commands/memory-v2-compare-render.ts +115 -0
  313. package/src/cli/commands/memory-v2.ts +176 -1
  314. package/src/cli/commands/memory-v3-render.ts +491 -0
  315. package/src/cli/commands/memory-v3.ts +567 -0
  316. package/src/cli/commands/notifications.ts +365 -55
  317. package/src/cli/lib/open-browser.ts +7 -2
  318. package/src/cli/program.ts +4 -0
  319. package/src/config/assistant-feature-flags.ts +39 -46
  320. package/src/config/bundled-skills/document-editor/SKILL.md +16 -3
  321. package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
  322. package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
  323. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  324. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
  325. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
  326. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
  327. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
  328. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
  329. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
  330. package/src/config/bundled-skills/schedule/SKILL.md +1 -1
  331. package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
  332. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
  333. package/src/config/bundled-tool-registry.ts +2 -0
  334. package/src/config/call-site-defaults.ts +8 -7
  335. package/src/config/feature-flag-cache.ts +86 -0
  336. package/src/config/feature-flag-registry.json +33 -17
  337. package/src/config/llm-context-resolution.ts +10 -1
  338. package/src/config/llm-resolver.ts +121 -15
  339. package/src/config/loader.ts +4 -5
  340. package/src/config/schemas/__tests__/memory-v2.test.ts +228 -1
  341. package/src/config/schemas/call-site-catalog.ts +21 -7
  342. package/src/config/schemas/heartbeat.ts +1 -1
  343. package/src/config/schemas/llm.ts +102 -2
  344. package/src/config/schemas/memory-v2.ts +272 -0
  345. package/src/config/schemas/memory.ts +2 -1
  346. package/src/config/schemas/services.ts +6 -2
  347. package/src/config/seed-inference-profiles.ts +36 -16
  348. package/src/context/compactor.ts +52 -0
  349. package/src/context/token-estimator.ts +10 -5
  350. package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
  351. package/src/conversations/message-consolidation.ts +404 -0
  352. package/src/credential-execution/executable-discovery.ts +40 -0
  353. package/src/credential-execution/process-manager.ts +6 -2
  354. package/src/credential-health/credential-health-service.ts +125 -40
  355. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
  356. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
  357. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +2 -3
  358. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
  359. package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
  360. package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
  361. package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
  362. package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
  363. package/src/daemon/conversation-agent-loop-handlers.ts +390 -80
  364. package/src/daemon/conversation-agent-loop.ts +244 -90
  365. package/src/daemon/conversation-error.ts +64 -6
  366. package/src/daemon/conversation-lifecycle.ts +27 -22
  367. package/src/daemon/conversation-messaging.ts +84 -43
  368. package/src/daemon/conversation-process.ts +74 -37
  369. package/src/daemon/conversation-runtime-assembly.ts +38 -17
  370. package/src/daemon/conversation-skill-tools.ts +14 -30
  371. package/src/daemon/conversation-surfaces.ts +69 -34
  372. package/src/daemon/conversation-tool-setup.ts +77 -32
  373. package/src/daemon/conversation-usage.ts +2 -0
  374. package/src/daemon/conversation.ts +40 -75
  375. package/src/daemon/daemon-control.ts +1 -1
  376. package/src/daemon/daemon-skill-host.ts +9 -2
  377. package/src/daemon/disk-pressure-guard.ts +39 -29
  378. package/src/daemon/first-greeting.ts +31 -13
  379. package/src/daemon/handlers/config-model.test.ts +1 -0
  380. package/src/daemon/handlers/conversations.ts +11 -3
  381. package/src/daemon/handlers/shared.ts +6 -1
  382. package/src/daemon/host-browser-proxy.ts +5 -5
  383. package/src/daemon/host-cu-proxy.ts +4 -4
  384. package/src/daemon/host-file-proxy.ts +4 -4
  385. package/src/daemon/host-proxy-base.ts +4 -4
  386. package/src/daemon/host-transfer-proxy.ts +10 -10
  387. package/src/daemon/lifecycle.ts +29 -26
  388. package/src/daemon/mcp-reload-service.ts +1 -1
  389. package/src/daemon/meet-manifest-loader.ts +11 -24
  390. package/src/daemon/message-types/conversations.ts +22 -27
  391. package/src/daemon/message-types/document-comments.ts +8 -44
  392. package/src/daemon/message-types/home.ts +2 -14
  393. package/src/daemon/message-types/integrations.ts +2 -7
  394. package/src/daemon/message-types/messages.ts +25 -48
  395. package/src/daemon/message-types/subagents.ts +6 -0
  396. package/src/daemon/message-types/sync.ts +14 -0
  397. package/src/daemon/process-message.ts +9 -9
  398. package/src/daemon/providers-setup.ts +1 -1
  399. package/src/daemon/server.ts +16 -0
  400. package/src/daemon/shutdown-handlers.ts +24 -5
  401. package/src/daemon/switch-inference-profile-tool.ts +62 -0
  402. package/src/daemon/tool-setup-types.ts +7 -0
  403. package/src/daemon/wake-target-adapter.ts +10 -0
  404. package/src/documents/document-store.ts +38 -0
  405. package/src/export/__tests__/transcript-formatter.test.ts +1 -0
  406. package/src/heartbeat/__tests__/heartbeat-service.test.ts +30 -1
  407. package/src/heartbeat/heartbeat-service.ts +63 -0
  408. package/src/home/__tests__/feed-writer.test.ts +161 -0
  409. package/src/home/__tests__/post-connect-feed.test.ts +1 -0
  410. package/src/home/__tests__/suggested-prompts.test.ts +55 -59
  411. package/src/home/feed-writer.ts +146 -7
  412. package/src/home/home-greeting.ts +0 -9
  413. package/src/home/suggested-prompts.ts +27 -154
  414. package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
  415. package/src/ipc/gateway-client.test.ts +4 -1
  416. package/src/ipc/gateway-flag-listener.ts +123 -0
  417. package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
  418. package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
  419. package/src/ipc/skill-routes/memory.ts +4 -3
  420. package/src/ipc/skill-routes/registries.ts +35 -40
  421. package/src/memory/__tests__/db-async-query.test.ts +165 -0
  422. package/src/memory/__tests__/db-maintenance.test.ts +115 -0
  423. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +242 -0
  424. package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
  425. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
  426. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
  427. package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
  428. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
  429. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
  430. package/src/memory/auto-analysis-enqueue.ts +5 -1
  431. package/src/memory/conversation-attention-store.ts +17 -3
  432. package/src/memory/conversation-crud.ts +423 -182
  433. package/src/memory/conversation-starters-cadence.ts +3 -1
  434. package/src/memory/conversation-title-service.ts +19 -3
  435. package/src/memory/db-async-query.ts +214 -0
  436. package/src/memory/db-connection.ts +29 -19
  437. package/src/memory/db-init.ts +14 -0
  438. package/src/memory/db-maintenance.ts +30 -21
  439. package/src/memory/db-singleton.ts +77 -0
  440. package/src/memory/delivery-channels.ts +82 -0
  441. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
  442. package/src/memory/graph/bootstrap.ts +8 -1
  443. package/src/memory/graph/capability-seed.ts +7 -3
  444. package/src/memory/graph/conversation-graph-memory.ts +100 -17
  445. package/src/memory/graph/extraction.ts +1 -5
  446. package/src/memory/graph/graph-search.ts +7 -1
  447. package/src/memory/graph/retriever.test.ts +3 -3
  448. package/src/memory/indexer.ts +28 -18
  449. package/src/memory/job-handlers/cleanup.ts +76 -18
  450. package/src/memory/job-handlers/conversation-starters.ts +1 -4
  451. package/src/memory/job-handlers/embedding.test.ts +3 -2
  452. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
  453. package/src/memory/jobs/embed-pkb-file.ts +6 -1
  454. package/src/memory/jobs-store.ts +14 -0
  455. package/src/memory/jobs-worker.ts +66 -22
  456. package/src/memory/llm-request-log-source-clickhouse.ts +122 -2
  457. package/src/memory/llm-request-log-source-local.ts +31 -0
  458. package/src/memory/llm-request-log-source.ts +40 -2
  459. package/src/memory/llm-request-log-store.ts +228 -1
  460. package/src/memory/llm-usage-store.ts +24 -0
  461. package/src/memory/memory-retrospective-enqueue.ts +8 -1
  462. package/src/memory/memory-retrospective-job.ts +5 -0
  463. package/src/memory/memory-v2-activation-log-store.ts +110 -7
  464. package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
  465. package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
  466. package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
  467. package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
  468. package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
  469. package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
  470. package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
  471. package/src/memory/migrations/index.ts +19 -0
  472. package/src/memory/migrations/registry.ts +33 -0
  473. package/src/memory/schema/conversations.ts +10 -2
  474. package/src/memory/schema/inference.ts +0 -1
  475. package/src/memory/schema/infrastructure.ts +21 -0
  476. package/src/memory/tool-usage-store.ts +36 -8
  477. package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
  478. package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
  479. package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
  480. package/src/memory/v2/__tests__/harness-metrics.test.ts +83 -0
  481. package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
  482. package/src/memory/v2/__tests__/harness-replay-input.test.ts +230 -0
  483. package/src/memory/v2/__tests__/harness-runner.test.ts +135 -0
  484. package/src/memory/v2/__tests__/injection.test.ts +127 -98
  485. package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
  486. package/src/memory/v2/__tests__/router.test.ts +171 -3
  487. package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
  488. package/src/memory/v2/harness/compare.ts +57 -0
  489. package/src/memory/v2/harness/metrics.ts +128 -0
  490. package/src/memory/v2/harness/oracle.ts +145 -0
  491. package/src/memory/v2/harness/replay-input.ts +240 -0
  492. package/src/memory/v2/harness/retriever.ts +74 -0
  493. package/src/memory/v2/harness/router-retriever.ts +43 -0
  494. package/src/memory/v2/harness/runner.ts +112 -0
  495. package/src/memory/v2/harness/trace.ts +64 -0
  496. package/src/memory/v2/injection.ts +21 -15
  497. package/src/memory/v2/prompts/router.ts +26 -1
  498. package/src/memory/v2/qdrant.ts +14 -2
  499. package/src/memory/v2/router.ts +171 -18
  500. package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
  501. package/src/memory/v3/__tests__/consolidation-job.test.ts +466 -0
  502. package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
  503. package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
  504. package/src/memory/v3/__tests__/edges.test.ts +706 -0
  505. package/src/memory/v3/__tests__/filter.test.ts +560 -0
  506. package/src/memory/v3/__tests__/gate.test.ts +637 -0
  507. package/src/memory/v3/__tests__/index-composition.test.ts +291 -0
  508. package/src/memory/v3/__tests__/loop.test.ts +775 -0
  509. package/src/memory/v3/__tests__/retriever.test.ts +226 -0
  510. package/src/memory/v3/__tests__/scouts.test.ts +489 -0
  511. package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
  512. package/src/memory/v3/__tests__/shadow-middleware.test.ts +398 -0
  513. package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
  514. package/src/memory/v3/__tests__/traversal.test.ts +508 -0
  515. package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
  516. package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
  517. package/src/memory/v3/__tests__/tree-walk.test.ts +784 -0
  518. package/src/memory/v3/__tests__/validate.test.ts +277 -0
  519. package/src/memory/v3/auto-edges.ts +223 -0
  520. package/src/memory/v3/coactivation-store.ts +124 -0
  521. package/src/memory/v3/consolidation-job.ts +323 -0
  522. package/src/memory/v3/coretrieval-seed.ts +240 -0
  523. package/src/memory/v3/edge-learning-job.ts +160 -0
  524. package/src/memory/v3/edges.ts +286 -0
  525. package/src/memory/v3/filter.ts +286 -0
  526. package/src/memory/v3/gate.ts +349 -0
  527. package/src/memory/v3/index-composition.ts +126 -0
  528. package/src/memory/v3/llm-capture.ts +46 -0
  529. package/src/memory/v3/loop.ts +430 -0
  530. package/src/memory/v3/maintenance.ts +144 -0
  531. package/src/memory/v3/prompt-context.ts +33 -0
  532. package/src/memory/v3/prompts/consolidation.ts +458 -0
  533. package/src/memory/v3/prompts/system-prompts.ts +196 -0
  534. package/src/memory/v3/retriever.ts +33 -0
  535. package/src/memory/v3/scouts.ts +431 -0
  536. package/src/memory/v3/shadow-diff.ts +287 -0
  537. package/src/memory/v3/shadow-middleware.ts +347 -0
  538. package/src/memory/v3/traversal.ts +211 -0
  539. package/src/memory/v3/tree-index.ts +237 -0
  540. package/src/memory/v3/tree-store.ts +394 -0
  541. package/src/memory/v3/tree-walk.ts +356 -0
  542. package/src/memory/v3/types.ts +65 -0
  543. package/src/memory/v3/validate.ts +323 -0
  544. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
  545. package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
  546. package/src/notifications/adapters/macos.ts +18 -1
  547. package/src/notifications/adapters/platform.ts +1 -1
  548. package/src/notifications/adapters/slack.ts +45 -11
  549. package/src/notifications/broadcaster.ts +114 -63
  550. package/src/notifications/conversation-pairing.ts +23 -3
  551. package/src/notifications/decision-engine.ts +1 -4
  552. package/src/notifications/decisions-store.ts +32 -1
  553. package/src/notifications/deliveries-store.ts +45 -0
  554. package/src/notifications/edit-notification.ts +201 -0
  555. package/src/notifications/emit-signal.ts +40 -50
  556. package/src/notifications/signal.ts +10 -0
  557. package/src/notifications/types.ts +37 -0
  558. package/src/oauth/byo-connection.test.ts +67 -3
  559. package/src/oauth/byo-connection.ts +32 -5
  560. package/src/oauth/connect-orchestrator.ts +9 -0
  561. package/src/oauth/connection-resolver.test.ts +76 -0
  562. package/src/oauth/connection-resolver.ts +49 -10
  563. package/src/oauth/manual-token-connection.ts +51 -3
  564. package/src/oauth/seed-providers.ts +3 -0
  565. package/src/permissions/approval-policy.test.ts +19 -5
  566. package/src/permissions/approval-policy.ts +14 -3
  567. package/src/permissions/checker.ts +21 -8
  568. package/src/permissions/prompter.ts +3 -3
  569. package/src/permissions/question-prompter.ts +5 -2
  570. package/src/permissions/secret-prompter.ts +2 -2
  571. package/src/platform/client.test.ts +24 -1
  572. package/src/platform/client.ts +8 -0
  573. package/src/platform/feature-gate.ts +15 -0
  574. package/src/plugin-api/index.ts +4 -0
  575. package/src/plugin-api/types.ts +7 -33
  576. package/src/plugins/defaults/index.ts +6 -0
  577. package/src/plugins/defaults/injectors.ts +20 -19
  578. package/src/plugins/defaults/persistence.ts +25 -6
  579. package/src/plugins/external-plugin-loader.ts +5 -68
  580. package/src/plugins/types.ts +68 -29
  581. package/src/proactive-artifact/aux-message-injector.ts +17 -4
  582. package/src/proactive-artifact/job.test.ts +1 -0
  583. package/src/prompts/__tests__/system-prompt.test.ts +4 -4
  584. package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
  585. package/src/prompts/persona-resolver.ts +36 -21
  586. package/src/prompts/sections.ts +39 -7
  587. package/src/prompts/system-prompt.ts +84 -221
  588. package/src/prompts/template-detection.ts +10 -4
  589. package/src/prompts/templates/BOOTSTRAP.md +9 -13
  590. package/src/prompts/templates/IDENTITY.md +0 -2
  591. package/src/prompts/templates/system-sections.ts +230 -8
  592. package/src/providers/__tests__/connection-model-compat.test.ts +233 -0
  593. package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
  594. package/src/providers/__tests__/retry-callsite.test.ts +85 -5
  595. package/src/providers/anthropic/client.ts +32 -66
  596. package/src/providers/call-site-routing.ts +42 -6
  597. package/src/providers/connection-model-compat.ts +61 -0
  598. package/src/providers/connection-resolution.ts +47 -14
  599. package/src/providers/fireworks/client.ts +1 -0
  600. package/src/providers/gemini/client.ts +70 -6
  601. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
  602. package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
  603. package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
  604. package/src/providers/inference/adapter-factory.ts +3 -0
  605. package/src/providers/inference/auth.ts +0 -8
  606. package/src/providers/inference/connections.ts +3 -66
  607. package/src/providers/inference/resolve-auth.ts +2 -3
  608. package/src/providers/minimax/client.ts +106 -0
  609. package/src/providers/model-catalog.ts +78 -1
  610. package/src/providers/model-intents.ts +4 -4
  611. package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
  612. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
  613. package/src/providers/openai/chat-completions-provider.ts +116 -15
  614. package/src/providers/openai/codex-models.ts +20 -0
  615. package/src/providers/openai/responses-provider.ts +87 -30
  616. package/src/providers/openrouter/client.ts +13 -8
  617. package/src/providers/provider-send-message.ts +20 -5
  618. package/src/providers/registry.ts +48 -8
  619. package/src/providers/retry.ts +50 -7
  620. package/src/providers/search-provider-catalog.ts +17 -9
  621. package/src/providers/thinking-config.ts +26 -1
  622. package/src/providers/types.ts +9 -0
  623. package/src/providers/usage-tracking.ts +2 -0
  624. package/src/runtime/AGENTS.md +2 -2
  625. package/src/runtime/__tests__/agent-wake.test.ts +1 -0
  626. package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
  627. package/src/runtime/access-request-helper.ts +1 -0
  628. package/src/runtime/agent-wake.ts +1 -0
  629. package/src/runtime/assistant-event-hub.ts +76 -6
  630. package/src/runtime/auth/route-policy.ts +46 -0
  631. package/src/runtime/btw-sidechain.ts +0 -6
  632. package/src/runtime/channel-readiness-service.ts +68 -0
  633. package/src/runtime/channel-reply-delivery.ts +23 -0
  634. package/src/runtime/channel-retry-sweep.ts +47 -14
  635. package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
  636. package/src/runtime/http-types.ts +0 -2
  637. package/src/runtime/migrations/vbundle-builder.ts +12 -4
  638. package/src/runtime/pending-interactions.ts +0 -1
  639. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
  640. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
  641. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +204 -0
  642. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  643. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
  644. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
  645. package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +76 -9
  646. package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
  647. package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
  648. package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
  649. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
  650. package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
  651. package/src/runtime/routes/acp-routes-list.test.ts +3 -0
  652. package/src/runtime/routes/acp-routes.test.ts +255 -6
  653. package/src/runtime/routes/acp-routes.ts +8 -1
  654. package/src/runtime/routes/app-management-routes.ts +111 -4
  655. package/src/runtime/routes/avatar-routes.ts +10 -10
  656. package/src/runtime/routes/background-wake-routes.ts +356 -0
  657. package/src/runtime/routes/browser-tabs-routes.ts +200 -0
  658. package/src/runtime/routes/btw-routes.ts +4 -10
  659. package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
  660. package/src/runtime/routes/conversation-cli-routes.ts +1 -1
  661. package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
  662. package/src/runtime/routes/conversation-list-routes.ts +159 -4
  663. package/src/runtime/routes/conversation-management-routes.ts +108 -26
  664. package/src/runtime/routes/conversation-query-routes.ts +200 -44
  665. package/src/runtime/routes/conversation-routes.ts +409 -521
  666. package/src/runtime/routes/conversation-starter-routes.ts +6 -3
  667. package/src/runtime/routes/conversations-import-routes.ts +19 -6
  668. package/src/runtime/routes/disk-pressure-routes.ts +1 -1
  669. package/src/runtime/routes/documents-routes.ts +10 -1
  670. package/src/runtime/routes/domain-routes.ts +60 -10
  671. package/src/runtime/routes/email-routes.ts +5 -2
  672. package/src/runtime/routes/events-routes.ts +54 -10
  673. package/src/runtime/routes/group-routes.ts +35 -8
  674. package/src/runtime/routes/home-feed-routes.ts +129 -0
  675. package/src/runtime/routes/host-browser-routes.ts +10 -2
  676. package/src/runtime/routes/host-cu-routes.ts +2 -2
  677. package/src/runtime/routes/identity-intro-cache.ts +61 -16
  678. package/src/runtime/routes/identity-routes.ts +30 -9
  679. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
  680. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
  681. package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
  682. package/src/runtime/routes/index.ts +10 -0
  683. package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
  684. package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
  685. package/src/runtime/routes/inference-provider-connection-routes.ts +5 -26
  686. package/src/runtime/routes/integrations/vercel.ts +15 -0
  687. package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
  688. package/src/runtime/routes/llm-context-normalization.ts +7 -2
  689. package/src/runtime/routes/memory-item-routes.ts +8 -3
  690. package/src/runtime/routes/memory-v2-routes.ts +215 -5
  691. package/src/runtime/routes/memory-v3-routes.ts +474 -0
  692. package/src/runtime/routes/migration-routes.ts +32 -28
  693. package/src/runtime/routes/notification-routes.ts +63 -1
  694. package/src/runtime/routes/oauth-commands-routes.ts +6 -1
  695. package/src/runtime/routes/plugins-routes.ts +337 -0
  696. package/src/runtime/routes/rename-conversation-routes.ts +6 -2
  697. package/src/runtime/routes/secret-routes.ts +25 -5
  698. package/src/runtime/routes/settings-routes.ts +12 -11
  699. package/src/runtime/routes/slack-channel-routes.ts +5 -4
  700. package/src/runtime/routes/surface-action-routes.ts +1 -38
  701. package/src/runtime/routes/surface-content-routes.ts +12 -5
  702. package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
  703. package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
  704. package/src/runtime/routes/workspace-routes.ts +25 -10
  705. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
  706. package/src/runtime/slack-dm-text-delivery.ts +177 -0
  707. package/src/runtime/sync/resource-sync-events.ts +106 -38
  708. package/src/runtime/sync/sync-publisher.test.ts +49 -0
  709. package/src/runtime/sync/sync-publisher.ts +2 -1
  710. package/src/runtime/tool-grant-request-helper.ts +1 -0
  711. package/src/runtime/verification-outbound-actions.ts +73 -1
  712. package/src/schedule/schedule-store.ts +8 -1
  713. package/src/schedule/scheduler.ts +111 -15
  714. package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
  715. package/src/security/encrypted-store.ts +7 -16
  716. package/src/security/store-path-override.ts +61 -0
  717. package/src/signals/user-message.ts +5 -8
  718. package/src/skills/validate-input.ts +177 -0
  719. package/src/subagent/manager.ts +13 -13
  720. package/src/subagent/types.ts +6 -0
  721. package/src/tasks/tool-sanitizer.ts +2 -2
  722. package/src/telemetry/types.ts +12 -0
  723. package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
  724. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  725. package/src/tools/acp/spawn.test.ts +119 -0
  726. package/src/tools/acp/spawn.ts +15 -2
  727. package/src/tools/apps/definitions.ts +36 -28
  728. package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
  729. package/src/tools/ask-question/ask-question-tool.ts +38 -45
  730. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
  731. package/src/tools/browser/__tests__/pinned-tabs.test.ts +70 -0
  732. package/src/tools/browser/browser-execution.ts +16 -3
  733. package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
  734. package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
  735. package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
  736. package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
  737. package/src/tools/browser/cdp-client/factory.ts +100 -17
  738. package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
  739. package/src/tools/browser/cdp-client/types.ts +65 -0
  740. package/src/tools/browser/pinned-tabs.ts +96 -40
  741. package/src/tools/computer-use/definitions.ts +282 -336
  742. package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
  743. package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
  744. package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
  745. package/src/tools/credentials/vault.ts +3 -9
  746. package/src/tools/document/document-tool.ts +189 -7
  747. package/src/tools/execution-target.ts +18 -23
  748. package/src/tools/executor.ts +24 -56
  749. package/src/tools/filesystem/edit.ts +3 -9
  750. package/src/tools/filesystem/list.ts +3 -9
  751. package/src/tools/filesystem/read.ts +3 -9
  752. package/src/tools/filesystem/write.ts +3 -9
  753. package/src/tools/host-filesystem/edit.test.ts +1 -0
  754. package/src/tools/host-filesystem/edit.ts +3 -9
  755. package/src/tools/host-filesystem/read.test.ts +1 -0
  756. package/src/tools/host-filesystem/read.ts +3 -9
  757. package/src/tools/host-filesystem/transfer.test.ts +31 -6
  758. package/src/tools/host-filesystem/transfer.ts +3 -9
  759. package/src/tools/host-filesystem/write.test.ts +1 -0
  760. package/src/tools/host-filesystem/write.ts +3 -9
  761. package/src/tools/host-terminal/host-shell.ts +3 -9
  762. package/src/tools/mcp/mcp-tool-factory.ts +1 -10
  763. package/src/tools/memory/register.test.ts +1 -1
  764. package/src/tools/memory/register.ts +4 -9
  765. package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
  766. package/src/tools/network/__tests__/web-search.test.ts +211 -3
  767. package/src/tools/network/managed-search-proxy.ts +183 -0
  768. package/src/tools/network/web-fetch.ts +3 -9
  769. package/src/tools/network/web-search.ts +224 -76
  770. package/src/tools/policy-context.ts +3 -1
  771. package/src/tools/registry.ts +150 -123
  772. package/src/tools/schedule/create.ts +1 -1
  773. package/src/tools/schema-transforms.ts +1 -1
  774. package/src/tools/skills/execute.ts +3 -9
  775. package/src/tools/skills/load.ts +3 -9
  776. package/src/tools/skills/skill-tool-factory.ts +18 -44
  777. package/src/tools/subagent/notify-parent.ts +3 -9
  778. package/src/tools/subagent/spawn.ts +3 -0
  779. package/src/tools/system/request-permission.ts +3 -9
  780. package/src/tools/terminal/shell.ts +3 -9
  781. package/src/tools/tool-approval-handler.ts +10 -4
  782. package/src/tools/tool-defaults.ts +94 -0
  783. package/src/tools/tool-name-aliases.ts +72 -14
  784. package/src/tools/types.ts +32 -101
  785. package/src/tools/ui-surface/definitions.ts +104 -108
  786. package/src/types/onboarding-context.ts +6 -0
  787. package/src/usage/attribution.ts +32 -1
  788. package/src/usage/pricing.ts +23 -0
  789. package/src/usage/types.ts +12 -0
  790. package/src/util/browser.ts +7 -2
  791. package/src/util/logger.ts +16 -7
  792. package/src/util/platform.ts +7 -2
  793. package/src/util/sqlite3-runtime.ts +65 -0
  794. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
  795. package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
  796. package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
  797. package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
  798. package/src/workspace/migrations/registry.ts +6 -0
  799. package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
  800. package/src/__tests__/message-complete-display-id.test.ts +0 -175
  801. package/src/daemon/query-complexity-router.ts +0 -75
  802. package/src/prompts/cache-boundary.ts +0 -8
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Tests for the surface-content route handler.
3
+ *
4
+ * Focus is the rehydrate-on-miss path: after daemon restart or LRU
5
+ * eviction, the in-memory conversation map is empty even though the
6
+ * surface still persists as a `ui_surface` content block in the
7
+ * messages table. The handler must fall back to a DB scan via the
8
+ * shared `resolveSurfaceConversation` helper, which calls
9
+ * `getOrCreateConversation` to rehydrate the conversation. The
10
+ * rehydration runs `restoreSurfaceStateFromHistory()` in production,
11
+ * which is what repopulates the surfaceState the handler then reads
12
+ * from — in tests we simulate the rehydrated conversation by stubbing
13
+ * `getOrCreateConversation`'s return value with pre-populated
14
+ * `surfaceState`.
15
+ *
16
+ * Strategy mirrors `surface-action-routes.test.ts`: mock the
17
+ * `conversation-store` and `raw-query` modules at their boundary so
18
+ * the resolver code path executes against the test doubles, import
19
+ * ROUTES afterwards, and dispatch by operationId.
20
+ */
21
+
22
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // Mock state
26
+ // ---------------------------------------------------------------------------
27
+
28
+ interface StoredSurface {
29
+ surfaceType: string;
30
+ title: string | null;
31
+ data: Record<string, unknown>;
32
+ }
33
+
34
+ interface StubConversation {
35
+ id: string;
36
+ surfaceState: Map<string, StoredSurface>;
37
+ currentTurnSurfaces?: Array<{
38
+ surfaceId: string;
39
+ surfaceType: string;
40
+ title?: string | null;
41
+ data: Record<string, unknown>;
42
+ }>;
43
+ }
44
+
45
+ let memoryById: StubConversation | null = null;
46
+ let rehydrated: StubConversation | null = null;
47
+ let rawGetReturn: { conversation_id: string } | null = null;
48
+
49
+ const findConvCalls: string[] = [];
50
+ const findBySurfaceCalls: string[] = [];
51
+ const getOrCreateCalls: string[] = [];
52
+ const rawGetCalls: Array<{ sql: string; params: unknown[] }> = [];
53
+
54
+ mock.module("../../../daemon/conversation-store.js", () => ({
55
+ findConversation: (id: string) => {
56
+ findConvCalls.push(id);
57
+ return memoryById ?? undefined;
58
+ },
59
+ findConversationBySurfaceId: (surfaceId: string) => {
60
+ findBySurfaceCalls.push(surfaceId);
61
+ return undefined;
62
+ },
63
+ getOrCreateConversation: async (id: string) => {
64
+ getOrCreateCalls.push(id);
65
+ if (!rehydrated) {
66
+ throw new Error(
67
+ `getOrCreateConversation(${id}) called but no rehydrated stub configured`,
68
+ );
69
+ }
70
+ return rehydrated;
71
+ },
72
+ }));
73
+
74
+ mock.module("../../../memory/raw-query.js", () => ({
75
+ rawGet: (sql: string, ...params: unknown[]) => {
76
+ rawGetCalls.push({ sql, params });
77
+ return rawGetReturn;
78
+ },
79
+ }));
80
+
81
+ // Defer route import until after mocks are installed.
82
+ const { ROUTES } = await import("../surface-content-routes.js");
83
+ const { BadRequestError, NotFoundError } = await import("../errors.js");
84
+ import type { RouteDefinition } from "../types.js";
85
+
86
+ function findHandler(operationId: string): RouteDefinition["handler"] {
87
+ const route = ROUTES.find((r) => r.operationId === operationId);
88
+ if (!route) throw new Error(`Route ${operationId} not found`);
89
+ return route.handler;
90
+ }
91
+
92
+ function makeStub(id: string): StubConversation {
93
+ return { id, surfaceState: new Map() };
94
+ }
95
+
96
+ // ---------------------------------------------------------------------------
97
+ // Setup
98
+ // ---------------------------------------------------------------------------
99
+
100
+ beforeEach(() => {
101
+ memoryById = null;
102
+ rehydrated = null;
103
+ rawGetReturn = null;
104
+ findConvCalls.length = 0;
105
+ findBySurfaceCalls.length = 0;
106
+ getOrCreateCalls.length = 0;
107
+ rawGetCalls.length = 0;
108
+ });
109
+
110
+ // ---------------------------------------------------------------------------
111
+ // surfaces_get_content
112
+ // ---------------------------------------------------------------------------
113
+
114
+ describe("surfaces_get_content handler", () => {
115
+ test("serves surface from in-memory surfaceState", async () => {
116
+ const conv = makeStub("conv-active");
117
+ conv.surfaceState.set("surf-1", {
118
+ surfaceType: "card",
119
+ title: "T",
120
+ data: { foo: "bar" },
121
+ });
122
+ memoryById = conv;
123
+
124
+ const handler = findHandler("surfaces_get_content");
125
+ const result = await handler({
126
+ pathParams: { surfaceId: "surf-1" },
127
+ queryParams: { conversationId: "conv-active" },
128
+ });
129
+
130
+ expect(result).toEqual({
131
+ surfaceId: "surf-1",
132
+ surfaceType: "card",
133
+ title: "T",
134
+ data: { foo: "bar" },
135
+ });
136
+ expect(findConvCalls).toEqual(["conv-active"]);
137
+ // Fast path — never touched the DB or rehydration helpers.
138
+ expect(rawGetCalls).toEqual([]);
139
+ expect(getOrCreateCalls).toEqual([]);
140
+ });
141
+
142
+ test("falls back to currentTurnSurfaces when surfaceState misses", async () => {
143
+ const conv = makeStub("conv-mid-turn");
144
+ conv.currentTurnSurfaces = [
145
+ {
146
+ surfaceId: "surf-pending",
147
+ surfaceType: "list",
148
+ title: "Picks",
149
+ data: { items: [] },
150
+ },
151
+ ];
152
+ memoryById = conv;
153
+
154
+ const handler = findHandler("surfaces_get_content");
155
+ const result = await handler({
156
+ pathParams: { surfaceId: "surf-pending" },
157
+ queryParams: { conversationId: "conv-mid-turn" },
158
+ });
159
+
160
+ expect(result).toEqual({
161
+ surfaceId: "surf-pending",
162
+ surfaceType: "list",
163
+ title: "Picks",
164
+ data: { items: [] },
165
+ });
166
+ });
167
+
168
+ // -------------------------------------------------------------------------
169
+ // The bug fix: rehydration on in-memory miss.
170
+ // -------------------------------------------------------------------------
171
+ test("rehydrates from DB when the conversation is not in memory", async () => {
172
+ // Simulate post-restart or post-eviction: nothing in memory, but the
173
+ // surface exists in the messages table and rehydration restores the
174
+ // conversation with its surfaceState repopulated from history.
175
+ memoryById = null;
176
+ rawGetReturn = { conversation_id: "conv-evicted" };
177
+ const restored = makeStub("conv-evicted");
178
+ restored.surfaceState.set("surf-restored", {
179
+ surfaceType: "card",
180
+ title: "Restored",
181
+ data: { from: "history" },
182
+ });
183
+ rehydrated = restored;
184
+
185
+ const handler = findHandler("surfaces_get_content");
186
+ const result = await handler({
187
+ pathParams: { surfaceId: "surf-restored" },
188
+ queryParams: { conversationId: "conv-evicted" },
189
+ });
190
+
191
+ expect(result).toEqual({
192
+ surfaceId: "surf-restored",
193
+ surfaceType: "card",
194
+ title: "Restored",
195
+ data: { from: "history" },
196
+ });
197
+ // Hit the in-memory map first, missed, fell through to the DB scan,
198
+ // then rehydrated. The DB scan keyed on the surfaceId.
199
+ expect(findConvCalls).toEqual(["conv-evicted"]);
200
+ expect(rawGetCalls).toHaveLength(1);
201
+ expect(rawGetCalls[0]!.params[0]).toBe(`%"surfaceId":"surf-restored"%`);
202
+ expect(getOrCreateCalls).toEqual(["conv-evicted"]);
203
+ });
204
+
205
+ test("400s when conversationId is missing", async () => {
206
+ const handler = findHandler("surfaces_get_content");
207
+
208
+ let caught: unknown;
209
+ try {
210
+ await handler({
211
+ pathParams: { surfaceId: "surf-1" },
212
+ queryParams: {},
213
+ });
214
+ } catch (err) {
215
+ caught = err;
216
+ }
217
+
218
+ expect(caught).toBeInstanceOf(BadRequestError);
219
+ expect(findConvCalls).toEqual([]);
220
+ });
221
+
222
+ test("404s when no row in the DB matches the surfaceId (truly unknown surface)", async () => {
223
+ // Cold-cache miss with no DB row — the surfaceId is bogus or has
224
+ // never been persisted. We must 404, not rehydrate a phantom
225
+ // conversation for the caller-supplied conversationId.
226
+ memoryById = null;
227
+ rawGetReturn = null;
228
+
229
+ const handler = findHandler("surfaces_get_content");
230
+
231
+ let caught: unknown;
232
+ try {
233
+ await handler({
234
+ pathParams: { surfaceId: "surf-missing" },
235
+ queryParams: { conversationId: "conv-unknown" },
236
+ });
237
+ } catch (err) {
238
+ caught = err;
239
+ }
240
+
241
+ expect(caught).toBeInstanceOf(NotFoundError);
242
+ // Rehydration must NOT have been called — otherwise an arbitrary
243
+ // caller could materialize empty conversations for any UUID.
244
+ expect(getOrCreateCalls).toEqual([]);
245
+ });
246
+
247
+ test("404s when the DB row's conversation_id mismatches the caller's", async () => {
248
+ // The surface lives on a different conversation than the caller
249
+ // claims. Refusing to rehydrate prevents cross-conversation
250
+ // information leakage via guessable surfaceIds.
251
+ memoryById = null;
252
+ rawGetReturn = { conversation_id: "conv-actual-owner" };
253
+
254
+ const handler = findHandler("surfaces_get_content");
255
+
256
+ let caught: unknown;
257
+ try {
258
+ await handler({
259
+ pathParams: { surfaceId: "surf-leaked" },
260
+ queryParams: { conversationId: "conv-attacker" },
261
+ });
262
+ } catch (err) {
263
+ caught = err;
264
+ }
265
+
266
+ expect(caught).toBeInstanceOf(NotFoundError);
267
+ expect(getOrCreateCalls).toEqual([]);
268
+ });
269
+
270
+ test("404s when rehydration succeeds but the surface still isn't present", async () => {
271
+ // Adversarial sanity check: the DB scan found a row pointing at a
272
+ // conversation, but after rehydration the surface neither lives in
273
+ // surfaceState nor in currentTurnSurfaces. (Shouldn't really
274
+ // happen given the scan keyed on the surfaceId — defensive.)
275
+ memoryById = null;
276
+ rawGetReturn = { conversation_id: "conv-evicted" };
277
+ rehydrated = makeStub("conv-evicted"); // empty surfaceState
278
+
279
+ const handler = findHandler("surfaces_get_content");
280
+
281
+ let caught: unknown;
282
+ try {
283
+ await handler({
284
+ pathParams: { surfaceId: "surf-gone" },
285
+ queryParams: { conversationId: "conv-evicted" },
286
+ });
287
+ } catch (err) {
288
+ caught = err;
289
+ }
290
+
291
+ expect(caught).toBeInstanceOf(NotFoundError);
292
+ expect(getOrCreateCalls).toEqual(["conv-evicted"]);
293
+ });
294
+ });
@@ -195,9 +195,54 @@ mock.module("../../../tools/tasks/work-item-run.js", () => ({
195
195
  }));
196
196
 
197
197
  // Also mock getWorkspaceDir so handlers don't hit the real filesystem
198
- mock.module("../../../util/platform.js", () => ({
199
- getWorkspaceDir: () => "/mock/workspace",
200
- }));
198
+ mock.module("../../../util/platform.js", () => {
199
+ const stub = () => "/mock/workspace";
200
+ return {
201
+ getWorkspaceDir: () => "/mock/workspace",
202
+ vellumRoot: stub,
203
+ isMacOS: () => false,
204
+ isLinux: () => true,
205
+ isWindows: () => false,
206
+ getPlatformName: () => "linux",
207
+ normalizeAssistantId: (id: string) => id,
208
+ getDataDir: stub,
209
+ getEmbeddingModelsDir: stub,
210
+ getSandboxRootDir: stub,
211
+ getSandboxWorkingDir: stub,
212
+ getSoundsDir: stub,
213
+ getAvatarDir: stub,
214
+ AVATAR_IMAGE_FILENAME: "avatar-image.png",
215
+ getAvatarImagePath: stub,
216
+ getXdgVellumConfigDirName: () => ".vellum",
217
+ getPidPath: stub,
218
+ getDbPath: stub,
219
+ getLogsDir: stub,
220
+ getHistoryPath: stub,
221
+ getProtectedDir: stub,
222
+ getSignalsDir: stub,
223
+ getDaemonStderrLogPath: stub,
224
+ getDaemonStartupLockPath: stub,
225
+ getExternalDir: stub,
226
+ getBinDir: stub,
227
+ getDotEnvPath: stub,
228
+ getEmbedWorkerPidPath: stub,
229
+ getWorkspaceDirDisplay: stub,
230
+ getWorkspaceConfigPath: stub,
231
+ getWorkspaceSkillsDir: stub,
232
+ getWorkspaceHooksDir: stub,
233
+ getWorkspacePluginsDir: stub,
234
+ getWorkspaceRoutesDir: stub,
235
+ getDeprecatedDir: stub,
236
+ getConversationsDir: stub,
237
+ getWorkspacePromptPath: stub,
238
+ getProfilerRootDir: stub,
239
+ getProfilerRunsDir: stub,
240
+ getProfilerRunDir: stub,
241
+ getSkillRuntimePath: stub,
242
+ getBundledBunPath: () => undefined,
243
+ ensureDataDir: () => {},
244
+ };
245
+ });
201
246
 
202
247
  // ---------------------------------------------------------------------------
203
248
  // Import route definitions after mocking
@@ -44,6 +44,9 @@ mock.module("../../memory/db-connection.js", () => {
44
44
  builder.all = () => [];
45
45
  return {
46
46
  getDb: () => builder,
47
+ getSqlite: () => ({ __stub: true }),
48
+ getSqliteFrom: () => ({ __stub: true }),
49
+ resetDb: () => {},
47
50
  };
48
51
  });
49
52
 
@@ -4,6 +4,10 @@
4
4
  * Suites:
5
5
  * - POST /v1/acp/spawn — the three failure paths produced by
6
6
  * `resolveAcpAgent` (acp_disabled, unknown_agent, binary_not_found).
7
+ * - POST /v1/acp/spawn (env injection) — CLAUDE_CODE_OAUTH_TOKEN is read
8
+ * from the secure store under the canonical
9
+ * `credential/acp/claude_oauth_token` key (built by `credentialKey()`)
10
+ * and merged into `agentConfig.env` ONLY for the `claude` agent.
7
11
  * - DELETE /v1/acp/sessions?status=completed — the bulk-clear route that
8
12
  * wipes terminal-state rows (completed/failed/cancelled) from
9
13
  * `acp_session_history` while leaving running/initializing rows intact.
@@ -42,10 +46,21 @@ afterAll(() => {
42
46
  });
43
47
 
44
48
  // Stub `getAcpSessionManager` so the DELETE /:id tests can drive the
45
- // in-memory-status check without spawning real ACP processes. Stored in
46
- // a mutable map so individual tests can plant arbitrary states.
49
+ // in-memory-status check without spawning real ACP processes, and so the
50
+ // env-injection spawn tests can capture the `agentConfig` arg without
51
+ // launching a real subprocess. Stored in mutable state so individual tests
52
+ // can plant arbitrary states / inspect capture.
47
53
  const inMemoryStates = new Map<string, AcpSessionState>();
48
54
 
55
+ interface CapturedSpawn {
56
+ agent: string;
57
+ agentConfig: { env?: Record<string, string> };
58
+ task: string;
59
+ conversationId: string;
60
+ }
61
+
62
+ const capturedSpawns: CapturedSpawn[] = [];
63
+
49
64
  mock.module("../../acp/index.js", () => ({
50
65
  getAcpSessionManager: () => ({
51
66
  getStatus: (id?: string) => {
@@ -56,9 +71,27 @@ mock.module("../../acp/index.js", () => ({
56
71
  if (!state) throw new Error(`ACP session "${id}" not found`);
57
72
  return state;
58
73
  },
74
+ spawn: async (
75
+ agent: string,
76
+ agentConfig: { env?: Record<string, string> },
77
+ task: string,
78
+ _cwd: string | undefined,
79
+ conversationId: string,
80
+ ) => {
81
+ capturedSpawns.push({ agent, agentConfig, task, conversationId });
82
+ return { acpSessionId: "acp-test", protocolSessionId: "proto-test" };
83
+ },
59
84
  }),
60
85
  }));
61
86
 
87
+ // Stub secure-keys so env-injection tests can plant a known token (or
88
+ // absence). Driven via `secureKeyStore` per test in beforeEach.
89
+ const secureKeyStore = new Map<string, string>();
90
+
91
+ mock.module("../../security/secure-keys.js", () => ({
92
+ getSecureKeyAsync: async (key: string) => secureKeyStore.get(key),
93
+ }));
94
+
62
95
  import { eq } from "drizzle-orm";
63
96
 
64
97
  import { getDb, getSqlite } from "../../memory/db-connection.js";
@@ -79,6 +112,8 @@ function getSpawnHandler() {
79
112
  beforeEach(() => {
80
113
  config.setConfig({});
81
114
  which.setWhich((cmd) => `/usr/local/bin/${cmd}`);
115
+ capturedSpawns.length = 0;
116
+ secureKeyStore.clear();
82
117
  });
83
118
 
84
119
  // ---------------------------------------------------------------------------
@@ -146,6 +181,212 @@ describe("POST /v1/acp/spawn", () => {
146
181
  });
147
182
  });
148
183
 
184
+ // ---------------------------------------------------------------------------
185
+ // POST /v1/acp/spawn — CLAUDE_CODE_OAUTH_TOKEN env injection + preflight
186
+ //
187
+ // claude-agent-acp authenticates via CLAUDE_CODE_OAUTH_TOKEN. The route
188
+ // accepts the token from two provisioning routes:
189
+ // 1. Secure store under the canonical `credential/acp/claude_oauth_token`
190
+ // key (built by `credentialKey()`), populated by
191
+ // `assistant credentials set --service acp --field claude_oauth_token`.
192
+ // 2. `acp.agents.claude.env.CLAUDE_CODE_OAUTH_TOKEN` in the user's
193
+ // config.json, surfaced on `resolved.agent.env` by the resolver.
194
+ // After merging the secure-store value into `agentConfig.env`, the route
195
+ // preflights for the token and throws `FailedDependencyError` if it is
196
+ // still absent. The "fail-fast" behavior is symmetric with the existing
197
+ // `binary_not_found` preflight and avoids the zombie-subprocess footgun
198
+ // where claude-agent-acp launches, crashes on auth, and leaves the
199
+ // caller with no useful signal.
200
+ //
201
+ // These tests pin both the happy paths and the throw path so a future
202
+ // drift in the key path, the env-override route, or the preflight check
203
+ // fails the suite loudly.
204
+ // ---------------------------------------------------------------------------
205
+
206
+ describe("POST /v1/acp/spawn — CLAUDE_CODE_OAUTH_TOKEN injection", () => {
207
+ test("injects CLAUDE_CODE_OAUTH_TOKEN from credential/acp/claude_oauth_token for the claude agent", async () => {
208
+ secureKeyStore.set(
209
+ "credential/acp/claude_oauth_token",
210
+ "test-token-abc123",
211
+ );
212
+
213
+ const handler = getSpawnHandler();
214
+ await handler({
215
+ body: {
216
+ agent: "claude",
217
+ task: "do a thing",
218
+ conversationId: "conv-1",
219
+ },
220
+ });
221
+
222
+ expect(capturedSpawns).toHaveLength(1);
223
+ expect(capturedSpawns[0]?.agent).toBe("claude");
224
+ expect(capturedSpawns[0]?.agentConfig.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe(
225
+ "test-token-abc123",
226
+ );
227
+ });
228
+
229
+ test("accepts CLAUDE_CODE_OAUTH_TOKEN from acp.agents.claude.env (config.json override) without a secure-store entry", async () => {
230
+ // The user-supplied config.json env override is the first-priority
231
+ // provisioning route. resolveAcpAgent returns it on `resolved.agent.env`,
232
+ // which the route then preserves on `agentConfig.env`. The preflight
233
+ // should accept this path with no secure-store entry needed.
234
+ config.setConfig({
235
+ agents: {
236
+ claude: {
237
+ command: "claude-agent-acp",
238
+ args: [],
239
+ env: { CLAUDE_CODE_OAUTH_TOKEN: "config-token-xyz789" },
240
+ },
241
+ },
242
+ });
243
+
244
+ const handler = getSpawnHandler();
245
+ await handler({
246
+ body: {
247
+ agent: "claude",
248
+ task: "do a thing",
249
+ conversationId: "conv-1",
250
+ },
251
+ });
252
+
253
+ expect(capturedSpawns).toHaveLength(1);
254
+ expect(capturedSpawns[0]?.agentConfig.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe(
255
+ "config-token-xyz789",
256
+ );
257
+ });
258
+
259
+ test("config.json env override wins over a secure-store token (precedence pin)", async () => {
260
+ // Codex review feedback (PR #31901 / P2): when a user explicitly sets
261
+ // CLAUDE_CODE_OAUTH_TOKEN under `acp.agents.<id>.env` (per-workspace,
262
+ // rotated, scoped credential, etc.), the secure-store value must NOT
263
+ // silently overwrite it. Vault is fallback, not override.
264
+ secureKeyStore.set("credential/acp/claude_oauth_token", "vault-token-AAA");
265
+ config.setConfig({
266
+ agents: {
267
+ claude: {
268
+ command: "claude-agent-acp",
269
+ args: [],
270
+ env: { CLAUDE_CODE_OAUTH_TOKEN: "config-token-BBB" },
271
+ },
272
+ },
273
+ });
274
+
275
+ const handler = getSpawnHandler();
276
+ await handler({
277
+ body: {
278
+ agent: "claude",
279
+ task: "do a thing",
280
+ conversationId: "conv-1",
281
+ },
282
+ });
283
+
284
+ expect(capturedSpawns).toHaveLength(1);
285
+ expect(capturedSpawns[0]?.agentConfig.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe(
286
+ "config-token-BBB",
287
+ );
288
+ });
289
+
290
+ test("injects via command match for a user-defined agent id aliased to claude-agent-acp", async () => {
291
+ // Codex review feedback (PR #31901 / P2): gating is keyed off the
292
+ // resolved command (basename), not the agent id. A custom agent id
293
+ // pointing at claude-agent-acp still needs CLAUDE_CODE_OAUTH_TOKEN,
294
+ // so injection + preflight must fire regardless of the id string.
295
+ secureKeyStore.set("credential/acp/claude_oauth_token", "vault-token-zzz");
296
+ config.setConfig({
297
+ agents: {
298
+ "my-claude": {
299
+ command: "claude-agent-acp",
300
+ args: [],
301
+ },
302
+ },
303
+ });
304
+
305
+ const handler = getSpawnHandler();
306
+ await handler({
307
+ body: {
308
+ agent: "my-claude",
309
+ task: "do a thing",
310
+ conversationId: "conv-1",
311
+ },
312
+ });
313
+
314
+ expect(capturedSpawns).toHaveLength(1);
315
+ expect(capturedSpawns[0]?.agent).toBe("my-claude");
316
+ expect(capturedSpawns[0]?.agentConfig.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe(
317
+ "vault-token-zzz",
318
+ );
319
+ });
320
+
321
+ test("throws FailedDependencyError when no CLAUDE_CODE_OAUTH_TOKEN is available from any source", async () => {
322
+ // secureKeyStore intentionally empty AND no agentConfig.env override —
323
+ // simulates a fresh install where the user hasn't provisioned a token
324
+ // via either route. Fail-fast preflight surfaces this immediately
325
+ // instead of letting claude-agent-acp launch, crash on auth, and leave
326
+ // a zombie subprocess behind.
327
+
328
+ const handler = getSpawnHandler();
329
+ await expect(
330
+ handler({
331
+ body: {
332
+ agent: "claude",
333
+ task: "do a thing",
334
+ conversationId: "conv-1",
335
+ },
336
+ }),
337
+ ).rejects.toThrow(/CLAUDE_CODE_OAUTH_TOKEN/);
338
+ expect(capturedSpawns).toHaveLength(0);
339
+ });
340
+
341
+ test("does NOT inject CLAUDE_CODE_OAUTH_TOKEN for agents whose command is not claude-agent-acp", async () => {
342
+ // Token-injection AND preflight are scoped to claude-agent-acp by
343
+ // command basename. A codex-acp spawn with the secure-store key set
344
+ // must still launch without that env var — and must not be blocked
345
+ // by claude's preflight.
346
+ secureKeyStore.set(
347
+ "credential/acp/claude_oauth_token",
348
+ "test-token-abc123",
349
+ );
350
+
351
+ const handler = getSpawnHandler();
352
+ await handler({
353
+ body: {
354
+ agent: "codex",
355
+ task: "do a thing",
356
+ conversationId: "conv-1",
357
+ },
358
+ });
359
+
360
+ expect(capturedSpawns).toHaveLength(1);
361
+ expect(capturedSpawns[0]?.agent).toBe("codex");
362
+ expect(
363
+ capturedSpawns[0]?.agentConfig.env?.CLAUDE_CODE_OAUTH_TOKEN,
364
+ ).toBeUndefined();
365
+ });
366
+
367
+ test("does NOT pick up a token planted at the legacy non-`credential/` key path", async () => {
368
+ // Regression guard: the original implementation used the raw key
369
+ // "acp/claude/oauth_token". The fix routes through `credentialKey()`
370
+ // so the CLI (`assistant credentials set --service acp --field
371
+ // claude_oauth_token`) is the canonical provisioning path. Pin this
372
+ // by planting the token ONLY under the legacy key — the preflight
373
+ // should fail-fast because the canonical path is empty.
374
+ secureKeyStore.set("acp/claude/oauth_token", "legacy-token-should-miss");
375
+
376
+ const handler = getSpawnHandler();
377
+ await expect(
378
+ handler({
379
+ body: {
380
+ agent: "claude",
381
+ task: "do a thing",
382
+ conversationId: "conv-1",
383
+ },
384
+ }),
385
+ ).rejects.toThrow(/CLAUDE_CODE_OAUTH_TOKEN/);
386
+ expect(capturedSpawns).toHaveLength(0);
387
+ });
388
+ });
389
+
149
390
  // ---------------------------------------------------------------------------
150
391
  // DELETE /v1/acp/sessions?status=completed — bulk-clear terminal rows
151
392
  // ---------------------------------------------------------------------------
@@ -205,7 +446,9 @@ describe("DELETE /v1/acp/sessions?status=completed", () => {
205
446
  seedHistoryRow("row-initializing", "initializing", 5000);
206
447
 
207
448
  const handler = getBulkDeleteHandler();
208
- const result = (await handler({ queryParams: { status: "completed" } })) as {
449
+ const result = (await handler({
450
+ queryParams: { status: "completed" },
451
+ })) as {
209
452
  deleted: number;
210
453
  };
211
454
  expect(result.deleted).toBe(3);
@@ -221,7 +464,9 @@ describe("DELETE /v1/acp/sessions?status=completed", () => {
221
464
  seedHistoryRow("row-running", "running", 1000);
222
465
 
223
466
  const handler = getBulkDeleteHandler();
224
- const result = (await handler({ queryParams: { status: "completed" } })) as {
467
+ const result = (await handler({
468
+ queryParams: { status: "completed" },
469
+ })) as {
225
470
  deleted: number;
226
471
  };
227
472
  expect(result.deleted).toBe(0);
@@ -244,7 +489,9 @@ describe("DELETE /v1/acp/sessions?status=completed", () => {
244
489
  seedHistoryRow("row-completed", "completed", 1000);
245
490
 
246
491
  const handler = getBulkDeleteHandler();
247
- expect(() => handler({ queryParams: { status: "failed" } })).toThrow("status");
492
+ expect(() => handler({ queryParams: { status: "failed" } })).toThrow(
493
+ "status",
494
+ );
248
495
  expect(listRows()).toHaveLength(1);
249
496
  });
250
497
  });
@@ -297,7 +544,9 @@ describe("DELETE /v1/acp/sessions/:id", () => {
297
544
  insertHistoryRow({ id: "sess-completed", status: "completed" });
298
545
 
299
546
  const handler = getDeleteSessionHandler();
300
- const result = (await handler({ pathParams: { id: "sess-completed" } })) as {
547
+ const result = (await handler({
548
+ pathParams: { id: "sess-completed" },
549
+ })) as {
301
550
  deleted: boolean;
302
551
  };
303
552
  expect(result.deleted).toBe(true);