@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
@@ -109,7 +109,7 @@ import {
109
109
  } from "../permissions/checker.js";
110
110
  import { _clearGlobalCacheForTesting } from "../permissions/gateway-threshold-reader.js";
111
111
  import { RiskLevel } from "../permissions/types.js";
112
- import { registerTool } from "../tools/registry.js";
112
+ import { registerSkillTools, registerTool } from "../tools/registry.js";
113
113
  import type { Tool } from "../tools/types.js";
114
114
  import * as platformModule from "../util/platform.js";
115
115
 
@@ -128,33 +128,35 @@ const STRICT_GATEWAY_THRESHOLDS = {
128
128
  } as const;
129
129
 
130
130
  // Register a mock skill-origin tool for testing default-ask policy.
131
+ // Ownership is recorded by `registerSkillTools(skillId, tools)`, not by
132
+ // stamping a field on the `Tool` object — `isToolOwnerSkillBundled()` reads
133
+ // from the registry via `getToolOwner(name)` to find the owning skill id.
131
134
  const mockSkillTool: Tool = {
132
135
  name: "skill_test_tool",
133
136
  description: "A test skill tool",
134
137
  category: "skill",
135
138
  defaultRiskLevel: RiskLevel.Low,
136
139
  executionTarget: "sandbox",
137
- origin: "skill",
138
- ownerSkillId: "test-skill",
139
140
  input_schema: { type: "object" as const, properties: {} },
140
141
  execute: async () => ({ content: "ok", isError: false }),
141
142
  };
142
- registerTool(mockSkillTool);
143
+ registerSkillTools("test-skill", [mockSkillTool]);
143
144
 
144
- // Register a mock bundled skill-origin tool for testing strict mode + bundled policy.
145
+ // Register a mock bundled skill-origin tool for testing strict mode + bundled
146
+ // policy. `app-builder` is a real entry under `bundled-skills/`, so
147
+ // `loadSkillCatalog()` reports it as `bundled: true` and the permission
148
+ // checker derives `isSkillBundled = true` from the registry's ownersByName
149
+ // map (populated by `registerSkillTools`) without any per-tool stamp.
145
150
  const mockBundledSkillTool: Tool = {
146
151
  name: "skill_bundled_test_tool",
147
152
  description: "A test bundled skill tool",
148
153
  category: "skill",
149
154
  defaultRiskLevel: RiskLevel.Low,
150
155
  executionTarget: "sandbox",
151
- origin: "skill",
152
- ownerSkillId: "gmail",
153
- ownerSkillBundled: true,
154
156
  input_schema: { type: "object" as const, properties: {} },
155
157
  execute: async () => ({ content: "ok", isError: false }),
156
158
  };
157
- registerTool(mockBundledSkillTool);
159
+ registerSkillTools("app-builder", [mockBundledSkillTool]);
158
160
 
159
161
  // Register CU tools so check() can look them up in the tool registry
160
162
  // instead of falling through to Medium (unknown tool).
@@ -386,12 +388,10 @@ describe("Permission Checker", () => {
386
388
  category: "skill",
387
389
  defaultRiskLevel: RiskLevel.Medium,
388
390
  executionTarget: "sandbox",
389
- origin: "skill",
390
- ownerSkillId: "test-skill",
391
391
  input_schema: { type: "object" as const, properties: {} },
392
392
  execute: async () => ({ content: "ok", isError: false }),
393
393
  };
394
- registerTool(mediumSkillTool);
394
+ registerSkillTools("test-skill", [mediumSkillTool]);
395
395
  const result = await check("skill_medium_tool", {}, "/tmp");
396
396
  expect(result.decision).toBe("prompt");
397
397
  expect(result.reason).toContain("Skill tool");
@@ -150,6 +150,7 @@ mock.module("../memory/conversation-crud.js", () => ({
150
150
  addMessage: () => ({ id: `msg-${Date.now()}` }),
151
151
  updateConversationUsage: () => {},
152
152
  updateConversationTitle: () => {},
153
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
153
154
  }));
154
155
 
155
156
  mock.module("../memory/conversation-queries.js", () => ({
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Tests for the compaction-trail store helpers:
3
+ * - `getCompactionLogsBetween` (windowed trail fetch)
4
+ * - `getPreviousNonCompactionCallCreatedAt` (window-floor resolver)
5
+ *
6
+ * Exercises the SQL directly against a real in-memory DB — same pattern
7
+ * as `llm-request-log-turn-query.test.ts`. Each test sets up a small
8
+ * conversation, inserts a mix of `mainAgent` / `compactionAgent` /
9
+ * NULL-call-site rows with controlled `createdAt` timestamps, and
10
+ * asserts the right subset comes back.
11
+ */
12
+
13
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
14
+
15
+ mock.module("../util/logger.js", () => ({
16
+ getLogger: () =>
17
+ new Proxy({} as Record<string, unknown>, {
18
+ get: () => () => {},
19
+ }),
20
+ }));
21
+
22
+ mock.module("../config/loader.js", () => ({
23
+ getConfig: () => ({
24
+ ui: {},
25
+ model: "test",
26
+ provider: "test",
27
+ memory: { enabled: false },
28
+ rateLimit: { maxRequestsPerMinute: 0 },
29
+ secretDetection: { enabled: false },
30
+ }),
31
+ }));
32
+
33
+ import { eq } from "drizzle-orm";
34
+
35
+ import { createConversation } from "../memory/conversation-crud.js";
36
+ import { getDb } from "../memory/db-connection.js";
37
+ import { initializeDb } from "../memory/db-init.js";
38
+ import {
39
+ getCompactionLogsBetween,
40
+ getPreviousNonCompactionCallCreatedAt,
41
+ recordRequestLog,
42
+ } from "../memory/llm-request-log-store.js";
43
+ import { llmRequestLogs } from "../memory/schema.js";
44
+
45
+ initializeDb();
46
+
47
+ function resetTables(): void {
48
+ const db = getDb();
49
+ db.delete(llmRequestLogs).run();
50
+ db.run("DELETE FROM messages");
51
+ db.run("DELETE FROM conversations");
52
+ }
53
+
54
+ /**
55
+ * Insert a log row and overwrite its `createdAt` so tests can assert
56
+ * order/cutoff without relying on `Date.now()` timing.
57
+ */
58
+ function insertLogAt(
59
+ conversationId: string,
60
+ createdAt: number,
61
+ callSite: "mainAgent" | "compactionAgent" | null,
62
+ ): string {
63
+ const id = recordRequestLog(
64
+ conversationId,
65
+ "{}",
66
+ "{}",
67
+ undefined,
68
+ "anthropic",
69
+ callSite ?? undefined,
70
+ );
71
+ // Use the Drizzle update builder rather than `db.run("UPDATE … ?")` —
72
+ // the drizzle wrapper doesn't accept positional parameters the same
73
+ // way `bun:sqlite` does, and a silent no-op there manifests as zero
74
+ // rows in the query under test (the inserted `created_at` keeps its
75
+ // `Date.now()` value and ends up far in the future of the cutoff).
76
+ const db = getDb();
77
+ db.update(llmRequestLogs)
78
+ .set({ createdAt })
79
+ .where(eq(llmRequestLogs.id, id))
80
+ .run();
81
+ return id;
82
+ }
83
+
84
+ describe("getCompactionLogsBetween", () => {
85
+ beforeEach(() => {
86
+ resetTables();
87
+ });
88
+
89
+ test("returns only compactionAgent rows in the conversation, in the (after, before) window", () => {
90
+ const conv = createConversation("test-conv");
91
+
92
+ // Timeline (createdAt in ms):
93
+ // 100 → compactionAgent ← excluded (before the floor — would belong to an earlier turn)
94
+ // 150 ← floor (the prior real call's createdAt)
95
+ // 200 → mainAgent ← excluded (wrong call site)
96
+ // 300 → compactionAgent ← included
97
+ // 400 → null call site ← excluded (pre-migration row, not a compaction)
98
+ // 500 ← ceiling (the selected call's createdAt)
99
+ // 600 → compactionAgent ← excluded (after ceiling)
100
+ insertLogAt(conv.id, 100, "compactionAgent");
101
+ insertLogAt(conv.id, 200, "mainAgent");
102
+ insertLogAt(conv.id, 300, "compactionAgent");
103
+ insertLogAt(conv.id, 400, null);
104
+ insertLogAt(conv.id, 600, "compactionAgent");
105
+
106
+ const result = getCompactionLogsBetween(conv.id, 150, 500);
107
+ expect(result).toHaveLength(1);
108
+ expect(result[0]!.createdAt).toBe(300);
109
+ expect(result[0]!.callSite).toBe("compactionAgent");
110
+ expect(result[0]!.conversationId).toBe(conv.id);
111
+ });
112
+
113
+ test("null floor matches all compactions before the ceiling (first-real-call case)", () => {
114
+ const conv = createConversation("null-floor");
115
+
116
+ insertLogAt(conv.id, 100, "compactionAgent");
117
+ insertLogAt(conv.id, 200, "compactionAgent");
118
+ insertLogAt(conv.id, 300, "compactionAgent");
119
+ insertLogAt(conv.id, 600, "compactionAgent");
120
+
121
+ const result = getCompactionLogsBetween(conv.id, null, 500);
122
+ expect(result.map((r) => r.createdAt)).toEqual([100, 200, 300]);
123
+ });
124
+
125
+ test("uses strict < at the ceiling (a row exactly at the cutoff is excluded)", () => {
126
+ const conv = createConversation("strict-ceiling");
127
+
128
+ insertLogAt(conv.id, 100, "compactionAgent");
129
+ insertLogAt(conv.id, 500, "compactionAgent"); // exactly at the ceiling
130
+
131
+ const result = getCompactionLogsBetween(conv.id, null, 500);
132
+ expect(result).toHaveLength(1);
133
+ expect(result[0]!.createdAt).toBe(100);
134
+ });
135
+
136
+ test("uses strict > at the floor (a row exactly at the floor is excluded)", () => {
137
+ const conv = createConversation("strict-floor");
138
+
139
+ insertLogAt(conv.id, 150, "compactionAgent"); // exactly at the floor
140
+ insertLogAt(conv.id, 200, "compactionAgent");
141
+
142
+ const result = getCompactionLogsBetween(conv.id, 150, 500);
143
+ expect(result).toHaveLength(1);
144
+ expect(result[0]!.createdAt).toBe(200);
145
+ });
146
+
147
+ test("scopes by conversation_id (other conversations are invisible)", () => {
148
+ const a = createConversation("conv-a");
149
+ const b = createConversation("conv-b");
150
+
151
+ insertLogAt(a.id, 100, "compactionAgent");
152
+ insertLogAt(b.id, 150, "compactionAgent");
153
+ insertLogAt(a.id, 200, "compactionAgent");
154
+
155
+ const result = getCompactionLogsBetween(a.id, null, 500);
156
+ expect(result).toHaveLength(2);
157
+ for (const row of result) {
158
+ expect(row.conversationId).toBe(a.id);
159
+ }
160
+ });
161
+
162
+ test("returns rows in chronological order by createdAt then id", () => {
163
+ const conv = createConversation("ordered");
164
+
165
+ // Insert out of order to verify the ORDER BY clause does the work.
166
+ insertLogAt(conv.id, 300, "compactionAgent");
167
+ insertLogAt(conv.id, 100, "compactionAgent");
168
+ insertLogAt(conv.id, 200, "compactionAgent");
169
+
170
+ const result = getCompactionLogsBetween(conv.id, null, 500);
171
+ expect(result.map((r) => r.createdAt)).toEqual([100, 200, 300]);
172
+ });
173
+
174
+ test("returns an empty array when no compaction rows fall in the window", () => {
175
+ const conv = createConversation("empty");
176
+
177
+ // mainAgent (wrong site) + compactionAgent after the ceiling.
178
+ insertLogAt(conv.id, 100, "mainAgent");
179
+ insertLogAt(conv.id, 600, "compactionAgent");
180
+
181
+ const result = getCompactionLogsBetween(conv.id, null, 500);
182
+ expect(result).toEqual([]);
183
+ });
184
+
185
+ test("returns an empty array for an unknown conversation_id", () => {
186
+ const result = getCompactionLogsBetween("nonexistent-conv", null, 500);
187
+ expect(result).toEqual([]);
188
+ });
189
+ });
190
+
191
+ describe("getPreviousNonCompactionCallCreatedAt", () => {
192
+ beforeEach(() => {
193
+ resetTables();
194
+ });
195
+
196
+ test("returns the most recent non-compaction call's createdAt before the cutoff", () => {
197
+ const conv = createConversation("prior-call");
198
+
199
+ // Timeline:
200
+ // 100 → mainAgent
201
+ // 200 → compactionAgent ← skipped (we want the previous *real* call)
202
+ // 300 → mainAgent ← this should be the answer for cutoff=500
203
+ // 400 → compactionAgent ← skipped
204
+ // 500 ← cutoff
205
+ // 600 → mainAgent ← excluded (after cutoff)
206
+ insertLogAt(conv.id, 100, "mainAgent");
207
+ insertLogAt(conv.id, 200, "compactionAgent");
208
+ insertLogAt(conv.id, 300, "mainAgent");
209
+ insertLogAt(conv.id, 400, "compactionAgent");
210
+ insertLogAt(conv.id, 600, "mainAgent");
211
+
212
+ const result = getPreviousNonCompactionCallCreatedAt(conv.id, 500);
213
+ expect(result).toBe(300);
214
+ });
215
+
216
+ test("returns null when no non-compaction call exists before the cutoff", () => {
217
+ const conv = createConversation("no-prior");
218
+
219
+ // Only compactions before the cutoff.
220
+ insertLogAt(conv.id, 100, "compactionAgent");
221
+ insertLogAt(conv.id, 200, "compactionAgent");
222
+
223
+ const result = getPreviousNonCompactionCallCreatedAt(conv.id, 500);
224
+ expect(result).toBeNull();
225
+ });
226
+
227
+ test("returns null for an unknown conversation_id", () => {
228
+ const result = getPreviousNonCompactionCallCreatedAt("nope", 500);
229
+ expect(result).toBeNull();
230
+ });
231
+
232
+ test("treats NULL call_site (pre-migration-264) as a real agent call", () => {
233
+ const conv = createConversation("null-site");
234
+
235
+ // Pre-migration rows have NULL call_site. They were mainAgent calls
236
+ // in practice, so the floor walker must surface them.
237
+ insertLogAt(conv.id, 100, null);
238
+ insertLogAt(conv.id, 200, "compactionAgent");
239
+
240
+ const result = getPreviousNonCompactionCallCreatedAt(conv.id, 500);
241
+ expect(result).toBe(100);
242
+ });
243
+
244
+ test("uses strict < at the cutoff (a row exactly at the cutoff is excluded)", () => {
245
+ const conv = createConversation("strict-prior");
246
+
247
+ insertLogAt(conv.id, 100, "mainAgent");
248
+ insertLogAt(conv.id, 500, "mainAgent"); // exactly at the cutoff
249
+
250
+ const result = getPreviousNonCompactionCallCreatedAt(conv.id, 500);
251
+ expect(result).toBe(100);
252
+ });
253
+
254
+ test("scopes by conversation_id (a prior call in another conversation is invisible)", () => {
255
+ const a = createConversation("conv-a");
256
+ const b = createConversation("conv-b");
257
+
258
+ insertLogAt(b.id, 100, "mainAgent"); // wrong conversation
259
+ insertLogAt(a.id, 200, "compactionAgent");
260
+
261
+ const result = getPreviousNonCompactionCallCreatedAt(a.id, 500);
262
+ expect(result).toBeNull();
263
+ });
264
+ });
@@ -31,6 +31,7 @@ mock.module("../util/logger.js", () => ({
31
31
 
32
32
  mock.module("../memory/conversation-crud.js", () => ({
33
33
  getMessages: () => [],
34
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
34
35
  }));
35
36
 
36
37
  mock.module("../memory/attachments-store.js", () => ({
@@ -23,6 +23,7 @@ mock.module("../util/logger.js", () => ({
23
23
 
24
24
  mock.module("../memory/conversation-crud.js", () => ({
25
25
  getMessages: () => [],
26
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
26
27
  }));
27
28
 
28
29
  mock.module("../memory/attachments-store.js", () => ({
@@ -113,8 +113,9 @@ describe("computer-use skill manifest regression", () => {
113
113
  await initializeTools();
114
114
 
115
115
  // Simulate what projectSkillTools() does when the computer-use skill is
116
- // activated: create skill-origin Tool objects matching the manifest names
117
- // and register them. This must not throw.
116
+ // activated: create Tool objects matching the manifest names and register
117
+ // them through `registerSkillTools(skillId, tools)`, which records
118
+ // ownership in the registry's `ownersByName` map. This must not throw.
118
119
  const skillTools: Tool[] = manifest.tools.map(
119
120
  (entry: { name: string; description: string }) => ({
120
121
  name: entry.name,
@@ -122,13 +123,14 @@ describe("computer-use skill manifest regression", () => {
122
123
  input_schema: { type: "object" as const, properties: {} },
123
124
  category: "computer-use",
124
125
  defaultRiskLevel: RiskLevel.Low,
125
- origin: "skill" as const,
126
- ownerSkillId: "computer-use",
127
126
  execute: async () => ({ content: "stub", isError: false }),
128
127
  }),
129
128
  );
130
129
 
131
- expect(() => registerSkillTools(skillTools)).not.toThrow();
130
+ // Owner flows in through `registerSkillTools(skillId, tools)` and lands
131
+ // in the registry's `ownersByName` map — the tools themselves carry no
132
+ // per-tool owner field.
133
+ expect(() => registerSkillTools("computer-use", skillTools)).not.toThrow();
132
134
 
133
135
  // Clean up
134
136
  unregisterSkillTools("computer-use");
@@ -40,12 +40,6 @@ describe("computer-use tool definitions", () => {
40
40
  expect(allComputerUseTools.length).toBe(11);
41
41
  });
42
42
 
43
- test("all tools have proxy execution mode", () => {
44
- for (const tool of allComputerUseTools) {
45
- expect(tool.executionMode).toBe("proxy");
46
- }
47
- });
48
-
49
43
  test("all tools belong to computer-use category", () => {
50
44
  for (const tool of allComputerUseTools) {
51
45
  expect(tool.category).toBe("computer-use");
@@ -94,8 +88,10 @@ describe("computer_use_click (unified)", () => {
94
88
  expect(props.y.type).toBe("integer");
95
89
  });
96
90
 
97
- test("execute throws proxy error", () => {
98
- expect(() => computerUseClickTool.execute({}, ctx)).toThrow("Proxy tool");
91
+ test("execute returns isError when no proxy resolver is configured", async () => {
92
+ const result = await computerUseClickTool.execute({}, ctx);
93
+ expect(result.isError).toBe(true);
94
+ expect(result.content).toMatch(/No proxy resolver/);
99
95
  });
100
96
  });
101
97
 
@@ -107,10 +103,10 @@ describe("computer_use_type_text", () => {
107
103
  expect(schema(computerUseTypeTextTool).required).toContain("reasoning");
108
104
  });
109
105
 
110
- test("execute throws proxy error", () => {
111
- expect(() => computerUseTypeTextTool.execute({}, ctx)).toThrow(
112
- "Proxy tool",
113
- );
106
+ test("execute returns isError when no proxy resolver is configured", async () => {
107
+ const result = await computerUseTypeTextTool.execute({}, ctx);
108
+ expect(result.isError).toBe(true);
109
+ expect(result.content).toMatch(/No proxy resolver/);
114
110
  });
115
111
  });
116
112
 
@@ -122,8 +118,10 @@ describe("computer_use_key", () => {
122
118
  expect(schema(computerUseKeyTool).required).toContain("reasoning");
123
119
  });
124
120
 
125
- test("execute throws proxy error", () => {
126
- expect(() => computerUseKeyTool.execute({}, ctx)).toThrow("Proxy tool");
121
+ test("execute returns isError when no proxy resolver is configured", async () => {
122
+ const result = await computerUseKeyTool.execute({}, ctx);
123
+ expect(result.isError).toBe(true);
124
+ expect(result.content).toMatch(/No proxy resolver/);
127
125
  });
128
126
  });
129
127
 
@@ -82,7 +82,7 @@ import { migrateProviderConnectionStatusLabel } from "../memory/migrations/244-p
82
82
  import { migrateProviderConnectionBaseUrlAndModels } from "../memory/migrations/250-provider-connection-base-url-and-models.js";
83
83
  import * as schema from "../memory/schema.js";
84
84
  import { getConnection } from "../providers/inference/connections.js";
85
- import { _setStorePath } from "../security/encrypted-store.js";
85
+ import { setStorePathForTesting } from "./encrypted-store-test-helpers.js";
86
86
 
87
87
  // ---------------------------------------------------------------------------
88
88
  // Helpers
@@ -328,14 +328,14 @@ describe("loadConfig startup behavior", () => {
328
328
  const updatesPath = join(WORKSPACE_DIR, "UPDATES.md");
329
329
  if (existsSync(updatesPath)) rmSync(updatesPath, { force: true });
330
330
  ensureTestDir();
331
- _setStorePath(join(WORKSPACE_DIR, "keys.enc"));
331
+ setStorePathForTesting(join(WORKSPACE_DIR, "keys.enc"));
332
332
  delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
333
333
  delete process.env.IS_PLATFORM;
334
334
  invalidateConfigCache();
335
335
  });
336
336
 
337
337
  afterEach(() => {
338
- _setStorePath(null);
338
+ setStorePathForTesting(null);
339
339
  delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
340
340
  delete process.env.IS_PLATFORM;
341
341
  invalidateConfigCache();
@@ -943,14 +943,14 @@ describe("seedInferenceProfiles BYOK-mode managed profile labels", () => {
943
943
  }
944
944
  }
945
945
  ensureTestDir();
946
- _setStorePath(join(WORKSPACE_DIR, "keys.enc"));
946
+ setStorePathForTesting(join(WORKSPACE_DIR, "keys.enc"));
947
947
  delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
948
948
  delete process.env.IS_PLATFORM;
949
949
  invalidateConfigCache();
950
950
  });
951
951
 
952
952
  afterEach(() => {
953
- _setStorePath(null);
953
+ setStorePathForTesting(null);
954
954
  delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
955
955
  delete process.env.IS_PLATFORM;
956
956
  invalidateConfigCache();
@@ -1037,9 +1037,10 @@ describe("seedInferenceProfiles BYOK-mode managed profile labels", () => {
1037
1037
  "anthropic-managed",
1038
1038
  );
1039
1039
  expect("status" in raw.llm.profiles.balanced).toBe(false);
1040
- expect(getConnection(db, "anthropic-managed")?.status).toBe("active");
1041
- expect(getConnection(db, "openai-managed")?.status).toBe("disabled");
1042
- expect(getConnection(db, "gemini-managed")?.status).toBe("disabled");
1040
+ // Connections exist (status is no longer a connection-level concept).
1041
+ expect(getConnection(db, "anthropic-managed")).not.toBeNull();
1042
+ expect(getConnection(db, "openai-managed")).not.toBeNull();
1043
+ expect(getConnection(db, "gemini-managed")).not.toBeNull();
1043
1044
  });
1044
1045
 
1045
1046
  test("off-platform managed-inference hatch respects explicit non-managed active connection", () => {
@@ -1075,26 +1076,10 @@ describe("seedInferenceProfiles BYOK-mode managed profile labels", () => {
1075
1076
  expect(raw.llm.profiles.balanced.provider_connection).toBe(
1076
1077
  "anthropic-personal",
1077
1078
  );
1078
- expect(getConnection(db, "anthropic-managed")?.status).toBe("disabled");
1079
- expect(getConnection(db, "openai-managed")?.status).toBe("disabled");
1080
- expect(getConnection(db, "gemini-managed")?.status).toBe("disabled");
1081
- });
1082
-
1083
- test("off-platform BYOK hatch still disables managed connections", () => {
1084
- const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
1085
- writeFileSync(
1086
- overlayPath,
1087
- JSON.stringify({ llm: { default: { provider: "anthropic" } } }, null, 2) +
1088
- "\n",
1089
- );
1090
- process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
1091
- const db = createProviderConnectionsDb();
1092
-
1093
- mergeDefaultConfigAndSeedInferenceProfiles(db);
1094
-
1095
- expect(getConnection(db, "anthropic-managed")?.status).toBe("disabled");
1096
- expect(getConnection(db, "openai-managed")?.status).toBe("disabled");
1097
- expect(getConnection(db, "gemini-managed")?.status).toBe("disabled");
1079
+ // Connections exist (status is no longer a connection-level concept).
1080
+ expect(getConnection(db, "anthropic-managed")).not.toBeNull();
1081
+ expect(getConnection(db, "openai-managed")).not.toBeNull();
1082
+ expect(getConnection(db, "gemini-managed")).not.toBeNull();
1098
1083
  });
1099
1084
 
1100
1085
  test("non-hatch off-platform boot does NOT auto-disable freshly-materialized managed profiles", () => {
@@ -23,7 +23,7 @@ import {
23
23
  loadConfig,
24
24
  loadRawConfig,
25
25
  } from "../config/loader.js";
26
- import { _setStorePath } from "../security/encrypted-store.js";
26
+ import { setStorePathForTesting } from "./encrypted-store-test-helpers.js";
27
27
 
28
28
  // ---------------------------------------------------------------------------
29
29
  // Helpers
@@ -65,12 +65,12 @@ function listQuarantinedFiles(): string[] {
65
65
  describe("loadConfig corrupt-file recovery", () => {
66
66
  beforeEach(() => {
67
67
  resetWorkspace();
68
- _setStorePath(join(WORKSPACE_DIR, "keys.enc"));
68
+ setStorePathForTesting(join(WORKSPACE_DIR, "keys.enc"));
69
69
  invalidateConfigCache();
70
70
  });
71
71
 
72
72
  afterEach(() => {
73
- _setStorePath(null);
73
+ setStorePathForTesting(null);
74
74
  invalidateConfigCache();
75
75
  });
76
76
 
@@ -187,12 +187,12 @@ describe("loadConfig corrupt-file recovery", () => {
187
187
  describe("loadRawConfig corrupt-file recovery", () => {
188
188
  beforeEach(() => {
189
189
  resetWorkspace();
190
- _setStorePath(join(WORKSPACE_DIR, "keys.enc"));
190
+ setStorePathForTesting(join(WORKSPACE_DIR, "keys.enc"));
191
191
  invalidateConfigCache();
192
192
  });
193
193
 
194
194
  afterEach(() => {
195
- _setStorePath(null);
195
+ setStorePathForTesting(null);
196
196
  invalidateConfigCache();
197
197
  });
198
198