scoutline 0.7.0 → 0.9.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/README.md +11 -3
- package/dist/capabilities/quota.d.ts +11 -0
- package/dist/capabilities/quota.d.ts.map +1 -1
- package/dist/capabilities/quota.js.map +1 -1
- package/dist/capabilities/search.d.ts +11 -1
- package/dist/capabilities/search.d.ts.map +1 -1
- package/dist/commands/crawl.js +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +13 -10
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/map.js +1 -1
- package/dist/commands/quota.d.ts +23 -0
- package/dist/commands/quota.d.ts.map +1 -1
- package/dist/commands/quota.js +21 -4
- package/dist/commands/quota.js.map +1 -1
- package/dist/commands/read.js +1 -1
- package/dist/commands/repo.js +1 -1
- package/dist/commands/research.js +1 -1
- package/dist/commands/search.d.ts +2 -1
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +21 -12
- package/dist/commands/search.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -4
- package/dist/index.js.map +1 -1
- package/dist/lib/redact.d.ts +2 -2
- package/dist/lib/redact.d.ts.map +1 -1
- package/dist/lib/redact.js +8 -2
- package/dist/lib/redact.js.map +1 -1
- package/dist/providers/brave/adapter.d.ts +42 -0
- package/dist/providers/brave/adapter.d.ts.map +1 -0
- package/dist/providers/brave/adapter.js +504 -0
- package/dist/providers/brave/adapter.js.map +1 -0
- package/dist/providers/brave/client.d.ts +161 -0
- package/dist/providers/brave/client.d.ts.map +1 -0
- package/dist/providers/brave/client.js +297 -0
- package/dist/providers/brave/client.js.map +1 -0
- package/dist/providers/brave/credentials.d.ts +33 -0
- package/dist/providers/brave/credentials.d.ts.map +1 -0
- package/dist/providers/brave/credentials.js +55 -0
- package/dist/providers/brave/credentials.js.map +1 -0
- package/dist/providers/brave/diagnostics.d.ts +46 -0
- package/dist/providers/brave/diagnostics.d.ts.map +1 -0
- package/dist/providers/brave/diagnostics.js +76 -0
- package/dist/providers/brave/diagnostics.js.map +1 -0
- package/dist/providers/brave/quota.d.ts +86 -0
- package/dist/providers/brave/quota.d.ts.map +1 -0
- package/dist/providers/brave/quota.js +247 -0
- package/dist/providers/brave/quota.js.map +1 -0
- package/dist/providers/exa/adapter.d.ts +58 -0
- package/dist/providers/exa/adapter.d.ts.map +1 -0
- package/dist/providers/exa/adapter.js +892 -0
- package/dist/providers/exa/adapter.js.map +1 -0
- package/dist/providers/exa/client.d.ts +143 -0
- package/dist/providers/exa/client.d.ts.map +1 -0
- package/dist/providers/exa/client.js +328 -0
- package/dist/providers/exa/client.js.map +1 -0
- package/dist/providers/exa/credentials.d.ts +34 -0
- package/dist/providers/exa/credentials.d.ts.map +1 -0
- package/dist/providers/exa/credentials.js +56 -0
- package/dist/providers/exa/credentials.js.map +1 -0
- package/dist/providers/exa/diagnostics.d.ts +42 -0
- package/dist/providers/exa/diagnostics.d.ts.map +1 -0
- package/dist/providers/exa/diagnostics.js +69 -0
- package/dist/providers/exa/diagnostics.js.map +1 -0
- package/dist/providers/minimax/adapter.js +1 -1
- package/dist/providers/minimax/adapter.js.map +1 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +4 -0
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/tavily/adapter.d.ts.map +1 -1
- package/dist/providers/tavily/adapter.js +5 -0
- package/dist/providers/tavily/adapter.js.map +1 -1
- package/dist/providers/types.d.ts +1 -1
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js +1 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/providers/zai/adapter.d.ts.map +1 -1
- package/dist/providers/zai/adapter.js +7 -1
- package/dist/providers/zai/adapter.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brave Provider Adapter (brave-tech-plan §2, §5, §6).
|
|
3
|
+
*
|
|
4
|
+
* T2 wires the Search Capability (web + news). The descriptor
|
|
5
|
+
* advertises `"search"` and `create()` returns an Adapter whose
|
|
6
|
+
* `search` Capability owns credentials, transport, Provider field
|
|
7
|
+
* mapping, and failure normalization. Credentials, the direct-HTTP GET
|
|
8
|
+
* transport, and the header-bearing fetch seam come from T1; later
|
|
9
|
+
* tickets widen the capability set (reader, etc.). T5 wires the
|
|
10
|
+
* Diagnostics Capability (one-query doctor probe); T6 wires the Quota
|
|
11
|
+
* Capability (1-query rate-limit-header probe with a spend caveat).
|
|
12
|
+
*
|
|
13
|
+
* Boundary rules (ARCHITECTURE.md §2):
|
|
14
|
+
* - May import capability types, normalized errors, Provider identity
|
|
15
|
+
* types, and the Adapter-local credential and transport Modules.
|
|
16
|
+
* - Must NOT import command presentation, output mode, or another
|
|
17
|
+
* Provider's Adapter.
|
|
18
|
+
*/
|
|
19
|
+
import crypto from "node:crypto";
|
|
20
|
+
import { ApiError, AuthError, ConfigurationError, NetworkError, QuotaError, TimeoutError, UnsupportedOptionError, ValidationError, } from "../../lib/errors.js";
|
|
21
|
+
import { applySearchTopic } from "../../lib/search-topic.js";
|
|
22
|
+
import { requireBraveApiKey, isBraveConfigured } from "./credentials.js";
|
|
23
|
+
import { fetchBraveSearch, fetchBraveNewsSearch, fetchBraveVideoSearch, fetchBraveLlmContext, } from "./client.js";
|
|
24
|
+
import { createBraveDiagnosticsCapability } from "./diagnostics.js";
|
|
25
|
+
import { createBraveQuotaCapability } from "./quota.js";
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Provider-owned credential fingerprint
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
function credentialFingerprint(apiKey) {
|
|
30
|
+
return crypto.createHash("sha256").update(apiKey).digest("hex");
|
|
31
|
+
}
|
|
32
|
+
function resolveApiKey(env) {
|
|
33
|
+
return requireBraveApiKey(env);
|
|
34
|
+
}
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Helpers
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
function isPlainObject(value) {
|
|
39
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40
|
+
}
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Validation (FR-012): reject unsupported controls before any API access
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
/**
|
|
45
|
+
* Controls the Brave Search Adapter does NOT accept as individuals.
|
|
46
|
+
* Every control (`domain`/`recency`/`location`/`topic`/`type`/
|
|
47
|
+
* `contentSize`) is now honored here — `contentSize:"high"` routes to
|
|
48
|
+
* the LLM Context endpoint (T4), and `medium`/default is a no-op depth
|
|
49
|
+
* on the web path. Brave therefore has NO per-control reject-list.
|
|
50
|
+
*
|
|
51
|
+
* The one Brave-specific constraint is a COMBINATION — `type:"video"`
|
|
52
|
+
* has no depth mode, so `type:"video"` + `contentSize` is incompatible.
|
|
53
|
+
* That is enforced separately as a combination guard in {@link validate}
|
|
54
|
+
* (it fires BEFORE dispatch, naming `contentSize` as the offending
|
|
55
|
+
* option, since `contentSize` is meaningful in general but not on the
|
|
56
|
+
* video path).
|
|
57
|
+
*/
|
|
58
|
+
const UNSUPPORTED_CONTROLS = [];
|
|
59
|
+
function assertNoUnsupportedControls(request) {
|
|
60
|
+
const controls = request.controls;
|
|
61
|
+
if (!controls)
|
|
62
|
+
return;
|
|
63
|
+
for (const key of UNSUPPORTED_CONTROLS) {
|
|
64
|
+
if (controls[key] !== undefined) {
|
|
65
|
+
throw new UnsupportedOptionError("brave", "search", key);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Brave-specific combination guards for the `type:"video"` path. Video
|
|
71
|
+
* results have no depth mode and no editorial topic axis, so
|
|
72
|
+
* `type:"video"` combined with `contentSize` OR `topic` is rejected
|
|
73
|
+
* BEFORE dispatch. Each error names the incompatible option
|
|
74
|
+
* (`contentSize` / `topic`) — both are individually accepted elsewhere.
|
|
75
|
+
* The `type`×`topic` rule mirrors the CLI parse-time gate so the
|
|
76
|
+
* adapter contract holds for programmatic callers too, not just the CLI.
|
|
77
|
+
*/
|
|
78
|
+
function assertNoVideoCombinations(request) {
|
|
79
|
+
const controls = request.controls;
|
|
80
|
+
if (controls?.type !== "video")
|
|
81
|
+
return;
|
|
82
|
+
if (controls.contentSize !== undefined) {
|
|
83
|
+
throw new UnsupportedOptionError("brave", "search", "contentSize");
|
|
84
|
+
}
|
|
85
|
+
if (controls.topic !== undefined) {
|
|
86
|
+
throw new UnsupportedOptionError("brave", "search", "topic");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Control mapping (SearchControls → Brave-native API params + query mutators)
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
function mapRecencyToFreshness(recency) {
|
|
93
|
+
switch (recency) {
|
|
94
|
+
case "oneDay":
|
|
95
|
+
return "pd";
|
|
96
|
+
case "oneWeek":
|
|
97
|
+
return "pw";
|
|
98
|
+
case "oneMonth":
|
|
99
|
+
return "pm";
|
|
100
|
+
case "oneYear":
|
|
101
|
+
return "py";
|
|
102
|
+
case "noLimit":
|
|
103
|
+
return undefined;
|
|
104
|
+
default:
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Map the param-bearing controls into Brave-native API fields. Query-
|
|
110
|
+
* mutating controls (`domain`, `topic:"finance"`) are handled separately
|
|
111
|
+
* in `invoke` via {@link applyQueryMutators}; `topic:"news"` is an
|
|
112
|
+
* endpoint switch, not a param.
|
|
113
|
+
*/
|
|
114
|
+
function mapSearchControls(controls) {
|
|
115
|
+
if (!controls)
|
|
116
|
+
return undefined;
|
|
117
|
+
const params = {};
|
|
118
|
+
if (controls.recency) {
|
|
119
|
+
const freshness = mapRecencyToFreshness(controls.recency);
|
|
120
|
+
if (freshness)
|
|
121
|
+
params.freshness = freshness;
|
|
122
|
+
}
|
|
123
|
+
if (controls.location) {
|
|
124
|
+
params.country = controls.location === "us" ? "US" : "CN";
|
|
125
|
+
}
|
|
126
|
+
if (params.country === undefined && params.freshness === undefined)
|
|
127
|
+
return undefined;
|
|
128
|
+
return params;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Apply the query-mutating controls to `query` BEFORE dispatch (not as
|
|
132
|
+
* API params). `domain` appends a `site:<domain>` operator (Brave has no
|
|
133
|
+
* dedicated domain param); `topic:"finance"` appends the finance keyword
|
|
134
|
+
* via the shared helper. `topic:"news"` is NOT a query mutation — it is
|
|
135
|
+
* an endpoint switch handled by the dispatcher.
|
|
136
|
+
*
|
|
137
|
+
* `suppressTopic` drops the `topic:"finance"` keyword appendage while
|
|
138
|
+
* keeping the `domain` operator. The LLM Context (`high`) path sets it:
|
|
139
|
+
* `high` overrides `topic` (it routes to LLM Context regardless of
|
|
140
|
+
* `--topic`), so the editorial topic keyword must NOT pollute the
|
|
141
|
+
* passage-extraction query. Domain is a filter and still applies on the
|
|
142
|
+
* high path, so it is preserved.
|
|
143
|
+
*/
|
|
144
|
+
function applyQueryMutators(query, controls, suppressTopic = false) {
|
|
145
|
+
let effective = query;
|
|
146
|
+
if (controls?.domain) {
|
|
147
|
+
effective = `${effective} site:${controls.domain}`;
|
|
148
|
+
}
|
|
149
|
+
if (!suppressTopic && controls?.topic === "finance") {
|
|
150
|
+
effective = applySearchTopic(effective, "finance");
|
|
151
|
+
}
|
|
152
|
+
return effective;
|
|
153
|
+
}
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
// Response normalization
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
/**
|
|
158
|
+
* Normalize one Brave result entry into a `SearchSource`.
|
|
159
|
+
*
|
|
160
|
+
* title -> title
|
|
161
|
+
* url -> url
|
|
162
|
+
* description -> summary
|
|
163
|
+
* meta_url.netloc -> source (only when present and string)
|
|
164
|
+
* page_age ?? age -> date (only when present and string)
|
|
165
|
+
*
|
|
166
|
+
* A missing/non-string title/url/description is a malformed response.
|
|
167
|
+
*/
|
|
168
|
+
function normalizeBraveResultEntry(entry) {
|
|
169
|
+
if (!isPlainObject(entry)) {
|
|
170
|
+
throw new ApiError("Brave search returned a malformed response", 500);
|
|
171
|
+
}
|
|
172
|
+
const title = entry.title;
|
|
173
|
+
const url = entry.url;
|
|
174
|
+
const description = entry.description;
|
|
175
|
+
if (typeof title !== "string" || typeof url !== "string" || typeof description !== "string") {
|
|
176
|
+
throw new ApiError("Brave search returned a malformed response", 500);
|
|
177
|
+
}
|
|
178
|
+
const source = { title, url, summary: description };
|
|
179
|
+
const metaUrl = entry.meta_url;
|
|
180
|
+
if (isPlainObject(metaUrl) && typeof metaUrl.netloc === "string") {
|
|
181
|
+
source.source = metaUrl.netloc;
|
|
182
|
+
}
|
|
183
|
+
let dateValue;
|
|
184
|
+
if (typeof entry.page_age === "string") {
|
|
185
|
+
dateValue = entry.page_age;
|
|
186
|
+
}
|
|
187
|
+
else if (typeof entry.age === "string") {
|
|
188
|
+
dateValue = entry.age;
|
|
189
|
+
}
|
|
190
|
+
if (dateValue !== undefined) {
|
|
191
|
+
source.date = dateValue;
|
|
192
|
+
}
|
|
193
|
+
return source;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Normalize a raw Brave WEB search response into `SearchSource[]`.
|
|
197
|
+
* Reads `raw.web.results[]`. Any malformed shape is a retryable
|
|
198
|
+
* `ApiError` 500.
|
|
199
|
+
*/
|
|
200
|
+
function normalizeBraveWebResults(raw) {
|
|
201
|
+
if (!isPlainObject(raw)) {
|
|
202
|
+
throw new ApiError("Brave search returned a malformed response", 500);
|
|
203
|
+
}
|
|
204
|
+
const web = raw.web;
|
|
205
|
+
if (!isPlainObject(web)) {
|
|
206
|
+
throw new ApiError("Brave search returned a malformed response", 500);
|
|
207
|
+
}
|
|
208
|
+
const results = web.results;
|
|
209
|
+
if (!Array.isArray(results)) {
|
|
210
|
+
throw new ApiError("Brave search returned a malformed response", 500);
|
|
211
|
+
}
|
|
212
|
+
const out = [];
|
|
213
|
+
for (const entry of results) {
|
|
214
|
+
out.push(normalizeBraveResultEntry(entry));
|
|
215
|
+
}
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Normalize a raw Brave NEWS or VIDEO search response into
|
|
220
|
+
* `SearchSource[]`. Both responses use the same top-level `raw.results[]`
|
|
221
|
+
* wrapper (NOT nested under `web`), so they share one normalizer.
|
|
222
|
+
* Brave-only video fields (`duration`/`views`/`creator`/`thumbnail`) are
|
|
223
|
+
* naturally DROPPED — the shared {@link normalizeBraveResultEntry} reads
|
|
224
|
+
* only `title`/`url`/`description`/`meta_url.netloc`/`page_age`/`age`
|
|
225
|
+
* (ADR-0001). Any malformed shape is a retryable `ApiError` 500.
|
|
226
|
+
*/
|
|
227
|
+
function normalizeBraveTopLevelResults(raw) {
|
|
228
|
+
if (!isPlainObject(raw)) {
|
|
229
|
+
throw new ApiError("Brave search returned a malformed response", 500);
|
|
230
|
+
}
|
|
231
|
+
const results = raw.results;
|
|
232
|
+
if (!Array.isArray(results)) {
|
|
233
|
+
throw new ApiError("Brave search returned a malformed response", 500);
|
|
234
|
+
}
|
|
235
|
+
const out = [];
|
|
236
|
+
for (const entry of results) {
|
|
237
|
+
out.push(normalizeBraveResultEntry(entry));
|
|
238
|
+
}
|
|
239
|
+
return out;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Normalize a raw Brave LLM Context response into `SearchSource[]`.
|
|
243
|
+
* Reads `raw.grounding.generic[]`; each entry carries `title`/`url` and
|
|
244
|
+
* a `snippets` array of extracted passages. Passages are joined with a
|
|
245
|
+
* blank line into `summary`. LLM Context entries do NOT carry
|
|
246
|
+
* `meta_url.netloc` or `page_age`/`age` (the web/news/video shape), so
|
|
247
|
+
* `source`/`date` are not synthesized here. Any malformed shape is a
|
|
248
|
+
* retryable `ApiError` 500.
|
|
249
|
+
*/
|
|
250
|
+
function normalizeBraveLlmContextResults(raw) {
|
|
251
|
+
if (!isPlainObject(raw)) {
|
|
252
|
+
throw new ApiError("Brave search returned a malformed response", 500);
|
|
253
|
+
}
|
|
254
|
+
const grounding = raw.grounding;
|
|
255
|
+
if (!isPlainObject(grounding)) {
|
|
256
|
+
throw new ApiError("Brave search returned a malformed response", 500);
|
|
257
|
+
}
|
|
258
|
+
const generic = grounding.generic;
|
|
259
|
+
if (!Array.isArray(generic)) {
|
|
260
|
+
throw new ApiError("Brave search returned a malformed response", 500);
|
|
261
|
+
}
|
|
262
|
+
const out = [];
|
|
263
|
+
for (const entry of generic) {
|
|
264
|
+
if (!isPlainObject(entry)) {
|
|
265
|
+
throw new ApiError("Brave search returned a malformed response", 500);
|
|
266
|
+
}
|
|
267
|
+
const title = entry.title;
|
|
268
|
+
const url = entry.url;
|
|
269
|
+
const snippets = entry.snippets;
|
|
270
|
+
if (typeof title !== "string" ||
|
|
271
|
+
typeof url !== "string" ||
|
|
272
|
+
!Array.isArray(snippets) ||
|
|
273
|
+
snippets.some((s) => typeof s !== "string")) {
|
|
274
|
+
throw new ApiError("Brave search returned a malformed response", 500);
|
|
275
|
+
}
|
|
276
|
+
out.push({ title, url, summary: snippets.join("\n\n") });
|
|
277
|
+
}
|
|
278
|
+
return out;
|
|
279
|
+
}
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
// Failure normalization: stable public codes, no raw payloads (NFR-006)
|
|
282
|
+
// ---------------------------------------------------------------------------
|
|
283
|
+
/**
|
|
284
|
+
* Resolve a stable HTTP-style status code for retry classification.
|
|
285
|
+
* Explicit terminal client errors (400, 404, 410, 422) map to their
|
|
286
|
+
* real codes; transient failures map to a representative status in the
|
|
287
|
+
* retryable set (429 or any 5xx 500..599 inclusive, per DESIGN.md §18 /
|
|
288
|
+
* FR-090). Unknown failures default to 500 (transient). When the caller
|
|
289
|
+
* already carries a numeric status (a typed ApiError), that status is
|
|
290
|
+
* honoured directly.
|
|
291
|
+
*/
|
|
292
|
+
function inferStatusCode(lower, known) {
|
|
293
|
+
if (typeof known === "number" && Number.isFinite(known))
|
|
294
|
+
return known;
|
|
295
|
+
if (lower.includes("404") || lower.includes("not found"))
|
|
296
|
+
return 404;
|
|
297
|
+
if (lower.includes("400") || lower.includes("bad request"))
|
|
298
|
+
return 400;
|
|
299
|
+
if (lower.includes("410") || lower.includes("gone"))
|
|
300
|
+
return 410;
|
|
301
|
+
if (lower.includes("422") || lower.includes("unprocessable"))
|
|
302
|
+
return 422;
|
|
303
|
+
if (lower.includes("500") || lower.includes("internal"))
|
|
304
|
+
return 500;
|
|
305
|
+
if (lower.includes("502") || lower.includes("bad gateway"))
|
|
306
|
+
return 502;
|
|
307
|
+
if (lower.includes("503") || lower.includes("service unavailable"))
|
|
308
|
+
return 503;
|
|
309
|
+
if (lower.includes("504") || lower.includes("gateway timeout"))
|
|
310
|
+
return 504;
|
|
311
|
+
return 500;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Status-keyed outward message for rewrapped Brave ApiErrors. The rewrap
|
|
315
|
+
* does not echo upstream `error.message` — a future change embedding a
|
|
316
|
+
* raw Provider body in an ApiError message would leak through
|
|
317
|
+
* normalization, the cache, and stdout. Curated constants only.
|
|
318
|
+
*/
|
|
319
|
+
function braveApiErrorMessage(statusCode) {
|
|
320
|
+
if (statusCode === 429)
|
|
321
|
+
return "Brave rate limit exceeded";
|
|
322
|
+
return "Brave request failed";
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Normalize a Provider failure with sanitized messages. Raw response
|
|
326
|
+
* bodies never cross the adapter boundary. Same pattern as
|
|
327
|
+
* `normalizeTavilyError` / `normalizeMiniMaxError`.
|
|
328
|
+
*/
|
|
329
|
+
function normalizeBraveError(error) {
|
|
330
|
+
// QuotaError pass-through — terminal retry guarantee preserved.
|
|
331
|
+
if (error instanceof QuotaError)
|
|
332
|
+
return error;
|
|
333
|
+
// Configuration/option/validation errors carry clean, human-authored
|
|
334
|
+
// messages and are safe to surface verbatim.
|
|
335
|
+
if (error instanceof ValidationError ||
|
|
336
|
+
error instanceof UnsupportedOptionError ||
|
|
337
|
+
error instanceof ConfigurationError) {
|
|
338
|
+
return error;
|
|
339
|
+
}
|
|
340
|
+
// Re-wrap typed transport errors with sanitized messages so a raw
|
|
341
|
+
// Provider response body embedded upstream never survives. Code +
|
|
342
|
+
// statusCode (retry signal) are preserved.
|
|
343
|
+
if (error instanceof AuthError) {
|
|
344
|
+
return new AuthError("Brave authentication failed", "BRAVE_SEARCH_API_KEY");
|
|
345
|
+
}
|
|
346
|
+
if (error instanceof NetworkError) {
|
|
347
|
+
return new NetworkError("Brave network error");
|
|
348
|
+
}
|
|
349
|
+
if (error instanceof TimeoutError) {
|
|
350
|
+
return new TimeoutError(error.durationMs, "Try again or increase timeout with BRAVE_TIMEOUT env var");
|
|
351
|
+
}
|
|
352
|
+
if (error instanceof ApiError) {
|
|
353
|
+
const statusCode = inferStatusCode("", error.statusCode);
|
|
354
|
+
return new ApiError(braveApiErrorMessage(statusCode), statusCode);
|
|
355
|
+
}
|
|
356
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
357
|
+
const lower = message.toLowerCase();
|
|
358
|
+
if (lower.includes("401") ||
|
|
359
|
+
lower.includes("403") ||
|
|
360
|
+
lower.includes("unauthorized") ||
|
|
361
|
+
lower.includes("forbidden")) {
|
|
362
|
+
return new AuthError("Brave authentication failed");
|
|
363
|
+
}
|
|
364
|
+
if (lower.includes("timeout") || lower.includes("timed out") || lower.includes("etimedout")) {
|
|
365
|
+
// Fallback branch: the transport wraps real timeouts into a typed
|
|
366
|
+
// TimeoutError (which carries the configured duration) before they
|
|
367
|
+
// reach this point. This untyped-message heuristic is rarely hit, so
|
|
368
|
+
// a constant default is fine and keeps process.env out of the
|
|
369
|
+
// normalization path (test isolation).
|
|
370
|
+
return new TimeoutError(30000);
|
|
371
|
+
}
|
|
372
|
+
if (lower.includes("econnrefused") ||
|
|
373
|
+
lower.includes("econnreset") ||
|
|
374
|
+
lower.includes("network") ||
|
|
375
|
+
lower.includes("enotfound") ||
|
|
376
|
+
lower.includes("fetch failed")) {
|
|
377
|
+
return new NetworkError("Brave network error");
|
|
378
|
+
}
|
|
379
|
+
if (lower.includes("429") || lower.includes("rate limit")) {
|
|
380
|
+
return new ApiError("Brave rate limit exceeded", 429);
|
|
381
|
+
}
|
|
382
|
+
return new ApiError("Brave request failed", inferStatusCode(lower));
|
|
383
|
+
}
|
|
384
|
+
function createBraveSearchCapability(options) {
|
|
385
|
+
const { env, transport } = options;
|
|
386
|
+
const capability = {
|
|
387
|
+
validate(request) {
|
|
388
|
+
if (!request || typeof request.query !== "string" || request.query.trim() === "") {
|
|
389
|
+
throw new ValidationError("Search query must contain at least one non-whitespace character");
|
|
390
|
+
}
|
|
391
|
+
// Brave supports domain, recency, location, topic, and contentSize
|
|
392
|
+
// (contentSize:"high" → LLM Context in T4; medium/default is a
|
|
393
|
+
// no-op depth on the web path). type:"video" combined with
|
|
394
|
+
// contentSize or topic is rejected as incompatible before any
|
|
395
|
+
// transport call.
|
|
396
|
+
assertNoUnsupportedControls(request);
|
|
397
|
+
assertNoVideoCombinations(request);
|
|
398
|
+
},
|
|
399
|
+
cacheIdentity(request) {
|
|
400
|
+
const apiKey = resolveApiKey(env);
|
|
401
|
+
const identityRequest = {
|
|
402
|
+
query: request.query,
|
|
403
|
+
};
|
|
404
|
+
if (request.controls) {
|
|
405
|
+
identityRequest.controls = request.controls;
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
provider: "brave",
|
|
409
|
+
capability: "search",
|
|
410
|
+
credentialFingerprint: credentialFingerprint(apiKey),
|
|
411
|
+
request: identityRequest,
|
|
412
|
+
// Brave never probes legacy keys — no legacyCandidates.
|
|
413
|
+
};
|
|
414
|
+
},
|
|
415
|
+
async invoke(request) {
|
|
416
|
+
// Validate before any credential access or transport call.
|
|
417
|
+
capability.validate(request);
|
|
418
|
+
const apiKey = resolveApiKey(env);
|
|
419
|
+
try {
|
|
420
|
+
// Dispatch precedence: video > high > news > web.
|
|
421
|
+
// - `video` (type:"video") stays the top branch (the
|
|
422
|
+
// type×contentSize combination is already rejected in
|
|
423
|
+
// validate, so `isVideo` and `isHigh` never co-occur).
|
|
424
|
+
// - `high` (contentSize:"high") routes to LLM Context and
|
|
425
|
+
// OVERRIDES `topic`: a `high + topic:news|finance` request
|
|
426
|
+
// goes to LLM Context, NOT news/keyword-append.
|
|
427
|
+
// - `news` (topic:"news") is the news endpoint switch.
|
|
428
|
+
// - everything else falls through to web search.
|
|
429
|
+
const isVideo = request.controls?.type === "video";
|
|
430
|
+
const isHigh = !isVideo && request.controls?.contentSize === "high";
|
|
431
|
+
const isNews = !isVideo && !isHigh && request.controls?.topic === "news";
|
|
432
|
+
// Query-mutating controls are applied to the query BEFORE
|
|
433
|
+
// dispatch; param-bearing controls (recency/location) are mapped
|
|
434
|
+
// separately. The high path MUST suppress the `topic:finance`
|
|
435
|
+
// keyword appendage (`high` overrides topic, so the editorial
|
|
436
|
+
// keyword must not pollute the passage-extraction query); the
|
|
437
|
+
// `domain` operator is a filter and still applies on every path.
|
|
438
|
+
const effectiveQuery = isHigh
|
|
439
|
+
? applyQueryMutators(request.query, request.controls, true)
|
|
440
|
+
: applyQueryMutators(request.query, request.controls);
|
|
441
|
+
const params = mapSearchControls(request.controls);
|
|
442
|
+
// The high path forwards `params` (country/freshness) to LLM
|
|
443
|
+
// Context too, so a `high` search honors `--recency`/`--location`
|
|
444
|
+
// rather than silently dropping them (consistent with the other
|
|
445
|
+
// paths). See fetchBraveLlmContext for the live gate on whether
|
|
446
|
+
// LLM Context honors these.
|
|
447
|
+
const raw = isVideo
|
|
448
|
+
? await fetchBraveVideoSearch(apiKey, effectiveQuery, params, transport)
|
|
449
|
+
: isHigh
|
|
450
|
+
? await fetchBraveLlmContext(apiKey, effectiveQuery, params, transport)
|
|
451
|
+
: isNews
|
|
452
|
+
? await fetchBraveNewsSearch(apiKey, effectiveQuery, params, transport)
|
|
453
|
+
: await fetchBraveSearch(apiKey, effectiveQuery, params, transport);
|
|
454
|
+
return isVideo
|
|
455
|
+
? normalizeBraveTopLevelResults(raw)
|
|
456
|
+
: isHigh
|
|
457
|
+
? normalizeBraveLlmContextResults(raw)
|
|
458
|
+
: isNews
|
|
459
|
+
? normalizeBraveTopLevelResults(raw)
|
|
460
|
+
: normalizeBraveWebResults(raw);
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
throw normalizeBraveError(error);
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
};
|
|
467
|
+
return capability;
|
|
468
|
+
}
|
|
469
|
+
// ---------------------------------------------------------------------------
|
|
470
|
+
// Descriptor factory
|
|
471
|
+
// ---------------------------------------------------------------------------
|
|
472
|
+
/**
|
|
473
|
+
* Build the Brave Provider Descriptor. The descriptor advertises the
|
|
474
|
+
* Search (T2), Diagnostics (T5), and Quota (T6) capabilities and
|
|
475
|
+
* constructs an Adapter whose `search`/`diagnostics`/`quota`
|
|
476
|
+
* Capabilities own credentials, transport, Provider field mapping, and
|
|
477
|
+
* failure normalization. Construction is side-effect-free; the
|
|
478
|
+
* transport is invoked per Capability call. Tests pass `transport`
|
|
479
|
+
* (typically a fake-fetch wrapper); production uses the no-argument
|
|
480
|
+
* factory which resolves to the global `fetch` and timers inside the
|
|
481
|
+
* transport Module.
|
|
482
|
+
*/
|
|
483
|
+
export function createBraveDescriptor(dependencies) {
|
|
484
|
+
const transport = dependencies?.transport;
|
|
485
|
+
return {
|
|
486
|
+
id: "brave",
|
|
487
|
+
isConfigured(env) {
|
|
488
|
+
return isBraveConfigured(env);
|
|
489
|
+
},
|
|
490
|
+
capabilities() {
|
|
491
|
+
// T2 wires search; T5 wires diagnostics; T6 wires quota. Later
|
|
492
|
+
// tickets (reader) widen this set in lockstep with the matching
|
|
493
|
+
// Adapter slots.
|
|
494
|
+
return new Set(["search", "diagnostics", "quota"]);
|
|
495
|
+
},
|
|
496
|
+
create(context) {
|
|
497
|
+
const search = createBraveSearchCapability({ env: context.env, transport });
|
|
498
|
+
const diagnostics = createBraveDiagnosticsCapability({ env: context.env, transport });
|
|
499
|
+
const quota = createBraveQuotaCapability({ env: context.env, transport });
|
|
500
|
+
return { id: "brave", search, diagnostics, quota };
|
|
501
|
+
},
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/providers/brave/adapter.ts"],"names":[],"mappings":"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"}
|