@vellumai/assistant 0.10.12 → 0.11.0-staging.2

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 (809) 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 +264 -14
  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__/app-conversation-ids-backfill.test.ts +33 -2
  39. package/src/__tests__/app-conversation-ids.test.ts +204 -0
  40. package/src/__tests__/approval-cascade.test.ts +5 -5
  41. package/src/__tests__/approval-routes-http.test.ts +3 -3
  42. package/src/__tests__/ask-question-resolver.test.ts +207 -0
  43. package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +16 -16
  44. package/src/__tests__/assistant-event-hub-targeted.test.ts +13 -11
  45. package/src/__tests__/assistant-event-hub.test.ts +13 -11
  46. package/src/__tests__/assistant-event.test.ts +12 -9
  47. package/src/__tests__/assistant-feature-flag-guard.test.ts +3 -3
  48. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +1 -1
  49. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -58
  50. package/src/__tests__/assistant-stream-state.test.ts +17 -7
  51. package/src/__tests__/avatar-identity-sync.test.ts +3 -3
  52. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
  53. package/src/__tests__/call-conversation-messages.test.ts +134 -18
  54. package/src/__tests__/call-start-guardian-guard.test.ts +27 -0
  55. package/src/__tests__/channel-approvals.test.ts +0 -27
  56. package/src/__tests__/channel-guardian.test.ts +85 -512
  57. package/src/__tests__/channel-readiness-slack-remote.test.ts +151 -3
  58. package/src/__tests__/channel-retry-sweep.test.ts +88 -1
  59. package/src/__tests__/channel-setup-panel-ack.test.ts +12 -9
  60. package/src/__tests__/chat-reveal-guard-priming.test.ts +31 -34
  61. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +2 -2
  62. package/src/__tests__/compaction-events.test.ts +8 -8
  63. package/src/__tests__/config-loader-platform-defaults.test.ts +54 -28
  64. package/src/__tests__/config-model-image-provider.test.ts +20 -0
  65. package/src/__tests__/config-schema-memory-substrate.test.ts +306 -0
  66. package/src/__tests__/config-schema.test.ts +14 -2
  67. package/src/__tests__/config-set-platform-guard.test.ts +11 -12
  68. package/src/__tests__/config-sounds-sync.test.ts +4 -4
  69. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +5 -0
  70. package/src/__tests__/context-search-memory-source.test.ts +1 -1
  71. package/src/__tests__/context-search-memory-v2-source.test.ts +6 -6
  72. package/src/__tests__/context-token-estimator.test.ts +54 -1
  73. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +12 -3
  74. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +13 -4
  75. package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +4 -4
  76. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -1
  77. package/src/__tests__/conversation-agent-loop-overflow.test.ts +22 -13
  78. package/src/__tests__/conversation-agent-loop.test.ts +39 -30
  79. package/src/__tests__/conversation-confirmation-signals.test.ts +14 -14
  80. package/src/__tests__/conversation-evictor.test.ts +49 -0
  81. package/src/__tests__/conversation-fork-crud.test.ts +1 -1
  82. package/src/__tests__/conversation-group-tools.test.ts +279 -0
  83. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  84. package/src/__tests__/conversation-key-store-disk-view.test.ts +5 -5
  85. package/src/__tests__/conversation-lineage.test.ts +235 -0
  86. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +5 -5
  87. package/src/__tests__/conversation-message-sync-tags.test.ts +4 -4
  88. package/src/__tests__/conversation-queue.test.ts +81 -81
  89. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +8 -1
  90. package/src/__tests__/conversation-routes-hidden-queue.test.ts +8 -1
  91. package/src/__tests__/conversation-routes-slash-commands.test.ts +10 -1
  92. package/src/__tests__/conversation-runtime-assembly.test.ts +29 -2
  93. package/src/__tests__/conversation-slash-queue.test.ts +11 -11
  94. package/src/__tests__/conversation-slash-unknown.test.ts +2 -2
  95. package/src/__tests__/conversation-speed-override.test.ts +2 -2
  96. package/src/__tests__/conversation-summarize-route.test.ts +9 -0
  97. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +18 -16
  98. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +17 -17
  99. package/src/__tests__/conversation-surfaces-app-open.test.ts +7 -4
  100. package/src/__tests__/conversation-surfaces-data-persist.test.ts +7 -7
  101. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +9 -9
  102. package/src/__tests__/conversation-surfaces-standalone.test.ts +12 -12
  103. package/src/__tests__/conversation-surfaces-state-update.test.ts +8 -5
  104. package/src/__tests__/conversation-surfaces-table-action.test.ts +6 -3
  105. package/src/__tests__/conversation-surfaces-task-progress.test.ts +46 -46
  106. package/src/__tests__/conversation-sync-tags.test.ts +5 -5
  107. package/src/__tests__/conversation-wait-for-idle.test.ts +2 -2
  108. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
  109. package/src/__tests__/conversation-workspace-injection.test.ts +0 -3
  110. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -3
  111. package/src/__tests__/copy-composer-tc-templates.test.ts +3 -131
  112. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  113. package/src/__tests__/daemon-assistant-events.test.ts +14 -15
  114. package/src/__tests__/db-test-helpers.ts +13 -27
  115. package/src/__tests__/disk-pressure-routes.test.ts +12 -3
  116. package/src/__tests__/document-tool-security.test.ts +95 -0
  117. package/src/__tests__/drain-kick-guard.test.ts +232 -0
  118. package/src/__tests__/dynamic-skill-background-guard.test.ts +19 -6
  119. package/src/__tests__/emit-event-signal.test.ts +5 -6
  120. package/src/__tests__/encrypted-store-test-helpers.ts +10 -20
  121. package/src/__tests__/events-tail-route.test.ts +6 -4
  122. package/src/__tests__/feature-flag-test-helpers.ts +10 -20
  123. package/src/__tests__/file-edit-tool.test.ts +24 -4
  124. package/src/__tests__/file-list-tool.test.ts +2 -1
  125. package/src/__tests__/file-read-tool.test.ts +62 -10
  126. package/src/__tests__/file-write-tool.test.ts +24 -5
  127. package/src/__tests__/followup-tools.test.ts +58 -0
  128. package/src/__tests__/gateway-threshold-reader-mock.ts +99 -0
  129. package/src/__tests__/graph-extraction-event-date.test.ts +1 -1
  130. package/src/__tests__/guardian-question-mode.test.ts +42 -3
  131. package/src/__tests__/guardian-reply-router-answer-mode.test.ts +283 -0
  132. package/src/__tests__/guardian-vellum-destination-pinning.test.ts +221 -0
  133. package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
  134. package/src/__tests__/heartbeat-service.test.ts +1 -0
  135. package/src/__tests__/helpers/native-web-search-harness.ts +10 -10
  136. package/src/__tests__/host-browser-proxy.test.ts +1 -1
  137. package/src/__tests__/host-file-edit-tool.test.ts +3 -3
  138. package/src/__tests__/host-file-read-tool.test.ts +2 -2
  139. package/src/__tests__/host-file-write-tool.test.ts +7 -3
  140. package/src/__tests__/host-shell-tool.test.ts +17 -5
  141. package/src/__tests__/host-transfer-pending-interactions.test.ts +8 -8
  142. package/src/__tests__/image-credentials.test.ts +65 -8
  143. package/src/__tests__/injection-block.test.ts +4 -4
  144. package/src/__tests__/injector-chain.test.ts +1 -1
  145. package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
  146. package/src/__tests__/injector-registry-order-guard.test.ts +4 -9
  147. package/src/__tests__/injector-v3-suppression.test.ts +6 -4
  148. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +27 -28
  149. package/src/__tests__/list-messages-page-latest.test.ts +2 -2
  150. package/src/__tests__/llm-usage-store.test.ts +67 -4
  151. package/src/__tests__/log-redact.test.ts +18 -0
  152. package/src/__tests__/managed-profile-guard.test.ts +27 -0
  153. package/src/__tests__/managed-skill-lifecycle.test.ts +2 -2
  154. package/src/__tests__/media-generate-image.test.ts +62 -11
  155. package/src/__tests__/memory-identity-context-parity.test.ts +1 -1
  156. package/src/__tests__/memory-jobs-worker-lanes.test.ts +9 -1
  157. package/src/__tests__/memory-retrieval-hook.test.ts +4 -4
  158. package/src/__tests__/notification-decision-strategy.test.ts +115 -11
  159. package/src/__tests__/notification-deep-link.test.ts +12 -12
  160. package/src/__tests__/notification-vellum-adapter.test.ts +8 -8
  161. package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
  162. package/src/__tests__/path-policy.test.ts +315 -0
  163. package/src/__tests__/pending-interactions-resolved-event.test.ts +6 -6
  164. package/src/__tests__/persistence-layering-guard.test.ts +2 -2
  165. package/src/__tests__/pkb-autoinject.test.ts +1 -1
  166. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -0
  167. package/src/__tests__/platform-callback-registration.test.ts +10 -10
  168. package/src/__tests__/plugin-event-hub-facade.test.ts +22 -15
  169. package/src/__tests__/plugin-import-boundary-guard.test.ts +15 -15
  170. package/src/__tests__/processing-flag-persist-failure.test.ts +0 -4
  171. package/src/__tests__/provider-platform-proxy-integration.test.ts +0 -1
  172. package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
  173. package/src/__tests__/request-secret-standalone-channel-gate.test.ts +5 -5
  174. package/src/__tests__/require-fresh-approval.test.ts +38 -38
  175. package/src/__tests__/resolve-app-id.test.ts +32 -0
  176. package/src/__tests__/run-due-schedules.test.ts +72 -1
  177. package/src/__tests__/runtime-events-sse-parity.test.ts +11 -10
  178. package/src/__tests__/runtime-events-sse.test.ts +1 -1
  179. package/src/__tests__/schedule-routes.test.ts +44 -5
  180. package/src/__tests__/schedule-store.test.ts +3 -3
  181. package/src/__tests__/schedule-tools.test.ts +176 -0
  182. package/src/__tests__/secret-prompt-log-hygiene.test.ts +3 -3
  183. package/src/__tests__/secret-prompter-channel-fallback.test.ts +3 -3
  184. package/src/__tests__/secret-response-routing.test.ts +3 -3
  185. package/src/__tests__/secret-routes-platform-proxy.test.ts +4 -7
  186. package/src/__tests__/secret-scanner.test.ts +36 -0
  187. package/src/__tests__/send-endpoint-busy.test.ts +7 -7
  188. package/src/__tests__/slack-required-scopes-mirror.test.ts +81 -0
  189. package/src/__tests__/starter-task-flow.test.ts +26 -3
  190. package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
  191. package/src/__tests__/subagent-disposal.test.ts +40 -11
  192. package/src/__tests__/subagent-fork-notifications.test.ts +4 -4
  193. package/src/__tests__/subagent-fork-prompt-role.test.ts +3 -3
  194. package/src/__tests__/subagent-fork-spawn.test.ts +4 -4
  195. package/src/__tests__/subagent-manager-notify.test.ts +73 -14
  196. package/src/__tests__/subagent-notify-parent.test.ts +48 -4
  197. package/src/__tests__/subagent-spawn-and-await.test.ts +62 -14
  198. package/src/__tests__/subagent-tools.test.ts +64 -0
  199. package/src/__tests__/sync-message-contract.test.ts +3 -3
  200. package/src/__tests__/terminal-tools.test.ts +12 -3
  201. package/src/__tests__/test-preload.ts +9 -0
  202. package/src/__tests__/tool-approval-handler.test.ts +587 -43
  203. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +7 -4
  204. package/src/__tests__/tool-executor.test.ts +116 -0
  205. package/src/__tests__/tool-grant-request-escalation.test.ts +5 -0
  206. package/src/__tests__/tool-preview-lifecycle.test.ts +32 -29
  207. package/src/__tests__/tool-result-metadata-plumbing.test.ts +5 -5
  208. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  209. package/src/__tests__/tool-start-timestamp.test.ts +4 -4
  210. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -22
  211. package/src/__tests__/ui-choice-copy-surfaces.test.ts +13 -13
  212. package/src/__tests__/ui-work-result-surface.test.ts +3 -3
  213. package/src/__tests__/voice-scoped-grant-consumer.test.ts +6 -6
  214. package/src/__tests__/voice-session-bridge.test.ts +44 -44
  215. package/src/__tests__/workspace-migration-134-image-generation-mode-to-provider.test.ts +284 -0
  216. package/src/__tests__/workspace-policy.test.ts +482 -2
  217. package/src/acp/__tests__/client-handler.test.ts +3 -3
  218. package/src/acp/__tests__/session-manager-persistence.test.ts +10 -10
  219. package/src/acp/__tests__/session-manager-resume.test.ts +7 -7
  220. package/src/acp/client-handler.ts +3 -3
  221. package/src/acp/session-manager.ts +8 -8
  222. package/src/api/events/subagent-event.ts +2 -2
  223. package/src/api/responses/memory-v2-activation-log.ts +2 -2
  224. package/src/api/responses/subagent-detail.ts +13 -0
  225. package/src/approvals/AGENTS.md +2 -0
  226. package/src/approvals/guardian-request-resolvers.ts +118 -24
  227. package/src/apps/app-store.ts +95 -4
  228. package/src/calls/__tests__/voice-control-protocol.test.ts +57 -0
  229. package/src/calls/__tests__/voice-session-bridge.test.ts +229 -7
  230. package/src/calls/__tests__/voice-triage-escalate.test.ts +3 -4
  231. package/src/calls/call-controller.ts +27 -27
  232. package/src/calls/call-conversation-messages.ts +58 -18
  233. package/src/calls/voice-control-protocol.ts +56 -0
  234. package/src/calls/voice-session-bridge.ts +178 -65
  235. package/src/calls/voice-triage-escalate.ts +2 -3
  236. package/src/channels/config.ts +8 -0
  237. package/src/channels/types.ts +1 -0
  238. package/src/cli/commands/config.ts +49 -13
  239. package/src/cli/commands/memory/index.help.ts +4 -2
  240. package/src/cli/commands/memory/memory-retrospective.ts +5 -0
  241. package/src/cli/commands/webhooks.help.ts +9 -4
  242. package/src/cli/lib/bundled-marketplace.json +12 -0
  243. package/src/cli.ts +2 -109
  244. package/src/config/__tests__/deployment-context-defaults.test.ts +9 -0
  245. package/src/config/__tests__/substrate-twin-shadowing.test.ts +191 -0
  246. package/src/config/assistant-feature-flags.ts +1 -1
  247. package/src/config/bundled-skills/conversation-groups/SKILL.md +29 -0
  248. package/src/config/bundled-skills/conversation-groups/TOOLS.json +58 -0
  249. package/src/config/bundled-skills/conversation-groups/tools/group-create.ts +12 -0
  250. package/src/config/bundled-skills/conversation-groups/tools/group-list.ts +12 -0
  251. package/src/config/bundled-skills/conversation-groups/tools/move-to-group.ts +12 -0
  252. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +13 -7
  253. package/src/config/bundled-skills/schedule/SKILL.md +2 -0
  254. package/src/config/feature-flag-cache.ts +6 -16
  255. package/src/config/feature-flag-registry.json +14 -38
  256. package/src/config/loader.ts +7 -1
  257. package/src/config/memory-tier.ts +15 -10
  258. package/src/config/memory-v3-gate.test.ts +278 -1
  259. package/src/config/memory-v3-gate.ts +88 -26
  260. package/src/config/raw-config-utils.ts +1 -1
  261. package/src/config/schemas/__tests__/live-voice.test.ts +27 -16
  262. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  263. package/src/config/schemas/live-voice.ts +33 -7
  264. package/src/config/schemas/llm.ts +1 -0
  265. package/src/config/schemas/memory-retrospective.ts +13 -0
  266. package/src/config/schemas/memory-substrate.ts +183 -0
  267. package/src/config/schemas/memory-v2.ts +3 -2
  268. package/src/config/schemas/memory-v3.ts +11 -4
  269. package/src/config/schemas/memory.ts +35 -1
  270. package/src/config/schemas/services.ts +10 -2
  271. package/src/config/substrate-twin-shadowing.ts +195 -0
  272. package/src/config/webhook-routing.ts +67 -0
  273. package/src/context/compactor.ts +10 -3
  274. package/src/context/token-estimator.ts +21 -0
  275. package/src/daemon/__tests__/channel-ui-capability.test.ts +85 -0
  276. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +3 -3
  277. package/src/daemon/__tests__/embedding-reconcile.test.ts +3 -3
  278. package/src/daemon/__tests__/inference-profile-notification.test.ts +3 -6
  279. package/src/daemon/__tests__/native-web-search-metadata.test.ts +5 -5
  280. package/src/daemon/__tests__/web-search-status-text.test.ts +2 -2
  281. package/src/daemon/channel-ui-capability.ts +70 -1
  282. package/src/daemon/conversation-agent-loop-handlers.ts +4 -4
  283. package/src/daemon/conversation-agent-loop.ts +12 -5
  284. package/src/daemon/conversation-evictor.ts +26 -4
  285. package/src/daemon/conversation-launch.ts +11 -14
  286. package/src/daemon/conversation-lineage.ts +76 -0
  287. package/src/daemon/conversation-messaging.ts +14 -14
  288. package/src/daemon/conversation-notifiers.ts +2 -2
  289. package/src/daemon/conversation-process.ts +133 -21
  290. package/src/daemon/conversation-queue-manager.ts +7 -7
  291. package/src/daemon/conversation-runtime-assembly.ts +16 -0
  292. package/src/daemon/conversation-store.ts +11 -3
  293. package/src/daemon/conversation-surfaces.ts +8 -14
  294. package/src/daemon/conversation-tool-setup.ts +13 -7
  295. package/src/daemon/conversation-usage.ts +12 -11
  296. package/src/daemon/conversation.ts +38 -15
  297. package/src/daemon/disk-pressure-guard.ts +5 -12
  298. package/src/daemon/embedding-reconcile.ts +14 -9
  299. package/src/daemon/handlers/config-channels.ts +40 -134
  300. package/src/daemon/handlers/config-model.ts +15 -7
  301. package/src/daemon/handlers/conversations.ts +4 -2
  302. package/src/daemon/handlers/shared.ts +29 -0
  303. package/src/daemon/host-proxy-base.ts +4 -4
  304. package/src/daemon/lifecycle.ts +13 -0
  305. package/src/daemon/message-protocol.ts +8 -144
  306. package/src/daemon/message-types/computer-use.ts +0 -12
  307. package/src/daemon/message-types/conversations.ts +9 -345
  308. package/src/daemon/message-types/host-app-control.ts +0 -9
  309. package/src/daemon/message-types/host-browser.ts +0 -7
  310. package/src/daemon/message-types/host-ui-snapshot.ts +0 -7
  311. package/src/daemon/message-types/messages.ts +0 -48
  312. package/src/daemon/message-types/notifications.ts +0 -7
  313. package/src/daemon/message-types/skills.ts +0 -5
  314. package/src/daemon/message-types/surfaces.ts +0 -9
  315. package/src/daemon/message-types/sync.ts +0 -2
  316. package/src/daemon/process-message.ts +5 -5
  317. package/src/daemon/skill-memory-refresh.ts +5 -5
  318. package/src/daemon/tool-side-effects.ts +32 -16
  319. package/src/daemon/trust-context.ts +1 -1
  320. package/src/daemon/wake-conversation-ops.ts +4 -4
  321. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +100 -7
  322. package/src/heartbeat/__tests__/heartbeat-service.test.ts +67 -0
  323. package/src/heartbeat/heartbeat-run-store.ts +81 -4
  324. package/src/heartbeat/heartbeat-service.ts +32 -1
  325. package/src/home/__tests__/feed-writer.test.ts +7 -7
  326. package/src/home/__tests__/home-content-refresh.test.ts +3 -0
  327. package/src/home/__tests__/suggested-prompts.test.ts +1 -0
  328. package/src/home/feed-writer.ts +6 -13
  329. package/src/home/home-content-refresh.ts +6 -9
  330. package/src/home/relationship-state-writer.ts +5 -12
  331. package/src/home/suggested-prompts-cache.ts +6 -19
  332. package/src/ipc/__tests__/events-publish-client.test.ts +67 -0
  333. package/src/ipc/events-publish-client.ts +44 -0
  334. package/src/ipc/routes/__tests__/conversation-sync-ipc-routes.test.ts +2 -2
  335. package/src/ipc/routes/__tests__/events-ipc-routes.test.ts +38 -9
  336. package/src/ipc/routes/events-ipc-routes.ts +11 -31
  337. package/src/live-voice/__tests__/front-decision.test.ts +4 -176
  338. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +276 -68
  339. package/src/live-voice/__tests__/live-voice-continuation-fork-hydration.test.ts +286 -0
  340. package/src/live-voice/__tests__/live-voice-events.test.ts +6 -3
  341. package/src/live-voice/__tests__/live-voice-progress.test.ts +185 -46
  342. package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +24 -59
  343. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +38 -54
  344. package/src/live-voice/__tests__/live-voice-vad.test.ts +1154 -636
  345. package/src/live-voice/front-decision.ts +5 -155
  346. package/src/live-voice/live-voice-metrics.ts +4 -1
  347. package/src/live-voice/live-voice-session.ts +1288 -439
  348. package/src/live-voice/progress-phrases.ts +17 -0
  349. package/src/live-voice/protocol.ts +15 -0
  350. package/src/media/app-icon-generator.ts +15 -8
  351. package/src/media/avatar-router.ts +9 -5
  352. package/src/media/image-credentials.ts +42 -10
  353. package/src/media/image-service.ts +1 -13
  354. package/src/media/types.ts +26 -3
  355. package/src/notifications/AGENTS.md +2 -0
  356. package/src/notifications/__tests__/broadcaster.test.ts +95 -0
  357. package/src/notifications/adapters/macos.ts +3 -3
  358. package/src/notifications/broadcaster.ts +57 -0
  359. package/src/notifications/copy-composer.ts +0 -15
  360. package/src/notifications/decision-engine.ts +21 -22
  361. package/src/notifications/guardian-question-mode.ts +57 -2
  362. package/src/notifications/home-feed-side-effect.ts +4 -0
  363. package/src/notifications/signal.ts +6 -4
  364. package/src/notifications/trusted-contact-payloads.ts +3 -4
  365. package/src/notifications/vellum-card-affinity.ts +39 -0
  366. package/src/oauth/AGENTS.md +1 -1
  367. package/src/permissions/channel-permission-query.test.ts +69 -0
  368. package/src/permissions/channel-permission-query.ts +73 -1
  369. package/src/permissions/checker.test.ts +298 -15
  370. package/src/permissions/checker.ts +102 -36
  371. package/src/permissions/confirmation-guardian-request.test.ts +2 -2
  372. package/src/permissions/confirmation-guardian-request.ts +2 -2
  373. package/src/permissions/gateway-threshold-reader.test.ts +224 -17
  374. package/src/permissions/gateway-threshold-reader.ts +82 -10
  375. package/src/permissions/ipc-risk-types.ts +8 -0
  376. package/src/permissions/prompter.ts +5 -5
  377. package/src/permissions/question-guardian-request.test.ts +222 -0
  378. package/src/permissions/question-guardian-request.ts +179 -0
  379. package/src/permissions/question-prompter.test.ts +8 -8
  380. package/src/permissions/question-prompter.ts +18 -0
  381. package/src/permissions/secret-prompter.ts +2 -4
  382. package/src/permissions/workspace-policy.ts +269 -34
  383. package/src/persistence/__tests__/lifecycle-quiesce.test.ts +82 -0
  384. package/src/persistence/__tests__/message-content-file.test.ts +58 -3
  385. package/src/persistence/conversation-crud.ts +93 -0
  386. package/src/persistence/conversation-key-store.ts +63 -0
  387. package/src/persistence/conversation-parent.ts +27 -0
  388. package/src/persistence/db-async-query.ts +1 -1
  389. package/src/persistence/db-singleton.ts +14 -27
  390. package/src/persistence/delivery-crud.ts +45 -0
  391. package/src/persistence/embeddings/embedding-backend.ts +2 -1
  392. package/src/persistence/embeddings/embedding-identity.ts +7 -3
  393. package/src/persistence/job-utils.ts +32 -27
  394. package/src/persistence/jobs-store.ts +92 -3
  395. package/src/persistence/lifecycle-quiesce.ts +80 -0
  396. package/src/persistence/llm-usage-store.ts +45 -8
  397. package/src/persistence/message-content-file.ts +4 -4
  398. package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +1 -1
  399. package/src/persistence/migrations/351-schedule-skill-script-handoff.ts +39 -0
  400. package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.test.ts +83 -0
  401. package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.ts +36 -0
  402. package/src/persistence/migrations/353-add-llm-usage-conversation-type.test.ts +110 -0
  403. package/src/persistence/migrations/353-add-llm-usage-conversation-type.ts +49 -0
  404. package/src/persistence/migrations/354-backfill-app-conversation-lineage.ts +41 -0
  405. package/src/persistence/schema/infrastructure.ts +11 -0
  406. package/src/persistence/steps.ts +9 -1
  407. package/src/plugin-api/__tests__/publish-event-forwarding.test.ts +113 -0
  408. package/src/plugin-api/__tests__/publish-event.test.ts +57 -0
  409. package/src/plugin-api/conversation-turn.ts +4 -4
  410. package/src/plugin-api/event-hub-facade.ts +15 -6
  411. package/src/plugin-api/index.ts +10 -4
  412. package/src/plugin-api/publish-event.ts +36 -0
  413. package/src/plugins/AGENTS.md +2 -0
  414. package/src/plugins/defaults/compaction/window-manager.ts +9 -0
  415. package/src/plugins/defaults/index.ts +9 -13
  416. package/src/plugins/defaults/memory/AGENTS.md +775 -0
  417. package/src/plugins/defaults/memory/__tests__/capability-seed-embed-gate.test.ts +186 -0
  418. package/src/plugins/defaults/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +1 -1
  419. package/src/plugins/defaults/memory/__tests__/indexer-tier-dispatch.test.ts +129 -0
  420. package/src/plugins/defaults/memory/__tests__/jobs-worker-quiesce-gate.test.ts +91 -0
  421. package/src/plugins/defaults/memory/__tests__/jobs-worker-v1-graph-substrate-noop.test.ts +342 -0
  422. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +9 -1
  423. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +36 -1
  424. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-sweep-defer.test.ts +9 -1
  425. package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +2 -2
  426. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +44 -10
  427. package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +151 -10
  428. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1155 -0
  429. package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
  430. package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -3
  431. package/src/plugins/defaults/memory/__tests__/tools-delete-memory-page.test.ts +1 -1
  432. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +71 -35
  433. package/src/plugins/defaults/memory/context-search/sources/memory.ts +5 -1
  434. package/src/plugins/defaults/memory/fork-conversation-memory.ts +4 -4
  435. package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +80 -10
  436. package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +1 -1
  437. package/src/plugins/defaults/memory/graph/capability-seed.ts +24 -10
  438. package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +123 -49
  439. package/src/plugins/defaults/memory/graph/graph-search.ts +6 -118
  440. package/src/plugins/defaults/memory/graph/in-context-tracker.test.ts +173 -0
  441. package/src/plugins/defaults/memory/graph/in-context-tracker.ts +109 -0
  442. package/src/plugins/defaults/memory/graph/store.ts +1 -0
  443. package/src/plugins/defaults/memory/graph/tool-handlers.test.ts +1 -1
  444. package/src/plugins/defaults/memory/graph/tool-handlers.ts +5 -2
  445. package/src/plugins/defaults/memory/graph-topology/__tests__/build-memory-graph.test.ts +1 -1
  446. package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +6 -9
  447. package/src/plugins/defaults/memory/hooks/__tests__/user-prompt-submit.test.ts +30 -16
  448. package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +18 -14
  449. package/src/plugins/defaults/memory/indexer.ts +146 -89
  450. package/src/plugins/defaults/memory/injectors.ts +86 -41
  451. package/src/plugins/defaults/memory/job-handlers.ts +130 -39
  452. package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +2 -2
  453. package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +22 -10
  454. package/src/plugins/defaults/memory/jobs-worker.ts +279 -208
  455. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +4 -2
  456. package/src/plugins/defaults/memory/memory-retrospective-job.ts +40 -3
  457. package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +99 -11
  458. package/src/plugins/defaults/memory/src/__tests__/memory-v2-routes.test.ts +5 -3
  459. package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +3 -4
  460. package/src/plugins/defaults/memory/src/memory-graph-routes.ts +2 -1
  461. package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +7 -5
  462. package/src/plugins/defaults/memory/src/memory-item-routes.ts +51 -19
  463. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +31 -20
  464. package/src/plugins/defaults/memory/startup.ts +58 -21
  465. package/src/plugins/defaults/memory/substrate/__tests__/boot-maintenance.test.ts +335 -0
  466. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/cli-command-store.test.ts +14 -8
  467. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-job.test.ts +51 -21
  468. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/edge-index.test.ts +1 -1
  469. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/frontmatter-sweep.test.ts +3 -3
  470. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-index.test.ts +1 -1
  471. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-store.test.ts +1 -1
  472. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/prompts-consolidation.test.ts +2 -2
  473. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/qdrant.test.ts +23 -14
  474. package/src/plugins/defaults/memory/substrate/__tests__/reembed-job.test.ts +262 -0
  475. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sim.test.ts +9 -12
  476. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-content.test.ts +2 -2
  477. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-store.test.ts +9 -9
  478. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sparse-bm25.test.ts +12 -5
  479. package/src/plugins/defaults/memory/substrate/__tests__/spread.test.ts +276 -0
  480. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/static-context.test.ts +17 -8
  481. package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sweep-job.test.ts +9 -9
  482. package/src/plugins/defaults/memory/{v3/substrate/memory-v2-startup.ts → substrate/boot-maintenance.ts} +43 -24
  483. package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-store.ts +13 -8
  484. package/src/plugins/defaults/memory/{v3/substrate → substrate}/consolidation-job.ts +51 -27
  485. package/src/plugins/defaults/memory/{v3/substrate → substrate}/constants.ts +1 -0
  486. package/src/plugins/defaults/memory/{v3/substrate → substrate}/edge-index.ts +28 -9
  487. package/src/plugins/defaults/memory/{v3/substrate → substrate}/frontmatter-sweep.ts +14 -7
  488. package/src/plugins/defaults/memory/{v3/substrate → substrate}/injected-block-slugs.ts +9 -3
  489. package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-index.ts +29 -10
  490. package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-store.ts +35 -12
  491. package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/consolidation.ts +14 -8
  492. package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/sweep.ts +4 -1
  493. package/src/plugins/defaults/memory/{v3/substrate → substrate}/qdrant.ts +96 -36
  494. package/src/plugins/defaults/memory/substrate/reembed-job.ts +54 -0
  495. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sim.ts +26 -15
  496. package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-content.ts +1 -1
  497. package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-store.ts +13 -8
  498. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sparse-bm25.ts +27 -10
  499. package/src/plugins/defaults/memory/substrate/spread.ts +165 -0
  500. package/src/plugins/defaults/memory/{v3/substrate → substrate}/static-context.ts +12 -7
  501. package/src/plugins/defaults/memory/{v3/substrate → substrate}/sweep-job.ts +20 -15
  502. package/src/plugins/defaults/memory/substrate/tuning.ts +93 -0
  503. package/src/plugins/defaults/memory/{v3/substrate → substrate}/types.ts +7 -4
  504. package/src/plugins/defaults/memory/tools.test.ts +1 -1
  505. package/src/plugins/defaults/memory/tools.ts +1 -1
  506. package/src/plugins/defaults/memory/v1/README.md +5 -0
  507. package/src/plugins/defaults/memory/{__tests__ → v1/__tests__}/filing-jobs.test.ts +4 -4
  508. package/src/plugins/defaults/memory/{filing-jobs.ts → v1/filing-jobs.ts} +3 -3
  509. package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.test.ts +68 -6
  510. package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.ts +40 -21
  511. package/src/plugins/defaults/memory/{graph → v1/graph}/consolidation.ts +14 -14
  512. package/src/plugins/defaults/memory/{graph → v1/graph}/decay.test.ts +1 -1
  513. package/src/plugins/defaults/memory/{graph → v1/graph}/decay.ts +3 -3
  514. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction-job.ts +5 -5
  515. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.test.ts +1 -1
  516. package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.ts +20 -14
  517. package/src/plugins/defaults/memory/{graph → v1/graph}/graph-search.test.ts +3 -3
  518. package/src/plugins/defaults/memory/v1/graph/graph-search.ts +123 -0
  519. package/src/plugins/defaults/memory/{graph → v1/graph}/injection.test.ts +1 -118
  520. package/src/plugins/defaults/memory/{graph → v1/graph}/injection.ts +9 -111
  521. package/src/plugins/defaults/memory/{graph → v1/graph}/narrative.ts +6 -6
  522. package/src/plugins/defaults/memory/{graph → v1/graph}/pattern-scan.ts +5 -5
  523. package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.test.ts +135 -42
  524. package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.ts +40 -22
  525. package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.test.ts +1 -1
  526. package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.ts +1 -1
  527. package/src/plugins/defaults/memory/{graph → v1/graph}/serendipity.ts +1 -1
  528. package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.test.ts +1 -1
  529. package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.ts +1 -1
  530. package/src/plugins/defaults/memory/{identity-context.ts → v1/identity-context.ts} +4 -4
  531. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/backfill.ts +6 -6
  532. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.test.ts +6 -6
  533. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.ts +6 -6
  534. package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/index-maintenance.ts +8 -8
  535. package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.test.ts +7 -7
  536. package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.ts +5 -5
  537. package/src/plugins/defaults/memory/{pkb → v1/pkb}/autoinject.ts +1 -1
  538. package/src/plugins/defaults/memory/{pkb → v1/pkb}/context.ts +2 -2
  539. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.test.ts +3 -3
  540. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.ts +2 -2
  541. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.test.ts +3 -3
  542. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.ts +2 -2
  543. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.test.ts +3 -3
  544. package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.ts +6 -6
  545. package/src/plugins/defaults/memory/{pkb → v1/pkb}/types.ts +3 -5
  546. package/src/plugins/defaults/memory/{pkb-schedule.ts → v1/pkb-schedule.ts} +2 -2
  547. package/src/plugins/defaults/memory/{search/semantic.ts → v1/semantic-search.ts} +1 -1
  548. package/src/plugins/defaults/memory/v2/__tests__/activation-store.test.ts +1 -1
  549. package/src/plugins/defaults/memory/v2/__tests__/activation.test.ts +11 -274
  550. package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +9 -131
  551. package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +1 -1
  552. package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +1 -1
  553. package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
  554. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +14 -10
  555. package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +7 -5
  556. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +12 -6
  557. package/src/plugins/defaults/memory/{memory-v2-activation-log-store.ts → v2/activation-log-store.ts} +2 -2
  558. package/src/plugins/defaults/memory/v2/activation-store.ts +22 -8
  559. package/src/plugins/defaults/memory/v2/activation.ts +30 -163
  560. package/src/plugins/defaults/memory/v2/backfill-jobs.ts +7 -54
  561. package/src/plugins/defaults/memory/{memory-v2-concept-frequency.ts → v2/concept-frequency.ts} +3 -3
  562. package/src/plugins/defaults/memory/v2/harness/oracle.ts +1 -1
  563. package/src/plugins/defaults/memory/v2/harness/replay-input.ts +2 -2
  564. package/src/plugins/defaults/memory/v2/harness/retriever.ts +1 -1
  565. package/src/plugins/defaults/memory/v2/injection.ts +36 -26
  566. package/src/plugins/defaults/memory/v2/migration.ts +2 -2
  567. package/src/plugins/defaults/memory/{rerank-local.ts → v2/rerank-local.ts} +44 -18
  568. package/src/plugins/defaults/memory/v2/reranker.ts +29 -11
  569. package/src/plugins/defaults/memory/v2/router.ts +38 -15
  570. package/src/plugins/defaults/memory/v3/__tests__/candidate-match.test.ts +5 -3
  571. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +21 -8
  572. package/src/plugins/defaults/memory/v3/__tests__/edge.test.ts +1 -1
  573. package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +1 -1
  574. package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +4 -1
  575. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +181 -3
  576. package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +3 -0
  577. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +14 -5
  578. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +40 -50
  579. package/src/plugins/defaults/memory/v3/__tests__/tuning-profile.test.ts +1 -0
  580. package/src/plugins/defaults/memory/v3/candidate-match.ts +2 -2
  581. package/src/plugins/defaults/memory/v3/capabilities.ts +6 -4
  582. package/src/plugins/defaults/memory/v3/card.ts +25 -9
  583. package/src/plugins/defaults/memory/v3/edge.ts +52 -18
  584. package/src/plugins/defaults/memory/v3/gate.ts +4 -4
  585. package/src/plugins/defaults/memory/v3/injector.ts +10 -3
  586. package/src/plugins/defaults/memory/v3/maintain-job.ts +3 -3
  587. package/src/plugins/defaults/memory/v3/orchestrate.ts +100 -18
  588. package/src/plugins/defaults/memory/v3/page-content.ts +26 -10
  589. package/src/plugins/defaults/memory/v3/prune.ts +40 -16
  590. package/src/plugins/defaults/memory/v3/selection-log-store.ts +34 -12
  591. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +9 -13
  592. package/src/plugins/defaults/memory/v3/span-query.test.ts +86 -0
  593. package/src/plugins/defaults/memory/v3/span-query.ts +71 -0
  594. package/src/plugins/defaults/memory/v3/tuning-profile.ts +3 -0
  595. package/src/plugins/defaults/memory/v3/types.ts +4 -1
  596. package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +2 -2
  597. package/src/plugins/defaults/memory/validation.ts +1 -1
  598. package/src/plugins/defaults/memory/worker.ts +2 -1
  599. package/src/plugins/defaults/platform-hosted/__tests__/reengage.test.ts +104 -12
  600. package/src/plugins/defaults/platform-hosted/routes/reengage.ts +104 -12
  601. package/src/plugins/types.ts +2 -2
  602. package/src/prompts/sections.ts +4 -16
  603. package/src/providers/__tests__/registry-native-web-search.test.ts +47 -2
  604. package/src/providers/anthropic/client.ts +15 -6
  605. package/src/providers/content-block-schema.ts +26 -0
  606. package/src/providers/inference/__tests__/connections-credential-normalize.test.ts +87 -0
  607. package/src/providers/inference/adapter-factory.ts +6 -0
  608. package/src/providers/inference/connections.ts +30 -14
  609. package/src/providers/model-catalog.ts +77 -0
  610. package/src/providers/openai/__tests__/chat-completions-input-audio.test.ts +260 -0
  611. package/src/providers/openai/chat-completions-provider.ts +65 -17
  612. package/src/providers/openai/input-audio.ts +76 -0
  613. package/src/providers/openrouter/client.ts +0 -2
  614. package/src/providers/platform-proxy/constants.ts +4 -0
  615. package/src/providers/poolside/client.ts +42 -0
  616. package/src/providers/registry.ts +40 -8
  617. package/src/providers/retry.ts +2 -0
  618. package/src/providers/types.ts +39 -1
  619. package/src/providers/vercel-ai-gateway/client.ts +0 -2
  620. package/src/runtime/AGENTS.md +7 -5
  621. package/src/runtime/__tests__/question-request-guardian-bridge.test.ts +173 -0
  622. package/src/runtime/__tests__/question-resolution.test.ts +111 -0
  623. package/src/runtime/access-request-helper.ts +7 -15
  624. package/src/runtime/assistant-event-hub.ts +43 -31
  625. package/src/runtime/assistant-event-publish-options.ts +31 -0
  626. package/src/runtime/assistant-event.ts +19 -30
  627. package/src/runtime/assistant-stream-state.ts +4 -4
  628. package/src/runtime/channel-approvals.ts +0 -25
  629. package/src/runtime/channel-readiness-service.ts +99 -40
  630. package/src/runtime/channel-retry-sweep.ts +38 -15
  631. package/src/runtime/confirmation-request-guardian-bridge.ts +4 -0
  632. package/src/runtime/guardian-reply-router.ts +108 -0
  633. package/src/runtime/http-server.ts +8 -0
  634. package/src/runtime/http-types.ts +2 -2
  635. package/src/runtime/process-role.ts +42 -0
  636. package/src/runtime/question-request-guardian-bridge.ts +184 -0
  637. package/src/runtime/question-resolution.ts +153 -0
  638. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +6 -2
  639. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -1
  640. package/src/runtime/routes/__tests__/subagents-routes.test.ts +250 -0
  641. package/src/runtime/routes/__tests__/webhook-routes.test.ts +201 -0
  642. package/src/runtime/routes/acp-routes.ts +2 -2
  643. package/src/runtime/routes/bookmark-routes.ts +3 -15
  644. package/src/runtime/routes/canned-message-complete.ts +2 -2
  645. package/src/runtime/routes/consolidation-routes.ts +8 -2
  646. package/src/runtime/routes/conversation-list-routes.ts +3 -19
  647. package/src/runtime/routes/conversation-management-routes.ts +1 -5
  648. package/src/runtime/routes/conversation-query-routes.ts +52 -8
  649. package/src/runtime/routes/conversation-routes.ts +36 -22
  650. package/src/runtime/routes/credential-request-routes.ts +0 -1
  651. package/src/runtime/routes/filing-routes.ts +7 -7
  652. package/src/runtime/routes/global-search-routes.ts +1 -1
  653. package/src/runtime/routes/guardian-approval-prompt.ts +2 -2
  654. package/src/runtime/routes/image-generation-routes.ts +12 -9
  655. package/src/runtime/routes/inbound-message-handler.ts +17 -0
  656. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +50 -0
  657. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +19 -0
  658. package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -4
  659. package/src/runtime/routes/inbound-stages/inbound-content-prep.test.ts +129 -0
  660. package/src/runtime/routes/inbound-stages/inbound-content-prep.ts +141 -9
  661. package/src/runtime/routes/index.ts +2 -0
  662. package/src/runtime/routes/lifecycle-routes.ts +199 -0
  663. package/src/runtime/routes/platform-routes.ts +3 -8
  664. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +7 -7
  665. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +5 -5
  666. package/src/runtime/routes/question-routes.ts +34 -87
  667. package/src/runtime/routes/secret-routes.ts +11 -1
  668. package/src/runtime/routes/settings-routes.ts +8 -18
  669. package/src/runtime/routes/subagents-routes.ts +35 -8
  670. package/src/runtime/routes/upgrade-broadcast-routes.ts +4 -5
  671. package/src/runtime/routes/webhook-routes.ts +89 -30
  672. package/src/runtime/routes/workspace-routes.test.ts +7 -4
  673. package/src/runtime/slack-reply-session.test.ts +12 -12
  674. package/src/runtime/slack-reply-session.ts +17 -17
  675. package/src/runtime/sync/sync-publisher.test.ts +7 -5
  676. package/src/runtime/tool-grant-request-helper.ts +4 -0
  677. package/src/schedule/schedule-store.ts +70 -0
  678. package/src/schedule/scheduler.ts +27 -0
  679. package/src/security/AGENTS.md +1 -1
  680. package/src/security/credential-key.ts +17 -0
  681. package/src/security/secret-ingress.ts +14 -105
  682. package/src/security/secret-patterns.ts +8 -139
  683. package/src/security/secret-scanner.ts +8 -3
  684. package/src/security/store-path-override.ts +6 -16
  685. package/src/sequence/store.ts +8 -0
  686. package/src/signals/emit-event.ts +5 -10
  687. package/src/signals/event-stream.ts +20 -10
  688. package/src/subagent/manager.ts +76 -25
  689. package/src/subagent/notify.ts +8 -0
  690. package/src/subagent/types.ts +13 -3
  691. package/src/telegram/__tests__/webhook-health.test.ts +442 -0
  692. package/src/telegram/webhook-health.ts +478 -0
  693. package/src/telemetry/AGENTS.md +6 -0
  694. package/src/telemetry/memory-corpus-size.test.ts +129 -0
  695. package/src/telemetry/memory-corpus-size.ts +184 -0
  696. package/src/telemetry/memory-tier-reporter.test.ts +67 -2
  697. package/src/telemetry/memory-tier-reporter.ts +30 -3
  698. package/src/tools/__tests__/conversation-group-tool-input-schemas.test.ts +61 -0
  699. package/src/tools/__tests__/document-tool-input-schemas.test.ts +103 -0
  700. package/src/tools/__tests__/followup-call-acp-tool-input-schemas.test.ts +125 -0
  701. package/src/tools/__tests__/schedule-tool-input-schemas.test.ts +83 -0
  702. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +116 -0
  703. package/src/tools/__tests__/tool-input-schemas.test.ts +192 -0
  704. package/src/tools/__tests__/tool-schema-drift-harness.ts +142 -0
  705. package/src/tools/acp/abort.ts +21 -1
  706. package/src/tools/acp/context.ts +5 -5
  707. package/src/tools/acp/spawn.test.ts +15 -5
  708. package/src/tools/acp/spawn.ts +26 -3
  709. package/src/tools/acp/status.ts +20 -1
  710. package/src/tools/acp/steer.test.ts +20 -0
  711. package/src/tools/acp/steer.ts +23 -2
  712. package/src/tools/apps/resolve-app-id.ts +15 -3
  713. package/src/tools/ask-question/ask-question-tool.test.ts +65 -0
  714. package/src/tools/ask-question/ask-question-tool.ts +68 -92
  715. package/src/tools/browser/browser-screencast.ts +6 -6
  716. package/src/tools/calls/call-end.ts +24 -3
  717. package/src/tools/calls/call-start.ts +35 -11
  718. package/src/tools/calls/call-status.ts +20 -1
  719. package/src/tools/conversation-groups/group_create.ts +63 -0
  720. package/src/tools/conversation-groups/group_list.ts +20 -0
  721. package/src/tools/conversation-groups/group_shared.ts +52 -0
  722. package/src/tools/conversation-groups/move_to_group.ts +106 -0
  723. package/src/tools/document/document-comment-tool.test.ts +49 -0
  724. package/src/tools/document/document-comment-tool.ts +45 -6
  725. package/src/tools/document/document-tool.ts +142 -24
  726. package/src/tools/executor.ts +27 -13
  727. package/src/tools/filesystem/edit.ts +62 -60
  728. package/src/tools/filesystem/list.ts +36 -29
  729. package/src/tools/filesystem/read.ts +56 -39
  730. package/src/tools/filesystem/write.ts +44 -38
  731. package/src/tools/followups/followup_create.ts +41 -12
  732. package/src/tools/followups/followup_list.ts +34 -6
  733. package/src/tools/followups/followup_resolve.ts +26 -4
  734. package/src/tools/host-filesystem/edit.ts +50 -60
  735. package/src/tools/host-filesystem/read.ts +45 -39
  736. package/src/tools/host-filesystem/write.ts +31 -36
  737. package/src/tools/host-terminal/host-shell.ts +76 -62
  738. package/src/tools/policy-context.ts +27 -10
  739. package/src/tools/schedule/create.ts +76 -33
  740. package/src/tools/schedule/delete.ts +21 -2
  741. package/src/tools/schedule/list.ts +25 -3
  742. package/src/tools/schedule/update.ts +105 -48
  743. package/src/tools/shared/filesystem/path-policy.ts +246 -40
  744. package/src/tools/shared/zod-tool-schema.ts +117 -0
  745. package/src/tools/subagent/abort.ts +12 -4
  746. package/src/tools/subagent/consult-deadline.ts +9 -3
  747. package/src/tools/subagent/message.ts +21 -5
  748. package/src/tools/subagent/notify-parent.ts +44 -23
  749. package/src/tools/subagent/read.ts +15 -4
  750. package/src/tools/subagent/resolve.ts +26 -4
  751. package/src/tools/subagent/spawn.ts +37 -13
  752. package/src/tools/subagent/status.ts +12 -4
  753. package/src/tools/system/request-permission.ts +35 -26
  754. package/src/tools/terminal/shell.ts +68 -55
  755. package/src/tools/tool-approval-handler.ts +327 -53
  756. package/src/tools/tool-input-schemas.ts +85 -0
  757. package/src/tools/tool-types.ts +7 -0
  758. package/src/tools/types.ts +8 -0
  759. package/src/tools/workflows/manage-workflows.ts +30 -2
  760. package/src/tools/workflows/run-workflow.test.ts +54 -2
  761. package/src/tools/workflows/run-workflow.ts +32 -4
  762. package/src/util/fs-symlinks.ts +30 -0
  763. package/src/util/log-redact.ts +7 -3
  764. package/src/util/platform.ts +15 -0
  765. package/src/vellum-assistant-namespace.d.ts +80 -0
  766. package/src/watcher/watcher-store.ts +8 -0
  767. package/src/workflows/leaf-runner.test.ts +104 -2
  768. package/src/workflows/leaf-runner.ts +31 -6
  769. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +2 -2
  770. package/src/workspace/migrations/134-image-generation-mode-to-provider.ts +128 -0
  771. package/src/workspace/migrations/135-copy-substrate-tunables.ts +248 -0
  772. package/src/workspace/migrations/__tests__/135-copy-substrate-tunables.test.ts +446 -0
  773. package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +2 -2
  774. package/src/workspace/migrations/registry.ts +4 -0
  775. package/tsconfig.plugin-api.json +1 -1
  776. package/src/__tests__/memory-retrieval-budget.test.ts +0 -49
  777. package/src/__tests__/secret-patterns.test.ts +0 -27
  778. package/src/config/__tests__/proc-to-skills.test.ts +0 -21
  779. package/src/config/memory-tier.test.ts +0 -44
  780. package/src/daemon/message-types/acp.ts +0 -20
  781. package/src/daemon/message-types/apps.ts +0 -11
  782. package/src/daemon/message-types/background-tools.ts +0 -14
  783. package/src/daemon/message-types/bookmarks.ts +0 -13
  784. package/src/daemon/message-types/contacts.ts +0 -13
  785. package/src/daemon/message-types/document-comments.ts +0 -14
  786. package/src/daemon/message-types/documents.ts +0 -13
  787. package/src/daemon/message-types/home.ts +0 -15
  788. package/src/daemon/message-types/host-bash.ts +0 -12
  789. package/src/daemon/message-types/host-cu.ts +0 -10
  790. package/src/daemon/message-types/host-file.ts +0 -12
  791. package/src/daemon/message-types/host-transfer.ts +0 -12
  792. package/src/daemon/message-types/integrations.ts +0 -90
  793. package/src/daemon/message-types/memory.ts +0 -10
  794. package/src/daemon/message-types/schedules.ts +0 -14
  795. package/src/daemon/message-types/settings.ts +0 -17
  796. package/src/daemon/message-types/subagents.ts +0 -63
  797. package/src/daemon/message-types/upgrades.ts +0 -14
  798. package/src/daemon/message-types/workflows.ts +0 -25
  799. package/src/daemon/message-types/workspace.ts +0 -137
  800. package/src/live-voice/ack-phrases.ts +0 -58
  801. package/src/plugins/defaults/memory/retrieval-budget.ts +0 -29
  802. package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +0 -69
  803. package/src/plugins/defaults/memory/v3/gate-flag.ts +0 -20
  804. package/src/plugins/defaults/memory/v3/substrate/__tests__/memory-v2-startup.test.ts +0 -86
  805. package/src/plugins/defaults/memory/v3/substrate/memory-v2-startup.test.ts +0 -205
  806. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/concept-page-frontmatter-schema.test.ts +0 -0
  807. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-prompt-flag-gating-guard.test.ts +0 -0
  808. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/injected-block-slugs.test.ts +0 -0
  809. /package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-content.ts +0 -0
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Memory v3 — deterministic clause chunking for the span-query dense pass.
3
+ *
4
+ * A single embedding of a long, multi-topic message averages its distinct
5
+ * retrieval intents into one vector that matches none of them — the
6
+ * within-message form of the cross-speaker averaging the reply-query pass
7
+ * exists to avoid. The span pass re-runs the dense lane over the message's
8
+ * clause spans as separate queries so a motif buried in one clause retrieves
9
+ * at full strength.
10
+ *
11
+ * Chunking is pure text processing: split at newlines and sentence
12
+ * punctuation, drop fragments below {@link MIN_SPAN_WEIGHT}. A message yielding
13
+ * more than {@link MAX_SPAN_CHUNKS} spans is NOT truncated to its head — all
14
+ * spans are partitioned into {@link MAX_SPAN_CHUNKS} contiguous near-equal
15
+ * groups, so the whole message stays covered and long messages are simply
16
+ * queried at paragraph grain instead of clause grain.
17
+ */
18
+
19
+ /** Hard cap on span chunks per message — bounds the pass at
20
+ * `MAX_SPAN_CHUNKS × spanQueryK` extra candidates and as many embed calls. */
21
+ export const MAX_SPAN_CHUNKS = 8;
22
+
23
+ /** Spans weighing less than this carry no retrieval signal ("ok.", bare emoji
24
+ * lines) and are dropped before chunking. Weight, not raw length — see
25
+ * {@link spanWeight}. */
26
+ const MIN_SPAN_WEIGHT = 15;
27
+
28
+ /** Dense CJK scripts pack roughly a clause into the character budget English
29
+ * needs for a few words, so a raw char floor tuned for spaced scripts would
30
+ * drop nearly every realistic Chinese/Japanese/Korean sentence. Weigh those
31
+ * chars at 3× so the floor measures comparable information content. */
32
+ const DENSE_SCRIPT = /[\p{sc=Han}\p{sc=Hiragana}\p{sc=Katakana}\p{sc=Hangul}]/u;
33
+
34
+ function spanWeight(span: string): number {
35
+ let weight = 0;
36
+ for (const ch of span) {
37
+ weight += DENSE_SCRIPT.test(ch) ? 3 : 1;
38
+ }
39
+ return weight;
40
+ }
41
+
42
+ /**
43
+ * Split `message` into at most {@link MAX_SPAN_CHUNKS} contiguous clause
44
+ * chunks. Messages with that many spans or fewer return them unchanged;
45
+ * longer messages merge adjacent spans into near-equal groups covering the
46
+ * whole message. Deterministic; returns `[]` for empty/whitespace input.
47
+ */
48
+ export function spanChunksOf(message: string): string[] {
49
+ // Boundaries: newlines; any Unicode sentence terminator (`\p{STerm}` covers
50
+ // ASCII `.!?` plus CJK `。!?`, Arabic `؟`, Devanagari `।`, …) or ellipsis
51
+ // followed by whitespace; and a zero-width split after fullwidth CJK
52
+ // terminators, which conventionally have NO trailing space. The whitespace
53
+ // requirement on the general arm keeps ASCII `.` from splitting decimals
54
+ // and dotted abbreviations; fullwidth terminators never appear there.
55
+ const spans = message
56
+ .split(/\n+|(?<=[\p{STerm}…])\s+|(?<=[。!?。])/u)
57
+ .map((s) => s.trim())
58
+ .filter((s) => spanWeight(s) >= MIN_SPAN_WEIGHT);
59
+ if (spans.length <= MAX_SPAN_CHUNKS) {
60
+ return spans;
61
+ }
62
+ const chunks: string[] = [];
63
+ for (let i = 0; i < MAX_SPAN_CHUNKS; i++) {
64
+ const lo = Math.floor((i * spans.length) / MAX_SPAN_CHUNKS);
65
+ const hi = Math.floor(((i + 1) * spans.length) / MAX_SPAN_CHUNKS);
66
+ if (hi > lo) {
67
+ chunks.push(spans.slice(lo, hi).join(" "));
68
+ }
69
+ }
70
+ return chunks;
71
+ }
@@ -28,6 +28,7 @@ export interface ResolvedV3Tuning {
28
28
  needleK: number;
29
29
  denseK: number;
30
30
  replyQueryK: number;
31
+ spanQueryK: number;
31
32
  selectorEnabled: boolean;
32
33
  learnedEdgesCap: number;
33
34
  edgeSeedCount: number;
@@ -55,6 +56,7 @@ export const MEMORY_V3_NEW_USER_TUNING: ResolvedV3Tuning = {
55
56
  needleK: 12,
56
57
  denseK: 0,
57
58
  replyQueryK: 0,
59
+ spanQueryK: 0,
58
60
  selectorEnabled: false,
59
61
  learnedEdgesCap: 0,
60
62
  edgeSeedCount: 6,
@@ -82,6 +84,7 @@ export function resolveV3Tuning(
82
84
  needleK: v3.needleK,
83
85
  denseK: v3.denseK,
84
86
  replyQueryK: v3.replyQueryK,
87
+ spanQueryK: v3.spanQueryK,
85
88
  selectorEnabled: v3.selectorEnabled,
86
89
  learnedEdgesCap: v3.learnedEdges.cap,
87
90
  edgeSeedCount: v3.edge.seedCount,
@@ -96,7 +96,9 @@ export interface MemoryRoutingTurn {
96
96
  * frecency hot set, modification-recency fresh set); `needle` / `dense` /
97
97
  * `edge` are the per-turn finder lanes over the user's message; `reply` marks
98
98
  * finder candidates first surfaced by the reply-query pass (needle + dense
99
- * re-run over the assistant's previous message); `learned` marks candidates
99
+ * re-run over the assistant's previous message); `span` marks candidates first
100
+ * surfaced by the span-query pass (dense re-run over the current message's
101
+ * clause chunks as separate queries); `learned` marks candidates
100
102
  * surfaced by the co-selection NPMI association graph; `entity` marks
101
103
  * candidates surfaced because the message named an entity that titles a section
102
104
  * heading (the heading-anchored entity lane).
@@ -114,6 +116,7 @@ export const SELECTION_SOURCES = [
114
116
  "dense",
115
117
  "edge",
116
118
  "reply",
119
+ "span",
117
120
  "learned",
118
121
  "entity",
119
122
  ] as const;
@@ -36,11 +36,11 @@ import {
36
36
  messages,
37
37
  } from "../../../../persistence/schema/index.js";
38
38
  import { FRONTMATTER_REGEX, parseFrontmatterFields } from "../frontmatter.js";
39
+ import { injectedConceptHeader } from "../substrate/injected-block-slugs.js";
40
+ import { slugFromConceptPath } from "../substrate/page-store.js";
39
41
  import { renderCard } from "../v3/card.js";
40
42
  import { buildSectionNeedle } from "../v3/section-needle.js";
41
43
  import { buildSectionIndex } from "../v3/sections.js";
42
- import { injectedConceptHeader } from "../v3/substrate/injected-block-slugs.js";
43
- import { slugFromConceptPath } from "../v3/substrate/page-store.js";
44
44
  import type { SectionIndex, Slug } from "../v3/types.js";
45
45
 
46
46
  type DrizzleDb = ReturnType<typeof getDb>;
@@ -14,7 +14,7 @@ export function clampUnitInterval(value: number): number {
14
14
  * `(x + 1) / 2`, then clamp. Single-channel display normalization for the
15
15
  * legacy v1 semantic-search path; do **not** use before hybrid fusion —
16
16
  * the affine rescale halves pairwise dense differences and shifts ranking
17
- * toward sparse. Hybrid fusion (`v2/sim.ts`) instead clamps negative
17
+ * toward sparse. Hybrid fusion (`substrate/sim.ts`) instead clamps negative
18
18
  * cosines to 0 with `Math.max(0, x)` and lets positive cosines pass
19
19
  * through unchanged.
20
20
  */
@@ -13,6 +13,7 @@
13
13
  import { writeFileSync } from "node:fs";
14
14
 
15
15
  import { getConfig } from "../../../config/loader.js";
16
+ import { isMemoryEnabled } from "../../../config/memory-v3-gate.js";
16
17
  import { rehydratePlatformCredentials } from "../../../config/platform-rehydration.js";
17
18
  import { resetDb } from "../../../persistence/db-connection.js";
18
19
  import { disableStreamSeqStamping } from "../../../runtime/assistant-stream-state.js";
@@ -34,7 +35,7 @@ async function main(): Promise<void> {
34
35
  const config = getConfig();
35
36
  const pidPath = getMemoryWorkerPidPath();
36
37
 
37
- if (config.memory.enabled === false) {
38
+ if (!isMemoryEnabled(config)) {
38
39
  log.info("Memory is disabled in config; worker process exiting");
39
40
  process.exit(0);
40
41
  }
@@ -12,6 +12,8 @@
12
12
  * Covers:
13
13
  * - Happy path: model writes valid JSON → structured subject/body, file cleaned up
14
14
  * - Runs in a fresh background conversation
15
+ * - Offers standard conversations as candidates; returns the assistant's chosen
16
+ * id, drops hallucinated ids, excludes surfaced background rows
15
17
  * - Fenced JSON in the file → still parsed
16
18
  * - Model writes nothing → 502
17
19
  * - Model writes JSON missing a field → 502
@@ -32,12 +34,30 @@ import type { RunConversationTurnOptions } from "@vellumai/plugin-api";
32
34
  // prompt).
33
35
  // ---------------------------------------------------------------------------
34
36
 
37
+ interface ConversationRowStub {
38
+ id: string;
39
+ title: string | null;
40
+ conversationType: string;
41
+ }
42
+
43
+ /** JSON the assistant "writes", including its chosen conversation id. */
44
+ function draftJson(conversation: string | null): string {
45
+ return JSON.stringify({
46
+ subject: "Ready when you are",
47
+ body: "Just picking up where we left off.",
48
+ conversation,
49
+ });
50
+ }
51
+
35
52
  let workspaceDir = mkdtempSync(join(tmpdir(), "reengage-test-"));
36
- let fileContents: string | null = JSON.stringify({
37
- subject: "Ready when you are",
38
- body: "Just picking up where we left off.",
39
- });
53
+ let fileContents: string | null = draftJson("conv-42");
40
54
  let lastOptions: RunConversationTurnOptions | undefined;
55
+ // Rows the mocked `listConversations` returns, newest-first — the route filters
56
+ // these to genuine `standard` rows and offers them as link candidates.
57
+ let conversationRows: ConversationRowStub[] = [
58
+ { id: "conv-42", title: "Roadmap planning", conversationType: "standard" },
59
+ ];
60
+ let lastListArgs: unknown[] | undefined;
41
61
 
42
62
  function extractInjectedPath(prompt: string): string {
43
63
  const match = prompt.match(/`([^`]+)`/);
@@ -57,6 +77,10 @@ mock.module("@vellumai/plugin-api", () => ({
57
77
  }
58
78
  return { content: [], userMessageId: "msg-1", conversationId: "conv-1" };
59
79
  },
80
+ listConversations: async (...args: unknown[]) => {
81
+ lastListArgs = args;
82
+ return conversationRows;
83
+ },
60
84
  }));
61
85
 
62
86
  const { POST } = await import("../routes/reengage.js");
@@ -72,23 +96,34 @@ describe("platform-hosted /reengage POST", () => {
72
96
  beforeEach(() => {
73
97
  workspaceDir = mkdtempSync(join(tmpdir(), "reengage-test-"));
74
98
  lastOptions = undefined;
75
- fileContents = JSON.stringify({
76
- subject: "Ready when you are",
77
- body: "Just picking up where we left off.",
78
- });
99
+ lastListArgs = undefined;
100
+ conversationRows = [
101
+ {
102
+ id: "conv-42",
103
+ title: "Roadmap planning",
104
+ conversationType: "standard",
105
+ },
106
+ ];
107
+ fileContents = draftJson("conv-42");
79
108
  });
80
109
 
110
+ function promptText(): string {
111
+ return (lastOptions?.content[0] as { text: string }).text;
112
+ }
113
+
81
114
  test("returns the structured subject/body the model wrote, and cleans up", async () => {
82
115
  const response = await POST(postRequest());
83
116
  expect(response.status).toBe(200);
84
- const json = (await response.json()) as { subject: string; body: string };
117
+ const json = (await response.json()) as {
118
+ subject: string;
119
+ body: string;
120
+ conversation: string | null;
121
+ };
85
122
  expect(json.subject).toBe("Ready when you are");
86
123
  expect(json.body).toBe("Just picking up where we left off.");
87
124
 
88
125
  // The injected file is removed after the handler returns.
89
- const injectedPath = extractInjectedPath(
90
- (lastOptions?.content[0] as { text: string }).text,
91
- );
126
+ const injectedPath = extractInjectedPath(promptText());
92
127
  expect(existsSync(injectedPath)).toBe(false);
93
128
  });
94
129
 
@@ -103,6 +138,63 @@ describe("platform-hosted /reengage POST", () => {
103
138
  expect(lastOptions?.callSite).toBe("inference");
104
139
  });
105
140
 
141
+ test("offers the standard conversations as candidates and returns the chosen id", async () => {
142
+ conversationRows = [
143
+ {
144
+ id: "conv-42",
145
+ title: "Roadmap planning",
146
+ conversationType: "standard",
147
+ },
148
+ { id: "older", title: "Trip notes", conversationType: "standard" },
149
+ ];
150
+ fileContents = draftJson("conv-42");
151
+ const response = await POST(postRequest());
152
+ const json = (await response.json()) as { conversation: string | null };
153
+
154
+ expect(json.conversation).toBe("conv-42");
155
+ // The candidates are offered to the model in the prompt (id + title).
156
+ expect(promptText()).toContain("conv-42: Roadmap planning");
157
+ expect(promptText()).toContain("older: Trip notes");
158
+ // The standard bucket is queried (subagent/background excluded there).
159
+ expect(lastListArgs).toEqual([20, "standard"]);
160
+ });
161
+
162
+ test("drops a chosen id that isn't among the offered candidates", async () => {
163
+ // A hallucinated / stale id the assistant made up is never trusted.
164
+ fileContents = draftJson("made-up-id");
165
+ const response = await POST(postRequest());
166
+ const json = (await response.json()) as { conversation: string | null };
167
+ expect(json.conversation).toBeNull();
168
+ });
169
+
170
+ test("null conversation is returned when the assistant declines to pick", async () => {
171
+ fileContents = draftJson(null);
172
+ const response = await POST(postRequest());
173
+ const json = (await response.json()) as { conversation: string | null };
174
+ expect(json.conversation).toBeNull();
175
+ });
176
+
177
+ test("excludes surfaced background/scheduled rows from the candidates", async () => {
178
+ // `listConversations(…, "standard")` can surface promoted background rows;
179
+ // they are not real chats to re-open, so they are filtered out — never
180
+ // offered, and rejected even if the model somehow names one.
181
+ conversationRows = [
182
+ { id: "surfaced-bg", title: "Heartbeat", conversationType: "background" },
183
+ {
184
+ id: "conv-42",
185
+ title: "Roadmap planning",
186
+ conversationType: "standard",
187
+ },
188
+ ];
189
+ fileContents = draftJson("surfaced-bg");
190
+ const response = await POST(postRequest());
191
+ const json = (await response.json()) as { conversation: string | null };
192
+
193
+ expect(json.conversation).toBeNull();
194
+ expect(promptText()).not.toContain("surfaced-bg");
195
+ expect(promptText()).toContain("conv-42: Roadmap planning");
196
+ });
197
+
106
198
  test("tolerates JSON wrapped in a code fence", async () => {
107
199
  fileContents =
108
200
  '```json\n{"subject": "A quick nudge", "body": "Let me know."}\n```';
@@ -14,12 +14,22 @@
14
14
  * from structured JSON rather than parsed out of the chat reply. The turn runs
15
15
  * in a fresh `background` conversation, so it stays out of the user's visible
16
16
  * chats.
17
+ *
18
+ * The response also carries `conversation` — the id of the conversation the
19
+ * email's "jump back in" link should re-open, or `null`. The assistant chooses
20
+ * it: the prompt offers a list of the owner's recent conversations and asks it
21
+ * to name the one its email is about, and the route returns that id only after
22
+ * validating it against the offered set. See {@link conversationCandidates}.
17
23
  */
18
24
 
19
25
  import { mkdir, readFile, rm } from "node:fs/promises";
20
26
  import { join } from "node:path";
21
27
 
22
- import { getWorkspaceDir, runConversationTurn } from "@vellumai/plugin-api";
28
+ import {
29
+ getWorkspaceDir,
30
+ listConversations,
31
+ runConversationTurn,
32
+ } from "@vellumai/plugin-api";
23
33
 
24
34
  // ---------------------------------------------------------------------------
25
35
  // Output location — the plugin's own data directory
@@ -34,7 +44,15 @@ function pluginDataDir(): string {
34
44
  // Prompt
35
45
  // ---------------------------------------------------------------------------
36
46
 
37
- function buildPrompt(outputPath: string): string {
47
+ function buildPrompt(
48
+ outputPath: string,
49
+ candidates: ConversationCandidate[],
50
+ ): string {
51
+ const conversationList =
52
+ candidates.length > 0
53
+ ? candidates.map((c) => `- ${c.id}: ${c.title}`).join("\n")
54
+ : "(you have no recent conversations)";
55
+
38
56
  return `Compose a short re-engagement email to me, in your own voice as my assistant, to gently draw me back into our work together.
39
57
 
40
58
  Draw on what you know about me and our recent conversations to make it personal and specific — reference something concrete we have been working on, or a next step that is waiting on me, rather than a generic "just checking in." Keep it warm, brief, and low-pressure: a few sentences at most, with no pushy or salesy language.
@@ -43,22 +61,38 @@ When the email is ready, use your file-writing tool to write it to exactly this
43
61
 
44
62
  \`${outputPath}\`
45
63
 
46
- Write ONLY a raw JSON object to that file — no markdown, no code fence, no surrounding prose — with exactly these two string fields:
47
- {"subject": "<the subject line>", "body": "<the plain-text email body>"}
64
+ Write ONLY a raw JSON object to that file — no markdown, no code fence, no surrounding prose — with exactly these fields:
65
+ {"subject": "<the subject line>", "body": "<the plain-text email body>", "conversation": "<id or null>"}
66
+
67
+ The subject should be short and specific. The body is the email itself, written as if you are speaking directly to me.
48
68
 
49
- The subject should be short and specific. The body is the email itself, written as if you are speaking directly to me. The file is the deliverable; do not include the email in your chat reply.`;
69
+ For "conversation", choose the one conversation below that your email is about — the thread I should re-open to pick up where we left off — and use its id exactly as written. If none of them fit what your email references, use null. Never invent an id; only use one from this list:
70
+ ${conversationList}
71
+
72
+ The file is the deliverable; do not include the email in your chat reply.`;
50
73
  }
51
74
 
52
75
  // ---------------------------------------------------------------------------
53
76
  // Parsing
54
77
  // ---------------------------------------------------------------------------
55
78
 
79
+ interface ParsedEmail {
80
+ subject: string;
81
+ body: string;
82
+ /** The conversation id the assistant chose, or `null` for none. */
83
+ conversation: string | null;
84
+ }
85
+
56
86
  /**
57
- * Read `{ subject, body }` out of the JSON the assistant wrote. The instruction
58
- * asks for a bare object, but tolerate a stray code fence or surrounding prose
59
- * by falling back to the first brace-delimited span.
87
+ * Read `{ subject, body, conversation }` out of the JSON the assistant wrote.
88
+ * The instruction asks for a bare object, but tolerate a stray code fence or
89
+ * surrounding prose by falling back to the first brace-delimited span.
90
+ *
91
+ * `conversation` is optional and the id it names is not trusted here — the
92
+ * handler validates it against the offered candidates. A missing value, JSON
93
+ * `null`, or the literal string `"null"` all normalize to `null`.
60
94
  */
61
- function parseEmail(raw: string): { subject: string; body: string } | null {
95
+ function parseEmail(raw: string): ParsedEmail | null {
62
96
  const candidates = [raw.trim()];
63
97
  const brace = raw.match(/\{[\s\S]*\}/);
64
98
  if (brace?.[0]) {
@@ -73,7 +107,12 @@ function parseEmail(raw: string): { subject: string; body: string } | null {
73
107
  typeof record.subject === "string" ? record.subject.trim() : "";
74
108
  const body = typeof record.body === "string" ? record.body.trim() : "";
75
109
  if (subject && body) {
76
- return { subject, body };
110
+ const raw =
111
+ typeof record.conversation === "string"
112
+ ? record.conversation.trim()
113
+ : "";
114
+ const conversation = raw && raw !== "null" ? raw : null;
115
+ return { subject, body, conversation };
77
116
  }
78
117
  }
79
118
  } catch {
@@ -87,6 +126,42 @@ function jsonError(message: string, status: number): Response {
87
126
  return Response.json({ error: { message } }, { status });
88
127
  }
89
128
 
129
+ // ---------------------------------------------------------------------------
130
+ // Conversation candidates for the "jump back in" link
131
+ // ---------------------------------------------------------------------------
132
+
133
+ /** A conversation the assistant may choose to link the email back to. */
134
+ interface ConversationCandidate {
135
+ id: string;
136
+ title: string;
137
+ }
138
+
139
+ /** How many recent conversations to offer the assistant to choose from. */
140
+ const CANDIDATE_LIMIT = 10;
141
+
142
+ /**
143
+ * Recent, genuinely-standard conversations the assistant can pick from for the
144
+ * email's "jump back in" link.
145
+ *
146
+ * The assistant chooses which conversation the email is about (see
147
+ * {@link buildPrompt}), but it has no reliable handle on raw conversation ids —
148
+ * there is no list/search-conversations tool and ids are not in its context —
149
+ * so we hand it real candidates to choose among and validate its pick against
150
+ * this set, rather than trusting a free-formed (hallucinatable) id.
151
+ *
152
+ * `listConversations(…, "standard")` also surfaces background/scheduled rows
153
+ * that were promoted via `surfaced_at`, which are not real chats to re-open, so
154
+ * the result is filtered to rows whose type is actually `"standard"`. That also
155
+ * excludes the drafting turn's own background conversation.
156
+ */
157
+ async function conversationCandidates(): Promise<ConversationCandidate[]> {
158
+ const rows = await listConversations(CANDIDATE_LIMIT * 2, "standard");
159
+ return rows
160
+ .filter((row) => row.conversationType === "standard")
161
+ .slice(0, CANDIDATE_LIMIT)
162
+ .map((row) => ({ id: row.id, title: row.title?.trim() || "Untitled" }));
163
+ }
164
+
90
165
  // ---------------------------------------------------------------------------
91
166
  // Handler
92
167
  // ---------------------------------------------------------------------------
@@ -96,9 +171,13 @@ export const POST = async (request: Request): Promise<Response> => {
96
171
  await mkdir(dir, { recursive: true });
97
172
  const outputPath = join(dir, `reengage-${crypto.randomUUID()}.json`);
98
173
 
174
+ // Offer the assistant real conversations to choose the "jump back in" link
175
+ // from, so the id it writes can be validated against actual chats.
176
+ const candidates = await conversationCandidates();
177
+
99
178
  try {
100
179
  await runConversationTurn({
101
- content: [{ type: "text", text: buildPrompt(outputPath) }],
180
+ content: [{ type: "text", text: buildPrompt(outputPath, candidates) }],
102
181
  conversationType: "background",
103
182
  // Drafting a short email is latency-bound, not depth-bound, so run it on
104
183
  // the fast model rather than the balanced main-agent default. `inference`
@@ -127,7 +206,20 @@ export const POST = async (request: Request): Promise<Response> => {
127
206
  );
128
207
  }
129
208
 
130
- return Response.json(email);
209
+ // Trust the assistant's choice only if it names one of the conversations we
210
+ // offered — never a free-formed id. The platform wraps `body` in a template
211
+ // whose CTA deep-links to this conversation when present, else the
212
+ // assistant root.
213
+ const candidateIds = new Set(candidates.map((c) => c.id));
214
+ const conversation =
215
+ email.conversation && candidateIds.has(email.conversation)
216
+ ? email.conversation
217
+ : null;
218
+ return Response.json({
219
+ subject: email.subject,
220
+ body: email.body,
221
+ conversation,
222
+ });
131
223
  } finally {
132
224
  await rm(outputPath, { force: true });
133
225
  }
@@ -91,8 +91,8 @@ export type {
91
91
  /**
92
92
  * The complete set of compaction circuit-breaker transition events:
93
93
  * `compaction_circuit_open` when the breaker trips and `compaction_circuit_closed`
94
- * on the open→closed transition. Both are a subset of `ServerMessage`, so any
95
- * existing `ServerMessage` sink remains assignable to a
94
+ * on the open→closed transition. Both are a subset of `AssistantEvent`, so any
95
+ * existing `AssistantEvent` sink remains assignable to a
96
96
  * `(msg: CompactionCircuitEvent) => void` parameter.
97
97
  */
98
98
  export type CompactionCircuitEvent =
@@ -3,7 +3,10 @@ import { join } from "node:path";
3
3
 
4
4
  import { parseFrontmatterFields } from "../skills/frontmatter.js";
5
5
  import { getLogger } from "../util/logger.js";
6
- import { getWorkspaceDir, getWorkspacePromptPath } from "../util/platform.js";
6
+ import {
7
+ getWorkspacePromptPath,
8
+ getWorkspaceSystemPromptDir,
9
+ } from "../util/platform.js";
7
10
  import { stripCommentLines } from "../util/strip-comment-lines.js";
8
11
  import {
9
12
  BUNDLED_SYSTEM_SECTIONS,
@@ -25,21 +28,6 @@ const log = getLogger("system-prompt-sections");
25
28
  */
26
29
  export type SectionRenderContext = Record<string, unknown>;
27
30
 
28
- /**
29
- * Workspace override location for user-authored system prompt sections.
30
- * Layout: `<workspace>/prompts/system/<NN-name>.md`.
31
- *
32
- * The bundled section registry (`templates/system-sections.ts`) is the
33
- * source of default truth; this directory is an optional override layer.
34
- * Drop a file with the same id as a bundled section to replace its body,
35
- * or drop a file with a brand-new `<NN-name>` to add a workspace-only
36
- * section. Either path is opt-in — the directory may not exist on a
37
- * fresh install, and the renderer will simply use bundled defaults.
38
- */
39
- export function getWorkspaceSystemPromptDir(): string {
40
- return join(getWorkspaceDir(), "prompts", "system");
41
- }
42
-
43
31
  /**
44
32
  * Render static sections in id-sort order, then dynamic sections in id-sort
45
33
  * order, returning the trimmed bodies of enabled sections grouped into
@@ -1,4 +1,12 @@
1
- import { beforeEach, describe, expect, mock, test } from "bun:test";
1
+ import {
2
+ afterEach,
3
+ beforeEach,
4
+ describe,
5
+ expect,
6
+ mock,
7
+ setSystemTime,
8
+ test,
9
+ } from "bun:test";
2
10
 
3
11
  import { LLMSchema } from "../../config/schemas/llm.js";
4
12
  import type { ProviderConnection } from "../inference/auth.js";
@@ -52,7 +60,6 @@ function makeConfig(): ProvidersConfig {
52
60
  services: {
53
61
  inference: {},
54
62
  "image-generation": {
55
- mode: "your-own",
56
63
  provider: "gemini",
57
64
  model: "gemini-3.1-flash-image-preview",
58
65
  },
@@ -115,6 +122,44 @@ describe("resolveProviderFromConnection native web search selection", () => {
115
122
  });
116
123
  });
117
124
 
125
+ describe("resolveProviderFromConnection connection cache TTL", () => {
126
+ beforeEach(() => {
127
+ adapterCalls.length = 0;
128
+ clearConnectionProviderCache();
129
+ setSystemTime(new Date("2026-01-01T00:00:00Z"));
130
+ });
131
+
132
+ afterEach(() => {
133
+ // Restore the real clock so later suites are not frozen.
134
+ setSystemTime();
135
+ });
136
+
137
+ test("serves a cached provider within the TTL, re-resolves after it expires", async () => {
138
+ // First resolution: a cache miss builds an adapter.
139
+ await resolveProviderFromConnection(openRouterConnection, makeConfig(), {
140
+ model: "anthropic/claude-opus-4-7",
141
+ });
142
+ expect(adapterCalls).toHaveLength(1);
143
+
144
+ // A second resolution 59s later is a cache hit — no new adapter, so the
145
+ // baked-in credential is reused.
146
+ setSystemTime(new Date("2026-01-01T00:00:59Z"));
147
+ await resolveProviderFromConnection(openRouterConnection, makeConfig(), {
148
+ model: "anthropic/claude-opus-4-7",
149
+ });
150
+ expect(adapterCalls).toHaveLength(1);
151
+
152
+ // Past the 60s TTL the entry is stale: the next resolution re-reads the
153
+ // credential and rebuilds the adapter, so a key rotated out-of-band is
154
+ // picked up without any explicit cache invalidation.
155
+ setSystemTime(new Date("2026-01-01T00:01:01Z"));
156
+ await resolveProviderFromConnection(openRouterConnection, makeConfig(), {
157
+ model: "anthropic/claude-opus-4-7",
158
+ });
159
+ expect(adapterCalls).toHaveLength(2);
160
+ });
161
+ });
162
+
118
163
  describe("isNativeWebSearchCapableProvider gateway anthropic routing", () => {
119
164
  test("vercel-ai-gateway anthropic/* models are capable", () => {
120
165
  expect(
@@ -1790,8 +1790,8 @@ export class AnthropicProvider implements Provider {
1790
1790
  ),
1791
1791
  );
1792
1792
 
1793
- // Preserve assistant turns that would otherwise become empty after filtering
1794
- // unknown block types (e.g. ui_surface). Dropping these messages can violate
1793
+ // Preserve assistant turns that would otherwise become empty after
1794
+ // filtering unknown block types. Dropping these messages can violate
1795
1795
  // Anthropic's role alternation requirement.
1796
1796
  if (
1797
1797
  content.length === 0 &&
@@ -1940,10 +1940,13 @@ export class AnthropicProvider implements Provider {
1940
1940
  }
1941
1941
 
1942
1942
  /**
1943
- * Convert a content block to Anthropic format, returning null for unknown
1944
- * block types instead of throwing. Unknown types (e.g. ui_surface stored
1945
- * in DB) are silently dropped so they don't prevent the request from being
1946
- * sent or break tool_use/tool_result pairing.
1943
+ * Convert a content block to Anthropic format, returning null for blocks the
1944
+ * Messages API cannot carry instead of throwing, so they don't prevent the
1945
+ * request from being sent or break tool_use/tool_result pairing.
1946
+ *
1947
+ * Two distinct null cases: `ui_surface` is a known client-rendering block
1948
+ * dropped by design, while a block reaching `default` is genuinely
1949
+ * unrecognised and warns so the gap is visible.
1947
1950
  */
1948
1951
  private toAnthropicBlockSafe(
1949
1952
  block: ContentBlock,
@@ -2086,6 +2089,12 @@ export class AnthropicProvider implements Provider {
2086
2089
  tool_use_id: block.tool_use_id,
2087
2090
  content: block.content,
2088
2091
  } as unknown as Anthropic.ContentBlockParam;
2092
+ case "ui_surface":
2093
+ // A client rendering instruction, not model context. Dropped by
2094
+ // design: the producer's sibling `_surfaceFallback` text block is what
2095
+ // the model reads. `buildSentMessages` projects the surface to text
2096
+ // for legacy rows that have no fallback sibling.
2097
+ return null;
2089
2098
  default: {
2090
2099
  log.warn(
2091
2100
  { blockType: (block as { type: string }).type },