@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
@@ -49,13 +49,6 @@ const logger = getLogger("schedule-store");
49
49
 
50
50
  function notifySchedulesChanged(): void {
51
51
  publishSchedulesChanged();
52
- void import("../background-wake/publisher.js")
53
- .then(({ refreshBackgroundWakeIntent }) =>
54
- refreshBackgroundWakeIntent("schedule-changed"),
55
- )
56
- .catch((err) =>
57
- logger.warn({ err }, "Failed to queue background wake refresh"),
58
- );
59
52
  }
60
53
 
61
54
  export type ScheduleMode =
@@ -1,4 +1,3 @@
1
- import { refreshBackgroundWakeIntent } from "../background-wake/publisher.js";
2
1
  import { resolveSingleRouteProfileKey } from "../config/llm-resolver.js";
3
2
  import { getConfig } from "../config/loader.js";
4
3
  import { findConversationOrSubagent } from "../daemon/conversation-registry.js";
@@ -556,10 +555,6 @@ export function startScheduler(): SchedulerHandle {
556
555
  },
557
556
  };
558
557
 
559
- // Publish the initial background wake intent now that the scheduler is live
560
- // and its schedules are visible to `computeNextBackgroundWakeIntent`.
561
- refreshBackgroundWakeIntent("daemon-startup");
562
-
563
558
  return instance;
564
559
  }
565
560
 
@@ -144,7 +144,7 @@ async function main(): Promise<void> {
144
144
  // standalone process must do it itself so getCloudBaseUrl() resolves to
145
145
  // the persisted platform environment instead of the CADET_ENVIRONMENT
146
146
  // default — otherwise valid credentials are sent to the wrong platform and
147
- // rejected for both inference and background-wake requests.
147
+ // rejected for inference requests.
148
148
  await ensureCloudIdentityIds();
149
149
 
150
150
  // This process is the sole runner of schedule execution and hosts real agent
@@ -610,16 +610,8 @@ describe("normalizeSttError", () => {
610
610
  });
611
611
  });
612
612
 
613
- describe("cadet factory case", () => {
614
- test("constructs the cloud transcriber with no API key", () => {
615
- const transcriber = createDaemonBatchTranscriber(null, "cadet");
616
- expect(transcriber?.providerId).toBe("cadet");
617
- expect(transcriber?.boundaryId).toBe("daemon-batch");
618
- });
619
-
620
- test("still returns null for key-based providers without a key", () => {
621
- expect(createDaemonBatchTranscriber(null, "deepgram")).toBeNull();
622
- });
613
+ test("still returns null for key-based providers without a key", () => {
614
+ expect(createDaemonBatchTranscriber(null, "deepgram")).toBeNull();
623
615
  });
624
616
 
625
617
  describe("deepgram-flux factory case", () => {
@@ -205,32 +205,6 @@ export function normalizeSttError(err: unknown): SttError {
205
205
  return new SttError("provider-error", message);
206
206
  }
207
207
 
208
- // ---------------------------------------------------------------------------
209
- // Cadet Cloud adapter — implements BatchTranscriber on top of the
210
- // platform's cloud speech endpoint. No API key: the cloud connection
211
- // is the credential.
212
- // ---------------------------------------------------------------------------
213
-
214
- class CadetManagedBatchTranscriber implements BatchTranscriber {
215
- readonly providerId = "cadet" as const;
216
- readonly boundaryId = "daemon-batch" as const;
217
-
218
- constructor(private readonly language: string | undefined) {}
219
-
220
- async transcribe(
221
- request: SttTranscribeRequest,
222
- ): Promise<SttTranscribeResult> {
223
- const { cadetCloudTranscribe } =
224
- await import("../providers/speech-to-text/cadet-cloud.js");
225
- return cadetCloudTranscribe(
226
- request.audio,
227
- request.mimeType,
228
- request.signal,
229
- this.language,
230
- );
231
- }
232
- }
233
-
234
208
  /**
235
209
  * Create a `BatchTranscriber` for the daemon-batch boundary.
236
210
  *
@@ -241,10 +215,9 @@ class CadetManagedBatchTranscriber implements BatchTranscriber {
241
215
  * is unavailable.
242
216
  *
243
217
  * `language` is the spoken language, forwarded to providers whose batch API
244
- * accepts one: Deepgram (where `"multi"` also pins nova-3), xAI (where
218
+ * accepts one: Deepgram (where `"multi"` also pins nova-3) and xAI (where
245
219
  * `"multi"` is dropped because it is a Deepgram-specific value, not a
246
- * language code), and the Cadet Cloud path, whose cloud proxy passes
247
- * it to Deepgram server-side. Whisper and Gemini auto-detect natively and
220
+ * language code). Whisper and Gemini auto-detect natively and
248
221
  * take no language parameter, so it is silently ignored for them.
249
222
  *
250
223
  * Throws an {@link SttError} for a provider with no batch endpoint at all,
@@ -255,11 +228,6 @@ export function createDaemonBatchTranscriber(
255
228
  providerId: SttProviderId,
256
229
  language?: string,
257
230
  ): BatchTranscriber | null {
258
- // Cloud speech authenticates via the cloud connection, not an API
259
- // key. Callers pass canonical ids; the resolver maps legacy ones first.
260
- if (providerId === "cadet") {
261
- return new CadetManagedBatchTranscriber(language);
262
- }
263
231
  if (!apiKey) {
264
232
  return null;
265
233
  }
@@ -274,11 +242,9 @@ export function createDaemonBatchTranscriber(
274
242
  case "xai":
275
243
  return new XAIBatchTranscriber(apiKey, language);
276
244
  case "deepgram-flux":
277
- case "cadet-flux":
278
245
  // Same copy the resolver raises, so a direct factory caller and a
279
- // config-driven one report the mismatch identically. Both Flux
280
- // variants are streaming-only: the model has no batch endpoint, BYOK
281
- // or managed.
246
+ // config-driven one report the mismatch identically. Flux is
247
+ // streaming-only: the model has no batch endpoint.
282
248
  throw new SttError("provider-error", batchBoundaryGapReason(providerId), {
283
249
  userFacing: true,
284
250
  });
package/src/stt/types.ts CHANGED
@@ -52,15 +52,7 @@ export type SttProviderId =
52
52
  */
53
53
  | "deepgram-flux"
54
54
  | "google-gemini"
55
- | "xai"
56
- | "cadet"
57
- /**
58
- * Cloud Flux: the same conversational model as `deepgram-flux`, reached
59
- * through the cloud's speech relay instead of a Deepgram key. Dials the
60
- * relay's STT v2 endpoint asking for native Flux frames, so it keeps the
61
- * turn events the relay's default v1-shaped translation drops.
62
- */
63
- | "cadet-flux";
55
+ | "xai";
64
56
 
65
57
  /**
66
58
  * Telephony-specific STT capability class.
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
1
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2
2
 
3
3
  import { useMemorySecureKeyMap } from "../../../__tests__/helpers/secure-keys.js";
4
4
  import { setConfig } from "../../../__tests__/helpers/set-config.js";
@@ -15,14 +15,6 @@ function setKey(provider: string, value: string | undefined): void {
15
15
  secureKeys.set(credentialKey(provider, "api_key"), value);
16
16
  }
17
17
  }
18
- let mockManagedSearchProxyResult: any;
19
- let mockManagedSearchAvailable = true;
20
- let mockManagedSearchProxyCalls: Array<{
21
- provider: string;
22
- request: Record<string, unknown>;
23
- signal?: AbortSignal;
24
- }> = [];
25
-
26
18
  /**
27
19
  * Seed the web-search service into the workspace config. Pass `undefined`
28
20
  * for mode to write a post-migration-132 config carrying only `provider`.
@@ -42,18 +34,6 @@ function seedWebSearch(
42
34
  });
43
35
  }
44
36
 
45
- mock.module("../cloud-search-proxy.js", () => ({
46
- callManagedSearchProxy: async (
47
- provider: string,
48
- request: Record<string, unknown>,
49
- signal?: AbortSignal,
50
- ) => {
51
- mockManagedSearchProxyCalls.push({ provider, request, signal });
52
- return mockManagedSearchProxyResult;
53
- },
54
- managedSearchAvailable: async () => mockManagedSearchAvailable,
55
- }));
56
-
57
37
  // Import after the mocks above so the module under test sees them.
58
38
  const { webSearchTool } = await import("../web-search.js");
59
39
 
@@ -73,14 +53,6 @@ describe("web_search tool", () => {
73
53
  setKey("tinyfish", undefined);
74
54
  setKey("exa", undefined);
75
55
  setKey("serply", undefined);
76
- mockManagedSearchProxyCalls = [];
77
- mockManagedSearchAvailable = true;
78
- mockManagedSearchProxyResult = {
79
- ok: true,
80
- status: 200,
81
- headers: { "content-type": "application/json" },
82
- body: { web: { results: [] } },
83
- };
84
56
  });
85
57
 
86
58
  afterEach(() => {
@@ -115,58 +87,7 @@ describe("web_search tool", () => {
115
87
  expect(result.content).toContain("No web search API key configured");
116
88
  });
117
89
 
118
- // ---- Provider cadet (managed, provider is the only axis) ---------------
119
-
120
- test("provider cadet with no mode routes to the cloud proxy", async () => {
121
- seedWebSearch(undefined, "cadet");
122
-
123
- const result = await execute({ query: "cadet managed query" });
124
-
125
- expect(result.isError).toBe(false);
126
- expect(mockManagedSearchProxyCalls).toHaveLength(1);
127
- expect(mockManagedSearchProxyCalls[0].provider).toBe("brave");
128
- });
129
-
130
- test("provider cadet routes managed even under a stale your-own mode", async () => {
131
- // The provider choice wins over a leftover legacy mode key.
132
- seedWebSearch("your-own", "cadet");
133
-
134
- const result = await execute({ query: "stale mode query" });
135
-
136
- expect(result.isError).toBe(false);
137
- expect(mockManagedSearchProxyCalls).toHaveLength(1);
138
- });
139
-
140
- test("provider cadet surfaces a 402 hard error and never falls back to BYOK keys", async () => {
141
- // Billing rule: an explicit cadet choice must never silently reroute to
142
- // a user's paid third-party key (and vice versa).
143
- seedWebSearch(undefined, "cadet");
144
- setKey("perplexity", "pplx-should-not-be-used");
145
- mockManagedSearchProxyResult = {
146
- ok: false,
147
- kind: "platform-error",
148
- status: 402,
149
- headers: { "content-type": "application/json" },
150
- body: { detail: "Insufficient balance" },
151
- message: "Cloud search proxy returned status 402: Insufficient balance",
152
- };
153
- let byokFetchCalls = 0;
154
- globalThis.fetch = (async () => {
155
- byokFetchCalls += 1;
156
- return new Response("{}", { status: 200 });
157
- }) as any;
158
-
159
- const result = await execute({ query: "billing query" });
160
-
161
- expect(result.isError).toBe(true);
162
- expect(result.content).toContain("account balance");
163
- expect(result.content).toContain("different web search provider");
164
- expect(byokFetchCalls).toBe(0);
165
- });
166
-
167
- // ---- Provider Native fallback order (keys first, proxy last) ------------
168
-
169
- test("provider native with a BYOK key uses the key, not the proxy", async () => {
90
+ test("provider native with a BYOK key uses the key", async () => {
170
91
  seedWebSearch(undefined, "inference-provider-native");
171
92
  setKey("perplexity", "pplx-test-key");
172
93
  globalThis.fetch = (async () =>
@@ -182,27 +103,15 @@ describe("web_search tool", () => {
182
103
 
183
104
  expect(result.isError).toBe(false);
184
105
  expect(result.content).toContain("BYOK answer");
185
- expect(mockManagedSearchProxyCalls).toHaveLength(0);
186
106
  });
187
107
 
188
- test("provider native with no keys falls back to the cloud proxy", async () => {
108
+ test("provider native with no keys reports the no-key error", async () => {
189
109
  seedWebSearch(undefined, "inference-provider-native");
190
110
 
191
111
  const result = await execute({ query: "no key native query" });
192
112
 
193
- expect(result.isError).toBe(false);
194
- expect(mockManagedSearchProxyCalls).toHaveLength(1);
195
- });
196
-
197
- test("provider native with no keys and no platform reports the no-key error", async () => {
198
- seedWebSearch(undefined, "inference-provider-native");
199
- mockManagedSearchAvailable = false;
200
-
201
- const result = await execute({ query: "offline native query" });
202
-
203
113
  expect(result.isError).toBe(true);
204
114
  expect(result.content).toContain("No web search API key configured");
205
- expect(mockManagedSearchProxyCalls).toHaveLength(0);
206
115
  });
207
116
 
208
117
  // ---- Perplexity provider ------------------------------------------------
@@ -471,161 +380,6 @@ describe("web_search tool", () => {
471
380
  expect(callCount).toBe(4);
472
381
  });
473
382
 
474
- // ---- Cloud Brave provider -------------------------------------------
475
-
476
- test("provider cadet uses Brave proxy without BYOK provider keys", async () => {
477
- seedWebSearch(undefined, "cadet");
478
- mockManagedSearchProxyResult = {
479
- ok: true,
480
- status: 200,
481
- headers: { "content-type": "application/json" },
482
- body: {
483
- web: {
484
- results: [
485
- {
486
- title: "Cloud Result",
487
- url: "https://example.com/managed",
488
- description: "Cloud Brave result",
489
- },
490
- ],
491
- },
492
- },
493
- };
494
-
495
- const result = await execute({
496
- query: "managed query",
497
- count: 5,
498
- offset: 2,
499
- freshness: "pw",
500
- });
501
-
502
- expect(result.isError).toBe(false);
503
- expect(result.content).toContain("Cloud Result");
504
- expect(mockManagedSearchProxyCalls).toHaveLength(1);
505
- expect(mockManagedSearchProxyCalls[0]).toMatchObject({
506
- provider: "brave",
507
- request: {
508
- method: "GET",
509
- path: "/res/v1/web/search",
510
- query: {
511
- q: "managed query",
512
- count: "5",
513
- offset: "2",
514
- freshness: "pw",
515
- },
516
- headers: {
517
- Accept: "application/json",
518
- },
519
- body: null,
520
- },
521
- });
522
- });
523
-
524
- test("managed Brave formats results like direct Brave", async () => {
525
- const braveBody = {
526
- web: {
527
- results: [
528
- {
529
- title: "Same Result",
530
- url: "https://example.com/same",
531
- description: "Same description",
532
- age: "1 day ago",
533
- extra_snippets: ["Same snippet"],
534
- },
535
- ],
536
- },
537
- };
538
-
539
- seedWebSearch("your-own", "brave");
540
- setKey("brave", "brave-key");
541
- globalThis.fetch = (async () => {
542
- return new Response(JSON.stringify(braveBody), {
543
- status: 200,
544
- headers: { "content-type": "application/json" },
545
- });
546
- }) as any;
547
-
548
- const directResult = await execute({ query: "same query" });
549
-
550
- seedWebSearch(undefined, "cadet");
551
- setKey("brave", undefined);
552
- mockManagedSearchProxyResult = {
553
- ok: true,
554
- status: 200,
555
- headers: { "content-type": "application/json" },
556
- body: braveBody,
557
- };
558
-
559
- const managedResult = await execute({ query: "same query" });
560
-
561
- expect(managedResult.isError).toBe(false);
562
- expect(managedResult.content).toBe(directResult.content);
563
- expect(managedResult.activityMetadata.webSearch.results).toEqual(
564
- directResult.activityMetadata.webSearch.results,
565
- );
566
- });
567
-
568
- test("provider cadet passes abort signal to the cloud proxy", async () => {
569
- seedWebSearch(undefined, "cadet");
570
- const controller = new AbortController();
571
-
572
- await execute({ query: "abortable query" }, { signal: controller.signal });
573
-
574
- expect(mockManagedSearchProxyCalls).toHaveLength(1);
575
- expect(mockManagedSearchProxyCalls[0].signal).toBe(controller.signal);
576
- });
577
-
578
- test("provider cadet maps insufficient balance to a cloud usage error", async () => {
579
- seedWebSearch(undefined, "cadet");
580
- mockManagedSearchProxyResult = {
581
- ok: false,
582
- kind: "platform-error",
583
- status: 402,
584
- headers: { "content-type": "application/json" },
585
- body: { detail: "Insufficient balance" },
586
- message: "Cloud search proxy returned status 402: Insufficient balance",
587
- };
588
-
589
- const result = await execute({ query: "billing query" });
590
-
591
- expect(result.isError).toBe(true);
592
- expect(result.content).toContain("Managed web search");
593
- expect(result.content).toContain("account balance");
594
- expect(result.content).toContain("different web search provider");
595
- });
596
-
597
- test("provider cadet maps proxied provider errors to a tool error", async () => {
598
- seedWebSearch(undefined, "cadet");
599
- mockManagedSearchProxyResult = {
600
- ok: true,
601
- status: 400,
602
- headers: { "content-type": "application/json" },
603
- body: { error: "Bad upstream request" },
604
- };
605
-
606
- const result = await execute({ query: "provider error query" });
607
-
608
- expect(result.isError).toBe(true);
609
- expect(result.content).toContain(
610
- "Cloud Brave Search provider returned status 400",
611
- );
612
- });
613
-
614
- test("provider cadet returns a clear error when platform context is unavailable", async () => {
615
- seedWebSearch(undefined, "cadet");
616
- mockManagedSearchProxyResult = {
617
- ok: false,
618
- kind: "unavailable",
619
- message: "Cloud search proxy is unavailable in this environment.",
620
- };
621
-
622
- const result = await execute({ query: "local managed query" });
623
-
624
- expect(result.isError).toBe(true);
625
- expect(result.content).toContain("Cloud search proxy is unavailable");
626
- expect(result.content).toContain("Log in to Cadet");
627
- });
628
-
629
383
  test("your-own mode keeps direct Brave BYOK behavior unchanged", async () => {
630
384
  seedWebSearch("your-own", "brave");
631
385
  setKey("brave", "brave-direct-key");
@@ -641,7 +395,6 @@ describe("web_search tool", () => {
641
395
  const result = await execute({ query: "direct query" });
642
396
 
643
397
  expect(result.isError).toBe(false);
644
- expect(mockManagedSearchProxyCalls).toHaveLength(0);
645
398
  expect(capturedHeaders!.get("X-Subscription-Token")).toBe(
646
399
  "brave-direct-key",
647
400
  );
@@ -21,7 +21,6 @@ import type {
21
21
  ToolDefinition,
22
22
  ToolExecutionResult,
23
23
  } from "../types.js";
24
- import type { ManagedSearchProxyResult } from "./cloud-search-proxy.js";
25
24
  import { extractDomain } from "./domain-normalize.js";
26
25
  import {
27
26
  extractFirecrawlCompatSearchResults,
@@ -242,10 +241,8 @@ function getWebSearchProvider(): WebSearchProvider {
242
241
  // In Your Own mode, `inference-provider-native` is only executable when the
243
242
  // inference provider swaps this tool for a native hosted-search definition.
244
243
  // If this app-executed tool is still invoked, fall back to the existing BYOK
245
- // provider chain. `cadet` short-circuits into the cloud branch before
246
- // this function runs, so its coercion here only satisfies the return type
247
- // and keeps an undefined WEB_SEARCH_ADAPTERS lookup unreachable.
248
- if (configured === "inference-provider-native" || configured === "cadet") {
244
+ // provider chain.
245
+ if (configured === "inference-provider-native") {
249
246
  return "perplexity";
250
247
  }
251
248
  return configured as WebSearchProvider;
@@ -1181,110 +1178,6 @@ async function executeBraveSearch(
1181
1178
  );
1182
1179
  }
1183
1180
 
1184
- async function executeManagedBraveSearch(
1185
- query: string,
1186
- count: number,
1187
- offset: number,
1188
- freshness: string | undefined,
1189
- signal?: AbortSignal,
1190
- ): Promise<ToolExecutionResult> {
1191
- const { callManagedSearchProxy } = await import("./cloud-search-proxy.js");
1192
- const startedAt = Date.now();
1193
- const proxyResult = await callManagedSearchProxy(
1194
- "brave",
1195
- {
1196
- method: "GET",
1197
- path: BRAVE_SEARCH_PATH,
1198
- query: braveQueryParams(query, count, offset, freshness),
1199
- headers: {
1200
- Accept: "application/json",
1201
- },
1202
- body: null,
1203
- },
1204
- signal,
1205
- );
1206
-
1207
- if (!proxyResult.ok) {
1208
- // Keep billing/auth/unavailable mapping as specific copy; route genuine
1209
- // platform 5xx (transport-level failures) to the friendly backend helper.
1210
- if (proxyResult.kind === "platform-error" && proxyResult.status >= 500) {
1211
- return backendFailureResult(
1212
- query,
1213
- "brave",
1214
- startedAt,
1215
- {
1216
- statusCode: proxyResult.status,
1217
- error: rawBodyDetail(proxyResult.body),
1218
- },
1219
- managedSearchProxyErrorMessage(proxyResult),
1220
- );
1221
- }
1222
- return errorResult(
1223
- query,
1224
- "brave",
1225
- startedAt,
1226
- managedSearchProxyErrorMessage(proxyResult),
1227
- );
1228
- }
1229
-
1230
- if (proxyResult.status >= 200 && proxyResult.status < 300) {
1231
- return successfulBraveResult(
1232
- proxyResult.body as BraveSearchResponse,
1233
- query,
1234
- startedAt,
1235
- );
1236
- }
1237
-
1238
- if (proxyResult.status === 401 || proxyResult.status === 403) {
1239
- return errorResult(
1240
- query,
1241
- "brave",
1242
- startedAt,
1243
- "Cloud Brave Search is not authenticated correctly. This is a Cadet Cloud configuration issue.",
1244
- );
1245
- }
1246
-
1247
- if (proxyResult.status === 429 || proxyResult.status >= 500) {
1248
- return backendFailureResult(
1249
- query,
1250
- "brave",
1251
- startedAt,
1252
- {
1253
- statusCode: proxyResult.status,
1254
- error: rawBodyDetail(proxyResult.body),
1255
- },
1256
- proxyResult.status === 429
1257
- ? "Cloud Brave Search rate limit exceeded. Try again shortly."
1258
- : `Cloud Brave Search provider returned status ${proxyResult.status}`,
1259
- );
1260
- }
1261
-
1262
- return errorResult(
1263
- query,
1264
- "brave",
1265
- startedAt,
1266
- `Cloud Brave Search provider returned status ${proxyResult.status}`,
1267
- );
1268
- }
1269
-
1270
- function managedSearchProxyErrorMessage(
1271
- result: Exclude<ManagedSearchProxyResult, { ok: true }>,
1272
- ): string {
1273
- if (result.kind === "unavailable") {
1274
- return `${result.message} Log in to Cadet or choose a different web search provider in Settings.`;
1275
- }
1276
-
1277
- if (result.kind === "platform-error" && result.status === 402) {
1278
- return "Managed web search is unavailable because your Cadet account balance is too low. Add funds or choose a different web search provider in Settings.";
1279
- }
1280
-
1281
- if (result.kind === "platform-error") {
1282
- return `Managed web search platform request failed: ${result.message}`;
1283
- }
1284
-
1285
- return result.message;
1286
- }
1287
-
1288
1181
  async function executePerplexitySearch(
1289
1182
  query: string,
1290
1183
  apiKey: string,
@@ -2264,14 +2157,6 @@ const braveSearchAdapter: WebSearchAdapter = {
2264
2157
  executeBraveSearch(query, count, offset, freshness, apiKey, signal),
2265
2158
  };
2266
2159
 
2267
- const managedBraveSearchAdapter: WebSearchAdapter = {
2268
- id: "brave",
2269
- providerKeyName: "brave",
2270
- fallbackOrder: 2,
2271
- execute: ({ query, count, offset, freshness, signal }) =>
2272
- executeManagedBraveSearch(query, count, offset, freshness, signal),
2273
- };
2274
-
2275
2160
  const tavilySearchAdapter: WebSearchAdapter = {
2276
2161
  id: "tavily",
2277
2162
  providerKeyName: "tavily",
@@ -2414,12 +2299,6 @@ export const webSearchTool = {
2414
2299
  }
2415
2300
 
2416
2301
  const startedAt = Date.now();
2417
- // An explicit Cadet choice is unconditionally managed: proxy errors
2418
- // (including 402) surface to the user and never fall back to BYOK keys.
2419
- // The config schema normalizes the legacy `cadet` id to `cadet` on
2420
- // parse, so this is the only spelling that survives here.
2421
- const managedSearch =
2422
- getConfig().services["web-search"].provider === "cadet";
2423
2302
 
2424
2303
  const count =
2425
2304
  typeof input.count === "number"
@@ -2432,33 +2311,6 @@ export const webSearchTool = {
2432
2311
  const freshness =
2433
2312
  typeof input.freshness === "string" ? input.freshness : undefined;
2434
2313
 
2435
- const executeManagedSearch = async (): Promise<ToolExecutionResult> => {
2436
- try {
2437
- log.debug({ query, provider: "brave" }, "Executing managed web search");
2438
- return await managedBraveSearchAdapter.execute({
2439
- query,
2440
- count,
2441
- offset,
2442
- freshness,
2443
- apiKey: "",
2444
- signal: context.signal,
2445
- });
2446
- } catch (err) {
2447
- log.error({ err }, "Managed web search failed");
2448
- return networkFailureResult(
2449
- query,
2450
- "brave",
2451
- startedAt,
2452
- err,
2453
- context.signal,
2454
- );
2455
- }
2456
- };
2457
-
2458
- if (managedSearch) {
2459
- return executeManagedSearch();
2460
- }
2461
-
2462
2314
  let provider = getWebSearchProvider();
2463
2315
  let apiKey = await getApiKey(provider);
2464
2316
 
@@ -2496,21 +2348,8 @@ export const webSearchTool = {
2496
2348
 
2497
2349
  if (!apiKey) {
2498
2350
  // Provider Native reaches this app-executed path only when the
2499
- // inference model had no hosted search of its own. The user's own keys
2500
- // win above; the cloud proxy is the last resort, which is what
2501
- // `mode: "managed"` did for installs that never configured a search
2502
- // key. Read the configured provider off config — the local `provider`
2503
- // has already been coerced to "perplexity".
2504
- if (
2505
- getConfig().services["web-search"].provider ===
2506
- "inference-provider-native"
2507
- ) {
2508
- const { managedSearchAvailable } =
2509
- await import("./cloud-search-proxy.js");
2510
- if (await managedSearchAvailable()) {
2511
- return executeManagedSearch();
2512
- }
2513
- }
2351
+ // inference model had no hosted search of its own. The user's own
2352
+ // keys win above; without one the run fails with the setup hint.
2514
2353
  return errorResult(
2515
2354
  query,
2516
2355
  provider,
@@ -89,11 +89,6 @@ describe("managed TTS provider resolution", () => {
89
89
  typeof resolveTtsConfig
90
90
  >[0];
91
91
 
92
- test("resolves the cadet provider", () => {
93
- const config = configWith({ provider: "cadet", providers: {} });
94
- expect(resolveTtsConfig(config).provider).toBe("cadet");
95
- });
96
-
97
92
  test("resolves a BYOK provider", () => {
98
93
  const config = configWith({ provider: "deepgram", providers: {} });
99
94
  expect(resolveTtsConfig(config).provider).toBe("deepgram");