@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
@@ -17,6 +17,8 @@ import {
17
17
  } from "../../persistence/llm-usage-store.js";
18
18
  import { isDeferSchedule } from "../../schedule/defer-provenance.js";
19
19
  import { validateScheduleInferenceProfile } from "../../schedule/inference-profile.js";
20
+ import { declarationExistsOnDisk } from "../../schedule/plugin-schedule-declarations.js";
21
+ import { isPluginSchedulesEnabled } from "../../schedule/plugin-schedules-gate.js";
20
22
  import {
21
23
  describeRRuleExpression,
22
24
  isSingleFireRRule,
@@ -39,6 +41,7 @@ import {
39
41
  listSchedules,
40
42
  resolveScheduleConversationGroupId,
41
43
  type ScheduleJob,
44
+ setUserEnabled,
42
45
  updateSchedule,
43
46
  } from "../../schedule/schedule-store.js";
44
47
  import { getScheduleUsageSummaries } from "../../schedule/schedule-usage-store.js";
@@ -135,7 +138,24 @@ const scheduleSchema = z.object({
135
138
  reuseConversation: z.boolean(),
136
139
  wakeConversationId: z.string().nullable(),
137
140
  workflowName: z.string().nullable(),
141
+ sourceKey: z
142
+ .string()
143
+ .nullable()
144
+ .describe(
145
+ "Plugin declaration this schedule mirrors (plugin:<pluginName>/<scheduleName>); null for user-created schedules",
146
+ ),
147
+ userEnabled: z
148
+ .boolean()
149
+ .nullable()
150
+ .describe(
151
+ "User enable/disable override on a plugin-sourced schedule; null when the declaration's own enabled value applies. Always null for user-created schedules.",
152
+ ),
138
153
  isOneShot: z.boolean(),
154
+ // A deferred wake ("remind me about this tomorrow") is an ordinary schedule
155
+ // row created by the defer path, distinguishable only by `createdBy`, which
156
+ // is not otherwise projected. Clients need it to separate the user's named
157
+ // schedules from their reminders when listing what a change affects.
158
+ isDeferred: z.boolean(),
139
159
  });
140
160
 
141
161
  const scheduleRunSchema = z.object({
@@ -218,6 +238,15 @@ function getCadenceDescription(
218
238
  return describeRRuleExpression(job.cronExpression);
219
239
  }
220
240
 
241
+ /**
242
+ * Whether a schedule still has a firing ahead of it. `fired` and `cancelled`
243
+ * are the two terminal states a one-shot lands in; everything else (including
244
+ * a disabled row, which fires again once re-enabled) can still run.
245
+ */
246
+ function canScheduleStillRun(job: Pick<ScheduleJob, "status">): boolean {
247
+ return job.status !== "fired" && job.status !== "cancelled";
248
+ }
249
+
221
250
  /**
222
251
  * Presentation-layer one-shot flag. A COUNT=1 rrule fires exactly once and
223
252
  * should read as one-time in clients, even though the scheduler internally
@@ -271,13 +300,19 @@ function serializeSchedule(
271
300
  reuseConversation: j.reuseConversation,
272
301
  wakeConversationId: j.wakeConversationId,
273
302
  workflowName: j.workflowName,
303
+ sourceKey: j.sourceKey,
304
+ userEnabled: j.userEnabled,
274
305
  isOneShot: isOneShotForDisplay(j),
306
+ isDeferred: isDeferSchedule(j.createdBy),
275
307
  };
276
308
  }
277
309
 
278
310
  function handleListSchedules(queryParams: Record<string, string>) {
279
311
  const includeAll = queryParams.include_all === "true";
280
- const jobs = listSchedules();
312
+ const inferenceProfile = queryParams.inference_profile?.trim();
313
+ const jobs = listSchedules(
314
+ inferenceProfile ? { inferenceProfile } : undefined,
315
+ );
281
316
  const filtered = includeAll
282
317
  ? jobs
283
318
  : jobs.filter((j) => !isDeferSchedule(j.createdBy));
@@ -300,6 +335,88 @@ function handleGetSchedule(id: string) {
300
335
  return { schedule: serializeSchedule(job, new Map()) };
301
336
  }
302
337
 
338
+ /**
339
+ * Move schedules onto the `to` inference profile.
340
+ *
341
+ * `from` narrows the move to the schedules pinned to that profile. It is the
342
+ * companion to deleting an inference profile: without it the profile's
343
+ * schedules keep a pin that no longer names anything. The dangling pin is not
344
+ * fatal (the resolver drops a missing override and falls through to the call
345
+ * site's own selection), so this exists to keep the user's stated model choice
346
+ * rather than to prevent a failure.
347
+ *
348
+ * Omitting `from` selects every schedule that can still run, which is what
349
+ * re-pinning the whole set onto the current default needs: schedules pinned by
350
+ * earlier defaults name several different profiles, so there is no single
351
+ * source to move from. A one-shot that already fired and a cancelled row are
352
+ * left out: their profile is history, and rewriting them would report a move
353
+ * larger than the set the user was looking at. An explicit `from` still
354
+ * selects exactly the rows pinned to it, dead or not, since a deleted profile
355
+ * has to be swept out of every row that names it. Rows already pinned to `to`
356
+ * are skipped either way, so the returned count is the number of schedules
357
+ * whose model actually changed.
358
+ *
359
+ * Each row goes through `updateSchedule`, so the store's profile validation
360
+ * and re-snapshot semantics apply exactly as they do to a single-row PATCH.
361
+ * Deferred-wake rows are moved too, since a defer inherits the profile of the
362
+ * conversation it was created in and would otherwise be the one row left
363
+ * dangling. Callers that warn a user before deleting a profile must count
364
+ * those rows as well, which is what `include_all` plus the serialized
365
+ * `isDeferred` flag on the list route are for. Moving one is a guardian-owned
366
+ * state change, so the whole call requires owner authority as soon as a wake
367
+ * row is in the selected set.
368
+ */
369
+ async function handleReassignScheduleInferenceProfile(
370
+ body: Record<string, unknown>,
371
+ headers?: Record<string, string>,
372
+ ) {
373
+ const hasFrom = body.from !== undefined && body.from !== null;
374
+ const from = typeof body.from === "string" ? body.from.trim() : "";
375
+ const to = typeof body.to === "string" ? body.to.trim() : "";
376
+ if (hasFrom && !from) {
377
+ throw new BadRequestError(
378
+ "from must name an inference profile when provided",
379
+ );
380
+ }
381
+ if (!to) {
382
+ throw new BadRequestError("to is required");
383
+ }
384
+ // `to` must name a configured profile; `from` deliberately is not validated
385
+ // so an already-deleted profile's leftover pins can still be swept up.
386
+ const profileError = validateScheduleInferenceProfile(to);
387
+ if (profileError) {
388
+ throw new BadRequestError(profileError);
389
+ }
390
+
391
+ const selected = hasFrom
392
+ ? listSchedules({ inferenceProfile: from })
393
+ : listSchedules().filter(canScheduleStillRun);
394
+ const matches = selected.filter((job) => job.inferenceProfile !== to);
395
+ // The guard depends only on the caller, so its answer is the same for every
396
+ // row: settle it once for the whole set. Checking per row would spend a
397
+ // cache-bypassing gateway round trip per matching reminder, and a profile
398
+ // that many reminders point at would take seconds to move or time out.
399
+ // All-or-nothing either way: one wake row in scope refuses the whole call
400
+ // before anything moves.
401
+ const wakeMatch = matches.find((job) => job.mode === "wake") ?? null;
402
+ await assertWakeMutationAllowed(wakeMatch, undefined, headers);
403
+
404
+ let reassigned = 0;
405
+ for (const job of matches) {
406
+ const updated = await updateSchedule(job.id, { inferenceProfile: to });
407
+ if (updated) {
408
+ reassigned += 1;
409
+ }
410
+ }
411
+ if (reassigned > 0) {
412
+ log.info(
413
+ { from: hasFrom ? from : null, to, reassigned },
414
+ "Schedules reassigned to new profile",
415
+ );
416
+ }
417
+ return { reassigned };
418
+ }
419
+
303
420
  async function handleCreateSchedule(body: Record<string, unknown>) {
304
421
  const name = typeof body.name === "string" ? body.name.trim() : "";
305
422
  const expression =
@@ -382,6 +499,7 @@ async function handleCreateSchedule(body: Record<string, unknown>) {
382
499
  timezone,
383
500
  expression: normalized.expression,
384
501
  syntax: normalized.syntax,
502
+ inferenceProfile,
385
503
  });
386
504
  log.info(
387
505
  { id: job.id, name: job.name, workflowName },
@@ -420,6 +538,7 @@ async function handleCreateSchedule(body: Record<string, unknown>) {
420
538
  expression: normalized.expression,
421
539
  syntax: normalized.syntax,
422
540
  timeoutMs,
541
+ inferenceProfile,
423
542
  });
424
543
  log.info({ id: job.id, name: job.name }, "Script schedule created");
425
544
  return { schedule: serializeSchedule(job, new Map()) };
@@ -468,7 +587,9 @@ async function handleToggleSchedule(
468
587
  // enabled, with no further caller involvement.
469
588
  await assertWakeMutationAllowed(getSchedule(id), undefined, headers);
470
589
 
471
- const updated = await updateSchedule(id, { enabled });
590
+ // One endpoint serves both kinds of row: imperative schedules take the
591
+ // plain enabled write, plugin-sourced ones record the user_enabled override.
592
+ const updated = await setUserEnabled(id, enabled);
472
593
  if (!updated) {
473
594
  throw new NotFoundError("Schedule not found");
474
595
  }
@@ -481,7 +602,18 @@ async function handleDeleteSchedule(
481
602
  headers?: Record<string, string>,
482
603
  ) {
483
604
  await assertWakeMutationAllowed(getSchedule(id), undefined, headers);
484
- const removed = await deleteSchedule(id);
605
+ let removed: boolean;
606
+ try {
607
+ removed = await deleteSchedule(id);
608
+ } catch (err) {
609
+ // Store-layer refusals (e.g. plugin-sourced rows, which only the plugin's
610
+ // schedule file can remove) are caller mistakes with an actionable
611
+ // message, not daemon faults.
612
+ if (err instanceof UserError) {
613
+ throw new BadRequestError(err.message);
614
+ }
615
+ throw err;
616
+ }
485
617
  if (!removed) {
486
618
  throw new NotFoundError("Schedule not found");
487
619
  }
@@ -494,7 +626,18 @@ async function handleCancelSchedule(
494
626
  headers?: Record<string, string>,
495
627
  ) {
496
628
  await assertWakeMutationAllowed(getSchedule(id), undefined, headers);
497
- const cancelled = await cancelSchedule(id);
629
+ let cancelled: boolean;
630
+ try {
631
+ cancelled = await cancelSchedule(id);
632
+ } catch (err) {
633
+ // Store-layer refusals (plugin-sourced rows, for which cancellation is a
634
+ // permanent latch) are caller mistakes with an actionable message, not
635
+ // daemon faults.
636
+ if (err instanceof UserError) {
637
+ throw new BadRequestError(err.message);
638
+ }
639
+ throw err;
640
+ }
498
641
  if (!cancelled) {
499
642
  throw new NotFoundError("Schedule not found or not cancellable");
500
643
  }
@@ -625,8 +768,8 @@ async function handleUpdateSchedule(
625
768
  }
626
769
  }
627
770
 
628
- // Inference profile: null clears the override (back to the default
629
- // main-agent model selection); a string must name a configured profile.
771
+ // Inference profile: null re-pins to the currently resolved default; a
772
+ // string must name a configured profile.
630
773
  if ("inferenceProfile" in body) {
631
774
  const inferenceProfile = body.inferenceProfile;
632
775
  if (inferenceProfile !== null && typeof inferenceProfile !== "string") {
@@ -761,6 +904,12 @@ export const ROUTES: RouteDefinition[] = [
761
904
  description:
762
905
  "When 'true', include deferred schedules that are normally hidden.",
763
906
  },
907
+ {
908
+ name: "inference_profile",
909
+ schema: { type: "string" },
910
+ description:
911
+ "Return only schedules pinned to this inference profile (llm.profiles key).",
912
+ },
764
913
  ],
765
914
  responseBody: z.object({
766
915
  schedules: z.array(scheduleSchema).describe("Schedule objects"),
@@ -802,8 +951,38 @@ export const ROUTES: RouteDefinition[] = [
802
951
  handler: ({ queryParams }: RouteHandlerArgs) =>
803
952
  handleScheduleUsageSummary(queryParams ?? {}),
804
953
  },
805
- // Must stay after literal `schedules/*` GET siblings (e.g. usage-summary):
806
- // the router matches in declaration order and `:id` would shadow them.
954
+ {
955
+ operationId: "reassignScheduleInferenceProfile",
956
+ endpoint: "schedules/reassign-profile",
957
+ method: "POST",
958
+ policy: {
959
+ requiredScopes: ["settings.write"],
960
+ allowedPrincipalTypes: ACTOR_PRINCIPALS,
961
+ },
962
+ summary: "Reassign schedules to another inference profile",
963
+ description:
964
+ "Move schedules onto one inference profile. Pass 'from' to move only the schedules pinned to that profile, so deleting a profile does not leave its schedules pointing at a name that no longer exists. Omit 'from' to move every schedule, which re-pins the whole set onto one profile. Schedules already pinned to the target are skipped.",
965
+ tags: ["schedules"],
966
+ requestBody: z.object({
967
+ from: z
968
+ .string()
969
+ .optional()
970
+ .describe(
971
+ "Inference profile key the schedules are pinned to now; omit to select every schedule",
972
+ ),
973
+ to: z
974
+ .string()
975
+ .describe("Inference profile key to move them to; must be configured"),
976
+ }),
977
+ responseBody: z.object({
978
+ reassigned: z.number().describe("Number of schedules moved"),
979
+ }),
980
+ handler: ({ body, headers }: RouteHandlerArgs) =>
981
+ handleReassignScheduleInferenceProfile(body ?? {}, headers),
982
+ },
983
+ // Must stay after literal `schedules/*` siblings (e.g. usage-summary,
984
+ // reassign-profile): the router matches in declaration order and `:id`
985
+ // would shadow them.
807
986
  {
808
987
  operationId: "getSchedule",
809
988
  endpoint: "schedules/:id",
@@ -882,7 +1061,7 @@ export const ROUTES: RouteDefinition[] = [
882
1061
  .string()
883
1062
  .nullable()
884
1063
  .describe(
885
- "Inference profile (llm.profiles key) the schedule's runs use. Omitted or null = default, i.e. the mainAgent call-site model selection.",
1064
+ "Inference profile (llm.profiles key) the schedule's runs use. Omitted or null pins the schedule to the currently resolved default profile, so its model does not move when that default changes. Workflow-mode schedules resolve a model per workflow step, so the pin is recorded but does not govern their runs.",
886
1065
  )
887
1066
  .optional(),
888
1067
  }),
@@ -919,7 +1098,8 @@ export const ROUTES: RouteDefinition[] = [
919
1098
  allowedPrincipalTypes: ACTOR_PRINCIPALS,
920
1099
  },
921
1100
  summary: "Toggle schedule",
922
- description: "Enable or disable a schedule.",
1101
+ description:
1102
+ "Enable or disable a schedule. On a plugin-managed schedule this records the user's override (userEnabled).",
923
1103
  tags: ["schedules"],
924
1104
  requestBody: z.object({
925
1105
  enabled: z.boolean().describe("New enabled state"),
@@ -1002,7 +1182,7 @@ export const ROUTES: RouteDefinition[] = [
1002
1182
  .string()
1003
1183
  .nullable()
1004
1184
  .describe(
1005
- "Inference profile (llm.profiles key) the schedule's runs use; null clears it back to the default mainAgent call-site model selection",
1185
+ "Inference profile (llm.profiles key) the schedule's runs use; null re-pins the schedule to the currently resolved default profile. Workflow-mode schedules resolve a model per workflow step, so the pin is recorded but does not govern their runs.",
1006
1186
  )
1007
1187
  .optional(),
1008
1188
  }),
@@ -1038,7 +1218,8 @@ export const ROUTES: RouteDefinition[] = [
1038
1218
  allowedPrincipalTypes: ACTOR_PRINCIPALS,
1039
1219
  },
1040
1220
  summary: "Run schedule now",
1041
- description: "Trigger an immediate execution of a schedule.",
1221
+ description:
1222
+ "Trigger an immediate execution of a schedule. A plugin-sourced schedule is rejected with a 400 when its plugin is disabled or no longer declares it.",
1042
1223
  tags: ["schedules"],
1043
1224
  responseBody: z.object({
1044
1225
  schedules: z.array(scheduleSchema).describe("Updated schedule list"),
@@ -1057,6 +1238,23 @@ async function handleRunScheduleNow(
1057
1238
  throw new NotFoundError("Schedule not found");
1058
1239
  }
1059
1240
 
1241
+ // A plugin-sourced row runs the plugin's own script or prompt, so run-now is
1242
+ // only offered while that plugin is something the runtime would activate.
1243
+ // `declarationExistsOnDisk` is the same probe the enable path uses: it covers
1244
+ // a disabled plugin, an unreadable or invalid manifest, and a declaration
1245
+ // that is simply gone. Turning the feature flag off retires the surface
1246
+ // wholesale and takes the same path. The row can still be armed at this
1247
+ // point, because the reconciler that disarms it runs on its own schedule.
1248
+ if (
1249
+ schedule.sourceKey !== null &&
1250
+ (!isPluginSchedulesEnabled() ||
1251
+ !(await declarationExistsOnDisk(schedule.sourceKey)))
1252
+ ) {
1253
+ throw new BadRequestError(
1254
+ "This schedule's plugin is disabled or no longer declares it, so it cannot be run.",
1255
+ );
1256
+ }
1257
+
1060
1258
  // ── Script mode (shell command, no LLM) ──────────────────────────
1061
1259
  if (schedule.mode === "script") {
1062
1260
  if (!schedule.script) {
@@ -108,7 +108,7 @@ async function queueApiKeyPropagation(
108
108
  getPlatformAssistantId() || undefined,
109
109
  );
110
110
  log.info(
111
- "Pushed queued assistant API key to CES after handshake completed",
111
+ "Notified CES of the queued assistant API key after handshake completed (ack only; CES reads the durable value from the credential store)",
112
112
  );
113
113
  } catch (err) {
114
114
  log.warn(
@@ -124,6 +124,44 @@ async function queueApiKeyPropagation(
124
124
  );
125
125
  }
126
126
 
127
+ /**
128
+ * Notify CES that the assistant API key changed. This is advisory: the key is
129
+ * durably stored in the credential vault and CES reads it from there. When no
130
+ * CES client is connected the notification is skipped, but the skip is logged
131
+ * rather than dropped silently. Exported for direct testing.
132
+ */
133
+ export async function notifyCesOfAssistantApiKeyUpdate(
134
+ value: string,
135
+ cesClient: CesClient | undefined,
136
+ logger: Pick<ReturnType<typeof getLogger>, "info" | "warn"> = log,
137
+ ): Promise<void> {
138
+ const generation = ++apiKeyGeneration;
139
+ if (!cesClient) {
140
+ logger.warn(
141
+ "Assistant API key updated but no CES client is connected; skipping the CES key-update notification (advisory only; CES reads the durable value from the credential store)",
142
+ );
143
+ return;
144
+ }
145
+ if (cesClient.isReady()) {
146
+ try {
147
+ await cesClient.updateAssistantApiKey(
148
+ value,
149
+ getPlatformAssistantId() || undefined,
150
+ );
151
+ logger.info(
152
+ "Notified CES of the updated assistant API key (ack only; CES reads the durable value from the credential store)",
153
+ );
154
+ } catch (err) {
155
+ logger.warn(
156
+ { error: err instanceof Error ? err.message : String(err) },
157
+ "Failed to notify CES of the assistant API key update (non-fatal)",
158
+ );
159
+ }
160
+ return;
161
+ }
162
+ void queueApiKeyPropagation(cesClient, value, generation);
163
+ }
164
+
127
165
  // ---------------------------------------------------------------------------
128
166
  // Provider refresh after secret changes
129
167
  // ---------------------------------------------------------------------------
@@ -381,28 +419,7 @@ async function handleAddSecret({ body }: RouteHandlerArgs) {
381
419
  // pages unseeded until restart. Detached — must not block the response.
382
420
  void maybeReseedCapabilitiesAfterManagedCredential(getConfig());
383
421
  if (service === "vellum" && field === "assistant_api_key") {
384
- const generation = ++apiKeyGeneration;
385
- const cesClient = getCesClient();
386
- if (cesClient) {
387
- if (cesClient.isReady()) {
388
- try {
389
- await cesClient.updateAssistantApiKey(
390
- value,
391
- getPlatformAssistantId() || undefined,
392
- );
393
- log.info(
394
- "Pushed assistant API key to CES after managed proxy credential update",
395
- );
396
- } catch (err) {
397
- log.warn(
398
- { error: err instanceof Error ? err.message : String(err) },
399
- "Failed to push assistant API key to CES (non-fatal)",
400
- );
401
- }
402
- } else {
403
- void queueApiKeyPropagation(cesClient, value, generation);
404
- }
405
- }
422
+ await notifyCesOfAssistantApiKeyUpdate(value, getCesClient());
406
423
  }
407
424
  }
408
425
  if (
@@ -46,6 +46,7 @@ import { getSecureKeyAsync } from "../../security/secure-keys.js";
46
46
  import { parseToolManifestFile } from "../../skills/tool-manifest.js";
47
47
  import { getSubagentManager } from "../../subagent/index.js";
48
48
  import { mergeSkillIds } from "../../subagent/manager.js";
49
+ import { resolveSubagentRole } from "../../subagent/role-resolution.js";
49
50
  import {
50
51
  SUBAGENT_ROLE_REGISTRY,
51
52
  type SubagentRole,
@@ -407,10 +408,24 @@ type SchemaShape = {
407
408
  required?: string[];
408
409
  };
409
410
 
411
+ /** How an `agent` query param was read, when one was given by role. */
412
+ interface ResolvedAgentInfo {
413
+ /** The `agent` value as asked for. */
414
+ requested: string;
415
+ /** The subagent type whose surface is listed. */
416
+ role: SubagentRole;
417
+ /** The older type name that produced `role`, when one did. */
418
+ alias?: string;
419
+ /** The free text carried as a persona, when `requested` named no type. */
420
+ persona?: string;
421
+ }
422
+
410
423
  interface ToolNamesListResponse {
411
424
  names: string[];
412
425
  schemas: Record<string, SchemaShape>;
413
426
  tools: ToolListEntry[];
427
+ /** Present only for an `agent` listing resolved from a role string. */
428
+ agent?: ResolvedAgentInfo;
414
429
  }
415
430
 
416
431
  /**
@@ -475,7 +490,11 @@ function handleToolNamesList(
475
490
 
476
491
  /**
477
492
  * Resolve the tool surface a subagent would receive, identified either by a
478
- * role name (e.g. "researcher") or a live subagent id.
493
+ * live subagent id or by any string a spawn's `role` field accepts: a type
494
+ * name (e.g. "researcher"), an older type name, or free text that a spawn
495
+ * carries as a persona. The response reports which type the string landed on
496
+ * and what carried it there, so a surface that came from an alias or a persona
497
+ * fallback is not mistaken for one that was asked for by name.
479
498
  *
480
499
  * For a role name: build a minimal {@link Conversation} stand-in matching what
481
500
  * the {@link SubagentManager} sets up at spawn time (isSubagent, allowedTools,
@@ -495,16 +514,13 @@ function handleAgentToolList(agent: string): ToolNamesListResponse {
495
514
  return handleConversationToolList(state.conversationId);
496
515
  }
497
516
 
498
- // Otherwise, treat as a role name.
499
- const role = agent as SubagentRole;
500
- const roleConfig = SUBAGENT_ROLE_REGISTRY[role];
501
- if (!roleConfig) {
502
- throw new NotFoundError(
503
- `Unknown agent "${agent}". Expected a subagent role ` +
504
- `(general, researcher, coder, planner, investigator, advisor) ` +
505
- `or a live subagent id.`,
506
- );
507
- }
517
+ // Otherwise, read it the way a spawn reads its `role` field. Resolution is
518
+ // total: a type name passes through, an older name resolves to its successor
519
+ // type, and anything else is a persona that runs as a researcher. Rejecting
520
+ // what a spawn accepts would leave the two spawn shapes a caller most wants
521
+ // to preview (an alias, a persona) with no way to see their tool surface.
522
+ const resolved = resolveSubagentRole(agent);
523
+ const roleConfig = SUBAGENT_ROLE_REGISTRY[resolved.role];
508
524
 
509
525
  // Build the same context the SubagentManager creates at spawn time. The
510
526
  // resolver reads only this subset of Conversation state, so a minimal
@@ -525,6 +541,11 @@ function handleAgentToolList(agent: string): ToolNamesListResponse {
525
541
  ? new Set(roleConfig.allowedTools)
526
542
  : undefined,
527
543
  subagentToolGateMode: undefined,
544
+ // Roles that refuse side effects require an allowed name to resolve to a
545
+ // first-party built-in, so a workspace or plugin tool claiming one is off
546
+ // the surface. Without this the preview would advertise a tool the live
547
+ // subagent refuses at dispatch.
548
+ subagentDenySideEffects: roleConfig.denySideEffects === true,
528
549
  toolsDisabledDepth: 0,
529
550
  diskPressureCleanupModeActive: false,
530
551
  skillProjectionState: new Map<string, string>(),
@@ -533,12 +554,19 @@ function handleAgentToolList(agent: string): ToolNamesListResponse {
533
554
  preactivatedSkillIds: mergedSkillIds,
534
555
  } as unknown as Conversation;
535
556
 
557
+ const agentInfo: ResolvedAgentInfo = {
558
+ requested: agent,
559
+ role: resolved.role,
560
+ ...(resolved.alias ? { alias: resolved.alias } : {}),
561
+ ...(resolved.personaText ? { persona: resolved.personaText } : {}),
562
+ };
563
+
536
564
  // Run the real tool resolver — the same callback a subagent conversation
537
565
  // uses each turn. An empty message history simulates the first turn before
538
566
  // any skill activations have been recorded.
539
567
  const resolveTools = createResolveToolsCallback(toolDefs, ctx);
540
568
  if (!resolveTools) {
541
- return { names: [], schemas: {}, tools: [] };
569
+ return { names: [], schemas: {}, tools: [], agent: agentInfo };
542
570
  }
543
571
  const resolvedDefs = resolveTools([]);
544
572
  const names = resolvedDefs
@@ -562,7 +590,7 @@ function handleAgentToolList(agent: string): ToolNamesListResponse {
562
590
  tools.push(toolEntryForName(name));
563
591
  }
564
592
 
565
- return { names, schemas, tools };
593
+ return { names, schemas, tools, agent: agentInfo };
566
594
  }
567
595
 
568
596
  /**
@@ -23,10 +23,12 @@ import {
23
23
  listSkills,
24
24
  listSkillsFiltered,
25
25
  searchSkills,
26
+ skillExistsLocally,
26
27
  uninstallSkill,
27
28
  updateSkill,
28
29
  } from "../../daemon/handlers/skills.js";
29
30
  import { getCategories } from "../../skills/categories-cache.js";
31
+ import { getSkillHistory } from "../../skills/skill-history.js";
30
32
  import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
31
33
  import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
32
34
  import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
@@ -351,6 +353,83 @@ export const ROUTES: RouteDefinition[] = [
351
353
  return result;
352
354
  },
353
355
  },
356
+ {
357
+ operationId: "getSkillHistory",
358
+ endpoint: "skills/:id/history",
359
+ method: "GET",
360
+ policy: {
361
+ requiredScopes: ["settings.read"],
362
+ allowedPrincipalTypes: ACTOR_PRINCIPALS,
363
+ },
364
+ summary: "Get skill revision history",
365
+ description:
366
+ "Return a skill's recent updates, newest first, each with a combined diff across the skill directory. Read-only: revisions come from the workspace git repository, which already retains prior content. Commits whose only in-skill change is the `lastUsedAt` usage stamp are omitted, so entries are edits rather than loads.",
367
+ tags: ["skills"],
368
+ queryParams: [
369
+ {
370
+ name: "limit",
371
+ schema: { type: "integer" },
372
+ required: false,
373
+ description:
374
+ "Maximum revisions to return, newest first. Defaults to 20 and is clamped to 100.",
375
+ },
376
+ ],
377
+ responseBody: z.object({
378
+ skillId: z.string().describe("The skill these revisions belong to"),
379
+ revisions: z
380
+ .array(
381
+ z.object({
382
+ id: z.string().describe("Opaque revision identifier"),
383
+ changedAt: z.string().describe("ISO-8601 time of the update"),
384
+ files: z
385
+ .array(z.string())
386
+ .describe("Paths changed, relative to the skill directory"),
387
+ diff: z
388
+ .string()
389
+ .describe("Unified diff of this update, scoped to the skill"),
390
+ }),
391
+ )
392
+ .describe("Recent updates, newest first"),
393
+ truncatedByCompaction: z
394
+ .boolean()
395
+ .describe(
396
+ "Older history was squashed away, so the oldest entry is a floor rather than the skill's creation",
397
+ ),
398
+ }),
399
+ handler: async ({ pathParams, queryParams }: RouteHandlerArgs) => {
400
+ const rawLimit = queryParams?.limit;
401
+ const limit =
402
+ typeof rawLimit === "string" && rawLimit.trim().length > 0
403
+ ? Number.parseInt(rawLimit, 10)
404
+ : undefined;
405
+ try {
406
+ // Same current-resource boundary as the file routes. Git retains a
407
+ // deleted skill's commits, so without this a removed skill keeps
408
+ // answering with history for something the rest of the API reports as
409
+ // gone. An existing skill with nothing recorded still gets an empty
410
+ // list, which is the honest answer for a bundled skill or one the
411
+ // workspace has not committed yet.
412
+ if (!skillExistsLocally(pathParams!.id)) {
413
+ throw new NotFoundError(`Skill "${pathParams!.id}" not found`);
414
+ }
415
+ return await getSkillHistory(pathParams!.id, {
416
+ ...(limit !== undefined && Number.isFinite(limit) ? { limit } : {}),
417
+ });
418
+ } catch (err) {
419
+ if (err instanceof NotFoundError) {
420
+ throw err;
421
+ }
422
+ const message = err instanceof Error ? err.message : String(err);
423
+ // The id reaches a git pathspec, so a malformed one is the caller's
424
+ // error. Anything else escaping the service is a server fault: the
425
+ // read is otherwise fail-soft and returns an empty history.
426
+ if (message.startsWith("Invalid skill id")) {
427
+ throw new BadRequestError(message);
428
+ }
429
+ throw new InternalError(message);
430
+ }
431
+ },
432
+ },
354
433
  {
355
434
  operationId: "enableSkill",
356
435
  endpoint: "skills/:id/enable",
@@ -206,6 +206,7 @@ async function handleHostUiSnapshotResult({ body, headers }: RouteHandlerArgs) {
206
206
  targetActorPrincipalId: peeked.targetActorPrincipalId,
207
207
  targetClientId: peeked.targetClientId,
208
208
  op: "host_ui_snapshot",
209
+ hubForMissingTarget: assistantEventHub,
209
210
  });
210
211
  }
211
212