@vellumai/assistant 0.10.4 → 0.10.5-dev.202607022329.d89bf2f

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 (866) hide show
  1. package/ARCHITECTURE.md +94 -91
  2. package/Dockerfile +5 -16
  3. package/README.md +7 -10
  4. package/bun.lock +0 -4
  5. package/docs/architecture/security.md +20 -20
  6. package/docs/stt-provider-onboarding.md +4 -5
  7. package/docs/trusted-contact-access.md +7 -7
  8. package/eslint-rules/cli-no-daemon-internals.js +4 -0
  9. package/eslint.config.mjs +7 -1
  10. package/knip.json +0 -1
  11. package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +36 -0
  12. package/node_modules/@vellumai/gateway-client/src/__tests__/invite-contract.test.ts +233 -0
  13. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +40 -0
  14. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -8
  15. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
  16. package/node_modules/@vellumai/gateway-client/src/index.ts +33 -0
  17. package/node_modules/@vellumai/gateway-client/src/invite-contract.ts +216 -0
  18. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +91 -0
  19. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +39 -3
  20. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +0 -8
  21. package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +1 -5
  22. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +3 -14
  23. package/openapi.yaml +1073 -225
  24. package/package.json +1 -4
  25. package/scripts/test.sh +35 -13
  26. package/src/__tests__/access-request-seed-content-blocks.test.ts +60 -4
  27. package/src/__tests__/acp-session.test.ts +4 -1
  28. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +0 -6
  29. package/src/__tests__/add-message-preassigned-id.test.ts +56 -0
  30. package/src/__tests__/agent-loop-set-system-prompt.test.ts +139 -0
  31. package/src/__tests__/app-conversation-ids-backfill.test.ts +3 -0
  32. package/src/__tests__/app-source-watcher.test.ts +11 -0
  33. package/src/__tests__/approval-interception-trust-gates.test.ts +148 -3
  34. package/src/__tests__/assistant-attachments.test.ts +62 -4
  35. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -1
  36. package/src/__tests__/attachments-store-heic-normalize.test.ts +230 -0
  37. package/src/__tests__/attachments-store.test.ts +3 -0
  38. package/src/__tests__/background-shell-bash.test.ts +34 -0
  39. package/src/__tests__/background-shell-host-bash.test.ts +12 -0
  40. package/src/__tests__/background-tool-registry.test.ts +97 -0
  41. package/src/__tests__/background-tool-routes.test.ts +72 -1
  42. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
  43. package/src/__tests__/btw-routes.test.ts +57 -3
  44. package/src/__tests__/call-controller.test.ts +474 -84
  45. package/src/__tests__/call-domain.test.ts +48 -1
  46. package/src/__tests__/call-pointer-messages.test.ts +57 -19
  47. package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +2 -6
  48. package/src/__tests__/call-routes-http.test.ts +15 -14
  49. package/src/__tests__/call-setup-flow-invite.test.ts +568 -0
  50. package/src/__tests__/call-setup-flow-midcall-trust.test.ts +231 -0
  51. package/src/__tests__/call-setup-flow-name-capture.test.ts +754 -0
  52. package/src/__tests__/call-setup-flow-verification.test.ts +925 -0
  53. package/src/__tests__/call-setup-flow.test.ts +311 -0
  54. package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -1
  55. package/src/__tests__/channel-guardian.test.ts +4 -7
  56. package/src/__tests__/channel-readiness-service.test.ts +0 -6
  57. package/src/__tests__/channel-readiness-slack-remote.test.ts +0 -4
  58. package/src/__tests__/channel-retry-sweep.test.ts +76 -64
  59. package/src/__tests__/channel-setup-panel-ack.test.ts +184 -0
  60. package/src/__tests__/clear-all-lexical.test.ts +90 -0
  61. package/src/__tests__/compactor-media-strip.test.ts +177 -0
  62. package/src/__tests__/config-loader-backfill.test.ts +5 -5
  63. package/src/__tests__/config-schema.test.ts +17 -0
  64. package/src/__tests__/contact-store-interaction-info.test.ts +27 -70
  65. package/src/__tests__/contacts-relay-reads.test.ts +188 -23
  66. package/src/__tests__/contacts-tools.test.ts +42 -1
  67. package/src/__tests__/contacts-write.test.ts +181 -0
  68. package/src/__tests__/context-search-conversations-source.test.ts +220 -81
  69. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
  70. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  71. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  72. package/src/__tests__/conversation-agent-loop.test.ts +39 -0
  73. package/src/__tests__/conversation-analysis-routes.test.ts +1 -1
  74. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -0
  75. package/src/__tests__/conversation-clear-safety.test.ts +0 -1
  76. package/src/__tests__/conversation-crud-enabled-plugins.test.ts +60 -0
  77. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -1
  78. package/src/__tests__/conversation-disk-view.test.ts +1 -0
  79. package/src/__tests__/conversation-enabledplugins-route.test.ts +184 -0
  80. package/src/__tests__/conversation-error.test.ts +0 -18
  81. package/src/__tests__/conversation-fork-crud.test.ts +67 -0
  82. package/src/__tests__/conversation-history-web-search.test.ts +7 -137
  83. package/src/__tests__/conversation-initial-prompt.test.ts +110 -0
  84. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +191 -0
  85. package/src/__tests__/conversation-process-callsite.test.ts +37 -0
  86. package/src/__tests__/conversation-queue.test.ts +149 -0
  87. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +392 -0
  88. package/src/__tests__/conversation-routes-guardian-reply.test.ts +84 -0
  89. package/src/__tests__/conversation-routes-hidden-queue.test.ts +407 -0
  90. package/src/__tests__/conversation-runtime-assembly.test.ts +36 -16
  91. package/src/__tests__/conversation-skill-tools.test.ts +73 -0
  92. package/src/__tests__/conversation-wipe.test.ts +20 -5
  93. package/src/__tests__/credential-prompt-route.test.ts +69 -0
  94. package/src/__tests__/credential-security-invariants.test.ts +1 -3
  95. package/src/__tests__/db-drop-messages-fts.test.ts +115 -0
  96. package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -62
  97. package/src/__tests__/edit-propagation.test.ts +56 -2
  98. package/src/__tests__/empty-state-greeting-cache.test.ts +9 -0
  99. package/src/__tests__/gateway-only-enforcement.test.ts +15 -110
  100. package/src/__tests__/guardian-expiry-notifier.test.ts +1 -0
  101. package/src/__tests__/guardian-question-mode.test.ts +57 -0
  102. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
  103. package/src/__tests__/guardian-wait-controller.test.ts +619 -0
  104. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +33 -2
  105. package/src/__tests__/heic-fixture.ts +55 -0
  106. package/src/__tests__/helpers/seed-contact-channel.ts +0 -2
  107. package/src/__tests__/http-conversation-lineage.test.ts +6 -1
  108. package/src/__tests__/image-conversion.test.ts +170 -0
  109. package/src/__tests__/inbound-invite-redemption.test.ts +72 -341
  110. package/src/__tests__/introduction-card-resolver.test.ts +354 -0
  111. package/src/__tests__/invite-redeemed-ipc.test.ts +97 -0
  112. package/src/__tests__/invite-routes-http.test.ts +246 -420
  113. package/src/__tests__/job-handler-registration-guard.test.ts +104 -0
  114. package/src/__tests__/lexical-index-dual-write.test.ts +426 -0
  115. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +2 -2
  116. package/src/__tests__/list-messages-attachments.test.ts +159 -0
  117. package/src/__tests__/list-messages-background-tool-completion.test.ts +141 -0
  118. package/src/__tests__/list-messages-queued.test.ts +25 -0
  119. package/src/__tests__/managed-store.test.ts +129 -1
  120. package/src/__tests__/media-stream-audio-transcode.test.ts +113 -0
  121. package/src/__tests__/media-stream-output.test.ts +350 -19
  122. package/src/__tests__/media-stream-server-integration.test.ts +943 -169
  123. package/src/__tests__/media-stream-stt-session.test.ts +498 -1
  124. package/src/__tests__/memory-jobs-worker-lanes.test.ts +2 -2
  125. package/src/__tests__/model-intents.test.ts +1 -1
  126. package/src/__tests__/mtime-cache.test.ts +19 -0
  127. package/src/__tests__/non-member-access-request.test.ts +349 -3
  128. package/src/__tests__/notification-decision-fallback.test.ts +104 -8
  129. package/src/__tests__/notification-decision-strategy.test.ts +57 -8
  130. package/src/__tests__/onboarding-template-contract.test.ts +27 -43
  131. package/src/__tests__/openai-provider.test.ts +33 -0
  132. package/src/__tests__/openai-responses-provider.test.ts +40 -0
  133. package/src/__tests__/persistence-layering-guard.test.ts +29 -20
  134. package/src/__tests__/persona-resolver.test.ts +56 -2
  135. package/src/__tests__/personal-memory-auth-bypass.test.ts +62 -0
  136. package/src/__tests__/phone.test.ts +1 -15
  137. package/src/__tests__/plugin-bootstrap.test.ts +25 -196
  138. package/src/__tests__/plugin-disabled-state.test.ts +33 -0
  139. package/src/__tests__/plugin-effective-enabled-set.test.ts +227 -0
  140. package/src/__tests__/plugin-event-hub-facade.test.ts +323 -0
  141. package/src/__tests__/plugin-import-boundary-guard.test.ts +156 -42
  142. package/src/__tests__/plugin-injector-contribution.test.ts +4 -20
  143. package/src/__tests__/plugin-pipeline.test.ts +63 -1
  144. package/src/__tests__/plugin-route-contribution.test.ts +62 -115
  145. package/src/__tests__/plugin-tool-contribution.test.ts +0 -22
  146. package/src/__tests__/plugin-types.test.ts +0 -1
  147. package/src/__tests__/pointer-conversation-trust.test.ts +38 -6
  148. package/src/__tests__/pre-model-call-sanitize.test.ts +1 -1
  149. package/src/__tests__/prune-old-tool-invocations-job.test.ts +97 -0
  150. package/src/__tests__/public-ingress-urls.test.ts +0 -48
  151. package/src/__tests__/qdrant-collection-migration.test.ts +145 -2
  152. package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +0 -1
  153. package/src/__tests__/resolve-trust-class.test.ts +28 -10
  154. package/src/__tests__/scaffold-managed-skill-tool.test.ts +137 -0
  155. package/src/__tests__/schedule-retry.test.ts +38 -14
  156. package/src/__tests__/schedule-routes-workflow-validation.test.ts +3 -3
  157. package/src/__tests__/schedule-routes.test.ts +14 -6
  158. package/src/__tests__/schedule-store.test.ts +3 -1
  159. package/src/__tests__/scheduler-disk-pressure.test.ts +17 -6
  160. package/src/__tests__/scheduler-recurrence.test.ts +57 -107
  161. package/src/__tests__/scheduler-reuse-conversation.test.ts +51 -46
  162. package/src/__tests__/scheduler-wake.test.ts +13 -23
  163. package/src/__tests__/scheduler-worker-standdown.test.ts +220 -0
  164. package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
  165. package/src/__tests__/shell-observability.test.ts +1 -0
  166. package/src/__tests__/skill-boundary-guard.test.ts +3 -4
  167. package/src/__tests__/skill-load-plugin-scope.test.ts +238 -0
  168. package/src/__tests__/skill-projection-feature-flag.test.ts +2 -0
  169. package/src/__tests__/skill-script-runner-host.test.ts +53 -0
  170. package/src/__tests__/skill-script-runner-sandbox.test.ts +5 -2
  171. package/src/__tests__/skill-tool-factory.test.ts +73 -1
  172. package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -14
  173. package/src/__tests__/slack-inbound-verification.test.ts +36 -0
  174. package/src/__tests__/slack-notification-approval-card.test.ts +89 -2
  175. package/src/__tests__/slack-reaction-canonical-approval.test.ts +51 -1
  176. package/src/__tests__/stt-hints.test.ts +2 -256
  177. package/src/__tests__/subagent-allowlist-validation.test.ts +47 -0
  178. package/src/__tests__/subagent-call-site-routing.test.ts +72 -0
  179. package/src/__tests__/subagent-fork-notifications.test.ts +14 -2
  180. package/src/__tests__/subagent-persistence.test.ts +122 -0
  181. package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
  182. package/src/__tests__/subagent-terminal-message.test.ts +99 -0
  183. package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -1
  184. package/src/__tests__/system-prompt.test.ts +17 -118
  185. package/src/__tests__/task-scheduler.test.ts +68 -89
  186. package/src/__tests__/telephony-credential-preflight.test.ts +312 -0
  187. package/src/__tests__/telephony-tts-guard.test.ts +538 -0
  188. package/src/__tests__/title-generate-hook.test.ts +16 -0
  189. package/src/__tests__/tool-approval-handler.test.ts +87 -1
  190. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +45 -20
  191. package/src/__tests__/tool-grant-request-escalation.test.ts +39 -0
  192. package/src/__tests__/trust-context-guards.test.ts +21 -10
  193. package/src/__tests__/trusted-contact-multichannel.test.ts +4 -0
  194. package/src/__tests__/twilio-provider.test.ts +17 -17
  195. package/src/__tests__/twilio-routes-twiml.test.ts +6 -543
  196. package/src/__tests__/twilio-routes.test.ts +257 -387
  197. package/src/__tests__/twilio-validation.test.ts +1 -1
  198. package/src/__tests__/unified-turn-context-client-os.test.ts +45 -0
  199. package/src/__tests__/usage-cache-backfill-migration.test.ts +5 -0
  200. package/src/__tests__/voice-approval-resolver-relay.test.ts +150 -0
  201. package/src/__tests__/voice-ingress-preflight.test.ts +61 -0
  202. package/src/__tests__/voice-quality.test.ts +2 -2
  203. package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -7
  204. package/src/__tests__/voice-session-bridge-processing-wait.test.ts +27 -0
  205. package/src/__tests__/voice-session-bridge.test.ts +1 -10
  206. package/src/__tests__/workspace-git-service.test.ts +1 -1
  207. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -0
  208. package/src/__tests__/workspace-migration-118-seed-now-md.test.ts +120 -0
  209. package/src/__tests__/workspace-migration-120-revise-onboarding-threads.test.ts +175 -0
  210. package/src/__tests__/workspace-migration-121-seed-default-user-guardrails.test.ts +118 -0
  211. package/src/__tests__/workspace-migration-122-relocate-default-user-boundary.test.ts +119 -0
  212. package/src/__tests__/workspace-migration-123-swap-quality-profile-to-fable.test.ts +191 -0
  213. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +235 -241
  214. package/src/acp/__tests__/prepare-agent-env.test.ts +0 -97
  215. package/src/acp/__tests__/session-manager-persistence.test.ts +2 -0
  216. package/src/acp/__tests__/session-manager-resume.test.ts +8 -0
  217. package/src/acp/__tests__/session-manager-usage.test.ts +6 -0
  218. package/src/acp/__tests__/session-manager.test.ts +6 -0
  219. package/src/acp/agent-process.test.ts +116 -0
  220. package/src/acp/agent-process.ts +71 -0
  221. package/src/acp/auto-install.ts +12 -8
  222. package/src/acp/failure-error.test.ts +109 -0
  223. package/src/acp/failure-error.ts +111 -0
  224. package/src/acp/prepare-agent-env.ts +0 -12
  225. package/src/acp/resolve-agent.test.ts +6 -45
  226. package/src/acp/resolve-agent.ts +2 -4
  227. package/src/acp/session-manager.test.ts +312 -0
  228. package/src/acp/session-manager.ts +102 -46
  229. package/src/agent/ax-tree-compaction.test.ts +4 -1
  230. package/src/agent/image-optimize.ts +17 -127
  231. package/src/agent/loop.ts +45 -192
  232. package/src/api/events/background-tool-completed.test.ts +51 -0
  233. package/src/api/events/background-tool-completed.ts +29 -0
  234. package/src/api/events/background-tool-started.test.ts +36 -0
  235. package/src/api/events/background-tool-started.ts +28 -0
  236. package/src/api/events/conversation-error.ts +0 -1
  237. package/src/api/events/open-panel.ts +33 -0
  238. package/src/api/events/subagent-status-changed.ts +4 -1
  239. package/src/api/index.ts +19 -0
  240. package/src/api/responses/conversation-message.ts +34 -0
  241. package/src/approvals/guardian-decision-primitive.ts +74 -24
  242. package/src/approvals/guardian-request-resolvers.ts +450 -122
  243. package/src/apps/app-store.ts +1 -0
  244. package/src/apps/shared-app-links-store.ts +1 -0
  245. package/src/avatar/identity-avatar.ts +3 -7
  246. package/src/background-wake/wake-intent-hooks.test.ts +1 -1
  247. package/src/calls/__tests__/fish-audio-client.test.ts +73 -0
  248. package/src/calls/__tests__/gateway-invite-reader.test.ts +170 -0
  249. package/src/calls/__tests__/relay-setup-router.test.ts +126 -102
  250. package/src/calls/call-controller.ts +134 -48
  251. package/src/calls/call-domain.ts +18 -42
  252. package/src/calls/call-pointer-messages.ts +51 -67
  253. package/src/calls/call-setup-flow-types.ts +76 -0
  254. package/src/calls/call-setup-flow.ts +1743 -0
  255. package/src/calls/call-speech-output.ts +87 -23
  256. package/src/calls/call-store.ts +4 -0
  257. package/src/calls/call-transport.ts +22 -36
  258. package/src/calls/fish-audio-client.ts +3 -0
  259. package/src/calls/gateway-invite-reader.ts +98 -0
  260. package/src/calls/guardian-wait-controller.ts +451 -0
  261. package/src/calls/media-stream-audio-transcode.ts +82 -2
  262. package/src/calls/media-stream-output.ts +142 -36
  263. package/src/calls/media-stream-server.ts +297 -178
  264. package/src/calls/media-stream-stt-session.ts +393 -50
  265. package/src/calls/media-turn-detector.ts +4 -6
  266. package/src/calls/relay-access-wait.ts +3 -4
  267. package/src/calls/relay-setup-router.ts +22 -43
  268. package/src/calls/relay-verification.ts +17 -24
  269. package/src/calls/resolve-call-tts-provider.ts +96 -29
  270. package/src/calls/stt-hints.ts +24 -87
  271. package/src/calls/telephony-credential-preflight.ts +159 -0
  272. package/src/calls/telephony-tts-capability.ts +183 -0
  273. package/src/calls/tts-call-strategy.ts +18 -20
  274. package/src/calls/twilio-provider.ts +3 -2
  275. package/src/calls/twilio-routes.ts +47 -351
  276. package/src/calls/types.ts +5 -3
  277. package/src/calls/voice-ingress-preflight.ts +9 -0
  278. package/src/calls/voice-quality.ts +13 -18
  279. package/src/calls/voice-session-bridge.ts +25 -35
  280. package/src/channels/__tests__/types.test.ts +28 -0
  281. package/src/channels/channel-verification-sessions.ts +7 -2
  282. package/src/channels/config.ts +0 -42
  283. package/src/channels/slack-thread-store.ts +12 -0
  284. package/src/channels/types.ts +23 -0
  285. package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -1
  286. package/src/cli/commands/__tests__/schedules.test.ts +83 -34
  287. package/src/cli/commands/__tests__/status.test.ts +42 -2
  288. package/src/cli/commands/contacts.ts +2 -2
  289. package/src/cli/commands/credentials.ts +17 -0
  290. package/src/cli/commands/monitoring.ts +191 -0
  291. package/src/cli/commands/schedules-worker.ts +175 -0
  292. package/src/cli/commands/schedules.ts +169 -43
  293. package/src/cli/commands/status.ts +12 -1
  294. package/src/cli/commands/tools.ts +5 -1
  295. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +1 -0
  296. package/src/cli/lib/__tests__/search-plugins.test.ts +29 -1
  297. package/src/cli/lib/__tests__/toggle-plugin.test.ts +7 -0
  298. package/src/cli/lib/search-plugins.ts +6 -0
  299. package/src/cli/lib/toggle-plugin.ts +21 -2
  300. package/src/cli/program.ts +3 -1
  301. package/src/config/__tests__/deployment-context-defaults.test.ts +23 -0
  302. package/src/config/acp-defaults.test.ts +0 -10
  303. package/src/config/acp-defaults.ts +0 -6
  304. package/src/config/bundled-skills/acp/SKILL.md +13 -45
  305. package/src/config/bundled-skills/acp/TOOLS.json +3 -3
  306. package/src/config/bundled-skills/app-builder/SKILL.md +3 -3
  307. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +9 -9
  308. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +1 -1
  309. package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -1
  310. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
  311. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -9
  312. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +10 -7
  313. package/src/config/bundled-skills/skill-management/TOOLS.json +10 -0
  314. package/src/config/call-site-defaults.ts +0 -2
  315. package/src/config/feature-flag-registry.json +16 -8
  316. package/src/config/loader.ts +11 -0
  317. package/src/config/schema.ts +9 -1
  318. package/src/config/schemas/__tests__/memory-v2.test.ts +2 -2
  319. package/src/config/schemas/__tests__/memory-v3.test.ts +64 -0
  320. package/src/config/schemas/call-site-catalog.ts +0 -12
  321. package/src/config/schemas/calls.ts +8 -0
  322. package/src/config/schemas/elevenlabs.ts +1 -1
  323. package/src/config/schemas/llm.ts +0 -2
  324. package/src/config/schemas/memory-v2.ts +1 -1
  325. package/src/config/schemas/memory-v3.ts +82 -0
  326. package/src/config/schemas/monitoring.ts +61 -0
  327. package/src/config/schemas/schedules.ts +35 -0
  328. package/src/config/seed-inference-profiles.ts +2 -2
  329. package/src/config/skills-plugin-filter.test.ts +96 -0
  330. package/src/config/skills.ts +26 -0
  331. package/src/contacts/__tests__/member-write-relay.test.ts +156 -4
  332. package/src/contacts/canonical-guardian-store.ts +5 -0
  333. package/src/contacts/contact-store.ts +81 -35
  334. package/src/contacts/contacts-write.ts +50 -25
  335. package/src/contacts/member-write-relay.ts +115 -31
  336. package/src/contacts/types.ts +0 -8
  337. package/src/context/compactor.ts +29 -15
  338. package/src/context/outbound-sanitize.ts +202 -0
  339. package/src/daemon/__tests__/abort-null-controller.test.ts +167 -0
  340. package/src/daemon/__tests__/conversation-tool-setup-plugin-scope.test.ts +122 -0
  341. package/src/daemon/__tests__/embedding-reconcile.test.ts +99 -16
  342. package/src/daemon/__tests__/wake-conversation-ops-completion.test.ts +107 -0
  343. package/src/daemon/abort-watchdog.ts +7 -0
  344. package/src/daemon/app-source-watcher.ts +9 -0
  345. package/src/daemon/assistant-attachments.ts +42 -0
  346. package/src/daemon/conversation-agent-loop-handlers.ts +256 -147
  347. package/src/daemon/conversation-agent-loop.ts +61 -68
  348. package/src/daemon/conversation-error.ts +1 -15
  349. package/src/daemon/conversation-history.ts +32 -236
  350. package/src/daemon/conversation-initial-prompt.ts +77 -0
  351. package/src/daemon/conversation-lifecycle.ts +25 -1
  352. package/src/daemon/conversation-messaging.ts +2 -2
  353. package/src/daemon/conversation-plugin-scope.ts +38 -0
  354. package/src/daemon/conversation-process.ts +50 -14
  355. package/src/daemon/conversation-runtime-assembly.ts +36 -6
  356. package/src/daemon/conversation-skill-tools.ts +19 -3
  357. package/src/daemon/conversation-store.ts +3 -3
  358. package/src/daemon/conversation-surfaces.ts +171 -0
  359. package/src/daemon/conversation-tool-setup.test.ts +95 -0
  360. package/src/daemon/conversation-tool-setup.ts +116 -1
  361. package/src/daemon/conversation-turn-finalize.ts +211 -0
  362. package/src/daemon/conversation.ts +92 -1
  363. package/src/daemon/disk-pressure-policy.ts +2 -1
  364. package/src/daemon/event-loop-watchdog.ts +22 -6
  365. package/src/daemon/external-plugins-bootstrap.ts +47 -134
  366. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
  367. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +26 -14
  368. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +27 -14
  369. package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -5
  370. package/src/daemon/handlers/config-a2a.ts +7 -14
  371. package/src/daemon/handlers/config-channels.ts +2 -10
  372. package/src/daemon/handlers/conversation-history.ts +3 -1
  373. package/src/daemon/handlers/conversations.ts +0 -52
  374. package/src/daemon/handlers/shared.ts +4 -24
  375. package/src/daemon/handlers/skills.ts +4 -1
  376. package/src/daemon/host-cu-proxy.ts +1 -1
  377. package/src/daemon/lifecycle.ts +59 -472
  378. package/src/daemon/message-protocol.ts +3 -3
  379. package/src/daemon/message-provenance.ts +12 -14
  380. package/src/daemon/message-types/background-tools.ts +28 -0
  381. package/src/daemon/message-types/contacts.ts +2 -10
  382. package/src/daemon/message-types/conversations.ts +10 -0
  383. package/src/daemon/message-types/integrations.ts +2 -0
  384. package/src/daemon/message-types/surfaces.ts +1 -0
  385. package/src/daemon/message-types/sync.ts +1 -0
  386. package/src/daemon/pointer-conversation-trust.ts +23 -9
  387. package/src/daemon/pointer-turn-runner.ts +174 -0
  388. package/src/daemon/providers-setup.ts +16 -0
  389. package/src/daemon/shutdown-handlers.ts +139 -47
  390. package/src/daemon/skill-memory-refresh.ts +2 -2
  391. package/src/daemon/sqlite-corruption-watchdog.test.ts +217 -0
  392. package/src/daemon/sqlite-corruption-watchdog.ts +155 -0
  393. package/src/daemon/tool-setup-types.ts +8 -0
  394. package/src/daemon/trust-context.ts +21 -6
  395. package/src/daemon/turn-latency-tracker.test.ts +93 -0
  396. package/src/daemon/turn-latency-tracker.ts +38 -0
  397. package/src/daemon/wake-conversation-ops.ts +10 -8
  398. package/src/documents/document-comments-store.test.ts +7 -1
  399. package/src/documents/document-comments-store.ts +8 -0
  400. package/src/documents/document-store.ts +15 -0
  401. package/src/export/__tests__/transcript-formatter.test.ts +11 -0
  402. package/src/export/transcript-formatter.ts +49 -67
  403. package/src/home/__tests__/feed-writer.test.ts +247 -1
  404. package/src/home/conversation-starter-checkpoints.ts +1 -0
  405. package/src/home/feed-writer.ts +61 -0
  406. package/src/home/job-handlers/conversation-starters.ts +1 -0
  407. package/src/hooks/hook-loader.ts +12 -0
  408. package/src/hooks/registry.ts +32 -4
  409. package/src/inbound/public-ingress-urls.ts +0 -17
  410. package/src/ipc/__tests__/contacts-info-ipc.test.ts +285 -0
  411. package/src/ipc/assistant-server.ts +28 -7
  412. package/src/ipc/routes/__tests__/contacts-mirror-apply-atomicity.test.ts +62 -0
  413. package/src/ipc/routes/__tests__/contacts-mirror-apply.test.ts +272 -0
  414. package/src/ipc/routes/__tests__/contacts-mirror-ipc-routes.test.ts +322 -0
  415. package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +60 -4
  416. package/src/ipc/routes/contacts-info-ipc-routes.ts +239 -0
  417. package/src/ipc/routes/contacts-mirror-ipc-routes.ts +202 -0
  418. package/src/ipc/routes/db-proxy.ts +5 -2
  419. package/src/ipc/routes/invite-ipc-routes.ts +53 -39
  420. package/src/jobs/worker.ts +9 -2
  421. package/src/live-voice/__tests__/live-voice-archive.test.ts +10 -1
  422. package/src/live-voice/live-voice-archive.ts +5 -0
  423. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +22 -6
  424. package/src/messaging/providers/channel-transport.ts +6 -0
  425. package/src/messaging/providers/index.ts +3 -0
  426. package/src/messaging/providers/slack/api.test.ts +49 -1
  427. package/src/messaging/providers/slack/api.ts +110 -0
  428. package/src/messaging/providers/slack/send.test.ts +85 -0
  429. package/src/messaging/providers/slack/send.ts +100 -28
  430. package/src/messaging/providers/slack/transport.ts +7 -13
  431. package/src/messaging/providers/whatsapp/send.ts +29 -9
  432. package/src/monitoring/__tests__/control.test.ts +235 -0
  433. package/src/monitoring/__tests__/sample-ring-buffer.test.ts +96 -0
  434. package/src/monitoring/control.ts +105 -0
  435. package/src/monitoring/resource-sampler.ts +258 -0
  436. package/src/monitoring/sample-ring-buffer.ts +108 -0
  437. package/src/monitoring/worker.ts +94 -0
  438. package/src/notifications/README.md +1 -1
  439. package/src/notifications/access-request-copy.ts +94 -23
  440. package/src/notifications/adapters/slack.ts +89 -21
  441. package/src/notifications/approval-card-builder.ts +33 -18
  442. package/src/notifications/approval-card-data.ts +48 -15
  443. package/src/notifications/broadcaster.ts +25 -16
  444. package/src/notifications/decision-engine.ts +131 -32
  445. package/src/notifications/guardian-question-mode.ts +58 -10
  446. package/src/permissions/approval-policy.ts +8 -1
  447. package/src/permissions/checker.ts +2 -0
  448. package/src/permissions/gateway-threshold-reader.ts +7 -6
  449. package/src/permissions/ipc-risk-types.ts +1 -0
  450. package/src/permissions/secret-prompter.ts +11 -3
  451. package/src/permissions/types.ts +2 -2
  452. package/src/persistence/__tests__/conversation-queries-search.test.ts +397 -0
  453. package/src/persistence/__tests__/conversation-search-lexical.test.ts +103 -0
  454. package/src/persistence/__tests__/jobs-worker-memory-disabled.test.ts +95 -0
  455. package/src/persistence/__tests__/slow-query-log.test.ts +266 -0
  456. package/src/persistence/__tests__/slow-sync-log.test.ts +155 -0
  457. package/src/persistence/a2a-invite-store.ts +205 -0
  458. package/src/persistence/attachments-store.ts +94 -10
  459. package/src/persistence/checkpoints.ts +45 -0
  460. package/src/persistence/conversation-crud.ts +453 -260
  461. package/src/persistence/conversation-display-order-migration.ts +8 -2
  462. package/src/persistence/conversation-group-migration.test.ts +8 -0
  463. package/src/persistence/conversation-group-migration.ts +9 -0
  464. package/src/persistence/conversation-queries.ts +244 -125
  465. package/src/persistence/conversation-row-batch-delete.ts +9 -5
  466. package/src/persistence/conversation-search-lexical.ts +49 -0
  467. package/src/persistence/db-async-query.ts +42 -0
  468. package/src/persistence/db-connection.ts +13 -0
  469. package/src/persistence/delivery-channels.ts +0 -82
  470. package/src/persistence/delivery-crud.ts +27 -6
  471. package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +18 -5
  472. package/src/persistence/embeddings/__tests__/messages-lexical-index.test.ts +334 -0
  473. package/src/persistence/embeddings/embedding-identity.ts +17 -5
  474. package/src/persistence/embeddings/embedding-runtime-manager.ts +31 -0
  475. package/src/persistence/embeddings/messages-lexical-index.ts +396 -0
  476. package/src/persistence/embeddings/qdrant-client.ts +81 -5
  477. package/src/persistence/group-crud.ts +13 -1
  478. package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +506 -0
  479. package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +164 -0
  480. package/src/persistence/job-handlers/__tests__/message-lexical.test.ts +259 -0
  481. package/src/persistence/job-handlers/cleanup.ts +57 -9
  482. package/src/persistence/job-handlers/message-lexical-backfill.ts +187 -0
  483. package/src/persistence/job-handlers/message-lexical.ts +251 -0
  484. package/src/persistence/jobs-store.ts +102 -8
  485. package/src/persistence/jobs-worker.ts +68 -28
  486. package/src/persistence/llm-request-log-store.ts +35 -19
  487. package/src/persistence/llm-usage-store.ts +11 -0
  488. package/src/persistence/memory-lifecycle-hooks.test.ts +65 -0
  489. package/src/persistence/memory-lifecycle-hooks.ts +55 -1
  490. package/src/persistence/migrations/028-call-session-mode.ts +1 -1
  491. package/src/persistence/migrations/116-messages-fts.ts +8 -1
  492. package/src/persistence/migrations/311-create-subagents-table.ts +50 -0
  493. package/src/persistence/migrations/312-drop-inbox-conversation-state-table.ts +15 -0
  494. package/src/persistence/migrations/313-drop-messages-fts.ts +17 -0
  495. package/src/persistence/migrations/314-add-conversation-enabled-plugins.ts +25 -0
  496. package/src/persistence/migrations/315-create-a2a-invites.ts +58 -0
  497. package/src/persistence/migrations/316-drop-contact-channels-invite-id.ts +28 -0
  498. package/src/persistence/migrations/317-canonical-guardian-requester-signals.ts +24 -0
  499. package/src/persistence/migrations/318-drop-contact-channel-telemetry.ts +32 -0
  500. package/src/persistence/migrations/__tests__/315-create-a2a-invites.test.ts +161 -0
  501. package/src/persistence/migrations/__tests__/316-drop-contact-channels-invite-id.test.ts +156 -0
  502. package/src/persistence/migrations/__tests__/318-drop-contact-channel-telemetry.test.ts +134 -0
  503. package/src/persistence/migrations/__tests__/migration-prefix-guard.test.ts +99 -0
  504. package/src/persistence/raw-query.ts +50 -11
  505. package/src/persistence/schema/a2a.ts +14 -0
  506. package/src/persistence/schema/contacts.ts +0 -62
  507. package/src/persistence/schema/conversation-groups.ts +12 -0
  508. package/src/persistence/schema/conversations.ts +2 -0
  509. package/src/persistence/schema/documents.ts +65 -0
  510. package/src/persistence/schema/guardian.ts +4 -0
  511. package/src/persistence/schema/index.ts +4 -0
  512. package/src/persistence/schema/memory-injection.ts +62 -0
  513. package/src/persistence/schema/workflows.ts +55 -0
  514. package/src/persistence/slow-query-log.ts +437 -0
  515. package/src/persistence/slow-sync-log.ts +204 -0
  516. package/src/persistence/steps.ts +16 -0
  517. package/src/persistence/subagent-store.ts +125 -0
  518. package/src/persistence/worker-control.ts +45 -238
  519. package/src/plugin-api/event-hub-facade.ts +172 -0
  520. package/src/plugin-api/index.ts +9 -1
  521. package/src/plugin-api/types.ts +40 -9
  522. package/src/plugins/defaults/default-plugin-names.ts +60 -0
  523. package/src/plugins/defaults/index.ts +19 -29
  524. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +46 -67
  525. package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +36 -1
  526. package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +2 -4
  527. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +2 -2
  528. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +9 -0
  529. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +7 -4
  530. package/src/plugins/defaults/memory/config.ts +11 -0
  531. package/src/plugins/defaults/memory/context-search/agent-runner.ts +1 -1
  532. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +124 -113
  533. package/src/plugins/defaults/memory/embeddings.ts +77 -0
  534. package/src/plugins/defaults/memory/find-most-recent-retrospective-for.ts +66 -0
  535. package/src/plugins/defaults/memory/frontmatter.ts +50 -0
  536. package/src/plugins/defaults/memory/graph/bootstrap.test.ts +36 -10
  537. package/src/plugins/defaults/memory/graph/bootstrap.ts +6 -5
  538. package/src/plugins/defaults/memory/graph/consolidation.ts +3 -5
  539. package/src/plugins/defaults/memory/graph/extraction.ts +3 -6
  540. package/src/plugins/defaults/memory/graph/graph-search.ts +12 -23
  541. package/src/plugins/defaults/memory/graph/narrative.ts +3 -5
  542. package/src/plugins/defaults/memory/graph/pattern-scan.ts +3 -5
  543. package/src/plugins/defaults/memory/graph/retriever.test.ts +1 -6
  544. package/src/plugins/defaults/memory/graph/retriever.ts +5 -10
  545. package/src/plugins/defaults/memory/graph/tools.ts +1 -1
  546. package/src/plugins/defaults/memory/hooks/init.ts +31 -5
  547. package/src/plugins/defaults/memory/indexer.ts +2 -3
  548. package/src/plugins/defaults/memory/injectors.ts +2 -2
  549. package/src/plugins/defaults/memory/job-handler-registration.ts +96 -0
  550. package/src/plugins/defaults/memory/job-handlers/backfill.ts +4 -26
  551. package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +6 -19
  552. package/src/plugins/defaults/memory/job-handlers/embedding.ts +9 -22
  553. package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +2 -3
  554. package/src/plugins/defaults/memory/job-handlers.ts +13 -12
  555. package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +1 -1
  556. package/src/plugins/defaults/memory/llm-helpers.ts +76 -0
  557. package/src/plugins/defaults/memory/memory-retrospective-job.ts +8 -5
  558. package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +2 -2
  559. package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +2 -0
  560. package/src/plugins/defaults/memory/persistence-hooks.ts +46 -1
  561. package/src/plugins/defaults/memory/pkb/pkb-index.ts +1 -5
  562. package/src/plugins/defaults/memory/pkb/pkb-search.ts +2 -2
  563. package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +4 -6
  564. package/src/plugins/defaults/memory/routes/memory-item-routes.ts +1 -1
  565. package/src/plugins/defaults/memory/search/semantic.ts +2 -2
  566. package/src/plugins/defaults/memory/startup.ts +244 -0
  567. package/src/plugins/defaults/memory/task-memory-cleanup.ts +8 -0
  568. package/src/{daemon → plugins/defaults/memory/v2}/__tests__/memory-v2-startup.test.ts +6 -6
  569. package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +2 -13
  570. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +4 -5
  571. package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +1 -8
  572. package/src/plugins/defaults/memory/v2/activation.ts +2 -4
  573. package/src/plugins/defaults/memory/v2/cli-command-store.ts +2 -4
  574. package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +1 -1
  575. package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.test.ts +8 -8
  576. package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.ts +20 -22
  577. package/src/plugins/defaults/memory/v2/migration.ts +2 -5
  578. package/src/plugins/defaults/memory/v2/page-store.ts +1 -1
  579. package/src/plugins/defaults/memory/v2/qdrant.ts +2 -3
  580. package/src/plugins/defaults/memory/v2/router.ts +5 -5
  581. package/src/plugins/defaults/memory/v2/sim.ts +2 -4
  582. package/src/plugins/defaults/memory/v2/skill-store.ts +2 -4
  583. package/src/plugins/defaults/memory/v2/sweep-job.ts +6 -6
  584. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +11 -9
  585. package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +107 -2
  586. package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +69 -0
  587. package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +181 -0
  588. package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +7 -3
  589. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +345 -8
  590. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -4
  591. package/src/plugins/defaults/memory/v3/__tests__/section-needle.test.ts +64 -0
  592. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +18 -13
  593. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +62 -1
  594. package/src/plugins/defaults/memory/v3/card.ts +1 -4
  595. package/src/plugins/defaults/memory/v3/dense.ts +60 -25
  596. package/src/plugins/defaults/memory/v3/edge.ts +1 -1
  597. package/src/plugins/defaults/memory/v3/gate-flag.ts +20 -0
  598. package/src/plugins/defaults/memory/v3/gate.ts +158 -0
  599. package/src/plugins/defaults/memory/v3/maintain-job.ts +2 -4
  600. package/src/plugins/defaults/memory/v3/orchestrate.ts +186 -25
  601. package/src/plugins/defaults/memory/v3/pool-select.test.ts +7 -9
  602. package/src/plugins/defaults/memory/v3/pool-select.ts +6 -6
  603. package/src/plugins/defaults/memory/v3/prune.ts +2 -2
  604. package/src/plugins/defaults/memory/v3/section-dense-store.ts +8 -11
  605. package/src/plugins/defaults/memory/v3/section-needle.ts +27 -7
  606. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +10 -0
  607. package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +1 -4
  608. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +5 -0
  609. package/src/plugins/defaults/turn-context/injectors.ts +1 -0
  610. package/src/plugins/defaults/turn-context/unified-turn-context.ts +12 -0
  611. package/src/plugins/injector-registry.ts +13 -2
  612. package/src/plugins/mtime-cache.ts +36 -47
  613. package/src/plugins/pipeline.ts +15 -1
  614. package/src/plugins/types.ts +14 -23
  615. package/src/prompts/__tests__/system-prompt.test.ts +170 -32
  616. package/src/prompts/persona-resolver.ts +13 -9
  617. package/src/prompts/system-prompt.ts +30 -9
  618. package/src/prompts/templates/BOOTSTRAP.md +16 -119
  619. package/src/prompts/templates/SOUL.md +43 -13
  620. package/src/prompts/templates/system-sections.ts +32 -27
  621. package/src/prompts/templates/users/default.md +19 -0
  622. package/src/providers/__tests__/placeholder-sentinels.test.ts +56 -0
  623. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +96 -1
  624. package/src/providers/model-intents.ts +2 -2
  625. package/src/providers/openai/chat-completions-provider.ts +14 -1
  626. package/src/providers/openai/responses-provider.ts +18 -0
  627. package/src/providers/placeholder-sentinels.ts +18 -8
  628. package/src/providers/retry.ts +1 -0
  629. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +0 -64
  630. package/src/providers/speech-to-text/__tests__/resolve.test.ts +92 -79
  631. package/src/providers/speech-to-text/deepgram-realtime.test.ts +98 -0
  632. package/src/providers/speech-to-text/deepgram-realtime.ts +62 -3
  633. package/src/providers/speech-to-text/provider-catalog.ts +0 -89
  634. package/src/providers/speech-to-text/resolve.ts +55 -0
  635. package/src/providers/tool-progress-events.test.ts +50 -0
  636. package/src/providers/tool-progress-events.ts +99 -0
  637. package/src/providers/types.ts +1 -1
  638. package/src/providers/vellum-model-routing.test.ts +51 -0
  639. package/src/providers/vellum-model-routing.ts +84 -0
  640. package/src/runtime/AGENTS.md +5 -4
  641. package/src/runtime/__tests__/agent-wake.test.ts +158 -1
  642. package/src/runtime/__tests__/channel-verification-service.test.ts +2 -2
  643. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +37 -8
  644. package/src/runtime/access-request-helper.ts +154 -3
  645. package/src/runtime/actor-trust-resolver.ts +7 -21
  646. package/src/runtime/agent-wake.ts +41 -1
  647. package/src/runtime/assistant-event.ts +86 -12
  648. package/src/runtime/auth/__tests__/route-policy.test.ts +31 -0
  649. package/src/runtime/channel-approval-types.ts +52 -2
  650. package/src/runtime/channel-approvals.ts +23 -8
  651. package/src/runtime/channel-invite-transport.ts +2 -2
  652. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  653. package/src/runtime/channel-readiness-service.ts +3 -5
  654. package/src/runtime/channel-retry-sweep.ts +18 -24
  655. package/src/runtime/channel-verification-service.ts +9 -11
  656. package/src/runtime/finalize-event-delivery.ts +30 -16
  657. package/src/runtime/guardian-action-service.ts +10 -11
  658. package/src/runtime/guardian-reply-router.ts +122 -21
  659. package/src/runtime/http-server.ts +44 -101
  660. package/src/runtime/introduction-policy.test.ts +214 -0
  661. package/src/runtime/introduction-policy.ts +284 -0
  662. package/src/runtime/invite-service.ts +104 -361
  663. package/src/runtime/local-actor-identity.test.ts +38 -0
  664. package/src/runtime/local-actor-identity.ts +14 -0
  665. package/src/runtime/middleware/__tests__/rate-limiter.test.ts +22 -0
  666. package/src/runtime/middleware/rate-limiter.ts +30 -0
  667. package/src/runtime/middleware/twilio-validation.ts +5 -7
  668. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +28 -0
  669. package/src/runtime/migrations/origin-mode.ts +6 -6
  670. package/src/runtime/pre-first-message-gate.ts +1 -0
  671. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +6 -35
  672. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +24 -3
  673. package/src/runtime/routes/__tests__/contact-routes.test.ts +80 -15
  674. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +7 -1
  675. package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -3
  676. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +142 -1
  677. package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +119 -30
  678. package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +70 -0
  679. package/src/runtime/routes/__tests__/monitoring-routes.test.ts +194 -0
  680. package/src/runtime/routes/__tests__/plugins-routes.test.ts +755 -29
  681. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +4 -0
  682. package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +70 -0
  683. package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +161 -0
  684. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +1 -1
  685. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
  686. package/src/runtime/routes/acp-routes.ts +15 -3
  687. package/src/runtime/routes/app-management-routes.ts +4 -7
  688. package/src/runtime/routes/approval-routes.ts +4 -0
  689. package/src/runtime/routes/attachment-routes.ts +54 -3
  690. package/src/runtime/routes/avatar-routes.ts +0 -4
  691. package/src/runtime/routes/background-tool-routes.ts +34 -5
  692. package/src/runtime/routes/btw-routes.ts +32 -4
  693. package/src/runtime/routes/channel-route-shared.ts +18 -14
  694. package/src/runtime/routes/channel-verification-routes.ts +0 -3
  695. package/src/runtime/routes/contact-routes.ts +298 -117
  696. package/src/runtime/routes/conversation-list-routes.ts +6 -0
  697. package/src/runtime/routes/conversation-management-routes.ts +74 -37
  698. package/src/runtime/routes/conversation-query-routes.ts +5 -2
  699. package/src/runtime/routes/conversation-routes.ts +222 -82
  700. package/src/runtime/routes/conversations-import-routes.ts +8 -1
  701. package/src/runtime/routes/credential-prompt-routes.ts +20 -5
  702. package/src/runtime/routes/debug-routes.ts +1 -0
  703. package/src/runtime/routes/documents-routes.ts +5 -2
  704. package/src/runtime/routes/empty-state-greeting-cache.ts +37 -10
  705. package/src/runtime/routes/global-search-routes.ts +2 -1
  706. package/src/runtime/routes/guardian-approval-interception.ts +51 -0
  707. package/src/runtime/routes/home-feed-routes.ts +60 -1
  708. package/src/runtime/routes/identity-routes.ts +4 -87
  709. package/src/runtime/routes/inbound-message-handler.ts +82 -41
  710. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +430 -57
  711. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +302 -572
  712. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +76 -270
  713. package/src/runtime/routes/inbound-stages/background-dispatch.ts +21 -116
  714. package/src/runtime/routes/inbound-stages/edit-intercept.ts +9 -1
  715. package/src/runtime/routes/inbound-stages/escalation-intercept.test.ts +158 -0
  716. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +22 -1
  717. package/src/runtime/routes/index.ts +6 -0
  718. package/src/runtime/routes/inference-provider-connection-routes.ts +22 -16
  719. package/src/runtime/routes/internal-twilio-routes.ts +0 -15
  720. package/src/runtime/routes/messages-lexical-routes.ts +75 -0
  721. package/src/runtime/routes/migration-routes.ts +69 -6
  722. package/src/runtime/routes/monitoring-routes.ts +237 -0
  723. package/src/runtime/routes/plugins-routes.ts +329 -8
  724. package/src/runtime/routes/schedule-routes.ts +49 -8
  725. package/src/runtime/routes/schedule-worker-routes.ts +210 -0
  726. package/src/runtime/routes/secret-routes.ts +1 -1
  727. package/src/runtime/routes/surface-conversation-resolver.ts +1 -0
  728. package/src/runtime/services/__tests__/analyze-conversation.test.ts +54 -9
  729. package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +30 -6
  730. package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +43 -8
  731. package/src/runtime/services/__tests__/conversation-serializer.test.ts +20 -0
  732. package/src/runtime/services/analyze-conversation.ts +14 -4
  733. package/src/runtime/services/conversation-serializer.ts +5 -0
  734. package/src/runtime/slack-no-response.ts +47 -0
  735. package/src/runtime/slack-reply-session.test.ts +633 -0
  736. package/src/runtime/slack-reply-session.ts +382 -0
  737. package/src/runtime/slack-task-progress.ts +95 -0
  738. package/src/runtime/sync/resource-sync-events.ts +25 -0
  739. package/src/runtime/tool-grant-request-helper.ts +17 -1
  740. package/src/runtime/trust-class.test.ts +141 -0
  741. package/src/runtime/trust-class.ts +121 -0
  742. package/src/runtime/trust-verdict-consumer.ts +7 -6
  743. package/src/schedule/__tests__/run-script.test.ts +21 -0
  744. package/src/schedule/__tests__/worker-control.test.ts +241 -0
  745. package/src/schedule/run-script.ts +13 -6
  746. package/src/schedule/schedule-usage-store.ts +1 -0
  747. package/src/schedule/scheduler.ts +178 -127
  748. package/src/schedule/worker-control.ts +118 -0
  749. package/src/schedule/worker.ts +131 -0
  750. package/src/skills/__tests__/categories-cache.test.ts +38 -0
  751. package/src/skills/categories-cache.ts +40 -5
  752. package/src/skills/managed-store.ts +41 -6
  753. package/src/skills/validate-input.ts +47 -0
  754. package/src/stt/types.ts +5 -9
  755. package/src/subagent/manager.ts +267 -39
  756. package/src/subagent/types.ts +6 -2
  757. package/src/subagent/validate-allowlists.ts +65 -0
  758. package/src/telemetry/watchdog-direct-emit.test.ts +109 -0
  759. package/src/telemetry/watchdog-direct-emit.ts +89 -0
  760. package/src/tools/acp/list-agents.test.ts +0 -6
  761. package/src/tools/background-tool-registry.ts +61 -0
  762. package/src/tools/document/document-comment-tool.test.ts +4 -0
  763. package/src/tools/host-terminal/host-shell.test.ts +397 -0
  764. package/src/tools/host-terminal/host-shell.ts +203 -14
  765. package/src/tools/skills/find-similar-skills.test.ts +152 -1
  766. package/src/tools/skills/find-similar-skills.ts +30 -4
  767. package/src/tools/skills/load.ts +36 -0
  768. package/src/tools/skills/scaffold-managed.ts +66 -34
  769. package/src/tools/skills/skill-script-runner.ts +17 -0
  770. package/src/tools/skills/skill-tool-factory.ts +5 -1
  771. package/src/tools/terminal/safe-env.ts +3 -0
  772. package/src/tools/terminal/shell.test.ts +177 -0
  773. package/src/tools/terminal/shell.ts +98 -4
  774. package/src/tools/tool-approval-handler.ts +106 -29
  775. package/{node_modules/@vellumai/skill-host-contracts/src → src/tools}/tool-types.ts +16 -17
  776. package/src/tools/types.ts +29 -17
  777. package/src/tools/ui-surface/definitions.ts +3 -1
  778. package/src/tts/__tests__/provider-adapters.test.ts +37 -0
  779. package/src/tts/__tests__/provider-catalog.test.ts +21 -0
  780. package/src/tts/provider-catalog.ts +40 -9
  781. package/src/tts/providers/fish-audio-provider.ts +19 -10
  782. package/src/tts/types.ts +3 -4
  783. package/src/util/__tests__/process-tree.test.ts +10 -2
  784. package/src/util/__tests__/text-spacing.test.ts +53 -0
  785. package/src/util/cgroup-memory.ts +142 -0
  786. package/src/util/image-conversion.ts +281 -0
  787. package/src/util/phone.ts +1 -8
  788. package/src/util/platform.ts +33 -0
  789. package/src/util/process-tree.ts +10 -2
  790. package/src/util/text-spacing.ts +53 -0
  791. package/src/util/worker-process.ts +271 -0
  792. package/src/workflows/journal-store.ts +16 -1
  793. package/src/workflows/library.test.ts +35 -20
  794. package/src/workflows/library.ts +105 -66
  795. package/src/workspace/git-service.ts +1 -0
  796. package/src/workspace/migrations/011-backfill-installation-id.ts +83 -31
  797. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +41 -22
  798. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +1 -1
  799. package/src/workspace/migrations/118-seed-now-md.ts +64 -0
  800. package/src/workspace/migrations/119-strip-persisted-memory-v3-tuning-defaults.ts +169 -0
  801. package/src/workspace/migrations/120-revise-onboarding-threads.ts +47 -0
  802. package/src/workspace/migrations/121-seed-default-user-guardrails.ts +82 -0
  803. package/src/workspace/migrations/122-relocate-default-user-boundary.ts +111 -0
  804. package/src/workspace/migrations/123-swap-quality-profile-to-fable.ts +85 -0
  805. package/src/workspace/migrations/__tests__/119-strip-persisted-memory-v3-tuning-defaults.test.ts +181 -0
  806. package/src/workspace/migrations/registry.ts +12 -0
  807. package/drizzle/0000_dizzy_maggott.sql +0 -301
  808. package/drizzle/meta/0000_snapshot.json +0 -1933
  809. package/drizzle/meta/_journal.json +0 -13
  810. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +0 -887
  811. package/node_modules/@vellumai/skill-host-contracts/bun.lock +0 -24
  812. package/node_modules/@vellumai/skill-host-contracts/package.json +0 -18
  813. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -97
  814. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +0 -1349
  815. package/node_modules/@vellumai/skill-host-contracts/src/index.ts +0 -6
  816. package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +0 -11
  817. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +0 -32
  818. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +0 -333
  819. package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +0 -20
  820. package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +0 -12
  821. package/src/__tests__/invite-redemption-service.test.ts +0 -1180
  822. package/src/__tests__/invite-service-ipc.test.ts +0 -350
  823. package/src/__tests__/job-handler-registry-guard.test.ts +0 -125
  824. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -203
  825. package/src/__tests__/relay-server.test.ts +0 -6153
  826. package/src/__tests__/telephony-stt-routing.test.ts +0 -329
  827. package/src/__tests__/voice-invite-redemption.test.ts +0 -702
  828. package/src/calls/relay-server.ts +0 -2463
  829. package/src/calls/telephony-stt-routing.ts +0 -145
  830. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -128
  831. package/src/daemon/__tests__/daemon-skill-host.test.ts +0 -273
  832. package/src/daemon/daemon-skill-host.ts +0 -262
  833. package/src/daemon/message-types/meet.ts +0 -143
  834. package/src/daemon/shutdown-registry.ts +0 -40
  835. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -253
  836. package/src/ipc/__tests__/skill-server.test.ts +0 -182
  837. package/src/ipc/skill-ipc-types.ts +0 -54
  838. package/src/ipc/skill-routes/__tests__/config.test.ts +0 -146
  839. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +0 -448
  840. package/src/ipc/skill-routes/__tests__/identity.test.ts +0 -62
  841. package/src/ipc/skill-routes/__tests__/log.test.ts +0 -133
  842. package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -203
  843. package/src/ipc/skill-routes/__tests__/platform.test.ts +0 -111
  844. package/src/ipc/skill-routes/__tests__/providers.test.ts +0 -265
  845. package/src/ipc/skill-routes/__tests__/registries.test.ts +0 -400
  846. package/src/ipc/skill-routes/config.ts +0 -47
  847. package/src/ipc/skill-routes/events.ts +0 -147
  848. package/src/ipc/skill-routes/identity.ts +0 -21
  849. package/src/ipc/skill-routes/index.ts +0 -37
  850. package/src/ipc/skill-routes/log.ts +0 -40
  851. package/src/ipc/skill-routes/memory.ts +0 -92
  852. package/src/ipc/skill-routes/platform.ts +0 -39
  853. package/src/ipc/skill-routes/providers.ts +0 -162
  854. package/src/ipc/skill-routes/registries.ts +0 -338
  855. package/src/ipc/skill-server.ts +0 -831
  856. package/src/ipc/skill-socket-path.ts +0 -20
  857. package/src/jobs/register-job-handlers.ts +0 -74
  858. package/src/persistence/invite-store.ts +0 -481
  859. package/src/plugins/job-handler-registry.ts +0 -94
  860. package/src/providers/cache-control.ts +0 -26
  861. package/src/runtime/__tests__/runtime-mode.test.ts +0 -62
  862. package/src/runtime/invite-redemption-service.ts +0 -828
  863. package/src/runtime/invite-redemption-templates.ts +0 -46
  864. package/src/runtime/runtime-mode.ts +0 -40
  865. package/src/runtime/slack-dm-text-delivery.ts +0 -177
  866. package/src/util/voice-code.ts +0 -31
@@ -0,0 +1,184 @@
1
+ /**
2
+ * `ui_show channel_setup` acknowledgment flow.
3
+ *
4
+ * `open_panel` is a side-effect-only command that is never persisted to the
5
+ * transcript, so a dropped event is unrecoverable. The tool result must
6
+ * therefore be gated on a client acknowledgment: "displayed" means a client
7
+ * actually rendered the drawer; every other outcome (nack, timeout, no
8
+ * client, aborted turn) is a tool error the model can act on instead of
9
+ * announcing a panel the user cannot see.
10
+ */
11
+ import { describe, expect, test } from "bun:test";
12
+
13
+ import type { OpenPanelEvent } from "../api/events/open-panel.js";
14
+ import {
15
+ createSurfaceMutex,
16
+ handleSurfaceAction,
17
+ openChannelSetupPanel,
18
+ type SurfaceConversationContext,
19
+ surfaceProxyResolver,
20
+ } from "../daemon/conversation-surfaces.js";
21
+ import type {
22
+ ServerMessage,
23
+ SurfaceData,
24
+ SurfaceType,
25
+ } from "../daemon/message-protocol.js";
26
+
27
+ function makeContext(
28
+ sent: ServerMessage[] = [],
29
+ overrides: Partial<SurfaceConversationContext> = {},
30
+ ): SurfaceConversationContext {
31
+ return {
32
+ conversationId: "session-1",
33
+ traceEmitter: { emit: () => {} },
34
+ sendToClient: (msg) => sent.push(msg),
35
+ pendingSurfaceActions: new Map<string, { surfaceType: SurfaceType }>(),
36
+ lastSurfaceAction: new Map<
37
+ string,
38
+ { actionId: string; data?: Record<string, unknown> }
39
+ >(),
40
+ surfaceState: new Map<
41
+ string,
42
+ { surfaceType: SurfaceType; data: SurfaceData; title?: string }
43
+ >(),
44
+ surfaceUndoStacks: new Map<string, string[]>(),
45
+ accumulatedSurfaceState: new Map<string, Record<string, unknown>>(),
46
+ surfaceActionRequestIds: new Set<string>(),
47
+ pendingStandaloneSurfaces: new Map(),
48
+ recentlyCompletedStandaloneSurfaces: new Map(),
49
+ currentTurnSurfaces: [],
50
+ isProcessing: () => false,
51
+ enqueueMessage: () => ({ queued: false, requestId: "req-1" }),
52
+ getQueueDepth: () => 0,
53
+ processMessage: async () => "ok",
54
+ withSurface: createSurfaceMutex(),
55
+ ...overrides,
56
+ };
57
+ }
58
+
59
+ function findOpenPanel(sent: ServerMessage[]): OpenPanelEvent | undefined {
60
+ return sent.find((msg): msg is OpenPanelEvent => msg.type === "open_panel");
61
+ }
62
+
63
+ async function waitForOpenPanel(
64
+ sent: ServerMessage[],
65
+ ): Promise<OpenPanelEvent> {
66
+ for (let i = 0; i < 20 && !findOpenPanel(sent); i++) {
67
+ await new Promise((resolve) => setTimeout(resolve, 0));
68
+ }
69
+ const event = findOpenPanel(sent);
70
+ expect(event).toBeDefined();
71
+ return event!;
72
+ }
73
+
74
+ describe("ui_show channel_setup acknowledgment", () => {
75
+ test("emits open_panel with a surfaceId and succeeds once the client acks", async () => {
76
+ const sent: ServerMessage[] = [];
77
+ const ctx = makeContext(sent);
78
+
79
+ const resultPromise = surfaceProxyResolver(ctx, "ui_show", {
80
+ surface_type: "channel_setup",
81
+ data: { channel: "slack" },
82
+ });
83
+
84
+ const event = await waitForOpenPanel(sent);
85
+ expect(event.panelType).toBe("channel_setup");
86
+ expect(event.conversationId).toBe("session-1");
87
+ expect(event.data).toEqual({ channel: "slack" });
88
+ expect(typeof event.surfaceId).toBe("string");
89
+
90
+ const surfaceId = event.surfaceId!;
91
+ expect(ctx.pendingStandaloneSurfaces!.has(surfaceId)).toBe(true);
92
+ // Registered so the surface-action route can resolve the conversation
93
+ // by surfaceId when the ack arrives.
94
+ expect(ctx.surfaceState.get(surfaceId)?.surfaceType).toBe("channel_setup");
95
+
96
+ await handleSurfaceAction(ctx, surfaceId, "ack");
97
+
98
+ const result = await resultPromise;
99
+ expect(result.isError).toBe(false);
100
+ expect(JSON.parse(result.content as string)).toEqual({
101
+ surfaceId,
102
+ status: "displayed",
103
+ });
104
+
105
+ // Ack consumed the pending entry without leaking surface state.
106
+ expect(ctx.pendingStandaloneSurfaces!.size).toBe(0);
107
+ expect(ctx.surfaceState.has(surfaceId)).toBe(false);
108
+ });
109
+
110
+ test("returns a tool error when the client nacks", async () => {
111
+ const sent: ServerMessage[] = [];
112
+ const ctx = makeContext(sent);
113
+
114
+ const resultPromise = surfaceProxyResolver(ctx, "ui_show", {
115
+ surface_type: "channel_setup",
116
+ data: { channel: "slack" },
117
+ });
118
+
119
+ const event = await waitForOpenPanel(sent);
120
+ await handleSurfaceAction(ctx, event.surfaceId!, "nack", {
121
+ reason: "no_active_assistant",
122
+ });
123
+
124
+ const result = await resultPromise;
125
+ expect(result.isError).toBe(true);
126
+ expect(result.content).toContain("no_active_assistant");
127
+ expect(result.content).toContain("Do NOT tell the user the panel is open");
128
+ });
129
+
130
+ test("fails closed without emitting when no interactive client is connected", async () => {
131
+ const sent: ServerMessage[] = [];
132
+ const ctx = makeContext(sent, { hasNoClient: true });
133
+
134
+ const result = await surfaceProxyResolver(ctx, "ui_show", {
135
+ surface_type: "channel_setup",
136
+ data: { channel: "slack" },
137
+ });
138
+
139
+ expect(result.isError).toBe(true);
140
+ expect(result.content).toContain("no connected client");
141
+ expect(findOpenPanel(sent)).toBeUndefined();
142
+ });
143
+
144
+ test("times out into a tool error when no client acknowledges", async () => {
145
+ const sent: ServerMessage[] = [];
146
+ const ctx = makeContext(sent);
147
+
148
+ const ack = await openChannelSetupPanel(
149
+ ctx,
150
+ "surface-timeout",
151
+ { channel: "slack" },
152
+ { timeoutMs: 10 },
153
+ );
154
+
155
+ expect(ack.status).toBe("timed_out");
156
+ // Timed-out entries are fully cleaned up and tombstoned so a late ack
157
+ // cannot fall through to the LLM-turn path.
158
+ expect(ctx.pendingStandaloneSurfaces!.size).toBe(0);
159
+ expect(ctx.surfaceState.has("surface-timeout")).toBe(false);
160
+ expect(
161
+ ctx.recentlyCompletedStandaloneSurfaces!.has("surface-timeout"),
162
+ ).toBe(true);
163
+ });
164
+
165
+ test("resolves cancelled when the turn is aborted mid-wait", async () => {
166
+ const sent: ServerMessage[] = [];
167
+ const ctx = makeContext(sent);
168
+ const controller = new AbortController();
169
+
170
+ const ackPromise = openChannelSetupPanel(
171
+ ctx,
172
+ "surface-abort",
173
+ { channel: "slack" },
174
+ { signal: controller.signal, timeoutMs: 5_000 },
175
+ );
176
+ controller.abort();
177
+
178
+ const ack = await ackPromise;
179
+ expect(ack.status).toBe("cancelled");
180
+ expect(ack.cancellationReason).toBe("resolver_unavailable");
181
+ expect(ctx.pendingStandaloneSurfaces!.size).toBe(0);
182
+ expect(ctx.surfaceState.has("surface-abort")).toBe(false);
183
+ });
184
+ });
@@ -0,0 +1,90 @@
1
+ // clearAll() must drop the memory feature's bulk per-message index (the whole
2
+ // lexical Qdrant collection) — a "delete all" leaves no conversation ids to key
3
+ // per-conversation purges on, so the points would otherwise survive a
4
+ // "permanently delete everything" action. clearAll routes this through the
5
+ // `MemoryPersistenceHooks.onAllConversationsCleared` seam (persistence stays
6
+ // decoupled from the plugin); the memory plugin's impl calls
7
+ // `clearMessagesLexicalIndex`. This asserts the full chain fires.
8
+
9
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
10
+
11
+ import { makeMockLogger } from "./helpers/mock-logger.js";
12
+
13
+ mock.module("../util/logger.js", () => ({
14
+ getLogger: () => makeMockLogger(),
15
+ }));
16
+
17
+ // Spy on `clearMessagesLexicalIndex` (the plugin's `onAllConversationsCleared`
18
+ // impl calls it) while keeping the rest of the module REAL. `mock.module` is
19
+ // process-global and not undone by `mock.restore()`, so a partial mock that
20
+ // drops the other exports would leak into any later test file in the same
21
+ // process that imports them (e.g. the handler tests importing
22
+ // `indexMessageLexicalJob`). Spread the real module so only this one export is
23
+ // replaced. Importing the real module here is safe: its deps
24
+ // (`@qdrant/js-client-rest`, `uuid`, the local TF-IDF encoder) resolve in the
25
+ // worktree.
26
+ const actualLexical =
27
+ await import("../persistence/job-handlers/message-lexical.js");
28
+ let clearCalls = 0;
29
+ mock.module("../persistence/job-handlers/message-lexical.js", () => ({
30
+ ...actualLexical,
31
+ clearMessagesLexicalIndex: async () => {
32
+ clearCalls += 1;
33
+ },
34
+ }));
35
+
36
+ import { clearAll } from "../persistence/conversation-crud.js";
37
+ import { initializeDb } from "../persistence/db-init.js";
38
+ import {
39
+ getMemoryPersistenceHooks,
40
+ registerMemoryPersistenceHooks,
41
+ resetMemoryPersistenceHooksForTests,
42
+ } from "../persistence/memory-lifecycle-hooks.js";
43
+ import { registerDefaultPluginPersistenceHooks } from "../plugins/defaults/index.js";
44
+
45
+ await initializeDb();
46
+
47
+ describe("clearAll bulk lexical index cleanup", () => {
48
+ beforeEach(() => {
49
+ clearCalls = 0;
50
+ // Register the real memory persistence hooks so `onAllConversationsCleared`
51
+ // routes to the plugin impl (which calls the spied clear helper).
52
+ registerDefaultPluginPersistenceHooks();
53
+ });
54
+
55
+ test("clearAll fires onAllConversationsCleared, which clears the lexical index", async () => {
56
+ await clearAll();
57
+ expect(clearCalls).toBe(1);
58
+ });
59
+
60
+ test("clearAll AWAITS the collection drop before returning", async () => {
61
+ // The drop must complete before clearAll resolves — otherwise a write right
62
+ // after clear-all could land in a collection that is about to be dropped.
63
+ // Register a hook whose drop yields to the microtask queue before finishing;
64
+ // if clearAll did not await, `dropCompleted` would still be false here.
65
+ let dropCompleted = false;
66
+ registerMemoryPersistenceHooks({
67
+ ...getMemoryPersistenceHooks(),
68
+ async onAllConversationsCleared() {
69
+ await new Promise((r) => setTimeout(r, 10));
70
+ dropCompleted = true;
71
+ },
72
+ });
73
+
74
+ await clearAll();
75
+ expect(dropCompleted).toBe(true);
76
+
77
+ registerDefaultPluginPersistenceHooks();
78
+ });
79
+
80
+ test("clearAll is a safe no-op when the memory hooks are not registered", async () => {
81
+ // Persistence must work with no memory present — the seam falls through to
82
+ // its no-op and clearAll does not touch the lexical index.
83
+ resetMemoryPersistenceHooksForTests();
84
+ clearCalls = 0;
85
+ await clearAll();
86
+ expect(clearCalls).toBe(0);
87
+ // Restore for any later test in the same process.
88
+ registerDefaultPluginPersistenceHooks();
89
+ });
90
+ });
@@ -0,0 +1,177 @@
1
+ import { describe, expect, mock, test } from "bun:test";
2
+
3
+ function makeLoggerStub(): Record<string, unknown> {
4
+ const stub: Record<string, unknown> = {};
5
+ for (const m of [
6
+ "info",
7
+ "warn",
8
+ "error",
9
+ "debug",
10
+ "trace",
11
+ "fatal",
12
+ "silent",
13
+ "child",
14
+ ]) {
15
+ stub[m] = m === "child" ? () => makeLoggerStub() : () => {};
16
+ }
17
+ return stub;
18
+ }
19
+
20
+ mock.module("../util/logger.js", () => ({
21
+ getLogger: () => makeLoggerStub(),
22
+ }));
23
+
24
+ mock.module("../persistence/conversation-crud.js", () => ({
25
+ setConversationProcessingStartedAt: () => {},
26
+ isConversationProcessing: () => false,
27
+ getMessages: () => [],
28
+ reserveMessage: mock(async () => ({ id: "msg-reserve" })),
29
+ }));
30
+
31
+ mock.module("../persistence/attachments-store.js", () => ({
32
+ getAttachmentMetadataForMessage: () => [],
33
+ getAttachmentContent: () => null,
34
+ }));
35
+
36
+ import { runAssistantDrivenCompaction } from "../context/compactor.js";
37
+ import type { Message, Provider } from "../providers/types.js";
38
+
39
+ const TAIL_TIMESTAMP =
40
+ "2026-05-21 (Thursday) 10:00:00 -05:00 (America/Chicago)";
41
+
42
+ const compactionResponse = `
43
+ <compaction_result>
44
+ <summary>
45
+ Earlier turns summarized here.
46
+ </summary>
47
+
48
+ <key_state>
49
+ - Nothing critical pending.
50
+ </key_state>
51
+
52
+ <tail_start timestamp="${TAIL_TIMESTAMP}" preview="tail anchor message" />
53
+ </compaction_result>
54
+ `;
55
+
56
+ const OLD_SCREENSHOT_DATA = "b64-old-screenshot-bytes";
57
+ const LATEST_SCREENSHOT_DATA = "b64-latest-screenshot-bytes";
58
+ const USER_ATTACHED_IMAGE_DATA = "b64-user-attached-bytes";
59
+
60
+ const userTextWithTurnContext = (text: string, timestamp: string): Message => ({
61
+ role: "user",
62
+ content: [
63
+ {
64
+ type: "text",
65
+ text: `<turn_context>\ncurrent_time: ${timestamp}\n</turn_context>\n${text}`,
66
+ },
67
+ ],
68
+ });
69
+
70
+ const assistantToolUse = (id: string): Message => ({
71
+ role: "assistant",
72
+ content: [{ type: "tool_use", id, name: "screenshot", input: {} }],
73
+ });
74
+
75
+ const toolResultWithImage = (id: string, data: string): Message => ({
76
+ role: "user",
77
+ content: [
78
+ {
79
+ type: "tool_result",
80
+ tool_use_id: id,
81
+ content: "captured",
82
+ contentBlocks: [
83
+ {
84
+ type: "image",
85
+ source: { type: "base64", media_type: "image/png", data },
86
+ },
87
+ ],
88
+ },
89
+ ],
90
+ });
91
+
92
+ const userWithAttachedImage = (): Message => ({
93
+ role: "user",
94
+ content: [
95
+ { type: "text", text: "here is a mockup" },
96
+ {
97
+ type: "image",
98
+ source: {
99
+ type: "base64",
100
+ media_type: "image/png",
101
+ data: USER_ATTACHED_IMAGE_DATA,
102
+ },
103
+ },
104
+ ],
105
+ });
106
+
107
+ function serializeBlocks(messages: Message[]): string {
108
+ return JSON.stringify(messages);
109
+ }
110
+
111
+ // Records the exact message list the provider is asked to summarize.
112
+ function recordingProvider(sink: { sent: Message[] }): Provider {
113
+ return {
114
+ name: "mock-provider",
115
+ sendMessage: async (msgs: Message[]) => {
116
+ sink.sent = msgs;
117
+ return {
118
+ content: [{ type: "text", text: compactionResponse }],
119
+ model: "mock-model",
120
+ usage: { inputTokens: 100, outputTokens: 50 },
121
+ stopReason: "end_turn",
122
+ };
123
+ },
124
+ };
125
+ }
126
+
127
+ // The summary request must carry the same media-stripped projection the agent
128
+ // loop sends on its own model calls. An unsanitized history resends every
129
+ // screenshot in the conversation; enough of them cross Anthropic's many-image
130
+ // threshold, where a stricter per-image dimension cap rejects the whole
131
+ // summary call (and trips the compaction circuit breaker).
132
+ describe("compaction summary calls — old tool-result media stripping", () => {
133
+ test("runAssistantDrivenCompaction strips images from older tool results, keeps the latest turn's image and user-attached images, and leaves durable history untouched", async () => {
134
+ // GIVEN a screenshot-heavy history: older tool results with images, a
135
+ // user-attached image, and a most-recent tool result with an image
136
+ const messages: Message[] = [
137
+ userWithAttachedImage(),
138
+ assistantToolUse("tu_old_1"),
139
+ toolResultWithImage("tu_old_1", OLD_SCREENSHOT_DATA),
140
+ userTextWithTurnContext("tail anchor message", TAIL_TIMESTAMP),
141
+ assistantToolUse("tu_latest"),
142
+ toolResultWithImage("tu_latest", LATEST_SCREENSHOT_DATA),
143
+ ];
144
+
145
+ // AND a snapshot of the caller's array so we can assert it is not mutated
146
+ const inputSnapshot = serializeBlocks(messages);
147
+ const sink = { sent: [] as Message[] };
148
+
149
+ // WHEN compaction runs over that history
150
+ const result = await runAssistantDrivenCompaction({
151
+ conversationId: "conv-media-strip",
152
+ messages,
153
+ provider: recordingProvider(sink),
154
+ systemPrompt: "system",
155
+ compaction: { enabled: true, autoThreshold: 0.7 },
156
+ // Large budget so the request is not front-truncated — this test
157
+ // exercises the media-strip sanitizer, not the truncation fallback.
158
+ maxInputTokens: 100000,
159
+ previousEstimatedInputTokens: 90000,
160
+ });
161
+
162
+ // THEN older tool-result screenshots are replaced with a text marker
163
+ const sentSerialized = serializeBlocks(sink.sent);
164
+ expect(sentSerialized).not.toContain(OLD_SCREENSHOT_DATA);
165
+ expect(sentSerialized).toContain("binary data removed to save context");
166
+
167
+ // AND the most recent tool-result turn keeps its image (the model may
168
+ // still need it), as do images the user attached directly
169
+ expect(sentSerialized).toContain(LATEST_SCREENSHOT_DATA);
170
+ expect(sentSerialized).toContain(USER_ATTACHED_IMAGE_DATA);
171
+
172
+ // AND the caller's durable history array is left byte-for-byte untouched,
173
+ // so persisted messages keep the original rich blocks
174
+ expect(serializeBlocks(messages)).toBe(inputSnapshot);
175
+ expect(result.compacted).toBe(true);
176
+ });
177
+ });
@@ -856,9 +856,9 @@ describe("loadConfig startup behavior", () => {
856
856
  );
857
857
  expect(raw.llm.profiles.balanced.effort).toBe("high");
858
858
  expect(raw.llm.profiles.balanced.source).toBe("managed");
859
- // Quality serves Anthropic Opus, the most capable managed profile.
859
+ // Quality serves Anthropic Fable, the most capable managed profile.
860
860
  expect(raw.llm.profiles["quality-optimized"].provider).toBe("anthropic");
861
- expect(raw.llm.profiles["quality-optimized"].model).toBe("claude-opus-4-8");
861
+ expect(raw.llm.profiles["quality-optimized"].model).toBe("claude-fable-5");
862
862
  // Speed is served by DeepSeek V4 Flash on Fireworks.
863
863
  expect(raw.llm.profiles["cost-optimized"].provider).toBe("fireworks");
864
864
  expect(raw.llm.profiles["cost-optimized"].model).toBe(
@@ -899,7 +899,7 @@ describe("loadConfig startup behavior", () => {
899
899
  test("reseed updates a source-less legacy canonical managed profile", () => {
900
900
  // Migration 052 seeded canonical profiles without a `source`. Such a
901
901
  // source-less `quality-optimized` is legacy managed, not user-owned, so it
902
- // must still reseed to the latest template (Opus) and be tagged managed.
902
+ // must still reseed to the latest template (Fable) and be tagged managed.
903
903
  writeConfig({
904
904
  llm: {
905
905
  profiles: {
@@ -915,7 +915,7 @@ describe("loadConfig startup behavior", () => {
915
915
  mergeDefaultConfigAndSeedInferenceProfiles();
916
916
  const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
917
917
 
918
- expect(raw.llm.profiles["quality-optimized"].model).toBe("claude-opus-4-8");
918
+ expect(raw.llm.profiles["quality-optimized"].model).toBe("claude-fable-5");
919
919
  expect(raw.llm.profiles["quality-optimized"].source).toBe("managed");
920
920
  });
921
921
 
@@ -1574,7 +1574,7 @@ describe("seedInferenceProfiles BYOK-mode managed profile labels", () => {
1574
1574
  const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
1575
1575
 
1576
1576
  expect(raw.llm.activeProfile).toBe("balanced");
1577
- // Balanced lives on `fireworks-managed`; `quality-optimized` (Opus on
1577
+ // Balanced lives on `fireworks-managed`; `quality-optimized` (Fable on
1578
1578
  // `anthropic-managed`) is on a different connection, so selecting balanced at
1579
1579
  // hatch disables it. The default advisor falls to the only active managed
1580
1580
  // profile, `balanced`.
@@ -890,6 +890,7 @@ describe("AssistantConfigSchema", () => {
890
890
  language: "en-US",
891
891
  hints: [],
892
892
  interruptSensitivity: "low",
893
+ telephonyStreaming: true,
893
894
  },
894
895
  callerIdentity: {
895
896
  allowPerCallOverride: true,
@@ -997,6 +998,7 @@ describe("AssistantConfigSchema", () => {
997
998
  expect(result.calls.voice.language).toBe("en-US");
998
999
  expect(result.calls.voice.hints).toEqual([]);
999
1000
  expect(result.calls.voice.interruptSensitivity).toBe("low");
1001
+ expect(result.calls.voice.telephonyStreaming).toBe(true);
1000
1002
  });
1001
1003
 
1002
1004
  test("accepts valid calls.voice overrides", () => {
@@ -1004,10 +1006,25 @@ describe("AssistantConfigSchema", () => {
1004
1006
  calls: {
1005
1007
  voice: {
1006
1008
  language: "es-ES",
1009
+ telephonyStreaming: false,
1007
1010
  },
1008
1011
  },
1009
1012
  });
1010
1013
  expect(result.calls.voice.language).toBe("es-ES");
1014
+ expect(result.calls.voice.telephonyStreaming).toBe(false);
1015
+ });
1016
+
1017
+ test("rejects non-boolean calls.voice.telephonyStreaming", () => {
1018
+ const result = AssistantConfigSchema.safeParse({
1019
+ calls: { voice: { telephonyStreaming: "yes" } },
1020
+ });
1021
+ expect(result.success).toBe(false);
1022
+ if (!result.success) {
1023
+ const msgs = result.error.issues.map((i) => i.message);
1024
+ expect(
1025
+ msgs.some((m) => m.includes("calls.voice.telephonyStreaming")),
1026
+ ).toBe(true);
1027
+ }
1011
1028
  });
1012
1029
 
1013
1030
  test("transcriptionProvider is no longer part of the voice config schema", () => {
@@ -1,8 +1,9 @@
1
1
  /**
2
- * INFO telemetry (interactionCount/lastInteraction/lastSeenAt) is local, not
3
- * ACL: the gateway's handle-inbound mirror writes it to the assistant DB, and
4
- * model-facing turn context reads it back. These tests assert the daemon-native
5
- * read paths (getContact / searchContacts) re-hydrate and aggregate it.
2
+ * Interaction telemetry (interactionCount/lastInteraction/lastSeenAt) is
3
+ * gateway-owned: reads source it from the stamped trust verdict and the gateway
4
+ * rich-read relay, and the assistant DB no longer carries the columns. These
5
+ * tests assert the daemon-native read paths (getContact / searchContacts /
6
+ * findContactInfoById) surface no telemetry.
6
7
  */
7
8
 
8
9
  import { beforeEach, describe, expect, mock, test } from "bun:test";
@@ -43,114 +44,70 @@ function insertChannel(params: {
43
44
  contactId: string;
44
45
  type: string;
45
46
  address: string;
46
- interactionCount: number;
47
- lastInteraction: number | null;
48
- lastSeenAt?: number | null;
49
47
  }): void {
50
48
  const now = Date.now();
51
49
  getSqlite().run(
52
- "INSERT INTO contact_channels (id, contact_id, type, address, is_primary, interaction_count, last_interaction, last_seen_at, created_at, updated_at) VALUES (?, ?, ?, ?, 0, ?, ?, ?, ?, ?)",
53
- [
54
- params.id,
55
- params.contactId,
56
- params.type,
57
- params.address,
58
- params.interactionCount,
59
- params.lastInteraction,
60
- params.lastSeenAt ?? null,
61
- now,
62
- now,
63
- ],
50
+ "INSERT INTO contact_channels (id, contact_id, type, address, is_primary, created_at, updated_at) VALUES (?, ?, ?, ?, 0, ?, ?)",
51
+ [params.id, params.contactId, params.type, params.address, now, now],
64
52
  );
65
53
  }
66
54
 
67
- describe("contact interaction INFO aggregation", () => {
55
+ const TELEMETRY_KEYS = ["interactionCount", "lastInteraction", "lastSeenAt"];
56
+
57
+ describe("contact-store surfaces no interaction telemetry", () => {
68
58
  beforeEach(() => {
69
59
  resetContactTables();
70
60
  });
71
61
 
72
- test("getContact sums interaction_count and takes the latest last_interaction across channels", () => {
62
+ test("getContact returns no telemetry fields on the contact or its channels", () => {
73
63
  insertContact("ct_1", "Alice");
74
64
  insertChannel({
75
65
  id: "ch_a",
76
66
  contactId: "ct_1",
77
67
  type: "phone",
78
68
  address: "+15550100",
79
- interactionCount: 3,
80
- lastInteraction: 1900,
81
- lastSeenAt: 1850,
82
- });
83
- insertChannel({
84
- id: "ch_b",
85
- contactId: "ct_1",
86
- type: "email",
87
- address: "alice@example.com",
88
- interactionCount: 4,
89
- lastInteraction: 2100,
90
- lastSeenAt: 2050,
91
69
  });
92
70
 
93
71
  const contact = getContact("ct_1");
94
72
  expect(contact).not.toBeNull();
95
- expect(contact!.interactionCount).toBe(7);
96
- expect(contact!.lastInteraction).toBe(2100);
97
-
98
- // Per-channel INFO is hydrated too.
99
- const phone = contact!.channels.find((c) => c.type === "phone");
100
- expect(phone?.interactionCount).toBe(3);
101
- expect(phone?.lastInteraction).toBe(1900);
102
- expect(phone?.lastSeenAt).toBe(1850);
73
+ for (const key of TELEMETRY_KEYS) {
74
+ expect(key in contact!).toBe(false);
75
+ }
76
+ const phone = contact!.channels.find((c) => c.type === "phone")!;
77
+ for (const key of TELEMETRY_KEYS) {
78
+ expect(key in phone).toBe(false);
79
+ }
103
80
  });
104
81
 
105
- test("findContactInfoById surfaces the real interaction count", () => {
82
+ test("findContactInfoById returns the notes-only INFO shape (telemetry is gateway-owned)", () => {
106
83
  insertContact("ct_2", "Bob");
107
84
  insertChannel({
108
85
  id: "ch_c",
109
86
  contactId: "ct_2",
110
87
  type: "phone",
111
88
  address: "+15550200",
112
- interactionCount: 5,
113
- lastInteraction: 1000,
114
89
  });
115
90
 
116
91
  const info = findContactInfoById("ct_2");
117
- expect(info?.interactionCount).toBe(5);
118
- });
119
-
120
- test("lastInteraction is null when no channel has interacted", () => {
121
- insertContact("ct_3", "Carol");
122
- insertChannel({
123
- id: "ch_d",
124
- contactId: "ct_3",
125
- type: "phone",
126
- address: "+15550300",
127
- interactionCount: 0,
128
- lastInteraction: null,
129
- });
130
-
131
- const contact = getContact("ct_3");
132
- expect(contact!.interactionCount).toBe(0);
133
- expect(contact!.lastInteraction).toBeNull();
92
+ expect(info).not.toBeNull();
93
+ expect(Object.keys(info!)).toEqual(["notes"]);
94
+ expect(info!.notes).toBeNull();
134
95
  });
135
96
 
136
- test("filtered searchContacts carries channel INFO fields", () => {
97
+ test("filtered searchContacts carries no telemetry fields", () => {
137
98
  insertContact("ct_4", "Dana");
138
99
  insertChannel({
139
100
  id: "ch_e",
140
101
  contactId: "ct_4",
141
102
  type: "phone",
142
103
  address: "+15550400",
143
- interactionCount: 9,
144
- lastInteraction: 3000,
145
- lastSeenAt: 2900,
146
104
  });
147
105
 
148
106
  const results = searchContacts({ query: "Dana", limit: 10 });
149
107
  expect(results).toHaveLength(1);
150
- expect(results[0].interactionCount).toBe(9);
151
- expect(results[0].lastInteraction).toBe(3000);
152
- const ch = results[0].channels[0];
153
- expect(ch.interactionCount).toBe(9);
154
- expect(ch.lastSeenAt).toBe(2900);
108
+ for (const key of TELEMETRY_KEYS) {
109
+ expect(key in results[0]).toBe(false);
110
+ expect(key in results[0].channels[0]).toBe(false);
111
+ }
155
112
  });
156
113
  });