@mycadet/assistant 0.12.10 → 0.13.0

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 (180) hide show
  1. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +10 -10
  2. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +3 -3
  3. package/node_modules/@mycadet/ces-client/src/http-credentials.ts +18 -1
  4. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +10 -10
  5. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +3 -3
  6. package/node_modules/@mycadet/gateway-client/src/gateway-ipc-contracts.ts +0 -20
  7. package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +10 -10
  8. package/node_modules/@mycadet/service-contracts/src/ingress.ts +3 -3
  9. package/openapi.yaml +2 -708
  10. package/package.json +2 -3
  11. package/scripts/sync-web-search-catalog.ts +1 -2
  12. package/src/__tests__/cloud-profile-guard.test.ts +41 -5
  13. package/src/__tests__/config-schema.test.ts +6 -38
  14. package/src/__tests__/conversation-queue.test.ts +45 -6
  15. package/src/__tests__/db-readiness-http-gate.test.ts +0 -6
  16. package/src/__tests__/persist-onboarding-artifacts.test.ts +0 -1
  17. package/src/__tests__/persona-resolver.test.ts +0 -51
  18. package/src/__tests__/provider-cloud-proxy-integration.test.ts +2 -110
  19. package/src/__tests__/run-due-schedules.test.ts +0 -4
  20. package/src/__tests__/schedule-store.test.ts +0 -12
  21. package/src/__tests__/stt-stream-session.test.ts +4 -4
  22. package/src/__tests__/telephony-tts-guard.test.ts +2 -50
  23. package/src/__tests__/voice-config-update.test.ts +12 -167
  24. package/src/__tests__/web-search-catalog-parity.test.ts +0 -2
  25. package/src/__tests__/workspace-migration-130-speech-mode-to-provider.test.ts +9 -7
  26. package/src/__tests__/workspace-migration-132-web-search-mode-to-provider.test.ts +6 -6
  27. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -4
  28. package/src/calls/resolve-call-tts-provider.ts +6 -25
  29. package/src/calls/telephony-credential-preflight.ts +0 -10
  30. package/src/calls/telephony-tts-capability.ts +1 -17
  31. package/src/cli/commands/tts.ts +1 -2
  32. package/src/cli/index.help.ts +0 -2
  33. package/src/cli/program.ts +0 -2
  34. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +4 -42
  35. package/src/config/schemas/__tests__/stt.test.ts +10 -14
  36. package/src/config/schemas/llm.ts +3 -5
  37. package/src/config/schemas/services.ts +5 -6
  38. package/src/config/schemas/stt.ts +1 -3
  39. package/src/config/schemas/tts.ts +1 -30
  40. package/src/daemon/daemon-readiness.ts +4 -29
  41. package/src/daemon/lifecycle.ts +0 -31
  42. package/src/daemon/providers-setup.ts +0 -8
  43. package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
  44. package/src/heartbeat/heartbeat-service.ts +1 -66
  45. package/src/ipc/__tests__/db-readiness-ipc-gate.test.ts +1 -9
  46. package/src/live-voice/__tests__/live-voice-credential-preflight.test.ts +0 -44
  47. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +4 -6
  48. package/src/live-voice/__tests__/live-voice-stt.test.ts +1 -1
  49. package/src/live-voice/live-voice-credential-preflight.ts +9 -33
  50. package/src/live-voice/live-voice-session.ts +10 -6
  51. package/src/live-voice/live-voice-tts.ts +1 -8
  52. package/src/plugins/defaults/memory/worker.ts +3 -3
  53. package/src/prompts/persona-resolver.ts +0 -35
  54. package/src/providers/__tests__/search-provider-catalog.test.ts +5 -8
  55. package/src/providers/__tests__/voice-error-copy.test.ts +9 -10
  56. package/src/providers/search-provider-catalog.ts +7 -39
  57. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +3 -47
  58. package/src/providers/speech-to-text/__tests__/resolve.test.ts +6 -372
  59. package/src/providers/speech-to-text/provider-catalog.ts +2 -73
  60. package/src/providers/speech-to-text/resolve.ts +3 -120
  61. package/src/runtime/http-router-types.ts +1 -3
  62. package/src/runtime/http-server.ts +1 -1
  63. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +13 -11
  64. package/src/runtime/routes/__tests__/tts-routes.test.ts +2 -6
  65. package/src/runtime/routes/conversation-query-routes.ts +0 -96
  66. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +7 -7
  67. package/src/runtime/routes/index.ts +0 -4
  68. package/src/runtime/routes/live-voice-routes.test.ts +4 -11
  69. package/src/runtime/routes/live-voice-routes.ts +8 -11
  70. package/src/runtime/routes/secret-routes.ts +0 -6
  71. package/src/runtime/routes/tts-routes.ts +0 -38
  72. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1 -7
  73. package/src/schedule/__tests__/worker-mcp-readiness.test.ts +0 -4
  74. package/src/schedule/schedule-store.ts +0 -7
  75. package/src/schedule/scheduler.ts +0 -5
  76. package/src/schedule/worker.ts +1 -1
  77. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +2 -10
  78. package/src/stt/daemon-batch-transcriber.ts +4 -38
  79. package/src/stt/types.ts +1 -9
  80. package/src/tools/network/__tests__/web-search.test.ts +3 -250
  81. package/src/tools/network/web-search.ts +4 -165
  82. package/src/tts/__tests__/provider-resolution.test.ts +0 -5
  83. package/src/tts/provider-catalog.ts +0 -4
  84. package/src/tts/types.ts +0 -1
  85. package/src/__tests__/cloud-speech-defaults.test.ts +0 -330
  86. package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1708
  87. package/src/__tests__/migration-export-http.test.ts +0 -557
  88. package/src/__tests__/migration-export-streaming.test.ts +0 -350
  89. package/src/__tests__/migration-export-to-gcs.test.ts +0 -706
  90. package/src/__tests__/migration-import-commit-http.test.ts +0 -1176
  91. package/src/__tests__/migration-import-from-gcs.test.ts +0 -534
  92. package/src/__tests__/migration-import-from-path.test.ts +0 -324
  93. package/src/__tests__/migration-import-from-url.test.ts +0 -588
  94. package/src/__tests__/migration-import-preflight-http.test.ts +0 -739
  95. package/src/__tests__/migration-jobs-status.test.ts +0 -139
  96. package/src/__tests__/migration-parity-persistence.test.ts +0 -1891
  97. package/src/__tests__/migration-transport.test.ts +0 -1089
  98. package/src/__tests__/migration-validate-http.test.ts +0 -634
  99. package/src/__tests__/migration-wizard.test.ts +0 -1395
  100. package/src/__tests__/rebind-secrets-screen.test.ts +0 -876
  101. package/src/__tests__/sanitize-config-for-transfer.test.ts +0 -259
  102. package/src/__tests__/transfer-progress-screen.test.ts +0 -1217
  103. package/src/__tests__/validation-results-screen.test.ts +0 -1130
  104. package/src/__tests__/vbundle-pax-and-symlink.test.ts +0 -147
  105. package/src/background-wake/background-wake-routes.test.ts +0 -906
  106. package/src/background-wake/cloud-client.test.ts +0 -328
  107. package/src/background-wake/cloud-client.ts +0 -196
  108. package/src/background-wake/next-wake.test.ts +0 -335
  109. package/src/background-wake/next-wake.ts +0 -188
  110. package/src/background-wake/publisher.ts +0 -93
  111. package/src/background-wake/wake-intent-hooks.test.ts +0 -234
  112. package/src/cli/commands/__tests__/backup.test.ts +0 -363
  113. package/src/cli/commands/backup.help.ts +0 -180
  114. package/src/cli/commands/backup.ts +0 -398
  115. package/src/cloud/cloud-speech.test.ts +0 -335
  116. package/src/cloud/cloud-speech.ts +0 -300
  117. package/src/config/cloud-speech-defaults.ts +0 -300
  118. package/src/config/sanitize-for-transfer.ts +0 -111
  119. package/src/live-voice/__tests__/live-voice-cloud-speech-fallback.test.ts +0 -250
  120. package/src/providers/speech-to-text/__tests__/cadet-cloud-realtime.test.ts +0 -457
  121. package/src/providers/speech-to-text/__tests__/cadet-cloud.test.ts +0 -271
  122. package/src/providers/speech-to-text/__tests__/cadet-speech-relay-connection.test.ts +0 -126
  123. package/src/providers/speech-to-text/cadet-cloud-flux-realtime.ts +0 -309
  124. package/src/providers/speech-to-text/cadet-cloud-realtime.ts +0 -315
  125. package/src/providers/speech-to-text/cadet-cloud.ts +0 -108
  126. package/src/providers/speech-to-text/cadet-speech-relay-connection.ts +0 -176
  127. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +0 -254
  128. package/src/runtime/migrations/__tests__/job-registry.test.ts +0 -346
  129. package/src/runtime/migrations/__tests__/origin-mode.test.ts +0 -62
  130. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +0 -184
  131. package/src/runtime/migrations/__tests__/staged-import-path.test.ts +0 -110
  132. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +0 -112
  133. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +0 -285
  134. package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +0 -126
  135. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +0 -253
  136. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +0 -208
  137. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +0 -485
  138. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +0 -349
  139. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +0 -196
  140. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +0 -551
  141. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +0 -428
  142. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +0 -220
  143. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +0 -1823
  144. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +0 -598
  145. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +0 -463
  146. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -538
  147. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +0 -515
  148. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +0 -453
  149. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +0 -319
  150. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +0 -240
  151. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +0 -473
  152. package/src/runtime/migrations/gcs-signed-url.ts +0 -190
  153. package/src/runtime/migrations/job-registry.ts +0 -297
  154. package/src/runtime/migrations/migration-transport.ts +0 -612
  155. package/src/runtime/migrations/migration-wizard.ts +0 -747
  156. package/src/runtime/migrations/origin-mode.ts +0 -42
  157. package/src/runtime/migrations/rebind-secrets-screen.ts +0 -412
  158. package/src/runtime/migrations/staged-import-path.ts +0 -116
  159. package/src/runtime/migrations/transfer-progress-screen.ts +0 -323
  160. package/src/runtime/migrations/validation-results-screen.ts +0 -469
  161. package/src/runtime/migrations/vbundle-builder.ts +0 -1382
  162. package/src/runtime/migrations/vbundle-import-analyzer.ts +0 -405
  163. package/src/runtime/migrations/vbundle-import-policy.ts +0 -241
  164. package/src/runtime/migrations/vbundle-importer.ts +0 -826
  165. package/src/runtime/migrations/vbundle-metadata-merge.ts +0 -113
  166. package/src/runtime/migrations/vbundle-streaming-importer.ts +0 -2844
  167. package/src/runtime/migrations/vbundle-streaming-validator.ts +0 -426
  168. package/src/runtime/migrations/vbundle-tar-stream.ts +0 -244
  169. package/src/runtime/migrations/vbundle-validator.ts +0 -724
  170. package/src/runtime/routes/__tests__/migration-cadet-metadata-reconcile.test.ts +0 -227
  171. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +0 -54
  172. package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +0 -70
  173. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +0 -257
  174. package/src/runtime/routes/background-wake-routes.ts +0 -387
  175. package/src/runtime/routes/migration-routes.ts +0 -2584
  176. package/src/tools/network/__tests__/cloud-search-proxy.test.ts +0 -282
  177. package/src/tools/network/cloud-search-proxy.ts +0 -211
  178. package/src/tts/__tests__/cadet-provider.test.ts +0 -253
  179. package/src/tts/providers/cadet-provider.ts +0 -244
  180. package/src/types/tar-stream.d.ts +0 -66
@@ -21,7 +21,6 @@ import type {
21
21
  TtsProviderCatalogEntry,
22
22
  TtsProviderDefinition,
23
23
  } from "./provider-definition.js";
24
- import { cadetTtsProviderDefinition } from "./providers/cadet-provider.js";
25
24
  import { deepgramTtsProviderDefinition } from "./providers/deepgram-provider.js";
26
25
  import { elevenLabsTtsProviderDefinition } from "./providers/elevenlabs-provider.js";
27
26
  import { fishAudioTtsProviderDefinition } from "./providers/fish-audio-provider.js";
@@ -48,15 +47,12 @@ const DEFINITIONS = {
48
47
  "fish-audio": fishAudioTtsProviderDefinition,
49
48
  deepgram: deepgramTtsProviderDefinition,
50
49
  xai: xaiTtsProviderDefinition,
51
- cadet: cadetTtsProviderDefinition,
52
50
  } as const satisfies Record<TtsProviderId, TtsProviderDefinition>;
53
51
 
54
52
  /**
55
53
  * Definitions in display order (e.g. settings dropdowns).
56
54
  */
57
- // cadet leads: it is the cloud option, selected like any other provider.
58
55
  const CATALOG: readonly TtsProviderDefinition[] = [
59
- DEFINITIONS.cadet,
60
56
  DEFINITIONS.elevenlabs,
61
57
  DEFINITIONS["fish-audio"],
62
58
  DEFINITIONS.deepgram,
package/src/tts/types.ts CHANGED
@@ -28,7 +28,6 @@ export const TTS_PROVIDER_IDS = [
28
28
  "fish-audio",
29
29
  "deepgram",
30
30
  "xai",
31
- "cadet",
32
31
  ] as const;
33
32
 
34
33
  /**
@@ -1,330 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { beforeEach, describe, expect, mock, test } from "bun:test";
4
-
5
- import * as actualTtsCapability from "../calls/telephony-tts-capability.js";
6
- import * as actualCloudSpeech from "../cloud/cloud-speech.js";
7
- import * as actualResolve from "../providers/speech-to-text/resolve.js";
8
-
9
- let mockCloudSpeechAvailable = false;
10
- let mockSttKeyResolves = false;
11
- let mockTtsSecretResolves = false;
12
-
13
- mock.module("../cloud/cloud-speech.js", () => ({
14
- ...actualCloudSpeech,
15
- managedSpeechAvailable: async () => mockCloudSpeechAvailable,
16
- }));
17
-
18
- mock.module("../providers/speech-to-text/resolve.js", () => ({
19
- ...actualResolve,
20
- sttProviderKeyResolves: async () => mockSttKeyResolves,
21
- }));
22
-
23
- mock.module("../calls/telephony-tts-capability.js", () => ({
24
- ...actualTtsCapability,
25
- ttsSecretResolves: async () => mockTtsSecretResolves,
26
- }));
27
-
28
- import {
29
- maybeDefaultSpeechToCloud,
30
- resolveEffectiveSpeechProviders,
31
- } from "../config/cloud-speech-defaults.js";
32
- import { getConfig, invalidateConfigCache } from "../config/loader.js";
33
- import { sttCatalogKeyForRole } from "../stt/roles.js";
34
-
35
- const WORKSPACE_DIR = process.env.CADET_WORKSPACE_DIR!;
36
- const CONFIG_PATH = join(WORKSPACE_DIR, "config.json");
37
-
38
- function ensureTestDir(): void {
39
- if (!existsSync(WORKSPACE_DIR)) {
40
- mkdirSync(WORKSPACE_DIR, { recursive: true });
41
- }
42
- }
43
-
44
- function writeConfig(obj: unknown): void {
45
- writeFileSync(CONFIG_PATH, JSON.stringify(obj));
46
- invalidateConfigCache();
47
- }
48
-
49
- function readConfig(): Record<string, unknown> {
50
- return JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
51
- }
52
-
53
- beforeEach(() => {
54
- ensureTestDir();
55
- writeConfig({});
56
- mockCloudSpeechAvailable = false;
57
- mockSttKeyResolves = false;
58
- mockTtsSecretResolves = false;
59
- });
60
-
61
- describe("maybeDefaultSpeechToCloud", () => {
62
- test("no-ops when cloud speech is unavailable", async () => {
63
- await maybeDefaultSpeechToCloud();
64
-
65
- const config = readConfig();
66
- expect(config.services).toBeUndefined();
67
- });
68
-
69
- test("defaults both services to cadet when no BYOK credentials resolve", async () => {
70
- mockCloudSpeechAvailable = true;
71
-
72
- await maybeDefaultSpeechToCloud();
73
-
74
- const config = readConfig();
75
- expect((config.services as any)?.stt?.provider).toBe("cadet");
76
- expect((config.services as any)?.tts?.provider).toBe("cadet");
77
- expect(getConfig().services.stt.provider).toBe("cadet");
78
- });
79
-
80
- test("leaves a service alone when its BYOK credential resolves", async () => {
81
- mockCloudSpeechAvailable = true;
82
- mockSttKeyResolves = true;
83
-
84
- await maybeDefaultSpeechToCloud();
85
-
86
- const config = readConfig();
87
- expect((config.services as any)?.stt?.provider).toBeUndefined();
88
- expect((config.services as any)?.tts?.provider).toBe("cadet");
89
- });
90
-
91
- test("no-ops when both BYOK credentials resolve", async () => {
92
- mockCloudSpeechAvailable = true;
93
- mockSttKeyResolves = true;
94
- mockTtsSecretResolves = true;
95
-
96
- await maybeDefaultSpeechToCloud();
97
-
98
- const config = readConfig();
99
- expect(config.services).toBeUndefined();
100
- });
101
-
102
- test("no-ops when services are already on cadet", async () => {
103
- mockCloudSpeechAvailable = true;
104
- writeConfig({
105
- services: {
106
- stt: { provider: "cadet" },
107
- tts: { provider: "cadet" },
108
- },
109
- });
110
-
111
- await maybeDefaultSpeechToCloud();
112
-
113
- const config = readConfig();
114
- expect(config).toEqual({
115
- services: {
116
- stt: { provider: "cadet" },
117
- tts: { provider: "cadet" },
118
- },
119
- });
120
- });
121
-
122
- test("a narrowing stand-in is written to the live-voice role, not the global", async () => {
123
- // BYOK Flux with no key: the stand-in preserves turn detection, so it is
124
- // cadet-flux, which streams and nothing else. Writing that globally is
125
- // how batch transcription and telephony disappear for a cloud user.
126
- mockCloudSpeechAvailable = true;
127
- writeConfig({
128
- services: {
129
- stt: {
130
- provider: "deepgram",
131
- providers: { deepgram: { model: "flux" } },
132
- },
133
- tts: { provider: "cadet" },
134
- },
135
- });
136
-
137
- await maybeDefaultSpeechToCloud();
138
-
139
- const stt = (readConfig().services as any).stt;
140
- expect(stt.roles.liveVoice).toEqual({ provider: "cadet", model: "flux" });
141
- // The other consumers land on the stand-in's base, which serves them all.
142
- expect(stt.provider).toBe("cadet");
143
- expect(stt.providers.cadet.model).toBe("nova-3");
144
- });
145
-
146
- test("the role write leaves batch and telephony on a provider that answers", async () => {
147
- mockCloudSpeechAvailable = true;
148
- writeConfig({
149
- services: {
150
- stt: {
151
- provider: "deepgram",
152
- providers: { deepgram: { model: "flux" } },
153
- },
154
- tts: { provider: "cadet" },
155
- },
156
- });
157
-
158
- await maybeDefaultSpeechToCloud();
159
-
160
- invalidateConfigCache();
161
- const stt = getConfig().services.stt;
162
- expect(sttCatalogKeyForRole(stt, "liveVoice")).toBe("cadet-flux");
163
- expect(sttCatalogKeyForRole(stt, "batch")).toBe("cadet");
164
- expect(sttCatalogKeyForRole(stt, "telephony")).toBe("cadet");
165
- });
166
-
167
- test("a language Flux has no model for keeps live voice on nova-3", async () => {
168
- // Korean is outside Flux's ten-language roster, so the relay would reject
169
- // the dial. Standing in with Flux hands the speaker a dead mic rather
170
- // than a worse transcriber.
171
- mockCloudSpeechAvailable = true;
172
- writeConfig({
173
- services: {
174
- stt: {
175
- provider: "deepgram",
176
- language: "ko",
177
- providers: { deepgram: { model: "flux" } },
178
- },
179
- tts: { provider: "cadet" },
180
- },
181
- });
182
-
183
- await maybeDefaultSpeechToCloud();
184
-
185
- const stt = (readConfig().services as any).stt;
186
- expect(stt.provider).toBe("cadet");
187
- expect(stt.providers.cadet.model).toBe("nova-3");
188
- expect(stt.roles).toBeUndefined();
189
- });
190
-
191
- test("a language Flux does serve still reaches the flux stand-in", async () => {
192
- mockCloudSpeechAvailable = true;
193
- writeConfig({
194
- services: {
195
- stt: {
196
- provider: "deepgram",
197
- language: "hi",
198
- providers: { deepgram: { model: "flux" } },
199
- },
200
- tts: { provider: "cadet" },
201
- },
202
- });
203
-
204
- await maybeDefaultSpeechToCloud();
205
-
206
- const stt = (readConfig().services as any).stt;
207
- expect(stt.roles.liveVoice).toEqual({ provider: "cadet", model: "flux" });
208
- });
209
-
210
- test("a capability-preserving stand-in still writes the global provider", async () => {
211
- // Plain deepgram has no turn detection, so the stand-in is plain cadet,
212
- // which serves every role. That one belongs on the global, not a role.
213
- mockCloudSpeechAvailable = true;
214
- writeConfig({
215
- services: {
216
- stt: { provider: "deepgram" },
217
- tts: { provider: "cadet" },
218
- },
219
- });
220
-
221
- await maybeDefaultSpeechToCloud();
222
-
223
- const stt = (readConfig().services as any).stt;
224
- expect(stt.provider).toBe("cadet");
225
- expect(stt.roles).toBeUndefined();
226
- });
227
-
228
- test("never repoints an explicit BYOK provider with resolving credentials", async () => {
229
- mockCloudSpeechAvailable = true;
230
- mockSttKeyResolves = true;
231
- mockTtsSecretResolves = true;
232
- writeConfig({
233
- services: {
234
- stt: { provider: "deepgram" },
235
- tts: { provider: "elevenlabs" },
236
- },
237
- });
238
-
239
- await maybeDefaultSpeechToCloud();
240
-
241
- const config = readConfig();
242
- expect((config.services as any).stt.provider).toBe("deepgram");
243
- expect((config.services as any).tts.provider).toBe("elevenlabs");
244
- });
245
- });
246
-
247
- describe("managed live voice runs Flux", () => {
248
- // Turn detection is the only reason to reach for that family, and a cloud
249
- // user cannot ask for it: the provider picker offers no family, so `cadet`
250
- // is as specific as they can be.
251
- test("live voice upgrades to the flux family", async () => {
252
- mockCloudSpeechAvailable = true;
253
- writeConfig({ services: { stt: { provider: "cadet" } } });
254
-
255
- const { stt } = await resolveEffectiveSpeechProviders(undefined, {
256
- role: "liveVoice",
257
- });
258
-
259
- expect(stt).toBe("cadet-flux");
260
- });
261
-
262
- test("no other consumer follows it there", async () => {
263
- // The family streams and nothing else, so batch and telephony would lose
264
- // their transcriber entirely.
265
- mockCloudSpeechAvailable = true;
266
- writeConfig({ services: { stt: { provider: "cadet" } } });
267
-
268
- for (const role of ["batch", "telephony", "dictation", "watch"] as const) {
269
- const { stt } = await resolveEffectiveSpeechProviders(undefined, {
270
- role,
271
- });
272
- expect(stt).toBe("cadet");
273
- }
274
- const { stt: roleless } = await resolveEffectiveSpeechProviders();
275
- expect(roleless).toBe("cadet");
276
- });
277
-
278
- test("a family the user named wins", async () => {
279
- // `services.stt.providers.cadet.model` accepts nova-3, so quietly
280
- // overriding it would be the silent substitution roles exist to prevent.
281
- mockCloudSpeechAvailable = true;
282
- writeConfig({
283
- services: {
284
- stt: { provider: "cadet", providers: { cadet: { model: "nova-3" } } },
285
- },
286
- });
287
-
288
- const { stt } = await resolveEffectiveSpeechProviders(undefined, {
289
- role: "liveVoice",
290
- });
291
-
292
- expect(stt).toBe("cadet");
293
- });
294
-
295
- test("a language the family cannot serve stays on nova-3", async () => {
296
- mockCloudSpeechAvailable = true;
297
- writeConfig({
298
- services: { stt: { provider: "cadet", language: "ko" } },
299
- });
300
-
301
- const { stt } = await resolveEffectiveSpeechProviders(undefined, {
302
- role: "liveVoice",
303
- });
304
-
305
- expect(stt).toBe("cadet");
306
- });
307
-
308
- test("nothing is upgraded while cloud speech is unavailable", async () => {
309
- mockCloudSpeechAvailable = false;
310
- writeConfig({ services: { stt: { provider: "cadet" } } });
311
-
312
- const { stt } = await resolveEffectiveSpeechProviders(undefined, {
313
- role: "liveVoice",
314
- });
315
-
316
- expect(stt).toBe("cadet");
317
- });
318
-
319
- test("the upgrade writes no config", async () => {
320
- // A resolution rule, not a substitution: nothing lands on disk for a user
321
- // to discover, reset, or have to migrate.
322
- mockCloudSpeechAvailable = true;
323
- writeConfig({ services: { stt: { provider: "cadet" } } });
324
- const before = JSON.stringify(readConfig());
325
-
326
- await resolveEffectiveSpeechProviders(undefined, { role: "liveVoice" });
327
-
328
- expect(JSON.stringify(readConfig())).toBe(before);
329
- });
330
- });