@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
@@ -44,6 +44,13 @@ export interface TrustContext {
44
44
  memberStatus?: string;
45
45
  /** Channel policy of the requester's channel (ACL). */
46
46
  memberPolicy?: string;
47
+ /**
48
+ * Prior-interaction count for the requester's member channel, sourced from
49
+ * the gateway trust verdict (gateway owns interaction telemetry). Undefined
50
+ * when the verdict carries no member telemetry (unknown sender) or when trust
51
+ * was resolved locally without a gateway verdict.
52
+ */
53
+ requesterInteractionCount?: number;
47
54
  }
48
55
 
49
56
  /**
@@ -75,17 +82,25 @@ export const FALLBACK_TURN_TRUST: TrustContext = {
75
82
  /**
76
83
  * Resolve the effective trust class for an actor.
77
84
  *
78
- * When HTTP auth is disabled (dev bypass), always returns `'guardian'`
79
- * so that control-plane gates don't block local development.
85
+ * Trust is a property of the actor, never of the deployment's auth posture.
86
+ * The dev/local bypass therefore fills in `'guardian'` only when NO actor was
87
+ * resolved: local/native turns reach the daemon without a channel-resolved
88
+ * trustContext, and in an auth-disabled (local) deployment that unresolved
89
+ * actor is the guardian. A *present* trustContext always reflects the real
90
+ * actor — even under `DISABLE_HTTP_AUTH`, which is the standing config in
91
+ * platform-managed deployments — so a resolved non-guardian channel actor is
92
+ * never elevated to guardian.
80
93
  *
81
- * When no trust context is available (e.g. desktop-only conversations that
82
- * don't go through channel trust resolution), defaults to `'unknown'`
83
- * to fail-closed.
94
+ * When no trust context is available and auth is enabled (e.g. a desktop-only
95
+ * conversation that hasn't gone through channel trust resolution), defaults to
96
+ * `'unknown'` to fail-closed.
84
97
  */
85
98
  export function resolveTrustClass(
86
99
  trustContext: TrustContext | undefined,
87
100
  ): TrustClass {
88
- if (isHttpAuthDisabled()) return "guardian";
101
+ if (trustContext === undefined && isHttpAuthDisabled()) {
102
+ return "guardian";
103
+ }
89
104
  return trustContext?.trustClass ?? "unknown";
90
105
  }
91
106
 
@@ -115,6 +115,99 @@ describe("TurnLatencyTracker", () => {
115
115
  expect(breakdown!.providerDurationMs).toBe(135);
116
116
  });
117
117
 
118
+ test("a failed first attempt is superseded by the successful retry", () => {
119
+ const t = new TurnLatencyTracker();
120
+ clock = 0;
121
+ t.mark("turn_start");
122
+ clock = 10;
123
+ t.mark("prompt_hook_start"); // queue = 10
124
+ clock = 110;
125
+ t.mark("prompt_hook_end"); // memory_context = 100
126
+ // First attempt: tools resolved and request sent, then the provider
127
+ // rejects (context overflow) — no first_token, no call_complete.
128
+ clock = 120;
129
+ t.mark("tools_resolved");
130
+ clock = 130;
131
+ t.mark("request_sent");
132
+ // Recovery runs, then the loop re-issues the call.
133
+ clock = 1000;
134
+ t.mark("tools_resolved");
135
+ clock = 1010;
136
+ t.mark("request_sent");
137
+ clock = 1200;
138
+ t.markFirstToken("text");
139
+ clock = 1260;
140
+ t.mark("call_complete");
141
+
142
+ const { breakdown } = t.serializeSince(0);
143
+ // ttft / provider-duration reflect ONLY the successful attempt (1010),
144
+ // not the failed attempt's request_sent (130).
145
+ expect(breakdown!.ttftMs).toBe(190);
146
+ expect(breakdown!.providerDurationMs).toBe(250);
147
+ // The failed attempt's per-call marks are gone: no duplicate phases.
148
+ expect(breakdown!.phases.map((p) => p.key)).toEqual([
149
+ "queue",
150
+ "memory_context",
151
+ "setup",
152
+ "request_prep",
153
+ "ttft",
154
+ "generation",
155
+ ]);
156
+ expect(phaseMap(breakdown!.phases).request_prep).toBe(10);
157
+ });
158
+
159
+ test("a failed retry mid tool-loop is superseded", () => {
160
+ const t = new TurnLatencyTracker();
161
+ clock = 0;
162
+ t.mark("turn_start");
163
+ clock = 10;
164
+ t.mark("prompt_hook_start");
165
+ clock = 110;
166
+ t.mark("prompt_hook_end");
167
+ clock = 120;
168
+ t.mark("tools_resolved");
169
+ clock = 130;
170
+ t.mark("request_sent");
171
+ clock = 430;
172
+ t.markFirstToken("thinking");
173
+ clock = 700;
174
+ t.mark("call_complete");
175
+ const first = t.serializeSince(0);
176
+
177
+ // Second call fails after streaming a partial token, then retries.
178
+ clock = 1000;
179
+ t.mark("tools_resolved");
180
+ clock = 1010;
181
+ t.mark("request_sent");
182
+ clock = 1100;
183
+ t.markFirstToken("text"); // partial stream before the failure
184
+ clock = 2000;
185
+ t.mark("tools_resolved");
186
+ clock = 2010;
187
+ t.mark("request_sent");
188
+ clock = 2200;
189
+ t.markFirstToken("text");
190
+ clock = 2260;
191
+ t.mark("call_complete");
192
+
193
+ const { breakdown } = t.serializeSince(first.cursor);
194
+ // Only the successful retry (2010) drives ttft / provider-duration; the
195
+ // failed attempt's request_sent (1010) and its stray first_token (1100)
196
+ // are dropped.
197
+ expect(breakdown!.ttftMs).toBe(190);
198
+ expect(breakdown!.providerDurationMs).toBe(250);
199
+ expect(breakdown!.firstTokenKind).toBe("text");
200
+ // No duplicate per-call phases from the failed attempt.
201
+ expect(breakdown!.phases.map((p) => p.key)).toEqual([
202
+ "setup",
203
+ "request_prep",
204
+ "ttft",
205
+ "generation",
206
+ ]);
207
+ expect(phaseMap(breakdown!.phases).request_prep).toBe(10);
208
+ expect(breakdown!.totalToFirstTokenMs).toBeUndefined();
209
+ });
210
+
118
211
  test("no marks serializes to null", () => {
119
212
  const t = new TurnLatencyTracker();
120
213
  expect(t.serializeSince(0).breakdown).toBeNull();
@@ -56,9 +56,47 @@ export class TurnLatencyTracker {
56
56
 
57
57
  /** Stamp a point-in-time mark. Cheap (`Date.now()`); safe to over-call. */
58
58
  mark(name: LatencyMark): void {
59
+ // A retried provider call re-issues `request_sent`; drop the failed
60
+ // attempt's stale marks first so the retry's segment measures only itself.
61
+ if (name === "request_sent") this.supersedeFailedAttempt();
59
62
  this.marks.push({ name, at: Date.now() });
60
63
  }
61
64
 
65
+ /**
66
+ * Discard the per-call marks of a prior provider attempt that never
67
+ * completed. A call retried within the same turn (context-overflow recovery,
68
+ * post-model-call repair on a rejection) leaves a `request_sent` with no
69
+ * `call_complete` and no `usage` event to serialize it and advance the
70
+ * cursor; the next successful segment would otherwise measure ttft /
71
+ * provider-duration / phases from the failed attempt's marks.
72
+ *
73
+ * Detection is cursor-free: a completed call always stamps `call_complete`
74
+ * before its `usage` event, so a `request_sent` with none after it belongs
75
+ * to a call that never returned. A retry re-stamps its setup `tools_resolved`
76
+ * before this `request_sent`, so that trailing mark is preserved as the
77
+ * successful segment's setup mark.
78
+ */
79
+ private supersedeFailedAttempt(): void {
80
+ let failedRequestSent = -1;
81
+ for (let i = this.marks.length - 1; i >= 0; i--) {
82
+ const name = this.marks[i]!.name;
83
+ if (name === "call_complete") return; // prior attempt finished — nothing stale
84
+ if (name === "request_sent") {
85
+ failedRequestSent = i;
86
+ break;
87
+ }
88
+ }
89
+ if (failedRequestSent === -1) return; // no prior attempt this turn
90
+ // Drop from the failed attempt's paired setup mark (its `tools_resolved`,
91
+ // if any) through its trailing marks, keeping a retry `tools_resolved`
92
+ // already stamped as the last mark.
93
+ let start = failedRequestSent;
94
+ if (this.marks[start - 1]?.name === "tools_resolved") start -= 1;
95
+ let end = this.marks.length;
96
+ if (this.marks[end - 1]!.name === "tools_resolved") end -= 1;
97
+ this.marks.splice(start, end - start);
98
+ }
99
+
62
100
  /**
63
101
  * Stamp the first streamed token of the current call, carrying its kind on
64
102
  * the mark. The caller fires this once per call (guarded loop-side), so each
@@ -23,6 +23,7 @@ import { backfillMessageIdOnLogs } from "../persistence/llm-request-log-store.js
23
23
  import type { Message } from "../providers/types.js";
24
24
  import { broadcastMessage } from "../runtime/assistant-event-hub.js";
25
25
  import { publishConversationMessagesChanged } from "../runtime/sync/resource-sync-events.js";
26
+ import type { CompletedBackgroundTool } from "../tools/background-tool-registry.js";
26
27
  import { getLogger } from "../util/logger.js";
27
28
  import type { Conversation } from "./conversation.js";
28
29
  import type { ServerMessage } from "./message-protocol.js";
@@ -266,13 +267,15 @@ export async function persistWakeTailMessage(
266
267
  *
267
268
  * Mirrors {@link persistWakeTailMessage}'s channel/interface/provenance
268
269
  * metadata, but stamps `kind: "background-event"` (+ the originating `source`)
269
- * for identification, skips indexing (the body may carry untrusted command
270
- * output), and is NOT flagged hidden so the trigger shows in the transcript.
270
+ * for identification and skips indexing (the body may carry untrusted command
271
+ * output). The `backgroundEventSource` stamp lets clients hide this row from the
272
+ * rendered transcript — the user-facing wake card carries the status instead.
271
273
  */
272
274
  export async function persistWakeTriggerMessage(
273
275
  conversation: Conversation,
274
276
  message: Message,
275
277
  source: string,
278
+ completion?: CompletedBackgroundTool,
276
279
  ): Promise<void> {
277
280
  const turnChannelCtx = conversation.getTurnChannelContext();
278
281
  const turnInterfaceCtx = conversation.getTurnInterfaceContext();
@@ -287,6 +290,7 @@ export async function persistWakeTriggerMessage(
287
290
  kind: "background-event",
288
291
  backgroundEventSource: source,
289
292
  automated: true,
293
+ ...(completion ? { backgroundToolCompletion: completion } : {}),
290
294
  };
291
295
  const persisted = await addMessage(
292
296
  conversation.conversationId,
@@ -309,12 +313,10 @@ export async function persistWakeTriggerMessage(
309
313
  "wake trigger persist: syncMessageToDisk failed (non-fatal)",
310
314
  );
311
315
  }
312
- // Tell connected clients the message list changed so they refetch and the
313
- // visible trigger renders live. The normal user-send path publishes the same
314
- // invalidation after persisting a user message; without it a wake that
315
- // produces no assistant stream (silent no-op), or a conversation open in
316
- // another client, would not show the <background_event> row until a manual
317
- // reload.
316
+ // Tell connected clients the message list changed so they refetch. The
317
+ // trigger row itself is hidden from the transcript (clients drop rows carrying
318
+ // `backgroundEventSource`), but the refetch keeps other clients' state in sync
319
+ // and lets a wake that produces no assistant stream still settle cleanly.
318
320
  try {
319
321
  publishConversationMessagesChanged(conversation.conversationId);
320
322
  } catch (err) {
@@ -31,12 +31,14 @@ const CONVERSATION_ID = "conv-test-123";
31
31
  function seedDocument(surfaceId: string = SURFACE_ID): void {
32
32
  const now = Date.now();
33
33
  rawRun(
34
+ "test:seedConversation",
34
35
  /*sql*/ `INSERT OR IGNORE INTO conversations (id, created_at, updated_at) VALUES (?, ?, ?)`,
35
36
  CONVERSATION_ID,
36
37
  now,
37
38
  now,
38
39
  );
39
40
  rawRun(
41
+ "test:seedDocument",
40
42
  /*sql*/ `INSERT OR IGNORE INTO documents (surface_id, conversation_id, title, content, word_count, created_at, updated_at)
41
43
  VALUES (?, ?, 'Test Doc', 'body', 2, ?, ?)`,
42
44
  surfaceId,
@@ -331,7 +333,11 @@ describe("cascade on document delete", () => {
331
333
  expect(listComments(SURFACE_ID)).toHaveLength(1);
332
334
 
333
335
  // Delete the document — FK cascade should remove comments.
334
- rawRun(/*sql*/ `DELETE FROM documents WHERE surface_id = ?`, SURFACE_ID);
336
+ rawRun(
337
+ "test:deleteDocument",
338
+ /*sql*/ `DELETE FROM documents WHERE surface_id = ?`,
339
+ SURFACE_ID,
340
+ );
335
341
 
336
342
  expect(listComments(SURFACE_ID)).toHaveLength(0);
337
343
  });
@@ -92,6 +92,7 @@ export function createComment(params: {
92
92
  const now = Date.now();
93
93
 
94
94
  rawRun(
95
+ "docComments:createComment",
95
96
  /*sql*/ `INSERT INTO document_comments
96
97
  (id, surface_id, conversation_id, author, content,
97
98
  anchor_start, anchor_end, anchor_text, parent_comment_id,
@@ -132,6 +133,7 @@ export function createComment(params: {
132
133
 
133
134
  export function getComment(id: string): CommentRecord | null {
134
135
  const row = rawGet<CommentRow>(
136
+ "docComments:getComment",
135
137
  /*sql*/ `SELECT * FROM document_comments WHERE id = ?`,
136
138
  id,
137
139
  );
@@ -162,6 +164,7 @@ export function listComments(
162
164
 
163
165
  const where = conditions.join(" AND ");
164
166
  const rows = rawAll<CommentRow>(
167
+ "docComments:listComments",
165
168
  /*sql*/ `SELECT * FROM document_comments WHERE ${where} ORDER BY created_at ASC`,
166
169
  ...params,
167
170
  );
@@ -172,6 +175,7 @@ export function listComments(
172
175
  export function resolveComment(id: string, resolvedBy: string): boolean {
173
176
  const now = Date.now();
174
177
  const changes = rawRun(
178
+ "docComments:resolveComment",
175
179
  /*sql*/ `UPDATE document_comments
176
180
  SET status = 'resolved', resolved_by = ?, resolved_at = ?, updated_at = ?
177
181
  WHERE id = ?`,
@@ -189,6 +193,7 @@ export function resolveComment(id: string, resolvedBy: string): boolean {
189
193
  export function reopenComment(id: string): boolean {
190
194
  const now = Date.now();
191
195
  const changes = rawRun(
196
+ "docComments:reopenComment",
192
197
  /*sql*/ `UPDATE document_comments
193
198
  SET status = 'open', resolved_by = NULL, resolved_at = NULL, updated_at = ?
194
199
  WHERE id = ?`,
@@ -204,6 +209,7 @@ export function reopenComment(id: string): boolean {
204
209
  export function updateCommentContent(id: string, content: string): boolean {
205
210
  const now = Date.now();
206
211
  const changes = rawRun(
212
+ "docComments:updateCommentContent",
207
213
  /*sql*/ `UPDATE document_comments SET content = ?, updated_at = ? WHERE id = ?`,
208
214
  content,
209
215
  now,
@@ -218,6 +224,7 @@ export function updateCommentContent(id: string, content: string): boolean {
218
224
  export function deleteComment(id: string): boolean {
219
225
  // Replies cascade-delete via the self-referential FK on parent_comment_id.
220
226
  const changes = rawRun(
227
+ "docComments:deleteComment",
221
228
  /*sql*/ `DELETE FROM document_comments WHERE id = ?`,
222
229
  id,
223
230
  );
@@ -229,6 +236,7 @@ export function deleteComment(id: string): boolean {
229
236
 
230
237
  export function getCommentCountForDocument(surfaceId: string): number {
231
238
  const row = rawGet<{ count: number }>(
239
+ "docComments:getCommentCount",
232
240
  /*sql*/ `SELECT COUNT(*) AS count FROM document_comments
233
241
  WHERE surface_id = ? AND status = 'open'`,
234
242
  surfaceId,
@@ -35,6 +35,7 @@ export function addDocumentConversation(
35
35
  conversationId: string,
36
36
  ): void {
37
37
  rawRun(
38
+ "documents:addDocumentConversation",
38
39
  /*sql*/ `INSERT OR IGNORE INTO document_conversations (surface_id, conversation_id, created_at) VALUES (?, ?, ?)`,
39
40
  surfaceId,
40
41
  conversationId,
@@ -78,6 +79,7 @@ function mapRowToRecord(row: DocumentRow): DocumentRecord {
78
79
  export function getDocumentById(surfaceId: string): DocumentRecord | null {
79
80
  try {
80
81
  const row = rawGet<DocumentRow>(
82
+ "documents:getDocumentById",
81
83
  /*sql*/ `SELECT surface_id, conversation_id, title, content, word_count, created_at, updated_at
82
84
  FROM documents
83
85
  WHERE surface_id = ?`,
@@ -104,6 +106,7 @@ export function isDocumentAssociatedWithConversation(
104
106
  ): boolean {
105
107
  try {
106
108
  const row = rawGet<{ found: number }>(
109
+ "documents:isAssociatedWithConversation",
107
110
  /*sql*/ `
108
111
  SELECT 1 AS found
109
112
  FROM document_conversations
@@ -132,6 +135,7 @@ export function getDocumentsForConversation(
132
135
  ): Omit<DocumentRecord, "content">[] {
133
136
  try {
134
137
  const rows = rawAll<DocumentListRow>(
138
+ "documents:getDocumentsForConversation",
135
139
  /*sql*/ `
136
140
  SELECT d.surface_id, dc.conversation_id AS conversation_id,
137
141
  d.title, d.word_count, d.created_at, d.updated_at
@@ -175,6 +179,7 @@ export function searchDocumentsByTitle(
175
179
  const pattern = `%${escapeSqlLikePattern(query)}%`;
176
180
  const rows = options.conversationId
177
181
  ? rawAll<DocumentListRow>(
182
+ "documents:searchByTitle:scoped",
178
183
  /*sql*/ `
179
184
  SELECT d.surface_id, dc.conversation_id AS conversation_id,
180
185
  d.title, d.word_count, d.created_at, d.updated_at
@@ -189,6 +194,7 @@ export function searchDocumentsByTitle(
189
194
  pattern,
190
195
  )
191
196
  : rawAll<DocumentListRow>(
197
+ "documents:searchByTitle:all",
192
198
  /*sql*/ `
193
199
  SELECT surface_id, conversation_id, title, word_count, created_at, updated_at
194
200
  FROM documents
@@ -234,6 +240,7 @@ export function findRecentEmptyDocumentByTitle(
234
240
  try {
235
241
  const threshold = Date.now() - withinMs;
236
242
  const row = rawGet<{ surface_id: string }>(
243
+ "documents:findRecentEmptyByTitle",
237
244
  /*sql*/ `SELECT surface_id FROM documents
238
245
  WHERE conversation_id = ?
239
246
  AND title = ?
@@ -262,10 +269,12 @@ export function findRecentEmptyDocumentByTitle(
262
269
  export function deleteDocument(surfaceId: string): boolean {
263
270
  try {
264
271
  const changes = rawRun(
272
+ "documents:deleteDocument:doc",
265
273
  /*sql*/ `DELETE FROM documents WHERE surface_id = ?`,
266
274
  surfaceId,
267
275
  );
268
276
  rawRun(
277
+ "documents:deleteDocument:associations",
269
278
  /*sql*/ `DELETE FROM document_conversations WHERE surface_id = ?`,
270
279
  surfaceId,
271
280
  );
@@ -310,6 +319,7 @@ export function findInDocument(
310
319
  ): FindResult | null {
311
320
  try {
312
321
  const row = rawGet<{ content: string }>(
322
+ "documents:findInDocument:getContent",
313
323
  /*sql*/ `SELECT content FROM documents WHERE surface_id = ?`,
314
324
  surfaceId,
315
325
  );
@@ -385,6 +395,7 @@ export function saveDocument(params: {
385
395
  try {
386
396
  const now = Date.now();
387
397
  rawRun(
398
+ "documents:saveDocument",
388
399
  `INSERT INTO documents (surface_id, conversation_id, title, content, word_count, created_at, updated_at)
389
400
  VALUES (?, ?, ?, ?, ?, ?, ?)
390
401
  ON CONFLICT(surface_id) DO UPDATE SET
@@ -458,6 +469,7 @@ export function replaceInDocument(
458
469
  ): ReplaceInDocumentResult {
459
470
  try {
460
471
  const row = rawGet<{ content: string }>(
472
+ "documents:replaceInDocument:getContent",
461
473
  /*sql*/ `SELECT content FROM documents WHERE surface_id = ?`,
462
474
  surfaceId,
463
475
  );
@@ -516,6 +528,7 @@ export function replaceInDocument(
516
528
  .split(/\s+/)
517
529
  .filter((w) => w.length > 0).length;
518
530
  rawRun(
531
+ "documents:replaceInDocument:update",
519
532
  /*sql*/ `UPDATE documents SET content = ?, word_count = ?, updated_at = ? WHERE surface_id = ?`,
520
533
  newContent,
521
534
  wordCount,
@@ -545,6 +558,7 @@ export function updateDocumentContent(
545
558
  ): { success: true } | { success: false; error: string } {
546
559
  try {
547
560
  const existing = rawGet<{ content: string }>(
561
+ "documents:updateDocumentContent:get",
548
562
  /*sql*/ `SELECT content FROM documents WHERE surface_id = ?`,
549
563
  surfaceId,
550
564
  );
@@ -559,6 +573,7 @@ export function updateDocumentContent(
559
573
  .split(/\s+/)
560
574
  .filter((w) => w.length > 0).length;
561
575
  rawRun(
576
+ "documents:updateDocumentContent:update",
562
577
  /*sql*/ `UPDATE documents SET content = ?, word_count = ?, updated_at = ? WHERE surface_id = ?`,
563
578
  newContent,
564
579
  wordCount,
@@ -81,6 +81,17 @@ mock.module("../../persistence/conversation-crud.js", () => ({
81
81
  getMessages: (id: string) =>
82
82
  id === "child-conv-1" ? childMessages : parentMessages,
83
83
  messageMetadataSchema,
84
+ parseMessageMetadata: (json: string | null) => {
85
+ if (!json) {
86
+ return undefined;
87
+ }
88
+ try {
89
+ const parsed = messageMetadataSchema.safeParse(JSON.parse(json));
90
+ return parsed.success ? parsed.data : undefined;
91
+ } catch {
92
+ return undefined;
93
+ }
94
+ },
84
95
  reserveMessage: mock(async () => ({ id: "msg-reserve" })),
85
96
  }));
86
97
 
@@ -9,7 +9,7 @@ import { formatLocalTimestamp } from "../daemon/date-context.js";
9
9
  import {
10
10
  getConversation,
11
11
  getMessages,
12
- messageMetadataSchema,
12
+ parseMessageMetadata,
13
13
  } from "../persistence/conversation-crud.js";
14
14
  import { truncate } from "../util/truncate.js";
15
15
 
@@ -29,7 +29,9 @@ function extractAnalysisText(blocks: ContentBlock[]): string {
29
29
  for (const block of blocks) {
30
30
  switch (block.type) {
31
31
  case "text":
32
- if (block.text) parts.push(block.text);
32
+ if (block.text) {
33
+ parts.push(block.text);
34
+ }
33
35
  break;
34
36
  case "tool_use":
35
37
  parts.push(
@@ -141,6 +143,45 @@ export function formatMessageSliceForTranscript(
141
143
  return lines.join("\n");
142
144
  }
143
145
 
146
+ /**
147
+ * Append the `### Subagent: …` section for `msg` when its metadata carries a
148
+ * terminal (completed/failed/aborted) subagent notification; a no-op otherwise.
149
+ *
150
+ * `subagentOptions` controls how the child transcript renders. Callers pass the
151
+ * parent's time zone but NOT its display names: a subagent conversation persists
152
+ * the parent assistant's objective as a `user` message (see subagent/manager.ts),
153
+ * so reusing the parent's names would render the assistant's tasking text under
154
+ * the human user's name. An empty options object keeps child transcripts on
155
+ * generic role labels.
156
+ */
157
+ function appendSubagentSection(
158
+ lines: string[],
159
+ msg: TranscriptMessage,
160
+ subagentOptions: TranscriptFormatOptions = {},
161
+ ): void {
162
+ const notif = parseMessageMetadata(msg.metadata)?.subagentNotification;
163
+ if (
164
+ !notif ||
165
+ (notif.status !== "completed" &&
166
+ notif.status !== "failed" &&
167
+ notif.status !== "aborted") ||
168
+ !notif.conversationId
169
+ ) {
170
+ return;
171
+ }
172
+ const subMessages = getMessages(notif.conversationId);
173
+ lines.push(`### Subagent: ${notif.label} (${notif.status})`);
174
+ lines.push("");
175
+ lines.push(formatSubagentMessages(subMessages, subagentOptions));
176
+ lines.push("");
177
+ }
178
+
179
+ /**
180
+ * Render one message as a transcript block: a `## role (time)` header, the
181
+ * extracted body text, and any terminal subagent section. Role and time honor
182
+ * `options` (display names + time zone); the subagent child transcript inherits
183
+ * only the time zone — see {@link appendSubagentSection}.
184
+ */
144
185
  function appendMessageBlock(
145
186
  lines: string[],
146
187
  msg: TranscriptMessage,
@@ -155,35 +196,7 @@ function appendMessageBlock(
155
196
  lines.push(text);
156
197
  lines.push("");
157
198
 
158
- if (msg.metadata) {
159
- try {
160
- const parsed = messageMetadataSchema.safeParse(JSON.parse(msg.metadata));
161
- if (parsed.success && parsed.data.subagentNotification) {
162
- const notif = parsed.data.subagentNotification;
163
- if (
164
- (notif.status === "completed" ||
165
- notif.status === "failed" ||
166
- notif.status === "aborted") &&
167
- notif.conversationId
168
- ) {
169
- const subMessages = getMessages(notif.conversationId);
170
- lines.push(`### Subagent: ${notif.label} (${notif.status})`);
171
- lines.push("");
172
- // Subagent conversations persist the parent assistant's objective
173
- // as a `user` message (see subagent/manager.ts), so reusing the
174
- // parent's display-name options would render the assistant's
175
- // tasking text under the human user's name. Keep child transcripts
176
- // on generic role labels — and only pass through the time zone.
177
- lines.push(
178
- formatSubagentMessages(subMessages, { timeZone: options.timeZone }),
179
- );
180
- lines.push("");
181
- }
182
- }
183
- } catch {
184
- // Skip unparseable metadata
185
- }
186
- }
199
+ appendSubagentSection(lines, msg, { timeZone: options.timeZone });
187
200
  }
188
201
 
189
202
  export function buildAnalysisTranscript(conversationId: string): string {
@@ -192,7 +205,6 @@ export function buildAnalysisTranscript(conversationId: string): string {
192
205
  return `# Conversation not found: ${conversationId}\n`;
193
206
  }
194
207
 
195
- const allMessages = getMessages(conversationId);
196
208
  const title = conversation.title ?? "Untitled";
197
209
  const lines: string[] = [];
198
210
 
@@ -200,41 +212,11 @@ export function buildAnalysisTranscript(conversationId: string): string {
200
212
  lines.push(`Created: ${formatLocalTimestamp(conversation.createdAt)}`);
201
213
  lines.push("");
202
214
 
203
- for (const msg of allMessages) {
204
- const role = formatRole(msg.role);
205
- const time = formatLocalTimestamp(msg.createdAt);
206
- const content = parseContent(msg.content);
207
- const text = extractAnalysisText(content);
208
-
209
- lines.push(`## ${role} (${time})`);
210
- lines.push(text);
211
- lines.push("");
212
-
213
- // Check for subagent notifications in metadata
214
- if (msg.metadata) {
215
- try {
216
- const parsed = messageMetadataSchema.safeParse(
217
- JSON.parse(msg.metadata),
218
- );
219
- if (parsed.success && parsed.data.subagentNotification) {
220
- const notif = parsed.data.subagentNotification;
221
- if (
222
- (notif.status === "completed" ||
223
- notif.status === "failed" ||
224
- notif.status === "aborted") &&
225
- notif.conversationId
226
- ) {
227
- const subMessages = getMessages(notif.conversationId);
228
- lines.push(`### Subagent: ${notif.label} (${notif.status})`);
229
- lines.push("");
230
- lines.push(formatSubagentMessages(subMessages));
231
- lines.push("");
232
- }
233
- }
234
- } catch {
235
- // Skip unparseable metadata
236
- }
237
- }
215
+ // Analyze-conversation flow renders under generic "User"/"Assistant" labels,
216
+ // so no options are threaded through (see `formatMessageSliceForTranscript`
217
+ // for the display-name variant).
218
+ for (const msg of getMessages(conversationId)) {
219
+ appendMessageBlock(lines, msg);
238
220
  }
239
221
 
240
222
  return lines.join("\n");