@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,19 +1,77 @@
1
- const TOOL_NAME_ALIASES = new Map<string, string>([
2
- ["create_app", "app_create"],
1
+ type ToolInputNormalizer = (
2
+ input: Record<string, unknown>,
3
+ ) => Record<string, unknown>;
4
+
5
+ const TOOL_NAME_ALIASES = new Map<
6
+ string,
7
+ { canonicalName: string; normalizeInput?: ToolInputNormalizer }
8
+ >([
9
+ ["create_app", { canonicalName: "app_create" }],
10
+ [
11
+ "computer_use_press_key",
12
+ {
13
+ canonicalName: "computer_use_key",
14
+ normalizeInput: normalizeLegacyComputerUsePressKeyInput,
15
+ },
16
+ ],
3
17
  ]);
4
18
 
5
- /**
6
- * Resolve high-confidence compatibility aliases before active-tool gating.
7
- * Keep this list narrow: aliases should only cover observed model drift where
8
- * the canonical target is active for the turn.
9
- */
10
- export function resolveToolNameAlias(
19
+ export function resolveToolInvocationAlias(
11
20
  name: string,
21
+ input: Record<string, unknown>,
12
22
  allowedToolNames?: ReadonlySet<string>,
13
- ): string {
14
- if (allowedToolNames?.has(name)) return name;
15
- const canonical = TOOL_NAME_ALIASES.get(name);
16
- if (!canonical) return name;
17
- if (allowedToolNames && !allowedToolNames.has(canonical)) return name;
18
- return canonical;
23
+ ): { name: string; input: Record<string, unknown> } {
24
+ if (allowedToolNames?.has(name)) return { name, input };
25
+ const alias = TOOL_NAME_ALIASES.get(name);
26
+ if (!alias) return { name, input };
27
+ if (allowedToolNames && !allowedToolNames.has(alias.canonicalName)) {
28
+ return { name, input };
29
+ }
30
+ return {
31
+ name: alias.canonicalName,
32
+ input: alias.normalizeInput ? alias.normalizeInput(input) : input,
33
+ };
34
+ }
35
+
36
+ function normalizeLegacyComputerUsePressKeyInput(
37
+ input: Record<string, unknown>,
38
+ ): Record<string, unknown> {
39
+ const normalized = { ...input };
40
+ const key = typeof normalized.key === "string" ? normalized.key.trim() : "";
41
+ const modifiers = Array.isArray(normalized.modifiers)
42
+ ? normalized.modifiers.flatMap((modifier) => {
43
+ if (typeof modifier !== "string") return [];
44
+ const normalizedModifier = normalizeKeyModifier(modifier);
45
+ return normalizedModifier ? [normalizedModifier] : [];
46
+ })
47
+ : [];
48
+
49
+ delete normalized.modifiers;
50
+
51
+ if (key && modifiers.length > 0 && !key.includes("+")) {
52
+ normalized.key = [...new Set(modifiers), key.toLowerCase()].join("+");
53
+ } else if (key && !key.includes("+")) {
54
+ normalized.key = key.toLowerCase();
55
+ }
56
+
57
+ return normalized;
58
+ }
59
+
60
+ function normalizeKeyModifier(modifier: string): string | undefined {
61
+ switch (modifier.trim().toLowerCase()) {
62
+ case "cmd":
63
+ case "command":
64
+ case "meta":
65
+ return "cmd";
66
+ case "ctrl":
67
+ case "control":
68
+ return "ctrl";
69
+ case "option":
70
+ case "alt":
71
+ return "option";
72
+ case "shift":
73
+ return "shift";
74
+ default:
75
+ return undefined;
76
+ }
19
77
  }
@@ -338,22 +338,24 @@ export interface ToolDefinition {
338
338
  }
339
339
 
340
340
  /** Tool after the loader has derived its name and filled defaults. */
341
- export type LoadedTool = Required<ToolDefinition> & { name: string };
341
+ export type LoadedTool = Required<ToolDefinition> & {
342
+ name: string;
343
+ };
344
+
345
+ /** The kind of extension that owns a tool. Core tools have no owner. */
346
+ export type OwnerKind = "skill" | "mcp" | "plugin";
347
+
348
+ /**
349
+ * Identifies which extension owns a tool (skill / plugin / MCP server).
350
+ * Tracked by the tool registry keyed by tool name, not stored on the `Tool`
351
+ * object itself — query via {@link ../tools/registry.getToolOwner}.
352
+ */
353
+ export interface OwnerInfo {
354
+ kind: OwnerKind;
355
+ /** ID of the owning extension (skill id / plugin name / MCP server id). */
356
+ id: string;
357
+ }
342
358
 
343
359
  export interface Tool extends LoadedTool {
344
360
  category: string;
345
- /** When set to 'proxy', the tool is forwarded to a connected client rather than executed locally. */
346
- executionMode?: "local" | "proxy";
347
- /** Whether this tool is a core built-in, provided by a skill, contributed by a plugin, or from an MCP server. */
348
- origin?: "core" | "skill" | "mcp" | "plugin";
349
- /** If origin is 'skill', the ID of the owning skill. */
350
- ownerSkillId?: string;
351
- /** If origin is 'mcp', the ID of the owning MCP server. */
352
- ownerMcpServerId?: string;
353
- /** If origin is 'plugin', the name of the owning plugin. */
354
- ownerPluginId?: string;
355
- /** Content-hash of the owning skill's source at registration time. */
356
- ownerSkillVersionHash?: string;
357
- /** Whether the owning skill is bundled with the daemon (trusted first-party). */
358
- ownerSkillBundled?: boolean;
359
361
  }
@@ -8,16 +8,31 @@
8
8
  */
9
9
 
10
10
  import { RiskLevel } from "../../permissions/types.js";
11
- import type { Tool, ToolExecutionResult } from "../types.js";
11
+ import type { Tool, ToolContext, ToolExecutionResult } from "../types.js";
12
12
 
13
13
  // ---------------------------------------------------------------------------
14
14
  // Helpers
15
15
  // ---------------------------------------------------------------------------
16
16
 
17
- function proxyExecute(): Promise<ToolExecutionResult> {
18
- throw new Error(
19
- "Proxy tool: execution must be forwarded to the connected client",
20
- );
17
+ /**
18
+ * Forward execution to the connected macOS client via the request-bound
19
+ * `proxyToolResolver`. Returns a structured error when no resolver is
20
+ * configured (e.g. no client connected) so callers see a normal tool
21
+ * failure rather than an unhandled throw.
22
+ */
23
+ function proxyExecute(toolName: string) {
24
+ return async (
25
+ input: Record<string, unknown>,
26
+ context: ToolContext,
27
+ ): Promise<ToolExecutionResult> => {
28
+ if (!context.proxyToolResolver) {
29
+ return {
30
+ content: `No proxy resolver configured for proxy tool "${toolName}". This tool requires an external resolver (e.g. a connected macOS client).`,
31
+ isError: true,
32
+ };
33
+ }
34
+ return context.proxyToolResolver(toolName, input);
35
+ };
21
36
  }
22
37
 
23
38
  // ---------------------------------------------------------------------------
@@ -40,73 +55,72 @@ export const uiShowTool: Tool = {
40
55
  "Proactively show a task_progress card before multi-step or long-running work (web searches, file operations, research). Show it before your first tool call, then update steps as work progresses.",
41
56
  category: "ui-surface",
42
57
  defaultRiskLevel: RiskLevel.Low,
43
- executionMode: "proxy",
44
58
  executionTarget: "host",
45
59
 
46
60
  input_schema: {
61
+ type: "object",
62
+ properties: {
63
+ surface_type: {
64
+ type: "string",
65
+ enum: [
66
+ "card",
67
+ "form",
68
+ "list",
69
+ "table",
70
+ "confirmation",
71
+ "dynamic_page",
72
+ "file_upload",
73
+ "task_preferences",
74
+ ],
75
+ description: "The type of surface to display",
76
+ },
77
+ title: {
78
+ type: "string",
79
+ description: "Optional title for the surface window",
80
+ },
81
+ data: {
47
82
  type: "object",
48
- properties: {
49
- surface_type: {
50
- type: "string",
51
- enum: [
52
- "card",
53
- "form",
54
- "list",
55
- "table",
56
- "confirmation",
57
- "dynamic_page",
58
- "file_upload",
59
- "task_preferences",
60
- ],
61
- description: "The type of surface to display",
62
- },
63
- title: {
64
- type: "string",
65
- description: "Optional title for the surface window",
66
- },
67
- data: {
68
- type: "object",
69
- description:
70
- "Surface data; structure depends on surface_type (see tool description)",
71
- },
72
- actions: {
73
- type: "array",
74
- items: {
75
- type: "object",
76
- properties: {
77
- id: { type: "string", description: "Unique action identifier" },
78
- label: { type: "string", description: "Button label text" },
79
- style: {
80
- type: "string",
81
- enum: ["primary", "secondary", "destructive"],
82
- description: "Visual style of the button",
83
- },
84
- },
85
- required: ["id", "label"],
83
+ description:
84
+ "Surface data; structure depends on surface_type (see tool description)",
85
+ },
86
+ actions: {
87
+ type: "array",
88
+ items: {
89
+ type: "object",
90
+ properties: {
91
+ id: { type: "string", description: "Unique action identifier" },
92
+ label: { type: "string", description: "Button label text" },
93
+ style: {
94
+ type: "string",
95
+ enum: ["primary", "secondary", "destructive"],
96
+ description: "Visual style of the button",
86
97
  },
87
- description: "Optional action buttons to display on the surface",
88
- },
89
- display: {
90
- type: "string",
91
- enum: ["inline", "panel"],
92
- description:
93
- 'Where to render the surface. "inline" embeds it in the chat message. "panel" shows a floating window. Defaults to "inline". Prefer inline — only use panel when a separate window is explicitly requested.',
94
- },
95
- await_action: {
96
- type: "boolean",
97
- description:
98
- "Whether to block until an action is selected. Defaults to true when actions are provided.",
99
- },
100
- persistent: {
101
- type: "boolean",
102
- description:
103
- "When true, clicking an action does not dismiss the surface — the card stays visible and only the clicked action is marked as spent. Use for launcher or menu-style cards where multiple buttons may be clicked. Defaults to false.",
104
98
  },
99
+ required: ["id", "label"],
105
100
  },
106
- required: ["surface_type", "data"],
101
+ description: "Optional action buttons to display on the surface",
107
102
  },
103
+ display: {
104
+ type: "string",
105
+ enum: ["inline", "panel"],
106
+ description:
107
+ 'Where to render the surface. "inline" embeds it in the chat message. "panel" shows a floating window. Defaults to "inline". Prefer inline — only use panel when a separate window is explicitly requested.',
108
+ },
109
+ await_action: {
110
+ type: "boolean",
111
+ description:
112
+ "Whether to block until an action is selected. Defaults to true when actions are provided.",
113
+ },
114
+ persistent: {
115
+ type: "boolean",
116
+ description:
117
+ "When true, clicking an action does not dismiss the surface — the card stays visible and only the clicked action is marked as spent. Use for launcher or menu-style cards where multiple buttons may be clicked. Defaults to false.",
118
+ },
119
+ },
120
+ required: ["surface_type", "data"],
121
+ },
108
122
 
109
- execute: proxyExecute,
123
+ execute: proxyExecute("ui_show"),
110
124
  };
111
125
 
112
126
  // ---------------------------------------------------------------------------
@@ -120,25 +134,24 @@ const uiUpdateTool: Tool = {
120
134
  "For card templates (for example `task_progress`), update nested fields under `data.templateData` rather than sending template fields at the top level.",
121
135
  category: "ui-surface",
122
136
  defaultRiskLevel: RiskLevel.Low,
123
- executionMode: "proxy",
124
137
  executionTarget: "host",
125
138
 
126
139
  input_schema: {
140
+ type: "object",
141
+ properties: {
142
+ surface_id: {
143
+ type: "string",
144
+ description: "The ID of the surface to update",
145
+ },
146
+ data: {
127
147
  type: "object",
128
- properties: {
129
- surface_id: {
130
- type: "string",
131
- description: "The ID of the surface to update",
132
- },
133
- data: {
134
- type: "object",
135
- description: "Partial data to merge into the existing surface data",
136
- },
137
- },
138
- required: ["surface_id", "data"],
148
+ description: "Partial data to merge into the existing surface data",
139
149
  },
150
+ },
151
+ required: ["surface_id", "data"],
152
+ },
140
153
 
141
- execute: proxyExecute,
154
+ execute: proxyExecute("ui_update"),
142
155
  };
143
156
 
144
157
  // ---------------------------------------------------------------------------
@@ -150,21 +163,20 @@ const uiDismissTool: Tool = {
150
163
  description: "Dismiss a currently displayed surface.",
151
164
  category: "ui-surface",
152
165
  defaultRiskLevel: RiskLevel.Low,
153
- executionMode: "proxy",
154
166
  executionTarget: "host",
155
167
 
156
168
  input_schema: {
157
- type: "object",
158
- properties: {
159
- surface_id: {
160
- type: "string",
161
- description: "The ID of the surface to dismiss",
162
- },
163
- },
164
- required: ["surface_id"],
169
+ type: "object",
170
+ properties: {
171
+ surface_id: {
172
+ type: "string",
173
+ description: "The ID of the surface to dismiss",
165
174
  },
175
+ },
176
+ required: ["surface_id"],
177
+ },
166
178
 
167
- execute: proxyExecute,
179
+ execute: proxyExecute("ui_dismiss"),
168
180
  };
169
181
 
170
182
  export const allUiSurfaceTools: Tool[] = [
@@ -10,4 +10,10 @@ export interface OnboardingContext {
10
10
  cohort?: string;
11
11
  websiteUrl?: string;
12
12
  contentSourceUrl?: string;
13
+ /** Filename of the bootstrap template to use (e.g. "BOOTSTRAP-CONTENT-AUTOMATION.md"). When set, replaces generic BOOTSTRAP.md if still pristine. */
14
+ bootstrapTemplate?: string;
15
+ /** Override the first user message content. When set during a wake-up greeting, this replaces the canned greeting. */
16
+ initialMessage?: string;
17
+ /** Skills to eagerly load on first turn (e.g. ["geo-writing", "document-editor"]). Informational — the bootstrap template drives actual loading. */
18
+ skills?: string[];
13
19
  }
@@ -15,6 +15,14 @@ export type UsageAttributionProfileSource =
15
15
  export interface UsageAttributionInput {
16
16
  callSite: LLMCallSite | null;
17
17
  overrideProfile?: string | null;
18
+ /**
19
+ * Per-conversation seed for `mix`-profile expansion (the conversation id).
20
+ * When the applied profile is a mix, threading the same seed the dispatch
21
+ * path uses ensures `resolvedModel`/`resolvedMixArm` reflect the arm the
22
+ * request actually ran on. Omitted by one-shot callers (the snapshot's
23
+ * `resolvedMixArm` is then null even if a mix was involved).
24
+ */
25
+ selectionSeed?: string;
18
26
  }
19
27
 
20
28
  export interface UsageAttributionSnapshot {
@@ -26,6 +34,12 @@ export interface UsageAttributionSnapshot {
26
34
  profileSource: UsageAttributionProfileSource;
27
35
  resolvedProvider: string;
28
36
  resolvedModel: string;
37
+ /**
38
+ * When `appliedProfile` is a mix profile, the constituent arm chosen for
39
+ * this request; null otherwise. Lets A/B analysis attribute usage to the
40
+ * specific arm (mix name lives in `appliedProfile`).
41
+ */
42
+ resolvedMixArm: string | null;
29
43
  }
30
44
 
31
45
  /**
@@ -51,7 +65,11 @@ export function resolveUsageAttribution(
51
65
  const overrideProfile = normalizeProfileId(input.overrideProfile);
52
66
 
53
67
  if (callSite == null) {
54
- const resolvedMainAgent = resolveCallSiteConfig("mainAgent", llm);
68
+ const resolvedMainAgent = resolveCallSiteConfig("mainAgent", llm, {
69
+ ...(input.selectionSeed != null
70
+ ? { selectionSeed: input.selectionSeed }
71
+ : {}),
72
+ });
55
73
  return {
56
74
  callSite: null,
57
75
  activeProfile: normalizeProfileId(llm.activeProfile),
@@ -61,11 +79,20 @@ export function resolveUsageAttribution(
61
79
  profileSource: "unknown",
62
80
  resolvedProvider: resolvedMainAgent.provider,
63
81
  resolvedModel: resolvedMainAgent.model,
82
+ resolvedMixArm: null,
64
83
  };
65
84
  }
66
85
 
86
+ // Capture which arm each expanded mix resolved to so we can attribute usage
87
+ // to the arm behind the applied (mix) profile below.
88
+ const mixSelections = new Map<string, string>();
67
89
  const resolved = resolveCallSiteConfig(callSite, llm, {
68
90
  ...(overrideProfile != null ? { overrideProfile } : {}),
91
+ ...(input.selectionSeed != null
92
+ ? { selectionSeed: input.selectionSeed }
93
+ : {}),
94
+ onMixSelected: ({ mixProfile, chosenProfile }) =>
95
+ mixSelections.set(mixProfile, chosenProfile),
69
96
  });
70
97
  const activeProfile = normalizeProfileId(llm.activeProfile);
71
98
  const callSiteProfile = normalizeProfileId(
@@ -88,6 +115,10 @@ export function resolveUsageAttribution(
88
115
  profileSource: profile.profileSource,
89
116
  resolvedProvider: resolved.provider,
90
117
  resolvedModel: resolved.model,
118
+ resolvedMixArm:
119
+ profile.appliedProfile != null
120
+ ? (mixSelections.get(profile.appliedProfile) ?? null)
121
+ : null,
91
122
  };
92
123
  }
93
124
 
@@ -10,8 +10,13 @@ const log = getLogger("browser");
10
10
  * Open a URL on the user's host machine.
11
11
  *
12
12
  * Writes an `open_url` event to the `signals/emit-event` file so that the
13
- * daemon's ConfigWatcher picks it up and publishes it to connected clients
14
- * (e.g. the Swift macOS app) via the assistant event hub.
13
+ * assistant's ConfigWatcher picks it up and publishes it to connected
14
+ * clients (e.g. the Swift macOS app) via the assistant event hub.
15
+ *
16
+ * CLI-initiated emit — no conversation context available, so the inner
17
+ * message has no `conversationId`. That's fine: `OpenUrlEventSchema`
18
+ * declares `conversationId` as optional, so this payload parses
19
+ * cleanly on the web side as well as in the Swift macOS app.
15
20
  */
16
21
  export async function openInHostBrowser(url: string): Promise<void> {
17
22
  try {
@@ -0,0 +1,109 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import type { WorkspaceMigration } from "./types.js";
5
+
6
+ // Flip callSites.memoryRouter from { profile: "balanced" } (the shape that
7
+ // migration 087 wrote) to the shipped cost-optimized default so the router
8
+ // rides the workspace's cheaper/faster managed profile.
9
+ //
10
+ // The migrated entry must mirror the shipped default in call-site-defaults.ts
11
+ // EXACTLY — { profile: "cost-optimized", contextWindow: { maxInputTokens:
12
+ // 1_000_000 } } — because the resolver prefers an explicit
13
+ // llm.callSites.memoryRouter entry over CALL_SITE_DEFAULTS. Writing a bare
14
+ // { profile: "cost-optimized" } would drop the 1M input window and regress
15
+ // migrated users to the profile's normal ~200k window.
16
+ //
17
+ // The shipped default in call-site-defaults.ts also moves to cost-optimized
18
+ // in the same change; this migration is what gets existing users — who carry
19
+ // an explicit { profile: "balanced" } in their config.json — onto the new
20
+ // default. Workspaces with no memoryRouter entry already pick up the shipped
21
+ // default automatically (e.g. BYOK installs that skipped 077/087, or fresh
22
+ // installs), so this migration only touches the 087-seeded balanced shape and
23
+ // the bare { profile: "cost-optimized" } shape an earlier (pre-fix) run of
24
+ // this migration may have written — the latter so those users also recover
25
+ // the 1M window.
26
+ //
27
+ // Two skip conditions, mirroring 087:
28
+ //
29
+ // 1. BYOK / non-Anthropic workspaces. `cost-optimized` is a managed
30
+ // Anthropic profile, which off-platform installs disable. Forcing it
31
+ // there would make getConfiguredProvider("memoryRouter") return null
32
+ // and silently disable memory injection. Detect via llm.default.provider.
33
+ //
34
+ // 2. User-customized memoryRouter config. If the existing entry carries any
35
+ // key beyond a bare balanced/cost-optimized profile reference, the user —
36
+ // or a platform overlay — chose those values deliberately. Preserve them.
37
+ const MEMORY_ROUTER_COST_OPTIMIZED = {
38
+ profile: "cost-optimized",
39
+ contextWindow: { maxInputTokens: 1_000_000 },
40
+ } as const;
41
+
42
+ export const memoryRouterCostOptimizedProfileMigration: WorkspaceMigration = {
43
+ id: "090-memory-router-cost-optimized-profile",
44
+ description:
45
+ "Set callSites.memoryRouter to the shipped cost-optimized default (with 1M context) for workspaces still carrying the 087-seeded balanced profile",
46
+ run(workspaceDir: string): void {
47
+ if (process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH) return;
48
+
49
+ const configPath = join(workspaceDir, "config.json");
50
+ if (!existsSync(configPath)) return;
51
+
52
+ let config: Record<string, unknown> = {};
53
+ try {
54
+ const raw = JSON.parse(readFileSync(configPath, "utf-8"));
55
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
56
+ config = raw as Record<string, unknown>;
57
+ } catch {
58
+ return;
59
+ }
60
+
61
+ const llm = readObject(config.llm);
62
+ if (llm === null) return;
63
+
64
+ const explicitProvider = readString(readObject(llm.default)?.provider);
65
+ if (explicitProvider !== undefined && explicitProvider !== "anthropic") {
66
+ return;
67
+ }
68
+
69
+ const callSites = readObject(llm.callSites);
70
+ if (callSites === null) return;
71
+
72
+ const existing = readObject(callSites.memoryRouter);
73
+ if (existing === null || !needsCostOptimizedUpgrade(existing)) return;
74
+
75
+ callSites.memoryRouter = { ...MEMORY_ROUTER_COST_OPTIMIZED };
76
+ llm.callSites = callSites;
77
+ config.llm = llm;
78
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
79
+ },
80
+ down(_workspaceDir: string): void {
81
+ // Forward-only.
82
+ },
83
+ };
84
+
85
+ // True when the entry is a bare single-key profile reference we own:
86
+ // - { profile: "balanced" } — what migration 087 wrote
87
+ // - { profile: "cost-optimized" } — what a pre-fix run of THIS migration
88
+ // wrote (no contextWindow), so those users
89
+ // still recover the 1M window
90
+ // Any extra keys (model pins, tuning fields, an already-present contextWindow)
91
+ // mean the user/platform customized it — preserve and skip. This keeps the
92
+ // migration idempotent: once it writes the full cost-optimized + contextWindow
93
+ // shape, the two-key entry no longer matches.
94
+ function needsCostOptimizedUpgrade(entry: Record<string, unknown>): boolean {
95
+ const keys = Object.keys(entry);
96
+ if (keys.length !== 1) return false;
97
+ return entry.profile === "balanced" || entry.profile === "cost-optimized";
98
+ }
99
+
100
+ function readObject(value: unknown): Record<string, unknown> | null {
101
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
102
+ return null;
103
+ }
104
+ return value as Record<string, unknown>;
105
+ }
106
+
107
+ function readString(value: unknown): string | undefined {
108
+ return typeof value === "string" && value.length > 0 ? value : undefined;
109
+ }
@@ -0,0 +1,41 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import type { MigrationRunContext, WorkspaceMigration } from "./types.js";
5
+
6
+ // The exact onboarding bullet seeded by 069-seed-onboarding-threads for the
7
+ // assistant-migration step. Inlined here (not imported) to keep this migration
8
+ // self-contained and decoupled from 069.
9
+ const OLD_BULLET =
10
+ "- Ask your user if they use ChatGPT, Claude or another AI tool and offer to help them import memories from there.";
11
+
12
+ // The tightened replacement: help-first, an early light one-time offer, naming
13
+ // the common prior assistants. Keeps the literal "ChatGPT, Claude" substring.
14
+ const NEW_BULLET =
15
+ "- After helping with the user's first real task, offer early — at the first natural opening — to port their context, memories, prompts, skills, or workflows from a prior assistant (ChatGPT, Claude, OpenClaw, Hermes, or another tool). Keep it a light one-time offer, not a push; if they decline, drop it.";
16
+
17
+ export const retightenMigrationOnboardingThreadMigration: WorkspaceMigration = {
18
+ id: "091-retighten-migration-onboarding-thread",
19
+ description:
20
+ "Retighten the assistant-migration onboarding bullet in memory/threads.md for brand new assistants",
21
+
22
+ run(workspaceDir: string, ctx?: MigrationRunContext): void {
23
+ // Only rewrite onboarding tasks for newly-created workspaces. An existing
24
+ // assistant whose user has edited threads.md must not have its content
25
+ // rewritten on upgrade. When invoked without a context (e.g. from older
26
+ // callers), default to the safe path and skip — the runner always supplies
27
+ // one in production.
28
+ if (!ctx?.isNewWorkspace) return;
29
+ const filePath = join(workspaceDir, "memory", "threads.md");
30
+ if (!existsSync(filePath)) return;
31
+ const content = readFileSync(filePath, "utf-8");
32
+ // Idempotent: if the old bullet is absent (already replaced, or the user
33
+ // edited it away), there is nothing to do.
34
+ if (!content.includes(OLD_BULLET)) return;
35
+ writeFileSync(filePath, content.replace(OLD_BULLET, NEW_BULLET), "utf-8");
36
+ },
37
+
38
+ down(_workspaceDir: string): void {
39
+ // Forward-only: never rewrite user-visible memory content on rollback.
40
+ },
41
+ };
@@ -87,6 +87,8 @@ import { revertStaleGeminiMisRewritesMigration } from "./086-revert-stale-gemini
87
87
  import { memoryRouterBalancedProfileMigration } from "./087-memory-router-balanced-profile.js";
88
88
  import { deprecateBackgroundConversationOverrideMigration } from "./088-deprecate-background-conversation-override.js";
89
89
  import { moveMemoryTreeOutOfV3Migration } from "./089-move-memory-tree-out-of-v3.js";
90
+ import { memoryRouterCostOptimizedProfileMigration } from "./090-memory-router-cost-optimized-profile.js";
91
+ import { retightenMigrationOnboardingThreadMigration } from "./091-retighten-migration-onboarding-thread.js";
90
92
  import { migrateToWorkspaceVolumeMigration } from "./migrate-to-workspace-volume.js";
91
93
  import type { WorkspaceMigration } from "./types.js";
92
94
 
@@ -185,4 +187,6 @@ export const WORKSPACE_MIGRATIONS: WorkspaceMigration[] = [
185
187
  memoryRouterBalancedProfileMigration,
186
188
  deprecateBackgroundConversationOverrideMigration,
187
189
  moveMemoryTreeOutOfV3Migration,
190
+ memoryRouterCostOptimizedProfileMigration,
191
+ retightenMigrationOnboardingThreadMigration,
188
192
  ];