@mycadet/assistant 0.12.11 → 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 (176) hide show
  1. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
  2. package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
  3. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
  4. package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
  5. package/node_modules/@mycadet/gateway-client/src/gateway-ipc-contracts.ts +0 -20
  6. package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
  7. package/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
  8. package/openapi.yaml +2 -708
  9. package/package.json +2 -3
  10. package/scripts/sync-web-search-catalog.ts +1 -2
  11. package/src/__tests__/cloud-profile-guard.test.ts +2 -2
  12. package/src/__tests__/config-schema.test.ts +6 -38
  13. package/src/__tests__/conversation-queue.test.ts +45 -6
  14. package/src/__tests__/db-readiness-http-gate.test.ts +0 -6
  15. package/src/__tests__/persist-onboarding-artifacts.test.ts +0 -1
  16. package/src/__tests__/persona-resolver.test.ts +0 -51
  17. package/src/__tests__/provider-cloud-proxy-integration.test.ts +2 -110
  18. package/src/__tests__/run-due-schedules.test.ts +0 -4
  19. package/src/__tests__/schedule-store.test.ts +0 -12
  20. package/src/__tests__/stt-stream-session.test.ts +4 -4
  21. package/src/__tests__/telephony-tts-guard.test.ts +2 -50
  22. package/src/__tests__/voice-config-update.test.ts +12 -167
  23. package/src/__tests__/web-search-catalog-parity.test.ts +0 -2
  24. package/src/__tests__/workspace-migration-130-speech-mode-to-provider.test.ts +9 -7
  25. package/src/__tests__/workspace-migration-132-web-search-mode-to-provider.test.ts +6 -6
  26. package/src/calls/__tests__/voice-session-bridge.test.ts +1 -4
  27. package/src/calls/resolve-call-tts-provider.ts +6 -25
  28. package/src/calls/telephony-credential-preflight.ts +0 -10
  29. package/src/calls/telephony-tts-capability.ts +1 -17
  30. package/src/cli/commands/tts.ts +1 -2
  31. package/src/cli/index.help.ts +0 -2
  32. package/src/cli/program.ts +0 -2
  33. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +4 -42
  34. package/src/config/schemas/__tests__/stt.test.ts +10 -14
  35. package/src/config/schemas/services.ts +5 -6
  36. package/src/config/schemas/stt.ts +1 -3
  37. package/src/config/schemas/tts.ts +1 -30
  38. package/src/daemon/daemon-readiness.ts +4 -29
  39. package/src/daemon/lifecycle.ts +0 -31
  40. package/src/daemon/providers-setup.ts +0 -8
  41. package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
  42. package/src/heartbeat/heartbeat-service.ts +1 -66
  43. package/src/ipc/__tests__/db-readiness-ipc-gate.test.ts +1 -9
  44. package/src/live-voice/__tests__/live-voice-credential-preflight.test.ts +0 -44
  45. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +4 -6
  46. package/src/live-voice/__tests__/live-voice-stt.test.ts +1 -1
  47. package/src/live-voice/live-voice-credential-preflight.ts +9 -33
  48. package/src/live-voice/live-voice-session.ts +10 -6
  49. package/src/live-voice/live-voice-tts.ts +1 -8
  50. package/src/plugins/defaults/memory/worker.ts +3 -3
  51. package/src/prompts/persona-resolver.ts +0 -35
  52. package/src/providers/__tests__/search-provider-catalog.test.ts +5 -8
  53. package/src/providers/__tests__/voice-error-copy.test.ts +9 -10
  54. package/src/providers/search-provider-catalog.ts +7 -39
  55. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +3 -47
  56. package/src/providers/speech-to-text/__tests__/resolve.test.ts +6 -372
  57. package/src/providers/speech-to-text/provider-catalog.ts +2 -73
  58. package/src/providers/speech-to-text/resolve.ts +3 -120
  59. package/src/runtime/http-router-types.ts +1 -3
  60. package/src/runtime/http-server.ts +1 -1
  61. package/src/runtime/routes/__tests__/tts-routes.test.ts +2 -6
  62. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +7 -7
  63. package/src/runtime/routes/index.ts +0 -4
  64. package/src/runtime/routes/live-voice-routes.test.ts +4 -11
  65. package/src/runtime/routes/live-voice-routes.ts +8 -11
  66. package/src/runtime/routes/secret-routes.ts +0 -6
  67. package/src/runtime/routes/tts-routes.ts +0 -38
  68. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1 -7
  69. package/src/schedule/__tests__/worker-mcp-readiness.test.ts +0 -4
  70. package/src/schedule/schedule-store.ts +0 -7
  71. package/src/schedule/scheduler.ts +0 -5
  72. package/src/schedule/worker.ts +1 -1
  73. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +2 -10
  74. package/src/stt/daemon-batch-transcriber.ts +4 -38
  75. package/src/stt/types.ts +1 -9
  76. package/src/tools/network/__tests__/web-search.test.ts +3 -250
  77. package/src/tools/network/web-search.ts +4 -165
  78. package/src/tts/__tests__/provider-resolution.test.ts +0 -5
  79. package/src/tts/provider-catalog.ts +0 -4
  80. package/src/tts/types.ts +0 -1
  81. package/src/__tests__/cloud-speech-defaults.test.ts +0 -330
  82. package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1708
  83. package/src/__tests__/migration-export-http.test.ts +0 -557
  84. package/src/__tests__/migration-export-streaming.test.ts +0 -350
  85. package/src/__tests__/migration-export-to-gcs.test.ts +0 -706
  86. package/src/__tests__/migration-import-commit-http.test.ts +0 -1176
  87. package/src/__tests__/migration-import-from-gcs.test.ts +0 -534
  88. package/src/__tests__/migration-import-from-path.test.ts +0 -324
  89. package/src/__tests__/migration-import-from-url.test.ts +0 -588
  90. package/src/__tests__/migration-import-preflight-http.test.ts +0 -739
  91. package/src/__tests__/migration-jobs-status.test.ts +0 -139
  92. package/src/__tests__/migration-parity-persistence.test.ts +0 -1891
  93. package/src/__tests__/migration-transport.test.ts +0 -1089
  94. package/src/__tests__/migration-validate-http.test.ts +0 -634
  95. package/src/__tests__/migration-wizard.test.ts +0 -1395
  96. package/src/__tests__/rebind-secrets-screen.test.ts +0 -876
  97. package/src/__tests__/sanitize-config-for-transfer.test.ts +0 -259
  98. package/src/__tests__/transfer-progress-screen.test.ts +0 -1217
  99. package/src/__tests__/validation-results-screen.test.ts +0 -1130
  100. package/src/__tests__/vbundle-pax-and-symlink.test.ts +0 -147
  101. package/src/background-wake/background-wake-routes.test.ts +0 -906
  102. package/src/background-wake/cloud-client.test.ts +0 -328
  103. package/src/background-wake/cloud-client.ts +0 -196
  104. package/src/background-wake/next-wake.test.ts +0 -335
  105. package/src/background-wake/next-wake.ts +0 -188
  106. package/src/background-wake/publisher.ts +0 -93
  107. package/src/background-wake/wake-intent-hooks.test.ts +0 -234
  108. package/src/cli/commands/__tests__/backup.test.ts +0 -363
  109. package/src/cli/commands/backup.help.ts +0 -180
  110. package/src/cli/commands/backup.ts +0 -398
  111. package/src/cloud/cloud-speech.test.ts +0 -335
  112. package/src/cloud/cloud-speech.ts +0 -300
  113. package/src/config/cloud-speech-defaults.ts +0 -300
  114. package/src/config/sanitize-for-transfer.ts +0 -111
  115. package/src/live-voice/__tests__/live-voice-cloud-speech-fallback.test.ts +0 -250
  116. package/src/providers/speech-to-text/__tests__/cadet-cloud-realtime.test.ts +0 -457
  117. package/src/providers/speech-to-text/__tests__/cadet-cloud.test.ts +0 -271
  118. package/src/providers/speech-to-text/__tests__/cadet-speech-relay-connection.test.ts +0 -126
  119. package/src/providers/speech-to-text/cadet-cloud-flux-realtime.ts +0 -309
  120. package/src/providers/speech-to-text/cadet-cloud-realtime.ts +0 -315
  121. package/src/providers/speech-to-text/cadet-cloud.ts +0 -108
  122. package/src/providers/speech-to-text/cadet-speech-relay-connection.ts +0 -176
  123. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +0 -254
  124. package/src/runtime/migrations/__tests__/job-registry.test.ts +0 -346
  125. package/src/runtime/migrations/__tests__/origin-mode.test.ts +0 -62
  126. package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +0 -184
  127. package/src/runtime/migrations/__tests__/staged-import-path.test.ts +0 -110
  128. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +0 -112
  129. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +0 -285
  130. package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +0 -126
  131. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +0 -253
  132. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +0 -208
  133. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +0 -485
  134. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +0 -349
  135. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +0 -196
  136. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +0 -551
  137. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +0 -428
  138. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +0 -220
  139. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +0 -1823
  140. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +0 -598
  141. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +0 -463
  142. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -538
  143. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +0 -515
  144. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +0 -453
  145. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +0 -319
  146. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +0 -240
  147. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +0 -473
  148. package/src/runtime/migrations/gcs-signed-url.ts +0 -190
  149. package/src/runtime/migrations/job-registry.ts +0 -297
  150. package/src/runtime/migrations/migration-transport.ts +0 -612
  151. package/src/runtime/migrations/migration-wizard.ts +0 -747
  152. package/src/runtime/migrations/origin-mode.ts +0 -42
  153. package/src/runtime/migrations/rebind-secrets-screen.ts +0 -412
  154. package/src/runtime/migrations/staged-import-path.ts +0 -116
  155. package/src/runtime/migrations/transfer-progress-screen.ts +0 -323
  156. package/src/runtime/migrations/validation-results-screen.ts +0 -469
  157. package/src/runtime/migrations/vbundle-builder.ts +0 -1382
  158. package/src/runtime/migrations/vbundle-import-analyzer.ts +0 -405
  159. package/src/runtime/migrations/vbundle-import-policy.ts +0 -241
  160. package/src/runtime/migrations/vbundle-importer.ts +0 -826
  161. package/src/runtime/migrations/vbundle-metadata-merge.ts +0 -113
  162. package/src/runtime/migrations/vbundle-streaming-importer.ts +0 -2844
  163. package/src/runtime/migrations/vbundle-streaming-validator.ts +0 -426
  164. package/src/runtime/migrations/vbundle-tar-stream.ts +0 -244
  165. package/src/runtime/migrations/vbundle-validator.ts +0 -724
  166. package/src/runtime/routes/__tests__/migration-cadet-metadata-reconcile.test.ts +0 -227
  167. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +0 -54
  168. package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +0 -70
  169. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +0 -257
  170. package/src/runtime/routes/background-wake-routes.ts +0 -387
  171. package/src/runtime/routes/migration-routes.ts +0 -2584
  172. package/src/tools/network/__tests__/cloud-search-proxy.test.ts +0 -282
  173. package/src/tools/network/cloud-search-proxy.ts +0 -211
  174. package/src/tts/__tests__/cadet-provider.test.ts +0 -253
  175. package/src/tts/providers/cadet-provider.ts +0 -244
  176. package/src/types/tar-stream.d.ts +0 -66
@@ -1,15 +1,6 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
- import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
4
-
5
- import * as actualCloudSpeech from "../cloud/cloud-speech.js";
6
-
7
- let mockCloudSpeechAvailable = false;
8
-
9
- mock.module("../cloud/cloud-speech.js", () => ({
10
- ...actualCloudSpeech,
11
- managedSpeechAvailable: async () => mockCloudSpeechAvailable,
12
- }));
3
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
13
4
 
14
5
  // ---------------------------------------------------------------------------
15
6
  // Mocks — declared before imports that depend on platform/logger
@@ -71,7 +62,6 @@ beforeEach(() => {
71
62
  ensureTestDir();
72
63
  writeConfig({});
73
64
  invalidateConfigCache();
74
- mockCloudSpeechAvailable = false;
75
65
  });
76
66
 
77
67
  afterEach(() => {
@@ -144,18 +134,6 @@ describe("voice_config_update — tts_provider", () => {
144
134
  expect(tts).not.toHaveProperty("mode");
145
135
  });
146
136
 
147
- test("tts_provider cadet persists when a cloud connection is available", async () => {
148
- mockCloudSpeechAvailable = true;
149
-
150
- const result = await run(
151
- { setting: "tts_provider", value: "cadet" },
152
- makeContext(),
153
- );
154
-
155
- expect(result.isError).toBe(false);
156
- expect((readConfig().services as any).tts.provider).toBe("cadet");
157
- });
158
-
159
137
  test("broadcasts ttsProvider to client", async () => {
160
138
  const messages: any[] = [];
161
139
  const ctx = makeContext({
@@ -220,130 +198,36 @@ describe("voice_config_update — tts_voice_id", () => {
220
198
  // Tests: tts_voice_id targets the active provider's voice field
221
199
  // ---------------------------------------------------------------------------
222
200
 
223
- describe("voice_config_update — tts_voice_id (managed/cadet active)", () => {
224
- function makeCadetActive(): void {
225
- writeConfig({ services: { tts: { provider: "cadet" } } });
201
+ describe("voice_config_update — tts_voice_id", () => {
202
+ test("writes the voice id and broadcasts the ttsVoiceId key", async () => {
203
+ writeConfig({ services: { tts: { provider: "elevenlabs" } } });
226
204
  invalidateConfigCache();
227
- }
228
-
229
- test("writes a Deepgram Aura model id to services.tts.providers.cadet.model", async () => {
230
- makeCadetActive();
231
-
232
- const result = await run(
233
- { setting: "tts_voice_id", value: "aura-2-zeus-en" },
234
- makeContext(),
235
- );
236
-
237
- expect(result.isError).toBe(false);
238
- const config = readConfig();
239
- expect((config.services as any)?.tts?.providers?.cadet?.model).toBe(
240
- "aura-2-zeus-en",
241
- );
242
- // The ElevenLabs field is never touched when cadet is active.
243
- expect(
244
- (config.services as any)?.tts?.providers?.elevenlabs?.voiceId,
245
- ).toBeUndefined();
246
- });
247
-
248
- test("accepts an ElevenLabs voice id as a cloud model (managed serves ElevenLabs voices)", async () => {
249
- makeCadetActive();
250
-
251
- const result = await run(
252
- { setting: "tts_voice_id", value: "EXAVITQu4vr4xnSDxMaL" },
253
- makeContext(),
254
- );
255
-
256
- expect(result.isError).toBe(false);
257
- expect((readConfig().services as any)?.tts?.providers?.cadet?.model).toBe(
258
- "EXAVITQu4vr4xnSDxMaL",
259
- );
260
- });
261
-
262
- test("does not broadcast the ElevenLabs ttsVoiceId key for a cloud voice", async () => {
263
- makeCadetActive();
264
205
  const messages: any[] = [];
265
206
  const ctx = makeContext({
266
207
  sendToClient: (msg: any) => messages.push(msg),
267
208
  });
268
209
 
269
- const result = await run(
270
- { setting: "tts_voice_id", value: "aura-2-zeus-en" },
271
- ctx,
272
- );
273
-
274
- expect(result.isError).toBe(false);
275
- expect(messages).toHaveLength(0);
276
- expect(result.content).not.toContain("broadcast");
277
- });
278
-
279
- test("hints the inline picker for the next cloud voice change", async () => {
280
- makeCadetActive();
281
-
282
- const result = await run(
283
- { setting: "tts_voice_id", value: "aura-2-zeus-en" },
284
- makeContext(),
285
- );
210
+ const result = await run({ setting: "tts_voice_id", value: "abc123" }, ctx);
286
211
 
287
212
  expect(result.isError).toBe(false);
288
- expect(result.content).toStartWith("Cadet Cloud voice updated to");
289
- expect(result.content).toContain(
290
- 'ui_show { surface_type: "voice_picker", data: {} }',
291
- );
213
+ expect(messages).toHaveLength(1);
214
+ expect(messages[0].key).toBe("ttsVoiceId");
215
+ expect(messages[0].value).toBe("abc123");
292
216
  });
293
217
 
294
- test("does not hint the picker when the voice is not managed", async () => {
218
+ test("rejects a value with characters invalid for any voice id", async () => {
295
219
  writeConfig({ services: { tts: { provider: "elevenlabs" } } });
296
220
  invalidateConfigCache();
297
221
 
298
- const result = await run(
299
- { setting: "tts_voice_id", value: "abc123" },
300
- makeContext(),
301
- );
302
-
303
- expect(result.isError).toBe(false);
304
- expect(result.content).not.toContain("voice_picker");
305
- });
306
-
307
- test("does not hint the picker for a non-voice setting", async () => {
308
- makeCadetActive();
309
-
310
- const result = await run(
311
- { setting: "conversation_timeout", value: 30 },
312
- makeContext(),
313
- );
314
-
315
- expect(result.isError).toBe(false);
316
- expect(result.content).not.toContain("voice_picker");
317
- });
318
-
319
- test("rejects a value with characters invalid for any voice id", async () => {
320
- makeCadetActive();
321
-
322
222
  const result = await run(
323
223
  { setting: "tts_voice_id", value: "a british man" },
324
224
  makeContext(),
325
225
  );
326
226
 
327
227
  expect(result.isError).toBe(true);
328
- expect((readConfig().services as any)?.tts?.providers?.cadet?.model).toBe(
329
- undefined,
330
- );
331
- });
332
-
333
- test("broadcasts the ElevenLabs ttsVoiceId key when elevenlabs is active", async () => {
334
- writeConfig({ services: { tts: { provider: "elevenlabs" } } });
335
- invalidateConfigCache();
336
- const messages: any[] = [];
337
- const ctx = makeContext({
338
- sendToClient: (msg: any) => messages.push(msg),
339
- });
340
-
341
- const result = await run({ setting: "tts_voice_id", value: "abc123" }, ctx);
342
-
343
- expect(result.isError).toBe(false);
344
- expect(messages).toHaveLength(1);
345
- expect(messages[0].key).toBe("ttsVoiceId");
346
- expect(messages[0].value).toBe("abc123");
228
+ expect(
229
+ (readConfig().services as any)?.tts?.providers?.elevenlabs?.voiceId,
230
+ ).toBeUndefined();
347
231
  });
348
232
  });
349
233
 
@@ -536,31 +420,6 @@ describe("voice_config_update — stt_provider", () => {
536
420
  );
537
421
  });
538
422
 
539
- test("persists the cadet provider when a cloud connection is available", async () => {
540
- mockCloudSpeechAvailable = true;
541
-
542
- const result = await run(
543
- { setting: "stt_provider", value: "cadet" },
544
- makeContext(),
545
- );
546
-
547
- expect(result.isError).toBe(false);
548
- expect((readConfig().services as any)?.stt?.provider).toBe("cadet");
549
- });
550
-
551
- test("rejects the cadet provider without a cloud connection", async () => {
552
- mockCloudSpeechAvailable = false;
553
-
554
- const result = await run(
555
- { setting: "stt_provider", value: "cadet" },
556
- makeContext(),
557
- );
558
-
559
- expect(result.isError).toBe(true);
560
- expect(result.content).toContain("assistant cloud connect");
561
- expect((readConfig().services as any)?.stt?.provider).toBeUndefined();
562
- });
563
-
564
423
  test("stt_model persists under the active provider", async () => {
565
424
  // Flux stays reachable from this surface after ceasing to be a provider
566
425
  // id: it is a model family on whichever provider is active.
@@ -916,22 +775,8 @@ describe("voice_config_update - stt_language", () => {
916
775
  // ---------------------------------------------------------------------------
917
776
 
918
777
  describe("voice_config_update — catalog-driven provider validation", () => {
919
- test("rejects tts_provider cadet without a cloud connection", async () => {
920
- mockCloudSpeechAvailable = false;
921
-
922
- const result = await run(
923
- { setting: "tts_provider", value: "cadet" },
924
- makeContext(),
925
- );
926
-
927
- expect(result.isError).toBe(true);
928
- expect(result.content).toContain("assistant cloud connect");
929
- expect((readConfig().services as any)?.tts?.provider).toBeUndefined();
930
- });
931
-
932
778
  test("accepts every provider ID in the catalog", async () => {
933
779
  // The catalog includes cadet, which is gated on a cloud connection.
934
- mockCloudSpeechAvailable = true;
935
780
  const catalogIds = listCatalogProviderIds();
936
781
  expect(catalogIds.length).toBeGreaterThanOrEqual(1);
937
782
 
@@ -23,7 +23,6 @@ interface JsonCatalogEntry {
23
23
  id: string;
24
24
  displayName: string;
25
25
  displayNameLong?: string;
26
- kind: "managed" | "byok";
27
26
  apiKeyPrefix?: string;
28
27
  envVar?: string;
29
28
  secretKey?: string;
@@ -61,7 +60,6 @@ function entryToPlain(
61
60
  if (entry.displayNameLong !== undefined) {
62
61
  out.displayNameLong = entry.displayNameLong;
63
62
  }
64
- out.kind = entry.kind;
65
63
  if (entry.apiKeyPrefix !== undefined) {
66
64
  out.apiKeyPrefix = entry.apiKeyPrefix;
67
65
  }
@@ -9,7 +9,6 @@ import { tmpdir } from "node:os";
9
9
  import { join } from "node:path";
10
10
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
11
 
12
- import { AssistantConfigSchema } from "../config/schema.js";
13
12
  import { speechModeToProviderMigration } from "../workspace/migrations/130-speech-mode-to-provider.js";
14
13
  import { WORKSPACE_MIGRATIONS } from "../workspace/migrations/registry.js";
15
14
  import { getLastWorkspaceMigrationId } from "../workspace/migrations/runner.js";
@@ -146,9 +145,10 @@ describe("130-speech-mode-to-provider", () => {
146
145
  expect(() => speechModeToProviderMigration.run(workspaceDir)).not.toThrow();
147
146
  });
148
147
 
149
- // The migrated shape is what the daemon actually parses, so a cloud user
150
- // must land on cadet rather than falling back to a keyless BYOK provider.
151
- test("migrated output parses to the cadet provider", () => {
148
+ // The migrated shape is frozen (the migration never reruns), asserted raw:
149
+ // the current config schema no longer knows the cadet provider id, so a
150
+ // schema parse of a migrated cloud config is no longer a valid invariant.
151
+ test("migrated output folds managed mode into the cadet provider", () => {
152
152
  writeConfig({
153
153
  services: {
154
154
  stt: { mode: "managed", provider: "deepgram", providers: {} },
@@ -157,10 +157,12 @@ describe("130-speech-mode-to-provider", () => {
157
157
  });
158
158
 
159
159
  speechModeToProviderMigration.run(workspaceDir);
160
- const parsed = AssistantConfigSchema.parse(readConfig());
161
160
 
162
- expect(parsed.services.stt.provider).toBe("cadet");
163
- expect(parsed.services.tts.provider).toBe("cadet");
161
+ expect(services(readConfig()).stt).toEqual({
162
+ provider: "cadet",
163
+ providers: {},
164
+ });
165
+ expect(services(readConfig()).tts).toEqual({ provider: "cadet" });
164
166
  });
165
167
 
166
168
  describe("down", () => {
@@ -9,7 +9,6 @@ import { tmpdir } from "node:os";
9
9
  import { join } from "node:path";
10
10
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
11
 
12
- import { AssistantConfigSchema } from "../config/schema.js";
13
12
  import { WORKSPACE_MIGRATIONS } from "../workspace/migrations/registry.js";
14
13
  import { getLastWorkspaceMigrationId } from "../workspace/migrations/runner.js";
15
14
 
@@ -163,17 +162,18 @@ describe("132-web-search-mode-to-provider", () => {
163
162
  ).not.toThrow();
164
163
  });
165
164
 
166
- // The migrated shape is what the daemon actually parses, so a cloud user
167
- // must land on cadet rather than falling back to a keyless BYOK provider.
168
- test("migrated output parses to the cadet provider", () => {
165
+ // The migrated shape is frozen (the migration never reruns), asserted raw:
166
+ // the current config schema no longer knows the cadet provider id, so a
167
+ // schema parse of a migrated cloud config is no longer a valid invariant —
168
+ // the config loader's recovery ladder owns any on-disk 'cadet' values.
169
+ test("migrated output folds managed mode into the cadet provider", () => {
169
170
  writeConfig({
170
171
  services: { "web-search": { mode: "managed", provider: "brave" } },
171
172
  });
172
173
 
173
174
  webSearchModeToProviderMigration.run(workspaceDir);
174
- const parsed = AssistantConfigSchema.parse(readConfig());
175
175
 
176
- expect(parsed.services["web-search"].provider).toBe("cadet");
176
+ expect(webSearch(readConfig())).toEqual({ provider: "cadet" });
177
177
  });
178
178
 
179
179
  describe("down", () => {
@@ -1091,16 +1091,13 @@ describe("default call protocol numbered rules", () => {
1091
1091
 
1092
1092
  test("a monolingual listening language becomes the pre-speech fallback", () => {
1093
1093
  // An assistant pinned to services.stt.language = "es" on a provider that
1094
- // honors the pin (deepgram, cadet) is already transcribing Spanish, so
1094
+ // honors the pin (deepgram) is already transcribing Spanish, so
1095
1095
  // the opener must not default to English. The default test config runs
1096
1096
  // the auto-detect branch ("multi"), so the pinned branch is covered at
1097
1097
  // the fragment level.
1098
1098
  expect(preSpeechLanguageRuleFragment("es", "deepgram")).toContain(
1099
1099
  'configured listening language ("es")',
1100
1100
  );
1101
- expect(preSpeechLanguageRuleFragment("es", "cadet")).toContain(
1102
- "default to English only when neither gives a language",
1103
- );
1104
1101
  for (const autoDetect of ["multi", "", " ", undefined]) {
1105
1102
  expect(preSpeechLanguageRuleFragment(autoDetect, "deepgram")).toBe(
1106
1103
  "use the language the Task context implies, if any; otherwise default to English",
@@ -7,7 +7,6 @@
7
7
  * native-vs-synthesized strategy decision stay in one implementation.
8
8
  */
9
9
 
10
- import { resolveEffectiveSpeechProviders } from "../config/cloud-speech-defaults.js";
11
10
  import { getConfig } from "../config/loader.js";
12
11
  import {
13
12
  getCatalogProvider,
@@ -74,13 +73,6 @@ export interface ResolveCallTtsOptions {
74
73
  /**
75
74
  * Resolve the active TTS provider via the global provider abstraction.
76
75
  *
77
- * The provider is the effective one after cloud-speech defaulting
78
- * ({@link resolveEffectiveSpeechProviders}): a configured BYOK provider
79
- * whose credential does not resolve is stood in for by cloud speech
80
- * while the cloud connection is usable, the same substitution live
81
- * voice makes, so a fresh Cadet connection speaks on the phone with zero
82
- * TTS configuration.
83
- *
84
76
  * The native-vs-synthesized decision is driven by the catalog's
85
77
  * `callMode` field via {@link resolveCallStrategy}. Providers with
86
78
  * `callMode: "synthesized-play"` have their audio streamed through the
@@ -185,25 +177,14 @@ export async function resolveCallTtsProvider(
185
177
  }
186
178
 
187
179
  /**
188
- * The TTS provider the call actually uses after cloud-speech defaulting.
189
- * A failure inside the cloud lookup (platform client, credential store)
190
- * keeps the configured provider: a cloud-speech hiccup must not demote a
191
- * working BYOK provider, and the outer resolver's own fallback is the
192
- * silent native path.
180
+ * The TTS provider the call actually uses — the configured one. Kept as a
181
+ * named seam because the outer resolver's own fallback is the silent
182
+ * native path when the config has no services.tts block.
193
183
  */
194
- async function effectiveTtsProviderId(
184
+ function effectiveTtsProviderId(
195
185
  config: ReturnType<typeof getConfig>,
196
- ): Promise<TtsProviderId | undefined> {
197
- try {
198
- const { tts } = await resolveEffectiveSpeechProviders(config);
199
- return tts;
200
- } catch (err) {
201
- log.warn(
202
- { err },
203
- "Managed-speech defaulting failed for call TTS; keeping the configured provider",
204
- );
205
- return undefined;
206
- }
186
+ ): TtsProviderId | undefined {
187
+ return config.services.tts?.provider;
207
188
  }
208
189
 
209
190
  /**
@@ -140,16 +140,6 @@ function ttsGap(
140
140
  clause: `an API key for the text-to-speech provider "${providerId}" (no fallback provider has usable credentials)`,
141
141
  };
142
142
  }
143
- case "missing-cloud-connection": {
144
- return {
145
- gap: {
146
- kind: "tts",
147
- providerId,
148
- reason: `Managed TTS has no usable Cadet Cloud connection and no playable fallback provider is available`,
149
- },
150
- clause: `a Cadet Cloud connection for cloud speech (run 'assistant cloud connect'; no fallback provider has usable credentials)`,
151
- };
152
- }
153
143
  case "missing-fish-audio-reference-id": {
154
144
  return {
155
145
  gap: {
@@ -37,8 +37,7 @@ import { resolveTtsConfig } from "../tts/tts-config-resolver.js";
37
37
  export type TelephonyTtsNotPlayableReason =
38
38
  | "unsupported-format"
39
39
  | "missing-credentials"
40
- | "missing-fish-audio-reference-id"
41
- | "missing-cloud-connection";
40
+ | "missing-fish-audio-reference-id";
42
41
 
43
42
  /**
44
43
  * Result of resolving whether a TTS provider is playable over the
@@ -113,21 +112,6 @@ export async function evaluateTelephonyTtsPlayability(
113
112
  }
114
113
  }
115
114
 
116
- // The cadet secret alone doesn't prove usability: cloud speech also
117
- // needs the cloud assistant identity, or synthesis fails before any
118
- // request is made — with allowNativeFallback false, that would mean
119
- // silent call failures instead of a BYOK fallback.
120
- if (entry.id === "cadet") {
121
- const { managedSpeechAvailable } = await import("../cloud/cloud-speech.js");
122
- if (!(await managedSpeechAvailable())) {
123
- return {
124
- status: "not-playable",
125
- providerId: entry.id,
126
- reason: "missing-cloud-connection",
127
- };
128
- }
129
- }
130
-
131
115
  if (entry.id === "fish-audio" && !fishAudioReferenceIdConfigured()) {
132
116
  return {
133
117
  status: "not-playable",
@@ -222,8 +222,7 @@ export function registerTtsCommand(program: Command): void {
222
222
  }
223
223
 
224
224
  // Read the active TTS provider so the voice lands on the field that
225
- // provider actually reads. Writing the ElevenLabs field while the
226
- // active provider is `cadet` is a silent no-op.
225
+ // provider actually reads.
227
226
  const cfg = await cliIpcCall<{
228
227
  services?: { tts?: { provider?: string } };
229
228
  }>("config_get");
@@ -16,7 +16,6 @@ import { attachmentHelp } from "./commands/attachment.help.js";
16
16
  import { auditHelp } from "./commands/audit.help.js";
17
17
  import { authHelp } from "./commands/auth.help.js";
18
18
  import { avatarHelp } from "./commands/avatar.help.js";
19
- import { backupHelp } from "./commands/backup.help.js";
20
19
  import { bashHelp } from "./commands/bash.help.js";
21
20
  import { browserHelp } from "./commands/browser.help.js";
22
21
  import { cacheHelp } from "./commands/cache.help.js";
@@ -67,7 +66,6 @@ export const CLI_COMMAND_HELP: readonly CliCommandHelp[] = [
67
66
  auditHelp,
68
67
  authHelp,
69
68
  avatarHelp,
70
- backupHelp,
71
69
  bashHelp,
72
70
  browserHelp,
73
71
  cacheHelp,
@@ -10,7 +10,6 @@ import { registerAttachmentCommand } from "./commands/attachment.js";
10
10
  import { registerAuditCommand } from "./commands/audit.js";
11
11
  import { registerAuthCommand } from "./commands/auth.js";
12
12
  import { registerAvatarCommand } from "./commands/avatar.js";
13
- import { registerBackupCommand } from "./commands/backup.js";
14
13
  import { registerBashCommand } from "./commands/bash.js";
15
14
  import { registerBrowserCommand } from "./commands/browser.js";
16
15
  import { registerCacheCommand } from "./commands/cache.js";
@@ -108,7 +107,6 @@ Examples:
108
107
  registerAuditCommand(program);
109
108
  registerAuthCommand(program);
110
109
  registerAvatarCommand(program);
111
- registerBackupCommand(program);
112
110
  registerBashCommand(program);
113
111
  registerBrowserCommand(program);
114
112
  registerCacheCommand(program);
@@ -1,13 +1,9 @@
1
- import { managedSpeechAvailable } from "../../../../cloud/cloud-speech.js";
2
1
  import { normalizeActivationKey } from "../../../../daemon/handlers/config-voice.js";
3
2
  import {
4
3
  DEEPGRAM_MULTI_LANGUAGE_CODES,
5
4
  DEEPGRAM_NOVA3_MONOLINGUAL_CODES,
6
5
  } from "../../../../providers/speech-to-text/deepgram.js";
7
- import {
8
- isCloudSttProvider,
9
- listProviderModelFamilies,
10
- } from "../../../../providers/speech-to-text/provider-catalog.js";
6
+ import { listProviderModelFamilies } from "../../../../providers/speech-to-text/provider-catalog.js";
11
7
  import type { SttProviderId } from "../../../../stt/types.js";
12
8
  import { throwIfCancelled } from "../../../../tools/shared/abort.js";
13
9
  import type {
@@ -28,7 +24,6 @@ import {
28
24
  normalizeSttProviderId,
29
25
  VALID_STT_PROVIDERS,
30
26
  } from "../../../schemas/stt.js";
31
- import { voicePickerHint } from "./shared.js";
32
27
 
33
28
  /**
34
29
  * Valid voice config settings and their UserDefaults key mappings.
@@ -199,19 +194,6 @@ const STT_LANGUAGE_ALIASES: Record<
199
194
  "code-switching": "multi",
200
195
  };
201
196
 
202
- /**
203
- * Same steer `navigate_settings_tab` puts on the Voice tab, applied to the
204
- * strongest competing affordance: this tool's description coaches the model to
205
- * read the cloud catalog and set `tts_voice_id` itself, which is exactly the
206
- * "assistant names voices in prose" outcome the inline picker exists to
207
- * replace. Managed only, because that is the catalog the picker renders. The
208
- * write still happens and the result stays non-error; this only redirects the
209
- * next request.
210
- */
211
- const MANAGED_VOICE_PICKER_HINT = voicePickerHint(
212
- "which lets them hear and pick from the cloud catalog in the conversation. Set the id here only when the user named a specific voice.",
213
- );
214
-
215
197
  function validateSetting(
216
198
  setting: string,
217
199
  value: unknown,
@@ -469,24 +451,8 @@ export async function run(
469
451
  return { content: `Error: ${validation.error}`, isError: true };
470
452
  }
471
453
 
472
- // Cloud speech has more than one STT id, so the gate reads the catalog
473
- // rather than a literal: without this, setting a cloud provider other
474
- // than "cadet" on a disconnected assistant persists happily and then
475
- // resolves no transcriber at all.
476
- const wantsCloudSpeech =
477
- (setting === "stt_provider" &&
478
- isCloudSttProvider(validation.coerced as SttProviderId)) ||
479
- (setting === "tts_provider" && validation.coerced === "cadet");
480
- if (wantsCloudSpeech && !(await managedSpeechAvailable())) {
481
- return {
482
- content:
483
- "Error: cloud speech requires a Cadet Cloud connection. Run 'assistant cloud connect' first.",
484
- isError: true,
485
- };
486
- }
487
-
488
- // Recheck: the cloud-speech reachability probe above is an await, and the
489
- // client broadcast and config write below are what the user would notice.
454
+ // Recheck: the reachability probe above is an await, and the client
455
+ // broadcast and config write below are what the user would notice.
490
456
  throwIfCancelled(context);
491
457
 
492
458
  const meta: VoiceSettingMeta = VOICE_SETTINGS[setting as VoiceSettingName];
@@ -618,14 +584,10 @@ export async function run(
618
584
  AUTO_DETECT_STT_PROVIDERS.has(activeSttProviderId)
619
585
  ? ` Note: the configured STT provider (${activeSttProviderId}) auto-detects the spoken language natively and ignores this setting.`
620
586
  : "";
621
- const pickerNote =
622
- setting === "tts_voice_id" && activeTtsProviderId === "cadet"
623
- ? ` ${MANAGED_VOICE_PICKER_HINT}`
624
- : "";
625
587
  return {
626
588
  content: `${friendlyName} updated to ${JSON.stringify(
627
589
  validation.coerced,
628
- )}.${broadcastNote}${autoDetectNote}${pickerNote}`,
590
+ )}.${broadcastNote}${autoDetectNote}`,
629
591
  isError: false,
630
592
  };
631
593
  }
@@ -69,9 +69,9 @@ describe("SttServiceSchema", () => {
69
69
  test("language defaults to multilingual rather than staying absent", () => {
70
70
  // Every config carries a real language, so nothing downstream has to
71
71
  // infer one from an absent key. Omitting the param entirely is not a
72
- // neutral state on Deepgram and the cloud relay: it decodes as
73
- // English, which is what this default exists to stop.
74
- const parsed = SttServiceSchema.parse({ provider: "cadet" });
72
+ // neutral state on Deepgram: it decodes as English, which is what this
73
+ // default exists to stop.
74
+ const parsed = SttServiceSchema.parse({ provider: "deepgram" });
75
75
  expect(parsed.language).toBe("multi");
76
76
  });
77
77
 
@@ -86,7 +86,8 @@ describe("SttServiceSchema", () => {
86
86
 
87
87
  test("language round-trips a code and the multi code-switching mode", () => {
88
88
  expect(
89
- SttServiceSchema.parse({ provider: "cadet", language: "multi" }).language,
89
+ SttServiceSchema.parse({ provider: "deepgram", language: "multi" })
90
+ .language,
90
91
  ).toBe("multi");
91
92
  expect(
92
93
  SttServiceSchema.parse({ provider: "deepgram", language: "hi" }).language,
@@ -95,30 +96,25 @@ describe("SttServiceSchema", () => {
95
96
 
96
97
  test("language is trimmed and rejects blank strings", () => {
97
98
  expect(
98
- SttServiceSchema.parse({ provider: "cadet", language: " multi " })
99
+ SttServiceSchema.parse({ provider: "deepgram", language: " multi " })
99
100
  .language,
100
101
  ).toBe("multi");
101
102
  expect(() =>
102
- SttServiceSchema.parse({ provider: "cadet", language: " " }),
103
+ SttServiceSchema.parse({ provider: "deepgram", language: " " }),
103
104
  ).toThrow(/must not be empty/);
104
105
  });
105
106
  });
106
107
 
107
- describe("cloud provider", () => {
108
- test("accepts cadet as an ordinary provider choice", () => {
109
- const parsed = SttServiceSchema.parse({ provider: "cadet" });
110
- expect(parsed.provider).toBe("cadet");
111
- });
112
-
108
+ describe("provider parsing", () => {
113
109
  // Migration 130 folds mode into provider; a stale key must not resurrect
114
110
  // the second axis or fail the parse.
115
111
  test("ignores a legacy mode key", () => {
116
112
  const parsed = SttServiceSchema.parse({
117
113
  mode: "managed",
118
- provider: "cadet",
114
+ provider: "deepgram",
119
115
  });
120
116
  expect(parsed).toEqual({
121
- provider: "cadet",
117
+ provider: "deepgram",
122
118
  language: "multi",
123
119
  providers: {},
124
120
  roles: {},
@@ -71,12 +71,11 @@ const ImageGenerationServiceSchema = z.object({
71
71
  });
72
72
 
73
73
  /**
74
- * Web-search carries no `mode`: `provider` is the only axis. `"cadet"`
75
- * searches through the Cadet Cloud search proxy, billed to Cadet
76
- * credits; `"inference-provider-native"` prefers the inference model's own
77
- * hosted search, falling back to the user's keys and then the cloud
78
- * proxy; any other provider uses the user's own API key. A `mode` key sent
79
- * by an older client is stripped at parse.
74
+ * Web-search carries no `mode`: `provider` is the only axis.
75
+ * `"inference-provider-native"` prefers the inference model's own hosted
76
+ * search, falling back to the user's own keys; any other provider uses the
77
+ * user's own API key. A `mode` key sent by an older client is stripped at
78
+ * parse.
80
79
  */
81
80
  const WebSearchServiceSchema = z.object({
82
81
  provider: z