@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
@@ -26,6 +26,7 @@ import {
26
26
  addMessage,
27
27
  isEchoSuppressedUserMessage,
28
28
  isHiddenMessageMetadata,
29
+ isSuppressedQueuedMessage,
29
30
  provenanceFromTrustContext,
30
31
  recordConversationPersistedSeq,
31
32
  setConversationOriginChannelIfUnset,
@@ -61,6 +62,7 @@ import { getModelInfo } from "./handlers/config-model.js";
61
62
  import { preactivateHostProxySkills } from "./host-proxy-preactivation.js";
62
63
  import type { UserMessageAttachment } from "./message-protocol.js";
63
64
  import { buildTransportHints } from "./transport-hints.js";
65
+ import { sameTrustIdentity, type TrustContext } from "./trust-context-types.js";
64
66
  import { resolveVerificationSessionIntent } from "./verification-session-intent.js";
65
67
 
66
68
  const log = getLogger("conversation-process");
@@ -285,9 +287,9 @@ async function buildPassthroughBatch(
285
287
  break;
286
288
  }
287
289
  // The batched turn applies only the head's `clientOs`, so messages from a
288
- // different OS surface must not coalesce. The web, iOS, and macOS apps all
290
+ // different OS surface must not coalesce. Browser, mobile, and desktop apps
289
291
  // report `interfaceId: "web"`, so the interface check above no longer
290
- // separates them split on the reported OS explicitly.
292
+ // separates them, so split on the reported OS explicitly.
291
293
  if (candidate.transport?.clientOs !== head.transport?.clientOs) {
292
294
  break;
293
295
  }
@@ -300,6 +302,13 @@ async function buildPassthroughBatch(
300
302
  if (candidate.sourceActorPrincipalId !== head.sourceActorPrincipalId) {
301
303
  break;
302
304
  }
305
+ // Channel senders carry no principal, so the check above leaves two
306
+ // different Slack contacts looking identical (`undefined === undefined`).
307
+ // The batch runs under a single trust context, so split on the sender's
308
+ // trust identity too or a tail executes with the head's privileges.
309
+ if (!sameTrustIdentity(candidate.trustContext, head.trustContext)) {
310
+ break;
311
+ }
303
312
  if (classifySlash(candidate.content) !== "passthrough") {
304
313
  break;
305
314
  }
@@ -324,10 +333,11 @@ async function buildPassthroughBatch(
324
333
  return conversation.queue.shiftN(matched);
325
334
  }
326
335
 
327
- // ── Steer repair ────────────────────────────────────────────────────
336
+ // ── Steer / interrupt repair ────────────────────────────────────────
328
337
 
329
338
  /**
330
- * When a steer-to-message abort interrupts an in-flight tool call, the
339
+ * When a steer-to-message abort (or a user interrupt with messages still
340
+ * queued behind the stopped turn) cuts off an in-flight tool call, the
331
341
  * conversation history may end with an assistant message containing one
332
342
  * or more `tool_use` blocks that have no corresponding `tool_result`.
333
343
  * LLM providers reject this sequence. This helper scans the tail of the
@@ -335,10 +345,12 @@ async function buildPassthroughBatch(
335
345
  * unmatched `tool_use` blocks.
336
346
  */
337
347
  function repairPendingToolUseBlocks(conversation: Conversation): void {
338
- if (!conversation.pendingSteerRepair) {
348
+ const steered = conversation.pendingSteerRepair;
349
+ if (!steered && !conversation.pendingInterruptRepair) {
339
350
  return;
340
351
  }
341
352
  conversation.pendingSteerRepair = false;
353
+ conversation.pendingInterruptRepair = false;
342
354
 
343
355
  const messages = conversation.messages;
344
356
  if (messages.length === 0) {
@@ -381,15 +393,18 @@ function repairPendingToolUseBlocks(conversation: Conversation): void {
381
393
  {
382
394
  conversationId: conversation.conversationId,
383
395
  pendingToolUseCount: pendingToolUseIds.length,
396
+ trigger: steered ? "steer" : "interrupt",
384
397
  },
385
- "Injecting synthetic tool_result for pending tool_use blocks after steer",
398
+ "Injecting synthetic tool_result for pending tool_use blocks",
386
399
  );
387
400
 
388
401
  // Build a single user message with tool_result blocks for all pending IDs.
389
402
  const syntheticContent = pendingToolUseIds.map((toolUseId) => ({
390
403
  type: "tool_result" as const,
391
404
  tool_use_id: toolUseId,
392
- content: "Tool execution was interrupted by user steering.",
405
+ content: steered
406
+ ? "Tool execution was interrupted by user steering."
407
+ : "Tool execution was interrupted by the user.",
393
408
  is_error: true,
394
409
  }));
395
410
  conversation.messages.push({
@@ -405,11 +420,23 @@ function repairPendingToolUseBlocks(conversation: Conversation): void {
405
420
  * we did. The flag is what makes the requeue paths able to distinguish a
406
421
  * message clients still believe is running from one they never stopped
407
422
  * showing as queued. See {@link requeueDrainedMessages}.
423
+ *
424
+ * Queue events come in pairs. A row with no client-visible queued counterpart
425
+ * ({@link isSuppressedQueuedMessage} — hidden sends and the daemon-injected
426
+ * subagent/ACP/wake notifications) never produced a `message_queued` ack, so
427
+ * releasing one produces no dequeue either: an unpaired dequeue would retire a
428
+ * client's counter entry for a message that is still waiting. Nothing was
429
+ * announced, so the flag stays false and the requeue paths correctly send
430
+ * nothing for it. The activity-state transition callers emit alongside this is
431
+ * unrelated to the queue and always fires: the turn really is starting.
408
432
  */
409
433
  function announceDequeue(
410
434
  conversation: Conversation,
411
435
  message: QueuedMessage,
412
436
  ): void {
437
+ if (isSuppressedQueuedMessage(message.metadata)) {
438
+ return;
439
+ }
413
440
  message.onEvent({
414
441
  type: "message_dequeued",
415
442
  conversationId: conversation.conversationId,
@@ -434,7 +461,7 @@ function visibleQueuePosition(
434
461
  ): number | undefined {
435
462
  let position = 0;
436
463
  for (const item of conversation.queue.snapshot()) {
437
- if (isHiddenMessageMetadata(item.metadata)) {
464
+ if (isSuppressedQueuedMessage(item.metadata)) {
438
465
  continue;
439
466
  }
440
467
  position += 1;
@@ -460,8 +487,10 @@ function visibleQueuePosition(
460
487
  * `message_dequeued` and would otherwise see the row vanish until a later
461
488
  * drain. Messages requeued before the announcement (the pre-flight
462
489
  * processing-lock checks) get nothing, because clients never stopped showing
463
- * them as queued and an event there would be noise. Hidden sends are suppressed
464
- * for the same reason they get no queued ack: they have no client row.
490
+ * them as queued and an event there would be noise. Rows with no client-visible
491
+ * queued counterpart ({@link isSuppressedQueuedMessage} hidden sends and
492
+ * daemon-injected subagent/ACP/wake notifications) are suppressed for the same
493
+ * reason they get no queued ack: they have no client row.
465
494
  */
466
495
  function requeueDrainedMessages(
467
496
  conversation: Conversation,
@@ -488,7 +517,7 @@ function requeueDrainedMessages(
488
517
  continue;
489
518
  }
490
519
  message.dequeueAnnounced = false;
491
- if (isHiddenMessageMetadata(message.metadata)) {
520
+ if (isSuppressedQueuedMessage(message.metadata)) {
492
521
  continue;
493
522
  }
494
523
  const position = visibleQueuePosition(conversation, message.requestId);
@@ -653,7 +682,15 @@ export async function kickQueueDrain(
653
682
  },
654
683
  "drainQueue retry rejected; queued messages remain stranded until the next drain trigger",
655
684
  );
656
- for (const queued of conversation.queue.snapshot()) {
685
+ // Only the sends a user is waiting on get the failure notice. A stranded
686
+ // row with no client-visible queued counterpart (hidden machine signal,
687
+ // daemon-injected subagent/ACP/wake notification) has no queued bubble to
688
+ // explain, so a "your queued message" error would describe something the
689
+ // user never sent.
690
+ const strandedVisible = conversation.queue
691
+ .snapshot()
692
+ .filter((queued) => !isSuppressedQueuedMessage(queued.metadata));
693
+ for (const queued of strandedVisible) {
657
694
  queued.onEvent({
658
695
  type: "error",
659
696
  conversationId: conversation.conversationId,
@@ -766,7 +803,11 @@ async function drainSingleMessage(
766
803
 
767
804
  // Snapshot persona context at turn start so later tool turns can't pick up
768
805
  // a different actor's context if a concurrent request mutates the live fields.
769
- conversation.currentTurnTrustContext = conversation.trustContext;
806
+ // Trust comes from the queued message, not the live slot: the slot holds
807
+ // whichever actor sent most recently, which is this sender only when nobody
808
+ // else sent while this message waited.
809
+ conversation.currentTurnTrustContext =
810
+ next.trustContext ?? conversation.trustContext;
770
811
  conversation.currentTurnChannelCapabilities =
771
812
  conversation.channelCapabilities;
772
813
 
@@ -813,7 +854,10 @@ async function drainSingleMessage(
813
854
  : {}),
814
855
  sentAt: next.sentAt,
815
856
  };
816
- const cleanUserMsg = createUserMessage(next.content, next.attachments);
857
+ const cleanUserMsg = await createUserMessage(
858
+ next.content,
859
+ next.attachments,
860
+ );
817
861
  const llmUserMsg = enrichMessageWithSourcePaths(
818
862
  cleanUserMsg,
819
863
  next.attachments,
@@ -821,7 +865,7 @@ async function drainSingleMessage(
821
865
  // When displayContent is provided (e.g. original text before recording
822
866
  // intent stripping), persist that to DB so users see the full message.
823
867
  // The in-memory userMessage (sent to the LLM) still uses the stripped content.
824
- const contentToPersist = serializePersistedUserMessageContent(
868
+ const contentToPersist = await serializePersistedUserMessageContent(
825
869
  next.content,
826
870
  next.displayContent,
827
871
  next.attachments,
@@ -913,11 +957,14 @@ async function drainSingleMessage(
913
957
  : {}),
914
958
  sentAt: next.sentAt,
915
959
  };
916
- const cleanUserMsg = createUserMessage(next.content, next.attachments);
960
+ const cleanUserMsg = await createUserMessage(
961
+ next.content,
962
+ next.attachments,
963
+ );
917
964
  await addMessage(
918
965
  conversation.conversationId,
919
966
  "user",
920
- serializePersistedUserMessageContent(
967
+ await serializePersistedUserMessageContent(
921
968
  next.content,
922
969
  next.displayContent,
923
970
  next.attachments,
@@ -1003,11 +1050,14 @@ async function drainSingleMessage(
1003
1050
  : {}),
1004
1051
  sentAt: next.sentAt,
1005
1052
  };
1006
- const cleanUserMsg = createUserMessage(next.content, next.attachments);
1053
+ const cleanUserMsg = await createUserMessage(
1054
+ next.content,
1055
+ next.attachments,
1056
+ );
1007
1057
  await addMessage(
1008
1058
  conversation.conversationId,
1009
1059
  "user",
1010
- serializePersistedUserMessageContent(
1060
+ await serializePersistedUserMessageContent(
1011
1061
  next.content,
1012
1062
  next.displayContent,
1013
1063
  next.attachments,
@@ -1097,6 +1147,12 @@ async function drainSingleMessage(
1097
1147
  metadata: { ...next.metadata, sentAt: next.sentAt },
1098
1148
  displayContent: next.displayContent,
1099
1149
  clientMessageId: next.clientMessageId,
1150
+ // Attribute the stored row to the sender this turn runs as, not to
1151
+ // whoever happens to occupy the conversation slot at drain time.
1152
+ trustContext: next.trustContext,
1153
+ ...(next.transport?.clientOs
1154
+ ? { requestClientOs: next.transport.clientOs }
1155
+ : {}),
1100
1156
  });
1101
1157
  } catch (err) {
1102
1158
  const message = err instanceof Error ? err.message : String(err);
@@ -1217,7 +1273,14 @@ async function drainSingleMessage(
1217
1273
  isUserMessage?: boolean;
1218
1274
  titleText?: string;
1219
1275
  isHiddenPrompt?: boolean;
1220
- } = { isUserMessage: true };
1276
+ turnTrustContext?: TrustContext;
1277
+ } = {
1278
+ isUserMessage: true,
1279
+ // Carry the sender's trust into the run. The loop re-initializes the
1280
+ // per-turn snapshot on entry, so without this the stamp above is undone
1281
+ // and the turn reverts to the conversation's most recent actor.
1282
+ turnTrustContext: conversation.currentTurnTrustContext,
1283
+ };
1221
1284
  if (next.isInteractive !== undefined) {
1222
1285
  drainLoopOptions.isInteractive = next.isInteractive;
1223
1286
  }
@@ -1342,7 +1405,12 @@ async function drainBatch(
1342
1405
 
1343
1406
  // Snapshot persona context at turn start so later tool turns can't pick up
1344
1407
  // a different actor's context if a concurrent request mutates the live fields.
1345
- conversation.currentTurnTrustContext = conversation.trustContext;
1408
+ // The head's trust governs the batch, which is sound only because
1409
+ // `buildPassthroughBatch` refuses to coalesce messages from different
1410
+ // actors; without that boundary this would run a tail under the head's
1411
+ // trust.
1412
+ conversation.currentTurnTrustContext =
1413
+ head.trustContext ?? conversation.trustContext;
1346
1414
  conversation.currentTurnChannelCapabilities =
1347
1415
  conversation.channelCapabilities;
1348
1416
 
@@ -1447,6 +1515,12 @@ async function drainBatch(
1447
1515
  metadata: { ...qm.metadata, sentAt: qm.sentAt },
1448
1516
  displayContent: qm.displayContent,
1449
1517
  clientMessageId: qm.clientMessageId,
1518
+ // Same attribution rule as the single-message drain. Batch members
1519
+ // share one sender, so every row here names that sender.
1520
+ trustContext: qm.trustContext,
1521
+ ...(qm.transport?.clientOs
1522
+ ? { requestClientOs: qm.transport.clientOs }
1523
+ : {}),
1450
1524
  };
1451
1525
  if (i === 0) {
1452
1526
  batchPersistResult =
@@ -1675,8 +1749,12 @@ async function drainBatch(
1675
1749
  titleText?: string;
1676
1750
  isHiddenPrompt?: boolean;
1677
1751
  notifyUserMessageId?: string;
1752
+ turnTrustContext?: TrustContext;
1678
1753
  } = {
1679
1754
  isUserMessage: true,
1755
+ // Same reason as the single-message drain: the loop re-initializes the
1756
+ // per-turn snapshot, so the head's trust has to travel with the call.
1757
+ turnTrustContext: conversation.currentTurnTrustContext,
1680
1758
  };
1681
1759
  if (lastPushEligibleUserMessageId !== undefined) {
1682
1760
  drainLoopOptions.notifyUserMessageId = lastPushEligibleUserMessageId;
@@ -1798,7 +1876,14 @@ export async function processMessage(
1798
1876
  await conversation.ensureActorScopedHistory();
1799
1877
  // Snapshot persona context at turn start so later tool turns can't pick up
1800
1878
  // a different actor's context if a concurrent request mutates the live fields.
1801
- conversation.currentTurnTrustContext = conversation.trustContext;
1879
+ //
1880
+ // Held in a local as well as on the conversation: the field is writable
1881
+ // out-of-band while this turn is in flight (`agent-wake` stamps it and
1882
+ // restores the prior value in a `finally`), so reading it back at the agent
1883
+ // loop call below would reintroduce the late read this capture exists to
1884
+ // avoid. The local is what the loop runs under.
1885
+ const turnTrustContext = conversation.trustContext;
1886
+ conversation.currentTurnTrustContext = turnTrustContext;
1802
1887
  conversation.currentTurnAuthContext = conversation.authContext;
1803
1888
  conversation.currentTurnSourceActorPrincipalId =
1804
1889
  sourceActorPrincipalId ?? conversation.authContext?.actorPrincipalId;
@@ -1873,7 +1958,7 @@ export async function processMessage(
1873
1958
  : {}),
1874
1959
  };
1875
1960
 
1876
- const cleanUserMsg = createUserMessage(content, attachments);
1961
+ const cleanUserMsg = await createUserMessage(content, attachments);
1877
1962
  const llmUserMsg = enrichMessageWithSourcePaths(
1878
1963
  cleanUserMsg,
1879
1964
  attachments,
@@ -1881,7 +1966,7 @@ export async function processMessage(
1881
1966
  const persisted = await addMessage(
1882
1967
  conversation.conversationId,
1883
1968
  "user",
1884
- serializePersistedUserMessageContent(
1969
+ await serializePersistedUserMessageContent(
1885
1970
  content,
1886
1971
  displayContent,
1887
1972
  attachments,
@@ -1965,12 +2050,12 @@ export async function processMessage(
1965
2050
  ? { imageSourcePaths: pmImageSourcePaths }
1966
2051
  : {}),
1967
2052
  };
1968
- const cleanUserMsg = createUserMessage(content, attachments);
2053
+ const cleanUserMsg = await createUserMessage(content, attachments);
1969
2054
  const llmUserMsg = enrichMessageWithSourcePaths(cleanUserMsg, attachments);
1970
2055
  // When displayContent is provided (e.g. original text before recording
1971
2056
  // intent stripping), persist that to DB so users see the full message.
1972
2057
  // The in-memory userMessage (sent to the LLM) still uses the stripped content.
1973
- const contentToPersist = serializePersistedUserMessageContent(
2058
+ const contentToPersist = await serializePersistedUserMessageContent(
1974
2059
  content,
1975
2060
  displayContent,
1976
2061
  attachments,
@@ -2049,11 +2134,11 @@ export async function processMessage(
2049
2134
  }
2050
2135
  : {}),
2051
2136
  };
2052
- const cleanUserMsg = createUserMessage(content, attachments);
2137
+ const cleanUserMsg = await createUserMessage(content, attachments);
2053
2138
  const persisted = await addMessage(
2054
2139
  conversation.conversationId,
2055
2140
  "user",
2056
- serializePersistedUserMessageContent(
2141
+ await serializePersistedUserMessageContent(
2057
2142
  content,
2058
2143
  displayContent,
2059
2144
  attachments,
@@ -2097,7 +2182,10 @@ export async function processMessage(
2097
2182
  throw err;
2098
2183
  } finally {
2099
2184
  conversation.setProcessing(false);
2100
- await drainQueue(conversation);
2185
+ // `kickQueueDrain` never rejects, so a failed drain in this `finally`
2186
+ // cannot mask the error the try block is unwinding, and its retry plus
2187
+ // sender notification replace a silently stranded queue.
2188
+ await kickQueueDrain(conversation, "loop_complete", "compact_command");
2101
2189
  }
2102
2190
  }
2103
2191
 
@@ -2127,11 +2215,11 @@ export async function processMessage(
2127
2215
  }
2128
2216
  : {}),
2129
2217
  };
2130
- const cleanUserMsg = createUserMessage(content, attachments);
2218
+ const cleanUserMsg = await createUserMessage(content, attachments);
2131
2219
  const persisted = await addMessage(
2132
2220
  conversation.conversationId,
2133
2221
  "user",
2134
- serializePersistedUserMessageContent(
2222
+ await serializePersistedUserMessageContent(
2135
2223
  content,
2136
2224
  displayContent,
2137
2225
  attachments,
@@ -2171,7 +2259,8 @@ export async function processMessage(
2171
2259
  throw err;
2172
2260
  } finally {
2173
2261
  conversation.setProcessing(false);
2174
- await drainQueue(conversation);
2262
+ // Same never-rejecting drain as the `/compact` branch above.
2263
+ await kickQueueDrain(conversation, "loop_complete", "clean_command");
2175
2264
  }
2176
2265
  }
2177
2266
 
@@ -2263,7 +2352,16 @@ export async function processMessage(
2263
2352
  titleText?: string;
2264
2353
  callSite?: LLMCallSite;
2265
2354
  overrideProfile?: string;
2266
- } = { isUserMessage: true };
2355
+ turnTrustContext?: TrustContext;
2356
+ } = {
2357
+ isUserMessage: true,
2358
+ // Carry the trust captured at turn start into the run. Several awaits sit
2359
+ // between that capture and the loop opening, and both the conversation
2360
+ // slot and the per-turn field are writable throughout that window, so
2361
+ // reading either here would run this turn as whoever wrote last. The
2362
+ // local captured at turn start is the only value no other writer can move.
2363
+ turnTrustContext,
2364
+ };
2267
2365
  if (isInteractive !== undefined) {
2268
2366
  loopOptions.isInteractive = isInteractive;
2269
2367
  }
@@ -14,6 +14,7 @@ import type { AuthContext } from "../runtime/auth/types.js";
14
14
  import { getLogger } from "../util/logger.js";
15
15
  import type { UserMessageAttachment } from "./message-protocol.js";
16
16
  import type { ConversationTransportMetadata } from "./message-types/conversations.js";
17
+ import type { TrustContext } from "./trust-context-types.js";
17
18
 
18
19
  const log = getLogger("conversation-queue");
19
20
 
@@ -33,6 +34,15 @@ export interface QueuedMessage {
33
34
  sourceActorPrincipalId?: string;
34
35
  /** Full auth snapshot captured at enqueue time for turn-scoped authorization decisions. */
35
36
  authContext?: AuthContext;
37
+ /**
38
+ * Sender's trust captured at enqueue time. The conversation-level
39
+ * `trustContext` is a single mutable slot holding whichever actor last sent
40
+ * a message, so a drain that read it would run this message under a
41
+ * different actor's trust whenever another actor sent in between. Trust
42
+ * governs `trustClass`, `executionChannel`, and `requesterExternalUserId`,
43
+ * so reading the wrong one misroutes the whole tool-approval path.
44
+ */
45
+ trustContext?: TrustContext;
36
46
  /** Transport metadata snapshot captured at enqueue time, applied when this message becomes active. */
37
47
  transport?: ConversationTransportMetadata;
38
48
  /** Original user message text to persist to DB when recording intent stripping produced a different `content`. */
@@ -451,12 +451,18 @@ export function buildActiveDocuments(conversationId: string): Array<{
451
451
  * the readable handle is its `slug` (the directory stem, frozen at creation).
452
452
  * The app tools key off the id, so the line carries it for tool calls and the
453
453
  * slug for everything a human or the model would recognize.
454
+ *
455
+ * The resolved directory is not part of the returned shape. A workspace app's
456
+ * files are reachable by joining the workspace `Root:` from the `<workspace>`
457
+ * block with the app-builder skill's `data/apps/<slug>/` layout and the slug
458
+ * above. A plugin-bundled app's files sit outside that layout and belong to
459
+ * the plugin, which the provenance clause marks as not the assistant's to
460
+ * rewrite, so no path is offered for them either.
454
461
  */
455
462
  export function buildVisibleAppContext(appId: string | undefined): {
456
463
  appId: string;
457
464
  name: string;
458
465
  slug: string;
459
- sourceDir: string;
460
466
  pluginName?: string;
461
467
  } | null {
462
468
  if (!appId) {
@@ -471,7 +477,6 @@ export function buildVisibleAppContext(appId: string | undefined): {
471
477
  appId: source.id,
472
478
  name: source.name,
473
479
  slug: source.dirName,
474
- sourceDir: source.sourceDir,
475
480
  ...(source.origin.kind === "plugin"
476
481
  ? { pluginName: source.origin.pluginName }
477
482
  : {}),
@@ -2239,10 +2244,10 @@ export async function applyRuntimeInjections(
2239
2244
  : undefined;
2240
2245
  // OS surface reported by the client, independent of the transport interface
2241
2246
  // above. Drives the per-turn `client_os:` line so the model knows whether it
2242
- // is talking to the web, iOS, or macOS app (all sharing the `"web"`
2247
+ // is talking to a browser, mobile, or desktop app (all sharing the `"web"`
2243
2248
  // transport interface). Read the frozen per-turn snapshot (not the live
2244
2249
  // `clientOs`) so a queued message from another surface can't perturb the
2245
- // in-flight turn same anti-race pattern as `clientTimezone`.
2250
+ // in-flight turn, using the same anti-race pattern as `clientTimezone`.
2246
2251
  const clientOs = liveConversation?.currentTurnClientOs ?? undefined;
2247
2252
  // The app the client has on screen (app viewer or the app-editing split),
2248
2253
  // resolved to its name and source directory so the assistant can act on it
@@ -19,6 +19,7 @@ import {
19
19
  ensureConversationExists,
20
20
  getConversation,
21
21
  } from "../persistence/conversation-crud.js";
22
+ import type { ConversationOrigin } from "../persistence/conversation-types.js";
22
23
  import { wrapWithCallSiteRouting } from "../providers/call-site-routing.js";
23
24
  import {
24
25
  mainAgentResolutionError,
@@ -51,6 +52,37 @@ import { buildTransportHints } from "./transport-hints.js";
51
52
 
52
53
  const conversationOptions = new Map<string, ConversationCreateOptions>();
53
54
 
55
+ /**
56
+ * The channel a conversation created here belongs to.
57
+ *
58
+ * A trust context is stamped per inbound message from the gateway verdict,
59
+ * so `sourceChannel` names the channel the message creating this
60
+ * conversation actually arrived on. This is the moment that fact is known,
61
+ * and the caller is the only party that holds it.
62
+ *
63
+ * Returns `undefined` when there is no trust context, which does NOT mean
64
+ * native. `handleSendMessage` materializes a conversation before the route
65
+ * resolves trust, so a Slack or phone send reaches here with no
66
+ * `sourceChannel` yet. Assuming native there would stamp a remote
67
+ * conversation as the guardian's own, and nothing could repair it:
68
+ * `setConversationOriginChannelIfUnset` only writes over NULL, and
69
+ * `recoverRestingTrustContext` grants INTERNAL_GUARDIAN_TRUST_CONTEXT to the
70
+ * native channel on every later wake and boot-resume.
71
+ *
72
+ * `transport.channelId` is not a substitute. It is the external Slack
73
+ * conversation id, not a {@link ChannelId}.
74
+ *
75
+ * So this states the origin only where it is genuinely known, and leaves the
76
+ * rest to attribution exactly as before. The remaining callers get their
77
+ * origin when they are migrated with real knowledge of it, not by guessing
78
+ * here.
79
+ */
80
+ function originFromStoredOptions(
81
+ storedOptions: ConversationCreateOptions | undefined,
82
+ ): ConversationOrigin | undefined {
83
+ return storedOptions?.trustContext?.sourceChannel;
84
+ }
85
+
54
86
  /**
55
87
  * Drops the transport fields that describe what the client had on screen for a
56
88
  * single message rather than for the conversation as a whole.
@@ -141,9 +173,17 @@ export async function getOrCreateConversation(
141
173
  );
142
174
  }
143
175
 
176
+ // A stale conversation is rebuilt only once it is genuinely idle. Queued
177
+ // messages live in memory on the instance being disposed, and the queue
178
+ // drains via an async dispatch after the current turn releases, so
179
+ // `isProcessing()` can read false while a queued turn is still pending:
180
+ // rebuilding in that gap would silently drop those messages. The conversation
181
+ // stays stale and is rebuilt on a later call.
144
182
  if (
145
183
  !conversation ||
146
- (conversation.isStale() && !conversation.isProcessing())
184
+ (conversation.isStale() &&
185
+ !conversation.isProcessing() &&
186
+ !conversation.hasQueuedMessages())
147
187
  ) {
148
188
  if (conversation) {
149
189
  // Stale rebuild: the conversation id lives on, so abort in-flight
@@ -229,9 +269,13 @@ export async function getOrCreateConversation(
229
269
  createConversation({
230
270
  id: conversationId,
231
271
  conversationType: storedOptions.conversationType,
272
+ origin: originFromStoredOptions(storedOptions),
232
273
  });
233
274
  } else {
234
- ensureConversationExists(conversationId);
275
+ ensureConversationExists(
276
+ conversationId,
277
+ originFromStoredOptions(storedOptions),
278
+ );
235
279
  }
236
280
  }
237
281
 
@@ -353,7 +397,12 @@ export function clearAllActiveConversations(): number {
353
397
  export function evictConversationsForReload(): void {
354
398
  const subagentManager = getSubagentManager();
355
399
  for (const [id, conversation] of conversationEntries()) {
356
- if (!conversation.isProcessing()) {
400
+ // A conversation with queued messages is not idle: the queue drains via an
401
+ // async dispatch after the current turn releases, so `isProcessing()` can
402
+ // read false while a queued turn is still pending. Disposing in that gap
403
+ // would silently drop the queued messages, so mark it stale instead and
404
+ // let it rebuild once the queue has run.
405
+ if (!conversation.isProcessing() && !conversation.hasQueuedMessages()) {
357
406
  subagentManager.abortAllForParent(id);
358
407
  conversation.dispose();
359
408
  deleteConversation(id);
@@ -76,6 +76,15 @@ export type CurrentTurnSurface = {
76
76
  * to the client.
77
77
  */
78
78
  activationMoment?: ActivationMomentParam;
79
+ /**
80
+ * Completion stamped when the user answers the surface before this turn's
81
+ * message lands. The snapshot is the only record of the surface at that
82
+ * point, so both persisted-content appenders carry these onto the
83
+ * `ui_surface` block they build; without them a reseed reactivates an
84
+ * already-answered card.
85
+ */
86
+ completed?: boolean;
87
+ completionSummary?: string;
79
88
  };
80
89
  }[SurfaceType];
81
90