@vellumai/assistant 0.11.6 → 0.11.7-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 (447) hide show
  1. package/ARCHITECTURE.md +31 -19
  2. package/Dockerfile +1 -0
  3. package/docs/architecture/security.md +3 -3
  4. package/docs/flux-turn-detection-spike.md +8 -7
  5. package/docs/runbook-trusted-contacts.md +14 -0
  6. package/docs/stt-provider-onboarding.md +8 -4
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/avatar-manifest/package.json +18 -0
  9. package/node_modules/@vellumai/avatar-manifest/src/__tests__/manifest.test.ts +173 -0
  10. package/node_modules/@vellumai/avatar-manifest/src/__tests__/read.test.ts +114 -0
  11. package/node_modules/@vellumai/avatar-manifest/src/index.ts +29 -0
  12. package/node_modules/@vellumai/avatar-manifest/src/layout.ts +18 -0
  13. package/node_modules/@vellumai/avatar-manifest/src/manifest.ts +156 -0
  14. package/node_modules/@vellumai/avatar-manifest/src/read.ts +109 -0
  15. package/node_modules/@vellumai/avatar-manifest/tsconfig.json +20 -0
  16. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
  17. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
  18. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
  19. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
  20. package/node_modules/@vellumai/environments/package.json +2 -1
  21. package/node_modules/@vellumai/environments/src/shell.test.ts +56 -0
  22. package/node_modules/@vellumai/environments/src/shell.ts +65 -0
  23. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
  24. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
  25. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
  26. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
  27. package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +32 -0
  28. package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +1 -0
  29. package/node_modules/@vellumai/gateway-client/src/__tests__/inbound-event-kind.test.ts +82 -0
  30. package/node_modules/@vellumai/gateway-client/src/__tests__/plugin-admission-denied-contract.test.ts +56 -0
  31. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +18 -0
  32. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +5 -11
  33. package/node_modules/@vellumai/gateway-client/src/channel-permission-contract.ts +3 -1
  34. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +9 -0
  35. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +4 -0
  36. package/node_modules/@vellumai/gateway-client/src/inbound-event-kind.ts +75 -0
  37. package/node_modules/@vellumai/gateway-client/src/index.ts +17 -0
  38. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +8 -0
  39. package/node_modules/@vellumai/gateway-client/src/plugin-admission-denied-contract.ts +47 -0
  40. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +11 -0
  41. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
  42. package/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
  43. package/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
  44. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
  45. package/openapi.yaml +419 -55
  46. package/package.json +4 -1
  47. package/src/__tests__/approval-card-edit-inbound-handoff.test.ts +199 -0
  48. package/src/__tests__/approval-card-edit.test.ts +153 -0
  49. package/src/__tests__/attachments-store-heic-normalize.test.ts +1 -1
  50. package/src/__tests__/available-skills.test.ts +54 -0
  51. package/src/__tests__/avatar-identity-sync.test.ts +5 -1
  52. package/src/__tests__/catalog-install-normalize.test.ts +9 -1
  53. package/src/__tests__/channel-policy.test.ts +1 -3
  54. package/src/__tests__/channel-readiness-discord.test.ts +9 -70
  55. package/src/__tests__/compactor-call-site-logging.test.ts +61 -0
  56. package/src/__tests__/config-loader-backfill.test.ts +69 -0
  57. package/src/__tests__/config-schema.test.ts +2 -3
  58. package/src/__tests__/conversation-agent-loop.test.ts +238 -0
  59. package/src/__tests__/conversation-attachments.test.ts +0 -1
  60. package/src/__tests__/conversation-error.test.ts +44 -0
  61. package/src/__tests__/conversation-evictor.test.ts +19 -0
  62. package/src/__tests__/conversation-fork-referential.test.ts +73 -63
  63. package/src/__tests__/conversation-fork-retrospective.test.ts +99 -74
  64. package/src/__tests__/conversation-runtime-assembly.test.ts +23 -0
  65. package/src/__tests__/conversation-slash.test.ts +9 -0
  66. package/src/__tests__/conversation-title-service.test.ts +97 -0
  67. package/src/__tests__/conversation-tool-setup-attribution.test.ts +16 -0
  68. package/src/__tests__/credential-broker-server-use.test.ts +0 -218
  69. package/src/__tests__/credential-broker.test.ts +43 -420
  70. package/src/__tests__/credential-routes.test.ts +17 -1
  71. package/src/__tests__/credential-security-invariants.test.ts +8 -9
  72. package/src/__tests__/default-profile-catalog-fallback.test.ts +289 -0
  73. package/src/__tests__/discord-callback-round-trip.test.ts +93 -0
  74. package/src/__tests__/discord-channel-config.test.ts +237 -0
  75. package/src/__tests__/evict-conversations-for-reload.test.ts +51 -1
  76. package/src/__tests__/fallback-breaker.test.ts +1335 -0
  77. package/src/__tests__/gateway-threshold-reader-mock.ts +6 -0
  78. package/src/__tests__/guardian-card-withdrawal.test.ts +30 -0
  79. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -2
  80. package/src/__tests__/image-conversion.test.ts +38 -4
  81. package/src/__tests__/install-skill-routing.test.ts +25 -0
  82. package/src/__tests__/llm-resolver.test.ts +74 -0
  83. package/src/__tests__/llm-schema-fallback-profile.test.ts +359 -0
  84. package/src/__tests__/managed-fallback-dispatch.test.ts +430 -0
  85. package/src/__tests__/managed-profile-guard.test.ts +28 -0
  86. package/src/__tests__/managed-speech-defaults.test.ts +196 -1
  87. package/src/__tests__/mcp-cli.test.ts +23 -1
  88. package/src/__tests__/mcp-tool-annotations-risk.test.ts +43 -34
  89. package/src/__tests__/media-stream-stt-session.test.ts +2 -0
  90. package/src/__tests__/notification-decision-fallback.test.ts +106 -0
  91. package/src/__tests__/notification-discord-adapter.test.ts +162 -0
  92. package/src/__tests__/persist-unsendable-image-downscale.test.ts +6 -8
  93. package/src/__tests__/persist-unsendable-image.test.ts +3 -3
  94. package/src/__tests__/platform.test.ts +19 -1
  95. package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
  96. package/src/__tests__/provider-usage-tracking.test.ts +56 -0
  97. package/src/__tests__/require-fresh-approval.test.ts +5 -2
  98. package/src/__tests__/retry-fallback-escalation.test.ts +1093 -0
  99. package/src/__tests__/schedule-retry.test.ts +183 -4
  100. package/src/__tests__/scheduler-reuse-conversation.test.ts +6 -6
  101. package/src/__tests__/secret-routes-platform-proxy.test.ts +55 -0
  102. package/src/__tests__/skill-load-tool.test.ts +34 -0
  103. package/src/__tests__/skill-tool-factory.test.ts +6 -1
  104. package/src/__tests__/skill-tool-manifest.test.ts +20 -0
  105. package/src/__tests__/skills.test.ts +25 -0
  106. package/src/__tests__/subagent-manager-notify.test.ts +38 -0
  107. package/src/__tests__/terminal-tools.test.ts +2 -0
  108. package/src/__tests__/tool-approval-handler.test.ts +146 -2
  109. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +108 -2
  110. package/src/__tests__/tool-audit.test.ts +111 -40
  111. package/src/__tests__/tool-executor-lifecycle-events.test.ts +228 -18
  112. package/src/__tests__/ui-shape-teaching.test.ts +1 -1
  113. package/src/__tests__/verification-control-plane-policy.test.ts +6 -2
  114. package/src/__tests__/voice-config-update.test.ts +43 -0
  115. package/src/__tests__/workspace-migration-147-rename-colliding-backup-profile-names.test.ts +480 -0
  116. package/src/__tests__/workspace-migration-148-strip-unsupported-fallback-profiles.test.ts +167 -0
  117. package/src/__tests__/workspace-migration-149-repoint-backup-profile-selections.test.ts +144 -0
  118. package/src/agent/loop.ts +31 -2
  119. package/src/approvals/guardian-card-withdrawal.ts +22 -0
  120. package/src/avatar/__tests__/ensure-raster.test.ts +291 -0
  121. package/src/avatar/avatar-manifest.ts +48 -100
  122. package/src/avatar/avatar-store.ts +7 -7
  123. package/src/avatar/ensure-raster.ts +146 -0
  124. package/src/avatar/resvg-lazy.test.ts +0 -1
  125. package/src/avatar/traits-png-sync.ts +9 -10
  126. package/src/background-wake/wake-intent-hooks.test.ts +0 -1
  127. package/src/backup/__tests__/paths.test.ts +6 -2
  128. package/src/backup/paths.ts +6 -4
  129. package/src/bundler/app-compiler.ts +2 -2
  130. package/src/bundler/compiler-tools.test.ts +36 -0
  131. package/src/bundler/compiler-tools.ts +54 -18
  132. package/src/calls/__tests__/telephony-synthesis-language.test.ts +81 -0
  133. package/src/calls/__tests__/voice-session-bridge.test.ts +20 -0
  134. package/src/calls/media-stream-stt-session.ts +2 -1
  135. package/src/calls/telephony-synthesis-language.ts +13 -5
  136. package/src/calls/voice-session-bridge.ts +6 -4
  137. package/src/channels/config.ts +23 -12
  138. package/src/cli/AGENTS.md +3 -1
  139. package/src/cli/commands/backup.help.ts +10 -13
  140. package/src/cli/commands/contacts.help.ts +16 -4
  141. package/src/cli/commands/contacts.ts +5 -1
  142. package/src/cli/commands/credentials.help.ts +1 -1
  143. package/src/cli/commands/inference-providers.ts +18 -53
  144. package/src/cli/commands/mcp.help.ts +6 -5
  145. package/src/cli/commands/mcp.ts +1 -1
  146. package/src/cli/commands/memory/memory-retrospective.ts +1 -0
  147. package/src/cli/commands/stt.help.ts +2 -2
  148. package/src/config/__tests__/backup-schema.test.ts +1 -1
  149. package/src/config/__tests__/default-profile-catalog.test.ts +83 -2
  150. package/src/config/__tests__/loader-sparse-array-cleanup.test.ts +1 -1
  151. package/src/config/__tests__/memory-retrospective-schema.test.ts +12 -15
  152. package/src/config/bundled-skills/computer-use/SKILL.md +6 -6
  153. package/src/config/bundled-skills/computer-use/TOOLS.json +9 -6
  154. package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +3 -1
  155. package/src/config/bundled-skills/media-processing/services/preprocess.ts +1 -1
  156. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
  157. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +16 -15
  158. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +2 -1
  159. package/src/config/bundled-skills/settings/TOOLS.json +11 -5
  160. package/src/config/bundled-skills/settings/tools/open-system-settings.test.ts +85 -0
  161. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +33 -8
  162. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +54 -3
  163. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +1 -1
  164. package/src/config/default-profile-catalog.ts +195 -10
  165. package/src/config/default-profile-names.ts +41 -0
  166. package/src/config/feature-flag-registry.json +18 -2
  167. package/src/config/inference-profile-validation.ts +11 -2
  168. package/src/config/llm-resolver.ts +25 -0
  169. package/src/config/loader.ts +3 -0
  170. package/src/config/managed-speech-defaults.ts +160 -10
  171. package/src/config/schema.ts +2 -0
  172. package/src/config/schemas/__tests__/live-voice.test.ts +7 -6
  173. package/src/config/schemas/__tests__/stt.test.ts +94 -0
  174. package/src/config/schemas/backup.ts +1 -1
  175. package/src/config/schemas/channels.ts +32 -0
  176. package/src/config/schemas/live-voice.ts +13 -4
  177. package/src/config/schemas/llm.ts +259 -11
  178. package/src/config/schemas/mcp.ts +10 -2
  179. package/src/config/schemas/memory-retrospective.ts +1 -19
  180. package/src/config/schemas/services.ts +24 -0
  181. package/src/config/schemas/stt.ts +128 -5
  182. package/src/config/seed-inference-profiles.ts +32 -3
  183. package/src/config/skill-state.ts +5 -0
  184. package/src/config/skills.ts +21 -0
  185. package/src/contacts/notify-contacts-changed.ts +5 -2
  186. package/src/context/compactor.ts +74 -1
  187. package/src/daemon/__tests__/conversation-tool-setup.test.ts +138 -1
  188. package/src/daemon/config-watcher.ts +2 -1
  189. package/src/daemon/conversation-agent-loop-handlers.ts +27 -0
  190. package/src/daemon/conversation-agent-loop.ts +86 -10
  191. package/src/daemon/conversation-error.ts +25 -0
  192. package/src/daemon/conversation-evictor.ts +2 -4
  193. package/src/daemon/conversation-runtime-assembly.ts +19 -7
  194. package/src/daemon/conversation-skill-tools.ts +5 -1
  195. package/src/daemon/conversation-slash.ts +2 -2
  196. package/src/daemon/conversation-store.ts +8 -1
  197. package/src/daemon/conversation-tool-setup.ts +37 -0
  198. package/src/daemon/conversation.ts +0 -4
  199. package/src/daemon/handlers/channel-config-result.ts +30 -0
  200. package/src/daemon/handlers/config-discord-channel.ts +301 -0
  201. package/src/daemon/handlers/config-ingress.ts +9 -0
  202. package/src/daemon/handlers/config-slack-channel.ts +13 -15
  203. package/src/daemon/handlers/config-telegram.ts +2 -5
  204. package/src/daemon/handlers/conversations.ts +0 -2
  205. package/src/daemon/handlers/skills.ts +25 -7
  206. package/src/daemon/lifecycle.ts +3 -1
  207. package/src/daemon/message-types/messages.ts +0 -2
  208. package/src/daemon/tool-setup-types.ts +5 -3
  209. package/src/daemon/trust-context-types.test.ts +33 -0
  210. package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
  211. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +58 -4
  212. package/src/live-voice/__tests__/live-voice-managed-speech-fallback.test.ts +8 -3
  213. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +73 -11
  214. package/src/live-voice/__tests__/live-voice-session-preflight.test.ts +148 -2
  215. package/src/live-voice/__tests__/live-voice-stt.test.ts +3 -0
  216. package/src/live-voice/__tests__/live-voice-text-turn.test.ts +391 -0
  217. package/src/live-voice/__tests__/protocol.test.ts +224 -0
  218. package/src/live-voice/live-voice-credential-preflight.ts +5 -1
  219. package/src/live-voice/live-voice-session-manager.ts +39 -2
  220. package/src/live-voice/live-voice-session.ts +213 -8
  221. package/src/live-voice/protocol.ts +187 -1
  222. package/src/messaging/providers/discord/api.ts +2 -1
  223. package/src/messaging/providers/discord/withdraw.ts +62 -0
  224. package/src/monitoring/__tests__/file-descriptors.test.ts +32 -0
  225. package/src/monitoring/__tests__/process-memory.test.ts +34 -1
  226. package/src/monitoring/db-integrity-sample.ts +1 -0
  227. package/src/monitoring/file-descriptors.ts +39 -6
  228. package/src/monitoring/process-memory.ts +37 -5
  229. package/src/monitoring/resource-sampler.ts +25 -8
  230. package/src/notifications/__tests__/activity-failed-dedupe.test.ts +161 -0
  231. package/src/notifications/__tests__/background-failure-signal.test.ts +107 -0
  232. package/src/notifications/__tests__/connected-channels.test.ts +12 -0
  233. package/src/notifications/__tests__/copy-composer.test.ts +83 -0
  234. package/src/notifications/__tests__/destination-resolver.test.ts +38 -0
  235. package/src/notifications/activity-failed-dedupe.ts +95 -0
  236. package/src/notifications/adapters/discord.ts +132 -0
  237. package/src/notifications/adapters/shared.ts +16 -0
  238. package/src/notifications/adapters/slack.ts +6 -1
  239. package/src/notifications/adapters/telegram.ts +5 -8
  240. package/src/notifications/approval-card-data.ts +94 -1
  241. package/src/notifications/background-failure-signal.ts +116 -0
  242. package/src/notifications/broadcaster.ts +3 -9
  243. package/src/notifications/copy-composer.ts +41 -8
  244. package/src/notifications/decision-engine.ts +55 -0
  245. package/src/notifications/destination-resolver.ts +45 -5
  246. package/src/notifications/emit-signal.ts +19 -5
  247. package/src/notifications/guardian-question-mode.ts +57 -0
  248. package/src/notifications/types.ts +2 -8
  249. package/src/oauth/__tests__/seed-providers-managed.test.ts +18 -0
  250. package/src/oauth/seed-providers.ts +261 -0
  251. package/src/permissions/checker.test.ts +21 -0
  252. package/src/permissions/checker.ts +6 -0
  253. package/src/permissions/gateway-threshold-reader.test.ts +184 -0
  254. package/src/permissions/gateway-threshold-reader.ts +144 -10
  255. package/src/permissions/prompter.ts +0 -6
  256. package/src/permissions/types.ts +5 -4
  257. package/src/persistence/__tests__/bulk-write-gate.test.ts +0 -38
  258. package/src/persistence/bulk-write-gate.ts +9 -10
  259. package/src/persistence/conversation-crud.ts +85 -133
  260. package/src/persistence/conversation-title-service.ts +43 -29
  261. package/src/persistence/embeddings/embedding-local.ts +14 -85
  262. package/src/persistence/embeddings/embedding-runtime-manager.ts +1 -0
  263. package/src/persistence/lifecycle-events-store.test.ts +50 -0
  264. package/src/persistence/lifecycle-events-store.ts +75 -5
  265. package/src/platform/platform-patch-queue.test.ts +368 -0
  266. package/src/platform/platform-patch-queue.ts +190 -0
  267. package/src/platform/sync-avatar.test.ts +527 -0
  268. package/src/platform/sync-avatar.ts +209 -0
  269. package/src/platform/sync-identity.test.ts +75 -0
  270. package/src/platform/sync-identity.ts +17 -110
  271. package/src/plugin-api/model-profiles.test.ts +2 -2
  272. package/src/plugin-api/model-profiles.ts +7 -7
  273. package/src/plugin-api/transcription-session.ts +1 -1
  274. package/src/plugins/defaults/compaction/window-manager.ts +4 -0
  275. package/src/plugins/defaults/image-recovery/recover.ts +2 -2
  276. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +133 -34
  277. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +21 -31
  278. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +13 -9
  279. package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +31 -4
  280. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +0 -11
  281. package/src/plugins/defaults/memory/memory-retrospective-fork-boundary.ts +27 -13
  282. package/src/plugins/defaults/memory/memory-retrospective-job.ts +183 -113
  283. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +13 -13
  284. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +2 -2
  285. package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +1 -1
  286. package/src/plugins/defaults/memory/substrate/consolidation-job.ts +4 -2
  287. package/src/plugins/defaults/memory/substrate/sweep-job.ts +9 -42
  288. package/src/plugins/defaults/memory/v2/rerank-local.ts +1 -0
  289. package/src/plugins/defaults/memory/worker.ts +7 -0
  290. package/src/providers/__tests__/retry-callsite.test.ts +55 -0
  291. package/src/providers/connection-resolution.ts +2 -17
  292. package/src/providers/fallback-breaker.ts +389 -0
  293. package/src/providers/inference/__tests__/adapter-factory-opencode.test.ts +92 -0
  294. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +16 -0
  295. package/src/providers/inference/__tests__/base-url-security.test.ts +12 -0
  296. package/src/providers/inference/adapter-factory.ts +231 -3
  297. package/src/providers/inference/auth.ts +1 -0
  298. package/src/providers/inference/chatgpt-subscription-auth.ts +70 -0
  299. package/src/providers/inference/chatgpt-subscription-credentials.ts +84 -0
  300. package/src/providers/inference/resolve-auth.ts +1 -1
  301. package/src/providers/media-resolve.ts +2 -3
  302. package/src/providers/model-catalog.ts +75 -0
  303. package/src/providers/openai/__tests__/api-error-normalization.test.ts +22 -0
  304. package/src/providers/openai/__tests__/chat-template-flatten.test.ts +198 -0
  305. package/src/providers/openai/api-error-normalization.ts +13 -0
  306. package/src/providers/openai/chat-completions-provider.ts +84 -0
  307. package/src/providers/opencode/client.test.ts +150 -0
  308. package/src/providers/opencode/client.ts +61 -0
  309. package/src/providers/provider-resolvability.ts +20 -0
  310. package/src/providers/retry.ts +956 -68
  311. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +42 -0
  312. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +136 -0
  313. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +120 -0
  314. package/src/providers/speech-to-text/__tests__/resolve.test.ts +316 -12
  315. package/src/providers/speech-to-text/deepgram-flux-frames.ts +83 -3
  316. package/src/providers/speech-to-text/deepgram-flux-realtime.ts +132 -4
  317. package/src/providers/speech-to-text/provider-catalog.ts +191 -3
  318. package/src/providers/speech-to-text/resolve.ts +132 -24
  319. package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +296 -0
  320. package/src/providers/types.ts +39 -0
  321. package/src/providers/usage-tracking.ts +12 -1
  322. package/src/runtime/AGENTS.md +1 -2
  323. package/src/runtime/__tests__/agent-wake.test.ts +105 -3
  324. package/src/runtime/__tests__/background-job-runner.test.ts +89 -3
  325. package/src/runtime/agent-wake.ts +44 -5
  326. package/src/runtime/background-job-runner.ts +68 -50
  327. package/src/runtime/channel-readiness-service.ts +0 -39
  328. package/src/runtime/http-server.ts +12 -4
  329. package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +18 -18
  330. package/src/runtime/routes/__tests__/backup-routes.test.ts +9 -5
  331. package/src/runtime/routes/__tests__/chatgpt-subscription-auth-routes.test.ts +372 -0
  332. package/src/runtime/routes/__tests__/contact-routes.test.ts +7 -0
  333. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +96 -0
  334. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +37 -0
  335. package/src/runtime/routes/__tests__/ingress-status-routes.test.ts +2 -1
  336. package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +87 -0
  337. package/src/runtime/routes/acp-claude-auth-routes.ts +25 -54
  338. package/src/runtime/routes/approval-routes.ts +0 -12
  339. package/src/runtime/routes/avatar-routes.ts +17 -30
  340. package/src/runtime/routes/backup-routes.ts +2 -2
  341. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +296 -113
  342. package/src/runtime/routes/contact-prompt-routes.ts +65 -6
  343. package/src/runtime/routes/contact-routes.ts +20 -15
  344. package/src/runtime/routes/conversation-query-routes.ts +98 -10
  345. package/src/runtime/routes/conversation-routes.ts +2 -2
  346. package/src/runtime/routes/credential-routes.ts +2 -1
  347. package/src/runtime/routes/guardian-approval-interception.ts +12 -9
  348. package/src/runtime/routes/inbound-message-handler.ts +21 -9
  349. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +18 -13
  350. package/src/runtime/routes/inbound-stages/admission-policy.ts +2 -2
  351. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +9 -8
  352. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -1
  353. package/src/runtime/routes/index.ts +2 -0
  354. package/src/runtime/routes/inference-profile-session-handler.ts +2 -2
  355. package/src/runtime/routes/inference-profiles-routes.ts +12 -7
  356. package/src/runtime/routes/inference-provider-connection-routes.ts +2 -2
  357. package/src/runtime/routes/inference-send-routes.ts +2 -2
  358. package/src/runtime/routes/ingress-status-routes.ts +2 -2
  359. package/src/runtime/routes/integrations/discord.ts +119 -0
  360. package/src/runtime/routes/llm-call-sites-routes.ts +2 -2
  361. package/src/runtime/routes/mcp-auth-routes.ts +12 -6
  362. package/src/runtime/routes/oauth-pending-flows.ts +136 -0
  363. package/src/runtime/routes/secret-routes.ts +7 -0
  364. package/src/runtime/routes/stt-routes.ts +38 -6
  365. package/src/runtime/routes/wake-conversation-routes.ts +8 -1
  366. package/src/runtime/routes/watch-routes.ts +9 -5
  367. package/src/runtime/sync/resource-sync-events.ts +2 -0
  368. package/src/runtime/trust-verdict-consumer.ts +3 -3
  369. package/src/schedule/__tests__/worker-feature-flags.test.ts +58 -0
  370. package/src/schedule/retry-policy.ts +8 -8
  371. package/src/schedule/run-script.ts +14 -23
  372. package/src/schedule/schedule-recovery.ts +0 -1
  373. package/src/schedule/scheduler.ts +89 -51
  374. package/src/schedule/worker.ts +57 -0
  375. package/src/security/__tests__/openai-device-auth.test.ts +355 -0
  376. package/src/security/oauth2.ts +7 -0
  377. package/src/security/openai-device-auth.ts +364 -0
  378. package/src/skills/available-skills.ts +10 -1
  379. package/src/skills/catalog-install.ts +19 -1
  380. package/src/skills/inline-command-runner.ts +6 -2
  381. package/src/skills/platform-compatibility.test.ts +49 -0
  382. package/src/skills/platform-compatibility.ts +65 -0
  383. package/src/skills/tool-manifest.ts +20 -0
  384. package/src/stt/__tests__/roles.test.ts +152 -0
  385. package/src/stt/daemon-batch-transcriber.ts +4 -1
  386. package/src/stt/roles.ts +180 -0
  387. package/src/stt/stt-stream-session.ts +3 -2
  388. package/src/stt/types.ts +33 -3
  389. package/src/subagent/manager.ts +12 -0
  390. package/src/telemetry/__tests__/live-voice-funnel.test.ts +34 -0
  391. package/src/telemetry/live-voice-funnel.ts +12 -2
  392. package/src/telemetry/telemetry-wire.generated.ts +6 -0
  393. package/src/telemetry/tool-audit.ts +83 -30
  394. package/src/telemetry/tool-executed-events-store.test.ts +0 -1
  395. package/src/telemetry/turn-outcome.ts +75 -4
  396. package/src/tools/client-os.ts +115 -0
  397. package/src/tools/computer-use/definitions.ts +11 -7
  398. package/src/tools/computer-use/skill-proxy-bridge.ts +2 -2
  399. package/src/tools/credentials/broker-types.ts +0 -71
  400. package/src/tools/credentials/broker.ts +6 -201
  401. package/src/tools/executor.ts +2 -8
  402. package/src/tools/host-shell.test.ts +75 -0
  403. package/src/tools/host-shell.ts +24 -0
  404. package/src/tools/host-terminal/host-shell.ts +15 -44
  405. package/src/tools/mcp/mcp-tool-factory.ts +44 -9
  406. package/src/tools/permission-checker.ts +73 -21
  407. package/src/tools/policy-context.ts +1 -0
  408. package/src/tools/shared/filesystem/image-read.ts +1 -1
  409. package/src/tools/skills/find-similar-skills.ts +10 -2
  410. package/src/tools/skills/load.ts +41 -6
  411. package/src/tools/skills/sandbox-runner.ts +8 -16
  412. package/src/tools/skills/skill-tool-factory.ts +1 -0
  413. package/src/tools/terminal/__tests__/safe-env.test.ts +64 -1
  414. package/src/tools/terminal/safe-env.ts +39 -9
  415. package/src/tools/terminal/shell.ts +12 -31
  416. package/src/tools/tool-approval-handler.ts +64 -10
  417. package/src/tools/tool-types.ts +10 -0
  418. package/src/tools/types.ts +19 -3
  419. package/src/tools/ui-surface/surface-shape-docs.ts +4 -3
  420. package/src/tools/workflows/manage-workflows.ts +2 -2
  421. package/src/tools/workflows/run-workflow.test.ts +2 -1
  422. package/src/util/__tests__/file-use.test.ts +61 -0
  423. package/src/util/__tests__/process-table.test.ts +66 -0
  424. package/src/util/__tests__/process-tree.test.ts +46 -0
  425. package/src/util/errors.ts +1 -0
  426. package/src/util/file-use.ts +91 -0
  427. package/src/util/host-process.test.ts +17 -0
  428. package/src/util/host-process.ts +75 -0
  429. package/src/util/image-conversion.ts +39 -7
  430. package/src/util/platform.ts +32 -13
  431. package/src/util/process-table.ts +249 -0
  432. package/src/util/process-tree.ts +85 -129
  433. package/src/util/provider-error-patterns.ts +20 -0
  434. package/src/util/spawn.ts +9 -2
  435. package/src/workspace/git-service.ts +4 -14
  436. package/src/workspace/migrations/147-rename-colliding-backup-profile-names.ts +360 -0
  437. package/src/workspace/migrations/148-strip-unsupported-fallback-profiles.ts +117 -0
  438. package/src/workspace/migrations/149-repoint-backup-profile-selections.ts +204 -0
  439. package/src/workspace/migrations/150-stt-flux-provider-to-model-family.ts +139 -0
  440. package/src/workspace/migrations/__tests__/150-stt-flux-provider-to-model-family.test.ts +160 -0
  441. package/src/workspace/migrations/registry.ts +8 -0
  442. package/src/__tests__/permission-types.test.ts +0 -17
  443. package/src/channels/gateway-discord-admission.ts +0 -32
  444. package/src/persistence/fork-message-copy.ts +0 -239
  445. package/src/plugins/defaults/memory/__tests__/fork-message-copy.test.ts +0 -221
  446. package/src/security/__tests__/oauth2-device-code.test.ts +0 -431
  447. package/src/security/oauth2-device-code.ts +0 -312
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Workspace migration `149-repoint-backup-profile-selections`.
3
+ *
4
+ * Managed backup profiles are internal failover routes. Earlier builds let
5
+ * users select those names directly, so existing workspaces can retain them
6
+ * in active, advisor, call-site, mix, conversation, or schedule references.
7
+ * Repoint those direct selections to their corresponding primary profile
8
+ * before the user-facing catalog hides the backups. Automatic fallback
9
+ * metadata is preserved: a primary's `fallbackProfile` still names its
10
+ * internal backup route.
11
+ */
12
+
13
+ import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
14
+ import { join } from "node:path";
15
+ import { Database } from "bun:sqlite";
16
+
17
+ import { FALLBACK_PROFILE_BY_KEY } from "../../config/default-profile-names.js";
18
+ import { getLogger } from "../../util/logger.js";
19
+ import type { WorkspaceMigration } from "./types.js";
20
+
21
+ const log = getLogger(
22
+ "workspace-migration-149-repoint-backup-profile-selections",
23
+ );
24
+
25
+ /** Mapping of every managed backup to its direct-selectable primary. */
26
+ const BACKUP_TO_PRIMARY: Record<string, string> = Object.fromEntries(
27
+ Object.entries(FALLBACK_PROFILE_BY_KEY).map(([primary, backup]) => [
28
+ backup,
29
+ primary,
30
+ ]),
31
+ );
32
+
33
+ const PROFILE_PIN_TABLES = ["conversations", "cron_jobs"] as const;
34
+ const DB_ATTEMPTS = 4;
35
+ const DB_RETRY_BASE_DELAY_MS = 50;
36
+
37
+ export const repointBackupProfileSelectionsMigration: WorkspaceMigration = {
38
+ id: "149-repoint-backup-profile-selections",
39
+ description:
40
+ "Repoint direct selections of managed backup profiles to their primaries",
41
+ retryFailedCheckpoint: true,
42
+
43
+ async run(workspaceDir: string): Promise<void> {
44
+ const configPath = join(workspaceDir, "config.json");
45
+ const config = readConfig(configPath);
46
+ const llm = config === null ? null : asObject(config.llm);
47
+ const configChanged = llm !== null && rewriteConfigReferences(llm);
48
+
49
+ // Rewrite database pins before config.json. If the database cannot be
50
+ // updated, leaving config untouched lets the next boot retry the same
51
+ // migration without stranding a direct selection.
52
+ await rewriteDbReferences(workspaceDir);
53
+
54
+ if (config !== null && configChanged) {
55
+ const tempPath = `${configPath}.tmp`;
56
+ writeFileSync(tempPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
57
+ renameSync(tempPath, configPath);
58
+ log.info("Repointed direct backup-profile selections to primaries");
59
+ }
60
+ },
61
+
62
+ down(_workspaceDir: string): void {
63
+ // Forward-only: restoring a backup selection would make it unreachable
64
+ // from the user-facing profile catalog.
65
+ },
66
+ };
67
+
68
+ function readConfig(path: string): Record<string, unknown> | null {
69
+ if (!existsSync(path)) {
70
+ return null;
71
+ }
72
+ try {
73
+ const parsed: unknown = JSON.parse(readFileSync(path, "utf-8"));
74
+ return isPlainObject(parsed) ? parsed : null;
75
+ } catch {
76
+ return null;
77
+ }
78
+ }
79
+
80
+ /** Rewrite config references that represent direct user profile choices. */
81
+ function rewriteConfigReferences(llm: Record<string, unknown>): boolean {
82
+ let changed = false;
83
+
84
+ for (const field of ["activeProfile", "advisorProfile"] as const) {
85
+ const current = llm[field];
86
+ const replacement = remapProfileName(current);
87
+ if (replacement !== current) {
88
+ llm[field] = replacement;
89
+ changed = true;
90
+ }
91
+ }
92
+
93
+ const callSites = asObject(llm.callSites);
94
+ if (callSites !== null) {
95
+ for (const value of Object.values(callSites)) {
96
+ const site = asObject(value);
97
+ if (site === null) {
98
+ continue;
99
+ }
100
+ const replacement = remapProfileName(site.profile);
101
+ if (replacement !== site.profile) {
102
+ site.profile = replacement;
103
+ changed = true;
104
+ }
105
+ }
106
+ }
107
+
108
+ const profiles = asObject(llm.profiles);
109
+ if (profiles === null) {
110
+ return changed;
111
+ }
112
+ for (const value of Object.values(profiles)) {
113
+ const entry = asObject(value);
114
+ if (entry === null || !Array.isArray(entry.mix)) {
115
+ continue;
116
+ }
117
+ for (const armValue of entry.mix as unknown[]) {
118
+ const arm = asObject(armValue);
119
+ if (arm === null) {
120
+ continue;
121
+ }
122
+ const replacement = remapProfileName(arm.profile);
123
+ if (replacement !== arm.profile) {
124
+ arm.profile = replacement;
125
+ changed = true;
126
+ }
127
+ }
128
+ }
129
+
130
+ return changed;
131
+ }
132
+
133
+ function remapProfileName(value: unknown): unknown {
134
+ if (typeof value !== "string") {
135
+ return value;
136
+ }
137
+ return BACKUP_TO_PRIMARY[value] ?? value;
138
+ }
139
+
140
+ /** Rewrite conversation and schedule pins, retrying transient DB contention. */
141
+ async function rewriteDbReferences(workspaceDir: string): Promise<void> {
142
+ const path = join(workspaceDir, "data", "db", "assistant.db");
143
+ if (!existsSync(path)) {
144
+ return;
145
+ }
146
+
147
+ await withDbRetry(() => {
148
+ const db = new Database(path);
149
+ try {
150
+ for (const table of PROFILE_PIN_TABLES) {
151
+ if (!tableHasColumn(db, table, "inference_profile")) {
152
+ continue;
153
+ }
154
+ for (const [backup, primary] of Object.entries(BACKUP_TO_PRIMARY)) {
155
+ db.query(
156
+ `UPDATE ${table} SET inference_profile = ? WHERE inference_profile = ?`,
157
+ ).run(primary, backup);
158
+ }
159
+ }
160
+ } finally {
161
+ db.close();
162
+ }
163
+ });
164
+ }
165
+
166
+ function tableHasColumn(
167
+ db: Database,
168
+ table: (typeof PROFILE_PIN_TABLES)[number],
169
+ column: string,
170
+ ): boolean {
171
+ const rows = db.query(`PRAGMA table_info(${table})`).all() as Array<{
172
+ name?: unknown;
173
+ }>;
174
+ return rows.some((row) => row.name === column);
175
+ }
176
+
177
+ async function withDbRetry(attempt: () => void): Promise<void> {
178
+ for (let index = 0; ; index += 1) {
179
+ try {
180
+ attempt();
181
+ return;
182
+ } catch (err) {
183
+ if (index >= DB_ATTEMPTS - 1) {
184
+ throw new Error(
185
+ `Could not repoint backup-profile selections after ${DB_ATTEMPTS} attempts`,
186
+ { cause: err },
187
+ );
188
+ }
189
+ log.warn(
190
+ { err, attempt: index },
191
+ "Could not repoint backup-profile selections; retrying",
192
+ );
193
+ await Bun.sleep(DB_RETRY_BASE_DELAY_MS * 2 ** index);
194
+ }
195
+ }
196
+ }
197
+
198
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
199
+ return value !== null && typeof value === "object" && !Array.isArray(value);
200
+ }
201
+
202
+ function asObject(value: unknown): Record<string, unknown> | null {
203
+ return isPlainObject(value) ? value : null;
204
+ }
@@ -0,0 +1,139 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import type { WorkspaceMigration } from "./types.js";
5
+
6
+ /**
7
+ * Fold the Flux provider ids back into their parent plus a model family.
8
+ *
9
+ * Flux shipped as its own `services.stt.provider` value, which made a model
10
+ * choice look like a provider choice. That cost an entry in the provider
11
+ * enum, a row in every settings picker, and a place in each
12
+ * managed-versus-BYOK predicate for a backend that shares its parent's
13
+ * credential and account. Model families now live where the rest of a
14
+ * provider's settings do:
15
+ *
16
+ * provider: "deepgram-flux" -> provider: "deepgram"
17
+ * providers.deepgram.model: "flux"
18
+ *
19
+ * The same rewrite applies to the managed pair. Any other provider value is
20
+ * left untouched, and an existing `providers.<parent>` entry keeps every key
21
+ * it already had.
22
+ *
23
+ * The same pass drops any `providers.<id>.model` a known provider cannot
24
+ * serve. That key was free-form before this change and read by nothing, so
25
+ * existing values carry no meaning, but the schema validates it now: leaving
26
+ * a stale one behind would fail the parse and drop the workspace onto the
27
+ * loader's salvage path, which resets the entire `services` section and takes
28
+ * unrelated STT and TTS settings with it.
29
+ *
30
+ * Idempotent: a config already naming a parent provider has nothing to
31
+ * rewrite, and a model key already naming a family it can serve is left
32
+ * alone.
33
+ */
34
+ const FLUX_PROVIDER_PARENTS: Record<string, string> = {
35
+ "deepgram-flux": "deepgram",
36
+ "vellum-flux": "vellum",
37
+ };
38
+
39
+ /**
40
+ * The model families each provider served when this migration was written,
41
+ * inlined rather than read from the provider catalog.
42
+ *
43
+ * A published migration has to behave identically every time it runs, and it
44
+ * reruns on newly initialized workspaces and after an interrupted checkpoint.
45
+ * Reading the live catalog would let a later change to it alter what this
46
+ * migration deletes from configs it has already seen.
47
+ */
48
+ const KNOWN_MODEL_FAMILIES: Record<string, readonly string[]> = {
49
+ deepgram: ["nova-3", "flux"],
50
+ vellum: ["nova-3", "flux"],
51
+ };
52
+
53
+ export const sttFluxProviderToModelFamilyMigration: WorkspaceMigration = {
54
+ id: "150-stt-flux-provider-to-model-family",
55
+ description:
56
+ "Rewrite services.stt.provider Flux ids to the parent provider plus providers.<id>.model",
57
+ run(workspaceDir: string): void {
58
+ const configPath = join(workspaceDir, "config.json");
59
+ if (!existsSync(configPath)) {
60
+ return;
61
+ }
62
+
63
+ let config: Record<string, unknown>;
64
+ try {
65
+ config = JSON.parse(readFileSync(configPath, "utf8")) as Record<
66
+ string,
67
+ unknown
68
+ >;
69
+ } catch {
70
+ // A config that does not parse is the loader's problem to report, not
71
+ // this migration's to guess at.
72
+ return;
73
+ }
74
+
75
+ const services = asRecord(config.services);
76
+ const stt = asRecord(services?.stt);
77
+ if (!stt || typeof stt.provider !== "string") {
78
+ return;
79
+ }
80
+
81
+ const providers = asRecord(stt.providers) ?? {};
82
+ let changed = dropUnservableModels(providers);
83
+
84
+ const parent = FLUX_PROVIDER_PARENTS[stt.provider];
85
+ if (parent !== undefined) {
86
+ stt.provider = parent;
87
+ const parentSettings = asRecord(providers[parent]) ?? {};
88
+ parentSettings.model = "flux";
89
+ providers[parent] = parentSettings;
90
+ changed = true;
91
+ }
92
+
93
+ if (!changed) {
94
+ return;
95
+ }
96
+
97
+ stt.providers = providers;
98
+ writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
99
+ },
100
+
101
+ down(_workspaceDir: string): void {
102
+ // Forward-only: the Flux provider ids are gone from the config enum, so
103
+ // restoring one would produce a config the schema rejects.
104
+ },
105
+ };
106
+
107
+ /**
108
+ * Remove `model` values a provider known at the time of writing cannot serve.
109
+ * Entries for any other provider are left untouched: that map is deliberately
110
+ * open to ids from future builds, and the schema does not validate them
111
+ * either.
112
+ */
113
+ function dropUnservableModels(providers: Record<string, unknown>): boolean {
114
+ let changed = false;
115
+ for (const [providerId, value] of Object.entries(providers)) {
116
+ const settings = asRecord(value);
117
+ if (!settings || settings.model === undefined) {
118
+ continue;
119
+ }
120
+ const families = KNOWN_MODEL_FAMILIES[providerId];
121
+ if (families === undefined) {
122
+ continue;
123
+ }
124
+ if (
125
+ typeof settings.model !== "string" ||
126
+ !families.includes(settings.model)
127
+ ) {
128
+ delete settings.model;
129
+ changed = true;
130
+ }
131
+ }
132
+ return changed;
133
+ }
134
+
135
+ function asRecord(value: unknown): Record<string, unknown> | null {
136
+ return typeof value === "object" && value !== null && !Array.isArray(value)
137
+ ? (value as Record<string, unknown>)
138
+ : null;
139
+ }
@@ -0,0 +1,160 @@
1
+ import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { describe, expect, test } from "bun:test";
5
+
6
+ import { sttFluxProviderToModelFamilyMigration } from "../150-stt-flux-provider-to-model-family.js";
7
+ import { WORKSPACE_MIGRATIONS } from "../registry.js";
8
+
9
+ function workspaceWith(config: unknown): string {
10
+ const dir = mkdtempSync(join(tmpdir(), "stt-flux-migration-"));
11
+ writeFileSync(join(dir, "config.json"), JSON.stringify(config, null, 2));
12
+ return dir;
13
+ }
14
+
15
+ function readConfig(dir: string): any {
16
+ return JSON.parse(readFileSync(join(dir, "config.json"), "utf8"));
17
+ }
18
+
19
+ describe("150-stt-flux-provider-to-model-family", () => {
20
+ test("is registered as the newest migration", () => {
21
+ expect(sttFluxProviderToModelFamilyMigration.id).toBe(
22
+ "150-stt-flux-provider-to-model-family",
23
+ );
24
+ expect(WORKSPACE_MIGRATIONS.at(-1)?.id).toBe(
25
+ "150-stt-flux-provider-to-model-family",
26
+ );
27
+ });
28
+
29
+ test("rewrites a Flux provider id to its parent plus a model family", () => {
30
+ const dir = workspaceWith({
31
+ services: { stt: { provider: "deepgram-flux", providers: {} } },
32
+ });
33
+
34
+ sttFluxProviderToModelFamilyMigration.run(dir);
35
+
36
+ expect(readConfig(dir).services.stt).toEqual({
37
+ provider: "deepgram",
38
+ providers: { deepgram: { model: "flux" } },
39
+ });
40
+ });
41
+
42
+ test("rewrites the managed pair the same way", () => {
43
+ const dir = workspaceWith({
44
+ services: { stt: { provider: "vellum-flux", providers: {} } },
45
+ });
46
+
47
+ sttFluxProviderToModelFamilyMigration.run(dir);
48
+
49
+ expect(readConfig(dir).services.stt.provider).toBe("vellum");
50
+ expect(readConfig(dir).services.stt.providers.vellum.model).toBe("flux");
51
+ });
52
+
53
+ test("keeps existing settings on the parent's entry", () => {
54
+ const dir = workspaceWith({
55
+ services: {
56
+ stt: {
57
+ provider: "deepgram-flux",
58
+ providers: { deepgram: { someExistingKey: 1 } },
59
+ },
60
+ },
61
+ });
62
+
63
+ sttFluxProviderToModelFamilyMigration.run(dir);
64
+
65
+ expect(readConfig(dir).services.stt.providers.deepgram).toEqual({
66
+ someExistingKey: 1,
67
+ model: "flux",
68
+ });
69
+ });
70
+
71
+ test("drops a model a known provider cannot serve", () => {
72
+ // That key was free-form and read by nothing before this change, so an
73
+ // existing value is meaningless -- but the schema validates it now, and
74
+ // leaving one behind drops the workspace onto the loader's salvage path,
75
+ // which resets the whole services section.
76
+ const dir = workspaceWith({
77
+ services: {
78
+ stt: {
79
+ provider: "deepgram",
80
+ providers: { deepgram: { model: "nova-2", keepMe: true } },
81
+ },
82
+ },
83
+ });
84
+
85
+ sttFluxProviderToModelFamilyMigration.run(dir);
86
+
87
+ expect(readConfig(dir).services.stt.providers.deepgram).toEqual({
88
+ keepMe: true,
89
+ });
90
+ });
91
+
92
+ test("keeps a model the provider can serve", () => {
93
+ const dir = workspaceWith({
94
+ services: {
95
+ stt: {
96
+ provider: "deepgram",
97
+ providers: { deepgram: { model: "flux" } },
98
+ },
99
+ },
100
+ });
101
+
102
+ sttFluxProviderToModelFamilyMigration.run(dir);
103
+
104
+ expect(readConfig(dir).services.stt.providers.deepgram.model).toBe("flux");
105
+ });
106
+
107
+ test("leaves entries for providers the catalog does not know", () => {
108
+ // The map is deliberately open to ids from future builds, and the schema
109
+ // does not validate those either.
110
+ const before = {
111
+ services: {
112
+ stt: {
113
+ provider: "deepgram",
114
+ providers: { "future-provider": { model: "next-gen" } },
115
+ },
116
+ },
117
+ };
118
+ const dir = workspaceWith(before);
119
+
120
+ sttFluxProviderToModelFamilyMigration.run(dir);
121
+
122
+ expect(readConfig(dir)).toEqual(before);
123
+ });
124
+
125
+ test("leaves a non-Flux provider untouched", () => {
126
+ const before = {
127
+ services: { stt: { provider: "deepgram", providers: {} } },
128
+ };
129
+ const dir = workspaceWith(before);
130
+
131
+ sttFluxProviderToModelFamilyMigration.run(dir);
132
+
133
+ expect(readConfig(dir)).toEqual(before);
134
+ });
135
+
136
+ test("is idempotent", () => {
137
+ const dir = workspaceWith({
138
+ services: { stt: { provider: "deepgram-flux", providers: {} } },
139
+ });
140
+
141
+ sttFluxProviderToModelFamilyMigration.run(dir);
142
+ const once = readConfig(dir);
143
+ sttFluxProviderToModelFamilyMigration.run(dir);
144
+
145
+ expect(readConfig(dir)).toEqual(once);
146
+ });
147
+
148
+ test("does nothing without a config file, or with an unparseable one", () => {
149
+ const empty = mkdtempSync(join(tmpdir(), "stt-flux-migration-"));
150
+ expect(() =>
151
+ sttFluxProviderToModelFamilyMigration.run(empty),
152
+ ).not.toThrow();
153
+
154
+ const broken = mkdtempSync(join(tmpdir(), "stt-flux-migration-"));
155
+ writeFileSync(join(broken, "config.json"), "{not json");
156
+ expect(() =>
157
+ sttFluxProviderToModelFamilyMigration.run(broken),
158
+ ).not.toThrow();
159
+ });
160
+ });
@@ -144,6 +144,10 @@ import { repairDeprecatedCodexModelIdMigration } from "./143-repair-deprecated-c
144
144
  import { convertStrandedSubscriptionOpenaiProfilesMigration } from "./144-convert-stranded-subscription-openai-profiles.js";
145
145
  import { collapseProfileBindingsToEntriesMigration } from "./145-collapse-profile-bindings-to-entries.js";
146
146
  import { repairRetiredFireworksDeepseekFlashModelIdMigration } from "./146-repair-retired-fireworks-deepseek-flash-model-id.js";
147
+ import { renameCollidingBackupProfileNamesMigration } from "./147-rename-colliding-backup-profile-names.js";
148
+ import { stripUnsupportedFallbackProfilesMigration } from "./148-strip-unsupported-fallback-profiles.js";
149
+ import { repointBackupProfileSelectionsMigration } from "./149-repoint-backup-profile-selections.js";
150
+ import { sttFluxProviderToModelFamilyMigration } from "./150-stt-flux-provider-to-model-family.js";
147
151
  import { migrateToWorkspaceVolumeMigration } from "./migrate-to-workspace-volume.js";
148
152
  import type { WorkspaceMigration } from "./types.js";
149
153
 
@@ -303,4 +307,8 @@ export const WORKSPACE_MIGRATIONS: WorkspaceMigration[] = [
303
307
  convertStrandedSubscriptionOpenaiProfilesMigration,
304
308
  collapseProfileBindingsToEntriesMigration,
305
309
  repairRetiredFireworksDeepseekFlashModelIdMigration,
310
+ renameCollidingBackupProfileNamesMigration,
311
+ stripUnsupportedFallbackProfilesMigration,
312
+ repointBackupProfileSelectionsMigration,
313
+ sttFluxProviderToModelFamilyMigration,
306
314
  ];
@@ -1,17 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
-
3
- import { isAllowDecision } from "../permissions/types.js";
4
-
5
- // ---------------------------------------------------------------------------
6
- // Tests
7
- // ---------------------------------------------------------------------------
8
-
9
- describe("isAllowDecision", () => {
10
- test("returns true for 'allow'", () => {
11
- expect(isAllowDecision("allow")).toBe(true);
12
- });
13
-
14
- test("returns false for 'deny'", () => {
15
- expect(isAllowDecision("deny")).toBe(false);
16
- });
17
- });
@@ -1,32 +0,0 @@
1
- /**
2
- * Daemon-side reader for how much Discord admits.
3
- *
4
- * The gateway owns the allow-list and the drop decision it feeds; the
5
- * readiness surface that reports channel setup to the user lives here. This is
6
- * the relay between them, and it exists for the same reason the socket-health
7
- * relay does: the fact lives on one side of the boundary and is reported from
8
- * the other.
9
- */
10
-
11
- import {
12
- type DiscordAdmissionIpcResponse,
13
- DiscordAdmissionIpcResponseSchema,
14
- } from "@vellumai/gateway-client/gateway-ipc-contracts";
15
-
16
- import { ipcCallPersistentValidated } from "../ipc/gateway-validated-call.js";
17
-
18
- /**
19
- * Ask the gateway how many channels Discord's allow-list admits.
20
- *
21
- * Throws on transport failure rather than reporting zero: an unreachable
22
- * gateway is a fact about the gateway, and answering zero would tell an
23
- * operator their allow-list is empty when nobody looked. Callers treat a throw
24
- * as indeterminate.
25
- */
26
- export async function readDiscordAdmission(): Promise<DiscordAdmissionIpcResponse> {
27
- return ipcCallPersistentValidated(
28
- "discord_admission",
29
- {},
30
- DiscordAdmissionIpcResponseSchema,
31
- );
32
- }