@broberg/ai-sdk 0.57.0 → 0.58.1
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/dist/index.d.ts +158 -120
- package/dist/index.js +248 -122
- package/dist/index.js.map +1 -1
- package/dist/{registry-U66vzTm0.d.ts → registry-VqJrONWk.d.ts} +2 -2
- package/dist/registry.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -26,6 +26,243 @@ import {
|
|
|
26
26
|
getPrice
|
|
27
27
|
} from "./chunk-QVMGFHCF.js";
|
|
28
28
|
|
|
29
|
+
// src/search/brave.ts
|
|
30
|
+
async function braveSearch(req, apiKey, f) {
|
|
31
|
+
const params = new URLSearchParams({ q: req.query, count: String(Math.min(req.limit ?? 10, 20)) });
|
|
32
|
+
if (req.lang) params.set("search_lang", req.lang);
|
|
33
|
+
if (req.country) params.set("country", req.country);
|
|
34
|
+
const res = await f(`https://api.search.brave.com/res/v1/web/search?${params}`, {
|
|
35
|
+
headers: { accept: "application/json", "X-Subscription-Token": apiKey }
|
|
36
|
+
});
|
|
37
|
+
if (!res.ok) throw Object.assign(new Error(`brave search: HTTP ${res.status} ${(await res.text()).slice(0, 200)}`), { status: res.status });
|
|
38
|
+
const body = await res.json();
|
|
39
|
+
const items = (body.web?.results ?? []).map((r) => ({
|
|
40
|
+
title: r.title ?? "",
|
|
41
|
+
url: r.url ?? "",
|
|
42
|
+
description: r.description ?? "",
|
|
43
|
+
provider: "brave",
|
|
44
|
+
...r.language ? { lang: r.language } : {},
|
|
45
|
+
...r.page_age ? { publishedAt: new Date(r.page_age).toISOString() } : {}
|
|
46
|
+
}));
|
|
47
|
+
return { items, requestId: res.headers.get("x-request-id") ?? void 0 };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/search/cloudflare.ts
|
|
51
|
+
var CLOUDFLARE_MAX_QUERY = 1024;
|
|
52
|
+
var CLOUDFLARE_MAX_LIMIT = 10;
|
|
53
|
+
async function cloudflareSearch(req, creds, f) {
|
|
54
|
+
if (req.query.length < 1 || req.query.length > CLOUDFLARE_MAX_QUERY) {
|
|
55
|
+
throw new Error(`search: Cloudflare takes a query of 1\u2013${CLOUDFLARE_MAX_QUERY} characters, got ${req.query.length}`);
|
|
56
|
+
}
|
|
57
|
+
const provider = req.provider.split(":")[1];
|
|
58
|
+
const res = await f(`https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(creds.accountId)}/ai/websearch/`, {
|
|
59
|
+
method: "POST",
|
|
60
|
+
headers: { authorization: `Bearer ${creds.apiToken}`, "content-type": "application/json" },
|
|
61
|
+
body: JSON.stringify({ query: req.query, provider, limit: Math.min(req.limit ?? CLOUDFLARE_MAX_LIMIT, CLOUDFLARE_MAX_LIMIT) })
|
|
62
|
+
});
|
|
63
|
+
if (!res.ok) throw Object.assign(new Error(`cloudflare search (${provider}): HTTP ${res.status} ${(await res.text()).slice(0, 200)}`), { status: res.status });
|
|
64
|
+
const body = await res.json();
|
|
65
|
+
const inner = body.result ?? body;
|
|
66
|
+
const items = (inner.items ?? []).map((r) => ({
|
|
67
|
+
title: r.title ?? "",
|
|
68
|
+
url: r.url ?? "",
|
|
69
|
+
description: r.description ?? "",
|
|
70
|
+
provider: req.provider
|
|
71
|
+
}));
|
|
72
|
+
return { items, requestId: inner.metadata?.requestId };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/search/prices.ts
|
|
76
|
+
var SEARCH_PRICE_USD = {
|
|
77
|
+
"cloudflare:ceramic": 25e-5,
|
|
78
|
+
"cloudflare:linkup": 5e-3,
|
|
79
|
+
"cloudflare:exa": 7e-3,
|
|
80
|
+
brave: 5e-3
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// src/search/router.ts
|
|
84
|
+
var DEFAULT_SEARCH_ROUTES = [
|
|
85
|
+
{ name: "fresh-or-country", when: { fresh: true }, chain: ["brave", "cloudflare:linkup"] },
|
|
86
|
+
{ name: "english-agent", when: { english: true, purpose: ["agent", "grounding"] }, chain: ["cloudflare:ceramic", "cloudflare:linkup", "brave"] },
|
|
87
|
+
{ name: "english-other", when: { english: true }, chain: ["cloudflare:linkup", "cloudflare:ceramic", "brave"] },
|
|
88
|
+
{ name: "non-english", when: {}, chain: ["cloudflare:linkup", "brave"] }
|
|
89
|
+
];
|
|
90
|
+
var ZDR_PROVIDERS = /* @__PURE__ */ new Set(["cloudflare:ceramic", "cloudflare:linkup"]);
|
|
91
|
+
var isEnglish = (lang) => !lang || /^en\b/i.test(lang);
|
|
92
|
+
function routeSearch(req, routes = DEFAULT_SEARCH_ROUTES) {
|
|
93
|
+
if (req.provider) {
|
|
94
|
+
if (req.zdr && !ZDR_PROVIDERS.has(req.provider)) {
|
|
95
|
+
throw new Error(`search: zdr:true but provider "${req.provider}" keeps query data \u2014 use cloudflare:ceramic or cloudflare:linkup`);
|
|
96
|
+
}
|
|
97
|
+
return [req.provider];
|
|
98
|
+
}
|
|
99
|
+
const fresh = Boolean(req.fresh || req.country);
|
|
100
|
+
const english = isEnglish(req.lang);
|
|
101
|
+
const route = routes.find(
|
|
102
|
+
(r) => (r.when.fresh === void 0 || r.when.fresh === fresh) && (r.when.english === void 0 || r.when.english === english) && (r.when.purpose === void 0 || r.when.purpose.includes(req.purpose ?? "agent"))
|
|
103
|
+
) ?? routes[routes.length - 1];
|
|
104
|
+
let chain = route.chain.filter((p) => english || p !== "cloudflare:ceramic");
|
|
105
|
+
chain = chain.filter((p) => p !== "cloudflare:exa");
|
|
106
|
+
if (req.zdr) chain = chain.filter((p) => ZDR_PROVIDERS.has(p));
|
|
107
|
+
return chain;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/search/cache.ts
|
|
111
|
+
var SEARCH_CACHE_TTL_MS = {
|
|
112
|
+
monitor: 5 * 6e4,
|
|
113
|
+
agent: 60 * 6e4,
|
|
114
|
+
grounding: 60 * 6e4,
|
|
115
|
+
discovery: 7 * 24 * 60 * 6e4
|
|
116
|
+
};
|
|
117
|
+
function searchCacheKey(provider, req) {
|
|
118
|
+
const q = req.query.normalize("NFKC").trim().toLowerCase().replace(/\s+/g, " ");
|
|
119
|
+
return JSON.stringify([provider, req.lang ?? "", req.country ?? "", req.limit ?? 10, q]);
|
|
120
|
+
}
|
|
121
|
+
function memorySearchCache(max = 1e3) {
|
|
122
|
+
const m = /* @__PURE__ */ new Map();
|
|
123
|
+
return {
|
|
124
|
+
get(k) {
|
|
125
|
+
const e = m.get(k);
|
|
126
|
+
if (!e) return void 0;
|
|
127
|
+
if (Date.now() > e.until) {
|
|
128
|
+
m.delete(k);
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
131
|
+
return e.v;
|
|
132
|
+
},
|
|
133
|
+
set(k, v, ttlMs) {
|
|
134
|
+
if (m.size >= max) m.delete(m.keys().next().value);
|
|
135
|
+
m.set(k, { v, until: Date.now() + ttlMs });
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/cost/failure.ts
|
|
141
|
+
function classifyFailure(err) {
|
|
142
|
+
const e = err;
|
|
143
|
+
const name = e?.name ?? "";
|
|
144
|
+
const message = String(e?.message ?? "");
|
|
145
|
+
if (name === "AbortError" || name === "TimeoutError" || /timed? ?out/i.test(message.split("\n")[0] ?? "")) {
|
|
146
|
+
return { errorCode: "timeout", errorKind: "timeout" };
|
|
147
|
+
}
|
|
148
|
+
let status = typeof e?.status === "number" ? e.status : void 0;
|
|
149
|
+
if (status === void 0) {
|
|
150
|
+
const m = /(?:^|\s)([45]\d{2})(?=[:\s]|$)/.exec(message.split("\n")[0] ?? "");
|
|
151
|
+
if (m) status = Number(m[1]);
|
|
152
|
+
}
|
|
153
|
+
if (status !== void 0) {
|
|
154
|
+
const kind = status === 401 || status === 403 ? "auth" : status === 404 ? "not_found" : status === 429 ? "rate_limit" : status >= 500 ? "server" : "other";
|
|
155
|
+
return { errorCode: String(status), errorKind: kind };
|
|
156
|
+
}
|
|
157
|
+
if (name === "TypeError" && /fetch failed|network|ECONN|ENOTFOUND/i.test(message + (e?.cause?.code ?? ""))) {
|
|
158
|
+
return { errorCode: "network", errorKind: "network" };
|
|
159
|
+
}
|
|
160
|
+
return { errorCode: "unknown", errorKind: "other" };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/search/types.ts
|
|
164
|
+
var SearchKeyMissingError = class extends Error {
|
|
165
|
+
constructor(provider, envVar) {
|
|
166
|
+
super(`search: ${provider} needs ${envVar} (env or options.credentials)`);
|
|
167
|
+
this.provider = provider;
|
|
168
|
+
this.envVar = envVar;
|
|
169
|
+
this.name = "SearchKeyMissingError";
|
|
170
|
+
}
|
|
171
|
+
provider;
|
|
172
|
+
envVar;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// src/search/index.ts
|
|
176
|
+
var sharedCache = memorySearchCache();
|
|
177
|
+
async function callProvider(provider, req, opts) {
|
|
178
|
+
const f = opts.fetch ?? fetch;
|
|
179
|
+
const c = opts.credentials ?? {};
|
|
180
|
+
if (provider === "brave") {
|
|
181
|
+
const key = c.braveApiKey ?? process.env.BRAVE_API_KEY;
|
|
182
|
+
if (!key) throw new SearchKeyMissingError(provider, "BRAVE_API_KEY");
|
|
183
|
+
return braveSearch({ ...req, provider }, key, f);
|
|
184
|
+
}
|
|
185
|
+
if (provider.startsWith("cloudflare:")) {
|
|
186
|
+
const accountId = c.cloudflareAccountId ?? process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
187
|
+
const apiToken = c.cloudflareApiToken ?? process.env.CLOUDFLARE_API_TOKEN;
|
|
188
|
+
if (!accountId) throw new SearchKeyMissingError(provider, "CLOUDFLARE_ACCOUNT_ID");
|
|
189
|
+
if (!apiToken) throw new SearchKeyMissingError(provider, "CLOUDFLARE_API_TOKEN");
|
|
190
|
+
return cloudflareSearch({ ...req, provider }, { accountId, apiToken }, f);
|
|
191
|
+
}
|
|
192
|
+
throw new Error(`search: unknown provider "${String(provider)}"`);
|
|
193
|
+
}
|
|
194
|
+
function usageRow(provider, req, costUsd, latencyMs) {
|
|
195
|
+
return {
|
|
196
|
+
provider,
|
|
197
|
+
model: "web-search",
|
|
198
|
+
region: "unknown",
|
|
199
|
+
// Brave and Cloudflare's gateway do not let us say where a query is served
|
|
200
|
+
transport: "http",
|
|
201
|
+
inputTokens: 0,
|
|
202
|
+
outputTokens: 0,
|
|
203
|
+
cacheReadTokens: 0,
|
|
204
|
+
cacheCreationTokens: 0,
|
|
205
|
+
costUsd,
|
|
206
|
+
costBasis: "computed",
|
|
207
|
+
latencyMs,
|
|
208
|
+
capability: "search",
|
|
209
|
+
...req.purpose ? { purpose: req.purpose } : {},
|
|
210
|
+
...req.labels ? { labels: req.labels } : {},
|
|
211
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
async function search(req, opts = {}) {
|
|
215
|
+
const chain = routeSearch(req);
|
|
216
|
+
if (chain.length === 0) throw new Error("search: no provider fits this request (zdr excludes every candidate)");
|
|
217
|
+
const cache = opts.cache === false ? void 0 : opts.cache ?? sharedCache;
|
|
218
|
+
const ttl = SEARCH_CACHE_TTL_MS[req.purpose ?? "agent"];
|
|
219
|
+
const sink = opts.costSink;
|
|
220
|
+
let lastErr;
|
|
221
|
+
for (const provider of chain) {
|
|
222
|
+
const key = searchCacheKey(provider, req);
|
|
223
|
+
const hit = cache?.get(key);
|
|
224
|
+
if (hit) return { items: hit.items, meta: { ...hit.meta, cached: true, costUsd: 0, latencyMs: 0 } };
|
|
225
|
+
const t0 = performance.now();
|
|
226
|
+
try {
|
|
227
|
+
const out = await callProvider(provider, req, opts);
|
|
228
|
+
const latencyMs = Math.round(performance.now() - t0);
|
|
229
|
+
const result = {
|
|
230
|
+
items: dedupe(out.items),
|
|
231
|
+
meta: { provider, latencyMs, cached: false, costUsd: SEARCH_PRICE_USD[provider], ...out.requestId ? { requestId: out.requestId } : {} }
|
|
232
|
+
};
|
|
233
|
+
cache?.set(key, result, ttl);
|
|
234
|
+
try {
|
|
235
|
+
await sink?.record(usageRow(provider, req, result.meta.costUsd, latencyMs));
|
|
236
|
+
} catch {
|
|
237
|
+
}
|
|
238
|
+
return result;
|
|
239
|
+
} catch (e) {
|
|
240
|
+
lastErr = e;
|
|
241
|
+
if (sink?.recordFailure) {
|
|
242
|
+
try {
|
|
243
|
+
await sink.recordFailure({
|
|
244
|
+
provider,
|
|
245
|
+
model: "web-search",
|
|
246
|
+
transport: "http",
|
|
247
|
+
capability: "search",
|
|
248
|
+
...req.purpose ? { purpose: req.purpose } : {},
|
|
249
|
+
...req.labels ? { labels: req.labels } : {},
|
|
250
|
+
latencyMs: Math.round(performance.now() - t0),
|
|
251
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
252
|
+
...classifyFailure(e)
|
|
253
|
+
});
|
|
254
|
+
} catch {
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
throw lastErr;
|
|
260
|
+
}
|
|
261
|
+
function dedupe(items) {
|
|
262
|
+
const seen = /* @__PURE__ */ new Set();
|
|
263
|
+
return items.filter((i) => seen.has(i.url) ? false : (seen.add(i.url), true));
|
|
264
|
+
}
|
|
265
|
+
|
|
29
266
|
// src/cost/default-hosts.ts
|
|
30
267
|
var DEFAULT_BASE_URLS = {
|
|
31
268
|
anthropic: "https://api.anthropic.com",
|
|
@@ -3548,8 +3785,8 @@ var aiConfigSchema = z.object({
|
|
|
3548
3785
|
import { randomUUID } from "crypto";
|
|
3549
3786
|
|
|
3550
3787
|
// src/version.ts
|
|
3551
|
-
var VERSION = "0.
|
|
3552
|
-
var SDK_TAG = "@broberg/ai-sdk@0.
|
|
3788
|
+
var VERSION = "0.58.1";
|
|
3789
|
+
var SDK_TAG = "@broberg/ai-sdk@0.58.1";
|
|
3553
3790
|
|
|
3554
3791
|
// src/cost/sinks/upmetrics.ts
|
|
3555
3792
|
function isRetryableStatus(status) {
|
|
@@ -3830,29 +4067,6 @@ function assertByokProviders(providers) {
|
|
|
3830
4067
|
}
|
|
3831
4068
|
}
|
|
3832
4069
|
|
|
3833
|
-
// src/cost/failure.ts
|
|
3834
|
-
function classifyFailure(err) {
|
|
3835
|
-
const e = err;
|
|
3836
|
-
const name = e?.name ?? "";
|
|
3837
|
-
const message = String(e?.message ?? "");
|
|
3838
|
-
if (name === "AbortError" || name === "TimeoutError" || /timed? ?out/i.test(message.split("\n")[0] ?? "")) {
|
|
3839
|
-
return { errorCode: "timeout", errorKind: "timeout" };
|
|
3840
|
-
}
|
|
3841
|
-
let status = typeof e?.status === "number" ? e.status : void 0;
|
|
3842
|
-
if (status === void 0) {
|
|
3843
|
-
const m = /(?:^|\s)([45]\d{2})(?=[:\s]|$)/.exec(message.split("\n")[0] ?? "");
|
|
3844
|
-
if (m) status = Number(m[1]);
|
|
3845
|
-
}
|
|
3846
|
-
if (status !== void 0) {
|
|
3847
|
-
const kind = status === 401 || status === 403 ? "auth" : status === 404 ? "not_found" : status === 429 ? "rate_limit" : status >= 500 ? "server" : "other";
|
|
3848
|
-
return { errorCode: String(status), errorKind: kind };
|
|
3849
|
-
}
|
|
3850
|
-
if (name === "TypeError" && /fetch failed|network|ECONN|ENOTFOUND/i.test(message + (e?.cause?.code ?? ""))) {
|
|
3851
|
-
return { errorCode: "network", errorKind: "network" };
|
|
3852
|
-
}
|
|
3853
|
-
return { errorCode: "unknown", errorKind: "other" };
|
|
3854
|
-
}
|
|
3855
|
-
|
|
3856
4070
|
// src/client.ts
|
|
3857
4071
|
var DEFAULT_IMAGE_SPEC = {
|
|
3858
4072
|
provider: "fal",
|
|
@@ -4364,6 +4578,10 @@ function createAI(config = {}) {
|
|
|
4364
4578
|
}
|
|
4365
4579
|
});
|
|
4366
4580
|
},
|
|
4581
|
+
async search(req, opts) {
|
|
4582
|
+
const labels = { ...cfg.labels, ...req.labels };
|
|
4583
|
+
return search({ ...req, ...Object.keys(labels).length ? { labels } : {} }, { ...opts, ...costSink ? { costSink } : {} });
|
|
4584
|
+
},
|
|
4367
4585
|
async judge(input) {
|
|
4368
4586
|
input = judgeInputSchema.parse(input);
|
|
4369
4587
|
const stateText = typeof input.state === "string" ? input.state : JSON.stringify(input.state);
|
|
@@ -5094,103 +5312,6 @@ function wouldRouteTo(tier) {
|
|
|
5094
5312
|
if (!spec) return { kind: "unknown-provider", provider: String(tier), onlyIf: [...ASSUMPTIONS] };
|
|
5095
5313
|
return wouldProviderRouteTo(spec.provider);
|
|
5096
5314
|
}
|
|
5097
|
-
|
|
5098
|
-
// src/search/brave.ts
|
|
5099
|
-
async function braveSearch(req, apiKey, f) {
|
|
5100
|
-
const params = new URLSearchParams({ q: req.query, count: String(Math.min(req.limit ?? 10, 20)) });
|
|
5101
|
-
if (req.lang) params.set("search_lang", req.lang);
|
|
5102
|
-
if (req.country) params.set("country", req.country);
|
|
5103
|
-
const res = await f(`https://api.search.brave.com/res/v1/web/search?${params}`, {
|
|
5104
|
-
headers: { accept: "application/json", "X-Subscription-Token": apiKey }
|
|
5105
|
-
});
|
|
5106
|
-
if (!res.ok) throw Object.assign(new Error(`brave search: HTTP ${res.status} ${(await res.text()).slice(0, 200)}`), { status: res.status });
|
|
5107
|
-
const body = await res.json();
|
|
5108
|
-
const items = (body.web?.results ?? []).map((r) => ({
|
|
5109
|
-
title: r.title ?? "",
|
|
5110
|
-
url: r.url ?? "",
|
|
5111
|
-
description: r.description ?? "",
|
|
5112
|
-
provider: "brave",
|
|
5113
|
-
...r.language ? { lang: r.language } : {},
|
|
5114
|
-
...r.page_age ? { publishedAt: new Date(r.page_age).toISOString() } : {}
|
|
5115
|
-
}));
|
|
5116
|
-
return { items, requestId: res.headers.get("x-request-id") ?? void 0 };
|
|
5117
|
-
}
|
|
5118
|
-
|
|
5119
|
-
// src/search/cloudflare.ts
|
|
5120
|
-
var CLOUDFLARE_MAX_QUERY = 1024;
|
|
5121
|
-
var CLOUDFLARE_MAX_LIMIT = 10;
|
|
5122
|
-
async function cloudflareSearch(req, creds, f) {
|
|
5123
|
-
if (req.query.length < 1 || req.query.length > CLOUDFLARE_MAX_QUERY) {
|
|
5124
|
-
throw new Error(`search: Cloudflare takes a query of 1\u2013${CLOUDFLARE_MAX_QUERY} characters, got ${req.query.length}`);
|
|
5125
|
-
}
|
|
5126
|
-
const provider = req.provider.split(":")[1];
|
|
5127
|
-
const res = await f(`https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(creds.accountId)}/ai/websearch/`, {
|
|
5128
|
-
method: "POST",
|
|
5129
|
-
headers: { authorization: `Bearer ${creds.apiToken}`, "content-type": "application/json" },
|
|
5130
|
-
body: JSON.stringify({ query: req.query, provider, limit: Math.min(req.limit ?? CLOUDFLARE_MAX_LIMIT, CLOUDFLARE_MAX_LIMIT) })
|
|
5131
|
-
});
|
|
5132
|
-
if (!res.ok) throw Object.assign(new Error(`cloudflare search (${provider}): HTTP ${res.status} ${(await res.text()).slice(0, 200)}`), { status: res.status });
|
|
5133
|
-
const body = await res.json();
|
|
5134
|
-
const inner = body.result ?? body;
|
|
5135
|
-
const items = (inner.items ?? []).map((r) => ({
|
|
5136
|
-
title: r.title ?? "",
|
|
5137
|
-
url: r.url ?? "",
|
|
5138
|
-
description: r.description ?? "",
|
|
5139
|
-
provider: req.provider
|
|
5140
|
-
}));
|
|
5141
|
-
return { items, requestId: inner.metadata?.requestId };
|
|
5142
|
-
}
|
|
5143
|
-
|
|
5144
|
-
// src/search/prices.ts
|
|
5145
|
-
var SEARCH_PRICE_USD = {
|
|
5146
|
-
"cloudflare:ceramic": 25e-5,
|
|
5147
|
-
"cloudflare:linkup": 5e-3,
|
|
5148
|
-
"cloudflare:exa": 7e-3,
|
|
5149
|
-
brave: 5e-3
|
|
5150
|
-
};
|
|
5151
|
-
|
|
5152
|
-
// src/search/types.ts
|
|
5153
|
-
var SearchKeyMissingError = class extends Error {
|
|
5154
|
-
constructor(provider, envVar) {
|
|
5155
|
-
super(`search: ${provider} needs ${envVar} (env or options.credentials)`);
|
|
5156
|
-
this.provider = provider;
|
|
5157
|
-
this.envVar = envVar;
|
|
5158
|
-
this.name = "SearchKeyMissingError";
|
|
5159
|
-
}
|
|
5160
|
-
provider;
|
|
5161
|
-
envVar;
|
|
5162
|
-
};
|
|
5163
|
-
|
|
5164
|
-
// src/search/index.ts
|
|
5165
|
-
async function search(req, opts = {}) {
|
|
5166
|
-
const f = opts.fetch ?? fetch;
|
|
5167
|
-
const c = opts.credentials ?? {};
|
|
5168
|
-
const t0 = performance.now();
|
|
5169
|
-
let out;
|
|
5170
|
-
if (req.provider === "brave") {
|
|
5171
|
-
const key = c.braveApiKey ?? process.env.BRAVE_API_KEY;
|
|
5172
|
-
if (!key) throw new SearchKeyMissingError(req.provider, "BRAVE_API_KEY");
|
|
5173
|
-
out = await braveSearch(req, key, f);
|
|
5174
|
-
} else if (req.provider.startsWith("cloudflare:")) {
|
|
5175
|
-
const accountId = c.cloudflareAccountId ?? process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
5176
|
-
const apiToken = c.cloudflareApiToken ?? process.env.CLOUDFLARE_API_TOKEN;
|
|
5177
|
-
if (!accountId) throw new SearchKeyMissingError(req.provider, "CLOUDFLARE_ACCOUNT_ID");
|
|
5178
|
-
if (!apiToken) throw new SearchKeyMissingError(req.provider, "CLOUDFLARE_API_TOKEN");
|
|
5179
|
-
out = await cloudflareSearch(req, { accountId, apiToken }, f);
|
|
5180
|
-
} else {
|
|
5181
|
-
throw new Error(`search: unknown provider "${String(req.provider)}"`);
|
|
5182
|
-
}
|
|
5183
|
-
return {
|
|
5184
|
-
items: out.items,
|
|
5185
|
-
meta: {
|
|
5186
|
-
provider: req.provider,
|
|
5187
|
-
latencyMs: Math.round(performance.now() - t0),
|
|
5188
|
-
cached: false,
|
|
5189
|
-
costUsd: SEARCH_PRICE_USD[req.provider],
|
|
5190
|
-
...out.requestId ? { requestId: out.requestId } : {}
|
|
5191
|
-
}
|
|
5192
|
-
};
|
|
5193
|
-
}
|
|
5194
5315
|
export {
|
|
5195
5316
|
AZURE_DANISH_VOICES,
|
|
5196
5317
|
AZURE_DANISH_VOICE_LIST,
|
|
@@ -5199,6 +5320,7 @@ export {
|
|
|
5199
5320
|
CONFIG_DERIVED_HOSTS,
|
|
5200
5321
|
DEFAULT_BASE_URLS,
|
|
5201
5322
|
DEFAULT_CLIP_SEC,
|
|
5323
|
+
DEFAULT_SEARCH_ROUTES,
|
|
5202
5324
|
DEFAULT_TIER_MAP,
|
|
5203
5325
|
ELEVENLABS_DANISH_VOICES,
|
|
5204
5326
|
LOCALLY_PINNED_HOSTS,
|
|
@@ -5206,12 +5328,14 @@ export {
|
|
|
5206
5328
|
ModelUnavailableError,
|
|
5207
5329
|
PRICING_STALE_AFTER_DAYS,
|
|
5208
5330
|
SDK_TAG,
|
|
5331
|
+
SEARCH_CACHE_TTL_MS,
|
|
5209
5332
|
SEARCH_PRICE_USD,
|
|
5210
5333
|
SearchKeyMissingError,
|
|
5211
5334
|
StreamHttpError,
|
|
5212
5335
|
UpmetricsCostError,
|
|
5213
5336
|
VERSION,
|
|
5214
5337
|
VoiceUnavailableError,
|
|
5338
|
+
ZDR_PROVIDERS,
|
|
5215
5339
|
aiConfigSchema,
|
|
5216
5340
|
alignWordTimings,
|
|
5217
5341
|
anthropicAdapter,
|
|
@@ -5254,6 +5378,7 @@ export {
|
|
|
5254
5378
|
makeContracts,
|
|
5255
5379
|
makeOpenAICompatibleAdapter,
|
|
5256
5380
|
matchLabel,
|
|
5381
|
+
memorySearchCache,
|
|
5257
5382
|
messageSchema,
|
|
5258
5383
|
mistralAdapter,
|
|
5259
5384
|
mistralStubAdapter,
|
|
@@ -5276,6 +5401,7 @@ export {
|
|
|
5276
5401
|
resolveModel,
|
|
5277
5402
|
resolveTier,
|
|
5278
5403
|
resolveVoice,
|
|
5404
|
+
routeSearch,
|
|
5279
5405
|
search,
|
|
5280
5406
|
sqliteBudgetStore,
|
|
5281
5407
|
sqliteSink,
|