@vellumai/assistant 0.10.12 → 0.11.0-staging.1

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 (776) hide show
  1. package/AGENTS.md +1 -1
  2. package/ARCHITECTURE.md +4 -5
  3. package/README.md +1 -1
  4. package/docs/architecture/memory.md +60 -23
  5. package/docs/error-handling.md +3 -3
  6. package/docs/guardian-request-flow.md +112 -0
  7. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  8. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
  9. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
  10. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
  11. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
  12. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/app.d.ts +28 -0
  13. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/app.d.ts.map +1 -1
  14. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.d.ts +2 -2
  15. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.d.ts.map +1 -1
  16. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.js.map +1 -1
  17. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/message.d.ts +2 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/message.d.ts.map +1 -1
  19. package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/package.json +1 -1
  20. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  21. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
  22. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
  23. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
  24. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
  25. package/node_modules/@vellumai/gateway-client/package.json +1 -1
  26. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +6 -0
  27. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +34 -0
  28. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  29. package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
  30. package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
  31. package/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
  32. package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
  33. package/openapi.yaml +246 -10
  34. package/package.json +2 -2
  35. package/src/__tests__/acp-session.test.ts +3 -3
  36. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +3 -0
  37. package/src/__tests__/anthropic-provider.test.ts +40 -0
  38. package/src/__tests__/approval-cascade.test.ts +5 -5
  39. package/src/__tests__/approval-routes-http.test.ts +3 -3
  40. package/src/__tests__/ask-question-resolver.test.ts +207 -0
  41. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +16 -16
  42. package/src/__tests__/assistant-event-hub-targeted.test.ts +13 -11
  43. package/src/__tests__/assistant-event-hub.test.ts +13 -11
  44. package/src/__tests__/assistant-event.test.ts +12 -9
  45. package/src/__tests__/assistant-feature-flag-guard.test.ts +3 -3
  46. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +1 -1
  47. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -58
  48. package/src/__tests__/assistant-stream-state.test.ts +17 -7
  49. package/src/__tests__/avatar-identity-sync.test.ts +3 -3
  50. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
  51. package/src/__tests__/call-conversation-messages.test.ts +134 -18
  52. package/src/__tests__/call-start-guardian-guard.test.ts +27 -0
  53. package/src/__tests__/channel-approvals.test.ts +0 -27
  54. package/src/__tests__/channel-guardian.test.ts +85 -512
  55. package/src/__tests__/channel-readiness-slack-remote.test.ts +151 -3
  56. package/src/__tests__/channel-retry-sweep.test.ts +88 -1
  57. package/src/__tests__/channel-setup-panel-ack.test.ts +12 -9
  58. package/src/__tests__/chat-reveal-guard-priming.test.ts +31 -34
  59. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +2 -2
  60. package/src/__tests__/compaction-events.test.ts +8 -8
  61. package/src/__tests__/config-loader-platform-defaults.test.ts +54 -28
  62. package/src/__tests__/config-model-image-provider.test.ts +20 -0
  63. package/src/__tests__/config-schema-memory-substrate.test.ts +306 -0
  64. package/src/__tests__/config-schema.test.ts +14 -2
  65. package/src/__tests__/config-set-platform-guard.test.ts +11 -12
  66. package/src/__tests__/config-sounds-sync.test.ts +4 -4
  67. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +5 -0
  68. package/src/__tests__/context-search-memory-source.test.ts +1 -1
  69. package/src/__tests__/context-search-memory-v2-source.test.ts +6 -6
  70. package/src/__tests__/context-token-estimator.test.ts +54 -1
  71. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +12 -3
  72. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +13 -4
  73. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +4 -4
  74. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -1
  75. package/src/__tests__/conversation-agent-loop-overflow.test.ts +22 -13
  76. package/src/__tests__/conversation-agent-loop.test.ts +39 -30
  77. package/src/__tests__/conversation-confirmation-signals.test.ts +14 -14
  78. package/src/__tests__/conversation-evictor.test.ts +49 -0
  79. package/src/__tests__/conversation-fork-crud.test.ts +1 -1
  80. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  81. package/src/__tests__/conversation-key-store-disk-view.test.ts +5 -5
  82. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +5 -5
  83. package/src/__tests__/conversation-message-sync-tags.test.ts +4 -4
  84. package/src/__tests__/conversation-queue.test.ts +81 -81
  85. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +8 -1
  86. package/src/__tests__/conversation-routes-hidden-queue.test.ts +8 -1
  87. package/src/__tests__/conversation-routes-slash-commands.test.ts +10 -1
  88. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -2
  89. package/src/__tests__/conversation-slash-queue.test.ts +11 -11
  90. package/src/__tests__/conversation-slash-unknown.test.ts +2 -2
  91. package/src/__tests__/conversation-speed-override.test.ts +2 -2
  92. package/src/__tests__/conversation-summarize-route.test.ts +9 -0
  93. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +18 -16
  94. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +17 -17
  95. package/src/__tests__/conversation-surfaces-app-open.test.ts +7 -4
  96. package/src/__tests__/conversation-surfaces-data-persist.test.ts +7 -7
  97. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +9 -9
  98. package/src/__tests__/conversation-surfaces-standalone.test.ts +12 -12
  99. package/src/__tests__/conversation-surfaces-state-update.test.ts +8 -5
  100. package/src/__tests__/conversation-surfaces-table-action.test.ts +6 -3
  101. package/src/__tests__/conversation-surfaces-task-progress.test.ts +46 -46
  102. package/src/__tests__/conversation-sync-tags.test.ts +5 -5
  103. package/src/__tests__/conversation-wait-for-idle.test.ts +2 -2
  104. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
  105. package/src/__tests__/conversation-workspace-injection.test.ts +0 -3
  106. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -3
  107. package/src/__tests__/copy-composer-tc-templates.test.ts +3 -131
  108. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  109. package/src/__tests__/daemon-assistant-events.test.ts +14 -15
  110. package/src/__tests__/db-test-helpers.ts +13 -27
  111. package/src/__tests__/disk-pressure-routes.test.ts +12 -3
  112. package/src/__tests__/document-tool-security.test.ts +95 -0
  113. package/src/__tests__/drain-kick-guard.test.ts +232 -0
  114. package/src/__tests__/dynamic-skill-background-guard.test.ts +19 -6
  115. package/src/__tests__/emit-event-signal.test.ts +5 -6
  116. package/src/__tests__/encrypted-store-test-helpers.ts +10 -20
  117. package/src/__tests__/events-tail-route.test.ts +6 -4
  118. package/src/__tests__/feature-flag-test-helpers.ts +10 -20
  119. package/src/__tests__/file-edit-tool.test.ts +24 -4
  120. package/src/__tests__/file-list-tool.test.ts +2 -1
  121. package/src/__tests__/file-read-tool.test.ts +62 -10
  122. package/src/__tests__/file-write-tool.test.ts +24 -5
  123. package/src/__tests__/followup-tools.test.ts +58 -0
  124. package/src/__tests__/gateway-threshold-reader-mock.ts +99 -0
  125. package/src/__tests__/graph-extraction-event-date.test.ts +1 -1
  126. package/src/__tests__/guardian-question-mode.test.ts +42 -3
  127. package/src/__tests__/guardian-reply-router-answer-mode.test.ts +283 -0
  128. package/src/__tests__/guardian-vellum-destination-pinning.test.ts +221 -0
  129. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  130. package/src/__tests__/heartbeat-service.test.ts +1 -0
  131. package/src/__tests__/helpers/native-web-search-harness.ts +10 -10
  132. package/src/__tests__/host-browser-proxy.test.ts +1 -1
  133. package/src/__tests__/host-file-edit-tool.test.ts +3 -3
  134. package/src/__tests__/host-file-read-tool.test.ts +2 -2
  135. package/src/__tests__/host-file-write-tool.test.ts +7 -3
  136. package/src/__tests__/host-shell-tool.test.ts +17 -5
  137. package/src/__tests__/host-transfer-pending-interactions.test.ts +8 -8
  138. package/src/__tests__/image-credentials.test.ts +65 -8
  139. package/src/__tests__/injection-block.test.ts +4 -4
  140. package/src/__tests__/injector-chain.test.ts +1 -1
  141. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  142. package/src/__tests__/injector-registry-order-guard.test.ts +4 -9
  143. package/src/__tests__/injector-v3-suppression.test.ts +6 -4
  144. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +27 -28
  145. package/src/__tests__/list-messages-page-latest.test.ts +2 -2
  146. package/src/__tests__/llm-usage-store.test.ts +67 -4
  147. package/src/__tests__/log-redact.test.ts +18 -0
  148. package/src/__tests__/managed-profile-guard.test.ts +27 -0
  149. package/src/__tests__/managed-skill-lifecycle.test.ts +2 -2
  150. package/src/__tests__/media-generate-image.test.ts +62 -11
  151. package/src/__tests__/memory-identity-context-parity.test.ts +1 -1
  152. package/src/__tests__/memory-jobs-worker-lanes.test.ts +9 -1
  153. package/src/__tests__/memory-retrieval-hook.test.ts +4 -4
  154. package/src/__tests__/notification-decision-strategy.test.ts +115 -11
  155. package/src/__tests__/notification-deep-link.test.ts +12 -12
  156. package/src/__tests__/notification-vellum-adapter.test.ts +8 -8
  157. package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
  158. package/src/__tests__/path-policy.test.ts +315 -0
  159. package/src/__tests__/pending-interactions-resolved-event.test.ts +6 -6
  160. package/src/__tests__/persistence-layering-guard.test.ts +2 -2
  161. package/src/__tests__/pkb-autoinject.test.ts +1 -1
  162. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -0
  163. package/src/__tests__/plugin-event-hub-facade.test.ts +22 -15
  164. package/src/__tests__/plugin-import-boundary-guard.test.ts +15 -15
  165. package/src/__tests__/processing-flag-persist-failure.test.ts +0 -4
  166. package/src/__tests__/provider-platform-proxy-integration.test.ts +0 -1
  167. package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
  168. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +5 -5
  169. package/src/__tests__/require-fresh-approval.test.ts +38 -38
  170. package/src/__tests__/run-due-schedules.test.ts +72 -1
  171. package/src/__tests__/runtime-events-sse-parity.test.ts +11 -10
  172. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  173. package/src/__tests__/schedule-routes.test.ts +44 -5
  174. package/src/__tests__/schedule-store.test.ts +3 -3
  175. package/src/__tests__/schedule-tools.test.ts +176 -0
  176. package/src/__tests__/secret-prompt-log-hygiene.test.ts +3 -3
  177. package/src/__tests__/secret-prompter-channel-fallback.test.ts +3 -3
  178. package/src/__tests__/secret-response-routing.test.ts +3 -3
  179. package/src/__tests__/secret-routes-platform-proxy.test.ts +4 -7
  180. package/src/__tests__/secret-scanner.test.ts +36 -0
  181. package/src/__tests__/send-endpoint-busy.test.ts +7 -7
  182. package/src/__tests__/slack-required-scopes-mirror.test.ts +81 -0
  183. package/src/__tests__/starter-task-flow.test.ts +6 -3
  184. package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
  185. package/src/__tests__/subagent-disposal.test.ts +40 -11
  186. package/src/__tests__/subagent-fork-notifications.test.ts +4 -4
  187. package/src/__tests__/subagent-fork-prompt-role.test.ts +3 -3
  188. package/src/__tests__/subagent-fork-spawn.test.ts +4 -4
  189. package/src/__tests__/subagent-manager-notify.test.ts +73 -14
  190. package/src/__tests__/subagent-notify-parent.test.ts +48 -4
  191. package/src/__tests__/subagent-spawn-and-await.test.ts +62 -14
  192. package/src/__tests__/subagent-tools.test.ts +64 -0
  193. package/src/__tests__/sync-message-contract.test.ts +3 -3
  194. package/src/__tests__/terminal-tools.test.ts +12 -3
  195. package/src/__tests__/test-preload.ts +9 -0
  196. package/src/__tests__/tool-approval-handler.test.ts +583 -43
  197. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +7 -4
  198. package/src/__tests__/tool-executor.test.ts +116 -0
  199. package/src/__tests__/tool-grant-request-escalation.test.ts +5 -0
  200. package/src/__tests__/tool-preview-lifecycle.test.ts +32 -29
  201. package/src/__tests__/tool-result-metadata-plumbing.test.ts +5 -5
  202. package/src/__tests__/tool-start-timestamp.test.ts +4 -4
  203. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -22
  204. package/src/__tests__/ui-choice-copy-surfaces.test.ts +13 -13
  205. package/src/__tests__/ui-work-result-surface.test.ts +3 -3
  206. package/src/__tests__/voice-scoped-grant-consumer.test.ts +6 -6
  207. package/src/__tests__/voice-session-bridge.test.ts +44 -44
  208. package/src/__tests__/workspace-migration-134-image-generation-mode-to-provider.test.ts +284 -0
  209. package/src/__tests__/workspace-policy.test.ts +399 -0
  210. package/src/acp/__tests__/client-handler.test.ts +3 -3
  211. package/src/acp/__tests__/session-manager-persistence.test.ts +10 -10
  212. package/src/acp/__tests__/session-manager-resume.test.ts +7 -7
  213. package/src/acp/client-handler.ts +3 -3
  214. package/src/acp/session-manager.ts +8 -8
  215. package/src/api/events/subagent-event.ts +2 -2
  216. package/src/api/responses/memory-v2-activation-log.ts +2 -2
  217. package/src/approvals/AGENTS.md +2 -0
  218. package/src/approvals/guardian-request-resolvers.ts +118 -24
  219. package/src/calls/__tests__/voice-control-protocol.test.ts +57 -0
  220. package/src/calls/__tests__/voice-session-bridge.test.ts +158 -4
  221. package/src/calls/__tests__/voice-triage-escalate.test.ts +3 -4
  222. package/src/calls/call-controller.ts +27 -27
  223. package/src/calls/call-conversation-messages.ts +58 -18
  224. package/src/calls/voice-control-protocol.ts +56 -0
  225. package/src/calls/voice-session-bridge.ts +156 -58
  226. package/src/calls/voice-triage-escalate.ts +2 -3
  227. package/src/channels/config.ts +8 -0
  228. package/src/channels/types.ts +1 -0
  229. package/src/cli/commands/config.ts +49 -13
  230. package/src/cli/commands/memory/index.help.ts +4 -2
  231. package/src/cli/commands/memory/memory-retrospective.ts +5 -0
  232. package/src/cli/lib/bundled-marketplace.json +12 -0
  233. package/src/cli.ts +2 -109
  234. package/src/config/__tests__/deployment-context-defaults.test.ts +9 -0
  235. package/src/config/__tests__/substrate-twin-shadowing.test.ts +191 -0
  236. package/src/config/assistant-feature-flags.ts +1 -1
  237. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +13 -7
  238. package/src/config/feature-flag-cache.ts +6 -16
  239. package/src/config/feature-flag-registry.json +14 -30
  240. package/src/config/loader.ts +7 -1
  241. package/src/config/memory-tier.ts +15 -10
  242. package/src/config/memory-v3-gate.test.ts +278 -1
  243. package/src/config/memory-v3-gate.ts +88 -26
  244. package/src/config/raw-config-utils.ts +1 -1
  245. package/src/config/schemas/__tests__/live-voice.test.ts +27 -16
  246. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  247. package/src/config/schemas/live-voice.ts +33 -7
  248. package/src/config/schemas/llm.ts +1 -0
  249. package/src/config/schemas/memory-retrospective.ts +13 -0
  250. package/src/config/schemas/memory-substrate.ts +183 -0
  251. package/src/config/schemas/memory-v2.ts +3 -2
  252. package/src/config/schemas/memory-v3.ts +11 -4
  253. package/src/config/schemas/memory.ts +35 -1
  254. package/src/config/schemas/services.ts +10 -2
  255. package/src/config/substrate-twin-shadowing.ts +195 -0
  256. package/src/config/webhook-routing.ts +67 -0
  257. package/src/context/compactor.ts +10 -3
  258. package/src/context/token-estimator.ts +21 -0
  259. package/src/daemon/__tests__/channel-ui-capability.test.ts +85 -0
  260. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +3 -3
  261. package/src/daemon/__tests__/embedding-reconcile.test.ts +3 -3
  262. package/src/daemon/__tests__/inference-profile-notification.test.ts +3 -6
  263. package/src/daemon/__tests__/native-web-search-metadata.test.ts +5 -5
  264. package/src/daemon/__tests__/web-search-status-text.test.ts +2 -2
  265. package/src/daemon/channel-ui-capability.ts +70 -1
  266. package/src/daemon/conversation-agent-loop-handlers.ts +4 -4
  267. package/src/daemon/conversation-agent-loop.ts +12 -5
  268. package/src/daemon/conversation-evictor.ts +26 -4
  269. package/src/daemon/conversation-launch.ts +11 -14
  270. package/src/daemon/conversation-messaging.ts +14 -14
  271. package/src/daemon/conversation-notifiers.ts +2 -2
  272. package/src/daemon/conversation-process.ts +133 -21
  273. package/src/daemon/conversation-queue-manager.ts +7 -7
  274. package/src/daemon/conversation-runtime-assembly.ts +16 -0
  275. package/src/daemon/conversation-store.ts +11 -3
  276. package/src/daemon/conversation-surfaces.ts +4 -4
  277. package/src/daemon/conversation-tool-setup.ts +13 -7
  278. package/src/daemon/conversation-usage.ts +12 -11
  279. package/src/daemon/conversation.ts +38 -15
  280. package/src/daemon/disk-pressure-guard.ts +5 -12
  281. package/src/daemon/embedding-reconcile.ts +14 -9
  282. package/src/daemon/handlers/config-channels.ts +40 -134
  283. package/src/daemon/handlers/config-model.ts +15 -7
  284. package/src/daemon/handlers/conversations.ts +4 -2
  285. package/src/daemon/handlers/shared.ts +29 -0
  286. package/src/daemon/host-proxy-base.ts +4 -4
  287. package/src/daemon/lifecycle.ts +13 -0
  288. package/src/daemon/message-protocol.ts +8 -144
  289. package/src/daemon/message-types/computer-use.ts +0 -12
  290. package/src/daemon/message-types/conversations.ts +9 -345
  291. package/src/daemon/message-types/host-app-control.ts +0 -9
  292. package/src/daemon/message-types/host-browser.ts +0 -7
  293. package/src/daemon/message-types/host-ui-snapshot.ts +0 -7
  294. package/src/daemon/message-types/messages.ts +0 -48
  295. package/src/daemon/message-types/notifications.ts +0 -7
  296. package/src/daemon/message-types/skills.ts +0 -5
  297. package/src/daemon/message-types/surfaces.ts +0 -9
  298. package/src/daemon/message-types/sync.ts +0 -2
  299. package/src/daemon/process-message.ts +5 -5
  300. package/src/daemon/skill-memory-refresh.ts +5 -5
  301. package/src/daemon/tool-side-effects.ts +13 -13
  302. package/src/daemon/trust-context.ts +1 -1
  303. package/src/daemon/wake-conversation-ops.ts +4 -4
  304. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +100 -7
  305. package/src/heartbeat/__tests__/heartbeat-service.test.ts +67 -0
  306. package/src/heartbeat/heartbeat-run-store.ts +81 -4
  307. package/src/heartbeat/heartbeat-service.ts +32 -1
  308. package/src/home/__tests__/feed-writer.test.ts +7 -7
  309. package/src/home/__tests__/home-content-refresh.test.ts +3 -0
  310. package/src/home/__tests__/suggested-prompts.test.ts +1 -0
  311. package/src/home/feed-writer.ts +6 -13
  312. package/src/home/home-content-refresh.ts +6 -9
  313. package/src/home/relationship-state-writer.ts +5 -12
  314. package/src/home/suggested-prompts-cache.ts +6 -19
  315. package/src/ipc/__tests__/events-publish-client.test.ts +67 -0
  316. package/src/ipc/events-publish-client.ts +44 -0
  317. package/src/ipc/routes/__tests__/conversation-sync-ipc-routes.test.ts +2 -2
  318. package/src/ipc/routes/__tests__/events-ipc-routes.test.ts +38 -9
  319. package/src/ipc/routes/events-ipc-routes.ts +11 -31
  320. package/src/live-voice/__tests__/front-decision.test.ts +4 -176
  321. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +276 -68
  322. package/src/live-voice/__tests__/live-voice-events.test.ts +6 -3
  323. package/src/live-voice/__tests__/live-voice-progress.test.ts +185 -46
  324. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +24 -59
  325. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +38 -54
  326. package/src/live-voice/__tests__/live-voice-vad.test.ts +218 -422
  327. package/src/live-voice/front-decision.ts +5 -155
  328. package/src/live-voice/live-voice-metrics.ts +4 -1
  329. package/src/live-voice/live-voice-session.ts +650 -333
  330. package/src/live-voice/progress-phrases.ts +17 -0
  331. package/src/live-voice/protocol.ts +15 -0
  332. package/src/media/app-icon-generator.ts +15 -8
  333. package/src/media/avatar-router.ts +9 -5
  334. package/src/media/image-credentials.ts +42 -10
  335. package/src/media/image-service.ts +1 -13
  336. package/src/media/types.ts +26 -3
  337. package/src/notifications/AGENTS.md +2 -0
  338. package/src/notifications/__tests__/broadcaster.test.ts +95 -0
  339. package/src/notifications/adapters/macos.ts +3 -3
  340. package/src/notifications/broadcaster.ts +57 -0
  341. package/src/notifications/copy-composer.ts +0 -15
  342. package/src/notifications/decision-engine.ts +21 -22
  343. package/src/notifications/guardian-question-mode.ts +57 -2
  344. package/src/notifications/home-feed-side-effect.ts +4 -0
  345. package/src/notifications/signal.ts +6 -4
  346. package/src/notifications/trusted-contact-payloads.ts +3 -4
  347. package/src/notifications/vellum-card-affinity.ts +39 -0
  348. package/src/oauth/AGENTS.md +1 -1
  349. package/src/permissions/channel-permission-query.test.ts +69 -0
  350. package/src/permissions/channel-permission-query.ts +73 -1
  351. package/src/permissions/checker.test.ts +85 -9
  352. package/src/permissions/checker.ts +17 -22
  353. package/src/permissions/confirmation-guardian-request.test.ts +2 -2
  354. package/src/permissions/confirmation-guardian-request.ts +2 -2
  355. package/src/permissions/gateway-threshold-reader.test.ts +224 -17
  356. package/src/permissions/gateway-threshold-reader.ts +82 -10
  357. package/src/permissions/ipc-risk-types.ts +8 -0
  358. package/src/permissions/prompter.ts +5 -5
  359. package/src/permissions/question-guardian-request.test.ts +222 -0
  360. package/src/permissions/question-guardian-request.ts +179 -0
  361. package/src/permissions/question-prompter.test.ts +8 -8
  362. package/src/permissions/question-prompter.ts +18 -0
  363. package/src/permissions/secret-prompter.ts +2 -4
  364. package/src/permissions/workspace-policy.ts +236 -34
  365. package/src/persistence/__tests__/lifecycle-quiesce.test.ts +82 -0
  366. package/src/persistence/__tests__/message-content-file.test.ts +58 -3
  367. package/src/persistence/conversation-crud.ts +93 -0
  368. package/src/persistence/conversation-key-store.ts +63 -0
  369. package/src/persistence/db-async-query.ts +1 -1
  370. package/src/persistence/db-singleton.ts +14 -27
  371. package/src/persistence/delivery-crud.ts +45 -0
  372. package/src/persistence/embeddings/embedding-backend.ts +2 -1
  373. package/src/persistence/embeddings/embedding-identity.ts +7 -3
  374. package/src/persistence/job-utils.ts +32 -27
  375. package/src/persistence/jobs-store.ts +92 -3
  376. package/src/persistence/lifecycle-quiesce.ts +80 -0
  377. package/src/persistence/llm-usage-store.ts +45 -8
  378. package/src/persistence/message-content-file.ts +4 -4
  379. package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +1 -1
  380. package/src/persistence/migrations/351-schedule-skill-script-handoff.ts +39 -0
  381. package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.test.ts +83 -0
  382. package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.ts +36 -0
  383. package/src/persistence/migrations/353-add-llm-usage-conversation-type.test.ts +110 -0
  384. package/src/persistence/migrations/353-add-llm-usage-conversation-type.ts +49 -0
  385. package/src/persistence/schema/infrastructure.ts +11 -0
  386. package/src/persistence/steps.ts +7 -1
  387. package/src/plugin-api/__tests__/publish-event-forwarding.test.ts +113 -0
  388. package/src/plugin-api/__tests__/publish-event.test.ts +57 -0
  389. package/src/plugin-api/conversation-turn.ts +4 -4
  390. package/src/plugin-api/event-hub-facade.ts +15 -6
  391. package/src/plugin-api/index.ts +10 -4
  392. package/src/plugin-api/publish-event.ts +36 -0
  393. package/src/plugins/AGENTS.md +2 -0
  394. package/src/plugins/defaults/compaction/window-manager.ts +9 -0
  395. package/src/plugins/defaults/index.ts +9 -13
  396. package/src/plugins/defaults/memory/AGENTS.md +775 -0
  397. package/src/plugins/defaults/memory/__tests__/capability-seed-embed-gate.test.ts +186 -0
  398. package/src/plugins/defaults/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +1 -1
  399. package/src/plugins/defaults/memory/__tests__/indexer-tier-dispatch.test.ts +129 -0
  400. package/src/plugins/defaults/memory/__tests__/jobs-worker-quiesce-gate.test.ts +91 -0
  401. package/src/plugins/defaults/memory/__tests__/jobs-worker-v1-graph-substrate-noop.test.ts +342 -0
  402. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +9 -1
  403. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +36 -1
  404. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-sweep-defer.test.ts +9 -1
  405. package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +2 -2
  406. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +44 -10
  407. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +151 -10
  408. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1155 -0
  409. package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
  410. package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -3
  411. package/src/plugins/defaults/memory/__tests__/tools-delete-memory-page.test.ts +1 -1
  412. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +71 -35
  413. package/src/plugins/defaults/memory/context-search/sources/memory.ts +5 -1
  414. package/src/plugins/defaults/memory/fork-conversation-memory.ts +4 -4
  415. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +80 -10
  416. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +1 -1
  417. package/src/plugins/defaults/memory/graph/capability-seed.ts +24 -10
  418. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +123 -49
  419. package/src/plugins/defaults/memory/graph/graph-search.ts +6 -118
  420. package/src/plugins/defaults/memory/graph/in-context-tracker.test.ts +173 -0
  421. package/src/plugins/defaults/memory/graph/in-context-tracker.ts +109 -0
  422. package/src/plugins/defaults/memory/graph/store.ts +1 -0
  423. package/src/plugins/defaults/memory/graph/tool-handlers.test.ts +1 -1
  424. package/src/plugins/defaults/memory/graph/tool-handlers.ts +5 -2
  425. package/src/plugins/defaults/memory/graph-topology/__tests__/build-memory-graph.test.ts +1 -1
  426. package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +6 -9
  427. package/src/plugins/defaults/memory/hooks/__tests__/user-prompt-submit.test.ts +30 -16
  428. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +18 -14
  429. package/src/plugins/defaults/memory/indexer.ts +146 -89
  430. package/src/plugins/defaults/memory/injectors.ts +86 -41
  431. package/src/plugins/defaults/memory/job-handlers.ts +130 -39
  432. package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +2 -2
  433. package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +22 -10
  434. package/src/plugins/defaults/memory/jobs-worker.ts +279 -208
  435. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +4 -2
  436. package/src/plugins/defaults/memory/memory-retrospective-job.ts +40 -3
  437. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +99 -11
  438. package/src/plugins/defaults/memory/src/__tests__/memory-v2-routes.test.ts +5 -3
  439. package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +3 -4
  440. package/src/plugins/defaults/memory/src/memory-graph-routes.ts +2 -1
  441. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +7 -5
  442. package/src/plugins/defaults/memory/src/memory-item-routes.ts +51 -19
  443. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +31 -20
  444. package/src/plugins/defaults/memory/startup.ts +58 -21
  445. package/src/plugins/defaults/memory/substrate/__tests__/boot-maintenance.test.ts +335 -0
  446. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/cli-command-store.test.ts +14 -8
  447. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-job.test.ts +51 -21
  448. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/edge-index.test.ts +1 -1
  449. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/frontmatter-sweep.test.ts +3 -3
  450. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-index.test.ts +1 -1
  451. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-store.test.ts +1 -1
  452. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/prompts-consolidation.test.ts +2 -2
  453. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/qdrant.test.ts +23 -14
  454. package/src/plugins/defaults/memory/substrate/__tests__/reembed-job.test.ts +262 -0
  455. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sim.test.ts +9 -12
  456. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-content.test.ts +2 -2
  457. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-store.test.ts +9 -9
  458. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sparse-bm25.test.ts +12 -5
  459. package/src/plugins/defaults/memory/substrate/__tests__/spread.test.ts +276 -0
  460. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/static-context.test.ts +17 -8
  461. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sweep-job.test.ts +9 -9
  462. package/src/plugins/defaults/memory/{v3/substrate/memory-v2-startup.ts → substrate/boot-maintenance.ts} +43 -24
  463. package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-store.ts +13 -8
  464. package/src/plugins/defaults/memory/{v3/substrate → substrate}/consolidation-job.ts +51 -27
  465. package/src/plugins/defaults/memory/{v3/substrate → substrate}/constants.ts +1 -0
  466. package/src/plugins/defaults/memory/{v3/substrate → substrate}/edge-index.ts +28 -9
  467. package/src/plugins/defaults/memory/{v3/substrate → substrate}/frontmatter-sweep.ts +14 -7
  468. package/src/plugins/defaults/memory/{v3/substrate → substrate}/injected-block-slugs.ts +9 -3
  469. package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-index.ts +29 -10
  470. package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-store.ts +35 -12
  471. package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/consolidation.ts +14 -8
  472. package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/sweep.ts +4 -1
  473. package/src/plugins/defaults/memory/{v3/substrate → substrate}/qdrant.ts +96 -36
  474. package/src/plugins/defaults/memory/substrate/reembed-job.ts +54 -0
  475. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sim.ts +26 -15
  476. package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-content.ts +1 -1
  477. package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-store.ts +13 -8
  478. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sparse-bm25.ts +27 -10
  479. package/src/plugins/defaults/memory/substrate/spread.ts +165 -0
  480. package/src/plugins/defaults/memory/{v3/substrate → substrate}/static-context.ts +12 -7
  481. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sweep-job.ts +20 -15
  482. package/src/plugins/defaults/memory/substrate/tuning.ts +93 -0
  483. package/src/plugins/defaults/memory/{v3/substrate → substrate}/types.ts +7 -4
  484. package/src/plugins/defaults/memory/tools.test.ts +1 -1
  485. package/src/plugins/defaults/memory/tools.ts +1 -1
  486. package/src/plugins/defaults/memory/v1/README.md +5 -0
  487. package/src/plugins/defaults/memory/{__tests__ → v1/__tests__}/filing-jobs.test.ts +4 -4
  488. package/src/plugins/defaults/memory/{filing-jobs.ts → v1/filing-jobs.ts} +3 -3
  489. package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.test.ts +68 -6
  490. package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.ts +40 -21
  491. package/src/plugins/defaults/memory/{graph → v1/graph}/consolidation.ts +14 -14
  492. package/src/plugins/defaults/memory/{graph → v1/graph}/decay.test.ts +1 -1
  493. package/src/plugins/defaults/memory/{graph → v1/graph}/decay.ts +3 -3
  494. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction-job.ts +5 -5
  495. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.test.ts +1 -1
  496. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.ts +20 -14
  497. package/src/plugins/defaults/memory/{graph → v1/graph}/graph-search.test.ts +3 -3
  498. package/src/plugins/defaults/memory/v1/graph/graph-search.ts +123 -0
  499. package/src/plugins/defaults/memory/{graph → v1/graph}/injection.test.ts +1 -118
  500. package/src/plugins/defaults/memory/{graph → v1/graph}/injection.ts +9 -111
  501. package/src/plugins/defaults/memory/{graph → v1/graph}/narrative.ts +6 -6
  502. package/src/plugins/defaults/memory/{graph → v1/graph}/pattern-scan.ts +5 -5
  503. package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.test.ts +135 -42
  504. package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.ts +40 -22
  505. package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.test.ts +1 -1
  506. package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.ts +1 -1
  507. package/src/plugins/defaults/memory/{graph → v1/graph}/serendipity.ts +1 -1
  508. package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.test.ts +1 -1
  509. package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.ts +1 -1
  510. package/src/plugins/defaults/memory/{identity-context.ts → v1/identity-context.ts} +4 -4
  511. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/backfill.ts +6 -6
  512. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.test.ts +6 -6
  513. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.ts +6 -6
  514. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/index-maintenance.ts +8 -8
  515. package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.test.ts +7 -7
  516. package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.ts +5 -5
  517. package/src/plugins/defaults/memory/{pkb → v1/pkb}/autoinject.ts +1 -1
  518. package/src/plugins/defaults/memory/{pkb → v1/pkb}/context.ts +2 -2
  519. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.test.ts +3 -3
  520. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.ts +2 -2
  521. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.test.ts +3 -3
  522. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.ts +2 -2
  523. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.test.ts +3 -3
  524. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.ts +6 -6
  525. package/src/plugins/defaults/memory/{pkb → v1/pkb}/types.ts +3 -5
  526. package/src/plugins/defaults/memory/{pkb-schedule.ts → v1/pkb-schedule.ts} +2 -2
  527. package/src/plugins/defaults/memory/{search/semantic.ts → v1/semantic-search.ts} +1 -1
  528. package/src/plugins/defaults/memory/v2/__tests__/activation-store.test.ts +1 -1
  529. package/src/plugins/defaults/memory/v2/__tests__/activation.test.ts +11 -274
  530. package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +9 -131
  531. package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +1 -1
  532. package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +1 -1
  533. package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
  534. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +14 -10
  535. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +7 -5
  536. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +12 -6
  537. package/src/plugins/defaults/memory/{memory-v2-activation-log-store.ts → v2/activation-log-store.ts} +2 -2
  538. package/src/plugins/defaults/memory/v2/activation-store.ts +22 -8
  539. package/src/plugins/defaults/memory/v2/activation.ts +30 -163
  540. package/src/plugins/defaults/memory/v2/backfill-jobs.ts +7 -54
  541. package/src/plugins/defaults/memory/{memory-v2-concept-frequency.ts → v2/concept-frequency.ts} +3 -3
  542. package/src/plugins/defaults/memory/v2/harness/oracle.ts +1 -1
  543. package/src/plugins/defaults/memory/v2/harness/replay-input.ts +2 -2
  544. package/src/plugins/defaults/memory/v2/harness/retriever.ts +1 -1
  545. package/src/plugins/defaults/memory/v2/injection.ts +36 -26
  546. package/src/plugins/defaults/memory/v2/migration.ts +2 -2
  547. package/src/plugins/defaults/memory/{rerank-local.ts → v2/rerank-local.ts} +44 -18
  548. package/src/plugins/defaults/memory/v2/reranker.ts +29 -11
  549. package/src/plugins/defaults/memory/v2/router.ts +38 -15
  550. package/src/plugins/defaults/memory/v3/__tests__/candidate-match.test.ts +5 -3
  551. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +21 -8
  552. package/src/plugins/defaults/memory/v3/__tests__/edge.test.ts +1 -1
  553. package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +1 -1
  554. package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +4 -1
  555. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +181 -3
  556. package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +3 -0
  557. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +14 -5
  558. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +40 -50
  559. package/src/plugins/defaults/memory/v3/__tests__/tuning-profile.test.ts +1 -0
  560. package/src/plugins/defaults/memory/v3/candidate-match.ts +2 -2
  561. package/src/plugins/defaults/memory/v3/capabilities.ts +6 -4
  562. package/src/plugins/defaults/memory/v3/card.ts +25 -9
  563. package/src/plugins/defaults/memory/v3/edge.ts +52 -18
  564. package/src/plugins/defaults/memory/v3/gate.ts +4 -4
  565. package/src/plugins/defaults/memory/v3/injector.ts +10 -3
  566. package/src/plugins/defaults/memory/v3/maintain-job.ts +3 -3
  567. package/src/plugins/defaults/memory/v3/orchestrate.ts +100 -18
  568. package/src/plugins/defaults/memory/v3/page-content.ts +26 -10
  569. package/src/plugins/defaults/memory/v3/prune.ts +40 -16
  570. package/src/plugins/defaults/memory/v3/selection-log-store.ts +34 -12
  571. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +9 -13
  572. package/src/plugins/defaults/memory/v3/span-query.test.ts +86 -0
  573. package/src/plugins/defaults/memory/v3/span-query.ts +71 -0
  574. package/src/plugins/defaults/memory/v3/tuning-profile.ts +3 -0
  575. package/src/plugins/defaults/memory/v3/types.ts +4 -1
  576. package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +2 -2
  577. package/src/plugins/defaults/memory/validation.ts +1 -1
  578. package/src/plugins/defaults/memory/worker.ts +2 -1
  579. package/src/plugins/defaults/platform-hosted/__tests__/reengage.test.ts +104 -12
  580. package/src/plugins/defaults/platform-hosted/routes/reengage.ts +104 -12
  581. package/src/plugins/types.ts +2 -2
  582. package/src/providers/__tests__/registry-native-web-search.test.ts +47 -2
  583. package/src/providers/anthropic/client.ts +15 -6
  584. package/src/providers/content-block-schema.ts +26 -0
  585. package/src/providers/inference/__tests__/connections-credential-normalize.test.ts +87 -0
  586. package/src/providers/inference/adapter-factory.ts +6 -0
  587. package/src/providers/inference/connections.ts +30 -14
  588. package/src/providers/model-catalog.ts +77 -0
  589. package/src/providers/openai/__tests__/chat-completions-input-audio.test.ts +260 -0
  590. package/src/providers/openai/chat-completions-provider.ts +65 -17
  591. package/src/providers/openai/input-audio.ts +76 -0
  592. package/src/providers/openrouter/client.ts +0 -2
  593. package/src/providers/platform-proxy/constants.ts +4 -0
  594. package/src/providers/poolside/client.ts +42 -0
  595. package/src/providers/registry.ts +40 -8
  596. package/src/providers/retry.ts +2 -0
  597. package/src/providers/types.ts +39 -1
  598. package/src/providers/vercel-ai-gateway/client.ts +0 -2
  599. package/src/runtime/AGENTS.md +7 -5
  600. package/src/runtime/__tests__/question-request-guardian-bridge.test.ts +173 -0
  601. package/src/runtime/__tests__/question-resolution.test.ts +111 -0
  602. package/src/runtime/access-request-helper.ts +7 -15
  603. package/src/runtime/assistant-event-hub.ts +43 -31
  604. package/src/runtime/assistant-event-publish-options.ts +31 -0
  605. package/src/runtime/assistant-event.ts +19 -30
  606. package/src/runtime/assistant-stream-state.ts +4 -4
  607. package/src/runtime/channel-approvals.ts +0 -25
  608. package/src/runtime/channel-readiness-service.ts +99 -40
  609. package/src/runtime/channel-retry-sweep.ts +38 -15
  610. package/src/runtime/confirmation-request-guardian-bridge.ts +4 -0
  611. package/src/runtime/guardian-reply-router.ts +108 -0
  612. package/src/runtime/http-server.ts +8 -0
  613. package/src/runtime/http-types.ts +2 -2
  614. package/src/runtime/process-role.ts +42 -0
  615. package/src/runtime/question-request-guardian-bridge.ts +184 -0
  616. package/src/runtime/question-resolution.ts +153 -0
  617. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +6 -2
  618. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -1
  619. package/src/runtime/routes/acp-routes.ts +2 -2
  620. package/src/runtime/routes/bookmark-routes.ts +3 -15
  621. package/src/runtime/routes/canned-message-complete.ts +2 -2
  622. package/src/runtime/routes/consolidation-routes.ts +8 -2
  623. package/src/runtime/routes/conversation-list-routes.ts +3 -19
  624. package/src/runtime/routes/conversation-management-routes.ts +1 -5
  625. package/src/runtime/routes/conversation-query-routes.ts +52 -8
  626. package/src/runtime/routes/conversation-routes.ts +36 -22
  627. package/src/runtime/routes/credential-request-routes.ts +0 -1
  628. package/src/runtime/routes/filing-routes.ts +7 -7
  629. package/src/runtime/routes/global-search-routes.ts +1 -1
  630. package/src/runtime/routes/guardian-approval-prompt.ts +2 -2
  631. package/src/runtime/routes/image-generation-routes.ts +12 -9
  632. package/src/runtime/routes/inbound-message-handler.ts +17 -0
  633. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +50 -0
  634. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +19 -0
  635. package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -4
  636. package/src/runtime/routes/inbound-stages/inbound-content-prep.test.ts +129 -0
  637. package/src/runtime/routes/inbound-stages/inbound-content-prep.ts +141 -9
  638. package/src/runtime/routes/index.ts +2 -0
  639. package/src/runtime/routes/lifecycle-routes.ts +199 -0
  640. package/src/runtime/routes/platform-routes.ts +3 -8
  641. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +7 -7
  642. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +5 -5
  643. package/src/runtime/routes/question-routes.ts +34 -87
  644. package/src/runtime/routes/secret-routes.ts +11 -1
  645. package/src/runtime/routes/settings-routes.ts +8 -18
  646. package/src/runtime/routes/upgrade-broadcast-routes.ts +4 -5
  647. package/src/runtime/routes/workspace-routes.test.ts +7 -4
  648. package/src/runtime/slack-reply-session.test.ts +12 -12
  649. package/src/runtime/slack-reply-session.ts +17 -17
  650. package/src/runtime/sync/sync-publisher.test.ts +7 -5
  651. package/src/runtime/tool-grant-request-helper.ts +4 -0
  652. package/src/schedule/schedule-store.ts +70 -0
  653. package/src/schedule/scheduler.ts +27 -0
  654. package/src/security/AGENTS.md +1 -1
  655. package/src/security/credential-key.ts +17 -0
  656. package/src/security/secret-ingress.ts +14 -105
  657. package/src/security/secret-patterns.ts +8 -139
  658. package/src/security/secret-scanner.ts +8 -3
  659. package/src/security/store-path-override.ts +6 -16
  660. package/src/sequence/store.ts +8 -0
  661. package/src/signals/emit-event.ts +5 -10
  662. package/src/signals/event-stream.ts +20 -10
  663. package/src/subagent/manager.ts +76 -25
  664. package/src/subagent/notify.ts +8 -0
  665. package/src/subagent/types.ts +13 -3
  666. package/src/telegram/__tests__/webhook-health.test.ts +442 -0
  667. package/src/telegram/webhook-health.ts +478 -0
  668. package/src/telemetry/AGENTS.md +6 -0
  669. package/src/telemetry/memory-corpus-size.test.ts +129 -0
  670. package/src/telemetry/memory-corpus-size.ts +184 -0
  671. package/src/telemetry/memory-tier-reporter.test.ts +67 -2
  672. package/src/telemetry/memory-tier-reporter.ts +30 -3
  673. package/src/tools/__tests__/document-tool-input-schemas.test.ts +103 -0
  674. package/src/tools/__tests__/followup-call-acp-tool-input-schemas.test.ts +125 -0
  675. package/src/tools/__tests__/schedule-tool-input-schemas.test.ts +83 -0
  676. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +116 -0
  677. package/src/tools/__tests__/tool-input-schemas.test.ts +192 -0
  678. package/src/tools/__tests__/tool-schema-drift-harness.ts +142 -0
  679. package/src/tools/acp/abort.ts +21 -1
  680. package/src/tools/acp/context.ts +5 -5
  681. package/src/tools/acp/spawn.test.ts +15 -5
  682. package/src/tools/acp/spawn.ts +26 -3
  683. package/src/tools/acp/status.ts +20 -1
  684. package/src/tools/acp/steer.test.ts +20 -0
  685. package/src/tools/acp/steer.ts +23 -2
  686. package/src/tools/ask-question/ask-question-tool.test.ts +65 -0
  687. package/src/tools/ask-question/ask-question-tool.ts +68 -92
  688. package/src/tools/browser/browser-screencast.ts +6 -6
  689. package/src/tools/calls/call-end.ts +24 -3
  690. package/src/tools/calls/call-start.ts +35 -11
  691. package/src/tools/calls/call-status.ts +20 -1
  692. package/src/tools/document/document-comment-tool.test.ts +49 -0
  693. package/src/tools/document/document-comment-tool.ts +45 -6
  694. package/src/tools/document/document-tool.ts +142 -24
  695. package/src/tools/executor.ts +27 -13
  696. package/src/tools/filesystem/edit.ts +62 -60
  697. package/src/tools/filesystem/list.ts +36 -29
  698. package/src/tools/filesystem/read.ts +56 -39
  699. package/src/tools/filesystem/write.ts +44 -38
  700. package/src/tools/followups/followup_create.ts +41 -12
  701. package/src/tools/followups/followup_list.ts +34 -6
  702. package/src/tools/followups/followup_resolve.ts +26 -4
  703. package/src/tools/host-filesystem/edit.ts +50 -60
  704. package/src/tools/host-filesystem/read.ts +45 -39
  705. package/src/tools/host-filesystem/write.ts +31 -36
  706. package/src/tools/host-terminal/host-shell.ts +76 -62
  707. package/src/tools/policy-context.ts +27 -10
  708. package/src/tools/schedule/create.ts +76 -33
  709. package/src/tools/schedule/delete.ts +21 -2
  710. package/src/tools/schedule/list.ts +25 -3
  711. package/src/tools/schedule/update.ts +105 -48
  712. package/src/tools/shared/filesystem/path-policy.ts +246 -40
  713. package/src/tools/shared/zod-tool-schema.ts +117 -0
  714. package/src/tools/subagent/abort.ts +12 -4
  715. package/src/tools/subagent/consult-deadline.ts +9 -3
  716. package/src/tools/subagent/message.ts +21 -5
  717. package/src/tools/subagent/notify-parent.ts +44 -23
  718. package/src/tools/subagent/read.ts +15 -4
  719. package/src/tools/subagent/resolve.ts +26 -4
  720. package/src/tools/subagent/spawn.ts +37 -13
  721. package/src/tools/subagent/status.ts +12 -4
  722. package/src/tools/system/request-permission.ts +35 -26
  723. package/src/tools/terminal/shell.ts +68 -55
  724. package/src/tools/tool-approval-handler.ts +327 -53
  725. package/src/tools/tool-input-schemas.ts +85 -0
  726. package/src/tools/tool-types.ts +7 -0
  727. package/src/tools/types.ts +8 -0
  728. package/src/tools/workflows/manage-workflows.ts +30 -2
  729. package/src/tools/workflows/run-workflow.test.ts +54 -2
  730. package/src/tools/workflows/run-workflow.ts +32 -4
  731. package/src/util/fs-symlinks.ts +30 -0
  732. package/src/util/log-redact.ts +7 -3
  733. package/src/vellum-assistant-namespace.d.ts +80 -0
  734. package/src/watcher/watcher-store.ts +8 -0
  735. package/src/workflows/leaf-runner.test.ts +104 -2
  736. package/src/workflows/leaf-runner.ts +31 -6
  737. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +2 -2
  738. package/src/workspace/migrations/134-image-generation-mode-to-provider.ts +128 -0
  739. package/src/workspace/migrations/135-copy-substrate-tunables.ts +248 -0
  740. package/src/workspace/migrations/__tests__/135-copy-substrate-tunables.test.ts +446 -0
  741. package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +2 -2
  742. package/src/workspace/migrations/registry.ts +4 -0
  743. package/src/__tests__/memory-retrieval-budget.test.ts +0 -49
  744. package/src/__tests__/secret-patterns.test.ts +0 -27
  745. package/src/config/__tests__/proc-to-skills.test.ts +0 -21
  746. package/src/config/memory-tier.test.ts +0 -44
  747. package/src/daemon/message-types/acp.ts +0 -20
  748. package/src/daemon/message-types/apps.ts +0 -11
  749. package/src/daemon/message-types/background-tools.ts +0 -14
  750. package/src/daemon/message-types/bookmarks.ts +0 -13
  751. package/src/daemon/message-types/contacts.ts +0 -13
  752. package/src/daemon/message-types/document-comments.ts +0 -14
  753. package/src/daemon/message-types/documents.ts +0 -13
  754. package/src/daemon/message-types/home.ts +0 -15
  755. package/src/daemon/message-types/host-bash.ts +0 -12
  756. package/src/daemon/message-types/host-cu.ts +0 -10
  757. package/src/daemon/message-types/host-file.ts +0 -12
  758. package/src/daemon/message-types/host-transfer.ts +0 -12
  759. package/src/daemon/message-types/integrations.ts +0 -90
  760. package/src/daemon/message-types/memory.ts +0 -10
  761. package/src/daemon/message-types/schedules.ts +0 -14
  762. package/src/daemon/message-types/settings.ts +0 -17
  763. package/src/daemon/message-types/subagents.ts +0 -63
  764. package/src/daemon/message-types/upgrades.ts +0 -14
  765. package/src/daemon/message-types/workflows.ts +0 -25
  766. package/src/daemon/message-types/workspace.ts +0 -137
  767. package/src/live-voice/ack-phrases.ts +0 -58
  768. package/src/plugins/defaults/memory/retrieval-budget.ts +0 -29
  769. package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +0 -69
  770. package/src/plugins/defaults/memory/v3/gate-flag.ts +0 -20
  771. package/src/plugins/defaults/memory/v3/substrate/__tests__/memory-v2-startup.test.ts +0 -86
  772. package/src/plugins/defaults/memory/v3/substrate/memory-v2-startup.test.ts +0 -205
  773. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/concept-page-frontmatter-schema.test.ts +0 -0
  774. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-prompt-flag-gating-guard.test.ts +0 -0
  775. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/injected-block-slugs.test.ts +0 -0
  776. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-content.ts +0 -0
@@ -0,0 +1,248 @@
1
+ import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import { getLogger } from "../../util/logger.js";
5
+ import type { WorkspaceMigration } from "./types.js";
6
+
7
+ const log = getLogger("workspace-migration-135");
8
+
9
+ /**
10
+ * Marks the two optional `memory.v2` keys that ship with no schema default
11
+ * (`min_sparse_spread`, `full_sparse_spread`) — for those, raw presence IS
12
+ * user intent, so they copy on presence alone.
13
+ */
14
+ const NO_DEFAULT: unique symbol = Symbol("no-default");
15
+
16
+ /**
17
+ * The fifteen substrate tunables shared between the historical `memory.v2`
18
+ * namespace and the new `memory.substrate` namespace, each paired with the
19
+ * shipped `memory.v2` schema default (from `config/schemas/memory-v2.ts`).
20
+ * `memory.v2.k` and `memory.v2.hops` were renamed to `spread_k` /
21
+ * `spread_hops` on the substrate side; every other key keeps its name.
22
+ *
23
+ * The defaults matter because raw presence in config.json is NOT user intent:
24
+ * the config loader serializes the fully-parsed configuration for
25
+ * normally-created workspaces, so defaulted `memory.v2` leaves are persisted
26
+ * for most existing assistants. Copying those seeded values would populate
27
+ * the override-only `memory.substrate` namespace with today's defaults and
28
+ * permanently pin those assistants when substrate defaults are later retuned
29
+ * — the same default-pinning problem migration 119 solves for `memory.v3`
30
+ * tuning, distinguished the same way (value-vs-shipped-default comparison,
31
+ * table inlined per the migrations self-containment rule).
32
+ */
33
+ const SUBSTRATE_KEY_PAIRS: ReadonlyArray<{
34
+ v2Key: string;
35
+ substrateKey: string;
36
+ shippedDefault: number | boolean | string | null | typeof NO_DEFAULT;
37
+ /**
38
+ * Additional values the loader has seeded as this key's default in earlier
39
+ * releases (multi-default keys, mirroring migration 119). A persisted value
40
+ * matching any of them is seeded, not a user override.
41
+ */
42
+ priorDefaults?: ReadonlyArray<number | boolean | string | null>;
43
+ }> = [
44
+ {
45
+ v2Key: "sweep_enabled",
46
+ substrateKey: "sweep_enabled",
47
+ shippedDefault: false,
48
+ },
49
+ { v2Key: "dense_weight", substrateKey: "dense_weight", shippedDefault: 0.85 },
50
+ {
51
+ v2Key: "sparse_weight",
52
+ substrateKey: "sparse_weight",
53
+ shippedDefault: 0.15,
54
+ },
55
+ {
56
+ v2Key: "min_sparse_spread",
57
+ substrateKey: "min_sparse_spread",
58
+ shippedDefault: NO_DEFAULT,
59
+ },
60
+ {
61
+ v2Key: "full_sparse_spread",
62
+ substrateKey: "full_sparse_spread",
63
+ shippedDefault: NO_DEFAULT,
64
+ },
65
+ { v2Key: "bm25_k1", substrateKey: "bm25_k1", shippedDefault: 1.2 },
66
+ {
67
+ v2Key: "bm25_b",
68
+ substrateKey: "bm25_b",
69
+ shippedDefault: 0.4,
70
+ // Workspaces seeded before migration 075 carry the earlier 0.75 default.
71
+ priorDefaults: [0.75],
72
+ },
73
+ {
74
+ v2Key: "consolidation_interval_hours",
75
+ substrateKey: "consolidation_interval_hours",
76
+ shippedDefault: 8,
77
+ },
78
+ {
79
+ v2Key: "consolidation_max_buffer_lines",
80
+ substrateKey: "consolidation_max_buffer_lines",
81
+ shippedDefault: 100,
82
+ },
83
+ {
84
+ v2Key: "consolidation_max_entries_per_run",
85
+ substrateKey: "consolidation_max_entries_per_run",
86
+ shippedDefault: 150,
87
+ },
88
+ {
89
+ v2Key: "max_page_chars",
90
+ substrateKey: "max_page_chars",
91
+ shippedDefault: 5000,
92
+ },
93
+ {
94
+ v2Key: "consolidation_prompt_path",
95
+ substrateKey: "consolidation_prompt_path",
96
+ shippedDefault: null,
97
+ },
98
+ { v2Key: "k", substrateKey: "spread_k", shippedDefault: 0.5 },
99
+ { v2Key: "hops", substrateKey: "spread_hops", shippedDefault: 2 },
100
+ {
101
+ v2Key: "ann_candidate_limit",
102
+ substrateKey: "ann_candidate_limit",
103
+ shippedDefault: null,
104
+ },
105
+ ];
106
+
107
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
108
+ return value != null && typeof value === "object" && !Array.isArray(value);
109
+ }
110
+
111
+ /**
112
+ * Copy user-overridden substrate tunables from `memory.v2` to
113
+ * `memory.substrate` so the substrate namespace carries the user's tuned
114
+ * values itself, independent of the runtime resolver's substrate→v2 fallback.
115
+ *
116
+ * Value-based, not presence-based: a key is copied only when it is present
117
+ * under `memory.v2`, absent under `memory.substrate`, AND its value differs
118
+ * from the shipped v2 schema default. The config loader persists the
119
+ * fully-parsed configuration for normally-created workspaces, so a defaulted
120
+ * `memory.v2` leaf in config.json is seeded, not user intent — copying it
121
+ * would pin the assistant to today's value when substrate defaults are later
122
+ * retuned (migration 119's rationale). A persisted value equal to its shipped
123
+ * default is treated as seeded even if a user typed it deliberately — the
124
+ * acceptable trade-off 119 already makes — so `memory.substrate` stays an
125
+ * override-only surface. The two no-default keys (`min_sparse_spread`,
126
+ * `full_sparse_spread`) copy on presence alone.
127
+ *
128
+ * That rule is narrower than "explicitly present", and the gap is deliberate:
129
+ * a value equal to a shipped default never copies, even when the user typed it
130
+ * on purpose. For every key whose shipped default is the current one that costs
131
+ * nothing — `memory.substrate` plus the shipped defaults resolve to exactly
132
+ * what the resolver's fallback produces. `bm25_b`'s retired `0.75` is the sole
133
+ * exception: it is skipped as seeded yet differs from today's `0.4`, so on a
134
+ * workspace carrying it the value survives only through the resolver's
135
+ * `memory.v2` fallback. That is the one case where dropping the fallback would
136
+ * change behavior — see the equivalence proof in this migration's test.
137
+ *
138
+ * `memory.v2.*` is never modified — the v2 injection engine still reads it.
139
+ * An already-present `memory.substrate` key is never clobbered. `memory.substrate` is only
140
+ * written at all when at least one key copies, so a fresh config never gains
141
+ * an empty object.
142
+ *
143
+ * Weight-pair safety: copying cannot create an invalid config. The v2
144
+ * schema's own refinement validates `dense_weight + sparse_weight` on the
145
+ * PERSISTED values (absent leaves resolve to defaults before the check), so a
146
+ * valid config carrying a non-default weight necessarily carries its
147
+ * non-default twin — both differ from their defaults, both copy, and the
148
+ * copied substrate pair is exactly the pair v2 already accepted.
149
+ */
150
+ export const copySubstrateTunablesMigration: WorkspaceMigration = {
151
+ id: "135-copy-substrate-tunables",
152
+ description:
153
+ "Copy memory.v2 substrate tunables that differ from their shipped defaults to memory.substrate (k→spread_k, hops→spread_hops) without touching memory.v2, clobbering existing memory.substrate values, or pinning loader-seeded defaults",
154
+ // run() only ever adds missing memory.substrate keys and never clobbers
155
+ // present ones, so retrying after a failed write attempt is safe.
156
+ retryFailedCheckpoint: true,
157
+
158
+ run(workspaceDir: string): void {
159
+ const configPath = join(workspaceDir, "config.json");
160
+ if (!existsSync(configPath)) {
161
+ return;
162
+ }
163
+
164
+ // A filesystem read failure propagates so the failed checkpoint retries
165
+ // on the next boot; only malformed JSON is a permanent no-op (the config
166
+ // loader owns surfacing that error).
167
+ const rawText = readFileSync(configPath, "utf-8");
168
+ let config: Record<string, unknown>;
169
+ try {
170
+ const raw = JSON.parse(rawText);
171
+ if (!isPlainObject(raw)) {
172
+ return;
173
+ }
174
+ config = raw;
175
+ } catch {
176
+ return;
177
+ }
178
+
179
+ const memory = config.memory;
180
+ if (!isPlainObject(memory)) {
181
+ return;
182
+ }
183
+ const v2 = memory.v2;
184
+ if (!isPlainObject(v2)) {
185
+ return;
186
+ }
187
+ // A malformed (non-object) persisted memory.substrate is left alone — the
188
+ // config loader surfaces that error; this migration must not clobber it.
189
+ if (memory.substrate !== undefined && !isPlainObject(memory.substrate)) {
190
+ return;
191
+ }
192
+
193
+ // Staged separately so memory.substrate is only attached when a key
194
+ // actually copies — never introduce an empty object.
195
+ const substrate: Record<string, unknown> = isPlainObject(memory.substrate)
196
+ ? memory.substrate
197
+ : {};
198
+
199
+ let copied = false;
200
+ for (const {
201
+ v2Key,
202
+ substrateKey,
203
+ shippedDefault,
204
+ priorDefaults,
205
+ } of SUBSTRATE_KEY_PAIRS) {
206
+ if (!(v2Key in v2) || substrateKey in substrate) {
207
+ continue;
208
+ }
209
+ // A persisted value equal to a shipped default (current or from an
210
+ // earlier release) is loader-seeded, not a user override — skip it so
211
+ // the substrate namespace stays override-only. Strict equality
212
+ // suffices: every tunable value is a primitive or null.
213
+ const value = v2[v2Key];
214
+ if (shippedDefault !== NO_DEFAULT && value === shippedDefault) {
215
+ continue;
216
+ }
217
+ if (priorDefaults?.some((seeded) => seeded === value)) {
218
+ continue;
219
+ }
220
+ substrate[substrateKey] = v2[v2Key];
221
+ copied = true;
222
+ }
223
+ if (!copied) {
224
+ return;
225
+ }
226
+ memory.substrate = substrate;
227
+
228
+ // Write-then-rename keeps the migration rerunnable: a crash mid-write
229
+ // must not leave a truncated config.json that a retry reads as malformed
230
+ // and "completes" past, stranding the user's v2 overrides. A write or
231
+ // rename failure propagates to the runner, which checkpoints this
232
+ // migration as failed and (via retryFailedCheckpoint) retries it on the
233
+ // next boot instead of recording it as completed.
234
+ const tmpPath = `${configPath}.tmp`;
235
+ writeFileSync(tmpPath, JSON.stringify(config, null, 2) + "\n");
236
+ renameSync(tmpPath, configPath);
237
+ log.info(
238
+ "Copied non-default memory.v2 substrate tunables to memory.substrate",
239
+ );
240
+ },
241
+
242
+ down(_workspaceDir: string): void {
243
+ // Forward-only: a copied value is indistinguishable from one the user set
244
+ // under memory.substrate directly, so removal could destroy deliberate
245
+ // overrides. The copy is also behavior-preserving, so there is nothing to
246
+ // unwind.
247
+ },
248
+ };
@@ -0,0 +1,446 @@
1
+ import {
2
+ chmodSync,
3
+ existsSync,
4
+ mkdtempSync,
5
+ readFileSync,
6
+ rmSync,
7
+ writeFileSync,
8
+ } from "node:fs";
9
+ import { tmpdir } from "node:os";
10
+ import { join } from "node:path";
11
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
12
+
13
+ import { MemoryConfigSchema } from "../../../config/schemas/memory.js";
14
+ import { MemoryV2ConfigSchema } from "../../../config/schemas/memory-v2.js";
15
+ import {
16
+ resolveSubstrateTuning,
17
+ type SubstrateTuning,
18
+ } from "../../../plugins/defaults/memory/substrate/tuning.js";
19
+ import { copySubstrateTunablesMigration as MIG } from "../135-copy-substrate-tunables.js";
20
+
21
+ let workspaceDir: string;
22
+ let configPath: string;
23
+
24
+ /** The shipped `memory.v2` defaults, i.e. the effective value of an unset key. */
25
+ const V2_SCHEMA_DEFAULTS = MemoryV2ConfigSchema.parse({});
26
+
27
+ function pick<T>(
28
+ substrate: Record<string, unknown>,
29
+ key: string,
30
+ fallback: T,
31
+ ): T {
32
+ // Presence, not truthiness: `resolveSubstrateTuning` falls back only on
33
+ // `undefined`, so an explicit `null` counts as set.
34
+ return key in substrate ? (substrate[key] as T) : fallback;
35
+ }
36
+
37
+ /**
38
+ * `resolveSubstrateTuning` with the `memory.v2` fallback stripped: every
39
+ * tunable resolves from `memory.substrate` alone, or from the shipped v2
40
+ * schema default when the substrate key is absent.
41
+ *
42
+ * Migration 135's whole purpose is to make this resolver agree with the real
43
+ * one on a migrated workspace — that agreement is what lets the fallback be
44
+ * removed later without changing anyone's behavior.
45
+ */
46
+ function resolveSubstrateOnly(
47
+ substrate: Record<string, unknown>,
48
+ ): SubstrateTuning {
49
+ const d = V2_SCHEMA_DEFAULTS;
50
+ return {
51
+ sweep_enabled: pick(substrate, "sweep_enabled", d.sweep_enabled),
52
+ dense_weight: pick(substrate, "dense_weight", d.dense_weight),
53
+ sparse_weight: pick(substrate, "sparse_weight", d.sparse_weight),
54
+ min_sparse_spread: pick(
55
+ substrate,
56
+ "min_sparse_spread",
57
+ d.min_sparse_spread,
58
+ ),
59
+ full_sparse_spread: pick(
60
+ substrate,
61
+ "full_sparse_spread",
62
+ d.full_sparse_spread,
63
+ ),
64
+ bm25_k1: pick(substrate, "bm25_k1", d.bm25_k1),
65
+ bm25_b: pick(substrate, "bm25_b", d.bm25_b),
66
+ consolidation_interval_hours: pick(
67
+ substrate,
68
+ "consolidation_interval_hours",
69
+ d.consolidation_interval_hours,
70
+ ),
71
+ consolidation_max_buffer_lines: pick(
72
+ substrate,
73
+ "consolidation_max_buffer_lines",
74
+ d.consolidation_max_buffer_lines,
75
+ ),
76
+ consolidation_max_entries_per_run: pick(
77
+ substrate,
78
+ "consolidation_max_entries_per_run",
79
+ d.consolidation_max_entries_per_run,
80
+ ),
81
+ max_page_chars: pick(substrate, "max_page_chars", d.max_page_chars),
82
+ consolidation_prompt_path: pick(
83
+ substrate,
84
+ "consolidation_prompt_path",
85
+ d.consolidation_prompt_path,
86
+ ),
87
+ spread_k: pick(substrate, "spread_k", d.k),
88
+ spread_hops: pick(substrate, "spread_hops", d.hops),
89
+ ann_candidate_limit: pick(
90
+ substrate,
91
+ "ann_candidate_limit",
92
+ d.ann_candidate_limit,
93
+ ),
94
+ };
95
+ }
96
+
97
+ function write(obj: unknown): void {
98
+ writeFileSync(configPath, JSON.stringify(obj, null, 2) + "\n");
99
+ }
100
+ function readRaw(): string {
101
+ return readFileSync(configPath, "utf-8");
102
+ }
103
+ function read(): Record<string, unknown> {
104
+ return JSON.parse(readRaw());
105
+ }
106
+ function memory(): Record<string, unknown> {
107
+ return read().memory as Record<string, unknown>;
108
+ }
109
+
110
+ beforeEach(() => {
111
+ workspaceDir = mkdtempSync(join(tmpdir(), "copy-substrate-tunables-"));
112
+ configPath = join(workspaceDir, "config.json");
113
+ });
114
+ afterEach(() => {
115
+ rmSync(workspaceDir, { recursive: true, force: true });
116
+ });
117
+
118
+ describe("135-copy-substrate-tunables", () => {
119
+ test("has the expected id", () => {
120
+ expect(MIG.id).toBe("135-copy-substrate-tunables");
121
+ });
122
+
123
+ test("no-ops when config.json is absent, unparseable, or has no memory config", () => {
124
+ // Absent config.json.
125
+ expect(() => MIG.run(workspaceDir)).not.toThrow();
126
+
127
+ // Unparseable config.json is left byte-for-byte alone.
128
+ writeFileSync(configPath, "{not json");
129
+ MIG.run(workspaceDir);
130
+ expect(readRaw()).toBe("{not json");
131
+
132
+ // No memory config — fresh-workspace shape.
133
+ write({ llm: { provider: "anthropic" } });
134
+ const before = readRaw();
135
+ MIG.run(workspaceDir);
136
+ expect(readRaw()).toBe(before);
137
+
138
+ // memory present but no v2 subtree.
139
+ write({ memory: { enabled: true } });
140
+ const beforeNoV2 = readRaw();
141
+ MIG.run(workspaceDir);
142
+ expect(readRaw()).toBe(beforeNoV2);
143
+ });
144
+
145
+ test("never introduces memory.substrate when memory.v2 sets no substrate tunables", () => {
146
+ write({ memory: { v2: { enabled: true, hybrid_min_score: 0.02 } } });
147
+ const before = readRaw();
148
+
149
+ MIG.run(workspaceDir);
150
+
151
+ // Nothing copied → no write at all, so no empty substrate object appears.
152
+ expect(readRaw()).toBe(before);
153
+ });
154
+
155
+ test("copies an explicit memory.v2.consolidation_interval_hours, leaving memory.v2 untouched", () => {
156
+ write({
157
+ memory: {
158
+ v2: { enabled: true, consolidation_interval_hours: 6 },
159
+ },
160
+ });
161
+
162
+ MIG.run(workspaceDir);
163
+
164
+ expect(memory()).toEqual({
165
+ v2: { enabled: true, consolidation_interval_hours: 6 },
166
+ substrate: { consolidation_interval_hours: 6 },
167
+ });
168
+ // Temp-then-rename persistence leaves no temp file behind on success.
169
+ expect(existsSync(configPath + ".tmp")).toBe(false);
170
+ });
171
+
172
+ // Root bypasses file permission checks, so chmod cannot make the workspace
173
+ // read-only — skip rather than assert a failure path that cannot be
174
+ // exercised.
175
+ test.skipIf(process.getuid?.() === 0)(
176
+ "throws on a write failure, leaving config.json byte-for-byte intact (retryable via failed checkpoint)",
177
+ () => {
178
+ write({ memory: { v2: { bm25_b: 0.6 } } });
179
+ const before = readRaw();
180
+
181
+ // A read-only workspace dir blocks creation of the config.json.tmp
182
+ // staging file, standing in for any persistence failure.
183
+ chmodSync(workspaceDir, 0o555);
184
+ try {
185
+ expect(() => MIG.run(workspaceDir)).toThrow();
186
+ } finally {
187
+ chmodSync(workspaceDir, 0o755);
188
+ }
189
+
190
+ // The failure surfaces to the runner (failed checkpoint, not completed)
191
+ // and the migration opts into retrying that checkpoint on the next boot.
192
+ expect(MIG.retryFailedCheckpoint).toBe(true);
193
+ // config.json is untouched — the failed write targeted the temp file.
194
+ expect(readRaw()).toBe(before);
195
+ expect(existsSync(configPath + ".tmp")).toBe(false);
196
+
197
+ // The retry succeeds once the workspace is writable again.
198
+ MIG.run(workspaceDir);
199
+ expect(memory().substrate).toEqual({ bm25_b: 0.6 });
200
+ },
201
+ );
202
+
203
+ // Root bypasses file permission checks, so chmod 0o000 cannot make the
204
+ // file unreadable — skip rather than assert a failure path that cannot be
205
+ // exercised.
206
+ test.skipIf(process.getuid?.() === 0)(
207
+ "throws on a filesystem read failure so the failed checkpoint retries; malformed JSON stays a no-op",
208
+ () => {
209
+ write({ memory: { v2: { bm25_b: 0.6 } } });
210
+
211
+ // An unreadable config.json is a transient fs failure, not malformed
212
+ // content — it must surface to the runner instead of completing.
213
+ chmodSync(configPath, 0o000);
214
+ try {
215
+ expect(() => MIG.run(workspaceDir)).toThrow();
216
+ } finally {
217
+ chmodSync(configPath, 0o644);
218
+ }
219
+
220
+ // The retry succeeds once the file is readable again.
221
+ MIG.run(workspaceDir);
222
+ expect(memory().substrate).toEqual({ bm25_b: 0.6 });
223
+ },
224
+ );
225
+
226
+ test("renames k→spread_k and hops→spread_hops; a tuned bm25_b lands on the substrate key", () => {
227
+ write({
228
+ memory: {
229
+ v2: { k: 0.4, hops: 3, bm25_b: 0.6 },
230
+ },
231
+ });
232
+
233
+ MIG.run(workspaceDir);
234
+
235
+ expect(memory().substrate).toEqual({
236
+ spread_k: 0.4,
237
+ spread_hops: 3,
238
+ bm25_b: 0.6,
239
+ });
240
+ expect(memory().v2).toEqual({ k: 0.4, hops: 3, bm25_b: 0.6 });
241
+ });
242
+
243
+ test("a migrated workspace resolves identically with the v2 fallback stripped", () => {
244
+ // A normally-created workspace: loader-seeded defaults alongside real user
245
+ // overrides, including the two no-default spread keys and the nullable
246
+ // keys on both sides of the copy rule.
247
+ write({
248
+ memory: {
249
+ v2: {
250
+ enabled: true,
251
+ // Seeded defaults — the migration must leave these behind.
252
+ sweep_enabled: false,
253
+ dense_weight: 0.85,
254
+ sparse_weight: 0.15,
255
+ bm25_k1: 1.2,
256
+ consolidation_max_entries_per_run: 150,
257
+ consolidation_prompt_path: null,
258
+ hops: 2,
259
+ // User overrides — the migration must carry these across.
260
+ bm25_b: 0.6,
261
+ consolidation_interval_hours: 6,
262
+ consolidation_max_buffer_lines: null,
263
+ max_page_chars: 9000,
264
+ k: 0.4,
265
+ ann_candidate_limit: 500,
266
+ min_sparse_spread: 0.05,
267
+ full_sparse_spread: 0.3,
268
+ },
269
+ },
270
+ });
271
+
272
+ MIG.run(workspaceDir);
273
+
274
+ const parsed = MemoryConfigSchema.parse(memory());
275
+ const withFallback = resolveSubstrateTuning(parsed);
276
+ const substrateOnly = resolveSubstrateOnly(
277
+ memory().substrate as Record<string, unknown>,
278
+ );
279
+
280
+ // The load-bearing claim: after the copy, the substrate namespace plus the
281
+ // shipped defaults reproduce the resolver's substrate→v2 fallback exactly.
282
+ expect(substrateOnly).toEqual(withFallback);
283
+ // Anchored against the operator's actual intent, so the equality above
284
+ // cannot pass by both sides being wrong in the same way.
285
+ expect(withFallback.consolidation_interval_hours).toBe(6);
286
+ expect(withFallback.consolidation_max_buffer_lines).toBeNull();
287
+ expect(withFallback.spread_k).toBe(0.4);
288
+ expect(withFallback.spread_hops).toBe(2);
289
+ expect(withFallback.min_sparse_spread).toBe(0.05);
290
+ });
291
+
292
+ test("bm25_b at the historical 0.75 default is the one value the copy rule cannot carry", () => {
293
+ // The skip list treats 0.75 as loader-seeded, so it never reaches
294
+ // memory.substrate and only the fallback keeps it in effect. Recorded here
295
+ // because it is the single case where dropping the fallback would change
296
+ // behavior.
297
+ write({ memory: { v2: { bm25_b: 0.75 } } });
298
+
299
+ MIG.run(workspaceDir);
300
+
301
+ const parsed = MemoryConfigSchema.parse(memory());
302
+ expect(resolveSubstrateTuning(parsed).bm25_b).toBe(0.75);
303
+ expect(resolveSubstrateOnly({}).bm25_b).toBe(0.4);
304
+ });
305
+
306
+ test("never clobbers an already-set memory.substrate key, but still copies its unset siblings", () => {
307
+ write({
308
+ memory: {
309
+ v2: { bm25_b: 0.6, max_page_chars: 9000 },
310
+ substrate: { bm25_b: 0.3 },
311
+ },
312
+ });
313
+
314
+ MIG.run(workspaceDir);
315
+
316
+ expect(memory().substrate).toEqual({ bm25_b: 0.3, max_page_chars: 9000 });
317
+ expect(memory().v2).toEqual({ bm25_b: 0.6, max_page_chars: 9000 });
318
+ });
319
+
320
+ test("skips loader-seeded values equal to the shipped defaults, including null-default keys", () => {
321
+ // The config loader persists the fully-parsed config for normally-created
322
+ // workspaces, so every defaulted v2 leaf is present in config.json. None
323
+ // of these are user intent — the migration must not pin them into the
324
+ // override-only substrate namespace.
325
+ write({
326
+ memory: {
327
+ v2: {
328
+ enabled: true,
329
+ sweep_enabled: false,
330
+ dense_weight: 0.85,
331
+ sparse_weight: 0.15,
332
+ bm25_k1: 1.2,
333
+ bm25_b: 0.4,
334
+ consolidation_interval_hours: 8,
335
+ consolidation_max_buffer_lines: 100,
336
+ consolidation_max_entries_per_run: 150,
337
+ max_page_chars: 5000,
338
+ consolidation_prompt_path: null,
339
+ k: 0.5,
340
+ hops: 2,
341
+ ann_candidate_limit: null,
342
+ },
343
+ },
344
+ });
345
+ const before = readRaw();
346
+
347
+ MIG.run(workspaceDir);
348
+
349
+ // Nothing differs from a shipped default → no copy, no write at all.
350
+ expect(readRaw()).toBe(before);
351
+ });
352
+
353
+ test("copies non-default values on nullable keys but skips their seeded null defaults", () => {
354
+ write({
355
+ memory: {
356
+ v2: {
357
+ ann_candidate_limit: 500,
358
+ consolidation_prompt_path: null,
359
+ },
360
+ },
361
+ });
362
+
363
+ MIG.run(workspaceDir);
364
+
365
+ // 500 differs from the shipped null default and copies; the seeded null
366
+ // equals its default and stays out of the substrate namespace.
367
+ expect(memory().substrate).toEqual({ ann_candidate_limit: 500 });
368
+ });
369
+
370
+ test("skips bm25_b values seeded by the earlier 0.75 default (multi-default key)", () => {
371
+ write({
372
+ memory: {
373
+ v2: { bm25_b: 0.75, bm25_k1: 1.5 },
374
+ },
375
+ });
376
+
377
+ MIG.run(workspaceDir);
378
+
379
+ // 0.75 matches the pre-migration-075 shipped default and is seeded, not a
380
+ // user override; the tuned bm25_k1 still copies.
381
+ expect(memory().substrate).toEqual({ bm25_k1: 1.5 });
382
+ });
383
+
384
+ test("copies the no-default spread keys on presence alone", () => {
385
+ // min_sparse_spread / full_sparse_spread ship with no schema default, so
386
+ // the loader never seeds them — raw presence IS user intent.
387
+ write({
388
+ memory: {
389
+ v2: { min_sparse_spread: 0.05, full_sparse_spread: 0.3 },
390
+ },
391
+ });
392
+
393
+ MIG.run(workspaceDir);
394
+
395
+ expect(memory().substrate).toEqual({
396
+ min_sparse_spread: 0.05,
397
+ full_sparse_spread: 0.3,
398
+ });
399
+ });
400
+
401
+ test("a tuned weight pair copies whole and still parses after migration (resolved-pair weight check)", () => {
402
+ // The v2 refinement validates dense_weight + sparse_weight on the
403
+ // persisted values, so a valid config with a non-default dense_weight
404
+ // necessarily persists its non-default twin — both copy, and the copied
405
+ // substrate pair is exactly the pair v2 already accepted.
406
+ write({ memory: { v2: { dense_weight: 0.9, sparse_weight: 0.1 } } });
407
+
408
+ MIG.run(workspaceDir);
409
+
410
+ expect(memory().substrate).toEqual({
411
+ dense_weight: 0.9,
412
+ sparse_weight: 0.1,
413
+ });
414
+ expect(() => MemoryConfigSchema.parse(memory())).not.toThrow();
415
+ });
416
+
417
+ test("is idempotent — a second run leaves the file byte-for-byte unchanged", () => {
418
+ write({
419
+ memory: {
420
+ v2: { bm25_b: 0.6, k: 0.4, ann_candidate_limit: 500 },
421
+ substrate: { sweep_enabled: true },
422
+ },
423
+ });
424
+
425
+ MIG.run(workspaceDir);
426
+ const afterFirst = readRaw();
427
+ MIG.run(workspaceDir);
428
+
429
+ expect(readRaw()).toBe(afterFirst);
430
+ expect(memory().substrate).toEqual({
431
+ sweep_enabled: true,
432
+ bm25_b: 0.6,
433
+ spread_k: 0.4,
434
+ ann_candidate_limit: 500,
435
+ });
436
+ });
437
+
438
+ test("down() is a forward-only no-op", () => {
439
+ write({ memory: { v2: { bm25_b: 0.6 }, substrate: { bm25_b: 0.6 } } });
440
+ const before = readRaw();
441
+
442
+ expect(() => MIG.down(workspaceDir)).not.toThrow();
443
+
444
+ expect(readRaw()).toBe(before);
445
+ });
446
+ });
@@ -6,8 +6,8 @@ import { afterEach, beforeEach, describe, expect, it } from "bun:test";
6
6
  import {
7
7
  readPage,
8
8
  writePage,
9
- } from "../../../plugins/defaults/memory/v3/substrate/page-store.js";
10
- import type { ConceptPageFrontmatter } from "../../../plugins/defaults/memory/v3/substrate/types.js";
9
+ } from "../../../plugins/defaults/memory/substrate/page-store.js";
10
+ import type { ConceptPageFrontmatter } from "../../../plugins/defaults/memory/substrate/types.js";
11
11
  import { backfillV3LeavesMigration } from "../092-backfill-v3-leaves.js";
12
12
 
13
13
  describe("092 backfill v3 leaves", () => {