@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.
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
- package/node_modules/@mycadet/gateway-client/src/gateway-ipc-contracts.ts +0 -20
- package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
- package/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
- 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 +2 -2
- 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/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__/tts-routes.test.ts +2 -6
- 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
|
@@ -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");
|
|
@@ -21,7 +21,6 @@ import type {
|
|
|
21
21
|
TtsProviderCatalogEntry,
|
|
22
22
|
TtsProviderDefinition,
|
|
23
23
|
} from "./provider-definition.js";
|
|
24
|
-
import { cadetTtsProviderDefinition } from "./providers/cadet-provider.js";
|
|
25
24
|
import { deepgramTtsProviderDefinition } from "./providers/deepgram-provider.js";
|
|
26
25
|
import { elevenLabsTtsProviderDefinition } from "./providers/elevenlabs-provider.js";
|
|
27
26
|
import { fishAudioTtsProviderDefinition } from "./providers/fish-audio-provider.js";
|
|
@@ -48,15 +47,12 @@ const DEFINITIONS = {
|
|
|
48
47
|
"fish-audio": fishAudioTtsProviderDefinition,
|
|
49
48
|
deepgram: deepgramTtsProviderDefinition,
|
|
50
49
|
xai: xaiTtsProviderDefinition,
|
|
51
|
-
cadet: cadetTtsProviderDefinition,
|
|
52
50
|
} as const satisfies Record<TtsProviderId, TtsProviderDefinition>;
|
|
53
51
|
|
|
54
52
|
/**
|
|
55
53
|
* Definitions in display order (e.g. settings dropdowns).
|
|
56
54
|
*/
|
|
57
|
-
// cadet leads: it is the cloud option, selected like any other provider.
|
|
58
55
|
const CATALOG: readonly TtsProviderDefinition[] = [
|
|
59
|
-
DEFINITIONS.cadet,
|
|
60
56
|
DEFINITIONS.elevenlabs,
|
|
61
57
|
DEFINITIONS["fish-audio"],
|
|
62
58
|
DEFINITIONS.deepgram,
|