@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
@@ -447,13 +447,20 @@ export function executeDocumentUpdate(
447
447
  };
448
448
  }
449
449
 
450
- // Fallback if no client is connected
450
+ // No client is connected to render the edit, but the write landed, so this is
451
+ // a success. Reporting it as an error would strand a headless turn (a
452
+ // schedule, SMS, or Telegram channel): post-execution hooks are skipped for
453
+ // errored tools, so the documents-changed broadcast that tells clients about
454
+ // the edit would never fire, and the model would be told to retry a write
455
+ // that already succeeded.
451
456
  return {
452
457
  content: JSON.stringify({
453
- success: false,
454
- error: "No client connected to update document",
458
+ success: true,
459
+ surface_id: surfaceId,
460
+ mode,
461
+ message: "Document content updated (no client connected to render it)",
455
462
  }),
456
- isError: true,
463
+ isError: false,
457
464
  };
458
465
  }
459
466
 
@@ -6,11 +6,18 @@ const TIMEOUT_SENTINEL = Symbol("tool-timeout");
6
6
  /**
7
7
  * Convert a config-provided seconds value to a safe milliseconds value,
8
8
  * falling back to the default if the input is NaN, non-finite, zero, or negative.
9
+ *
10
+ * `fallbackMs` lets callers governed by a different budget (e.g. the inline
11
+ * grant wait) keep their own floor instead of inheriting the tool-execution
12
+ * default.
9
13
  */
10
- export function safeTimeoutMs(sec: unknown): number {
14
+ export function safeTimeoutMs(
15
+ sec: unknown,
16
+ fallbackMs: number = DEFAULT_TOOL_EXECUTION_TIMEOUT_SEC * 1000,
17
+ ): number {
11
18
  const n = Number(sec);
12
19
  if (!Number.isFinite(n) || n <= 0) {
13
- return DEFAULT_TOOL_EXECUTION_TIMEOUT_SEC * 1000;
20
+ return fallbackMs;
14
21
  }
15
22
  return n * 1000;
16
23
  }
@@ -1,4 +1,4 @@
1
- import { readFileSync } from "node:fs";
1
+ import { readFile } from "node:fs/promises";
2
2
 
3
3
  import { getConfig } from "../config/loader.js";
4
4
  import { PermissionPrompter } from "../permissions/prompter.js";
@@ -484,18 +484,19 @@ export function computePerToolTimeoutMs(
484
484
  * confirmation payload — ahead of approval. Host file tools have no preview
485
485
  * for the same reason.
486
486
  */
487
- function computePreviewDiff(
487
+ async function computePreviewDiff(
488
488
  toolName: string,
489
489
  input: Record<string, unknown>,
490
490
  workingDir: string,
491
- ):
491
+ ): Promise<
492
492
  | {
493
493
  filePath: string;
494
494
  oldContent: string;
495
495
  newContent: string;
496
496
  isNewFile: boolean;
497
497
  }
498
- | undefined {
498
+ | undefined
499
+ > {
499
500
  try {
500
501
  if (toolName === "file_write") {
501
502
  // Parse with the tool's own schema so the preview reads the same shape
@@ -519,7 +520,7 @@ function computePreviewDiff(
519
520
  return undefined;
520
521
  }
521
522
  }
522
- const oldContent = isNewFile ? "" : readFileSync(filePath, "utf-8");
523
+ const oldContent = isNewFile ? "" : await readFile(filePath, "utf-8");
523
524
  return { filePath, oldContent, newContent: content, isNewFile };
524
525
  }
525
526
 
@@ -545,7 +546,7 @@ function computePreviewDiff(
545
546
  if (stat.size > MAX_FILE_SIZE_BYTES) {
546
547
  return undefined;
547
548
  }
548
- const content = readFileSync(filePath, "utf-8");
549
+ const content = await readFile(filePath, "utf-8");
549
550
  const replaceAll = parsed.data.replace_all === true;
550
551
  const result = applyEdit(content, oldString, newString, replaceAll);
551
552
  if (!result.ok) {
@@ -88,7 +88,7 @@ export const fileEditTool = {
88
88
  sandboxPolicyWithHostFallback(path, context.workingDir, opts),
89
89
  );
90
90
 
91
- const result = ops.editFileSafe({
91
+ const result = await ops.editFileSafe({
92
92
  path: rawPath,
93
93
  oldString,
94
94
  newString,
@@ -61,7 +61,7 @@ export const fileListTool = {
61
61
  sandboxPolicy(path, context.workingDir, opts),
62
62
  );
63
63
 
64
- const result = ops.listDirSafe({ path: rawPath, glob });
64
+ const result = await ops.listDirSafe({ path: rawPath, glob });
65
65
 
66
66
  if (!result.ok) {
67
67
  const { error } = result;
@@ -12,7 +12,7 @@ import {
12
12
  IMAGE_EXTENSIONS,
13
13
  readImageFile,
14
14
  } from "../shared/filesystem/image-read.js";
15
- import { sandboxPolicyWithHostFallback } from "../shared/filesystem/path-policy.js";
15
+ import { sandboxReadPolicy } from "../shared/filesystem/path-policy.js";
16
16
  import {
17
17
  invalidToolInputResult,
18
18
  toToolInputSchema,
@@ -43,7 +43,7 @@ export const fileReadInputSchema = z.looseObject({
43
43
  .catch(undefined),
44
44
  limit: z
45
45
  .number()
46
- .describe("Maximum number of lines to read")
46
+ .describe("Maximum number of lines to read (defaults to 2000)")
47
47
  .optional()
48
48
  .catch(undefined),
49
49
  activity: z
@@ -58,7 +58,7 @@ export const fileReadInputSchema = z.looseObject({
58
58
  export const fileReadTool = {
59
59
  name: "file_read",
60
60
  description:
61
- "Read the contents of a file on your own machine. For image files (JPEG, PNG, GIF, WebP), returns the image for visual analysis. For audio files (MP3, WAV, OGG, FLAC, AAC, M4A), returns the audio for listening. Use host_file_read for files on your guardian's device instead.",
61
+ "Read the contents of a file on your own machine. Text reads return the first 2000 lines unless you pass `limit`; when a read stops short the result says so, and `offset` pages on from there. For image files (JPEG, PNG, GIF, WebP), returns the image for visual analysis. For audio files (MP3, WAV, OGG, FLAC, AAC, M4A), returns the audio for listening. Use host_file_read for files on your guardian's device instead.",
62
62
  category: "filesystem",
63
63
  executionTarget: "sandbox",
64
64
  defaultRiskLevel: RiskLevel.Low,
@@ -80,10 +80,7 @@ export const fileReadTool = {
80
80
  // For image files, delegate to the shared image reader.
81
81
  const ext = extname(rawPath).toLowerCase();
82
82
  if (IMAGE_EXTENSIONS.has(ext)) {
83
- const pathCheck = sandboxPolicyWithHostFallback(
84
- rawPath,
85
- context.workingDir,
86
- );
83
+ const pathCheck = sandboxReadPolicy(rawPath, context.workingDir);
87
84
  if (!pathCheck.ok) {
88
85
  return {
89
86
  content: `Error: ${pathCheck.error}. To read files outside the workspace, use the host_file_read tool instead.`,
@@ -95,10 +92,7 @@ export const fileReadTool = {
95
92
 
96
93
  // For audio files, delegate to the shared audio reader.
97
94
  if (AUDIO_EXTENSIONS.has(ext)) {
98
- const pathCheck = sandboxPolicyWithHostFallback(
99
- rawPath,
100
- context.workingDir,
101
- );
95
+ const pathCheck = sandboxReadPolicy(rawPath, context.workingDir);
102
96
  if (!pathCheck.ok) {
103
97
  return {
104
98
  content: `Error: ${pathCheck.error}. To read files outside the workspace, use the host_file_read tool instead.`,
@@ -109,10 +103,10 @@ export const fileReadTool = {
109
103
  }
110
104
 
111
105
  const ops = new FileSystemOps((path, opts) =>
112
- sandboxPolicyWithHostFallback(path, context.workingDir, opts),
106
+ sandboxReadPolicy(path, context.workingDir, opts),
113
107
  );
114
108
 
115
- const result = ops.readFileSafe({ path: rawPath, offset, limit });
109
+ const result = await ops.readFileSafe({ path: rawPath, offset, limit });
116
110
 
117
111
  if (!result.ok) {
118
112
  const { error } = result;
@@ -1,4 +1,4 @@
1
- import { readdirSync, readFileSync, statSync } from "node:fs";
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
2
  import { basename, join, relative } from "node:path";
3
3
 
4
4
  import { minimatch } from "minimatch";
@@ -48,11 +48,10 @@ const MAX_DISPLAY_LINE_LENGTH = 2000;
48
48
  // report the result as truncated.
49
49
  const MAX_OUTPUT_BYTES = 4 * 1024 * 1024; // 4 MiB
50
50
 
51
- // Wall-clock deadline for the whole search. The synchronous scan never yields,
52
- // so the promise-based tool timeout / abort signal can't fire mid-scan. Checking
53
- // this deadline (and the abort signal) once per line bounds how long a search
54
- // over a very large tree can block the event loop and lets an external abort
55
- // stop the walk promptly.
51
+ // Wall-clock deadline for the whole search. File I/O yields between files,
52
+ // but the per-file line loop is CPU-bound; checking this deadline (and the
53
+ // abort signal) once per line bounds how long a search over a very large tree
54
+ // can occupy the event loop and lets an external abort stop the walk promptly.
56
55
  const MAX_SEARCH_MS = 10_000; // 10 s
57
56
 
58
57
  const DEFAULT_MAX_RESULTS = 200;
@@ -150,7 +149,7 @@ export const codeSearchTool = {
150
149
  // Match with the linear-time RE2 engine (via re2js) instead of V8's
151
150
  // backtracking RegExp. RE2 guarantees linear-time matching, so a
152
151
  // user/subagent-supplied pattern cannot trigger catastrophic backtracking
153
- // and block the synchronous scan. The trade-off is that RE2 rejects
152
+ // and pin the event loop inside the per-file line loop. The trade-off is that RE2 rejects
154
153
  // backreferences and lookarounds; compile() throws on those, surfaced as a
155
154
  // clean error below.
156
155
  let regex: RE2JS;
@@ -189,7 +188,7 @@ export const codeSearchTool = {
189
188
  // NOT_FOUND / NOT_A_DIRECTORY reporting in file_list.
190
189
  let rootStat: import("node:fs").Stats;
191
190
  try {
192
- rootStat = statSync(root);
191
+ rootStat = await stat(root);
193
192
  } catch {
194
193
  return {
195
194
  content: `Error: path not found: ${rawPath}`,
@@ -198,8 +197,8 @@ export const codeSearchTool = {
198
197
  }
199
198
 
200
199
  // Start the wall-clock deadline before walking so a pathological regex
201
- // (or an external abort) can stop the synchronous scan mid-flight instead
202
- // of blocking the event loop until the whole tree is exhausted.
200
+ // (or an external abort) can stop the scan mid-flight instead of running
201
+ // until the whole tree is exhausted.
203
202
  const searchStart = Date.now();
204
203
 
205
204
  const lines: string[] = [];
@@ -228,7 +227,7 @@ export const codeSearchTool = {
228
227
  let totalBytes = 0;
229
228
  // Number of directory entries visited during the walk (files + subdirs),
230
229
  // bounded by MAX_ENTRIES_TRAVERSED so a pathological tree can't run the
231
- // synchronous readdir/stat work unbounded even when no file is ever read.
230
+ // readdir/stat work unbounded even when no file is ever read.
232
231
  let entriesTraversed = 0;
233
232
  // Set when an EXPLICIT file root (not a child discovered mid-walk) can't be
234
233
  // read — e.g. EACCES/EPERM. A child file's read failure is optional and
@@ -264,7 +263,10 @@ export const codeSearchTool = {
264
263
 
265
264
  // Scan a single regular file for matches. Applies the denied-basename guard
266
265
  // and per-file size caps. Returns nothing; mutates the shared accumulators.
267
- const scanFile = (full: string, isExplicitRoot = false): void => {
266
+ const scanFile = async (
267
+ full: string,
268
+ isExplicitRoot = false,
269
+ ): Promise<void> => {
268
270
  if (truncated) {
269
271
  return;
270
272
  }
@@ -306,7 +308,7 @@ export const codeSearchTool = {
306
308
 
307
309
  let size: number;
308
310
  try {
309
- size = statSync(full).size;
311
+ size = (await stat(full)).size;
310
312
  } catch {
311
313
  return;
312
314
  }
@@ -323,7 +325,7 @@ export const codeSearchTool = {
323
325
 
324
326
  let buf: Buffer;
325
327
  try {
326
- buf = readFileSync(full);
328
+ buf = await readFile(full);
327
329
  } catch (err) {
328
330
  // A child file discovered mid-walk is optional — skip it silently. But
329
331
  // an explicit file root that can't be read was never searched, so record
@@ -407,13 +409,13 @@ export const codeSearchTool = {
407
409
  }
408
410
  };
409
411
 
410
- const walk = (dir: string, isExplicitRoot = false): void => {
412
+ const walk = async (dir: string, isExplicitRoot = false): Promise<void> => {
411
413
  if (truncated) {
412
414
  return;
413
415
  }
414
416
  // Bound the traversal itself, not just file reads: a deep/wide tree of
415
417
  // directories (or many entries that never get read) could otherwise run
416
- // the synchronous readdir/stat work far past the advertised deadline.
418
+ // the readdir/stat work far past the advertised deadline.
417
419
  if (Date.now() - searchStart > MAX_SEARCH_MS || context.signal?.aborted) {
418
420
  truncated = true;
419
421
  timedOut = true;
@@ -421,7 +423,7 @@ export const codeSearchTool = {
421
423
  }
422
424
  let entries: import("node:fs").Dirent[];
423
425
  try {
424
- entries = readdirSync(dir, { withFileTypes: true });
426
+ entries = await readdir(dir, { withFileTypes: true });
425
427
  } catch (err) {
426
428
  // A child directory discovered mid-walk is optional — skip it silently.
427
429
  // But an explicit directory root that can't be read (e.g. EACCES/EPERM)
@@ -458,18 +460,18 @@ export const codeSearchTool = {
458
460
  if (IGNORED_DIRS.has(entry.name)) {
459
461
  continue;
460
462
  }
461
- walk(full);
463
+ await walk(full);
462
464
  continue;
463
465
  }
464
466
  if (!entry.isFile()) {
465
467
  continue;
466
468
  }
467
- scanFile(full);
469
+ await scanFile(full);
468
470
  }
469
471
  };
470
472
 
471
473
  if (rootStat.isDirectory()) {
472
- walk(root, true);
474
+ await walk(root, true);
473
475
  // An explicit directory root that statSync sees but readdirSync can't read
474
476
  // (EACCES/EPERM) was never searched — surface a hard error instead of a
475
477
  // false "No matches found", mirroring the unreadable explicit-file root.
@@ -487,7 +489,7 @@ export const codeSearchTool = {
487
489
  isError: true,
488
490
  };
489
491
  }
490
- scanFile(root, true);
492
+ await scanFile(root, true);
491
493
  if (rootReadError) {
492
494
  return { content: rootReadError, isError: true };
493
495
  }
@@ -129,7 +129,10 @@ export const fileWriteTool = {
129
129
  sandboxPolicyWithHostFallback(path, context.workingDir, opts),
130
130
  );
131
131
 
132
- const result = ops.writeFileSafe({ path: rawPath, content: fileContent });
132
+ const result = await ops.writeFileSafe({
133
+ path: rawPath,
134
+ content: fileContent,
135
+ });
133
136
 
134
137
  if (!result.ok) {
135
138
  const { error } = result;
@@ -25,7 +25,12 @@ import type {
25
25
  * a non-string (or empty) value means "untargeted".
26
26
  */
27
27
  export const hostFileEditInputSchema = z.looseObject({
28
- path: z.string().min(1).describe("Absolute host path to the file to edit"),
28
+ path: z
29
+ .string()
30
+ .min(1)
31
+ .describe(
32
+ "Absolute path on the guardian's device, which is a separate filesystem from your workspace, to edit.",
33
+ ),
29
34
  old_string: z
30
35
  .string()
31
36
  .min(1, { message: "old_string must not be empty" })
@@ -158,7 +163,7 @@ export const hostFileEditTool = {
158
163
 
159
164
  const ops = new FileSystemOps(hostPolicy);
160
165
 
161
- const result = ops.editFileSafe({
166
+ const result = await ops.editFileSafe({
162
167
  path: rawPath,
163
168
  oldString,
164
169
  newString,
@@ -10,7 +10,10 @@ import {
10
10
  AUDIO_EXTENSIONS,
11
11
  readAudioFile,
12
12
  } from "../shared/filesystem/audio-read.js";
13
- import { FileSystemOps } from "../shared/filesystem/file-ops-service.js";
13
+ import {
14
+ DEFAULT_READ_LINE_LIMIT,
15
+ FileSystemOps,
16
+ } from "../shared/filesystem/file-ops-service.js";
14
17
  import {
15
18
  IMAGE_EXTENSIONS,
16
19
  readImageFile,
@@ -30,12 +33,17 @@ import type {
30
33
  * Model-input schema, the single source for both runtime validation (via
31
34
  * `TOOL_INPUT_SCHEMAS`) and the advertised `input_schema` below — mirrors
32
35
  * `filesystem/read.ts`. `offset`/`limit` catch to `undefined` so a
33
- * non-numeric value reads the whole file instead of failing the call;
34
- * `target_client_id` catches so a non-string (or empty) value means
36
+ * non-numeric value falls back to the default line window instead of failing
37
+ * the call; `target_client_id` catches so a non-string (or empty) value means
35
38
  * "untargeted".
36
39
  */
37
40
  export const hostFileReadInputSchema = z.looseObject({
38
- path: z.string().min(1).describe("Absolute path to the host file to read"),
41
+ path: z
42
+ .string()
43
+ .min(1)
44
+ .describe(
45
+ "Absolute path on the guardian's device, which is a separate filesystem from your workspace, to read.",
46
+ ),
39
47
  offset: z
40
48
  .number()
41
49
  .describe("Line number to start reading from (1-indexed)")
@@ -43,7 +51,7 @@ export const hostFileReadInputSchema = z.looseObject({
43
51
  .catch(undefined),
44
52
  limit: z
45
53
  .number()
46
- .describe("Maximum number of lines to read")
54
+ .describe("Maximum number of lines to read (defaults to 2000)")
47
55
  .optional()
48
56
  .catch(undefined),
49
57
  target_client_id: z
@@ -58,7 +66,7 @@ export const hostFileReadInputSchema = z.looseObject({
58
66
  export const hostFileReadTool = {
59
67
  name: "host_file_read",
60
68
  description:
61
- "Read the contents of a file on your guardian's device, including images (JPEG, PNG, GIF, WebP) and audio (MP3, WAV, OGG, FLAC, AAC, M4A). For files on your own machine, use file_read instead.",
69
+ "Read the contents of a file on your guardian's device, including images (JPEG, PNG, GIF, WebP) and audio (MP3, WAV, OGG, FLAC, AAC, M4A). Text reads return the first 2000 lines unless you pass `limit`; when a read stops short the result says so, and `offset` pages on from there. For files on your own machine, use file_read instead.",
62
70
  category: "host-filesystem",
63
71
  executionTarget: "host",
64
72
  defaultRiskLevel: RiskLevel.Medium,
@@ -73,7 +81,12 @@ export const hostFileReadTool = {
73
81
  if (!parsed.success) {
74
82
  return invalidToolInputResult("host_file_read", parsed.error);
75
83
  }
76
- const { path: rawPath, offset, limit } = parsed.data;
84
+ const { path: rawPath, offset } = parsed.data;
85
+ // Resolve the default here rather than leaving it to the read, so the
86
+ // proxied branch below is bounded by the same window as the local one. A
87
+ // proxied read that sent no limit would stream a whole host file across
88
+ // the bridge before anything could trim it.
89
+ const limit = parsed.data.limit ?? DEFAULT_READ_LINE_LIMIT;
77
90
 
78
91
  const targetClientId =
79
92
  parsed.data.target_client_id !== ""
@@ -170,7 +183,7 @@ export const hostFileReadTool = {
170
183
 
171
184
  const ops = new FileSystemOps(hostPolicy);
172
185
 
173
- const result = ops.readFileSafe({ path: rawPath, offset, limit });
186
+ const result = await ops.readFileSafe({ path: rawPath, offset, limit });
174
187
 
175
188
  if (!result.ok) {
176
189
  const { error } = result;
@@ -24,7 +24,12 @@ import type {
24
24
  * non-string (or empty) value means "untargeted".
25
25
  */
26
26
  export const hostFileWriteInputSchema = z.looseObject({
27
- path: z.string().min(1).describe("Absolute host path to the file to write"),
27
+ path: z
28
+ .string()
29
+ .min(1)
30
+ .describe(
31
+ "Absolute path on the guardian's device, which is a separate filesystem from your workspace, to write.",
32
+ ),
28
33
  content: z.string().describe("The content to write to the file"),
29
34
  target_client_id: z
30
35
  .string()
@@ -131,7 +136,10 @@ export const hostFileWriteTool = {
131
136
 
132
137
  const ops = new FileSystemOps(hostPolicy);
133
138
 
134
- const result = ops.writeFileSafe({ path: rawPath, content: fileContent });
139
+ const result = await ops.writeFileSafe({
140
+ path: rawPath,
141
+ content: fileContent,
142
+ });
135
143
 
136
144
  if (!result.ok) {
137
145
  const { error } = result;
@@ -121,7 +121,7 @@ export const hostShellInputSchema = z.looseObject({
121
121
  z
122
122
  .string()
123
123
  .describe(
124
- "Optional absolute host working directory (defaults to user home)",
124
+ "Optional absolute path on the host's filesystem, which is separate from your workspace (defaults to the host user's home).",
125
125
  ),
126
126
  ),
127
127
  timeout_seconds: z
@@ -150,7 +150,7 @@ export const hostShellInputSchema = z.looseObject({
150
150
  export const hostShellTool = {
151
151
  name: "host_bash",
152
152
  description:
153
- "LAST RESORT — Execute a shell command directly on the host machine. You MUST strongly prefer the regular `bash` tool for all commands. Only use `host_bash` when you are absolutely certain the command MUST run on the host machine and CANNOT run in the workspace (e.g., managing host-level system services, accessing host-only peripherals, or interacting with host paths outside the workspace). If in doubt, use `bash` instead. Approval-gated: each invocation must be explicitly approved. Do not use for commands that require injected credentials or secrets.",
153
+ "LAST RESORT — Execute a shell command directly on the host machine. You MUST strongly prefer the regular `bash` tool for all commands. Only use `host_bash` when you are absolutely certain the command MUST run on the host machine and CANNOT run in the workspace (e.g., managing host-level system services, accessing host-only peripherals, or interacting with host paths outside the workspace). If in doubt, use `bash` instead. Paths resolve on the host's filesystem, which is separate from your workspace; write output somewhere on the host and read it back with `host_file_read`. Approval-gated: each invocation must be explicitly approved. Do not use for commands that require injected credentials or secrets.",
154
154
  category: "host-terminal",
155
155
  executionTarget: "host",
156
156
  defaultRiskLevel: RiskLevel.Medium,
@@ -1,4 +1,5 @@
1
1
  import type { McpServerConfig } from "../../config/schemas/mcp.js";
2
+ import type { McpToolAnnotations } from "../../mcp/client.js";
2
3
  import type { McpServerManager } from "../../mcp/manager.js";
3
4
  import { RiskLevel } from "../../permissions/types.js";
4
5
  import { toProviderSafeToolName } from "../provider-tool-name.js";
@@ -23,6 +24,29 @@ export interface McpToolMetadata {
23
24
  name: string;
24
25
  description: string;
25
26
  inputSchema: Record<string, unknown>;
27
+ annotations?: McpToolAnnotations;
28
+ }
29
+
30
+ /**
31
+ * Resolve the risk level a tool carries.
32
+ *
33
+ * `readOnlyHint` is self-reported by the server, so it only refines risk
34
+ * downward and only for servers the user has already configured below the
35
+ * high-trust ceiling. Servers left at the default "high" are unaffected, and
36
+ * the hint never raises risk above the server default.
37
+ */
38
+ function resolveRiskLevel(
39
+ metadata: McpToolMetadata,
40
+ serverConfig: McpServerConfig,
41
+ ): RiskLevel {
42
+ const serverRisk = riskMap[serverConfig.defaultRiskLevel] ?? RiskLevel.High;
43
+ if (
44
+ metadata.annotations?.readOnlyHint === true &&
45
+ serverRisk !== RiskLevel.High
46
+ ) {
47
+ return RiskLevel.Low;
48
+ }
49
+ return serverRisk;
26
50
  }
27
51
 
28
52
  /**
@@ -36,7 +60,7 @@ export function createMcpTool(
36
60
  manager: McpServerManager,
37
61
  ): Tool {
38
62
  const namespacedName = mcpToolName(serverId, metadata.name);
39
- const riskLevel = riskMap[serverConfig.defaultRiskLevel] ?? RiskLevel.High;
63
+ const riskLevel = resolveRiskLevel(metadata, serverConfig);
40
64
  const serverDefinesActivity = schemaDefinesProperty(
41
65
  metadata.inputSchema,
42
66
  "activity",
@@ -104,14 +104,15 @@ export class PermissionChecker {
104
104
  toolName: string,
105
105
  input: Record<string, unknown>,
106
106
  workingDir: string,
107
- ) =>
107
+ ) => Promise<
108
108
  | {
109
109
  filePath: string;
110
110
  oldContent: string;
111
111
  newContent: string;
112
112
  isNewFile: boolean;
113
113
  }
114
- | undefined,
114
+ | undefined
115
+ >,
115
116
  ): Promise<PermissionDecision> {
116
117
  // Sandbox/host routing for the prompt comes from the tool's manifest.
117
118
  const executionTarget = resolveExecutionTarget(tool);
@@ -378,7 +379,11 @@ export class PermissionChecker {
378
379
  };
379
380
  }
380
381
 
381
- const previewDiff = computePreviewDiff(name, input, context.workingDir);
382
+ const previewDiff = await computePreviewDiff(
383
+ name,
384
+ input,
385
+ context.workingDir,
386
+ );
382
387
  const promptOptions = {
383
388
  allowlistOptions: await generateAllowlistOptions(
384
389
  name,
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
 
3
3
  import { deleteSchedule, getSchedule } from "../../schedule/schedule-store.js";
4
+ import { UserError } from "../../util/errors.js";
4
5
  import {
5
6
  invalidToolInputResult,
6
7
  nullAsOmitted,
@@ -35,7 +36,18 @@ export async function executeScheduleDelete(
35
36
  return { content: `Error: Schedule not found: ${jobId}`, isError: true };
36
37
  }
37
38
 
38
- const deleted = await deleteSchedule(jobId);
39
+ let deleted: boolean;
40
+ try {
41
+ deleted = await deleteSchedule(jobId);
42
+ } catch (err) {
43
+ // The store refuses to delete plugin-sourced rows with a UserError. That
44
+ // refusal is an expected outcome for the model to relay, not a daemon
45
+ // fault to classify as unexpected.
46
+ if (err instanceof UserError) {
47
+ return { content: `Error: ${err.message}`, isError: true };
48
+ }
49
+ throw err;
50
+ }
39
51
  if (!deleted) {
40
52
  return {
41
53
  content: `Error: Failed to delete schedule: ${jobId}`,
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
 
3
+ import { formatScheduleInferenceProfile } from "../../schedule/inference-profile.js";
3
4
  import { hasSetConstructs } from "../../schedule/recurrence-engine.js";
4
5
  import {
5
6
  describeCronExpression,
@@ -8,6 +9,7 @@ import {
8
9
  getScheduleRuns,
9
10
  listSchedules,
10
11
  } from "../../schedule/schedule-store.js";
12
+ import { describeScheduleSource } from "../../util/schedule-source-key.js";
11
13
  import {
12
14
  invalidToolInputResult,
13
15
  nullAsOmitted,
@@ -77,6 +79,13 @@ export async function executeScheduleList(
77
79
  ` Description: ${describeAuthoredPurpose(job)}`,
78
80
  ];
79
81
 
82
+ const detailPlugin = describeScheduleSource(job.sourceKey);
83
+ if (detailPlugin) {
84
+ lines.push(
85
+ ` Managed by plugin: ${detailPlugin} (definition read-only; only enabled can be changed)`,
86
+ );
87
+ }
88
+
80
89
  if (oneShot) {
81
90
  lines.push(` Fire at: ${formatLocalDate(job.nextRunAt)}`);
82
91
  } else {
@@ -93,7 +102,7 @@ export async function executeScheduleList(
93
102
  ` Enabled: ${job.enabled}`,
94
103
  ` Quiet: ${job.quiet}`,
95
104
  ` Reuse conversation: ${job.reuseConversation}`,
96
- ` Inference profile: ${job.inferenceProfile ?? "default (mainAgent)"}`,
105
+ ` Inference profile: ${formatScheduleInferenceProfile(job.inferenceProfile)}`,
97
106
  ` Message: ${job.message}`,
98
107
  );
99
108
 
@@ -142,18 +151,20 @@ export async function executeScheduleList(
142
151
  for (const job of jobs) {
143
152
  const status = job.enabled ? "enabled" : "disabled";
144
153
  const oneShot = isOneShot(job);
154
+ const plugin = describeScheduleSource(job.sourceKey);
155
+ const managed = plugin ? ` (managed by plugin ${plugin})` : "";
145
156
 
146
157
  if (oneShot) {
147
158
  const fireTime = formatLocalDate(job.nextRunAt);
148
159
  lines.push(
149
- ` - [${status}] ${job.name} (id: ${job.id}) (one-shot, ${job.mode}) [${job.status}]`,
160
+ ` - [${status}] ${job.name} (id: ${job.id}) (one-shot, ${job.mode}) [${job.status}]${managed}`,
150
161
  ` Description: ${describeAuthoredPurpose(job)}`,
151
162
  ` fire at: ${fireTime}`,
152
163
  );
153
164
  } else {
154
165
  const next = job.enabled ? formatLocalDate(job.nextRunAt) : "n/a";
155
166
  lines.push(
156
- ` - [${status}] ${job.name} (id: ${job.id}) (${job.mode})`,
167
+ ` - [${status}] ${job.name} (id: ${job.id}) (${job.mode})${managed}`,
157
168
  ` Description: ${describeAuthoredPurpose(job)}`,
158
169
  ` Schedule: [${job.syntax}] ${describeSchedule(job)}`,
159
170
  ` Next: ${next}`,