@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
@@ -229,26 +229,11 @@ function createFakeConversation(conversationId: string): Conversation {
229
229
  },
230
230
  persistUserMessage(
231
231
  this: Conversation,
232
- content: string,
233
- attachments: Array<{
234
- id: string;
235
- filename: string;
236
- mimeType: string;
237
- data: string;
238
- extractedText?: string;
239
- filePath?: string;
240
- }>,
241
- requestId?: string,
242
- metadata?: Record<string, unknown>,
243
- displayContent?: string,
244
- ): Promise<string> {
232
+ options: Parameters<typeof persistUserMessage>[1],
233
+ ): Promise<{ id: string; deduplicated: boolean }> {
245
234
  return persistUserMessage(
246
235
  this as Parameters<typeof persistUserMessage>[0],
247
- content,
248
- attachments,
249
- requestId,
250
- metadata,
251
- displayContent,
236
+ options,
252
237
  );
253
238
  },
254
239
  async runAgentLoop(
@@ -83,6 +83,7 @@ mock.module("../memory/conversation-crud.js", () => ({
83
83
  content: string,
84
84
  metadata?: Record<string, unknown>,
85
85
  ) => addMessageMock(conversationId, role, content, metadata),
86
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
86
87
  }));
87
88
 
88
89
  mock.module("../runtime/local-actor-identity.js", () => ({
@@ -149,7 +150,10 @@ describe("handleSendMessage canonical guardian reply interception", () => {
149
150
  replyText: "Access approved. Verification code: 123456.",
150
151
  });
151
152
 
152
- const persistUserMessage = mock(async () => "should-not-be-called");
153
+ const persistUserMessage = mock(async () => ({
154
+ id: "should-not-be-called",
155
+ deduplicated: false,
156
+ }));
153
157
  const runAgentLoop = mock(async () => undefined);
154
158
  const session = {
155
159
  setTrustContext: () => {},
@@ -233,7 +237,10 @@ describe("handleSendMessage canonical guardian reply interception", () => {
233
237
  type: "not_consumed",
234
238
  });
235
239
 
236
- const persistUserMessage = mock(async () => "persisted-user-id");
240
+ const persistUserMessage = mock(async () => ({
241
+ id: "persisted-user-id",
242
+ deduplicated: false,
243
+ }));
237
244
  const runAgentLoop = mock(async () => undefined);
238
245
  const session = {
239
246
  setTrustContext: () => {},
@@ -312,7 +319,10 @@ describe("handleSendMessage canonical guardian reply interception", () => {
312
319
  type: "not_consumed",
313
320
  });
314
321
 
315
- const persistUserMessage = mock(async () => "persisted-user-id");
322
+ const persistUserMessage = mock(async () => ({
323
+ id: "persisted-user-id",
324
+ deduplicated: false,
325
+ }));
316
326
  const runAgentLoop = mock(async () => undefined);
317
327
  const session = {
318
328
  setTrustContext: () => {},
@@ -397,7 +407,10 @@ describe("handleSendMessage canonical guardian reply interception", () => {
397
407
  requestId: "tool-req-code-1",
398
408
  });
399
409
 
400
- const persistUserMessage = mock(async () => "should-not-be-called");
410
+ const persistUserMessage = mock(async () => ({
411
+ id: "should-not-be-called",
412
+ deduplicated: false,
413
+ }));
401
414
  const runAgentLoop = mock(async () => undefined);
402
415
  const session = {
403
416
  setTrustContext: () => {},
@@ -477,7 +490,10 @@ describe("handleSendMessage canonical guardian reply interception", () => {
477
490
  requestId: "pending-reject-1",
478
491
  });
479
492
 
480
- const persistUserMessage = mock(async () => "should-not-be-called");
493
+ const persistUserMessage = mock(async () => ({
494
+ id: "should-not-be-called",
495
+ deduplicated: false,
496
+ }));
481
497
  const runAgentLoop = mock(async () => undefined);
482
498
  const session = {
483
499
  setTrustContext: () => {},
@@ -551,7 +567,10 @@ describe("handleSendMessage canonical guardian reply interception", () => {
551
567
  type: "not_consumed",
552
568
  });
553
569
 
554
- const persistUserMessage = mock(async () => "persisted-user-id");
570
+ const persistUserMessage = mock(async () => ({
571
+ id: "persisted-user-id",
572
+ deduplicated: false,
573
+ }));
555
574
  const runAgentLoop = mock(async () => undefined);
556
575
  const session = {
557
576
  setTrustContext: () => {},
@@ -627,7 +646,10 @@ describe("handleSendMessage canonical guardian reply interception", () => {
627
646
  });
628
647
 
629
648
  const mockGenerator = mock(async () => ({}));
630
- const persistUserMessage = mock(async () => "persisted-user-id");
649
+ const persistUserMessage = mock(async () => ({
650
+ id: "persisted-user-id",
651
+ deduplicated: false,
652
+ }));
631
653
  const runAgentLoop = mock(async () => undefined);
632
654
  const session = {
633
655
  setTrustContext: () => {},
@@ -704,7 +726,10 @@ describe("handleSendMessage canonical guardian reply interception", () => {
704
726
  });
705
727
 
706
728
  const mockGenerator = mock(async () => ({}));
707
- const persistUserMessage = mock(async () => "persisted-user-id");
729
+ const persistUserMessage = mock(async () => ({
730
+ id: "persisted-user-id",
731
+ deduplicated: false,
732
+ }));
708
733
  const runAgentLoop = mock(async () => undefined);
709
734
  const session = {
710
735
  setTrustContext: () => {},
@@ -82,6 +82,7 @@ const addMessageMock = mock(
82
82
  _metadata?: Record<string, unknown>,
83
83
  ) => ({
84
84
  id: role === "user" ? "persisted-user-id" : "persisted-assistant-id",
85
+ deduplicated: false,
85
86
  }),
86
87
  );
87
88
 
@@ -131,6 +132,8 @@ mock.module("../memory/conversation-crud.js", () => ({
131
132
  content: string,
132
133
  metadata?: Record<string, unknown>,
133
134
  ) => addMessageMock(conversationId, role, content, metadata),
135
+ extractImageSourcePaths: () => undefined,
136
+ getConversation: () => null,
134
137
  getConversationOverrideProfile: () => "short-context",
135
138
  getMessages: () => [],
136
139
  provenanceFromTrustContext: (ctx: unknown) =>
@@ -139,6 +142,21 @@ mock.module("../memory/conversation-crud.js", () => ({
139
142
  : { provenanceTrustClass: "unknown" },
140
143
  setConversationOriginChannelIfUnset: () => {},
141
144
  setConversationOriginInterfaceIfUnset: () => {},
145
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
146
+ }));
147
+
148
+ mock.module("../memory/conversation-disk-view.js", () => ({
149
+ syncMessageToDisk: () => {},
150
+ updateMetaFile: () => {},
151
+ }));
152
+
153
+ mock.module("../memory/attachments-store.js", () => ({
154
+ getAttachmentsByIds: () => [],
155
+ getSourcePathsForAttachments: () => new Map(),
156
+ attachmentExists: () => false,
157
+ linkAttachmentToMessage: () => {},
158
+ attachInlineAttachmentToMessage: () => {},
159
+ validateAttachmentUpload: () => ({ ok: true }),
142
160
  }));
143
161
 
144
162
  mock.module("../daemon/conversation-process.js", () => ({
@@ -208,8 +226,13 @@ const _testAuthContext: AuthContext = {
208
226
 
209
227
  function makeConversation() {
210
228
  const persistUserMessage = mock(
211
- async (_content: string, _attachments: unknown[], _requestId?: string) =>
212
- "persisted-user-id",
229
+ async (_options: {
230
+ content: string;
231
+ attachments?: unknown[];
232
+ requestId?: string;
233
+ metadata?: Record<string, unknown>;
234
+ clientMessageId?: string;
235
+ }) => ({ id: "persisted-user-id", deduplicated: false }),
213
236
  );
214
237
  const runAgentLoop = mock(
215
238
  async (
@@ -238,12 +261,20 @@ function makeConversation() {
238
261
  const events: unknown[] = [];
239
262
  const messages: unknown[] = [];
240
263
  const conversation = {
264
+ conversationId: "conv-slash-test",
265
+ messages,
266
+ processing: false,
267
+ abortController: null,
268
+ currentRequestId: undefined,
269
+ queue: { length: 0 },
241
270
  setTrustContext: () => {},
242
271
  updateClient: (_fn: unknown, _b: boolean) => {},
243
272
  emitConfirmationStateChanged: () => {},
244
273
  emitActivityState: () => {},
245
274
  setTurnChannelContext: () => {},
246
275
  setTurnInterfaceContext: () => {},
276
+ getTurnChannelContext: () => null,
277
+ getTurnInterfaceContext: () => null,
247
278
  ensureActorScopedHistory: async () => {},
248
279
  isProcessing: () => false,
249
280
  hasAnyPendingConfirmation: () => false,
@@ -1102,6 +1102,84 @@ describe("stripInjectionsForCompaction preserves persistent blocks", () => {
1102
1102
  });
1103
1103
  });
1104
1104
 
1105
+ // ---------------------------------------------------------------------------
1106
+ // stripInjectionsForCompaction — memory/info wrapper shape
1107
+ // ---------------------------------------------------------------------------
1108
+
1109
+ describe("stripInjectionsForCompaction memory/info wrapper matching", () => {
1110
+ test("injected <info>…</info> static-memory block IS stripped", () => {
1111
+ const messages: Message[] = [
1112
+ {
1113
+ role: "user",
1114
+ content: [
1115
+ { type: "text", text: "<info>\nessentials and threads\n</info>" },
1116
+ { type: "text", text: "Hello" },
1117
+ ],
1118
+ },
1119
+ ];
1120
+
1121
+ const result = stripInjectionsForCompaction(messages);
1122
+ expect(result.length).toBe(1);
1123
+ expect(result[0].content.length).toBe(1);
1124
+ expect((result[0].content[0] as { type: "text"; text: string }).text).toBe(
1125
+ "Hello",
1126
+ );
1127
+ });
1128
+
1129
+ test("injected <memory>…</memory> activation block IS stripped", () => {
1130
+ const messages: Message[] = [
1131
+ {
1132
+ role: "user",
1133
+ content: [
1134
+ { type: "text", text: "<memory>\nactivated slugs\n</memory>" },
1135
+ { type: "text", text: "Hello" },
1136
+ ],
1137
+ },
1138
+ ];
1139
+
1140
+ const result = stripInjectionsForCompaction(messages);
1141
+ expect(result.length).toBe(1);
1142
+ expect(result[0].content.length).toBe(1);
1143
+ expect((result[0].content[0] as { type: "text"; text: string }).text).toBe(
1144
+ "Hello",
1145
+ );
1146
+ });
1147
+
1148
+ test("user text merely starting with <info>\\n (no closing tag) is NOT stripped", () => {
1149
+ const userText = "<info>\nHere is what I want to discuss about the markup";
1150
+ const messages: Message[] = [
1151
+ {
1152
+ role: "user",
1153
+ content: [{ type: "text", text: userText }],
1154
+ },
1155
+ ];
1156
+
1157
+ const result = stripInjectionsForCompaction(messages);
1158
+ expect(result.length).toBe(1);
1159
+ expect(result[0].content.length).toBe(1);
1160
+ expect((result[0].content[0] as { type: "text"; text: string }).text).toBe(
1161
+ userText,
1162
+ );
1163
+ });
1164
+
1165
+ test("user text merely starting with <memory>\\n (no closing tag) is NOT stripped", () => {
1166
+ const userText = "<memory>\nplease remember to buy milk";
1167
+ const messages: Message[] = [
1168
+ {
1169
+ role: "user",
1170
+ content: [{ type: "text", text: userText }],
1171
+ },
1172
+ ];
1173
+
1174
+ const result = stripInjectionsForCompaction(messages);
1175
+ expect(result.length).toBe(1);
1176
+ expect(result[0].content.length).toBe(1);
1177
+ expect((result[0].content[0] as { type: "text"; text: string }).text).toBe(
1178
+ userText,
1179
+ );
1180
+ });
1181
+ });
1182
+
1105
1183
  // ---------------------------------------------------------------------------
1106
1184
  // applyRuntimeInjections with nowScratchpad
1107
1185
  // ---------------------------------------------------------------------------
@@ -92,12 +92,13 @@ mock.module("../skills/tool-manifest.js", () => ({
92
92
  }));
93
93
 
94
94
  mock.module("../tools/skills/skill-tool-factory.js", () => ({
95
+ // Mirrors the real factory: no skillId in/out — ownership is recorded by
96
+ // the registry at `registerSkillTools(skillId, tools)` time.
95
97
  createSkillToolsFromManifest: (
96
98
  entries: SkillToolManifest["tools"],
97
- skillId: string,
98
99
  _skillDir: string,
99
- versionHash: string,
100
- bundled?: boolean,
100
+ _versionHash: string,
101
+ _bundled?: boolean,
101
102
  ): Tool[] => {
102
103
  return entries.map((entry) => ({
103
104
  name: entry.name,
@@ -105,10 +106,6 @@ mock.module("../tools/skills/skill-tool-factory.js", () => ({
105
106
  category: entry.category,
106
107
  defaultRiskLevel: RiskLevel.Medium,
107
108
  executionTarget: "sandbox" as const,
108
- origin: "skill" as const,
109
- ownerSkillId: skillId,
110
- ownerSkillVersionHash: versionHash,
111
- ownerSkillBundled: bundled ?? undefined,
112
109
  input_schema: entry.input_schema as object,
113
110
  execute: async () => ({ content: "", isError: false }),
114
111
  }));
@@ -116,18 +113,14 @@ mock.module("../tools/skills/skill-tool-factory.js", () => ({
116
113
  }));
117
114
 
118
115
  mock.module("../tools/registry.js", () => ({
119
- registerSkillTools: (tools: Tool[]) => {
120
- const skillIds = new Set<string>();
121
- for (const tool of tools) {
122
- const skillId = tool.ownerSkillId!;
123
- skillIds.add(skillId);
124
- const existing = mockRegisteredTools.get(skillId) ?? [];
125
- existing.push(tool);
126
- mockRegisteredTools.set(skillId, existing);
127
- }
128
- for (const id of skillIds) {
129
- mockSkillRefCount.set(id, (mockSkillRefCount.get(id) ?? 0) + 1);
130
- }
116
+ // Matches the new signature: `registerSkillTools(skillId, tools)`. The
117
+ // skillId comes from the caller (conversation-skill-tools) and is the
118
+ // sole source of truth for ownership.
119
+ registerSkillTools: (skillId: string, tools: Tool[]) => {
120
+ const existing = mockRegisteredTools.get(skillId) ?? [];
121
+ existing.push(...tools);
122
+ mockRegisteredTools.set(skillId, existing);
123
+ mockSkillRefCount.set(skillId, (mockSkillRefCount.get(skillId) ?? 0) + 1);
131
124
  return tools;
132
125
  },
133
126
  unregisterSkillTools: (skillId: string) => {
@@ -151,6 +144,22 @@ mock.module("../tools/registry.js", () => ({
151
144
  }
152
145
  return found;
153
146
  },
147
+ // Mirrors the registry's `ownersByName` accessor: the mock derives the
148
+ // owning skillId from `mockRegisteredTools` (which is keyed by skillId)
149
+ // and reports it back as the `OwnerInfo` shape production callers expect.
150
+ getToolOwner: (
151
+ name: string,
152
+ ): { kind: "skill" | "plugin" | "mcp"; id: string } | undefined => {
153
+ let ownerSkillId: string | undefined;
154
+ for (const [skillId, tools] of mockRegisteredTools.entries()) {
155
+ for (const tool of tools) {
156
+ if (tool.name === name) ownerSkillId = skillId;
157
+ }
158
+ }
159
+ return ownerSkillId === undefined
160
+ ? undefined
161
+ : { kind: "skill", id: ownerSkillId };
162
+ },
154
163
  getSkillToolNames: () => {
155
164
  const names: string[] = [];
156
165
  for (const tools of mockRegisteredTools.values()) {
@@ -1730,11 +1739,11 @@ describe("bundled skill: app-builder", () => {
1730
1739
  expect(tools).toBeDefined();
1731
1740
  expect(tools!.length).toBe(4);
1732
1741
 
1733
- // All tools should have skill origin metadata
1734
- for (const tool of tools!) {
1735
- expect(tool.origin).toBe("skill");
1736
- expect(tool.ownerSkillId).toBe("app-builder");
1737
- }
1742
+ // Ownership is asserted by the fact that
1743
+ // `mockRegisteredTools.get("app-builder")` returned the tools — i.e. the
1744
+ // mock `registerSkillTools(skillId, tools)` was called with skillId
1745
+ // "app-builder", which is what the registry would record in production.
1746
+ // The Tool object itself no longer carries a kind/origin field.
1738
1747
  });
1739
1748
  });
1740
1749
 
@@ -2229,7 +2238,7 @@ describe("hash change re-prompt regressions (PR 35)", () => {
2229
2238
  expect(sessionState.get("oncall")).toBe("v2:oncall-edited");
2230
2239
  });
2231
2240
 
2232
- test("registered tools carry updated ownerSkillId after hash change re-registration", () => {
2241
+ test("registered tools carry updated owner after hash change re-registration", () => {
2233
2242
  mockCatalog = [makeSkill("deploy")];
2234
2243
  mockManifests = { deploy: makeManifest(["deploy_run"]) };
2235
2244
  mockVersionHashes = { deploy: "v1:pre-edit" };
@@ -2238,12 +2247,14 @@ describe("hash change re-prompt regressions (PR 35)", () => {
2238
2247
  ...skillLoadMessages('<loaded_skill id="deploy" />'),
2239
2248
  ];
2240
2249
 
2241
- // Turn 1
2250
+ // Turn 1: ownership is asserted by the mock registry's keying — the
2251
+ // tools landing under skillId "deploy" in `mockRegisteredTools` means
2252
+ // `registerSkillTools("deploy", tools)` was called, which is the only
2253
+ // path that records ownership in the real registry.
2242
2254
  projectSkillTools(history, { previouslyActiveSkillIds: sessionState });
2243
2255
  const toolsV1 = mockRegisteredTools.get("deploy");
2244
2256
  expect(toolsV1).toBeDefined();
2245
2257
  expect(toolsV1!.length).toBe(1);
2246
- expect(toolsV1![0].ownerSkillId).toBe("deploy");
2247
2258
 
2248
2259
  // Edit
2249
2260
  mockVersionHashes = { deploy: "v2:post-edit" };
@@ -2253,121 +2264,6 @@ describe("hash change re-prompt regressions (PR 35)", () => {
2253
2264
  const toolsV2 = mockRegisteredTools.get("deploy");
2254
2265
  expect(toolsV2).toBeDefined();
2255
2266
  expect(toolsV2!.length).toBeGreaterThanOrEqual(1);
2256
- expect(toolsV2![0].ownerSkillId).toBe("deploy");
2257
- });
2258
- });
2259
-
2260
- // ---------------------------------------------------------------------------
2261
- // Version hash plumbing regression tests
2262
- // Verify that createSkillToolsFromManifest receives the computed hash and
2263
- // that projected tools carry ownerSkillVersionHash, which downstream
2264
- // components (executor.ts) use to build policy context.
2265
- // ---------------------------------------------------------------------------
2266
-
2267
- describe("version hash plumbing to projected tools", () => {
2268
- let sessionState: Map<string, string>;
2269
-
2270
- beforeEach(() => {
2271
- mockCatalog = [];
2272
- mockManifests = {};
2273
- mockRegisteredTools = new Map();
2274
- mockUnregisteredSkillIds = [];
2275
- mockSkillRefCount = new Map();
2276
- mockVersionHashes = {};
2277
- mockVersionHashErrors = new Set();
2278
- sessionState = new Map<string, string>();
2279
- });
2280
-
2281
- test("projected tools carry ownerSkillVersionHash matching the computed hash", () => {
2282
- mockCatalog = [makeSkill("deploy")];
2283
- mockManifests = { deploy: makeManifest(["deploy_run", "deploy_status"]) };
2284
- mockVersionHashes = { deploy: "v1:secure-hash-abc" };
2285
-
2286
- const history: Message[] = [
2287
- ...skillLoadMessages('<loaded_skill id="deploy" />'),
2288
- ];
2289
-
2290
- projectSkillTools(history, { previouslyActiveSkillIds: sessionState });
2291
-
2292
- const tools = mockRegisteredTools.get("deploy");
2293
- expect(tools).toBeDefined();
2294
- expect(tools!.length).toBe(2);
2295
-
2296
- // Every tool created for this skill must carry the version hash
2297
- for (const tool of tools!) {
2298
- expect(tool.ownerSkillVersionHash).toBe("v1:secure-hash-abc");
2299
- }
2300
- });
2301
-
2302
- test("after hash change re-registration, new tools carry the updated hash", () => {
2303
- mockCatalog = [makeSkill("deploy")];
2304
- mockManifests = { deploy: makeManifest(["deploy_run"]) };
2305
- mockVersionHashes = { deploy: "v1:hash-before" };
2306
-
2307
- const history: Message[] = [
2308
- ...skillLoadMessages('<loaded_skill id="deploy" />'),
2309
- ];
2310
-
2311
- // Turn 1: register with original hash
2312
- projectSkillTools(history, { previouslyActiveSkillIds: sessionState });
2313
- const toolsV1 = mockRegisteredTools.get("deploy");
2314
- expect(toolsV1).toBeDefined();
2315
- expect(toolsV1![0].ownerSkillVersionHash).toBe("v1:hash-before");
2316
-
2317
- // Simulate file edit — hash changes
2318
- mockVersionHashes = { deploy: "v2:hash-after" };
2319
-
2320
- // Turn 2: re-registration with new hash
2321
- projectSkillTools(history, { previouslyActiveSkillIds: sessionState });
2322
- const toolsV2 = mockRegisteredTools.get("deploy");
2323
- expect(toolsV2).toBeDefined();
2324
-
2325
- // The most recently registered tool should carry the new hash
2326
- const lastTool = toolsV2![toolsV2!.length - 1];
2327
- expect(lastTool.ownerSkillVersionHash).toBe("v2:hash-after");
2328
- });
2329
-
2330
- test("tools for multiple co-active skills each carry their own version hash", () => {
2331
- mockCatalog = [makeSkill("deploy"), makeSkill("oncall")];
2332
- mockManifests = {
2333
- deploy: makeManifest(["deploy_run"]),
2334
- oncall: makeManifest(["oncall_page"]),
2335
- };
2336
- mockVersionHashes = {
2337
- deploy: "v1:deploy-hash-123",
2338
- oncall: "v1:oncall-hash-456",
2339
- };
2340
-
2341
- const history: Message[] = [
2342
- ...skillLoadMessages('<loaded_skill id="deploy" />'),
2343
- ...skillLoadMessages('<loaded_skill id="oncall" />'),
2344
- ];
2345
-
2346
- projectSkillTools(history, { previouslyActiveSkillIds: sessionState });
2347
-
2348
- const deployTools = mockRegisteredTools.get("deploy");
2349
- expect(deployTools).toBeDefined();
2350
- expect(deployTools![0].ownerSkillVersionHash).toBe("v1:deploy-hash-123");
2351
-
2352
- const oncallTools = mockRegisteredTools.get("oncall");
2353
- expect(oncallTools).toBeDefined();
2354
- expect(oncallTools![0].ownerSkillVersionHash).toBe("v1:oncall-hash-456");
2355
- });
2356
-
2357
- test("default hash is used and plumbed when no explicit hash override is set", () => {
2358
- mockCatalog = [makeSkill("deploy")];
2359
- mockManifests = { deploy: makeManifest(["deploy_run"]) };
2360
- // No mockVersionHashes override — mock returns 'v1:default-hash-deploy'
2361
-
2362
- const history: Message[] = [
2363
- ...skillLoadMessages('<loaded_skill id="deploy" />'),
2364
- ];
2365
-
2366
- projectSkillTools(history, { previouslyActiveSkillIds: sessionState });
2367
-
2368
- const tools = mockRegisteredTools.get("deploy");
2369
- expect(tools).toBeDefined();
2370
- expect(tools![0].ownerSkillVersionHash).toBe("v1:default-hash-deploy");
2371
2267
  });
2372
2268
  });
2373
2269