@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
@@ -100,8 +100,8 @@ describe("HEIC upload normalization wiring", () => {
100
100
  await initializeDb();
101
101
  }, 30_000);
102
102
 
103
- test("uploadAttachmentFromBytes stores a JPEG master for HEIC", () => {
104
- const stored = uploadAttachmentFromBytes(
103
+ test("uploadAttachmentFromBytes stores a JPEG master for HEIC", async () => {
104
+ const stored = await uploadAttachmentFromBytes(
105
105
  "IMG_5487.HEIC",
106
106
  "image/heic",
107
107
  HEIC_BYTES,
@@ -115,8 +115,8 @@ describe("HEIC upload normalization wiring", () => {
115
115
  expect(readFileSync(stagedPath!).equals(FAKE_JPEG)).toBe(true);
116
116
  });
117
117
 
118
- test("uploadAttachmentFromBytes leaves non-HEIC uploads verbatim", () => {
119
- const stored = uploadAttachmentFromBytes(
118
+ test("uploadAttachmentFromBytes leaves non-HEIC uploads verbatim", async () => {
119
+ const stored = await uploadAttachmentFromBytes(
120
120
  "photo.png",
121
121
  "image/png",
122
122
  HEIC_BYTES,
@@ -127,8 +127,8 @@ describe("HEIC upload normalization wiring", () => {
127
127
  expect(stored.sizeBytes).toBe(HEIC_BYTES.length);
128
128
  });
129
129
 
130
- test("uploadAttachment (base64) stores a JPEG master for HEIC", () => {
131
- const stored = uploadAttachment("IMG_1.heic", "image/heic", HEIC_B64);
130
+ test("uploadAttachment (base64) stores a JPEG master for HEIC", async () => {
131
+ const stored = await uploadAttachment("IMG_1.heic", "image/heic", HEIC_B64);
132
132
 
133
133
  expect(stored.originalFilename).toBe("IMG_1.jpg");
134
134
  expect(stored.mimeType).toBe("image/jpeg");
@@ -137,16 +137,20 @@ describe("HEIC upload normalization wiring", () => {
137
137
  expect(row?.dataBase64).toBe(FAKE_JPEG_B64);
138
138
  });
139
139
 
140
- test("uploadAttachment (base64) leaves non-HEIC uploads verbatim", () => {
141
- const stored = uploadAttachment("photo.png", "image/png", HEIC_B64);
140
+ test("uploadAttachment (base64) leaves non-HEIC uploads verbatim", async () => {
141
+ const stored = await uploadAttachment("photo.png", "image/png", HEIC_B64);
142
142
 
143
143
  expect(stored.originalFilename).toBe("photo.png");
144
144
  expect(stored.mimeType).toBe("image/png");
145
145
  expect(stored.sizeBytes).toBe(HEIC_BYTES.length);
146
146
  });
147
147
 
148
- test("uploadAttachment (base64) propagates a MIME-only sniff correction", () => {
149
- const stored = uploadAttachment("photo.png", "image/mislabeled", HEIC_B64);
148
+ test("uploadAttachment (base64) propagates a MIME-only sniff correction", async () => {
149
+ const stored = await uploadAttachment(
150
+ "photo.png",
151
+ "image/mislabeled",
152
+ HEIC_B64,
153
+ );
150
154
 
151
155
  // Corrected MIME is stored; filename and payload stay verbatim.
152
156
  expect(stored.originalFilename).toBe("photo.png");
@@ -163,7 +167,7 @@ describe("HEIC upload normalization wiring", () => {
163
167
  JSON.stringify([{ type: "text", text: "photos" }]),
164
168
  );
165
169
 
166
- const normalized = attachInlineAttachmentToMessage(
170
+ const normalized = await attachInlineAttachmentToMessage(
167
171
  msg.id,
168
172
  0,
169
173
  "IMG_2.HEIC",
@@ -176,7 +180,7 @@ describe("HEIC upload normalization wiring", () => {
176
180
 
177
181
  // Assistant-outbound attachments are stored verbatim: no normalizeImage
178
182
  // flag, no rewrite, even for HEIC content.
179
- const verbatim = attachInlineAttachmentToMessage(
183
+ const verbatim = await attachInlineAttachmentToMessage(
180
184
  msg.id,
181
185
  1,
182
186
  "IMG_3.HEIC",
@@ -65,8 +65,8 @@ function getLegacyConversationDirPath(
65
65
  describe("uploadAttachment", () => {
66
66
  beforeEach(resetTables);
67
67
 
68
- test("stores attachment and returns metadata", () => {
69
- const stored = uploadAttachment("chart.png", "image/png", "iVBORw0K");
68
+ test("stores attachment and returns metadata", async () => {
69
+ const stored = await uploadAttachment("chart.png", "image/png", "iVBORw0K");
70
70
 
71
71
  expect(stored.id).toBeDefined();
72
72
  expect(stored.originalFilename).toBe("chart.png");
@@ -76,16 +76,20 @@ describe("uploadAttachment", () => {
76
76
  expect(stored.createdAt).toBeGreaterThan(0);
77
77
  });
78
78
 
79
- test("keeps uploads staged until linked", () => {
80
- const stored = uploadAttachment("small.txt", "text/plain", "aGVsbG8=");
79
+ test("keeps uploads staged until linked", async () => {
80
+ const stored = await uploadAttachment(
81
+ "small.txt",
82
+ "text/plain",
83
+ "aGVsbG8=",
84
+ );
81
85
  const filePath = getFilePathForAttachment(stored.id);
82
86
 
83
87
  expect(filePath).toBeNull();
84
88
  expect(getAttachmentContent(stored.id)?.toString()).toBe("hello");
85
89
  });
86
90
 
87
- test("stores base64 in the DB row until linked", () => {
88
- const stored = uploadAttachment("test.txt", "text/plain", "dGVzdA==");
91
+ test("stores base64 in the DB row until linked", async () => {
92
+ const stored = await uploadAttachment("test.txt", "text/plain", "dGVzdA==");
89
93
 
90
94
  // Staged uploads keep the payload inline until they are attached to a message.
91
95
  const rawRow = rawGet<{ data_base64: string }>(
@@ -100,35 +104,43 @@ describe("uploadAttachment", () => {
100
104
  expect(row!.dataBase64).toBe("dGVzdA==");
101
105
  });
102
106
 
103
- test("classifies image MIME as image kind", () => {
104
- const stored = uploadAttachment("pic.jpg", "image/jpeg", "AAAA");
107
+ test("classifies image MIME as image kind", async () => {
108
+ const stored = await uploadAttachment("pic.jpg", "image/jpeg", "AAAA");
105
109
  expect(stored.kind).toBe("image");
106
110
  });
107
111
 
108
- test("classifies non-image MIME as document kind", () => {
109
- const stored = uploadAttachment("doc.pdf", "application/pdf", "JVBER");
112
+ test("classifies non-image MIME as document kind", async () => {
113
+ const stored = await uploadAttachment(
114
+ "doc.pdf",
115
+ "application/pdf",
116
+ "JVBER",
117
+ );
110
118
  expect(stored.kind).toBe("document");
111
119
  });
112
120
 
113
- test("generates unique IDs for each upload", () => {
114
- const a = uploadAttachment("a.txt", "text/plain", "AA==");
115
- const b = uploadAttachment("b.txt", "text/plain", "QQ==");
121
+ test("generates unique IDs for each upload", async () => {
122
+ const a = await uploadAttachment("a.txt", "text/plain", "AA==");
123
+ const b = await uploadAttachment("b.txt", "text/plain", "QQ==");
116
124
  expect(a.id).not.toBe(b.id);
117
125
  });
118
126
 
119
- test("computes sizeBytes from base64 correctly", () => {
127
+ test("computes sizeBytes from base64 correctly", async () => {
120
128
  // "hello" = "aGVsbG8=" (8 chars, 1 pad -> 5 bytes)
121
- const stored = uploadAttachment("hello.txt", "text/plain", "aGVsbG8=");
129
+ const stored = await uploadAttachment(
130
+ "hello.txt",
131
+ "text/plain",
132
+ "aGVsbG8=",
133
+ );
122
134
  expect(stored.sizeBytes).toBe(5);
123
135
  });
124
136
 
125
- test("does not deduplicate identical uploads before linking", () => {
126
- const first = uploadAttachment(
137
+ test("does not deduplicate identical uploads before linking", async () => {
138
+ const first = await uploadAttachment(
127
139
  "photo.png",
128
140
  "image/png",
129
141
  "iVBORw0KGgoAAAANSUh",
130
142
  );
131
- const second = uploadAttachment(
143
+ const second = await uploadAttachment(
132
144
  "photo.png",
133
145
  "image/png",
134
146
  "iVBORw0KGgoAAAANSUh",
@@ -136,13 +148,13 @@ describe("uploadAttachment", () => {
136
148
  expect(second.id).not.toBe(first.id);
137
149
  });
138
150
 
139
- test("does not deduplicate identical content when filenames differ", () => {
140
- const first = uploadAttachment(
151
+ test("does not deduplicate identical content when filenames differ", async () => {
152
+ const first = await uploadAttachment(
141
153
  "original.png",
142
154
  "image/png",
143
155
  "DUPECONTENT123",
144
156
  );
145
- const second = uploadAttachment(
157
+ const second = await uploadAttachment(
146
158
  "renamed.png",
147
159
  "image/png",
148
160
  "DUPECONTENT123",
@@ -150,45 +162,47 @@ describe("uploadAttachment", () => {
150
162
  expect(second.id).not.toBe(first.id);
151
163
  });
152
164
 
153
- test("does not deduplicate different content", () => {
154
- const first = uploadAttachment("a.txt", "text/plain", "CONTENTA");
155
- const second = uploadAttachment("b.txt", "text/plain", "CONTENTB");
165
+ test("does not deduplicate different content", async () => {
166
+ const first = await uploadAttachment("a.txt", "text/plain", "CONTENTA");
167
+ const second = await uploadAttachment("b.txt", "text/plain", "CONTENTB");
156
168
  expect(second.id).not.toBe(first.id);
157
169
  });
158
170
 
159
- test("rejects payloads exceeding MAX_UPLOAD_BYTES", () => {
171
+ test("rejects payloads exceeding MAX_UPLOAD_BYTES", async () => {
160
172
  // Build a base64 string that decodes to just over the limit.
161
173
  // 4 base64 chars -> 3 bytes, so we need ceil((MAX_UPLOAD_BYTES+1)/3)*4 chars.
162
174
  const oversizedLength = Math.ceil((MAX_UPLOAD_BYTES + 1) / 3) * 4;
163
175
  const oversizedData = "A".repeat(oversizedLength);
164
176
 
165
- expect(() =>
177
+ await expect(
166
178
  uploadAttachment("huge.bin", "application/octet-stream", oversizedData),
167
- ).toThrow(AttachmentUploadError);
179
+ ).rejects.toThrow(AttachmentUploadError);
168
180
  });
169
181
 
170
- test("rejects invalid base64 data", () => {
171
- expect(() =>
182
+ test("rejects invalid base64 data", async () => {
183
+ await expect(
172
184
  uploadAttachment("bad.txt", "text/plain", "!!!not-base64!!!"),
173
- ).toThrow(AttachmentUploadError);
185
+ ).rejects.toThrow(AttachmentUploadError);
174
186
  });
175
187
 
176
- test("accepts base64 with non-standard padding/length", () => {
188
+ test("accepts base64 with non-standard padding/length", async () => {
177
189
  // Lenient on length -- only character set is validated
178
- expect(() => uploadAttachment("ok.txt", "text/plain", "AAA")).not.toThrow();
190
+ await expect(
191
+ uploadAttachment("ok.txt", "text/plain", "AAA"),
192
+ ).resolves.toBeDefined();
179
193
  });
180
194
 
181
195
  // Inserting the 100 MB payload into SQLite can take several seconds on
182
196
  // slow CI runners, so this test needs more than the default 5s timeout.
183
- test("accepts payload exactly at MAX_UPLOAD_BYTES", () => {
197
+ test("accepts payload exactly at MAX_UPLOAD_BYTES", async () => {
184
198
  // MAX_UPLOAD_BYTES (100 MB) is divisible by 3, so (MAX/3)*4 base64 chars
185
199
  // decodes to exactly MAX bytes with no padding.
186
200
  const exactLength = (MAX_UPLOAD_BYTES / 3) * 4;
187
201
  const exactData = "A".repeat(exactLength);
188
202
 
189
- expect(() =>
203
+ await expect(
190
204
  uploadAttachment("exact.bin", "application/octet-stream", exactData),
191
- ).not.toThrow();
205
+ ).resolves.toBeDefined();
192
206
  }, 30_000);
193
207
  });
194
208
 
@@ -199,8 +213,12 @@ describe("uploadAttachment", () => {
199
213
  describe("getAttachmentContent", () => {
200
214
  beforeEach(resetTables);
201
215
 
202
- test("returns staged content before the attachment is linked", () => {
203
- const stored = uploadAttachment("hello.txt", "text/plain", "aGVsbG8=");
216
+ test("returns staged content before the attachment is linked", async () => {
217
+ const stored = await uploadAttachment(
218
+ "hello.txt",
219
+ "text/plain",
220
+ "aGVsbG8=",
221
+ );
204
222
  const content = getAttachmentContent(stored.id);
205
223
 
206
224
  expect(content).not.toBeNull();
@@ -215,7 +233,7 @@ describe("getAttachmentContent", () => {
215
233
  test("returns null when a materialized on-disk file is missing (ENOENT)", async () => {
216
234
  const conv = createConversation();
217
235
  const msg = await addMessage(conv.id, "assistant", "File");
218
- const stored = uploadAttachment("test.txt", "text/plain", "dGVzdA==");
236
+ const stored = await uploadAttachment("test.txt", "text/plain", "dGVzdA==");
219
237
  linkAttachmentToMessage(msg.id, stored.id, 0);
220
238
  const filePath = getFilePathForAttachment(stored.id);
221
239
 
@@ -259,8 +277,8 @@ describe("isValidBase64", () => {
259
277
  describe("deleteAttachment", () => {
260
278
  beforeEach(resetTables);
261
279
 
262
- test("deletes existing attachment and returns deleted", () => {
263
- const stored = uploadAttachment("file.txt", "text/plain", "dGVzdA==");
280
+ test("deletes existing attachment and returns deleted", async () => {
281
+ const stored = await uploadAttachment("file.txt", "text/plain", "dGVzdA==");
264
282
  const result = deleteAttachment(stored.id);
265
283
  expect(result).toBe("deleted");
266
284
 
@@ -271,7 +289,11 @@ describe("deleteAttachment", () => {
271
289
  test("cleans up on-disk file when deleting", async () => {
272
290
  const conv = createConversation();
273
291
  const msg = await addMessage(conv.id, "assistant", "cleanup");
274
- const stored = uploadAttachment("cleanup.txt", "text/plain", "dGVzdA==");
292
+ const stored = await uploadAttachment(
293
+ "cleanup.txt",
294
+ "text/plain",
295
+ "dGVzdA==",
296
+ );
275
297
  linkAttachmentToMessage(msg.id, stored.id, 0);
276
298
  const filePath = getFilePathForAttachment(stored.id);
277
299
  expect(existsSync(filePath!)).toBe(true);
@@ -296,7 +318,11 @@ describe("deleteAttachment", () => {
296
318
  const msg1 = await addMessage(conv.id, "user", "First upload");
297
319
  const msg2 = await addMessage(conv.id, "user", "Duplicate upload");
298
320
 
299
- const first = uploadAttachment("photo.png", "image/png", "SHAREDCONTENT1");
321
+ const first = await uploadAttachment(
322
+ "photo.png",
323
+ "image/png",
324
+ "SHAREDCONTENT1",
325
+ );
300
326
  linkAttachmentToMessage(msg1.id, first.id, 0);
301
327
  linkAttachmentToMessage(msg2.id, first.id, 0);
302
328
 
@@ -315,8 +341,12 @@ describe("deleteAttachment", () => {
315
341
  expect(linked2).toHaveLength(1);
316
342
  });
317
343
 
318
- test("deletes attachment when no messages reference it", () => {
319
- const stored = uploadAttachment("lonely.txt", "text/plain", "UNREFERENCED");
344
+ test("deletes attachment when no messages reference it", async () => {
345
+ const stored = await uploadAttachment(
346
+ "lonely.txt",
347
+ "text/plain",
348
+ "UNREFERENCED",
349
+ );
320
350
  // No linkAttachmentToMessage call -- zero references
321
351
  const result = deleteAttachment(stored.id);
322
352
  expect(result).toBe("deleted");
@@ -333,9 +363,9 @@ describe("deleteAttachment", () => {
333
363
  describe("getAttachmentsByIds", () => {
334
364
  beforeEach(resetTables);
335
365
 
336
- test("returns matching attachments with hydrated dataBase64", () => {
337
- const a = uploadAttachment("a.txt", "text/plain", "AAAA");
338
- const b = uploadAttachment("b.txt", "text/plain", "BBBB");
366
+ test("returns matching attachments with hydrated dataBase64", async () => {
367
+ const a = await uploadAttachment("a.txt", "text/plain", "AAAA");
368
+ const b = await uploadAttachment("b.txt", "text/plain", "BBBB");
339
369
 
340
370
  const results = getAttachmentsByIds([a.id, b.id], {
341
371
  hydrateFileData: true,
@@ -350,8 +380,8 @@ describe("getAttachmentsByIds", () => {
350
380
  expect(results).toHaveLength(0);
351
381
  });
352
382
 
353
- test("skips IDs that do not exist", () => {
354
- const a = uploadAttachment("a.txt", "text/plain", "AAAA");
383
+ test("skips IDs that do not exist", async () => {
384
+ const a = await uploadAttachment("a.txt", "text/plain", "AAAA");
355
385
  const results = getAttachmentsByIds([a.id, "nonexistent"]);
356
386
  expect(results).toHaveLength(1);
357
387
  });
@@ -364,8 +394,12 @@ describe("getAttachmentsByIds", () => {
364
394
  describe("getAttachmentById", () => {
365
395
  beforeEach(resetTables);
366
396
 
367
- test("returns attachment with hydrated dataBase64 when found", () => {
368
- const stored = uploadAttachment("report.pdf", "application/pdf", "JVBER");
397
+ test("returns attachment with hydrated dataBase64 when found", async () => {
398
+ const stored = await uploadAttachment(
399
+ "report.pdf",
400
+ "application/pdf",
401
+ "JVBER",
402
+ );
369
403
  const result = getAttachmentById(stored.id, { hydrateFileData: true });
370
404
 
371
405
  expect(result).not.toBeNull();
@@ -392,7 +426,7 @@ describe("createInlineAttachment (workspace_ref persistence)", () => {
392
426
  const msg = await addMessage(conv.id, "user", "hi");
393
427
 
394
428
  // "aGVsbG8=" = "hello"
395
- const stored = createInlineAttachment(
429
+ const stored = await createInlineAttachment(
396
430
  conv.id,
397
431
  conv.createdAt,
398
432
  "note.txt",
@@ -431,14 +465,14 @@ describe("attachInlineAttachmentToMessage filename collisions", () => {
431
465
  const msg2 = await addMessage(conv.id, "user", "re-upload after editing");
432
466
 
433
467
  // "aGVsbG8=" = "hello", "d29ybGQ=" = "world"
434
- const first = attachInlineAttachmentToMessage(
468
+ const first = await attachInlineAttachmentToMessage(
435
469
  msg1.id,
436
470
  0,
437
471
  "report.csv",
438
472
  "text/csv",
439
473
  "aGVsbG8=",
440
474
  );
441
- const second = attachInlineAttachmentToMessage(
475
+ const second = await attachInlineAttachmentToMessage(
442
476
  msg2.id,
443
477
  0,
444
478
  "report.csv",
@@ -463,7 +497,7 @@ describe("linkAttachmentToMessage + getAttachmentsForMessage", () => {
463
497
  test("links attachment and retrieves it by message", async () => {
464
498
  const conv = createConversation();
465
499
  const msg = await addMessage(conv.id, "assistant", "Here is a chart");
466
- const stored = uploadAttachment("chart.png", "image/png", "iVBORw0K");
500
+ const stored = await uploadAttachment("chart.png", "image/png", "iVBORw0K");
467
501
 
468
502
  linkAttachmentToMessage(msg.id, stored.id, 0);
469
503
 
@@ -482,7 +516,11 @@ describe("linkAttachmentToMessage + getAttachmentsForMessage", () => {
482
516
  const legacyDir = getLegacyConversationDirPath(conv.id, conv.createdAt);
483
517
  rmSync(legacyDir, { recursive: true, force: true });
484
518
 
485
- const stored = uploadAttachment("repaired.png", "image/png", "iVBORw0K");
519
+ const stored = await uploadAttachment(
520
+ "repaired.png",
521
+ "image/png",
522
+ "iVBORw0K",
523
+ );
486
524
  linkAttachmentToMessage(msg.id, stored.id, 0);
487
525
 
488
526
  const filePath = getFilePathForAttachment(stored.id);
@@ -501,7 +539,11 @@ describe("linkAttachmentToMessage + getAttachmentsForMessage", () => {
501
539
  rmSync(canonicalDir, { recursive: true, force: true });
502
540
  mkdirSync(legacyDir, { recursive: true });
503
541
 
504
- const stored = uploadAttachment("legacy.png", "image/png", "iVBORw0K");
542
+ const stored = await uploadAttachment(
543
+ "legacy.png",
544
+ "image/png",
545
+ "iVBORw0K",
546
+ );
505
547
  linkAttachmentToMessage(msg.id, stored.id, 0);
506
548
 
507
549
  const filePath = getFilePathForAttachment(stored.id);
@@ -514,8 +556,8 @@ describe("linkAttachmentToMessage + getAttachmentsForMessage", () => {
514
556
  test("returns attachments in position order", async () => {
515
557
  const conv = createConversation();
516
558
  const msg = await addMessage(conv.id, "assistant", "Multiple files");
517
- const a = uploadAttachment("first.txt", "text/plain", "AAAA");
518
- const b = uploadAttachment("second.txt", "text/plain", "BBBB");
559
+ const a = await uploadAttachment("first.txt", "text/plain", "AAAA");
560
+ const b = await uploadAttachment("second.txt", "text/plain", "BBBB");
519
561
 
520
562
  // Link in reverse order
521
563
  linkAttachmentToMessage(msg.id, b.id, 1);
@@ -543,8 +585,12 @@ describe("linkAttachmentToMessage + getAttachmentsForMessage", () => {
543
585
  describe("deleteOrphanAttachments", () => {
544
586
  beforeEach(resetTables);
545
587
 
546
- test("removes candidate attachments with no message links", () => {
547
- const stored = uploadAttachment("orphan.txt", "text/plain", "ZGF0YQ==");
588
+ test("removes candidate attachments with no message links", async () => {
589
+ const stored = await uploadAttachment(
590
+ "orphan.txt",
591
+ "text/plain",
592
+ "ZGF0YQ==",
593
+ );
548
594
 
549
595
  const removed = deleteOrphanAttachments([stored.id]);
550
596
  expect(removed).toBe(1);
@@ -553,7 +599,11 @@ describe("deleteOrphanAttachments", () => {
553
599
  test("cleans up on-disk files when removing orphaned materialized attachments", async () => {
554
600
  const conv = createConversation();
555
601
  const msg = await addMessage(conv.id, "assistant", "Orphan me");
556
- const stored = uploadAttachment("orphan.txt", "text/plain", "ZGF0YQ==");
602
+ const stored = await uploadAttachment(
603
+ "orphan.txt",
604
+ "text/plain",
605
+ "ZGF0YQ==",
606
+ );
557
607
  linkAttachmentToMessage(msg.id, stored.id, 0);
558
608
  const filePath = getFilePathForAttachment(stored.id);
559
609
  expect(existsSync(filePath!)).toBe(true);
@@ -571,7 +621,11 @@ describe("deleteOrphanAttachments", () => {
571
621
  test("preserves attachments that are still linked", async () => {
572
622
  const conv = createConversation();
573
623
  const msg = await addMessage(conv.id, "assistant", "With attachment");
574
- const stored = uploadAttachment("linked.txt", "text/plain", "ZGF0YQ==");
624
+ const stored = await uploadAttachment(
625
+ "linked.txt",
626
+ "text/plain",
627
+ "ZGF0YQ==",
628
+ );
575
629
  linkAttachmentToMessage(msg.id, stored.id, 0);
576
630
 
577
631
  const removed = deleteOrphanAttachments([stored.id]);
@@ -584,8 +638,8 @@ describe("deleteOrphanAttachments", () => {
584
638
  test("removes only orphans when mixed candidates provided", async () => {
585
639
  const conv = createConversation();
586
640
  const msg = await addMessage(conv.id, "assistant", "Mixed");
587
- const linked = uploadAttachment("linked.txt", "text/plain", "AAAA");
588
- const orphan = uploadAttachment("orphan.txt", "text/plain", "BBBB");
641
+ const linked = await uploadAttachment("linked.txt", "text/plain", "AAAA");
642
+ const orphan = await uploadAttachment("orphan.txt", "text/plain", "BBBB");
589
643
  linkAttachmentToMessage(msg.id, linked.id, 0);
590
644
 
591
645
  const removed = deleteOrphanAttachments([linked.id, orphan.id]);
@@ -600,9 +654,17 @@ describe("deleteOrphanAttachments", () => {
600
654
  expect(removed).toBe(0);
601
655
  });
602
656
 
603
- test("does not delete attachments outside the candidate set", () => {
604
- const unrelated = uploadAttachment("unrelated.txt", "text/plain", "AAAA");
605
- const candidate = uploadAttachment("candidate.txt", "text/plain", "BBBB");
657
+ test("does not delete attachments outside the candidate set", async () => {
658
+ const unrelated = await uploadAttachment(
659
+ "unrelated.txt",
660
+ "text/plain",
661
+ "AAAA",
662
+ );
663
+ const candidate = await uploadAttachment(
664
+ "candidate.txt",
665
+ "text/plain",
666
+ "BBBB",
667
+ );
606
668
 
607
669
  const removed = deleteOrphanAttachments([candidate.id]);
608
670
  expect(removed).toBe(1);