@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
@@ -11,7 +11,9 @@ import {
11
11
  createUserMessage,
12
12
  } from "../../agent/message-types.js";
13
13
  import {
14
+ BackgroundToolCompletionSchema,
14
15
  type ConversationContentBlock,
16
+ type ConversationMessage,
15
17
  ConversationMessageSchema,
16
18
  } from "../../api/responses/conversation-message.js";
17
19
  import {
@@ -19,6 +21,7 @@ import {
19
21
  INTERFACE_IDS,
20
22
  isInteractiveInterface,
21
23
  parseChannelId,
24
+ parseClientOs,
22
25
  parseInterfaceId,
23
26
  supportsHostProxy,
24
27
  } from "../../channels/types.js";
@@ -103,6 +106,7 @@ import {
103
106
  getMessagesPaginated,
104
107
  hasMessages,
105
108
  isConversationProcessing,
109
+ isHiddenMessageMetadata,
106
110
  type MessageRow,
107
111
  provenanceFromTrustContext,
108
112
  setConversationInferenceProfile,
@@ -119,6 +123,10 @@ import { getConfiguredProvider } from "../../providers/provider-send-message.js"
119
123
  import type { Provider } from "../../providers/types.js";
120
124
  import { checkIngressForSecrets } from "../../security/secret-ingress.js";
121
125
  import { getSubagentManager } from "../../subagent/index.js";
126
+ import {
127
+ isHeicFilename,
128
+ normalizeImageBase64,
129
+ } from "../../util/image-conversion.js";
122
130
  import { getLogger } from "../../util/logger.js";
123
131
  import {
124
132
  getWorkspaceDir,
@@ -341,8 +349,9 @@ function emitCannedMessageComplete(
341
349
  function isHiddenMessage(metadata: string | null): boolean {
342
350
  if (!metadata) return false;
343
351
  try {
344
- const meta = JSON.parse(metadata) as { hidden?: unknown };
345
- return meta?.hidden === true;
352
+ return isHiddenMessageMetadata(
353
+ JSON.parse(metadata) as Record<string, unknown>,
354
+ );
346
355
  } catch {
347
356
  return false;
348
357
  }
@@ -625,43 +634,51 @@ function buildQueuedMessagePayloads(
625
634
  const conversation = findConversation(conversationId);
626
635
  if (!conversation) return [];
627
636
 
628
- return conversation.snapshotQueuedMessages().map((item, index) => {
629
- const text = item.displayContent ?? item.content;
630
- const attachments: RuntimeAttachmentMetadata[] = item.attachments.map(
631
- (a, idx) => ({
632
- id: a.id ?? `${item.requestId}:attachment:${idx}`,
633
- filename: a.filename,
634
- mimeType: a.mimeType,
635
- sizeBytes:
636
- a.sizeBytes ?? (a.data ? Math.floor((a.data.length * 3) / 4) : 0),
637
- kind: classifyKind(a.mimeType),
638
- ...(a.mimeType.startsWith("image/") && a.data ? { data: a.data } : {}),
639
- ...(a.thumbnailData ? { thumbnailData: a.thumbnailData } : {}),
640
- }),
641
- );
637
+ // Hidden sends are suppressed from the transcript at every stage — echo,
638
+ // persisted row, and here the in-memory queue window: a latest-page fetch
639
+ // while the item still awaits drain must not surface it as a queued bubble.
640
+ return conversation
641
+ .snapshotQueuedMessages()
642
+ .filter((item) => !isHiddenMessageMetadata(item.metadata))
643
+ .map((item, index) => {
644
+ const text = item.displayContent ?? item.content;
645
+ const attachments: RuntimeAttachmentMetadata[] = item.attachments.map(
646
+ (a, idx) => ({
647
+ id: a.id ?? `${item.requestId}:attachment:${idx}`,
648
+ filename: a.filename,
649
+ mimeType: a.mimeType,
650
+ sizeBytes:
651
+ a.sizeBytes ?? (a.data ? Math.floor((a.data.length * 3) / 4) : 0),
652
+ kind: classifyKind(a.mimeType),
653
+ ...(a.mimeType.startsWith("image/") && a.data
654
+ ? { data: a.data }
655
+ : {}),
656
+ ...(a.thumbnailData ? { thumbnailData: a.thumbnailData } : {}),
657
+ }),
658
+ );
642
659
 
643
- const contentBlocks: ConversationContentBlock[] = [];
644
- if (text.length > 0) contentBlocks.push({ type: "text", text });
645
- for (const attachment of attachments) {
646
- contentBlocks.push({ type: "attachment", attachment });
647
- }
660
+ const contentBlocks: ConversationContentBlock[] = [];
661
+ if (text.length > 0) contentBlocks.push({ type: "text", text });
662
+ for (const attachment of attachments) {
663
+ contentBlocks.push({ type: "attachment", attachment });
664
+ }
648
665
 
649
- return {
650
- // The queued message has no DB row yet; its requestId is the stable
651
- // identifier the queued-message delete/steer endpoints key on.
652
- id: item.requestId,
653
- role: "user" as const,
654
- content: text,
655
- timestamp: new Date(item.sentAt).toISOString(),
656
- attachments,
657
- ...(contentBlocks.length > 0 ? { contentBlocks } : {}),
658
- ...(item.clientMessageId
659
- ? { clientMessageId: item.clientMessageId }
660
- : {}),
661
- queueStatus: "queued" as const,
662
- queuePosition: index + 1,
663
- };
664
- });
666
+ return {
667
+ // The queued message has no DB row yet; its requestId is the stable
668
+ // identifier the queued-message delete/steer endpoints key on.
669
+ id: item.requestId,
670
+ role: "user" as const,
671
+ content: text,
672
+ timestamp: new Date(item.sentAt).toISOString(),
673
+ attachments,
674
+ ...(contentBlocks.length > 0 ? { contentBlocks } : {}),
675
+ ...(item.clientMessageId
676
+ ? { clientMessageId: item.clientMessageId }
677
+ : {}),
678
+ queueStatus: "queued" as const,
679
+ queuePosition: index + 1,
680
+ };
681
+ });
665
682
  }
666
683
 
667
684
  export function handleListMessages({
@@ -838,10 +855,29 @@ export function handleListMessages({
838
855
  }
839
856
  | undefined;
840
857
  let acpNotification: { acpSessionId: string; agent?: string } | undefined;
858
+ let backgroundEventNotification: boolean | undefined;
859
+ let backgroundToolCompletion: ConversationMessage["backgroundToolCompletion"];
841
860
  if (msg.metadata) {
842
861
  try {
843
862
  const meta = JSON.parse(msg.metadata);
844
863
  if (typeof meta.sentAt === "number") sentAt = meta.sentAt;
864
+ // Every wake persists a `<background_event source="...">` trigger row
865
+ // (see `persistWakeTriggerMessage`) that the LLM reads. Flag any such
866
+ // row so clients hide it from the transcript like a subagent/ACP
867
+ // notification — the user-facing "Conversation Woke" card (or, for a
868
+ // backgrounded bash run, the inline terminal card) carries the status.
869
+ if (typeof meta.backgroundEventSource === "string") {
870
+ backgroundEventNotification = true;
871
+ }
872
+ // `persistWakeTriggerMessage` stamps the structured completion onto the
873
+ // same wake row, letting the web rebuild a terminal inline card from
874
+ // history after a restart (the in-memory completed ring does not survive).
875
+ const completionParse = BackgroundToolCompletionSchema.safeParse(
876
+ meta.backgroundToolCompletion,
877
+ );
878
+ if (completionParse.success) {
879
+ backgroundToolCompletion = completionParse.data;
880
+ }
845
881
  if (meta.subagentNotification) {
846
882
  const n = meta.subagentNotification;
847
883
  if (typeof n.subagentId === "string" && typeof n.label === "string") {
@@ -894,6 +930,8 @@ export function handleListMessages({
894
930
  sentAt,
895
931
  subagentNotification,
896
932
  acpNotification,
933
+ backgroundEventNotification,
934
+ backgroundToolCompletion,
897
935
  slackMessage,
898
936
  clientMessageId: msg.clientMessageId ?? undefined,
899
937
  };
@@ -926,27 +964,36 @@ export function handleListMessages({
926
964
  );
927
965
  if (linked.length > 0) {
928
966
  msgAttachments = linked.map((a) => {
929
- if (a.mimeType.startsWith("image/")) {
930
- const full = getAttachmentById(a.id, { hydrateFileData: true });
931
- return {
932
- id: a.id,
933
- filename: a.originalFilename,
934
- mimeType: a.mimeType,
935
- sizeBytes: a.sizeBytes,
936
- kind: a.kind,
937
- ...(full?.dataBase64 ? { data: full.dataBase64 } : {}),
938
- ...(a.thumbnailBase64
939
- ? { thumbnailData: a.thumbnailBase64 }
940
- : {}),
941
- fileBacked: true,
942
- };
943
- }
967
+ // Hydrate image rows for inline thumbnails. Legacy HEIC can be
968
+ // stored under application/octet-stream (empty File.type fallback),
969
+ // so `.heic`/`.heif` rows are hydrated by filename too;
970
+ // normalizeImageBase64 sniffs the bytes and rewrites only genuine
971
+ // HEIF, which Chromium-based clients cannot decode. Filename and
972
+ // sizeBytes keep describing the stored original, which
973
+ // /attachments/:id/content serves verbatim for downloads.
974
+ const isImage = a.mimeType.startsWith("image/");
975
+ const isLegacyHeic = !isImage && isHeicFilename(a.originalFilename);
976
+ const full =
977
+ isImage || isLegacyHeic
978
+ ? getAttachmentById(a.id, { hydrateFileData: true })
979
+ : null;
980
+ const display = full?.dataBase64
981
+ ? normalizeImageBase64(a.mimeType, full.dataBase64)
982
+ : null;
983
+ // Image rows carry data even when unconverted (thumbnails); a
984
+ // non-image row only becomes renderable once conversion yields a
985
+ // JPEG, so it stays metadata-only when conversion is unavailable.
986
+ const useDisplay =
987
+ display && (isImage || display.converted) ? display : null;
944
988
  return {
945
989
  id: a.id,
946
990
  filename: a.originalFilename,
947
- mimeType: a.mimeType,
991
+ mimeType: useDisplay?.mimeType ?? a.mimeType,
948
992
  sizeBytes: a.sizeBytes,
949
- kind: a.kind,
993
+ kind: useDisplay?.converted
994
+ ? classifyKind(useDisplay.mimeType)
995
+ : a.kind,
996
+ ...(useDisplay ? { data: useDisplay.dataBase64 } : {}),
950
997
  ...(a.thumbnailBase64 ? { thumbnailData: a.thumbnailBase64 } : {}),
951
998
  fileBacked: true,
952
999
  };
@@ -1078,6 +1125,12 @@ export function handleListMessages({
1078
1125
  ? { subagentNotification: m.subagentNotification }
1079
1126
  : {}),
1080
1127
  ...(m.acpNotification ? { acpNotification: m.acpNotification } : {}),
1128
+ ...(m.backgroundEventNotification
1129
+ ? { backgroundEventNotification: true }
1130
+ : {}),
1131
+ ...(m.backgroundToolCompletion
1132
+ ? { backgroundToolCompletion: m.backgroundToolCompletion }
1133
+ : {}),
1081
1134
  ...(m.slackMessage ? { slackMessage: m.slackMessage } : {}),
1082
1135
  };
1083
1136
  });
@@ -1245,13 +1298,20 @@ export async function handleSendMessage(
1245
1298
  interface?: string;
1246
1299
  conversationType?: string;
1247
1300
  automated?: boolean;
1301
+ // Persist the user message but suppress it from the UI transcript (kept in
1302
+ // LLM history). Used by flows like research-onboarding's "Let's chat"
1303
+ // handoff to prime a proactive assistant greeting without showing the
1304
+ // triggering user message. Honored on the standard send path only.
1305
+ hidden?: boolean;
1248
1306
  bypassSecretCheck?: boolean;
1249
1307
  hostHomeDir?: string;
1250
1308
  hostUsername?: string;
1251
1309
  clientTimezone?: unknown;
1310
+ clientOs?: unknown;
1252
1311
  clientId?: string;
1253
1312
  clientMessageId?: string;
1254
1313
  inferenceProfile?: string | null;
1314
+ enabledPlugins?: string[] | null;
1255
1315
  riskThreshold?: string;
1256
1316
  onboarding?: {
1257
1317
  tools: string[];
@@ -1311,6 +1371,18 @@ export async function handleSendMessage(
1311
1371
  );
1312
1372
  }
1313
1373
  }
1374
+ // `undefined` leaves the stored scope untouched; `null` clears it to the
1375
+ // default; `[]` scopes the chat to no plugins.
1376
+ const requestedEnabledPlugins = body.enabledPlugins;
1377
+ if (
1378
+ requestedEnabledPlugins != null &&
1379
+ (!Array.isArray(requestedEnabledPlugins) ||
1380
+ requestedEnabledPlugins.some((p) => typeof p !== "string"))
1381
+ ) {
1382
+ throw new BadRequestError(
1383
+ "enabledPlugins must be an array of strings or null",
1384
+ );
1385
+ }
1314
1386
  if (
1315
1387
  requestedRiskThreshold !== undefined &&
1316
1388
  !isValidRiskThreshold(requestedRiskThreshold)
@@ -1347,6 +1419,15 @@ export async function handleSendMessage(
1347
1419
  typeof body.clientTimezone === "string"
1348
1420
  ? (canonicalizeTimeZone(body.clientTimezone) ?? undefined)
1349
1421
  : undefined;
1422
+ // Client OS surface ("web" | "ios" | "macos" | "android"), reported
1423
+ // separately from the transport `interface`. Validated against the dedicated
1424
+ // `ClientOs` value set (NOT the interface vocabulary) and only kept when it
1425
+ // resolves — it drives the per-turn `client_os:` context line, never
1426
+ // transport/host-proxy gating.
1427
+ const clientOs =
1428
+ typeof body.clientOs === "string"
1429
+ ? (parseClientOs(body.clientOs) ?? undefined)
1430
+ : undefined;
1350
1431
 
1351
1432
  // Reject non-string content values (numbers, objects, etc.)
1352
1433
  if (content != null && typeof content !== "string") {
@@ -1506,11 +1587,13 @@ export async function handleSendMessage(
1506
1587
  hostHomeDir: body.hostHomeDir,
1507
1588
  hostUsername: body.hostUsername,
1508
1589
  ...(clientTimezone ? { clientTimezone } : {}),
1590
+ ...(clientOs ? { clientOs } : {}),
1509
1591
  } satisfies HostProxyTransportMetadata)
1510
1592
  : ({
1511
1593
  channelId: sourceChannel,
1512
1594
  interfaceId: sourceInterface,
1513
1595
  ...(clientTimezone ? { clientTimezone } : {}),
1596
+ ...(clientOs ? { clientOs } : {}),
1514
1597
  } satisfies NonHostProxyTransportMetadata);
1515
1598
 
1516
1599
  const conversation = await smDeps.getOrCreateConversation(
@@ -1530,6 +1613,10 @@ export async function handleSendMessage(
1530
1613
  });
1531
1614
  }
1532
1615
 
1616
+ if (requestedEnabledPlugins !== undefined) {
1617
+ conversation.setEnabledPlugins(requestedEnabledPlugins);
1618
+ }
1619
+
1533
1620
  // Store pre-chat onboarding context on the conversation when this is the
1534
1621
  // very first message (no prior messages loaded). Artifact persistence
1535
1622
  // (IDENTITY.md, USER.md, sidecar) runs before either the canned greeting
@@ -1906,6 +1993,10 @@ export async function handleSendMessage(
1906
1993
  userMessageInterface: sourceInterface,
1907
1994
  assistantMessageInterface: sourceInterface,
1908
1995
  ...(body.automated === true ? { automated: true } : {}),
1996
+ // Carry the transcript-suppression flag through the queue so a
1997
+ // hidden send that lands mid-turn stays hidden when drained —
1998
+ // the drain path persists this metadata and skips the echo.
1999
+ ...(body.hidden === true ? { hidden: true } : {}),
1909
2000
  },
1910
2001
  isInteractive,
1911
2002
  sourceActorPrincipalId,
@@ -1927,21 +2018,34 @@ export async function handleSendMessage(
1927
2018
  // here must not turn the 202 response into a 500 — that would leave
1928
2019
  // the client showing "Failed to send" for a message the daemon will
1929
2020
  // process from the queue.
1930
- try {
1931
- // Supersede interactions left pending by the in-flight turn: auto-deny
1932
- // confirmations (with canonical/client sync) and steer to the enqueued
1933
- // message if an ask_question is parked. Centralized so the CLI signal
1934
- // path (signals/user-message.ts) gets identical handling.
1935
- supersedePendingInteractionsOnEnqueue(mapping.conversationId, requestId);
1936
-
1937
- // Expire any orphaned canonical requests that survived without a
1938
- // matching in-memory pending interaction (e.g. prompter timeouts).
1939
- expireOrphanedCanonicalRequests(mapping.conversationId);
1940
- } catch (err) {
1941
- log.warn(
1942
- { err, conversationId: mapping.conversationId },
1943
- "Post-enqueue auto-deny failed queued message unaffected",
1944
- );
2021
+ //
2022
+ // Supersede encodes user intent a typed message while a prompt is open
2023
+ // means the user chose to move on. A hidden send is a machine signal
2024
+ // (e.g. the channel-setup wizard-close marker), not a user decision: it
2025
+ // must not auto-deny live approval prompts or steer a parked
2026
+ // ask_question to a message the user never typed. Daemon-injected
2027
+ // synthetic messages (subagent/ACP notifications) skip this path the
2028
+ // same way by enqueuing directly.
2029
+ if (body.hidden !== true) {
2030
+ try {
2031
+ // Supersede interactions left pending by the in-flight turn: auto-deny
2032
+ // confirmations (with canonical/client sync) and steer to the enqueued
2033
+ // message if an ask_question is parked. Centralized so the CLI signal
2034
+ // path (signals/user-message.ts) gets identical handling.
2035
+ supersedePendingInteractionsOnEnqueue(
2036
+ mapping.conversationId,
2037
+ requestId,
2038
+ );
2039
+
2040
+ // Expire any orphaned canonical requests that survived without a
2041
+ // matching in-memory pending interaction (e.g. prompter timeouts).
2042
+ expireOrphanedCanonicalRequests(mapping.conversationId);
2043
+ } catch (err) {
2044
+ log.warn(
2045
+ { err, conversationId: mapping.conversationId },
2046
+ "Post-enqueue auto-deny failed — queued message unaffected",
2047
+ );
2048
+ }
1945
2049
  }
1946
2050
 
1947
2051
  return {
@@ -1957,7 +2061,11 @@ export async function handleSendMessage(
1957
2061
  // before dispatching, so an idle conversation with lingering confirmations
1958
2062
  // (e.g. the user never responded to a tool-approval prompt) must deny
1959
2063
  // them before starting the new turn.
1960
- if (conversation.hasAnyPendingConfirmation()) {
2064
+ // Hidden sends are machine signals, not user decisions — like the queue
2065
+ // branch's supersede bypass above, they must not deny confirmations that
2066
+ // outlived a turn (e.g. a guardian approval still awaiting a channel
2067
+ // reply). The next visible send performs the cleanup instead.
2068
+ if (body.hidden !== true && conversation.hasAnyPendingConfirmation()) {
1961
2069
  for (const interaction of pendingInteractions.getByConversation(
1962
2070
  mapping.conversationId,
1963
2071
  )) {
@@ -2314,7 +2422,13 @@ export async function handleSendMessage(
2314
2422
  content: resolvedContent,
2315
2423
  attachments,
2316
2424
  requestId,
2317
- metadata: body.automated === true ? { automated: true } : undefined,
2425
+ metadata:
2426
+ body.automated === true || body.hidden === true
2427
+ ? {
2428
+ ...(body.automated === true ? { automated: true } : {}),
2429
+ ...(body.hidden === true ? { hidden: true } : {}),
2430
+ }
2431
+ : undefined,
2318
2432
  clientMessageId,
2319
2433
  });
2320
2434
 
@@ -2328,14 +2442,20 @@ export async function handleSendMessage(
2328
2442
  };
2329
2443
  }
2330
2444
 
2331
- broadcastMessage({
2332
- type: "user_message_echo",
2333
- text: resolvedContent,
2334
- conversationId: mapping.conversationId,
2335
- messageId,
2336
- requestId,
2337
- clientMessageId,
2338
- });
2445
+ // A hidden message is suppressed from the UI transcript: don't echo it back
2446
+ // to clients (the echo would render a user bubble the list-messages filter
2447
+ // otherwise hides). The turn still runs below, and the assistant's reply
2448
+ // streams normally — so the chat reads as a proactive greeting.
2449
+ if (body.hidden !== true) {
2450
+ broadcastMessage({
2451
+ type: "user_message_echo",
2452
+ text: resolvedContent,
2453
+ conversationId: mapping.conversationId,
2454
+ messageId,
2455
+ requestId,
2456
+ clientMessageId,
2457
+ });
2458
+ }
2339
2459
  publishConversationMessagesChanged(mapping.conversationId, originClientId);
2340
2460
 
2341
2461
  // Fire-and-forget the agent loop; events flow to the hub via broadcastMessage.
@@ -2344,6 +2464,7 @@ export async function handleSendMessage(
2344
2464
  onEvent: broadcastMessage,
2345
2465
  isInteractive,
2346
2466
  isUserMessage: true,
2467
+ ...(body.hidden === true ? { isHiddenPrompt: true } : {}),
2347
2468
  })
2348
2469
  .catch((err) => {
2349
2470
  log.error(
@@ -2619,9 +2740,9 @@ export async function handleGetSuggestion(
2619
2740
  * Full-text search across all conversations (message content + titles).
2620
2741
  * Returns ranked results grouped by conversation, each with matching message excerpts.
2621
2742
  */
2622
- function handleSearchConversations({
2743
+ async function handleSearchConversations({
2623
2744
  queryParams,
2624
- }: RouteHandlerArgs): Record<string, unknown> {
2745
+ }: RouteHandlerArgs): Promise<Record<string, unknown>> {
2625
2746
  const query = queryParams?.q ?? "";
2626
2747
  if (!query.trim()) {
2627
2748
  throw new BadRequestError("q query parameter is required");
@@ -2632,7 +2753,7 @@ function handleSearchConversations({
2632
2753
  ? Number(queryParams.maxMessagesPerConversation)
2633
2754
  : undefined;
2634
2755
 
2635
- const results = searchConversations(query, {
2756
+ const results = await searchConversations(query, {
2636
2757
  ...(limit !== undefined && !isNaN(limit) ? { limit } : {}),
2637
2758
  ...(maxMessagesPerConversation !== undefined &&
2638
2759
  !isNaN(maxMessagesPerConversation)
@@ -2834,6 +2955,12 @@ export const ROUTES: RouteDefinition[] = [
2834
2955
  conversationType: z.string().optional(),
2835
2956
  slashCommand: z.string().optional(),
2836
2957
  clientTimezone: z.string().optional(),
2958
+ clientOs: z
2959
+ .string()
2960
+ .optional()
2961
+ .describe(
2962
+ 'Client OS surface ("web" | "ios" | "macos" | "android"), reported separately from `interface`. Drives the per-turn `client_os` context only; does not affect transport/host-proxy capabilities.',
2963
+ ),
2837
2964
  clientMessageId: z
2838
2965
  .string()
2839
2966
  .describe(
@@ -2841,7 +2968,20 @@ export const ROUTES: RouteDefinition[] = [
2841
2968
  )
2842
2969
  .optional(),
2843
2970
  inferenceProfile: z.string().nullable().optional(),
2971
+ enabledPlugins: z
2972
+ .array(z.string())
2973
+ .nullable()
2974
+ .optional()
2975
+ .describe(
2976
+ "Plugin ids that scope this conversation to a subset of installed plugins (first-party defaults are always available). When present on a message, it sets/updates the conversation's plugin scope (the web client sends it only on the first message of a new chat). null clears the scope to default (all enabled plugins); omitting the field leaves the existing scope unchanged.",
2977
+ ),
2844
2978
  riskThreshold: z.enum(VALID_RISK_THRESHOLDS).optional(),
2979
+ hidden: z
2980
+ .boolean()
2981
+ .optional()
2982
+ .describe(
2983
+ "When true, persist the user message but suppress it from the UI transcript (it stays in LLM-side history and still drives the turn). Used for machine signals the user never typed (proactive-greeting priming, channel-setup wizard close). Suppression covers the queued path too: a hidden send that lands mid-turn returns { queued: true, requestId } but never appears in list-messages queued snapshots, emits no echo, and does not supersede pending interactions. Honored on the standard send path only — slash-command content bypasses it.",
2984
+ ),
2845
2985
  onboarding: z
2846
2986
  .object({
2847
2987
  tools: z.array(z.string()),
@@ -12,6 +12,7 @@ import {
12
12
  setConversationKey,
13
13
  } from "../../persistence/conversation-key-store.js";
14
14
  import { getDb } from "../../persistence/db-connection.js";
15
+ import { enqueueLexicalIndexForMessage } from "../../persistence/job-handlers/message-lexical.js";
15
16
  import {
16
17
  conversations as conversationsTable,
17
18
  messages as messagesTable,
@@ -59,7 +60,9 @@ function resolveTimestamps(
59
60
  const convCreatedAt = conv.createdAt ?? now;
60
61
  const convUpdatedAt = conv.updatedAt ?? conv.createdAt ?? now;
61
62
  const messageTimestamps = messages.map((msg, i) => {
62
- if (msg.createdAt != null) return msg.createdAt;
63
+ if (msg.createdAt != null) {
64
+ return msg.createdAt;
65
+ }
63
66
  return convCreatedAt + i;
64
67
  });
65
68
  return { convCreatedAt, convUpdatedAt, messageTimestamps };
@@ -190,6 +193,10 @@ async function handleConversationsImport({ body }: RouteHandlerArgs) {
190
193
  err instanceof Error ? err.message : String(err),
191
194
  );
192
195
  }
196
+ // Dual-write the imported message into the lexical index. Import inserts
197
+ // rows directly, bypassing `onMessagePersisted`, so enqueue here to keep
198
+ // the lexical index in lockstep with the segment index.
199
+ enqueueLexicalIndexForMessage(dbMessages[i].id);
193
200
  }
194
201
 
195
202
  if (conv.sourceKey) {
@@ -48,6 +48,12 @@ const CredentialPromptParams = z.object({
48
48
 
49
49
  export type CredentialPromptResult = {
50
50
  ok: boolean;
51
+ /**
52
+ * True when the user explicitly dismissed the secure prompt. This is a valid
53
+ * outcome, not a failure — the CLI surfaces it as an informational message
54
+ * and a distinct exit code rather than an error.
55
+ */
56
+ cancelled?: boolean;
51
57
  error?: string;
52
58
  service?: string;
53
59
  field?: string;
@@ -76,11 +82,19 @@ async function handleCredentialPrompt({ body = {} }: RouteHandlerArgs) {
76
82
  });
77
83
 
78
84
  if (!result.value) {
79
- const reason =
80
- result.error === "unsupported_channel"
81
- ? "No connected client supports secure credential entry"
82
- : "User cancelled the credential prompt";
83
- return { ok: false, error: reason };
85
+ if (result.error === "unsupported_channel") {
86
+ return {
87
+ ok: false,
88
+ error: "No connected client supports secure credential entry",
89
+ };
90
+ }
91
+ // An explicit user cancel is a valid flow, not a failure. Keep it distinct
92
+ // from a timeout (no response in the permission window) so the CLI can exit
93
+ // with the user-interrupt convention instead of a generic error.
94
+ if (result.reason === "timed_out") {
95
+ return { ok: false, error: "The credential prompt timed out" };
96
+ }
97
+ return { ok: false, cancelled: true, error: "Cancelled by the user" };
84
98
  }
85
99
 
86
100
  const persisted = await persistPromptedCredential({
@@ -142,6 +156,7 @@ export const ROUTES: RouteDefinition[] = [
142
156
  requestBody: CredentialPromptParams,
143
157
  responseBody: z.object({
144
158
  ok: z.boolean(),
159
+ cancelled: z.boolean().optional(),
145
160
  error: z.string().optional(),
146
161
  service: z.string().optional(),
147
162
  field: z.string().optional(),
@@ -34,6 +34,7 @@ function getDatabaseSizeBytes(): number | null {
34
34
  function getMemoryItemCount(): number {
35
35
  try {
36
36
  const rows = rawAll<{ c: number }>(
37
+ "debug:getMemoryItemCount",
37
38
  "SELECT COUNT(*) AS c FROM memory_graph_nodes",
38
39
  );
39
40
  return rows[0]?.c ?? 0;
@@ -40,11 +40,14 @@ function listAllDocuments(): Array<{
40
40
  updatedAt: number;
41
41
  }> {
42
42
  try {
43
- const results = rawAll<DocumentListRow>(/*sql*/ `
43
+ const results = rawAll<DocumentListRow>(
44
+ "documents:listAllDocuments",
45
+ /*sql*/ `
44
46
  SELECT surface_id, conversation_id, title, word_count, created_at, updated_at
45
47
  FROM documents
46
48
  ORDER BY updated_at DESC
47
- `);
49
+ `,
50
+ );
48
51
 
49
52
  log.info({ count: results.length }, "Listed documents");
50
53
  return results.map((row) => ({