@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
@@ -83,10 +83,10 @@ import { FALLBACK_TURN_TRUST, resolveTrustClass } from "./trust-context.js";
83
83
 
84
84
  const log = getLogger("conversation-tool-setup");
85
85
 
86
- import type { ToolSetupContext } from "./tool-setup-types.js";
86
+ import type { SubagentToolStats } from "./tool-setup-types.js";
87
87
  export type {
88
88
  SubagentToolGateMode,
89
- ToolSetupContext,
89
+ SubagentToolStats,
90
90
  WakeToolContextPin,
91
91
  } from "./tool-setup-types.js";
92
92
 
@@ -112,7 +112,7 @@ export type {
112
112
  */
113
113
  export function resolveConversationAttribution(
114
114
  ctx: Pick<
115
- ToolSetupContext,
115
+ Conversation,
116
116
  "conversationId" | "currentCallSite" | "currentTurnOverrideProfile"
117
117
  >,
118
118
  ): UsageAttributionSnapshot | null {
@@ -197,8 +197,13 @@ export function getEffectiveEnabledPluginSet(conv: {
197
197
  * own implementation) does not slip through. `skill_execute` is the dispatcher —
198
198
  * its resolved inner tool is classified by the same check in the executor gate,
199
199
  * so exposing the wrapper is safe.
200
+ *
201
+ * Exported so a role allowlist that relies on this gate for its read-only
202
+ * guarantee (the advisor consult) can be asserted to stay inside the set: a name
203
+ * outside it is admitted by the role and then refused at dispatch, which reads
204
+ * as a broken tool rather than a policy decision.
200
205
  */
201
- const READ_ONLY_ALLOWED_TOOLS: ReadonlySet<string> = new Set([
206
+ export const READ_ONLY_ALLOWED_TOOLS: ReadonlySet<string> = new Set([
202
207
  "file_read",
203
208
  "file_list",
204
209
  "code_search",
@@ -232,7 +237,7 @@ export function createToolExecutor(
232
237
  executor: ToolExecutor,
233
238
  prompter: PermissionPrompter,
234
239
  secretPrompter: SecretPrompter,
235
- ctx: ToolSetupContext,
240
+ ctx: Conversation,
236
241
  ): (
237
242
  name: string,
238
243
  input: Record<string, unknown>,
@@ -311,6 +316,45 @@ export function createToolExecutor(
311
316
  };
312
317
  };
313
318
 
319
+ // Machine tool-call accounting for the subagent truth envelope. Recorded
320
+ // here because this closure is the single dispatch choke point every tool
321
+ // call passes through, including the `skill_execute` indirection (counted
322
+ // under the resolved inner tool name, not the wrapper). Non-subagent
323
+ // conversations never reach the counters.
324
+ const subagentStats = (): SubagentToolStats | undefined =>
325
+ ctx.isSubagent === true ? ctx.subagentToolStats : undefined;
326
+
327
+ const recordToolDispatch = (): void => {
328
+ const stats = subagentStats();
329
+ if (stats) {
330
+ stats.calls++;
331
+ }
332
+ };
333
+
334
+ const recordToolResult = (
335
+ toolName: string,
336
+ toolInput: Record<string, unknown>,
337
+ result: ToolExecutionResult,
338
+ ): void => {
339
+ const stats = subagentStats();
340
+ if (!stats || result.isError) {
341
+ return;
342
+ }
343
+ stats.succeeded++;
344
+ // Both file tools name their target `path`. A Set dedupes repeated edits
345
+ // of the same file, so the count reads as "files touched", not "writes".
346
+ // These two are the only writes with a path to attribute: a builder can
347
+ // also write through the shell, a document tool, or an MCP tool, and those
348
+ // are invisible here, which is why the footer names the two tools it
349
+ // counts (see `formatSubagentToolStats`).
350
+ if (toolName === "file_write" || toolName === "file_edit") {
351
+ const target = toolInput.path;
352
+ if (typeof target === "string" && target.length > 0) {
353
+ stats.filesWritten.add(target);
354
+ }
355
+ }
356
+ };
357
+
314
358
  return async (
315
359
  name: string,
316
360
  input: Record<string, unknown>,
@@ -357,7 +401,7 @@ export function createToolExecutor(
357
401
  trustClass: resolveTrustClass(turnTrust),
358
402
  executionChannel: turnTrust.sourceChannel,
359
403
  requestOrigin: ctx.currentTurnRequestOrigin,
360
- sourceActorPrincipalId: turnTrust.guardianPrincipalId,
404
+ sourceActorPrincipalId: ctx.getTurnActorPrincipalId(),
361
405
  callSessionId: ctx.callSessionId,
362
406
  triggeredBySurfaceAction:
363
407
  ctx.surfaceActionRequestIds?.has(ctx.currentRequestId ?? "") ?? false,
@@ -390,6 +434,7 @@ export function createToolExecutor(
390
434
  isPlatformHosted: getIsPlatform(),
391
435
  transportInterface: ctx.transportInterface,
392
436
  overrideProfile: ctx.currentTurnOverrideProfile,
437
+ cronRunId: ctx.currentTurnCronRunId,
393
438
  invokingCallSite: ctx.currentCallSite ?? "mainAgent",
394
439
  attribution: resolveConversationAttribution(ctx),
395
440
  enabledPluginSet: effectiveEnabledPluginSet,
@@ -505,12 +550,14 @@ export function createToolExecutor(
505
550
  return pluginRejection;
506
551
  }
507
552
 
553
+ recordToolDispatch();
508
554
  const rawResult = await executor.execute(
509
555
  toolName,
510
556
  toolInput,
511
557
  toolContext,
512
558
  );
513
559
  const result = augmentSkillExecuteError(toolName, toolInput, rawResult);
560
+ recordToolResult(toolName, toolInput, result);
514
561
  if (toolContext.approvedViaPrompt) {
515
562
  ctx.approvedViaPromptThisTurn = true;
516
563
  }
@@ -520,11 +567,13 @@ export function createToolExecutor(
520
567
  return result;
521
568
  }
522
569
 
570
+ recordToolDispatch();
523
571
  const result = await executor.execute(
524
572
  executionName,
525
573
  executionInput,
526
574
  toolContext,
527
575
  );
576
+ recordToolResult(executionName, executionInput, result);
528
577
  if (toolContext.approvedViaPrompt) {
529
578
  ctx.approvedViaPromptThisTurn = true;
530
579
  }
@@ -547,7 +596,7 @@ export function createToolExecutor(
547
596
  */
548
597
  export function createProxyApprovalCallback(
549
598
  _prompter: PermissionPrompter,
550
- _ctx: ToolSetupContext,
599
+ _ctx: Conversation,
551
600
  ): ProxyApprovalCallback {
552
601
  return async (_request: ProxyApprovalRequest): Promise<boolean> => {
553
602
  // Proxied asks follow the same non-host auto-allow contract as regular
@@ -1,5 +1,5 @@
1
1
  /**
2
- * End-of-turn finalize work that runs OFF the send-button critical path.
2
+ * End-of-turn finalize work that runs after the terminal SSE.
3
3
  *
4
4
  * The web/Capacitor/CLI clients re-enable the composer the moment they observe
5
5
  * the terminal `message_complete` / `assistant_activity_state("idle")` SSE, so
@@ -9,10 +9,21 @@
9
9
  * None of the work here gates delivery of the reply: memory/attention indexing
10
10
  * only feeds the NEXT turn's retrieval and a sidebar indicator, tool-result
11
11
  * truncation only reshapes the in-memory history the next turn is built from,
12
- * and the disk-view mirror is a durability convenience. The agent loop persists
13
- * the reply content synchronously and emits the terminal SSE first, then drains
14
- * this module's work before the turn's `finally` starts the next turn — so the
15
- * bookkeeping still completes within the turn, just after the composer is free.
12
+ * and the disk-view mirror is a durability convenience. The work is split by
13
+ * whether a step is safe to overlap the NEXT turn:
14
+ *
15
+ * - {@link settleTurnContent} runs while the turn still holds the processing
16
+ * lock. Its steps rewrite `ctx.messages` and append to the conversation's disk
17
+ * view, both of which the next turn also writes, so they must finish before
18
+ * the lock releases. Every step is synchronous apart from the stranded-content
19
+ * fold, so holding the lock across them costs the queue nothing: synchronous
20
+ * work blocks the event loop either way.
21
+ * - {@link runDeferredTurnTail} runs detached, after the lock releases, chained
22
+ * by `chainTurnTail` so two turns' tails never overlap each other. Its steps
23
+ * are keyed by the message ids this turn produced and are network-bound
24
+ * (embeddings, vector upserts, the assistant-reply push notification), which
25
+ * is the work that must not hold the lock:
26
+ * a slow index otherwise leaves the next send queued behind an idle-looking UI.
16
27
  */
17
28
 
18
29
  import type pino from "pino";
@@ -42,20 +53,25 @@ import {
42
53
  } from "./inflight-message-content.js";
43
54
  import { conversationMetadataSyncTag } from "./message-types/sync.js";
44
55
 
45
- /** Minimal live-conversation surface the deferred tail reads and rewrites. */
56
+ /** Minimal live-conversation surface the finalize steps read and rewrite. */
46
57
  interface TurnTailContext {
47
58
  readonly conversationId: string;
48
59
  messages: Message[];
49
60
  }
50
61
 
51
- /** Minimal per-run handler state the deferred tail consumes. */
52
- interface TurnTailState {
53
- readonly deferredFinalizeEffects: ReadonlyArray<() => Promise<void>>;
62
+ /** Minimal per-run handler state {@link settleTurnContent} consumes. */
63
+ interface TurnContentState {
54
64
  readonly lastAssistantMessageId: string | undefined;
55
65
  /** In-flight content writers the turn left behind (see EventHandlerState). */
56
66
  readonly inflightWriters: Map<string, InflightContentWriter>;
57
67
  }
58
68
 
69
+ /** Minimal per-run handler state the detached tail consumes. */
70
+ interface TurnTailState {
71
+ readonly deferredFinalizeEffects: ReadonlyArray<() => Promise<void>>;
72
+ readonly lastAssistantMessageId: string | undefined;
73
+ }
74
+
59
75
  /**
60
76
  * Build the deferred finalize side-effect for one finalized assistant row:
61
77
  * memory segment indexing, lexical indexing, and attention projection.
@@ -129,95 +145,36 @@ export function buildDeferredFinalizeEffect(params: {
129
145
  }
130
146
 
131
147
  /**
132
- * Drain a turn's deferred bookkeeping after the terminal SSE has re-enabled the
133
- * composer but before the agent loop's `finally` commits and drains the queue
134
- * for the next turn. Ordering with the next turn is preserved (this completes
135
- * before `drainQueue`), while the last-token→send-button latency no longer
136
- * includes it. Every step is best-effort.
148
+ * Settle the turn's content while the processing lock is still held.
137
149
  *
138
- * `generationCompletedAt` is stamped when the agent loop returns; the emitted
139
- * `criticalSectionMs` / `deferredTailMs` split makes the previously-uninstrumented
140
- * end-of-turn window measurable.
150
+ * These steps run after the terminal SSE (so they are off the last-token to
151
+ * composer-enabled path) but before the lock releases, because each one writes
152
+ * a resource the next turn also writes: the in-memory history array and the
153
+ * conversation's append-only disk view. The processing lock is the only
154
+ * per-conversation serialization those resources have, so letting these steps
155
+ * run past the release would let a fast follow-up turn interleave with them.
156
+ * Every step is best-effort.
141
157
  */
142
- export async function runDeferredTurnTail(params: {
158
+ export async function settleTurnContent(params: {
143
159
  ctx: TurnTailContext;
144
- state: TurnTailState;
160
+ state: TurnContentState;
145
161
  rlog: pino.Logger;
146
- generationCompletedAt: number;
147
- /**
148
- * True only for a `message_complete` turn that produced a genuine reply. A
149
- * handed-off generation is not the end of the run, a cancelled one has no
150
- * final reply, and a provider-error turn's only assistant row is the
151
- * synthetic error text.
152
- */
153
- turnCompleted: boolean;
154
- /** Id of the row that opened this turn, for the notification producer. */
155
- userMessageId: string | undefined;
156
- /**
157
- * True when this turn's reply streams to the app and nowhere else, for the
158
- * notification producer's delivery-surface gates.
159
- */
160
- replyDeliveredInAppOnly?: boolean;
161
162
  }): Promise<void> {
162
- const {
163
- ctx,
164
- state,
165
- rlog,
166
- generationCompletedAt,
167
- turnCompleted,
168
- userMessageId,
169
- replyDeliveredInAppOnly,
170
- } = params;
171
- const tailStartedAt = Date.now();
163
+ const { ctx, state, rlog } = params;
172
164
 
173
- // Conversation row for the notification producer below. Guarded like every
174
- // step below, because this runs after the terminal SSE and a SQLite hiccup
175
- // must not escape into the loop's outer catch.
176
- let conversation: ConversationRow | null = null;
177
- try {
178
- conversation = getConversation(ctx.conversationId);
179
- } catch (err) {
180
- rlog.warn({ err }, "Failed to read conversation for end-of-turn work");
181
- }
182
-
183
- // Per-message memory/attention finalize side-effects deferred from
184
- // `handleMessageComplete`: one closure per assistant row produced this turn,
185
- // in production order.
186
- for (const effect of state.deferredFinalizeEffects) {
187
- try {
188
- await effect();
189
- } catch (err) {
190
- rlog.warn({ err }, "Deferred finalize side-effect failed (non-fatal)");
191
- }
192
- }
193
-
194
- // Notify about a finished reply the user is no longer looking at. Ordered
195
- // after the loop above so the producer's unseen check reads the attention
196
- // cursor this turn's last row just projected. Not awaited: the pipeline
197
- // awaits the platform adapter's HTTP dispatch, which retries with backoff,
198
- // and nothing below here depends on the emit. The producer never rejects.
199
- if (turnCompleted && state.lastAssistantMessageId) {
200
- void emitAssistantReplyNotification({
201
- conversationId: ctx.conversationId,
202
- assistantMessageId: state.lastAssistantMessageId,
203
- userMessageId,
204
- ...(replyDeliveredInAppOnly ? { replyDeliveredInAppOnly: true } : {}),
205
- rlog,
206
- conversation,
207
- });
208
- }
209
-
210
- // Fresh row for the two filesystem steps below. The awaited work above is
211
- // long enough for the user to delete the conversation, and the row read at
212
- // the top of the tail stays truthy across that deletion, so spooling or
213
- // mirroring against it would rebuild a deleted conversation's directory from
214
- // in-memory history. A row that is gone skips both steps exactly as an
215
- // unreadable one does.
165
+ // Conversation row for the two filesystem steps below. Read here rather than
166
+ // reused from anywhere earlier in the turn: the turn is long enough for the
167
+ // user to delete the conversation, and a row read before that deletion stays
168
+ // truthy across it, so spooling or mirroring against it would rebuild a
169
+ // deleted conversation's directory from in-memory history. A row that is gone
170
+ // skips both steps exactly as an unreadable one does. Guarded like every step
171
+ // below, because this runs after the terminal SSE and a SQLite hiccup must not
172
+ // escape into the loop's outer catch.
216
173
  let liveConversation: ConversationRow | null = null;
217
174
  try {
218
175
  liveConversation = getConversation(ctx.conversationId);
219
176
  } catch (err) {
220
- rlog.warn({ err }, "Failed to re-read conversation for end-of-turn work");
177
+ rlog.warn({ err }, "Failed to read conversation for end-of-turn work");
221
178
  }
222
179
 
223
180
  // Post-turn tool-result truncation: spool oversized results to disk and
@@ -275,10 +232,98 @@ export async function runDeferredTurnTail(params: {
275
232
  } catch (err) {
276
233
  rlog.warn({ err }, "Failed to sync assistant message to disk (non-fatal)");
277
234
  }
235
+ }
236
+
237
+ /**
238
+ * Drain a turn's deferred bookkeeping after the processing lock has released.
239
+ *
240
+ * Runs detached from the agent loop and chained through `chainTurnTail`, so a
241
+ * slow index never holds the next turn's send behind an idle composer, yet two
242
+ * turns' tails still run in turn order even when the second turn ran on a
243
+ * rebuilt `Conversation` instance. Every step is best-effort and keyed by a
244
+ * message id this turn produced, so it neither reads nor writes state the next
245
+ * turn owns.
246
+ *
247
+ * `criticalSectionMs` is the lock-held window the agent loop measured from the
248
+ * end of generation; paired with `deferredTailMs` it splits the end-of-turn
249
+ * window into the part a waiting sender feels and the part it no longer does.
250
+ */
251
+ export async function runDeferredTurnTail(params: {
252
+ conversationId: string;
253
+ state: TurnTailState;
254
+ rlog: pino.Logger;
255
+ criticalSectionMs: number;
256
+ /**
257
+ * True only for a `message_complete` turn that produced a genuine reply. A
258
+ * handed-off generation is not the end of the run, a cancelled one has no
259
+ * final reply, and a provider-error turn's only assistant row is the
260
+ * synthetic error text.
261
+ */
262
+ turnCompleted: boolean;
263
+ /** Id of the row that opened this turn, for the notification producer. */
264
+ userMessageId: string | undefined;
265
+ /**
266
+ * True when this turn's reply streams to the app and nowhere else, for the
267
+ * notification producer's delivery-surface gates.
268
+ */
269
+ replyDeliveredInAppOnly?: boolean;
270
+ }): Promise<void> {
271
+ const {
272
+ conversationId,
273
+ state,
274
+ rlog,
275
+ criticalSectionMs,
276
+ turnCompleted,
277
+ userMessageId,
278
+ replyDeliveredInAppOnly,
279
+ } = params;
280
+ const tailStartedAt = Date.now();
281
+
282
+ // Conversation row for the notification producer below. Guarded like every
283
+ // step here, because this runs after the terminal SSE and a SQLite hiccup must
284
+ // not escape into the detached tail's caller.
285
+ let conversation: ConversationRow | null = null;
286
+ try {
287
+ conversation = getConversation(conversationId);
288
+ } catch (err) {
289
+ rlog.warn({ err }, "Failed to read conversation for end-of-turn work");
290
+ }
291
+
292
+ // Per-message memory/attention finalize side-effects deferred from
293
+ // `handleMessageComplete`: one closure per assistant row produced this turn,
294
+ // in production order.
295
+ for (const effect of state.deferredFinalizeEffects) {
296
+ try {
297
+ await effect();
298
+ } catch (err) {
299
+ rlog.warn({ err }, "Deferred finalize side-effect failed (non-fatal)");
300
+ }
301
+ }
302
+
303
+ // Notify about a finished reply the user is no longer looking at. Ordered
304
+ // after the loop above so the producer's unseen check reads the attention
305
+ // cursor this turn's last row just projected; that projection is the
306
+ // network-bound work this whole tail exists to keep off the lock, so the
307
+ // check necessarily runs with the conversation already free. A follow-up
308
+ // send that beats it there advances the cursor and suppresses the push,
309
+ // which is the right answer: a user typing the next message is looking at
310
+ // the reply. Not awaited: the pipeline awaits the platform adapter's HTTP
311
+ // dispatch, which retries with backoff, and nothing below here depends on
312
+ // the emit. The producer never rejects.
313
+ if (turnCompleted && state.lastAssistantMessageId) {
314
+ void emitAssistantReplyNotification({
315
+ conversationId,
316
+ assistantMessageId: state.lastAssistantMessageId,
317
+ userMessageId,
318
+ ...(replyDeliveredInAppOnly ? { replyDeliveredInAppOnly: true } : {}),
319
+ rlog,
320
+ conversation,
321
+ });
322
+ }
278
323
 
279
324
  rlog.info(
280
325
  {
281
- criticalSectionMs: tailStartedAt - generationCompletedAt,
326
+ criticalSectionMs,
282
327
  deferredTailMs: Date.now() - tailStartedAt,
283
328
  },
284
329
  "End-of-turn work complete",
@@ -96,6 +96,7 @@ import type { OnboardingContext } from "../types/onboarding-context.js";
96
96
  import type { AbortReason } from "../util/abort-reasons.js";
97
97
  import { UserError } from "../util/errors.js";
98
98
  import { getLogger } from "../util/logger.js";
99
+ import { withSqliteRetry } from "../util/sqlite-retry.js";
99
100
  import type { WorkspaceGitService } from "../workspace/git-service.js";
100
101
  import type { commitTurnChanges } from "../workspace/turn-commit.js";
101
102
  import type { AssistantAttachmentDraft } from "./assistant-attachments.js";
@@ -154,7 +155,7 @@ import {
154
155
  } from "./conversation-surfaces.js";
155
156
  import type {
156
157
  SubagentToolGateMode,
157
- ToolSetupContext,
158
+ SubagentToolStats,
158
159
  WakeToolContextPin,
159
160
  } from "./conversation-tool-setup.js";
160
161
  import {
@@ -275,8 +276,8 @@ export interface ConversationConstructorOptions {
275
276
  * Give this conversation's LLM calls provider-native (server-side) web
276
277
  * search when the resolved provider supports it (see
277
278
  * {@link AgentLoopConfig.enableNativeWebSearch}). Set by the subagent manager
278
- * for the tool-less advisor consult so it can ground guidance with live web
279
- * access; non-native providers get nothing. Defaults to false.
279
+ * for the advisor consult so it can ground guidance with live web access;
280
+ * non-native providers get nothing. Defaults to false.
280
281
  */
281
282
  enableNativeWebSearch?: boolean;
282
283
  /**
@@ -360,6 +361,20 @@ export class Conversation {
360
361
  * @internal
361
362
  */
362
363
  subagentDeniedToolNames = new Set<string>();
364
+ /**
365
+ * Machine tool-call counters for this conversation when it runs as a
366
+ * subagent child. Recorded by the tool executor (gated on {@link isSubagent},
367
+ * so parent conversations never accumulate anything here) and harvested by
368
+ * the SubagentManager into the child's state when the run ends, where it
369
+ * becomes the stats footer on the parent's completion notification and on
370
+ * `subagent_read`. Ephemeral, never persisted.
371
+ * @internal
372
+ */
373
+ subagentToolStats: SubagentToolStats = {
374
+ calls: 0,
375
+ succeeded: 0,
376
+ filesWritten: new Set<string>(),
377
+ };
363
378
  /**
364
379
  * How {@link subagentAllowedTools} is enforced — see
365
380
  * {@link SubagentToolGateMode}. Set and restored alongside the allowlist
@@ -481,6 +496,14 @@ export class Conversation {
481
496
  */
482
497
  wakePersonaOverride?: SystemPromptPersonaOverride;
483
498
  /** @internal */ currentTurnOverrideProfile?: string;
499
+ /**
500
+ * The firing's `cron_runs.id` when a schedule triggered the current turn.
501
+ * Exposed on the live conversation so the tool context can forward it to
502
+ * delegated LLM work (subagent spawns and messages), whose usage rows then
503
+ * attribute to the same firing.
504
+ * @internal
505
+ */
506
+ currentTurnCronRunId?: string | null;
484
507
  /** @internal */ currentTurnIsNonInteractive?: boolean;
485
508
  /** @internal */ currentTurnModelProfileNoticeKey?: string;
486
509
  /** @internal */ currentTurnRequestOrigin?: string;
@@ -538,11 +561,23 @@ export class Conversation {
538
561
  * @internal
539
562
  */
540
563
  pendingSteerRepair = false;
564
+ /**
565
+ * Set by `abortConversation` when a user interrupt (Stop / Esc / the CLI
566
+ * cancel signal) ends a turn that still has messages queued behind it. Those
567
+ * messages survive the abort and drain into the next turn, so the drain path
568
+ * owes them the same synthetic tool_result repair a steer gets: the killed
569
+ * turn may have left `tool_use` blocks with no results. Unlike
570
+ * `pendingSteerRepair` this does not promote a single head message. An
571
+ * interrupt has nothing to promote, so the drain batches the queue the way it
572
+ * would after any other turn. Cleared after repair.
573
+ * @internal
574
+ */
575
+ pendingInterruptRepair = false;
541
576
  /**
542
577
  * When true, side-effect tools must prompt even if a trust/allow rule
543
578
  * would auto-allow. Set by non-interactive callers (e.g. non-guardian
544
579
  * phone voice) so their auto-deny handler reliably sees a
545
- * `confirmation_request` event. See ToolSetupContext.forcePromptSideEffects.
580
+ * `confirmation_request` event. See `forcePromptSideEffects` below.
546
581
  * @internal
547
582
  */
548
583
  forcePromptSideEffects = false;
@@ -605,7 +640,7 @@ export class Conversation {
605
640
  /** @internal */ clientTimezone?: string;
606
641
  /**
607
642
  * @internal
608
- * The client's OS surface ("web" | "ios" | "macos"), reported separately
643
+ * The client's OS surface, reported separately
609
644
  * from the transport `interfaceId` so the assistant's per-turn context can
610
645
  * show the real platform without affecting host-proxy/transport gating.
611
646
  * This is the LIVE value (re-applied from transport on every inbound
@@ -765,7 +800,7 @@ export class Conversation {
765
800
  this.executor,
766
801
  this.prompter,
767
802
  this.secretPrompter,
768
- this as ToolSetupContext,
803
+ this,
769
804
  );
770
805
 
771
806
  const config = getConfig();
@@ -1564,38 +1599,45 @@ export class Conversation {
1564
1599
  * Mutate the server-authoritative `processing` flag. Web/Capacitor/CLI
1565
1600
  * caches treat this flag as the source of truth for the avatar streaming
1566
1601
  * ring and thinking indicator, so the `true → false` clear must announce
1567
- * itself: the daemon flips it in the agent-loop `finally`, which runs after
1568
- * the user-visible terminal SSE events, and a racing metadata refetch can
1569
- * otherwise re-read the not-yet-cleared `true` and clobber the client's
1602
+ * itself: the daemon flips it once the finished turn's content is settled,
1603
+ * after the user-visible terminal SSE events, and a racing metadata refetch
1604
+ * can otherwise re-read the not-yet-cleared `true` and clobber the client's
1570
1605
  * optimistic `false`.
1571
1606
  *
1572
1607
  * Emitting a metadata invalidation on the clear lets every client GET the
1573
1608
  * authoritative `false`, per the multi-client-sync contract in AGENTS.md
1574
1609
  * ("emit the invalidation after the canonical state write succeeds").
1610
+ *
1611
+ * The two directions have different failure semantics because the in-memory
1612
+ * flag and the persisted column serve different readers. Acquiring is
1613
+ * strict: a failed persist reverts the in-memory flag and re-throws, so the
1614
+ * caller's existing failure handling runs and the two never disagree about a
1615
+ * turn that is starting. Clearing is not: the in-memory flag is the queue
1616
+ * gate this process enforces, while the column is advisory state for
1617
+ * out-of-process readers that the boot-time stale-processing sweep already
1618
+ * recovers. Reverting a clear because a mirror write lost a race with
1619
+ * SQLITE_BUSY would latch the conversation into "busy" for the rest of the
1620
+ * daemon's life, so the clear always sticks.
1575
1621
  */
1576
1622
  setProcessing(value: boolean): void {
1577
1623
  const wasProcessing = this._processing;
1578
1624
  this._processing = value;
1579
1625
  // Persist the cross-process source of truth so out-of-process callers
1580
1626
  // (retrospective CLI, future detached workers) can detect mid-turn state
1581
- // by reading the conversations row directly. If the write fails (e.g.
1582
- // SQLITE_BUSY), the persisted column keeps its prior value, so revert the
1583
- // in-memory flag to match rather than stranding `processing = true` in
1584
- // memory against a NULL column. Re-throw so callers' existing failure
1585
- // handling still runs.
1586
- try {
1587
- setConversationProcessingStartedAt(
1588
- this.conversationId,
1589
- value ? Date.now() : null,
1590
- );
1591
- } catch (err) {
1592
- this._processing = wasProcessing;
1593
- throw err;
1627
+ // by reading the conversations row directly.
1628
+ if (value) {
1629
+ try {
1630
+ setConversationProcessingStartedAt(this.conversationId, Date.now());
1631
+ } catch (err) {
1632
+ this._processing = wasProcessing;
1633
+ throw err;
1634
+ }
1635
+ } else {
1636
+ this.mirrorProcessingCleared();
1594
1637
  }
1595
1638
  if (!value && this.idleWaiters.size > 0) {
1596
- // Notify only after the persisted write above committed a thrown
1597
- // write reverts the in-memory flag and re-throws, so waiters must not
1598
- // observe a release that never happened. Copy-and-clear so a waiter
1639
+ // The in-memory flag is the release, so waiters are notified on it
1640
+ // rather than on the advisory mirror write. Copy-and-clear so a waiter
1599
1641
  // registered from inside a notification can't be re-entered.
1600
1642
  const waiters = [...this.idleWaiters];
1601
1643
  this.idleWaiters.clear();
@@ -1610,6 +1652,37 @@ export class Conversation {
1610
1652
  }
1611
1653
  }
1612
1654
 
1655
+ /**
1656
+ * Mirror a released processing lock into the advisory `processing_started_at`
1657
+ * column, without ever reporting failure back to the release.
1658
+ *
1659
+ * `withSqliteRetry` runs its first attempt synchronously, so the common case
1660
+ * is the same single write the acquire direction performs; only a contended
1661
+ * write falls back to the backoff retries, which run detached. The retry
1662
+ * re-checks the in-memory flag because a new turn may have acquired the lock
1663
+ * (and written its own timestamp) while the backoff slept, and a late clear
1664
+ * would then blank a column that describes a live turn.
1665
+ */
1666
+ private mirrorProcessingCleared(): void {
1667
+ void withSqliteRetry(
1668
+ () => {
1669
+ if (this._processing) {
1670
+ return;
1671
+ }
1672
+ setConversationProcessingStartedAt(this.conversationId, null);
1673
+ },
1674
+ {
1675
+ op: "conversation:clearProcessing",
1676
+ context: { conversationId: this.conversationId },
1677
+ },
1678
+ ).catch((err: unknown) => {
1679
+ log.error(
1680
+ { err, conversationId: this.conversationId },
1681
+ "Failed to clear the persisted processing marker; the conversation is released in memory and the boot-time stale-processing sweep recovers the column",
1682
+ );
1683
+ });
1684
+ }
1685
+
1613
1686
  /**
1614
1687
  * Wait until this conversation's processing lock releases.
1615
1688
  *
@@ -1746,8 +1819,13 @@ export class Conversation {
1746
1819
  return this.queue.snapshot();
1747
1820
  }
1748
1821
 
1749
- removeQueuedMessage(requestId: string): boolean {
1750
- return this.queue.removeByRequestId(requestId) !== undefined;
1822
+ /**
1823
+ * Drop a queued message by request id. Returns the removed entry so callers
1824
+ * can pair a cancellation event with the same visibility metadata the
1825
+ * enqueue ack used, or `undefined` when nothing matched.
1826
+ */
1827
+ removeQueuedMessage(requestId: string): QueuedMessage | undefined {
1828
+ return this.queue.removeByRequestId(requestId);
1751
1829
  }
1752
1830
 
1753
1831
  canHandoffAtCheckpoint(): boolean {
@@ -2583,6 +2661,12 @@ export class Conversation {
2583
2661
  * forwarded into {@link runAgentLoopImpl} and threaded to `recordUsage`.
2584
2662
  */
2585
2663
  cronRunId?: string | null;
2664
+ /**
2665
+ * See {@link runAgentLoopImpl}: trust this turn runs under. Queue
2666
+ * drains pass the sender's trust captured at enqueue so the run is not
2667
+ * reset to the conversation's most recent actor.
2668
+ */
2669
+ turnTrustContext?: TrustContext;
2586
2670
  },
2587
2671
  ): Promise<void> {
2588
2672
  const { onEvent, ...rest } = options ?? {};
@@ -16,10 +16,10 @@ const log = getLogger("disk-pressure-guard-lifecycle");
16
16
 
17
17
  let diskPressureStartupSampleTimer: ReturnType<typeof setTimeout> | null = null;
18
18
 
19
- function runDeferredDiskPressureStartupSample(): void {
19
+ async function runDeferredDiskPressureStartupSample(): Promise<void> {
20
20
  diskPressureStartupSampleTimer = null;
21
21
  try {
22
- const status = evaluateDiskPressureNow();
22
+ const status = await evaluateDiskPressureNow();
23
23
  if (status.error) {
24
24
  log.warn(
25
25
  { error: status.error },