@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
@@ -0,0 +1,229 @@
1
+ import { Database } from "bun:sqlite";
2
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
3
+
4
+ import { drizzle } from "drizzle-orm/bun-sqlite";
5
+
6
+ import {
7
+ type DurableProfileFields,
8
+ resolveDurableProfile,
9
+ } from "../conversation-crud.js";
10
+
11
+ // The migration resolves through the shared schedule helpers, which read the
12
+ // workspace config. The default is stubbed so both of its outcomes can be
13
+ // driven: a named profile, and the code-owned anchor (null), which has no key
14
+ // to record. The wake seed keeps the real durable-pin reader so the
15
+ // session-backed vs. sticky distinction under test is the production one.
16
+ let resolvedDefault: string | null = "balanced";
17
+ mock.module("../../schedule/inference-profile.js", () => ({
18
+ resolveDefaultScheduleInferenceProfile: () => resolvedDefault,
19
+ resolveWakeScheduleInferenceProfile: (target: DurableProfileFields | null) =>
20
+ resolveDurableProfile(target) ?? resolvedDefault,
21
+ }));
22
+
23
+ import * as schema from "../schema.js";
24
+ import { migrateBackfillScheduleInferenceProfile } from "./363-backfill-schedule-inference-profile.js";
25
+
26
+ function createTestDb(withProfileColumn = true) {
27
+ const sqlite = new Database(":memory:");
28
+ sqlite.exec(/*sql*/ `
29
+ CREATE TABLE cron_jobs (
30
+ id TEXT PRIMARY KEY,
31
+ name TEXT NOT NULL,
32
+ message TEXT NOT NULL,
33
+ next_run_at INTEGER NOT NULL,
34
+ mode TEXT NOT NULL DEFAULT 'execute',
35
+ wake_conversation_id TEXT${withProfileColumn ? ",\n inference_profile TEXT" : ""}
36
+ );
37
+ CREATE TABLE conversations (
38
+ id TEXT PRIMARY KEY,
39
+ conversation_type TEXT,
40
+ inference_profile TEXT,
41
+ inference_profile_session_id TEXT,
42
+ inference_profile_expires_at INTEGER
43
+ );
44
+ `);
45
+ return { sqlite, db: drizzle(sqlite, { schema }) };
46
+ }
47
+
48
+ function insertJob(
49
+ sqlite: Database,
50
+ id: string,
51
+ inferenceProfile: string | null,
52
+ ): void {
53
+ sqlite
54
+ .query(
55
+ "INSERT INTO cron_jobs (id, name, message, next_run_at, inference_profile) VALUES (?, ?, ?, ?, ?)",
56
+ )
57
+ .run(id, id, "hi", 1000, inferenceProfile);
58
+ }
59
+
60
+ function insertWakeJob(
61
+ sqlite: Database,
62
+ id: string,
63
+ wakeConversationId: string,
64
+ ): void {
65
+ sqlite
66
+ .query(
67
+ "INSERT INTO cron_jobs (id, name, message, next_run_at, mode, wake_conversation_id, inference_profile) VALUES (?, ?, ?, ?, 'wake', ?, NULL)",
68
+ )
69
+ .run(id, id, "hi", 1000, wakeConversationId);
70
+ }
71
+
72
+ function insertConversation(
73
+ sqlite: Database,
74
+ id: string,
75
+ fields: {
76
+ inferenceProfile?: string | null;
77
+ sessionId?: string | null;
78
+ expiresAt?: number | null;
79
+ } = {},
80
+ ): void {
81
+ sqlite
82
+ .query(
83
+ "INSERT INTO conversations (id, conversation_type, inference_profile, inference_profile_session_id, inference_profile_expires_at) VALUES (?, 'chat', ?, ?, ?)",
84
+ )
85
+ .run(
86
+ id,
87
+ fields.inferenceProfile ?? null,
88
+ fields.sessionId ?? null,
89
+ fields.expiresAt ?? null,
90
+ );
91
+ }
92
+
93
+ function profileOf(sqlite: Database, id: string): unknown {
94
+ return (
95
+ sqlite
96
+ .query("SELECT inference_profile FROM cron_jobs WHERE id = ?")
97
+ .get(id) as { inference_profile: unknown }
98
+ ).inference_profile;
99
+ }
100
+
101
+ describe("migration 363: backfill cron_jobs.inference_profile", () => {
102
+ beforeEach(() => {
103
+ resolvedDefault = "balanced";
104
+ });
105
+
106
+ test("pins unpinned rows to the resolved default", () => {
107
+ const { sqlite, db } = createTestDb();
108
+ insertJob(sqlite, "unpinned-1", null);
109
+ insertJob(sqlite, "unpinned-2", null);
110
+
111
+ migrateBackfillScheduleInferenceProfile(db);
112
+
113
+ expect(profileOf(sqlite, "unpinned-1")).toBe("balanced");
114
+ expect(profileOf(sqlite, "unpinned-2")).toBe("balanced");
115
+ });
116
+
117
+ test("leaves an existing pin alone", () => {
118
+ const { sqlite, db } = createTestDb();
119
+ insertJob(sqlite, "pinned", "cost-optimized");
120
+
121
+ migrateBackfillScheduleInferenceProfile(db);
122
+
123
+ expect(profileOf(sqlite, "pinned")).toBe("cost-optimized");
124
+ });
125
+
126
+ test("is idempotent: a second run changes nothing", () => {
127
+ const { sqlite, db } = createTestDb();
128
+ insertJob(sqlite, "unpinned", null);
129
+
130
+ migrateBackfillScheduleInferenceProfile(db);
131
+ resolvedDefault = "cost-optimized";
132
+ migrateBackfillScheduleInferenceProfile(db);
133
+
134
+ // The row was pinned by the first run, so the later default does not
135
+ // overwrite it. That is what makes a schedule's cost stable.
136
+ expect(profileOf(sqlite, "unpinned")).toBe("balanced");
137
+ });
138
+
139
+ test("leaves rows null when no named profile resolves", () => {
140
+ const { sqlite, db } = createTestDb();
141
+ insertJob(sqlite, "unpinned", null);
142
+ resolvedDefault = null;
143
+
144
+ migrateBackfillScheduleInferenceProfile(db);
145
+
146
+ expect(profileOf(sqlite, "unpinned")).toBeNull();
147
+ });
148
+
149
+ test("skips an install that has no inference_profile column yet", () => {
150
+ const { sqlite, db } = createTestDb(false);
151
+ sqlite
152
+ .query(
153
+ "INSERT INTO cron_jobs (id, name, message, next_run_at) VALUES ('legacy', 'legacy', 'hi', 1000)",
154
+ )
155
+ .run();
156
+
157
+ expect(() => migrateBackfillScheduleInferenceProfile(db)).not.toThrow();
158
+ });
159
+
160
+ // A pending wake fires with no forced override today, so it resolves its
161
+ // target conversation's pin live. The backfill has to preserve that, or a
162
+ // reminder set inside a pinned conversation silently moves to the global
163
+ // default.
164
+ describe("wake rows seed from their target conversation", () => {
165
+ test("takes the target's durable pin", () => {
166
+ const { sqlite, db } = createTestDb();
167
+ insertConversation(sqlite, "conv-pinned", {
168
+ inferenceProfile: "cost-optimized",
169
+ });
170
+ insertWakeJob(sqlite, "wake-pinned", "conv-pinned");
171
+
172
+ migrateBackfillScheduleInferenceProfile(db);
173
+
174
+ expect(profileOf(sqlite, "wake-pinned")).toBe("cost-optimized");
175
+ });
176
+
177
+ test("takes the default when the target has no pin, as does an ordinary schedule", () => {
178
+ const { sqlite, db } = createTestDb();
179
+ insertConversation(sqlite, "conv-unpinned");
180
+ insertWakeJob(sqlite, "wake-unpinned", "conv-unpinned");
181
+ insertJob(sqlite, "ordinary", null);
182
+
183
+ migrateBackfillScheduleInferenceProfile(db);
184
+
185
+ expect(profileOf(sqlite, "wake-unpinned")).toBe("balanced");
186
+ expect(profileOf(sqlite, "ordinary")).toBe("balanced");
187
+ });
188
+
189
+ test("ignores a session-backed pin on the target", () => {
190
+ const { sqlite, db } = createTestDb();
191
+ insertConversation(sqlite, "conv-session", {
192
+ inferenceProfile: "cost-optimized",
193
+ sessionId: "session-1",
194
+ expiresAt: Date.now() + 600_000,
195
+ });
196
+ insertWakeJob(sqlite, "wake-session", "conv-session");
197
+
198
+ migrateBackfillScheduleInferenceProfile(db);
199
+
200
+ // The session lapses in minutes; the row it seeded would keep billing
201
+ // that model for as long as the wake stays pending.
202
+ expect(profileOf(sqlite, "wake-session")).toBe("balanced");
203
+ });
204
+
205
+ test("takes the default when the target conversation is gone", () => {
206
+ const { sqlite, db } = createTestDb();
207
+ insertWakeJob(sqlite, "wake-orphan", "conv-deleted");
208
+
209
+ migrateBackfillScheduleInferenceProfile(db);
210
+
211
+ expect(profileOf(sqlite, "wake-orphan")).toBe("balanced");
212
+ });
213
+
214
+ test("keeps the target's pin even when no default resolves", () => {
215
+ const { sqlite, db } = createTestDb();
216
+ resolvedDefault = null;
217
+ insertConversation(sqlite, "conv-pinned", {
218
+ inferenceProfile: "cost-optimized",
219
+ });
220
+ insertWakeJob(sqlite, "wake-pinned", "conv-pinned");
221
+ insertJob(sqlite, "ordinary", null);
222
+
223
+ migrateBackfillScheduleInferenceProfile(db);
224
+
225
+ expect(profileOf(sqlite, "wake-pinned")).toBe("cost-optimized");
226
+ expect(profileOf(sqlite, "ordinary")).toBeNull();
227
+ });
228
+ });
229
+ });
@@ -0,0 +1,127 @@
1
+ import type { Database } from "bun:sqlite";
2
+
3
+ import {
4
+ resolveDefaultScheduleInferenceProfile,
5
+ resolveWakeScheduleInferenceProfile,
6
+ } from "../../schedule/inference-profile.js";
7
+ import type { DurableProfileFields } from "../conversation-crud.js";
8
+ import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
9
+
10
+ /** Columns a wake row's seed needs on `cron_jobs` and `conversations`. */
11
+ const WAKE_JOB_COLUMNS = ["mode", "wake_conversation_id"] as const;
12
+ const CONVERSATION_PIN_COLUMNS = [
13
+ "conversation_type",
14
+ "inference_profile",
15
+ "inference_profile_session_id",
16
+ "inference_profile_expires_at",
17
+ ] as const;
18
+
19
+ function hasColumns(
20
+ raw: Database,
21
+ table: string,
22
+ required: readonly string[],
23
+ ): boolean {
24
+ const columns = raw.prepare(`PRAGMA table_info(${table})`).all() as {
25
+ name: string;
26
+ }[];
27
+ const present = new Set(columns.map((c) => c.name));
28
+ return required.every((name) => present.has(name));
29
+ }
30
+
31
+ /**
32
+ * Pin every unpinned schedule to a concrete inference profile.
33
+ *
34
+ * A schedule with no pin follows `llm.activeProfile`, so changing the global
35
+ * default silently moves every such schedule onto a different model and a
36
+ * different price. Schedules created from now on snapshot a profile at write
37
+ * time (`insertSchedule`); this backfill gives the rows that predate that the
38
+ * same stability, on the profile they are running under today.
39
+ *
40
+ * "Running under today" is not the global default for every row. An unpinned
41
+ * wake row reaches `buildWakeScheduleOptions` with no forced override, so its
42
+ * firing resolves the target conversation's own pin live. Stamping the global
43
+ * default over it would silently re-point a pending reminder that was created
44
+ * inside a pinned conversation, so wake rows seed through the same
45
+ * {@link resolveWakeScheduleInferenceProfile} the create path uses: the
46
+ * target's durable pin, else the default. Every other row takes the default.
47
+ *
48
+ * Rows keep a NULL pin when no named profile resolves at all (the winner is
49
+ * the code-owned anchor). That is the same value they carry now and resolves
50
+ * identically at run time, through the `mainAgent` call-site configuration.
51
+ *
52
+ * Only `cron_jobs` is written. `conversations` carries a pin the user sets per
53
+ * conversation (read here, never modified), and the telemetry tables
54
+ * (tool_invocations, llm_usage_events, skill_loaded_events) carry an
55
+ * `inference_profile` recording what actually ran, which must keep its
56
+ * historical value.
57
+ *
58
+ * Idempotent: `WHERE inference_profile IS NULL` matches nothing once a row is
59
+ * pinned, and the PRAGMA guards skip an install that has not created the
60
+ * columns yet.
61
+ */
62
+ export function migrateBackfillScheduleInferenceProfile(
63
+ database: DrizzleDb,
64
+ ): void {
65
+ const raw = getSqliteFrom(database);
66
+ if (!hasColumns(raw, "cron_jobs", ["inference_profile"])) {
67
+ return;
68
+ }
69
+
70
+ if (
71
+ hasColumns(raw, "cron_jobs", WAKE_JOB_COLUMNS) &&
72
+ hasColumns(raw, "conversations", CONVERSATION_PIN_COLUMNS)
73
+ ) {
74
+ backfillWakeRows(raw);
75
+ }
76
+
77
+ const profile = resolveDefaultScheduleInferenceProfile();
78
+ if (profile === null) {
79
+ return;
80
+ }
81
+ raw
82
+ .prepare(
83
+ `UPDATE cron_jobs SET inference_profile = ? WHERE inference_profile IS NULL`,
84
+ )
85
+ .run(profile);
86
+ }
87
+
88
+ function backfillWakeRows(raw: Database): void {
89
+ const rows = raw
90
+ .prepare(
91
+ `SELECT id, wake_conversation_id AS wakeConversationId
92
+ FROM cron_jobs
93
+ WHERE inference_profile IS NULL
94
+ AND mode = 'wake'
95
+ AND wake_conversation_id IS NOT NULL`,
96
+ )
97
+ .all() as { id: string; wakeConversationId: string }[];
98
+ if (rows.length === 0) {
99
+ return;
100
+ }
101
+
102
+ const selectTarget = raw.prepare(
103
+ `SELECT conversation_type AS conversationType,
104
+ inference_profile AS inferenceProfile,
105
+ inference_profile_session_id AS inferenceProfileSessionId,
106
+ inference_profile_expires_at AS inferenceProfileExpiresAt
107
+ FROM conversations
108
+ WHERE id = ?`,
109
+ );
110
+ const pin = raw.prepare(
111
+ `UPDATE cron_jobs SET inference_profile = ? WHERE id = ? AND inference_profile IS NULL`,
112
+ );
113
+
114
+ for (const row of rows) {
115
+ // A target deleted since the wake was created reads as null and falls
116
+ // through to the default, the same value the firing would resolve.
117
+ const target =
118
+ (selectTarget.get(
119
+ row.wakeConversationId,
120
+ ) as DurableProfileFields | null) ?? null;
121
+ const profile = resolveWakeScheduleInferenceProfile(target);
122
+ if (profile === null) {
123
+ continue;
124
+ }
125
+ pin.run(profile, row.id);
126
+ }
127
+ }
@@ -0,0 +1,120 @@
1
+ import { Database } from "bun:sqlite";
2
+ import { describe, expect, test } from "bun:test";
3
+
4
+ import { drizzle } from "drizzle-orm/bun-sqlite";
5
+
6
+ import * as schema from "../schema.js";
7
+ import { migrateAddScheduleSourceKey } from "./364-add-schedule-source-key.js";
8
+
9
+ const NEW_COLUMNS = ["source_key", "definition_hash", "user_enabled"];
10
+
11
+ /** Pre-364 shape: the cron_jobs table exactly as core tables created it. */
12
+ function createTestDb() {
13
+ const sqlite = new Database(":memory:");
14
+ sqlite.exec(/*sql*/ `
15
+ CREATE TABLE cron_jobs (
16
+ id TEXT PRIMARY KEY,
17
+ name TEXT NOT NULL,
18
+ enabled INTEGER NOT NULL DEFAULT 1,
19
+ cron_expression TEXT NOT NULL,
20
+ schedule_syntax TEXT NOT NULL DEFAULT 'cron',
21
+ timezone TEXT,
22
+ message TEXT NOT NULL,
23
+ next_run_at INTEGER NOT NULL,
24
+ last_run_at INTEGER,
25
+ last_status TEXT,
26
+ retry_count INTEGER NOT NULL DEFAULT 0,
27
+ created_by TEXT NOT NULL,
28
+ created_at INTEGER NOT NULL,
29
+ updated_at INTEGER NOT NULL
30
+ );
31
+ `);
32
+ return { sqlite, db: drizzle(sqlite, { schema }) };
33
+ }
34
+
35
+ function columnInfo(sqlite: Database) {
36
+ return sqlite.query("PRAGMA table_info(cron_jobs)").all() as Array<{
37
+ name: string;
38
+ notnull: number;
39
+ }>;
40
+ }
41
+
42
+ function insertJob(
43
+ sqlite: Database,
44
+ id: string,
45
+ sourceKey: string | null,
46
+ ): void {
47
+ sqlite
48
+ .query(
49
+ /*sql*/ `INSERT INTO cron_jobs (id, name, cron_expression, message, next_run_at, created_by, created_at, updated_at, source_key)
50
+ VALUES (?, 'Job', '0 9 * * *', 'hello', 1000, 'agent', 1000, 1000, ?)`,
51
+ )
52
+ .run(id, sourceKey);
53
+ }
54
+
55
+ describe("migration 364: cron_jobs declaration provenance", () => {
56
+ test("adds the nullable columns to an existing database", () => {
57
+ const { sqlite, db } = createTestDb();
58
+ const before = columnInfo(sqlite).map((c) => c.name);
59
+ for (const name of NEW_COLUMNS) {
60
+ expect(before).not.toContain(name);
61
+ }
62
+
63
+ migrateAddScheduleSourceKey(db);
64
+
65
+ const after = columnInfo(sqlite);
66
+ for (const name of NEW_COLUMNS) {
67
+ const column = after.find((c) => c.name === name);
68
+ expect(column).toBeDefined();
69
+ expect(column?.notnull).toBe(0);
70
+ }
71
+ });
72
+
73
+ test("rows written before the columns existed read back null", () => {
74
+ const { sqlite, db } = createTestDb();
75
+ sqlite.exec(/*sql*/ `
76
+ INSERT INTO cron_jobs (id, name, cron_expression, message, next_run_at, created_by, created_at, updated_at)
77
+ VALUES ('job-old', 'Old', '0 9 * * *', 'hello', 1000, 'agent', 1000, 1000)
78
+ `);
79
+
80
+ migrateAddScheduleSourceKey(db);
81
+
82
+ const row = sqlite
83
+ .query(
84
+ "SELECT source_key, definition_hash, user_enabled FROM cron_jobs WHERE id = 'job-old'",
85
+ )
86
+ .get() as Record<string, unknown>;
87
+ expect(row.source_key).toBeNull();
88
+ expect(row.definition_hash).toBeNull();
89
+ expect(row.user_enabled).toBeNull();
90
+ });
91
+
92
+ test("rejects a second row with the same source_key", () => {
93
+ const { sqlite, db } = createTestDb();
94
+ migrateAddScheduleSourceKey(db);
95
+
96
+ insertJob(sqlite, "job-a", "plugin:example/daily");
97
+
98
+ expect(() => insertJob(sqlite, "job-b", "plugin:example/daily")).toThrow();
99
+ });
100
+
101
+ test("leaves imperative schedules unconstrained", () => {
102
+ const { sqlite, db } = createTestDb();
103
+ migrateAddScheduleSourceKey(db);
104
+
105
+ insertJob(sqlite, "job-a", null);
106
+ expect(() => insertJob(sqlite, "job-b", null)).not.toThrow();
107
+ });
108
+
109
+ test("is idempotent: re-run is a no-op", () => {
110
+ const { sqlite, db } = createTestDb();
111
+
112
+ migrateAddScheduleSourceKey(db);
113
+ expect(() => migrateAddScheduleSourceKey(db)).not.toThrow();
114
+
115
+ const names = columnInfo(sqlite).map((c) => c.name);
116
+ for (const name of NEW_COLUMNS) {
117
+ expect(names.filter((n) => n === name)).toHaveLength(1);
118
+ }
119
+ });
120
+ });
@@ -0,0 +1,43 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { tableHasColumn } from "./schema-introspection.js";
3
+
4
+ const COLUMNS: ReadonlyArray<{ name: string; definition: string }> = [
5
+ { name: "source_key", definition: "source_key TEXT" },
6
+ { name: "definition_hash", definition: "definition_hash TEXT" },
7
+ { name: "user_enabled", definition: "user_enabled INTEGER" },
8
+ ];
9
+
10
+ /**
11
+ * Add plugin-declaration provenance columns to `cron_jobs`.
12
+ *
13
+ * `source_key` links a schedule row to the plugin declaration it was
14
+ * reconciled from (`plugin:<pluginName>/<scheduleName>`). Rows with a NULL
15
+ * `source_key` are imperative schedules and keep their existing behavior.
16
+ * `definition_hash` is the reconciler's change detector over the declaration
17
+ * files. `user_enabled` is the user's enable/disable override for a sourced
18
+ * row; NULL means the declaration's own enabled value applies.
19
+ *
20
+ * The unique index is partial (`WHERE source_key IS NOT NULL`) so the many
21
+ * NULL rows stay unconstrained while a given declaration resolves to exactly
22
+ * one row. The reconciler's upsert depends on that uniqueness.
23
+ *
24
+ * Nullable with no backfill: nothing recorded declaration provenance before
25
+ * these columns existed, so pre-existing rows correctly stay NULL.
26
+ *
27
+ * Idempotent: each column add is guarded with `tableHasColumn` and the index
28
+ * with `IF NOT EXISTS`, so a crash partway through does not break the next
29
+ * boot.
30
+ */
31
+ export function migrateAddScheduleSourceKey(database: DrizzleDb): void {
32
+ for (const column of COLUMNS) {
33
+ if (!tableHasColumn(database, "cron_jobs", column.name)) {
34
+ database.run(`ALTER TABLE cron_jobs ADD COLUMN ${column.definition}`);
35
+ }
36
+ }
37
+
38
+ database.run(/*sql*/ `
39
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_cron_jobs_source_key
40
+ ON cron_jobs(source_key)
41
+ WHERE source_key IS NOT NULL
42
+ `);
43
+ }
@@ -0,0 +1,27 @@
1
+ import type { DrizzleDb } from "../db-connection.js";
2
+ import { tableHasColumn } from "./schema-introspection.js";
3
+
4
+ /**
5
+ * Add `fork_strategy` to `conversations`, the discriminator that says whether
6
+ * a fork's inherited history lives on the fork (copied) or on its parent
7
+ * (read through `fork_parent_message_id`).
8
+ *
9
+ * The column is required even though `fork_parent_conversation_id` and
10
+ * `fork_parent_message_id` already exist, because both are set on copied
11
+ * forks too. Without a discriminator, a lineage read cannot tell a fork whose
12
+ * prefix it must fetch from the parent from one that already holds its own
13
+ * copy of that prefix, and would return the copied rows twice.
14
+ *
15
+ * Nullable with no backfill: every fork that exists when this runs was
16
+ * materialized by copying, and `isReferentialFork` reads NULL as `cloning`.
17
+ * A backfill would have to write a value to every historical conversation row
18
+ * to encode what the absence of a value already means.
19
+ *
20
+ * Idempotent: the column add is guarded with `tableHasColumn`, so a crash
21
+ * partway through does not break the next boot.
22
+ */
23
+ export function migrateAddConversationForkStrategy(database: DrizzleDb): void {
24
+ if (!tableHasColumn(database, "conversations", "fork_strategy")) {
25
+ database.run(`ALTER TABLE conversations ADD COLUMN fork_strategy TEXT`);
26
+ }
27
+ }
@@ -37,6 +37,16 @@ export const conversations = sqliteTable(
37
37
  originInterface: text("origin_interface"),
38
38
  forkParentConversationId: text("fork_parent_conversation_id"),
39
39
  forkParentMessageId: text("fork_parent_message_id"),
40
+ /**
41
+ * How this conversation's fork was materialized: `reference` means the
42
+ * rows at-or-before `forkParentMessageId` live on the parent and are read
43
+ * through it, `cloning` (and NULL, the value every pre-existing fork
44
+ * carries) means they were physically copied onto this row. Read through
45
+ * `isReferentialFork` in `conversation-lineage.ts`, never directly: the
46
+ * NULL-is-cloning default is what keeps existing forks from being read
47
+ * twice, once from their copies and once through their parent.
48
+ */
49
+ forkStrategy: text("fork_strategy"),
40
50
  /**
41
51
  * Id of the conversation that spawned this one (subagent spawns stamp
42
52
  * their parent's conversation id). Distinct from
@@ -45,6 +55,28 @@ export const conversations = sqliteTable(
45
55
  * conversations not spawned by another conversation.
46
56
  */
47
57
  parentConversationId: text("parent_conversation_id"),
58
+ /**
59
+ * Role the subagent that owns this conversation was spawned with, from
60
+ * `SUBAGENT_ROLE_REGISTRY` (`researcher`, `builder`, `advisor`); a spawn
61
+ * that named no role records the default, `builder`. NULL for every
62
+ * conversation that is not a subagent.
63
+ *
64
+ * Denormalized here rather than read from the `subagents` table at
65
+ * telemetry-flush time on purpose: `subagents` rows are deleted on
66
+ * dispose (TTL sweep ~30 minutes after the run goes terminal), while
67
+ * usage telemetry flushes on a watermark that can trail arbitrarily far
68
+ * behind after an ingest outage. Stamping the conversation row, the same
69
+ * rationale that put `parent_conversation_id` here, makes the
70
+ * attribution durable for the life of the usage row.
71
+ */
72
+ subagentRole: text("subagent_role"),
73
+ /**
74
+ * How the subagent that owns this conversation was spawned: context
75
+ * inheritance and lifecycle, orthogonal to {@link subagentRole}. One of
76
+ * the modes described on `SubagentSpawnMode` in `subagent/types.ts`. NULL
77
+ * for every conversation that is not a subagent.
78
+ */
79
+ subagentSpawnMode: text("subagent_spawn_mode"),
48
80
  isAutoTitle: integer("is_auto_title").notNull().default(1),
49
81
  scheduleJobId: text("schedule_job_id"),
50
82
  lastMessageAt: integer("last_message_at"),
@@ -40,6 +40,9 @@ export const cronJobs = sqliteTable("cron_jobs", {
40
40
  workflowName: text("workflow_name"), // saved workflow to trigger (nullable, only used when mode = 'workflow')
41
41
  workflowArgsJson: text("workflow_args_json"), // JSON-encoded args passed to the workflow run (nullable)
42
42
  capabilitiesJson: text("capabilities_json"), // JSON-encoded capability manifest for the run (nullable; null = hardcoded read-only manifest)
43
+ sourceKey: text("source_key"), // plugin declaration key ('plugin:<pluginName>/<scheduleName>'); null = imperative schedule
44
+ definitionHash: text("definition_hash"), // reconciler change detector over the declaration files (nullable, only used when source_key is set)
45
+ userEnabled: integer("user_enabled", { mode: "boolean" }), // user override for a sourced row's enabled state; null = declaration's value applies
43
46
  createdAt: integer("created_at").notNull(),
44
47
  updatedAt: integer("updated_at").notNull(),
45
48
  });
@@ -468,6 +468,11 @@ import { migrateMoveMemorySegmentsToMemoryDb } from "./migrations/357-move-memor
468
468
  import { migrateMoveMemoryEmbeddingsToMemoryDb } from "./migrations/358-move-memory-embeddings-to-memory-db.js";
469
469
  import { migrateMoveMemorySummariesToMemoryDb } from "./migrations/359-move-memory-summaries-to-memory-db.js";
470
470
  import { migrateAddDocumentWorkspacePath } from "./migrations/360-add-document-workspace-path.js";
471
+ import { migrateNormalizeManagedConnectionRows } from "./migrations/361-normalize-managed-connection-rows.js";
472
+ import { migrateAddConversationSubagentKind } from "./migrations/362-add-conversation-subagent-kind.js";
473
+ import { migrateBackfillScheduleInferenceProfile } from "./migrations/363-backfill-schedule-inference-profile.js";
474
+ import { migrateAddScheduleSourceKey } from "./migrations/364-add-schedule-source-key.js";
475
+ import { migrateAddConversationForkStrategy } from "./migrations/365-add-conversation-fork-strategy.js";
471
476
  import type { MigrationStep } from "./migrations/run-migrations.js";
472
477
 
473
478
  export const migrationSteps: MigrationStep[] = [
@@ -1543,4 +1548,29 @@ export const migrationSteps: MigrationStep[] = [
1543
1548
  ],
1544
1549
  },
1545
1550
  migrateAddDocumentWorkspacePath,
1551
+ {
1552
+ name: "migrateNormalizeManagedConnectionRows",
1553
+ run: migrateNormalizeManagedConnectionRows,
1554
+ // The table-exists guard treats a missing table as nothing-to-do, so
1555
+ // without this dependency a failed table creation followed by repair
1556
+ // would permanently checkpoint the normalization as a no-op.
1557
+ dependsOn: ["migrateCreateProviderConnections"],
1558
+ },
1559
+ {
1560
+ name: "migrateAddConversationSubagentKind",
1561
+ run: migrateAddConversationSubagentKind,
1562
+ // The backfill reads the `subagents` table (migration 311), so that table
1563
+ // must exist and be checkpointed first.
1564
+ dependsOn: ["migrateCreateSubagentsTable"],
1565
+ },
1566
+ {
1567
+ name: "migrateBackfillScheduleInferenceProfile",
1568
+ run: migrateBackfillScheduleInferenceProfile,
1569
+ // The column-exists guard treats a missing column as nothing-to-do, so
1570
+ // without this dependency a failed column add followed by repair would
1571
+ // permanently checkpoint the backfill as a no-op.
1572
+ dependsOn: ["migrateScheduleInferenceProfile"],
1573
+ },
1574
+ migrateAddScheduleSourceKey,
1575
+ migrateAddConversationForkStrategy,
1546
1576
  ];