@vellumai/assistant 0.11.2 → 0.11.3-staging.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (720) hide show
  1. package/ARCHITECTURE.md +58 -3
  2. package/docs/trusted-contact-access.md +9 -5
  3. package/docs/vellum-doctor.md +195 -0
  4. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  5. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  6. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  7. package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
  8. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
  9. package/node_modules/@vellumai/environments/package.json +2 -1
  10. package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
  11. package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
  12. package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
  13. package/node_modules/@vellumai/environments/src/index.ts +17 -6
  14. package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
  15. package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
  16. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  17. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  19. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
  20. package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
  21. package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
  22. package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
  23. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
  24. package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
  25. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
  26. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
  27. package/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  28. package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  29. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  30. package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
  31. package/openapi.yaml +589 -30
  32. package/package.json +1 -1
  33. package/src/__tests__/agent-image-optimize.test.ts +4 -4
  34. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
  35. package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
  36. package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
  37. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
  38. package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
  39. package/src/__tests__/answered-question-persistence.test.ts +240 -0
  40. package/src/__tests__/anthropic-provider.test.ts +165 -30
  41. package/src/__tests__/app-control-flow.test.ts +9 -8
  42. package/src/__tests__/assistant-event-hub.test.ts +48 -0
  43. package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
  44. package/src/__tests__/attachments-store.test.ts +130 -68
  45. package/src/__tests__/attachments.test.ts +36 -36
  46. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  47. package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
  48. package/src/__tests__/canned-reply-release.test.ts +86 -0
  49. package/src/__tests__/channel-guardian.test.ts +59 -29
  50. package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
  51. package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
  52. package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
  53. package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
  54. package/src/__tests__/consult-deadline.test.ts +65 -0
  55. package/src/__tests__/conversation-agent-loop.test.ts +438 -2
  56. package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
  57. package/src/__tests__/conversation-disk-view.test.ts +4 -4
  58. package/src/__tests__/conversation-error.test.ts +22 -3
  59. package/src/__tests__/conversation-fork-crud.test.ts +5 -1
  60. package/src/__tests__/conversation-fork-referential.test.ts +352 -0
  61. package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
  62. package/src/__tests__/conversation-group-tools.test.ts +32 -2
  63. package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
  64. package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
  65. package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
  66. package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
  67. package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
  68. package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
  69. package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
  70. package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
  71. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
  72. package/src/__tests__/conversation-queue.test.ts +433 -1
  73. package/src/__tests__/conversation-retry-route.test.ts +3 -1
  74. package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
  75. package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
  76. package/src/__tests__/conversation-store.test.ts +26 -10
  77. package/src/__tests__/conversation-summarize-route.test.ts +1 -1
  78. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
  79. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
  81. package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
  82. package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
  83. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
  84. package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
  85. package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
  86. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
  87. package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
  88. package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
  89. package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
  90. package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
  91. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
  92. package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
  93. package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
  94. package/src/__tests__/credential-prompt-route.test.ts +57 -7
  95. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  96. package/src/__tests__/cu-unified-flow.test.ts +89 -28
  97. package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
  98. package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
  99. package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
  100. package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
  101. package/src/__tests__/disk-pressure-guard.test.ts +55 -55
  102. package/src/__tests__/disk-pressure-routes.test.ts +10 -10
  103. package/src/__tests__/disk-pressure-tools.test.ts +2 -2
  104. package/src/__tests__/disk-usage.test.ts +35 -20
  105. package/src/__tests__/document-sync-tags.test.ts +379 -0
  106. package/src/__tests__/document-update-default-surface.test.ts +28 -0
  107. package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
  108. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
  109. package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
  110. package/src/__tests__/events-dev-bypass-actor.test.ts +183 -1
  111. package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
  112. package/src/__tests__/file-list-tool.test.ts +12 -10
  113. package/src/__tests__/file-ops-service.test.ts +151 -44
  114. package/src/__tests__/file-read-container-boundary.test.ts +137 -0
  115. package/src/__tests__/file-read-tool.test.ts +21 -9
  116. package/src/__tests__/file-url-path-guard.test.ts +83 -0
  117. package/src/__tests__/filesystem-tools.test.ts +82 -66
  118. package/src/__tests__/guardian-outbound-http.test.ts +8 -8
  119. package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
  120. package/src/__tests__/helpers/hub-clients.ts +42 -0
  121. package/src/__tests__/helpers/mock-conversation.ts +46 -0
  122. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
  123. package/src/__tests__/history-repair.test.ts +112 -12
  124. package/src/__tests__/host-bash-proxy.test.ts +10 -5
  125. package/src/__tests__/host-bash-routes.test.ts +67 -0
  126. package/src/__tests__/host-browser-proxy.test.ts +2 -2
  127. package/src/__tests__/host-cu-proxy.test.ts +3 -7
  128. package/src/__tests__/host-file-proxy.test.ts +3 -7
  129. package/src/__tests__/host-file-read-tool.test.ts +5 -1
  130. package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
  131. package/src/__tests__/http-conversation-lineage.test.ts +2 -5
  132. package/src/__tests__/http-user-message-parity.test.ts +44 -0
  133. package/src/__tests__/identity-routes.test.ts +13 -13
  134. package/src/__tests__/image-conversion.test.ts +29 -26
  135. package/src/__tests__/image-source-path-reinject.test.ts +2 -2
  136. package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
  137. package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
  138. package/src/__tests__/introduction-card-resolver.test.ts +6 -1
  139. package/src/__tests__/list-messages-attachments.test.ts +56 -32
  140. package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
  141. package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
  142. package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
  143. package/src/__tests__/list-messages-page-latest.test.ts +61 -61
  144. package/src/__tests__/list-messages-provider-error.test.ts +6 -6
  145. package/src/__tests__/list-messages-queued.test.ts +49 -6
  146. package/src/__tests__/list-messages-system-card.test.ts +4 -4
  147. package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
  148. package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
  149. package/src/__tests__/llm-usage-store.test.ts +55 -0
  150. package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
  151. package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
  152. package/src/__tests__/media-stream-server-integration.test.ts +36 -0
  153. package/src/__tests__/migration-export-http.test.ts +1 -1
  154. package/src/__tests__/migration-import-commit-http.test.ts +1 -1
  155. package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
  156. package/src/__tests__/migration-validate-http.test.ts +1 -1
  157. package/src/__tests__/mtime-cache.test.ts +65 -3
  158. package/src/__tests__/notification-platform-adapter.test.ts +104 -0
  159. package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
  160. package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
  161. package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
  162. package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
  163. package/src/__tests__/oauth-providers-routes.test.ts +1 -0
  164. package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
  165. package/src/__tests__/path-policy.test.ts +164 -1
  166. package/src/__tests__/persist-media-references.test.ts +2 -2
  167. package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
  168. package/src/__tests__/persist-unsendable-image.test.ts +23 -23
  169. package/src/__tests__/persona-resolver.test.ts +154 -0
  170. package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
  171. package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
  172. package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
  173. package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
  174. package/src/__tests__/profiler-routes.test.ts +13 -13
  175. package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
  176. package/src/__tests__/proxy-approval-callback.test.ts +3 -3
  177. package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
  178. package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
  179. package/src/__tests__/resolve-trust-class.test.ts +20 -0
  180. package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
  181. package/src/__tests__/run-due-schedules.test.ts +174 -0
  182. package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
  183. package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
  184. package/src/__tests__/schedule-routes.test.ts +730 -8
  185. package/src/__tests__/schedule-store.test.ts +540 -0
  186. package/src/__tests__/schedule-tools.test.ts +103 -0
  187. package/src/__tests__/scheduler-wake.test.ts +5 -0
  188. package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
  189. package/src/__tests__/secure-keys.test.ts +91 -0
  190. package/src/__tests__/server-history-render.test.ts +97 -7
  191. package/src/__tests__/size-guard.test.ts +8 -8
  192. package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
  193. package/src/__tests__/skill-tool-factory.test.ts +247 -0
  194. package/src/__tests__/skills-install-staging.test.ts +15 -6
  195. package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
  196. package/src/__tests__/slack-inbound-verification.test.ts +4 -1
  197. package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
  198. package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
  199. package/src/__tests__/starter-task-flow.test.ts +5 -4
  200. package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
  201. package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
  202. package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
  203. package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
  204. package/src/__tests__/subagent-disposal.test.ts +10 -0
  205. package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
  206. package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
  207. package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
  208. package/src/__tests__/subagent-manager-notify.test.ts +148 -0
  209. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  210. package/src/__tests__/subagent-persistence.test.ts +141 -0
  211. package/src/__tests__/subagent-role-registry.test.ts +172 -63
  212. package/src/__tests__/subagent-role-resolution.test.ts +88 -0
  213. package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
  214. package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
  215. package/src/__tests__/subagent-terminal-message.test.ts +88 -1
  216. package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
  217. package/src/__tests__/subagent-tools.test.ts +1901 -108
  218. package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
  219. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
  220. package/src/__tests__/system-prompt.test.ts +82 -7
  221. package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
  222. package/src/__tests__/tool-result-spool.test.ts +74 -18
  223. package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
  224. package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
  225. package/src/__tests__/tools-audio-read.test.ts +10 -10
  226. package/src/__tests__/tools-get-route.test.ts +85 -12
  227. package/src/__tests__/tools-list-cli.test.ts +171 -0
  228. package/src/__tests__/top-level-renderer.test.ts +54 -1
  229. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
  230. package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
  231. package/src/__tests__/turn-tail-chain.test.ts +135 -0
  232. package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
  233. package/src/__tests__/ui-visual-surface.test.ts +5 -4
  234. package/src/__tests__/ui-work-result-surface.test.ts +5 -4
  235. package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
  236. package/src/__tests__/usage-routes.test.ts +62 -0
  237. package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
  238. package/src/__tests__/visible-app-context.test.ts +20 -4
  239. package/src/__tests__/web-search-history.test.ts +96 -0
  240. package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
  241. package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
  242. package/src/acp/failure-error.ts +3 -5
  243. package/src/agent/attachments.ts +26 -24
  244. package/src/agent/history-repair/history-repair.ts +27 -26
  245. package/src/agent/image-optimize.ts +6 -6
  246. package/src/agent/loop.ts +40 -22
  247. package/src/agent/message-types.ts +3 -3
  248. package/src/api/constants/document-tools.ts +55 -0
  249. package/src/api/events/question-answered.ts +53 -0
  250. package/src/api/events/tool-result.ts +7 -0
  251. package/src/api/index.ts +13 -0
  252. package/src/api/responses/conversation-message.ts +11 -0
  253. package/src/api/surfaces-oauth-connect.test.ts +96 -0
  254. package/src/api/surfaces.ts +36 -8
  255. package/src/approvals/guardian-channel-delivery.ts +83 -0
  256. package/src/approvals/guardian-expiry-notifier.ts +13 -11
  257. package/src/approvals/guardian-request-resolvers.ts +222 -135
  258. package/src/calls/__tests__/voice-session-bridge.test.ts +50 -0
  259. package/src/calls/media-stream-server.ts +9 -1
  260. package/src/calls/voice-session-bridge.ts +38 -0
  261. package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
  262. package/src/channels/config.ts +7 -2
  263. package/src/channels/gateway-verification-sessions.ts +7 -2
  264. package/src/channels/types.ts +7 -1
  265. package/src/cli/commands/__tests__/cache.test.ts +7 -4
  266. package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
  267. package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
  268. package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
  269. package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
  270. package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
  271. package/src/cli/commands/__tests__/plugins.test.ts +692 -0
  272. package/src/cli/commands/__tests__/schedules.test.ts +136 -37
  273. package/src/cli/commands/conversations.ts +7 -3
  274. package/src/cli/commands/credentials.help.ts +7 -0
  275. package/src/cli/commands/inference-profiles.ts +9 -3
  276. package/src/cli/commands/inference.help.ts +16 -2
  277. package/src/cli/commands/mcp.help.ts +4 -2
  278. package/src/cli/commands/memory/memory-retrospective.ts +18 -0
  279. package/src/cli/commands/notifications.ts +3 -6
  280. package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
  281. package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
  282. package/src/cli/commands/oauth/connect.test.ts +26 -1
  283. package/src/cli/commands/oauth/connect.ts +4 -1
  284. package/src/cli/commands/oauth/index.help.ts +3 -1
  285. package/src/cli/commands/oauth/providers.ts +3 -0
  286. package/src/cli/commands/plugins.help.ts +25 -2
  287. package/src/cli/commands/plugins.ts +289 -10
  288. package/src/cli/commands/schedules.help.ts +14 -12
  289. package/src/cli/commands/schedules.ts +19 -5
  290. package/src/cli/commands/tools.help.ts +4 -2
  291. package/src/cli/commands/tools.ts +38 -0
  292. package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
  293. package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
  294. package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
  295. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
  296. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +122 -0
  297. package/src/cli/lib/install-from-github.ts +61 -0
  298. package/src/cli/lib/install-from-platform.ts +13 -2
  299. package/src/cli/lib/plugin-surfaces.ts +124 -4
  300. package/src/cli/lib/upgrade-plugin.ts +18 -0
  301. package/src/cli.ts +1 -1
  302. package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
  303. package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
  304. package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
  305. package/src/config/__tests__/profile-tool-support.test.ts +131 -0
  306. package/src/config/bundled-skills/AGENTS.md +1 -1
  307. package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
  308. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
  309. package/src/config/bundled-skills/schedule/SKILL.md +5 -1
  310. package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
  311. package/src/config/bundled-skills/settings/TOOLS.json +2 -2
  312. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
  313. package/src/config/bundled-skills/subagent/SKILL.md +53 -22
  314. package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
  315. package/src/config/bundled-skills/visualize/SKILL.md +1 -1
  316. package/src/config/default-profile-catalog.ts +6 -2
  317. package/src/config/feature-flag-registry.json +25 -17
  318. package/src/config/llm-resolver.ts +45 -15
  319. package/src/config/loader.ts +70 -1
  320. package/src/config/profile-tool-support.ts +110 -0
  321. package/src/config/sanitize-for-transfer.ts +11 -0
  322. package/src/config/schema.ts +4 -0
  323. package/src/config/schemas/__tests__/stt.test.ts +20 -5
  324. package/src/config/schemas/channels.ts +13 -0
  325. package/src/config/schemas/memory-retrospective.ts +25 -0
  326. package/src/config/schemas/plugin-updates.ts +55 -0
  327. package/src/config/schemas/services.ts +8 -4
  328. package/src/config/schemas/stt.ts +17 -5
  329. package/src/config/schemas/timeouts.ts +1 -1
  330. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
  331. package/src/contacts/guardian-delivery-reader.ts +29 -2
  332. package/src/context/compactor.ts +4 -4
  333. package/src/context/post-turn-tool-result-truncation.ts +32 -16
  334. package/src/context/strip-injections.ts +42 -0
  335. package/src/context/tool-result-spool.ts +32 -18
  336. package/src/credential-execution/ces-runtime.ts +3 -0
  337. package/src/credential-execution/client.ts +22 -1
  338. package/src/credential-execution/process-manager.test.ts +99 -0
  339. package/src/credential-execution/process-manager.ts +62 -16
  340. package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
  341. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
  342. package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
  343. package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
  344. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
  345. package/src/daemon/channel-ui-capability.ts +4 -4
  346. package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
  347. package/src/daemon/conversation-agent-loop.ts +318 -148
  348. package/src/daemon/conversation-attachments.ts +1 -1
  349. package/src/daemon/conversation-error.ts +8 -1
  350. package/src/daemon/conversation-initial-prompt.ts +16 -38
  351. package/src/daemon/conversation-lifecycle.ts +154 -32
  352. package/src/daemon/conversation-messaging.ts +106 -43
  353. package/src/daemon/conversation-process.ts +131 -33
  354. package/src/daemon/conversation-queue-manager.ts +10 -0
  355. package/src/daemon/conversation-runtime-assembly.ts +9 -4
  356. package/src/daemon/conversation-store.ts +52 -3
  357. package/src/daemon/conversation-surface-state.ts +9 -0
  358. package/src/daemon/conversation-surfaces.ts +403 -210
  359. package/src/daemon/conversation-tool-setup.ts +56 -7
  360. package/src/daemon/conversation-turn-finalize.ts +134 -89
  361. package/src/daemon/conversation.ts +111 -27
  362. package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
  363. package/src/daemon/disk-pressure-guard.ts +3 -3
  364. package/src/daemon/doordash-steps.ts +5 -5
  365. package/src/daemon/external-plugins-bootstrap.ts +7 -1
  366. package/src/daemon/handlers/config-channels.ts +48 -5
  367. package/src/daemon/handlers/conversation-history.ts +1 -1
  368. package/src/daemon/handlers/conversations.ts +62 -17
  369. package/src/daemon/handlers/shared.ts +12 -0
  370. package/src/daemon/handlers/skills.ts +11 -1
  371. package/src/daemon/identity-helpers.ts +38 -10
  372. package/src/daemon/install-assistant-command.ts +322 -0
  373. package/src/daemon/lifecycle.ts +14 -3
  374. package/src/daemon/message-types/conversations.ts +6 -7
  375. package/src/daemon/message-types/sync.ts +1 -0
  376. package/src/daemon/persist-media-references.ts +23 -14
  377. package/src/daemon/process-message.ts +6 -6
  378. package/src/daemon/tool-setup-types.ts +19 -122
  379. package/src/daemon/tool-side-effects.ts +17 -94
  380. package/src/daemon/trust-context-types.ts +39 -0
  381. package/src/daemon/trust-context.ts +14 -6
  382. package/src/daemon/turn-tail-chain.ts +73 -0
  383. package/src/daemon/web-search-history.ts +47 -33
  384. package/src/heartbeat/heartbeat-service.ts +6 -6
  385. package/src/ipc/__tests__/socket-path.test.ts +21 -0
  386. package/src/ipc/assistant-server.ts +17 -10
  387. package/src/ipc/cli-client.ts +10 -1
  388. package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
  389. package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
  390. package/src/ipc/socket-cleanup.ts +9 -7
  391. package/src/ipc/socket-path.ts +4 -96
  392. package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
  393. package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
  394. package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
  395. package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
  396. package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
  397. package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
  398. package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
  399. package/src/live-voice/__tests__/protocol.test.ts +52 -0
  400. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
  401. package/src/live-voice/live-voice-archive.ts +13 -13
  402. package/src/live-voice/live-voice-connection.ts +7 -1
  403. package/src/live-voice/live-voice-photo.ts +169 -0
  404. package/src/live-voice/live-voice-session.ts +108 -4
  405. package/src/live-voice/protocol.ts +89 -1
  406. package/src/mcp/client.ts +10 -0
  407. package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
  408. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
  409. package/src/messaging/providers/callback-routing.ts +1 -0
  410. package/src/messaging/providers/discord/api.ts +312 -0
  411. package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
  412. package/src/messaging/providers/discord/render.test.ts +204 -0
  413. package/src/messaging/providers/discord/render.ts +195 -0
  414. package/src/messaging/providers/discord/send.test.ts +179 -0
  415. package/src/messaging/providers/discord/send.ts +212 -0
  416. package/src/messaging/providers/discord/transport.ts +81 -0
  417. package/src/messaging/providers/index.ts +3 -1
  418. package/src/messaging/providers/retry-policy.test.ts +247 -0
  419. package/src/messaging/providers/retry-policy.ts +206 -0
  420. package/src/messaging/providers/slack/mention-source.test.ts +285 -0
  421. package/src/messaging/providers/slack/mention-source.ts +287 -0
  422. package/src/messaging/providers/telegram-bot/api.ts +47 -130
  423. package/src/messaging/providers/whatsapp/api.ts +47 -136
  424. package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
  425. package/src/monitoring/__tests__/plugin-auto-update.test.ts +332 -0
  426. package/src/monitoring/db-integrity-sample.ts +6 -1
  427. package/src/monitoring/plugin-auto-update.ts +359 -0
  428. package/src/monitoring/resource-sampler.ts +21 -5
  429. package/src/monitoring/worker.ts +13 -0
  430. package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
  431. package/src/notifications/__tests__/broadcaster.test.ts +37 -1
  432. package/src/notifications/__tests__/copy-composer.test.ts +165 -0
  433. package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
  434. package/src/notifications/__tests__/notification-utils.test.ts +249 -0
  435. package/src/notifications/adapters/platform.ts +31 -2
  436. package/src/notifications/assistant-reply-producer.ts +79 -32
  437. package/src/notifications/broadcaster.ts +30 -10
  438. package/src/notifications/copy-composer.ts +69 -0
  439. package/src/notifications/emit-signal.ts +82 -15
  440. package/src/notifications/events-store.ts +10 -2
  441. package/src/notifications/home-feed-side-effect.ts +6 -3
  442. package/src/notifications/notification-utils.ts +173 -5
  443. package/src/notifications/signal.ts +12 -0
  444. package/src/oauth/AGENTS.md +4 -2
  445. package/src/oauth/byo-connection.ts +6 -1
  446. package/src/oauth/credential-token-resolver.ts +3 -10
  447. package/src/oauth/manual-token-connection.ts +29 -64
  448. package/src/oauth/manual-token-providers.ts +62 -0
  449. package/src/oauth/provider-serializer.ts +13 -0
  450. package/src/oauth/seed-providers.ts +62 -11
  451. package/src/onboarding/onboarding-events-store.ts +91 -1
  452. package/src/permissions/question-prompter.test.ts +4 -0
  453. package/src/permissions/question-prompter.ts +21 -4
  454. package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
  455. package/src/persistence/attachments-store.ts +15 -15
  456. package/src/persistence/conversation-attention-store.ts +30 -10
  457. package/src/persistence/conversation-bootstrap.ts +17 -0
  458. package/src/persistence/conversation-crud.ts +363 -97
  459. package/src/persistence/conversation-group-migration.ts +1 -1
  460. package/src/persistence/conversation-key-store.ts +38 -10
  461. package/src/persistence/conversation-lineage.ts +226 -0
  462. package/src/persistence/conversation-plugin-facade.ts +28 -3
  463. package/src/persistence/conversation-queries.ts +207 -33
  464. package/src/persistence/conversation-types.ts +107 -1
  465. package/src/persistence/jobs-store.ts +32 -8
  466. package/src/persistence/llm-usage-store.ts +22 -0
  467. package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
  468. package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
  469. package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
  470. package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
  471. package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
  472. package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
  473. package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
  474. package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
  475. package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
  476. package/src/persistence/schema/conversations.ts +32 -0
  477. package/src/persistence/schema/infrastructure.ts +3 -0
  478. package/src/persistence/steps.ts +30 -0
  479. package/src/persistence/subagent-store.ts +148 -6
  480. package/src/platform/managed-speech.test.ts +20 -0
  481. package/src/platform/managed-speech.ts +9 -0
  482. package/src/plugin-api/index.ts +8 -0
  483. package/src/plugin-api/webhook-url.ts +151 -0
  484. package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
  485. package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
  486. package/src/plugins/collect-source-versions.ts +4 -27
  487. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
  488. package/src/plugins/defaults/exploration-drift/package.json +1 -1
  489. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
  490. package/src/plugins/defaults/image-recovery/recover.ts +67 -57
  491. package/src/plugins/defaults/index.ts +1 -1
  492. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
  493. package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
  494. package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
  495. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
  496. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
  497. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
  498. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
  499. package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
  500. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
  501. package/src/plugins/defaults/memory/job-handlers.ts +87 -5
  502. package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
  503. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
  504. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
  505. package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
  506. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
  507. package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
  508. package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
  509. package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
  510. package/src/plugins/defaults/memory/v2/router.ts +8 -0
  511. package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
  512. package/src/plugins/external-plugin-loader.ts +17 -8
  513. package/src/plugins/installed-plugin-dirs.ts +101 -0
  514. package/src/plugins/mtime-cache.ts +34 -22
  515. package/src/plugins/types.ts +69 -8
  516. package/src/prompts/persona-resolver.ts +6 -2
  517. package/src/prompts/system-prompt.ts +72 -17
  518. package/src/providers/__tests__/inference.test.ts +40 -0
  519. package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
  520. package/src/providers/__tests__/retry-callsite.test.ts +67 -0
  521. package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
  522. package/src/providers/anthropic/client.ts +112 -95
  523. package/src/providers/connection-resolution.ts +35 -1
  524. package/src/providers/gemini/client.ts +5 -5
  525. package/src/providers/inference/adapter-factory.ts +16 -10
  526. package/src/providers/inference/auth.ts +16 -0
  527. package/src/providers/inference/connection-availability.ts +164 -12
  528. package/src/providers/inference/connections.ts +25 -1
  529. package/src/providers/media-resolve.ts +21 -11
  530. package/src/providers/model-catalog.ts +15 -0
  531. package/src/providers/openai/chat-completions-provider.ts +4 -4
  532. package/src/providers/openai/responses-provider.ts +12 -25
  533. package/src/providers/registry.ts +9 -4
  534. package/src/providers/retry.ts +25 -0
  535. package/src/providers/server-tool-pairing.ts +134 -0
  536. package/src/providers/speech-to-text/__tests__/resolve.test.ts +187 -6
  537. package/src/providers/speech-to-text/deepgram.ts +1 -0
  538. package/src/providers/speech-to-text/resolve.ts +80 -10
  539. package/src/providers/speech-to-text/vellum-managed.ts +7 -1
  540. package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
  541. package/src/providers/types.ts +26 -6
  542. package/src/providers/vellum-model-routing.ts +6 -7
  543. package/src/runtime/AGENTS.md +2 -0
  544. package/src/runtime/__tests__/agent-wake.test.ts +16 -16
  545. package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
  546. package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
  547. package/src/runtime/agent-wake.ts +63 -24
  548. package/src/runtime/assistant-event-hub.ts +87 -12
  549. package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
  550. package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
  551. package/src/runtime/auth/same-actor.ts +56 -8
  552. package/src/runtime/auth/scopes.ts +12 -0
  553. package/src/runtime/auth/types.ts +2 -0
  554. package/src/runtime/background-job-runner.ts +5 -27
  555. package/src/runtime/channel-readiness-service.ts +59 -3
  556. package/src/runtime/channel-readiness-types.ts +18 -0
  557. package/src/runtime/desktop-presence.ts +69 -0
  558. package/src/runtime/http-server.ts +12 -0
  559. package/src/runtime/local-actor-identity.ts +11 -9
  560. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  561. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  562. package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
  563. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
  564. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
  565. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
  566. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
  567. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
  568. package/src/runtime/routes/__tests__/plugins-routes.test.ts +173 -1
  569. package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
  570. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
  571. package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
  572. package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
  573. package/src/runtime/routes/archive-utils.ts +16 -12
  574. package/src/runtime/routes/attachment-routes.ts +13 -6
  575. package/src/runtime/routes/canned-reply-release.ts +54 -0
  576. package/src/runtime/routes/channel-verification-routes.ts +2 -27
  577. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
  578. package/src/runtime/routes/client-routes.ts +114 -2
  579. package/src/runtime/routes/conversation-cli-routes.ts +10 -12
  580. package/src/runtime/routes/conversation-list-routes.ts +59 -10
  581. package/src/runtime/routes/conversation-management-routes.ts +47 -18
  582. package/src/runtime/routes/conversation-query-routes.ts +32 -53
  583. package/src/runtime/routes/conversation-routes.ts +360 -293
  584. package/src/runtime/routes/credential-prompt-routes.ts +23 -2
  585. package/src/runtime/routes/debug-routes.ts +4 -1
  586. package/src/runtime/routes/default-provider-routes.ts +7 -11
  587. package/src/runtime/routes/documents-routes.ts +44 -1
  588. package/src/runtime/routes/events-routes.ts +28 -1
  589. package/src/runtime/routes/host-app-control-routes.ts +2 -0
  590. package/src/runtime/routes/host-bash-routes.ts +2 -0
  591. package/src/runtime/routes/host-browser-routes.ts +2 -0
  592. package/src/runtime/routes/host-cu-routes.ts +2 -0
  593. package/src/runtime/routes/host-file-routes.ts +2 -0
  594. package/src/runtime/routes/host-transfer-routes.ts +4 -0
  595. package/src/runtime/routes/identity-routes.ts +6 -6
  596. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  597. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
  598. package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
  599. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
  600. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
  601. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
  602. package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
  603. package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
  604. package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
  605. package/src/runtime/routes/inference-profiles-routes.ts +152 -73
  606. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
  607. package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
  608. package/src/runtime/routes/log-export-routes.ts +1 -1
  609. package/src/runtime/routes/notification-routes.ts +0 -14
  610. package/src/runtime/routes/oauth-providers.ts +1 -0
  611. package/src/runtime/routes/plugins-routes.ts +106 -1
  612. package/src/runtime/routes/profiler-routes.ts +4 -2
  613. package/src/runtime/routes/question-routes.ts +28 -10
  614. package/src/runtime/routes/retrospective-routes.ts +9 -3
  615. package/src/runtime/routes/schedule-routes.ts +210 -12
  616. package/src/runtime/routes/secret-routes.ts +40 -23
  617. package/src/runtime/routes/settings-routes.ts +41 -13
  618. package/src/runtime/routes/skills-routes.ts +79 -0
  619. package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
  620. package/src/runtime/routes/wake-conversation-routes.ts +23 -0
  621. package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
  622. package/src/runtime/services/conversation-serializer.ts +24 -9
  623. package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
  624. package/src/runtime/sync/resource-sync-events.ts +79 -1
  625. package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
  626. package/src/runtime/sync/worker-daemon-notify.ts +44 -6
  627. package/src/runtime/verification-outbound-actions.ts +250 -222
  628. package/src/runtime/verification-templates.ts +41 -30
  629. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
  630. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
  631. package/src/schedule/inference-profile.ts +64 -3
  632. package/src/schedule/plugin-schedule-declarations.ts +518 -0
  633. package/src/schedule/plugin-schedule-reconciler.ts +605 -0
  634. package/src/schedule/plugin-schedules-gate.ts +23 -0
  635. package/src/schedule/schedule-store.ts +520 -26
  636. package/src/schedule/scheduler.ts +38 -0
  637. package/src/security/credential-backend.ts +51 -4
  638. package/src/security/encrypted-store.ts +64 -42
  639. package/src/security/secure-keys.ts +55 -7
  640. package/src/skills/catalog-install.ts +20 -7
  641. package/src/skills/inline-command-runner.ts +2 -7
  642. package/src/skills/skill-history.test.ts +269 -0
  643. package/src/skills/skill-history.ts +250 -0
  644. package/src/skills/skillssh-registry.ts +1 -1
  645. package/src/stt/daemon-batch-transcriber.ts +8 -6
  646. package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
  647. package/src/subagent/consult-prompt.ts +3 -1
  648. package/src/subagent/consult-transcript.ts +1 -1
  649. package/src/subagent/manager.ts +304 -44
  650. package/src/subagent/progress-events.ts +35 -0
  651. package/src/subagent/role-resolution.ts +88 -0
  652. package/src/subagent/types.ts +302 -67
  653. package/src/subagent/validate-allowlists.ts +3 -4
  654. package/src/telegram/__tests__/webhook-health.test.ts +73 -1
  655. package/src/telegram/webhook-health.ts +101 -3
  656. package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
  657. package/src/telemetry/activation-funnel.ts +6 -1
  658. package/src/telemetry/live-voice-funnel.ts +75 -0
  659. package/src/telemetry/telemetry-event-sources.ts +6 -0
  660. package/src/telemetry/telemetry-wire-source.json +1 -1
  661. package/src/telemetry/telemetry-wire.generated.ts +2 -0
  662. package/src/telemetry/types.ts +23 -4
  663. package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
  664. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
  665. package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
  666. package/src/tools/ask-question/ask-question-tool.ts +56 -2
  667. package/src/tools/browser/browser-execution.ts +1 -1
  668. package/src/tools/calls/call-start.ts +8 -5
  669. package/src/tools/conversation-groups/move_to_group.ts +10 -12
  670. package/src/tools/document/document-tool.ts +11 -4
  671. package/src/tools/execution-timeout.ts +9 -2
  672. package/src/tools/executor.ts +7 -6
  673. package/src/tools/filesystem/edit.ts +1 -1
  674. package/src/tools/filesystem/list.ts +1 -1
  675. package/src/tools/filesystem/read.ts +7 -13
  676. package/src/tools/filesystem/search.ts +23 -21
  677. package/src/tools/filesystem/write.ts +4 -1
  678. package/src/tools/host-filesystem/edit.ts +7 -2
  679. package/src/tools/host-filesystem/read.ts +21 -8
  680. package/src/tools/host-filesystem/write.ts +10 -2
  681. package/src/tools/host-terminal/host-shell.ts +2 -2
  682. package/src/tools/mcp/mcp-tool-factory.ts +25 -1
  683. package/src/tools/permission-checker.ts +8 -3
  684. package/src/tools/schedule/delete.ts +13 -1
  685. package/src/tools/schedule/list.ts +14 -3
  686. package/src/tools/schedule/update.ts +56 -33
  687. package/src/tools/shared/filesystem/audio-read.ts +6 -4
  688. package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
  689. package/src/tools/shared/filesystem/image-read.ts +12 -12
  690. package/src/tools/shared/filesystem/path-policy.ts +70 -5
  691. package/src/tools/shared/filesystem/size-guard.ts +6 -6
  692. package/src/tools/shared/input-misuse.ts +72 -0
  693. package/src/tools/skills/scaffold-managed.ts +82 -0
  694. package/src/tools/skills/skill-tool-factory.ts +14 -1
  695. package/src/tools/subagent/consult-deadline.ts +12 -7
  696. package/src/tools/subagent/message.ts +3 -1
  697. package/src/tools/subagent/read.ts +66 -4
  698. package/src/tools/subagent/spawn.ts +500 -78
  699. package/src/tools/tool-approval-handler.ts +45 -4
  700. package/src/tools/types.ts +22 -3
  701. package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
  702. package/src/tools/ui-surface/visual-validation.ts +2 -0
  703. package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
  704. package/src/usage/subagent-attribution.ts +108 -0
  705. package/src/util/__tests__/sqlite-retry.test.ts +112 -0
  706. package/src/util/abort-reasons.ts +16 -0
  707. package/src/util/ansi.ts +44 -0
  708. package/src/util/disk-usage.ts +17 -13
  709. package/src/util/image-conversion.ts +20 -13
  710. package/src/util/schedule-source-key.ts +23 -0
  711. package/src/util/worker-process.ts +7 -1
  712. package/src/workspace/git-service.ts +33 -9
  713. package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
  714. package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
  715. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
  716. package/src/workspace/migrations/registry.ts +4 -0
  717. package/src/workspace/top-level-renderer.ts +15 -2
  718. package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
  719. package/src/daemon/install-symlink.ts +0 -207
  720. package/src/notifications/deferred-emit.ts +0 -147
@@ -4,9 +4,6 @@
4
4
  */
5
5
 
6
6
  import type { InterfaceId } from "../channels/types.js";
7
- import type { LLMCallSite } from "../config/schemas/llm.js";
8
- import type { SurfaceConversationContext } from "./conversation-surfaces.js";
9
- import type { TrustContext } from "./trust-context-types.js";
10
7
 
11
8
  /**
12
9
  * How a subagent/wake tool allowlist is enforced.
@@ -24,6 +21,25 @@ import type { TrustContext } from "./trust-context-types.js";
24
21
  */
25
22
  export type SubagentToolGateMode = "wire" | "execution";
26
23
 
24
+ /**
25
+ * Live tool-call counters for a subagent child, recorded by the tool executor
26
+ * and harvested by the SubagentManager when the run ends.
27
+ *
28
+ * This is the machine half of a subagent's result: the parent reads the child's
29
+ * own prose narrative, and these counts say what the child actually ran, so a
30
+ * claim of executed work that never touched a tool is visible rather than
31
+ * taken on trust. Ephemeral (in-memory only, never persisted) and only ever
32
+ * written for subagent conversations.
33
+ */
34
+ export interface SubagentToolStats {
35
+ /** Tool calls dispatched, including ones that returned an error. */
36
+ calls: number;
37
+ /** Of those, the calls whose result was not an error. */
38
+ succeeded: number;
39
+ /** Distinct paths successfully passed to `file_write` / `file_edit`. */
40
+ filesWritten: Set<string>;
41
+ }
42
+
27
43
  /**
28
44
  * Client-context inputs frozen for tool-DEFINITION resolution during a wake
29
45
  * that runs with `subagentToolGateMode: "execution"`.
@@ -64,122 +80,3 @@ export interface WakeToolContextPin {
64
80
  */
65
81
  requestOrigin?: string;
66
82
  }
67
-
68
- /**
69
- * Subset of Conversation state that the tool executor callback reads at
70
- * call time (not construction time). These are captured by the
71
- * returned closure, so they must be live references.
72
- */
73
- export interface ToolSetupContext extends SurfaceConversationContext {
74
- readonly conversationId: string;
75
- assistantId?: string;
76
- currentRequestId?: string;
77
- workingDir: string;
78
- abortController: AbortController | null;
79
- /** When set, only tools in this set may execute during the current turn. */
80
- allowedToolNames?: Set<string>;
81
- /** When set, the subagent/wake tool allowlist (see {@link subagentToolGateMode}). */
82
- subagentAllowedTools?: Set<string>;
83
- /**
84
- * When true, side-effecting tools are refused for this subagent regardless of
85
- * trust class (the read-only background continuation): kept off the wire tool
86
- * surface and rejected in the executor gate. Independent of the allowlist.
87
- */
88
- subagentDenySideEffects?: boolean;
89
- /**
90
- * Collects tool names the subagent attempted but that
91
- * {@link subagentAllowedTools} denied, for parent-visible reporting. The
92
- * executor records into this Set (shared by reference with the Conversation).
93
- */
94
- subagentDeniedToolNames?: Set<string>;
95
- /**
96
- * How {@link subagentAllowedTools} is enforced. Absent or `"wire"` keeps
97
- * the historical behavior (definitions filtered before the provider
98
- * request); `"execution"` keeps the full tool surface on the wire and
99
- * rejects non-allowlisted calls in the executor callback instead.
100
- */
101
- subagentToolGateMode?: SubagentToolGateMode;
102
- /** Turn-scoped disk-pressure cleanup mode flag. */
103
- diskPressureCleanupModeActive?: boolean;
104
- /** True when the conversation has no connected client (HTTP-only path). */
105
- hasNoClient?: boolean;
106
- /** When true, the conversation is executing a task run and must not become interactive. */
107
- headlessLock?: boolean;
108
- /** When set, this conversation is executing a task run. Used to retrieve ephemeral permission rules. */
109
- taskRunId?: string;
110
- /** Guardian runtime context for the conversation — trustClass is propagated into ToolContext for control-plane policy enforcement. */
111
- trustContext?: TrustContext;
112
- /** Per-turn trust snapshot, captured at turn start. Preferred over the live
113
- * `trustContext` for mid-turn trust decisions (tool approval, control-plane
114
- * policy) so a concurrent mutation cannot elevate the in-flight turn. */
115
- currentTurnTrustContext?: TrustContext;
116
- /** Voice/call session ID, if the conversation originates from a call. Propagated into ToolContext for scoped grant consumption. */
117
- callSessionId?: string;
118
- /** The interface ID of the connected client driving the current turn (e.g. "macos", "chrome-extension"). Propagated into ToolContext for browser backend selection. */
119
- readonly transportInterface?: InterfaceId;
120
- /**
121
- * Per-turn snapshot of the channel's UI capabilities, captured at turn start
122
- * (mirrors {@link Conversation.currentTurnChannelCapabilities}). Read per tool
123
- * call — together with the structural {@link SurfaceConversationContext.channelCapabilities}
124
- * fallback — to derive `ToolContext.supportsDynamicUi`, so UI-dependent tools
125
- * (e.g. `ask_question`) can degrade to text on channels that can't render
126
- * dynamic surfaces.
127
- */
128
- readonly currentTurnChannelCapabilities?: {
129
- readonly channel: string;
130
- readonly supportsDynamicUi: boolean;
131
- };
132
- /**
133
- * The conversation's per-chat plugin scope (mirrors
134
- * {@link Conversation.enabledPlugins}). `null`/absent means no per-chat
135
- * restriction. Read per tool call to derive the effective enabled-plugin set
136
- * (via `getEffectiveEnabledPluginSet`) for the `ToolContext.enabledPluginSet`
137
- * field and the `skill_execute` dispatch guard.
138
- */
139
- readonly enabledPlugins?: string[] | null;
140
-
141
- /** Turn-scoped flag: true when any tool call in the current turn received explicit user approval via interactive prompt. Cleared at turn end. */
142
- approvedViaPromptThisTurn?: boolean;
143
- /**
144
- * When true, side-effect tools must prompt for confirmation even if a
145
- * trust/allow rule would auto-allow them. Set by callers without an
146
- * interactive approval UI (e.g. non-guardian phone voice turns) to force
147
- * a `confirmation_request` event that the caller's auto-deny / scoped-grant
148
- * handler can intercept. Provides a second layer of defense against broad
149
- * trust rules auto-executing side-effect tools in non-interactive contexts.
150
- */
151
- forcePromptSideEffects?: boolean;
152
- /**
153
- * The LLM call site driving the current turn, set by `runAgentLoopImpl`
154
- * (`options.callSite ?? "mainAgent"`). Non-main turns (voice `callAgent`,
155
- * `filingAgent`, …) resolve different provider/model/profile config, so
156
- * tool telemetry attribution must use this rather than assuming
157
- * `mainAgent`. Absent before the first turn starts.
158
- */
159
- currentCallSite?: LLMCallSite;
160
- /**
161
- * Per-turn snapshot of the resolved inference-profile override, set by
162
- * `runAgentLoopImpl`. Propagated into `ToolContext.overrideProfile` so
163
- * tools that spawn nested invocations (e.g. `subagent_spawn`) can forward
164
- * the override without round-tripping through a row read that would
165
- * return `undefined` for the in-flight (background) subagent.
166
- */
167
- currentTurnOverrideProfile?: string;
168
- /**
169
- * Whether the current turn has no human present to answer clarification
170
- * prompts. Resolved once per turn by the agent loop — honoring an explicit
171
- * per-run `isInteractive` option (e.g. scheduled/background turns) over the
172
- * live client state — so tool execution sees turn-level interactivity rather
173
- * than re-deriving it from `hasNoClient`/`headlessLock`, which would read a
174
- * scheduled turn running on a client-attached conversation as interactive.
175
- */
176
- currentTurnIsNonInteractive?: boolean;
177
- /**
178
- * Origin tag of the current turn (the conversation's `TitleOrigin`, e.g.
179
- * "memory_consolidation"), set by `runAgentLoop` from its `requestOrigin`
180
- * option. Propagated into `ToolContext.requestOrigin` so the permission
181
- * checker can scope narrow non-interactive auto-grants to a specific
182
- * internal background origin. Absent for normal interactive turns.
183
- */
184
- currentTurnRequestOrigin?: string;
185
- }
@@ -9,32 +9,34 @@
9
9
 
10
10
  import { isAbsolute, resolve, sep } from "node:path";
11
11
 
12
+ import { DOCUMENT_MUTATION_TOOL_NAMES } from "../api/constants/document-tools.js";
12
13
  import type { AssistantEvent } from "../api/index.js";
13
14
  import { getApp, linkAppToConversationLineage } from "../apps/app-store.js";
14
- import { findActiveSession } from "../channels/gateway-verification-sessions.js";
15
15
  import { getConfig } from "../config/loader.js";
16
16
  import { generateAppIcon } from "../media/app-icon-generator.js";
17
17
  import { invalidateEdgeIndex } from "../plugins/defaults/memory/substrate/edge-index.js";
18
18
  import { invalidatePageIndex } from "../plugins/defaults/memory/substrate/page-index.js";
19
19
  import { getConceptsDir } from "../plugins/defaults/memory/substrate/page-store.js";
20
20
  import { broadcastMessage } from "../runtime/assistant-event-hub.js";
21
- import { publishAppsChanged } from "../runtime/sync/resource-sync-events.js";
22
- import { deliverVerificationSlack } from "../runtime/verification-outbound-actions.js";
21
+ import {
22
+ publishAppsChanged,
23
+ publishDocumentsChanged,
24
+ } from "../runtime/sync/resource-sync-events.js";
23
25
  import { updatePublishedAppDeployment } from "../services/published-app-updater.js";
24
26
  import type { ToolExecutionResult } from "../tools/types.js";
25
27
  import { getLogger } from "../util/logger.js";
26
28
  import { getWorkspaceDir } from "../util/platform.js";
27
29
  import { ensureAppSourceWatcher } from "./app-source-watcher.js";
30
+ import type { Conversation } from "./conversation.js";
28
31
  import { refreshSurfacesForApp } from "./conversation-surfaces.js";
29
32
  import { isDoordashCommand, updateDoordashProgress } from "./doordash-steps.js";
30
- import type { ToolSetupContext } from "./tool-setup-types.js";
31
33
 
32
34
  const log = getLogger("tool-side-effects");
33
35
 
34
36
  // ── Types ────────────────────────────────────────────────────────────
35
37
 
36
38
  export interface SideEffectContext {
37
- ctx: ToolSetupContext;
39
+ ctx: Conversation;
38
40
  }
39
41
 
40
42
  export type PostExecutionHook = (
@@ -57,7 +59,7 @@ export type PostExecutionHook = (
57
59
  * and would race with the executor's own output (LUM-1153).
58
60
  */
59
61
  function notifyAppChanged(
60
- ctx: ToolSetupContext,
62
+ ctx: Conversation,
61
63
  appId: string,
62
64
  opts?: { fileChange?: boolean; status?: string },
63
65
  ): void {
@@ -179,6 +181,15 @@ function registerAppSurfaceRefreshHook(toolName: string): void {
179
181
  registerAppSurfaceRefreshHook("app_refresh");
180
182
  registerAppSurfaceRefreshHook("app_update");
181
183
 
184
+ // The mutating document tools carry no list-level change signal of their own,
185
+ // so the conversation assets pill and the Library keep serving a cached list
186
+ // after an edit, and a deleted document lingers as a ghost row. `skill_execute`
187
+ // calls reach the runner already unwrapped to the inner tool name, so the
188
+ // bundled document-editor skill needs no separate registration.
189
+ registerHook([...DOCUMENT_MUTATION_TOOL_NAMES], () => {
190
+ publishDocumentsChanged();
191
+ });
192
+
182
193
  registerHook("voice_config_update", (_name, input) => {
183
194
  const setting = input.setting as string | undefined;
184
195
  if (!setting) {
@@ -229,94 +240,6 @@ registerHook("voice_config_update", (_name, input) => {
229
240
  } as unknown as AssistantEvent);
230
241
  });
231
242
 
232
- // Dispatch pending Slack DM delivery when a CLI verification command
233
- // completes. The CLI subprocess is sandboxed and cannot reach the
234
- // gateway, so it includes a `_pendingSlackDm` field in its JSON output.
235
- // This hook runs in the unsandboxed daemon process and delivers the DM.
236
- registerHook("bash", async (_name, input, result) => {
237
- const command = (input.command ?? "") as string;
238
- if (!command.includes("channel-verification-sessions")) {
239
- return;
240
- }
241
- if (!result.content.includes("_pendingSlackDm")) {
242
- return;
243
- }
244
-
245
- type PendingDm = { userId: string; text: string; assistantId: string };
246
- type Parsed = { _pendingSlackDm?: PendingDm };
247
-
248
- // Returns "delivered" when DM was sent, "rejected" when _pendingSlackDm
249
- // was found but failed validation, or null when the field was absent.
250
- const dispatch = async (
251
- parsed: Parsed,
252
- ): Promise<"delivered" | "rejected" | null> => {
253
- if (parsed._pendingSlackDm) {
254
- const { userId, text, assistantId } = parsed._pendingSlackDm;
255
-
256
- // Validate that an active Slack verification session exists and
257
- // that the destination matches the userId in the parsed payload.
258
- // Fail closed: an unverifiable DM (gateway unreachable) is not sent.
259
- let session;
260
- try {
261
- session = await findActiveSession("slack");
262
- } catch (err) {
263
- log.warn(
264
- { err, userId, assistantId },
265
- "Bash hook: gateway session lookup failed — ignoring _pendingSlackDm",
266
- );
267
- return "rejected";
268
- }
269
- if (!session) {
270
- log.warn(
271
- { userId, assistantId },
272
- "Bash hook: no active Slack verification session — ignoring _pendingSlackDm",
273
- );
274
- return "rejected";
275
- }
276
- if (session.destinationAddress !== userId) {
277
- log.warn(
278
- { userId, expected: session.destinationAddress, assistantId },
279
- "Bash hook: Slack DM userId does not match active session destination — ignoring",
280
- );
281
- return "rejected";
282
- }
283
-
284
- deliverVerificationSlack(userId, text, assistantId);
285
- return "delivered";
286
- }
287
- return null;
288
- };
289
-
290
- // Try full content first (handles pretty-printed single-object JSON)
291
- let singleObject: Parsed | undefined;
292
- try {
293
- singleObject = JSON.parse(result.content.trim()) as Parsed;
294
- } catch {
295
- // Not a single JSON object — fall back to line-by-line for
296
- // multi-object output (e.g. cancel + create chained with &&).
297
- }
298
- if (singleObject !== undefined) {
299
- if ((await dispatch(singleObject)) !== null) {
300
- return;
301
- }
302
- }
303
- for (const line of result.content.split("\n")) {
304
- const trimmed = line.trim();
305
- if (!trimmed.startsWith("{")) {
306
- continue;
307
- }
308
- let parsed: Parsed;
309
- try {
310
- parsed = JSON.parse(trimmed) as Parsed;
311
- } catch {
312
- continue;
313
- }
314
- if ((await dispatch(parsed)) === "delivered") {
315
- return;
316
- }
317
- }
318
- });
319
-
320
243
  // Invalidate the in-memory v2 edge index and page index when the LLM writes
321
244
  // or edits a file under `memory/concepts/`. The page-store invalidates on
322
245
  // programmatic writes; this hook covers consolidation, where the LLM edits
@@ -67,3 +67,42 @@ export interface TrustContext {
67
67
  */
68
68
  requesterInteractionCount?: number;
69
69
  }
70
+
71
+ /**
72
+ * Whether two trust contexts describe the same acting identity at the same
73
+ * privilege, for callers that may only run work under one of them (batched
74
+ * turns being the case that matters).
75
+ *
76
+ * Compares the privilege (`trustClass`), the channel a grant is scoped to
77
+ * (`sourceChannel`), and every field that can carry who the actor is. The
78
+ * identity fields are covered exhaustively rather than by picking the usual
79
+ * ones: an ingress that populates only `requesterIdentifier` or
80
+ * `requesterContactId` would otherwise leave two distinct senders comparing
81
+ * equal on a pair of undefineds, which is the exact case this guards.
82
+ *
83
+ * Deliberately conservative: an absent field never matches a present one, so
84
+ * unknown identities are treated as distinct. Answering "different" when they
85
+ * match only costs a batching opportunity; answering "same" when they differ
86
+ * runs one actor's work under another's privileges.
87
+ */
88
+ export function sameTrustIdentity(
89
+ a: TrustContext | undefined,
90
+ b: TrustContext | undefined,
91
+ ): boolean {
92
+ if (a === b) {
93
+ return true;
94
+ }
95
+ if (!a || !b) {
96
+ return false;
97
+ }
98
+ return (
99
+ a.trustClass === b.trustClass &&
100
+ a.sourceChannel === b.sourceChannel &&
101
+ a.requesterExternalUserId === b.requesterExternalUserId &&
102
+ a.requesterChatId === b.requesterChatId &&
103
+ a.requesterIdentifier === b.requesterIdentifier &&
104
+ a.requesterContactId === b.requesterContactId &&
105
+ a.guardianExternalUserId === b.guardianExternalUserId &&
106
+ a.guardianPrincipalId === b.guardianPrincipalId
107
+ );
108
+ }
@@ -87,12 +87,16 @@ export function isPersonalMemoryAllowed(
87
87
 
88
88
  /**
89
89
  * Map a channel-native chat type (Telegram `private`/`group`/`supergroup`,
90
- * Slack `im`/`mpim`/`channel`) onto the permission-matrix conversation-type
91
- * axis. Slack's gateway normalizer forwards every non-DM as `"channel"`
92
- * without distinguishing public from private, so `"channel"` maps to
93
- * undefined a permissive public-channel cell must not silently govern
94
- * private channels. The channel-type tier starts matching for Slack non-DMs
95
- * once the gateway forwards the distinct type.
90
+ * Slack `im`/`mpim`/`channel`, Discord `dm`/`channel`) onto the
91
+ * permission-matrix conversation-type axis. Slack and Discord both forward
92
+ * every non-DM as `"channel"` without distinguishing public from private, so
93
+ * `"channel"` maps to undefined: a permissive public-channel cell must not
94
+ * silently govern private channels. The channel-type tier starts matching for
95
+ * their non-DMs once the gateway forwards the distinct type.
96
+ *
97
+ * Every DM-capable channel must have an arm here. A missing one is silent:
98
+ * the cell stays settable, because the adapter validates, and simply never
99
+ * matches, so the guardian sets a rule for DMs and it does nothing.
96
100
  */
97
101
  export function mapChatTypeToConversationType(
98
102
  chatType?: string,
@@ -100,6 +104,10 @@ export function mapChatTypeToConversationType(
100
104
  switch (chatType) {
101
105
  case "im": // Slack DM
102
106
  case "private": // Telegram DM
107
+ // Discord has no string vocabulary for this: its API distinguishes a DM by
108
+ // a numeric channel type, and the absence of a guild. The normalizer names
109
+ // it for the axis rather than inventing a native-looking word.
110
+ case "dm":
103
111
  return "dm";
104
112
  // "mpim" is Slack's multi-party DM. The gateway normalizer currently
105
113
  // collapses mpim into "channel", so this arm matches nothing from Slack
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Per-conversation serialization for the detached end-of-turn tails the agent
3
+ * loop schedules after releasing the processing lock.
4
+ *
5
+ * The chain is keyed by conversation id and held at module scope rather than
6
+ * on the `Conversation` instance. A tail runs while the conversation reads
7
+ * idle, which is exactly the window in which `evictConversationsForReload` and
8
+ * the stale-instance rebuild in `conversation-store.ts` drop the live instance:
9
+ * an instance-scoped chain would let the rebuilt instance start an empty chain
10
+ * whose tail overlaps the previous instance's still-running one. The state
11
+ * those tails advance (memory segments, the conversation attention cursor) is
12
+ * per conversation, not per instance, so the serialization has to be too.
13
+ */
14
+
15
+ import { getLogger } from "../util/logger.js";
16
+
17
+ const log = getLogger("turn-tail-chain");
18
+
19
+ /** Tail promise per conversation id. Entries exist only while a tail is live. */
20
+ const chains = new Map<string, Promise<void>>();
21
+
22
+ /**
23
+ * Queue `tail` behind any tail already running for this conversation.
24
+ *
25
+ * Returns immediately: the tail is detached by design, so its failure is
26
+ * logged rather than surfaced. The chain is `.catch`-terminated at every link,
27
+ * so a rejected tail can neither become an unhandled rejection nor poison the
28
+ * tails queued after it.
29
+ */
30
+ export function chainTurnTail(
31
+ conversationId: string,
32
+ tail: () => Promise<void>,
33
+ ): void {
34
+ const previous = chains.get(conversationId) ?? Promise.resolve();
35
+ const next: Promise<void> = previous
36
+ .then(tail)
37
+ .catch((err: unknown) => {
38
+ log.warn(
39
+ { err, conversationId },
40
+ "Deferred turn tail failed (non-fatal)",
41
+ );
42
+ })
43
+ .then(() => {
44
+ // Drop the entry only when nothing chained onto this link while it ran,
45
+ // so the map holds an entry per conversation with a live tail rather
46
+ // than one per conversation the daemon has ever served.
47
+ if (chains.get(conversationId) === next) {
48
+ chains.delete(conversationId);
49
+ }
50
+ });
51
+ chains.set(conversationId, next);
52
+ }
53
+
54
+ /**
55
+ * Resolve once every tail currently queued for this conversation has settled.
56
+ *
57
+ * Tests use this to await work the agent loop deliberately detached. Callers
58
+ * that chain a new tail after awaiting get a fresh promise, so this is a
59
+ * point-in-time barrier, not a permanent quiesce.
60
+ */
61
+ export function settleTurnTail(conversationId: string): Promise<void> {
62
+ return chains.get(conversationId) ?? Promise.resolve();
63
+ }
64
+
65
+ /**
66
+ * Number of conversations with a live tail. Lets tests assert the map is
67
+ * released rather than growing per conversation.
68
+ *
69
+ * @internal
70
+ */
71
+ export function __turnTailChainSizeForTests(): number {
72
+ return chains.size;
73
+ }
@@ -20,18 +20,27 @@ export interface StripResult {
20
20
  /**
21
21
  * Replaces every `web_search_tool_result` block in the message list with a
22
22
  * plain `text` summary of its results, and drops the paired `server_tool_use`
23
- * that produced it.
23
+ * that produced it, wherever that use lives. The pair usually shares one
24
+ * assistant message, but a deferred execution (the API runs the search on the
25
+ * request after a mixed server/client parallel tool group) places the result
26
+ * at the head of the following assistant message, so pairing is resolved
27
+ * across the whole list. Dropping both sides together keeps the history free
28
+ * of unpaired server-tool blocks, which the provider layer would otherwise
29
+ * repair with a synthetic error result.
30
+ *
31
+ * A `server_tool_use` with no result anywhere in the list is left untouched:
32
+ * either the search is still pending (deferred tail, executed by the provider
33
+ * on this request) or it is a genuine orphan the provider layer repairs.
24
34
  *
25
35
  * Anthropic's `encrypted_content` tokens attached to each `web_search_result`
26
36
  * are opaque server tokens with bounded validity (they expire and/or are
27
37
  * route-scoped). Replaying a stale token produces
28
38
  * `messages.N.content.M: Invalid encrypted_content in search_result block`.
29
39
  * For historical turns the model does not need the opaque token to re-read
30
- * the body a title+url summary is sufficient to preserve context.
40
+ * the body: a title+url summary is sufficient to preserve context.
31
41
  *
32
- * Intended to run on `runMessages` immediately before the agent loop starts a
33
- * new turn, at which point every `web_search_tool_result` in the list is by
34
- * definition from a prior turn.
42
+ * Runs on the outbound message list before each model call; every executed
43
+ * search in the list is summarized regardless of which turn produced it.
35
44
  */
36
45
  export function stripHistoricalWebSearchResults(
37
46
  messages: Message[],
@@ -42,42 +51,45 @@ export function stripHistoricalWebSearchResults(
42
51
  messagesModified: 0,
43
52
  };
44
53
 
45
- const next: Message[] = messages.map((msg) => {
46
- const droppedServerToolUseIds = new Set<string>();
47
- const transformed: ContentBlock[] = [];
48
-
54
+ const strippedToolUseIds = new Set<string>();
55
+ for (const msg of messages) {
49
56
  for (const block of msg.content) {
50
- if (block.type !== "web_search_tool_result") {
51
- continue;
57
+ if (block.type === "web_search_tool_result") {
58
+ strippedToolUseIds.add(
59
+ (block as WebSearchToolResultContent).tool_use_id,
60
+ );
52
61
  }
53
- const wsr = block as WebSearchToolResultContent;
54
- const query = findQueryForToolUseId(msg.content, wsr.tool_use_id);
55
- transformed.push(formatAsText(wsr, query));
56
- droppedServerToolUseIds.add(wsr.tool_use_id);
57
- stats.blocksStripped++;
58
- }
59
-
60
- if (droppedServerToolUseIds.size === 0) {
61
- return msg;
62
62
  }
63
+ }
63
64
 
65
+ const next: Message[] = messages.map((msg) => {
66
+ let modified = false;
64
67
  const rewritten: ContentBlock[] = [];
65
- let wsrIndex = 0;
68
+
66
69
  for (const block of msg.content) {
67
70
  if (block.type === "server_tool_use") {
68
71
  const stu = block as ServerToolUseContent;
69
- if (droppedServerToolUseIds.has(stu.id)) {
72
+ if (strippedToolUseIds.has(stu.id)) {
70
73
  stats.serverToolUsesDropped++;
74
+ modified = true;
71
75
  continue;
72
76
  }
73
77
  rewritten.push(block);
74
78
  } else if (block.type === "web_search_tool_result") {
75
- rewritten.push(transformed[wsrIndex++]);
79
+ const wsr = block as WebSearchToolResultContent;
80
+ rewritten.push(
81
+ formatAsText(wsr, findQueryForToolUseId(messages, wsr.tool_use_id)),
82
+ );
83
+ stats.blocksStripped++;
84
+ modified = true;
76
85
  } else {
77
86
  rewritten.push(block);
78
87
  }
79
88
  }
80
89
 
90
+ if (!modified) {
91
+ return msg;
92
+ }
81
93
  stats.messagesModified++;
82
94
  return { ...msg, content: rewritten };
83
95
  });
@@ -86,19 +98,21 @@ export function stripHistoricalWebSearchResults(
86
98
  }
87
99
 
88
100
  function findQueryForToolUseId(
89
- blocks: ContentBlock[],
101
+ messages: Message[],
90
102
  toolUseId: string,
91
103
  ): string | null {
92
- for (const b of blocks) {
93
- if (b.type !== "server_tool_use") {
94
- continue;
95
- }
96
- const stu = b as ServerToolUseContent;
97
- if (stu.id !== toolUseId) {
98
- continue;
104
+ for (const msg of messages) {
105
+ for (const b of msg.content) {
106
+ if (b.type !== "server_tool_use") {
107
+ continue;
108
+ }
109
+ const stu = b as ServerToolUseContent;
110
+ if (stu.id !== toolUseId) {
111
+ continue;
112
+ }
113
+ const q = stu.input?.query;
114
+ return typeof q === "string" ? q : null;
99
115
  }
100
- const q = stu.input?.query;
101
- return typeof q === "string" ? q : null;
102
116
  }
103
117
  return null;
104
118
  }
@@ -4,7 +4,7 @@ import { join } from "node:path";
4
4
  import type { HeartbeatAlertEvent } from "../api/events/heartbeat-alert.js";
5
5
  import { getConfig } from "../config/loader.js";
6
6
  import type { HeartbeatConfig } from "../config/schemas/heartbeat.js";
7
- import { getGuardianDelivery } from "../contacts/guardian-delivery-reader.js";
7
+ import { warmGuardianBindings } from "../contacts/guardian-delivery-reader.js";
8
8
  import {
9
9
  checkDiskPressureBackgroundGate,
10
10
  diskPressureBackgroundSkipLogFields,
@@ -815,10 +815,11 @@ export class HeartbeatService {
815
815
 
816
816
  const checklist = this.readChecklist();
817
817
  const completedRunCount = countCompletedHeartbeatRuns();
818
- // Warm the vellum guardian-delivery cache so buildPrompt's sync guardian
819
- // persona read (isShallowProfile → resolveGuardianPersona) hits a fresh key
820
- // instead of falling back to default.md on a cold/TTL-expired cache.
821
- await getGuardianDelivery({ channelTypes: ["vellum"] });
818
+ // Warm both guardian-delivery cache keys (vellum + unfiltered) so
819
+ // buildPrompt's sync guardian persona read (isShallowProfile →
820
+ // resolveGuardianPersona), including its any-channel fallback, hits fresh
821
+ // keys instead of falling back to default.md on a cold/TTL-expired cache.
822
+ await warmGuardianBindings();
822
823
  const { prompt, includedReengagement } = this.buildPrompt(
823
824
  checklist,
824
825
  unhealthyProviders,
@@ -848,7 +849,6 @@ export class HeartbeatService {
848
849
  callSite: "heartbeatAgent",
849
850
  timeoutMs: getConfig().timeouts.backgroundTurnTimeoutSec * 1000,
850
851
  origin: "heartbeat",
851
- deferNotifications: true,
852
852
  onConversationCreated: (newConversationId) => {
853
853
  conversationId = newConversationId;
854
854
  broadcastMessage({
@@ -1,6 +1,8 @@
1
+ import { createServer } from "node:net";
1
2
  import { tmpdir } from "node:os";
2
3
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
3
4
 
5
+ import { ensureSocketPathFree } from "../socket-cleanup.js";
4
6
  import { resolveIpcSocketPath } from "../socket-path.js";
5
7
 
6
8
  let savedWorkspaceDir: string | undefined;
@@ -77,4 +79,23 @@ describe("resolveIpcSocketPath", () => {
77
79
 
78
80
  delete process.env.EXAMPLE_SERVICE_IPC_SOCKET_DIR;
79
81
  });
82
+
83
+ test.skipIf(process.platform !== "win32")(
84
+ "rejects an occupied named pipe",
85
+ async () => {
86
+ const pipe = `\\\\.\\pipe\\vellum-ipc-test-${process.pid}`;
87
+ const server = createServer();
88
+ await new Promise<void>((resolve, reject) => {
89
+ server.once("error", reject);
90
+ server.listen(pipe, resolve);
91
+ });
92
+ try {
93
+ await expect(ensureSocketPathFree(pipe)).rejects.toMatchObject({
94
+ code: "EADDRINUSE",
95
+ });
96
+ } finally {
97
+ server.close();
98
+ }
99
+ },
100
+ );
80
101
  });