@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.
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +10 -10
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +3 -3
- package/node_modules/@mycadet/ces-client/src/http-credentials.ts +18 -1
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +10 -10
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +3 -3
- package/node_modules/@mycadet/gateway-client/src/gateway-ipc-contracts.ts +0 -20
- package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +10 -10
- package/node_modules/@mycadet/service-contracts/src/ingress.ts +3 -3
- package/openapi.yaml +2 -708
- package/package.json +2 -3
- package/scripts/sync-web-search-catalog.ts +1 -2
- package/src/__tests__/cloud-profile-guard.test.ts +41 -5
- package/src/__tests__/config-schema.test.ts +6 -38
- package/src/__tests__/conversation-queue.test.ts +45 -6
- package/src/__tests__/db-readiness-http-gate.test.ts +0 -6
- package/src/__tests__/persist-onboarding-artifacts.test.ts +0 -1
- package/src/__tests__/persona-resolver.test.ts +0 -51
- package/src/__tests__/provider-cloud-proxy-integration.test.ts +2 -110
- package/src/__tests__/run-due-schedules.test.ts +0 -4
- package/src/__tests__/schedule-store.test.ts +0 -12
- package/src/__tests__/stt-stream-session.test.ts +4 -4
- package/src/__tests__/telephony-tts-guard.test.ts +2 -50
- package/src/__tests__/voice-config-update.test.ts +12 -167
- package/src/__tests__/web-search-catalog-parity.test.ts +0 -2
- package/src/__tests__/workspace-migration-130-speech-mode-to-provider.test.ts +9 -7
- package/src/__tests__/workspace-migration-132-web-search-mode-to-provider.test.ts +6 -6
- package/src/calls/__tests__/voice-session-bridge.test.ts +1 -4
- package/src/calls/resolve-call-tts-provider.ts +6 -25
- package/src/calls/telephony-credential-preflight.ts +0 -10
- package/src/calls/telephony-tts-capability.ts +1 -17
- package/src/cli/commands/tts.ts +1 -2
- package/src/cli/index.help.ts +0 -2
- package/src/cli/program.ts +0 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +4 -42
- package/src/config/schemas/__tests__/stt.test.ts +10 -14
- package/src/config/schemas/llm.ts +3 -5
- package/src/config/schemas/services.ts +5 -6
- package/src/config/schemas/stt.ts +1 -3
- package/src/config/schemas/tts.ts +1 -30
- package/src/daemon/daemon-readiness.ts +4 -29
- package/src/daemon/lifecycle.ts +0 -31
- package/src/daemon/providers-setup.ts +0 -8
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
- package/src/heartbeat/heartbeat-service.ts +1 -66
- package/src/ipc/__tests__/db-readiness-ipc-gate.test.ts +1 -9
- package/src/live-voice/__tests__/live-voice-credential-preflight.test.ts +0 -44
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +4 -6
- package/src/live-voice/__tests__/live-voice-stt.test.ts +1 -1
- package/src/live-voice/live-voice-credential-preflight.ts +9 -33
- package/src/live-voice/live-voice-session.ts +10 -6
- package/src/live-voice/live-voice-tts.ts +1 -8
- package/src/plugins/defaults/memory/worker.ts +3 -3
- package/src/prompts/persona-resolver.ts +0 -35
- package/src/providers/__tests__/search-provider-catalog.test.ts +5 -8
- package/src/providers/__tests__/voice-error-copy.test.ts +9 -10
- package/src/providers/search-provider-catalog.ts +7 -39
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +3 -47
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +6 -372
- package/src/providers/speech-to-text/provider-catalog.ts +2 -73
- package/src/providers/speech-to-text/resolve.ts +3 -120
- package/src/runtime/http-router-types.ts +1 -3
- package/src/runtime/http-server.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +13 -11
- package/src/runtime/routes/__tests__/tts-routes.test.ts +2 -6
- package/src/runtime/routes/conversation-query-routes.ts +0 -96
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +7 -7
- package/src/runtime/routes/index.ts +0 -4
- package/src/runtime/routes/live-voice-routes.test.ts +4 -11
- package/src/runtime/routes/live-voice-routes.ts +8 -11
- package/src/runtime/routes/secret-routes.ts +0 -6
- package/src/runtime/routes/tts-routes.ts +0 -38
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1 -7
- package/src/schedule/__tests__/worker-mcp-readiness.test.ts +0 -4
- package/src/schedule/schedule-store.ts +0 -7
- package/src/schedule/scheduler.ts +0 -5
- package/src/schedule/worker.ts +1 -1
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +2 -10
- package/src/stt/daemon-batch-transcriber.ts +4 -38
- package/src/stt/types.ts +1 -9
- package/src/tools/network/__tests__/web-search.test.ts +3 -250
- package/src/tools/network/web-search.ts +4 -165
- package/src/tts/__tests__/provider-resolution.test.ts +0 -5
- package/src/tts/provider-catalog.ts +0 -4
- package/src/tts/types.ts +0 -1
- package/src/__tests__/cloud-speech-defaults.test.ts +0 -330
- package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1708
- package/src/__tests__/migration-export-http.test.ts +0 -557
- package/src/__tests__/migration-export-streaming.test.ts +0 -350
- package/src/__tests__/migration-export-to-gcs.test.ts +0 -706
- package/src/__tests__/migration-import-commit-http.test.ts +0 -1176
- package/src/__tests__/migration-import-from-gcs.test.ts +0 -534
- package/src/__tests__/migration-import-from-path.test.ts +0 -324
- package/src/__tests__/migration-import-from-url.test.ts +0 -588
- package/src/__tests__/migration-import-preflight-http.test.ts +0 -739
- package/src/__tests__/migration-jobs-status.test.ts +0 -139
- package/src/__tests__/migration-parity-persistence.test.ts +0 -1891
- package/src/__tests__/migration-transport.test.ts +0 -1089
- package/src/__tests__/migration-validate-http.test.ts +0 -634
- package/src/__tests__/migration-wizard.test.ts +0 -1395
- package/src/__tests__/rebind-secrets-screen.test.ts +0 -876
- package/src/__tests__/sanitize-config-for-transfer.test.ts +0 -259
- package/src/__tests__/transfer-progress-screen.test.ts +0 -1217
- package/src/__tests__/validation-results-screen.test.ts +0 -1130
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +0 -147
- package/src/background-wake/background-wake-routes.test.ts +0 -906
- package/src/background-wake/cloud-client.test.ts +0 -328
- package/src/background-wake/cloud-client.ts +0 -196
- package/src/background-wake/next-wake.test.ts +0 -335
- package/src/background-wake/next-wake.ts +0 -188
- package/src/background-wake/publisher.ts +0 -93
- package/src/background-wake/wake-intent-hooks.test.ts +0 -234
- package/src/cli/commands/__tests__/backup.test.ts +0 -363
- package/src/cli/commands/backup.help.ts +0 -180
- package/src/cli/commands/backup.ts +0 -398
- package/src/cloud/cloud-speech.test.ts +0 -335
- package/src/cloud/cloud-speech.ts +0 -300
- package/src/config/cloud-speech-defaults.ts +0 -300
- package/src/config/sanitize-for-transfer.ts +0 -111
- package/src/live-voice/__tests__/live-voice-cloud-speech-fallback.test.ts +0 -250
- package/src/providers/speech-to-text/__tests__/cadet-cloud-realtime.test.ts +0 -457
- package/src/providers/speech-to-text/__tests__/cadet-cloud.test.ts +0 -271
- package/src/providers/speech-to-text/__tests__/cadet-speech-relay-connection.test.ts +0 -126
- package/src/providers/speech-to-text/cadet-cloud-flux-realtime.ts +0 -309
- package/src/providers/speech-to-text/cadet-cloud-realtime.ts +0 -315
- package/src/providers/speech-to-text/cadet-cloud.ts +0 -108
- package/src/providers/speech-to-text/cadet-speech-relay-connection.ts +0 -176
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +0 -254
- package/src/runtime/migrations/__tests__/job-registry.test.ts +0 -346
- package/src/runtime/migrations/__tests__/origin-mode.test.ts +0 -62
- package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +0 -184
- package/src/runtime/migrations/__tests__/staged-import-path.test.ts +0 -110
- package/src/runtime/migrations/__tests__/v1-test-helpers.ts +0 -112
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +0 -285
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +0 -126
- package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +0 -253
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +0 -208
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +0 -485
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +0 -349
- package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +0 -196
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +0 -551
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +0 -428
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +0 -220
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +0 -1823
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +0 -598
- package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +0 -463
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -538
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +0 -515
- package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +0 -453
- package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +0 -319
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +0 -240
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +0 -473
- package/src/runtime/migrations/gcs-signed-url.ts +0 -190
- package/src/runtime/migrations/job-registry.ts +0 -297
- package/src/runtime/migrations/migration-transport.ts +0 -612
- package/src/runtime/migrations/migration-wizard.ts +0 -747
- package/src/runtime/migrations/origin-mode.ts +0 -42
- package/src/runtime/migrations/rebind-secrets-screen.ts +0 -412
- package/src/runtime/migrations/staged-import-path.ts +0 -116
- package/src/runtime/migrations/transfer-progress-screen.ts +0 -323
- package/src/runtime/migrations/validation-results-screen.ts +0 -469
- package/src/runtime/migrations/vbundle-builder.ts +0 -1382
- package/src/runtime/migrations/vbundle-import-analyzer.ts +0 -405
- package/src/runtime/migrations/vbundle-import-policy.ts +0 -241
- package/src/runtime/migrations/vbundle-importer.ts +0 -826
- package/src/runtime/migrations/vbundle-metadata-merge.ts +0 -113
- package/src/runtime/migrations/vbundle-streaming-importer.ts +0 -2844
- package/src/runtime/migrations/vbundle-streaming-validator.ts +0 -426
- package/src/runtime/migrations/vbundle-tar-stream.ts +0 -244
- package/src/runtime/migrations/vbundle-validator.ts +0 -724
- package/src/runtime/routes/__tests__/migration-cadet-metadata-reconcile.test.ts +0 -227
- package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +0 -54
- package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +0 -70
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +0 -257
- package/src/runtime/routes/background-wake-routes.ts +0 -387
- package/src/runtime/routes/migration-routes.ts +0 -2584
- package/src/tools/network/__tests__/cloud-search-proxy.test.ts +0 -282
- package/src/tools/network/cloud-search-proxy.ts +0 -211
- package/src/tts/__tests__/cadet-provider.test.ts +0 -253
- package/src/tts/providers/cadet-provider.ts +0 -244
- 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
|
|
package/src/schedule/worker.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
614
|
-
|
|
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)
|
|
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)
|
|
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.
|
|
280
|
-
//
|
|
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,
|
|
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
|
-
|
|
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
|
|
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.
|
|
246
|
-
|
|
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
|
|
2500
|
-
// win above; the
|
|
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");
|