@vellumai/assistant 0.11.2 → 0.11.3-staging.1

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 (709) 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-queue.test.ts +265 -1
  72. package/src/__tests__/conversation-retry-route.test.ts +3 -1
  73. package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
  74. package/src/__tests__/conversation-store.test.ts +26 -10
  75. package/src/__tests__/conversation-summarize-route.test.ts +1 -1
  76. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
  77. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
  78. package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
  79. package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
  80. package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
  81. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
  82. package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
  83. package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
  84. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
  85. package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
  86. package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
  87. package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
  88. package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
  89. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
  90. package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
  91. package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
  92. package/src/__tests__/credential-prompt-route.test.ts +57 -7
  93. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  94. package/src/__tests__/cu-unified-flow.test.ts +89 -28
  95. package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
  96. package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
  97. package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
  98. package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
  99. package/src/__tests__/disk-pressure-guard.test.ts +55 -55
  100. package/src/__tests__/disk-pressure-routes.test.ts +10 -10
  101. package/src/__tests__/disk-pressure-tools.test.ts +2 -2
  102. package/src/__tests__/disk-usage.test.ts +35 -20
  103. package/src/__tests__/document-sync-tags.test.ts +379 -0
  104. package/src/__tests__/document-update-default-surface.test.ts +28 -0
  105. package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
  106. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
  107. package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
  108. package/src/__tests__/events-dev-bypass-actor.test.ts +183 -1
  109. package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
  110. package/src/__tests__/file-list-tool.test.ts +12 -10
  111. package/src/__tests__/file-ops-service.test.ts +151 -44
  112. package/src/__tests__/file-read-container-boundary.test.ts +137 -0
  113. package/src/__tests__/file-read-tool.test.ts +21 -9
  114. package/src/__tests__/file-url-path-guard.test.ts +83 -0
  115. package/src/__tests__/filesystem-tools.test.ts +82 -66
  116. package/src/__tests__/guardian-outbound-http.test.ts +8 -8
  117. package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
  118. package/src/__tests__/helpers/hub-clients.ts +42 -0
  119. package/src/__tests__/helpers/mock-conversation.ts +46 -0
  120. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
  121. package/src/__tests__/history-repair.test.ts +112 -12
  122. package/src/__tests__/host-bash-proxy.test.ts +10 -5
  123. package/src/__tests__/host-bash-routes.test.ts +67 -0
  124. package/src/__tests__/host-browser-proxy.test.ts +2 -2
  125. package/src/__tests__/host-cu-proxy.test.ts +3 -7
  126. package/src/__tests__/host-file-proxy.test.ts +3 -7
  127. package/src/__tests__/host-file-read-tool.test.ts +5 -1
  128. package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
  129. package/src/__tests__/http-conversation-lineage.test.ts +2 -5
  130. package/src/__tests__/http-user-message-parity.test.ts +44 -0
  131. package/src/__tests__/identity-routes.test.ts +13 -13
  132. package/src/__tests__/image-conversion.test.ts +29 -26
  133. package/src/__tests__/image-source-path-reinject.test.ts +2 -2
  134. package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
  135. package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
  136. package/src/__tests__/introduction-card-resolver.test.ts +6 -1
  137. package/src/__tests__/list-messages-attachments.test.ts +56 -32
  138. package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
  139. package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
  140. package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
  141. package/src/__tests__/list-messages-page-latest.test.ts +61 -61
  142. package/src/__tests__/list-messages-provider-error.test.ts +6 -6
  143. package/src/__tests__/list-messages-queued.test.ts +49 -6
  144. package/src/__tests__/list-messages-system-card.test.ts +4 -4
  145. package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
  146. package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
  147. package/src/__tests__/llm-usage-store.test.ts +55 -0
  148. package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
  149. package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
  150. package/src/__tests__/media-stream-server-integration.test.ts +36 -0
  151. package/src/__tests__/migration-export-http.test.ts +1 -1
  152. package/src/__tests__/migration-import-commit-http.test.ts +1 -1
  153. package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
  154. package/src/__tests__/migration-validate-http.test.ts +1 -1
  155. package/src/__tests__/mtime-cache.test.ts +65 -3
  156. package/src/__tests__/notification-platform-adapter.test.ts +104 -0
  157. package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
  158. package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
  159. package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
  160. package/src/__tests__/oauth-providers-routes.test.ts +1 -0
  161. package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
  162. package/src/__tests__/path-policy.test.ts +164 -1
  163. package/src/__tests__/persist-media-references.test.ts +2 -2
  164. package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
  165. package/src/__tests__/persist-unsendable-image.test.ts +23 -23
  166. package/src/__tests__/persona-resolver.test.ts +154 -0
  167. package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
  168. package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
  169. package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
  170. package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
  171. package/src/__tests__/profiler-routes.test.ts +13 -13
  172. package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
  173. package/src/__tests__/proxy-approval-callback.test.ts +3 -3
  174. package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
  175. package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
  176. package/src/__tests__/resolve-trust-class.test.ts +20 -0
  177. package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
  178. package/src/__tests__/run-due-schedules.test.ts +174 -0
  179. package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
  180. package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
  181. package/src/__tests__/schedule-routes.test.ts +730 -8
  182. package/src/__tests__/schedule-store.test.ts +540 -0
  183. package/src/__tests__/schedule-tools.test.ts +103 -0
  184. package/src/__tests__/scheduler-wake.test.ts +5 -0
  185. package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
  186. package/src/__tests__/secure-keys.test.ts +91 -0
  187. package/src/__tests__/server-history-render.test.ts +97 -7
  188. package/src/__tests__/size-guard.test.ts +8 -8
  189. package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
  190. package/src/__tests__/skill-tool-factory.test.ts +247 -0
  191. package/src/__tests__/skills-install-staging.test.ts +15 -6
  192. package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
  193. package/src/__tests__/slack-inbound-verification.test.ts +4 -1
  194. package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
  195. package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
  196. package/src/__tests__/starter-task-flow.test.ts +5 -4
  197. package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
  198. package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
  199. package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
  200. package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
  201. package/src/__tests__/subagent-disposal.test.ts +10 -0
  202. package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
  203. package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
  204. package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
  205. package/src/__tests__/subagent-manager-notify.test.ts +148 -0
  206. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  207. package/src/__tests__/subagent-persistence.test.ts +141 -0
  208. package/src/__tests__/subagent-role-registry.test.ts +172 -63
  209. package/src/__tests__/subagent-role-resolution.test.ts +88 -0
  210. package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
  211. package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
  212. package/src/__tests__/subagent-terminal-message.test.ts +88 -1
  213. package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
  214. package/src/__tests__/subagent-tools.test.ts +1901 -108
  215. package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
  216. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
  217. package/src/__tests__/system-prompt.test.ts +82 -7
  218. package/src/__tests__/tool-result-spool.test.ts +74 -18
  219. package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
  220. package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
  221. package/src/__tests__/tools-audio-read.test.ts +10 -10
  222. package/src/__tests__/tools-get-route.test.ts +85 -12
  223. package/src/__tests__/tools-list-cli.test.ts +171 -0
  224. package/src/__tests__/top-level-renderer.test.ts +54 -1
  225. package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
  226. package/src/__tests__/turn-tail-chain.test.ts +135 -0
  227. package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
  228. package/src/__tests__/ui-visual-surface.test.ts +5 -4
  229. package/src/__tests__/ui-work-result-surface.test.ts +5 -4
  230. package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
  231. package/src/__tests__/usage-routes.test.ts +62 -0
  232. package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
  233. package/src/__tests__/visible-app-context.test.ts +20 -4
  234. package/src/__tests__/web-search-history.test.ts +96 -0
  235. package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
  236. package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
  237. package/src/acp/failure-error.ts +3 -5
  238. package/src/agent/attachments.ts +26 -24
  239. package/src/agent/history-repair/history-repair.ts +27 -26
  240. package/src/agent/image-optimize.ts +6 -6
  241. package/src/agent/loop.ts +40 -22
  242. package/src/agent/message-types.ts +3 -3
  243. package/src/api/constants/document-tools.ts +55 -0
  244. package/src/api/events/question-answered.ts +53 -0
  245. package/src/api/events/tool-result.ts +7 -0
  246. package/src/api/index.ts +13 -0
  247. package/src/api/responses/conversation-message.ts +11 -0
  248. package/src/api/surfaces-oauth-connect.test.ts +96 -0
  249. package/src/api/surfaces.ts +36 -8
  250. package/src/approvals/guardian-channel-delivery.ts +83 -0
  251. package/src/approvals/guardian-expiry-notifier.ts +13 -11
  252. package/src/approvals/guardian-request-resolvers.ts +216 -132
  253. package/src/calls/__tests__/voice-session-bridge.test.ts +50 -0
  254. package/src/calls/media-stream-server.ts +9 -1
  255. package/src/calls/voice-session-bridge.ts +38 -0
  256. package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
  257. package/src/channels/config.ts +7 -2
  258. package/src/channels/gateway-verification-sessions.ts +7 -2
  259. package/src/channels/types.ts +7 -1
  260. package/src/cli/commands/__tests__/cache.test.ts +7 -4
  261. package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
  262. package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
  263. package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
  264. package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
  265. package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
  266. package/src/cli/commands/__tests__/plugins.test.ts +692 -0
  267. package/src/cli/commands/__tests__/schedules.test.ts +136 -37
  268. package/src/cli/commands/conversations.ts +7 -3
  269. package/src/cli/commands/credentials.help.ts +7 -0
  270. package/src/cli/commands/inference-profiles.ts +9 -3
  271. package/src/cli/commands/inference.help.ts +16 -2
  272. package/src/cli/commands/mcp.help.ts +4 -2
  273. package/src/cli/commands/memory/memory-retrospective.ts +18 -0
  274. package/src/cli/commands/notifications.ts +3 -6
  275. package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
  276. package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
  277. package/src/cli/commands/oauth/connect.test.ts +26 -1
  278. package/src/cli/commands/oauth/connect.ts +4 -1
  279. package/src/cli/commands/oauth/index.help.ts +3 -1
  280. package/src/cli/commands/oauth/providers.ts +3 -0
  281. package/src/cli/commands/plugins.help.ts +25 -2
  282. package/src/cli/commands/plugins.ts +289 -10
  283. package/src/cli/commands/schedules.help.ts +14 -12
  284. package/src/cli/commands/schedules.ts +19 -5
  285. package/src/cli/commands/tools.help.ts +4 -2
  286. package/src/cli/commands/tools.ts +38 -0
  287. package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
  288. package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
  289. package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
  290. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
  291. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +122 -0
  292. package/src/cli/lib/install-from-github.ts +61 -0
  293. package/src/cli/lib/install-from-platform.ts +13 -2
  294. package/src/cli/lib/plugin-surfaces.ts +124 -4
  295. package/src/cli/lib/upgrade-plugin.ts +18 -0
  296. package/src/cli.ts +1 -1
  297. package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
  298. package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
  299. package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
  300. package/src/config/__tests__/profile-tool-support.test.ts +131 -0
  301. package/src/config/bundled-skills/AGENTS.md +1 -1
  302. package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
  303. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
  304. package/src/config/bundled-skills/schedule/SKILL.md +5 -1
  305. package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
  306. package/src/config/bundled-skills/settings/TOOLS.json +2 -2
  307. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
  308. package/src/config/bundled-skills/subagent/SKILL.md +53 -22
  309. package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
  310. package/src/config/bundled-skills/visualize/SKILL.md +1 -1
  311. package/src/config/default-profile-catalog.ts +6 -2
  312. package/src/config/feature-flag-registry.json +25 -17
  313. package/src/config/llm-resolver.ts +45 -15
  314. package/src/config/loader.ts +70 -1
  315. package/src/config/profile-tool-support.ts +110 -0
  316. package/src/config/sanitize-for-transfer.ts +11 -0
  317. package/src/config/schema.ts +4 -0
  318. package/src/config/schemas/__tests__/stt.test.ts +20 -5
  319. package/src/config/schemas/channels.ts +13 -0
  320. package/src/config/schemas/memory-retrospective.ts +25 -0
  321. package/src/config/schemas/plugin-updates.ts +55 -0
  322. package/src/config/schemas/services.ts +8 -4
  323. package/src/config/schemas/stt.ts +17 -5
  324. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
  325. package/src/contacts/guardian-delivery-reader.ts +29 -2
  326. package/src/context/compactor.ts +4 -4
  327. package/src/context/post-turn-tool-result-truncation.ts +32 -16
  328. package/src/context/strip-injections.ts +42 -0
  329. package/src/context/tool-result-spool.ts +32 -18
  330. package/src/credential-execution/ces-runtime.ts +3 -0
  331. package/src/credential-execution/client.ts +22 -1
  332. package/src/credential-execution/process-manager.test.ts +99 -0
  333. package/src/credential-execution/process-manager.ts +62 -16
  334. package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
  335. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
  336. package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
  337. package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
  338. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
  339. package/src/daemon/channel-ui-capability.ts +4 -4
  340. package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
  341. package/src/daemon/conversation-agent-loop.ts +296 -145
  342. package/src/daemon/conversation-attachments.ts +1 -1
  343. package/src/daemon/conversation-error.ts +8 -1
  344. package/src/daemon/conversation-initial-prompt.ts +16 -38
  345. package/src/daemon/conversation-lifecycle.ts +154 -32
  346. package/src/daemon/conversation-messaging.ts +85 -42
  347. package/src/daemon/conversation-process.ts +76 -28
  348. package/src/daemon/conversation-runtime-assembly.ts +9 -4
  349. package/src/daemon/conversation-store.ts +52 -3
  350. package/src/daemon/conversation-surface-state.ts +9 -0
  351. package/src/daemon/conversation-surfaces.ts +403 -210
  352. package/src/daemon/conversation-tool-setup.ts +56 -7
  353. package/src/daemon/conversation-turn-finalize.ts +134 -89
  354. package/src/daemon/conversation.ts +105 -27
  355. package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
  356. package/src/daemon/disk-pressure-guard.ts +3 -3
  357. package/src/daemon/doordash-steps.ts +5 -5
  358. package/src/daemon/external-plugins-bootstrap.ts +7 -1
  359. package/src/daemon/handlers/config-channels.ts +48 -5
  360. package/src/daemon/handlers/conversation-history.ts +1 -1
  361. package/src/daemon/handlers/conversations.ts +62 -17
  362. package/src/daemon/handlers/shared.ts +12 -0
  363. package/src/daemon/handlers/skills.ts +11 -1
  364. package/src/daemon/identity-helpers.ts +38 -10
  365. package/src/daemon/install-assistant-command.ts +322 -0
  366. package/src/daemon/lifecycle.ts +14 -3
  367. package/src/daemon/message-types/conversations.ts +6 -7
  368. package/src/daemon/message-types/sync.ts +1 -0
  369. package/src/daemon/persist-media-references.ts +23 -14
  370. package/src/daemon/process-message.ts +6 -6
  371. package/src/daemon/tool-setup-types.ts +19 -122
  372. package/src/daemon/tool-side-effects.ts +17 -94
  373. package/src/daemon/trust-context.ts +14 -6
  374. package/src/daemon/turn-tail-chain.ts +73 -0
  375. package/src/daemon/web-search-history.ts +47 -33
  376. package/src/heartbeat/heartbeat-service.ts +6 -6
  377. package/src/ipc/__tests__/socket-path.test.ts +21 -0
  378. package/src/ipc/assistant-server.ts +17 -10
  379. package/src/ipc/cli-client.ts +10 -1
  380. package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
  381. package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
  382. package/src/ipc/socket-cleanup.ts +9 -7
  383. package/src/ipc/socket-path.ts +4 -96
  384. package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
  385. package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
  386. package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
  387. package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
  388. package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
  389. package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
  390. package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
  391. package/src/live-voice/__tests__/protocol.test.ts +52 -0
  392. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
  393. package/src/live-voice/live-voice-archive.ts +13 -13
  394. package/src/live-voice/live-voice-connection.ts +7 -1
  395. package/src/live-voice/live-voice-photo.ts +169 -0
  396. package/src/live-voice/live-voice-session.ts +108 -4
  397. package/src/live-voice/protocol.ts +89 -1
  398. package/src/mcp/client.ts +10 -0
  399. package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
  400. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
  401. package/src/messaging/providers/callback-routing.ts +1 -0
  402. package/src/messaging/providers/discord/api.ts +312 -0
  403. package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
  404. package/src/messaging/providers/discord/render.test.ts +204 -0
  405. package/src/messaging/providers/discord/render.ts +195 -0
  406. package/src/messaging/providers/discord/send.test.ts +179 -0
  407. package/src/messaging/providers/discord/send.ts +212 -0
  408. package/src/messaging/providers/discord/transport.ts +81 -0
  409. package/src/messaging/providers/index.ts +3 -1
  410. package/src/messaging/providers/retry-policy.test.ts +247 -0
  411. package/src/messaging/providers/retry-policy.ts +206 -0
  412. package/src/messaging/providers/slack/mention-source.test.ts +285 -0
  413. package/src/messaging/providers/slack/mention-source.ts +287 -0
  414. package/src/messaging/providers/telegram-bot/api.ts +47 -130
  415. package/src/messaging/providers/whatsapp/api.ts +47 -136
  416. package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
  417. package/src/monitoring/__tests__/plugin-auto-update.test.ts +332 -0
  418. package/src/monitoring/db-integrity-sample.ts +6 -1
  419. package/src/monitoring/plugin-auto-update.ts +359 -0
  420. package/src/monitoring/resource-sampler.ts +21 -5
  421. package/src/monitoring/worker.ts +13 -0
  422. package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
  423. package/src/notifications/__tests__/broadcaster.test.ts +37 -1
  424. package/src/notifications/__tests__/copy-composer.test.ts +165 -0
  425. package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
  426. package/src/notifications/__tests__/notification-utils.test.ts +249 -0
  427. package/src/notifications/adapters/platform.ts +31 -2
  428. package/src/notifications/assistant-reply-producer.ts +79 -32
  429. package/src/notifications/broadcaster.ts +30 -10
  430. package/src/notifications/copy-composer.ts +69 -0
  431. package/src/notifications/emit-signal.ts +82 -15
  432. package/src/notifications/events-store.ts +10 -2
  433. package/src/notifications/home-feed-side-effect.ts +6 -3
  434. package/src/notifications/notification-utils.ts +173 -5
  435. package/src/notifications/signal.ts +12 -0
  436. package/src/oauth/byo-connection.ts +6 -1
  437. package/src/oauth/credential-token-resolver.ts +3 -10
  438. package/src/oauth/manual-token-connection.ts +29 -64
  439. package/src/oauth/manual-token-providers.ts +62 -0
  440. package/src/oauth/provider-serializer.ts +13 -0
  441. package/src/oauth/seed-providers.ts +56 -8
  442. package/src/onboarding/onboarding-events-store.ts +91 -1
  443. package/src/permissions/question-prompter.test.ts +4 -0
  444. package/src/permissions/question-prompter.ts +21 -4
  445. package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
  446. package/src/persistence/attachments-store.ts +15 -15
  447. package/src/persistence/conversation-attention-store.ts +30 -10
  448. package/src/persistence/conversation-bootstrap.ts +17 -0
  449. package/src/persistence/conversation-crud.ts +363 -97
  450. package/src/persistence/conversation-group-migration.ts +1 -1
  451. package/src/persistence/conversation-key-store.ts +38 -10
  452. package/src/persistence/conversation-lineage.ts +226 -0
  453. package/src/persistence/conversation-plugin-facade.ts +28 -3
  454. package/src/persistence/conversation-queries.ts +207 -33
  455. package/src/persistence/conversation-types.ts +107 -1
  456. package/src/persistence/jobs-store.ts +32 -8
  457. package/src/persistence/llm-usage-store.ts +22 -0
  458. package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
  459. package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
  460. package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
  461. package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
  462. package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
  463. package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
  464. package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
  465. package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
  466. package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
  467. package/src/persistence/schema/conversations.ts +32 -0
  468. package/src/persistence/schema/infrastructure.ts +3 -0
  469. package/src/persistence/steps.ts +30 -0
  470. package/src/persistence/subagent-store.ts +148 -6
  471. package/src/platform/managed-speech.test.ts +20 -0
  472. package/src/platform/managed-speech.ts +9 -0
  473. package/src/plugin-api/index.ts +8 -0
  474. package/src/plugin-api/webhook-url.ts +151 -0
  475. package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
  476. package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
  477. package/src/plugins/collect-source-versions.ts +4 -27
  478. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
  479. package/src/plugins/defaults/exploration-drift/package.json +1 -1
  480. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
  481. package/src/plugins/defaults/image-recovery/recover.ts +67 -57
  482. package/src/plugins/defaults/index.ts +1 -1
  483. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
  484. package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
  485. package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
  486. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
  487. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
  488. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
  489. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
  490. package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
  491. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
  492. package/src/plugins/defaults/memory/job-handlers.ts +87 -5
  493. package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
  494. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
  495. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
  496. package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
  497. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
  498. package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
  499. package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
  500. package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
  501. package/src/plugins/defaults/memory/v2/router.ts +8 -0
  502. package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
  503. package/src/plugins/external-plugin-loader.ts +17 -8
  504. package/src/plugins/installed-plugin-dirs.ts +101 -0
  505. package/src/plugins/mtime-cache.ts +34 -22
  506. package/src/plugins/types.ts +69 -8
  507. package/src/prompts/persona-resolver.ts +6 -2
  508. package/src/prompts/system-prompt.ts +72 -17
  509. package/src/providers/__tests__/inference.test.ts +40 -0
  510. package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
  511. package/src/providers/__tests__/retry-callsite.test.ts +67 -0
  512. package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
  513. package/src/providers/anthropic/client.ts +112 -95
  514. package/src/providers/connection-resolution.ts +35 -1
  515. package/src/providers/gemini/client.ts +5 -5
  516. package/src/providers/inference/adapter-factory.ts +16 -10
  517. package/src/providers/inference/auth.ts +16 -0
  518. package/src/providers/inference/connection-availability.ts +164 -12
  519. package/src/providers/inference/connections.ts +25 -1
  520. package/src/providers/media-resolve.ts +21 -11
  521. package/src/providers/model-catalog.ts +15 -0
  522. package/src/providers/openai/chat-completions-provider.ts +4 -4
  523. package/src/providers/openai/responses-provider.ts +12 -25
  524. package/src/providers/registry.ts +9 -4
  525. package/src/providers/retry.ts +25 -0
  526. package/src/providers/server-tool-pairing.ts +134 -0
  527. package/src/providers/speech-to-text/__tests__/resolve.test.ts +187 -6
  528. package/src/providers/speech-to-text/deepgram.ts +1 -0
  529. package/src/providers/speech-to-text/resolve.ts +80 -10
  530. package/src/providers/speech-to-text/vellum-managed.ts +7 -1
  531. package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
  532. package/src/providers/types.ts +26 -6
  533. package/src/providers/vellum-model-routing.ts +6 -7
  534. package/src/runtime/AGENTS.md +2 -0
  535. package/src/runtime/__tests__/agent-wake.test.ts +16 -16
  536. package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
  537. package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
  538. package/src/runtime/agent-wake.ts +63 -24
  539. package/src/runtime/assistant-event-hub.ts +87 -12
  540. package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
  541. package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
  542. package/src/runtime/auth/same-actor.ts +56 -8
  543. package/src/runtime/auth/scopes.ts +12 -0
  544. package/src/runtime/auth/types.ts +2 -0
  545. package/src/runtime/background-job-runner.ts +5 -27
  546. package/src/runtime/channel-readiness-service.ts +59 -3
  547. package/src/runtime/channel-readiness-types.ts +18 -0
  548. package/src/runtime/desktop-presence.ts +69 -0
  549. package/src/runtime/http-server.ts +12 -0
  550. package/src/runtime/local-actor-identity.ts +11 -9
  551. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  552. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  553. package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
  554. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
  555. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
  556. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
  557. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
  558. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
  559. package/src/runtime/routes/__tests__/plugins-routes.test.ts +173 -1
  560. package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
  561. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
  562. package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
  563. package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
  564. package/src/runtime/routes/archive-utils.ts +16 -12
  565. package/src/runtime/routes/attachment-routes.ts +13 -6
  566. package/src/runtime/routes/canned-reply-release.ts +54 -0
  567. package/src/runtime/routes/channel-verification-routes.ts +2 -27
  568. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
  569. package/src/runtime/routes/client-routes.ts +114 -2
  570. package/src/runtime/routes/conversation-cli-routes.ts +10 -12
  571. package/src/runtime/routes/conversation-list-routes.ts +59 -10
  572. package/src/runtime/routes/conversation-management-routes.ts +47 -18
  573. package/src/runtime/routes/conversation-query-routes.ts +32 -53
  574. package/src/runtime/routes/conversation-routes.ts +350 -293
  575. package/src/runtime/routes/credential-prompt-routes.ts +23 -2
  576. package/src/runtime/routes/debug-routes.ts +4 -1
  577. package/src/runtime/routes/default-provider-routes.ts +7 -11
  578. package/src/runtime/routes/documents-routes.ts +44 -1
  579. package/src/runtime/routes/events-routes.ts +28 -1
  580. package/src/runtime/routes/host-app-control-routes.ts +2 -0
  581. package/src/runtime/routes/host-bash-routes.ts +2 -0
  582. package/src/runtime/routes/host-browser-routes.ts +2 -0
  583. package/src/runtime/routes/host-cu-routes.ts +2 -0
  584. package/src/runtime/routes/host-file-routes.ts +2 -0
  585. package/src/runtime/routes/host-transfer-routes.ts +4 -0
  586. package/src/runtime/routes/identity-routes.ts +6 -6
  587. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  588. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
  589. package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
  590. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
  591. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
  592. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
  593. package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
  594. package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
  595. package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
  596. package/src/runtime/routes/inference-profiles-routes.ts +152 -73
  597. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
  598. package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
  599. package/src/runtime/routes/log-export-routes.ts +1 -1
  600. package/src/runtime/routes/notification-routes.ts +0 -14
  601. package/src/runtime/routes/oauth-providers.ts +1 -0
  602. package/src/runtime/routes/plugins-routes.ts +106 -1
  603. package/src/runtime/routes/profiler-routes.ts +4 -2
  604. package/src/runtime/routes/question-routes.ts +28 -10
  605. package/src/runtime/routes/retrospective-routes.ts +9 -3
  606. package/src/runtime/routes/schedule-routes.ts +210 -12
  607. package/src/runtime/routes/secret-routes.ts +40 -23
  608. package/src/runtime/routes/settings-routes.ts +41 -13
  609. package/src/runtime/routes/skills-routes.ts +79 -0
  610. package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
  611. package/src/runtime/routes/wake-conversation-routes.ts +23 -0
  612. package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
  613. package/src/runtime/services/conversation-serializer.ts +24 -9
  614. package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
  615. package/src/runtime/sync/resource-sync-events.ts +79 -1
  616. package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
  617. package/src/runtime/sync/worker-daemon-notify.ts +44 -6
  618. package/src/runtime/verification-outbound-actions.ts +250 -222
  619. package/src/runtime/verification-templates.ts +41 -30
  620. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
  621. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
  622. package/src/schedule/inference-profile.ts +64 -3
  623. package/src/schedule/plugin-schedule-declarations.ts +518 -0
  624. package/src/schedule/plugin-schedule-reconciler.ts +605 -0
  625. package/src/schedule/plugin-schedules-gate.ts +23 -0
  626. package/src/schedule/schedule-store.ts +520 -26
  627. package/src/schedule/scheduler.ts +38 -0
  628. package/src/security/credential-backend.ts +51 -4
  629. package/src/security/encrypted-store.ts +64 -42
  630. package/src/security/secure-keys.ts +55 -7
  631. package/src/skills/catalog-install.ts +20 -7
  632. package/src/skills/inline-command-runner.ts +2 -7
  633. package/src/skills/skill-history.test.ts +269 -0
  634. package/src/skills/skill-history.ts +250 -0
  635. package/src/skills/skillssh-registry.ts +1 -1
  636. package/src/stt/daemon-batch-transcriber.ts +8 -6
  637. package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
  638. package/src/subagent/consult-prompt.ts +3 -1
  639. package/src/subagent/consult-transcript.ts +1 -1
  640. package/src/subagent/manager.ts +295 -42
  641. package/src/subagent/progress-events.ts +35 -0
  642. package/src/subagent/role-resolution.ts +88 -0
  643. package/src/subagent/types.ts +302 -67
  644. package/src/subagent/validate-allowlists.ts +3 -4
  645. package/src/telegram/__tests__/webhook-health.test.ts +73 -1
  646. package/src/telegram/webhook-health.ts +101 -3
  647. package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
  648. package/src/telemetry/activation-funnel.ts +6 -1
  649. package/src/telemetry/live-voice-funnel.ts +75 -0
  650. package/src/telemetry/telemetry-event-sources.ts +6 -0
  651. package/src/telemetry/telemetry-wire-source.json +1 -1
  652. package/src/telemetry/telemetry-wire.generated.ts +2 -0
  653. package/src/telemetry/types.ts +23 -4
  654. package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
  655. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
  656. package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
  657. package/src/tools/ask-question/ask-question-tool.ts +56 -2
  658. package/src/tools/browser/browser-execution.ts +1 -1
  659. package/src/tools/calls/call-start.ts +8 -5
  660. package/src/tools/conversation-groups/move_to_group.ts +10 -12
  661. package/src/tools/document/document-tool.ts +11 -4
  662. package/src/tools/executor.ts +7 -6
  663. package/src/tools/filesystem/edit.ts +1 -1
  664. package/src/tools/filesystem/list.ts +1 -1
  665. package/src/tools/filesystem/read.ts +7 -13
  666. package/src/tools/filesystem/search.ts +23 -21
  667. package/src/tools/filesystem/write.ts +4 -1
  668. package/src/tools/host-filesystem/edit.ts +7 -2
  669. package/src/tools/host-filesystem/read.ts +21 -8
  670. package/src/tools/host-filesystem/write.ts +10 -2
  671. package/src/tools/host-terminal/host-shell.ts +2 -2
  672. package/src/tools/mcp/mcp-tool-factory.ts +25 -1
  673. package/src/tools/permission-checker.ts +8 -3
  674. package/src/tools/schedule/delete.ts +13 -1
  675. package/src/tools/schedule/list.ts +14 -3
  676. package/src/tools/schedule/update.ts +56 -33
  677. package/src/tools/shared/filesystem/audio-read.ts +6 -4
  678. package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
  679. package/src/tools/shared/filesystem/image-read.ts +12 -12
  680. package/src/tools/shared/filesystem/path-policy.ts +70 -5
  681. package/src/tools/shared/filesystem/size-guard.ts +6 -6
  682. package/src/tools/shared/input-misuse.ts +72 -0
  683. package/src/tools/skills/scaffold-managed.ts +82 -0
  684. package/src/tools/skills/skill-tool-factory.ts +14 -1
  685. package/src/tools/subagent/consult-deadline.ts +12 -7
  686. package/src/tools/subagent/message.ts +3 -1
  687. package/src/tools/subagent/read.ts +66 -4
  688. package/src/tools/subagent/spawn.ts +500 -78
  689. package/src/tools/types.ts +22 -3
  690. package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
  691. package/src/tools/ui-surface/visual-validation.ts +2 -0
  692. package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
  693. package/src/usage/subagent-attribution.ts +108 -0
  694. package/src/util/__tests__/sqlite-retry.test.ts +112 -0
  695. package/src/util/abort-reasons.ts +16 -0
  696. package/src/util/ansi.ts +44 -0
  697. package/src/util/disk-usage.ts +17 -13
  698. package/src/util/image-conversion.ts +20 -13
  699. package/src/util/schedule-source-key.ts +23 -0
  700. package/src/util/worker-process.ts +7 -1
  701. package/src/workspace/git-service.ts +33 -9
  702. package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
  703. package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
  704. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
  705. package/src/workspace/migrations/registry.ts +4 -0
  706. package/src/workspace/top-level-renderer.ts +15 -2
  707. package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
  708. package/src/daemon/install-symlink.ts +0 -207
  709. package/src/notifications/deferred-emit.ts +0 -147
@@ -13,7 +13,7 @@ import { tmpdir } from "node:os";
13
13
  import { join } from "node:path";
14
14
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
15
15
 
16
- import { createApp, deleteApp, getAppDirPath } from "../apps/app-store.js";
16
+ import { createApp, deleteApp } from "../apps/app-store.js";
17
17
  import {
18
18
  clearConversations,
19
19
  setConversation,
@@ -56,7 +56,7 @@ afterEach(() => {
56
56
  });
57
57
 
58
58
  describe("buildVisibleAppContext", () => {
59
- test("resolves the app's name, readable slug, and source directory", () => {
59
+ test("resolves the app's name and readable slug, without a host path", () => {
60
60
  // A workspace app id is an opaque UUID; the slug is the handle a human
61
61
  // (or the model) recognizes, so both have to come back.
62
62
  const app = createApp({
@@ -69,10 +69,27 @@ describe("buildVisibleAppContext", () => {
69
69
  appId: app.id,
70
70
  name: "Grocery List",
71
71
  slug: "grocery-list",
72
- sourceDir: getAppDirPath(app.id),
73
72
  });
74
73
  });
75
74
 
75
+ test("carries no resolved directory, only derivable handles", () => {
76
+ // Only derivable handles ship: a workspace app's directory is the
77
+ // workspace `Root:` joined with the app-builder skill's
78
+ // `data/apps/<slug>/` layout, so no value here may be an absolute path.
79
+ const app = createApp({
80
+ name: "Grocery List",
81
+ schemaJson: "{}",
82
+ htmlDefinition: "<h1>Hello</h1>",
83
+ });
84
+
85
+ const context = buildVisibleAppContext(app.id);
86
+
87
+ expect(context).not.toBeNull();
88
+ for (const value of Object.values(context ?? {})) {
89
+ expect(value.startsWith("/")).toBe(false);
90
+ }
91
+ });
92
+
76
93
  test("returns null when no app is in view", () => {
77
94
  expect(buildVisibleAppContext(undefined)).toBeNull();
78
95
  expect(buildVisibleAppContext("")).toBeNull();
@@ -109,7 +126,6 @@ describe("buildVisibleAppContext", () => {
109
126
  appId: "plugins~acme~acme-dashboard",
110
127
  name: "acme-dashboard",
111
128
  slug: "acme-dashboard",
112
- sourceDir: join(pluginDir, "apps", "acme-dashboard"),
113
129
  pluginName: "acme",
114
130
  });
115
131
  });
@@ -328,4 +328,100 @@ describe("stripHistoricalWebSearchResults", () => {
328
328
  const afterTypes = messages[0].content.map((b) => b.type);
329
329
  expect(afterTypes).toEqual(beforeTypes);
330
330
  });
331
+
332
+ test("drops the server_tool_use of a cross-message pair from a deferred execution", () => {
333
+ // Deferred execution places the web_search_tool_result at the head of the
334
+ // assistant message after the client tool round-trip. Both sides of the
335
+ // pair must go together, or the leftover server_tool_use reads as an
336
+ // orphan and gets a synthetic error result downstream.
337
+ const messages: Message[] = [
338
+ { role: "user", content: [{ type: "text", text: "Check both" }] },
339
+ {
340
+ role: "assistant",
341
+ content: [
342
+ { type: "text", text: "On it" },
343
+ { type: "tool_use", id: "tu_read", name: "file_read", input: {} },
344
+ {
345
+ type: "server_tool_use",
346
+ id: "stu_deferred",
347
+ name: "web_search",
348
+ input: { query: "deferred query" },
349
+ },
350
+ ],
351
+ },
352
+ {
353
+ role: "user",
354
+ content: [
355
+ { type: "tool_result", tool_use_id: "tu_read", content: "file" },
356
+ ],
357
+ },
358
+ {
359
+ role: "assistant",
360
+ content: [
361
+ {
362
+ type: "web_search_tool_result",
363
+ tool_use_id: "stu_deferred",
364
+ content: [
365
+ {
366
+ type: "web_search_result",
367
+ url: "https://example.com",
368
+ title: "Deferred",
369
+ encrypted_content: "tok",
370
+ },
371
+ ],
372
+ },
373
+ { type: "text", text: "Found it." },
374
+ ],
375
+ },
376
+ ];
377
+
378
+ const { messages: result, stats } =
379
+ stripHistoricalWebSearchResults(messages);
380
+
381
+ // The use in the earlier assistant message is dropped with its result
382
+ expect(result[1].content.map((b) => b.type)).toEqual(["text", "tool_use"]);
383
+ const summarized = result[3].content[0];
384
+ expect(summarized.type).toBe("text");
385
+ expect((summarized as { text: string }).text).toContain("deferred query");
386
+ expect((summarized as { text: string }).text).toContain(
387
+ "https://example.com",
388
+ );
389
+ expect(stats.serverToolUsesDropped).toBe(1);
390
+ expect(stats.blocksStripped).toBe(1);
391
+ expect(stats.messagesModified).toBe(2);
392
+ });
393
+
394
+ test("leaves a pending server_tool_use with no result anywhere untouched", () => {
395
+ // A resultless use at the tail is a deferred search the provider executes
396
+ // on this request; stripping it would cancel the search.
397
+ const messages: Message[] = [
398
+ { role: "user", content: [{ type: "text", text: "Check both" }] },
399
+ {
400
+ role: "assistant",
401
+ content: [
402
+ { type: "tool_use", id: "tu_read", name: "file_read", input: {} },
403
+ {
404
+ type: "server_tool_use",
405
+ id: "stu_pending",
406
+ name: "web_search",
407
+ input: { query: "pending" },
408
+ },
409
+ ],
410
+ },
411
+ {
412
+ role: "user",
413
+ content: [
414
+ { type: "tool_result", tool_use_id: "tu_read", content: "file" },
415
+ ],
416
+ },
417
+ ];
418
+
419
+ const { messages: result, stats } =
420
+ stripHistoricalWebSearchResults(messages);
421
+
422
+ expect(result).toEqual(messages);
423
+ expect(stats.serverToolUsesDropped).toBe(0);
424
+ expect(stats.blocksStripped).toBe(0);
425
+ expect(stats.messagesModified).toBe(0);
426
+ });
331
427
  });
@@ -51,15 +51,15 @@ afterEach(() => {
51
51
  });
52
52
 
53
53
  describe("139-clear-renamed-cost-profile-label migration", () => {
54
- test("has correct migration id and is registered last", () => {
54
+ test("has correct migration id and is registered", () => {
55
55
  expect(clearRenamedCostProfileLabelMigration.id).toBe(
56
56
  "139-clear-renamed-cost-profile-label",
57
57
  );
58
- // getLastWorkspaceMigrationId() reports the final entry as the registry
59
- // ceiling, so the highest id must stay last.
60
- expect(WORKSPACE_MIGRATIONS[WORKSPACE_MIGRATIONS.length - 1]?.id).toBe(
61
- "139-clear-renamed-cost-profile-label",
62
- );
58
+ expect(
59
+ WORKSPACE_MIGRATIONS.some(
60
+ (migration) => migration.id === "139-clear-renamed-cost-profile-label",
61
+ ),
62
+ ).toBe(true);
63
63
  });
64
64
 
65
65
  test("clears the seeded label so the code catalog label applies", () => {
@@ -0,0 +1,330 @@
1
+ /**
2
+ * Tests for workspace migration `140-repair-seed-pinned-memory-v3-live`.
3
+ *
4
+ * The pre-#39847 first-launch seed persisted `memory.v3.live = false` before
5
+ * migration 105 could record the real decision, stranding brand-new
6
+ * assistants on v2 and demoting existing v3 assistants whose config.json was
7
+ * quarantined and reseeded. The repair flips `live` back to true only for
8
+ * those two victim classes and never over a deliberate opt-out.
9
+ */
10
+
11
+ import {
12
+ existsSync,
13
+ mkdirSync,
14
+ mkdtempSync,
15
+ readFileSync,
16
+ rmSync,
17
+ writeFileSync,
18
+ } from "node:fs";
19
+ import { tmpdir } from "node:os";
20
+ import { join } from "node:path";
21
+ import { Database } from "bun:sqlite";
22
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
23
+
24
+ import { repairSeedPinnedMemoryV3LiveMigration } from "../workspace/migrations/140-repair-seed-pinned-memory-v3-live.js";
25
+ import { WORKSPACE_MIGRATIONS } from "../workspace/migrations/registry.js";
26
+ import type { MigrationRunContext } from "../workspace/migrations/types.js";
27
+
28
+ const NEW_WORKSPACE_CTX: MigrationRunContext = { isNewWorkspace: true };
29
+ const UPGRADE_CTX: MigrationRunContext = { isNewWorkspace: false };
30
+
31
+ let workspaceDir: string;
32
+ let configPath: string;
33
+
34
+ beforeEach(() => {
35
+ workspaceDir = mkdtempSync(join(tmpdir(), "vellum-migration-140-test-"));
36
+ configPath = join(workspaceDir, "config.json");
37
+ mkdirSync(join(workspaceDir, "data", "db"), { recursive: true });
38
+ });
39
+
40
+ afterEach(() => {
41
+ if (existsSync(workspaceDir)) {
42
+ rmSync(workspaceDir, { recursive: true, force: true });
43
+ }
44
+ });
45
+
46
+ function readConfig(): Record<string, unknown> {
47
+ return JSON.parse(readFileSync(configPath, "utf-8"));
48
+ }
49
+
50
+ function readLive(): unknown {
51
+ const memory = (readConfig().memory ?? {}) as Record<string, unknown>;
52
+ const v3 = (memory.v3 ?? {}) as Record<string, unknown>;
53
+ return v3.live;
54
+ }
55
+
56
+ function writeConfig(config: Record<string, unknown>): void {
57
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
58
+ }
59
+
60
+ /** A checkpoint file whose 105 entry ran `gapMs` after the earliest entry. */
61
+ function writeCheckpoints(gapMs: number): void {
62
+ const base = Date.parse("2026-06-20T12:00:00.000Z");
63
+ writeFileSync(
64
+ join(workspaceDir, "data", ".workspace-migrations.json"),
65
+ JSON.stringify(
66
+ {
67
+ applied: {
68
+ "001-avatar-rename": {
69
+ appliedAt: new Date(base).toISOString(),
70
+ status: "completed",
71
+ },
72
+ "105-enable-memory-v3-live-for-new-workspaces": {
73
+ appliedAt: new Date(base + gapMs).toISOString(),
74
+ status: "completed",
75
+ },
76
+ },
77
+ },
78
+ null,
79
+ 2,
80
+ ) + "\n",
81
+ );
82
+ }
83
+
84
+ const FIRST_BOOT_GAP_MS = 5_000;
85
+ const UPGRADE_SWEEP_GAP_MS = 30 * 24 * 60 * 60 * 1000;
86
+
87
+ function writeSelectionRows(file: string): void {
88
+ const db = new Database(join(workspaceDir, "data", "db", file));
89
+ db.exec(`
90
+ CREATE TABLE memory_v3_selections (
91
+ conversation_id TEXT NOT NULL,
92
+ turn INTEGER NOT NULL,
93
+ slug TEXT NOT NULL,
94
+ source TEXT NOT NULL,
95
+ pinned INTEGER NOT NULL DEFAULT 0
96
+ );
97
+ INSERT INTO memory_v3_selections (conversation_id, turn, slug, source)
98
+ VALUES ('conv-1', 1, 'some-page', 'needle');
99
+ `);
100
+ db.close();
101
+ }
102
+
103
+ describe("140-repair-seed-pinned-memory-v3-live migration", () => {
104
+ test("has correct id and is registered last", () => {
105
+ expect(repairSeedPinnedMemoryV3LiveMigration.id).toBe(
106
+ "140-repair-seed-pinned-memory-v3-live",
107
+ );
108
+ expect(repairSeedPinnedMemoryV3LiveMigration.description).toContain(
109
+ "memory.v3.live",
110
+ );
111
+ // getLastWorkspaceMigrationId() reports the final entry as the registry
112
+ // ceiling, so ordering matters: this must be registered, and everything
113
+ // after it must carry a higher id. Asserting it stays literally last
114
+ // would break on every migration appended after it.
115
+ const index = WORKSPACE_MIGRATIONS.findIndex(
116
+ (migration) => migration.id === "140-repair-seed-pinned-memory-v3-live",
117
+ );
118
+ expect(index).toBeGreaterThan(-1);
119
+ for (const later of WORKSPACE_MIGRATIONS.slice(index + 1)) {
120
+ expect(later.id > "140").toBe(true);
121
+ }
122
+ });
123
+
124
+ test("flips a seed-race victim: born in the 105 era, live=false, v3 never ran", () => {
125
+ writeConfig({
126
+ memory: { v2: { enabled: true }, v3: { live: false } },
127
+ llm: { activeProfile: "balanced" },
128
+ });
129
+ writeCheckpoints(FIRST_BOOT_GAP_MS);
130
+
131
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
132
+
133
+ expect(readLive()).toBe(true);
134
+ // The rest of the config is untouched.
135
+ const config = readConfig();
136
+ expect((config.llm as Record<string, unknown>).activeProfile).toBe(
137
+ "balanced",
138
+ );
139
+ expect(
140
+ ((config.memory as Record<string, unknown>).v2 as Record<string, unknown>)
141
+ .enabled,
142
+ ).toBe(true);
143
+ });
144
+
145
+ test("skips new workspaces so a hatch-time opt-out override wins", () => {
146
+ writeConfig({ memory: { v3: { live: false } } });
147
+ writeCheckpoints(FIRST_BOOT_GAP_MS);
148
+
149
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, NEW_WORKSPACE_CTX);
150
+
151
+ expect(readLive()).toBe(false);
152
+ });
153
+
154
+ test("leaves an absent leaf alone: pre-105 assistants stay on the manual-upgrade path", () => {
155
+ writeConfig({ memory: { v2: { enabled: true } } });
156
+ writeCheckpoints(UPGRADE_SWEEP_GAP_MS);
157
+
158
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
159
+
160
+ expect(readLive()).toBeUndefined();
161
+ });
162
+
163
+ test("leaves live=true alone (idempotent after its own repair)", () => {
164
+ writeConfig({ memory: { v3: { live: false } } });
165
+ writeCheckpoints(FIRST_BOOT_GAP_MS);
166
+
167
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
168
+ expect(readLive()).toBe(true);
169
+ const afterFirstRun = readFileSync(configPath, "utf-8");
170
+
171
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
172
+ expect(readFileSync(configPath, "utf-8")).toBe(afterFirstRun);
173
+ });
174
+
175
+ test("skips a live=false workspace that was NOT born in the 105 era", () => {
176
+ writeConfig({ memory: { v3: { live: false } } });
177
+ writeCheckpoints(UPGRADE_SWEEP_GAP_MS);
178
+
179
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
180
+
181
+ expect(readLive()).toBe(false);
182
+ });
183
+
184
+ test("skips when the checkpoint file is missing (no era evidence)", () => {
185
+ writeConfig({ memory: { v3: { live: false } } });
186
+
187
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
188
+
189
+ expect(readLive()).toBe(false);
190
+ });
191
+
192
+ test("respects a hatch-time opt-out recorded in the archived default overlay", () => {
193
+ writeConfig({ memory: { v3: { live: false } } });
194
+ writeCheckpoints(FIRST_BOOT_GAP_MS);
195
+ writeFileSync(
196
+ join(workspaceDir, "default-config.json"),
197
+ JSON.stringify({ memory: { v3: { live: false } } }, null, 2),
198
+ );
199
+
200
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
201
+
202
+ expect(readLive()).toBe(false);
203
+ });
204
+
205
+ test("an archived overlay without a memory.v3.live opt-out does not block repair", () => {
206
+ writeConfig({ memory: { v3: { live: false } } });
207
+ writeCheckpoints(FIRST_BOOT_GAP_MS);
208
+ writeFileSync(
209
+ join(workspaceDir, "default-config.json"),
210
+ JSON.stringify({ llm: { activeProfile: "balanced" } }, null, 2),
211
+ );
212
+
213
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
214
+
215
+ expect(readLive()).toBe(true);
216
+ });
217
+
218
+ test("respects a deliberate opt-out: v3 selection rows exist", () => {
219
+ writeConfig({ memory: { v3: { live: false } } });
220
+ writeCheckpoints(FIRST_BOOT_GAP_MS);
221
+ writeSelectionRows("assistant-memory.db");
222
+
223
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
224
+
225
+ expect(readLive()).toBe(false);
226
+ });
227
+
228
+ test("finds selection rows staged under the __relocating name mid-drain", () => {
229
+ writeConfig({ memory: { v3: { live: false } } });
230
+ writeCheckpoints(FIRST_BOOT_GAP_MS);
231
+ const db = new Database(join(workspaceDir, "data", "db", "assistant.db"));
232
+ db.exec(`
233
+ CREATE TABLE memory_v3_selections__relocating (
234
+ conversation_id TEXT NOT NULL,
235
+ turn INTEGER NOT NULL,
236
+ slug TEXT NOT NULL,
237
+ source TEXT NOT NULL
238
+ );
239
+ INSERT INTO memory_v3_selections__relocating
240
+ (conversation_id, turn, slug, source)
241
+ VALUES ('conv-1', 1, 'some-page', 'needle');
242
+ `);
243
+ db.close();
244
+
245
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
246
+
247
+ expect(readLive()).toBe(false);
248
+ });
249
+
250
+ test("finds selection rows in the pre-relocation assistant.db too", () => {
251
+ writeConfig({ memory: { v3: { live: false } } });
252
+ writeCheckpoints(FIRST_BOOT_GAP_MS);
253
+ writeSelectionRows("assistant.db");
254
+
255
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
256
+
257
+ expect(readLive()).toBe(false);
258
+ });
259
+
260
+ test("an empty selections table is not usage evidence", () => {
261
+ writeConfig({ memory: { v3: { live: false } } });
262
+ writeCheckpoints(FIRST_BOOT_GAP_MS);
263
+ const db = new Database(
264
+ join(workspaceDir, "data", "db", "assistant-memory.db"),
265
+ );
266
+ db.exec(
267
+ `CREATE TABLE memory_v3_selections (conversation_id TEXT, turn INTEGER)`,
268
+ );
269
+ db.close();
270
+
271
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
272
+
273
+ expect(readLive()).toBe(true);
274
+ });
275
+
276
+ test("quarantine carry-forward flips a demoted v3 assistant even with usage rows and an old workspace", () => {
277
+ writeConfig({ memory: { v3: { live: false } } });
278
+ writeCheckpoints(UPGRADE_SWEEP_GAP_MS);
279
+ writeSelectionRows("assistant-memory.db");
280
+ writeFileSync(
281
+ join(workspaceDir, "config.json.corrupt-2026-08-01T10-00-00.000Z.json"),
282
+ JSON.stringify({ memory: { v3: { live: true } } }, null, 2),
283
+ );
284
+
285
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
286
+
287
+ expect(readLive()).toBe(true);
288
+ });
289
+
290
+ test("salvages live=true from a truncated (unparseable) quarantined config", () => {
291
+ writeConfig({ memory: { v3: { live: false } } });
292
+ writeCheckpoints(UPGRADE_SWEEP_GAP_MS);
293
+ writeFileSync(
294
+ join(workspaceDir, "config.json.corrupt-2026-08-01T10-00-00.000Z.json"),
295
+ `{\n "memory": {\n "v3": {\n "live": true\n }\n },\n "llm": {\n "activeProf`,
296
+ );
297
+
298
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
299
+
300
+ expect(readLive()).toBe(true);
301
+ });
302
+
303
+ test("the NEWEST quarantined config wins", () => {
304
+ writeConfig({ memory: { v3: { live: false } } });
305
+ writeCheckpoints(UPGRADE_SWEEP_GAP_MS);
306
+ writeFileSync(
307
+ join(workspaceDir, "config.json.corrupt-2026-07-01T10-00-00.000Z.json"),
308
+ JSON.stringify({ memory: { v3: { live: true } } }),
309
+ );
310
+ writeFileSync(
311
+ join(workspaceDir, "config.json.corrupt-2026-08-01T10-00-00.000Z.json"),
312
+ JSON.stringify({ memory: { v3: { live: false } } }),
313
+ );
314
+
315
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
316
+
317
+ expect(readLive()).toBe(false);
318
+ });
319
+
320
+ test("no-ops when config.json is missing or corrupt", () => {
321
+ // Missing.
322
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
323
+ expect(existsSync(configPath)).toBe(false);
324
+
325
+ // Corrupt.
326
+ writeFileSync(configPath, "{ not json");
327
+ repairSeedPinnedMemoryV3LiveMigration.run(workspaceDir, UPGRADE_CTX);
328
+ expect(readFileSync(configPath, "utf-8")).toBe("{ not json");
329
+ });
330
+ });
@@ -6,15 +6,13 @@
6
6
  * `{"error":{"message":"..."}}`. This picks the most specific signal available:
7
7
  * a structured stderr error, else the last stderr line, else the ack message.
8
8
  *
9
- * Pure and dependency-free.
9
+ * Pure; the only dependency is the shared escape-sequence strip.
10
10
  */
11
11
 
12
- // CSI escape sequences (colour codes, cursor moves) that adapters interleave
13
- // with their log lines: ESC `[`, parameter/intermediate bytes, then final byte.
14
- const ANSI_ESCAPE = /\u001B\[[0-?]*[ -/]*[@-~]/g;
12
+ import { stripAnsiSequences } from "../util/ansi.js";
15
13
 
16
14
  export function deriveFailureError(ackMessage: string, stderr: string): string {
17
- const clean = stderr.replace(ANSI_ESCAPE, "").trim();
15
+ const clean = stripAnsiSequences(stderr).trim();
18
16
 
19
17
  // Most precise: a structured adapter error — prefer it over the ack.
20
18
  const jsonMessage = lastJsonErrorMessage(clean);
@@ -76,35 +76,37 @@ export function attachmentsToReferenceBlocks(
76
76
 
77
77
  export function attachmentsToContentBlocks(
78
78
  attachments: MessageAttachmentInput[],
79
- ): ContentBlock[] {
80
- return attachments.map((attachment) => {
81
- if (attachment.mimeType.toLowerCase().startsWith("image/")) {
82
- const { data, mediaType } = optimizeImageForTransport(
83
- attachment.data,
84
- attachment.mimeType,
85
- );
79
+ ): Promise<ContentBlock[]> {
80
+ return Promise.all(
81
+ attachments.map(async (attachment) => {
82
+ if (attachment.mimeType.toLowerCase().startsWith("image/")) {
83
+ const { data, mediaType } = await optimizeImageForTransport(
84
+ attachment.data,
85
+ attachment.mimeType,
86
+ );
87
+ return {
88
+ type: "image",
89
+ source: {
90
+ type: "base64",
91
+ media_type: mediaType,
92
+ data,
93
+ },
94
+ } as ContentBlock;
95
+ }
96
+
86
97
  return {
87
- type: "image",
98
+ type: "file",
88
99
  source: {
89
100
  type: "base64",
90
- media_type: mediaType,
91
- data,
101
+ media_type: attachment.mimeType,
102
+ data: attachment.data,
103
+ filename: attachment.filename,
92
104
  },
105
+ extracted_text: attachment.extractedText,
106
+ ...(attachment.id ? { _attachmentId: attachment.id } : {}),
93
107
  } as ContentBlock;
94
- }
95
-
96
- return {
97
- type: "file",
98
- source: {
99
- type: "base64",
100
- media_type: attachment.mimeType,
101
- data: attachment.data,
102
- filename: attachment.filename,
103
- },
104
- extracted_text: attachment.extractedText,
105
- ...(attachment.id ? { _attachmentId: attachment.id } : {}),
106
- } as ContentBlock;
107
- });
108
+ }),
109
+ );
108
110
  }
109
111
 
110
112
  /**
@@ -15,6 +15,7 @@
15
15
  * recover — so detection and repair of ordering drift live together as one unit.
16
16
  */
17
17
 
18
+ import { analyzeServerToolPairing } from "../../providers/server-tool-pairing.js";
18
19
  import type {
19
20
  ContentBlock,
20
21
  Message,
@@ -69,6 +70,10 @@ export function repairHistory(messages: Message[]): RepairResult {
69
70
  let pendingToolUseIds = new Set<string>();
70
71
  // tool_result blocks stripped from assistant messages, keyed by tool_use_id
71
72
  let recoveredResults = new Map<string, ToolResultContent>();
73
+ // Server-tool pairs can legitimately span messages (deferred execution) or
74
+ // sit unanswered at the tail (the provider runs the search on the next
75
+ // request), so orphanhood is judged against the whole list, not per message.
76
+ const serverToolPairing = analyzeServerToolPairing(messages);
72
77
 
73
78
  for (const [msgIndex, msg] of messages.entries()) {
74
79
  if (msg.role === "assistant") {
@@ -100,36 +105,32 @@ export function repairHistory(messages: Message[]): RepairResult {
100
105
  }
101
106
  }
102
107
 
103
- // Pair server-side tool blocks within the same assistant message.
104
- // Server tools (e.g. web_search) emit server_tool_use + matching
105
- // web_search_tool_result. Either side can go missing — the synthetic
106
- // result is inserted IMMEDIATELY AFTER the orphan server_tool_use (not
108
+ // Repair orphaned server-side tool blocks. Server tools (e.g.
109
+ // web_search) emit server_tool_use + matching web_search_tool_result;
110
+ // orphanhood comes from `serverToolPairing`, which resolves pairs
111
+ // across messages and exempts the deferred tail. The synthetic result
112
+ // is inserted IMMEDIATELY AFTER the orphan server_tool_use (not
107
113
  // appended to the end) so ensureToolPairing's split at tool_use
108
114
  // boundaries cannot separate the pair. An orphan
109
- // web_search_tool_result (no preceding server_tool_use) is downgraded
110
- // to text — Anthropic rejects the request otherwise.
111
- const serverToolIds = new Set(
112
- cleanedContent
113
- .filter(
114
- (b): b is ServerToolUseContent => b.type === "server_tool_use",
115
- )
116
- .map((b) => b.id),
117
- );
118
- const matchedServerIds = new Set(
119
- cleanedContent
120
- .filter((b) => b.type === "web_search_tool_result")
121
- .map((b) => (b as { tool_use_id: string }).tool_use_id),
122
- );
115
+ // web_search_tool_result with no use anywhere is downgraded to text.
116
+ // Anthropic rejects the request otherwise.
123
117
  const orphanedServerIds = new Set<string>();
124
- for (const id of serverToolIds) {
125
- if (!matchedServerIds.has(id)) {
126
- orphanedServerIds.add(id);
127
- }
128
- }
129
118
  const orphanedWebSearchResultIds = new Set<string>();
130
- for (const id of matchedServerIds) {
131
- if (!serverToolIds.has(id)) {
132
- orphanedWebSearchResultIds.add(id);
119
+ for (const b of cleanedContent) {
120
+ if (b.type === "server_tool_use") {
121
+ const id = (b as ServerToolUseContent).id;
122
+ if (
123
+ !serverToolPairing.resolvedPairIds.has(id) &&
124
+ !serverToolPairing.deferredUseIds.has(id)
125
+ ) {
126
+ orphanedServerIds.add(id);
127
+ }
128
+ }
129
+ if (b.type === "web_search_tool_result") {
130
+ const id = (b as { tool_use_id: string }).tool_use_id;
131
+ if (!serverToolPairing.resolvedPairIds.has(id)) {
132
+ orphanedWebSearchResultIds.add(id);
133
+ }
133
134
  }
134
135
  }
135
136