@broberg/ai-sdk 0.57.0 → 0.58.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/dist/index.d.ts +158 -120
- package/dist/index.js +243 -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,238 @@ 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) return [req.provider];
|
|
94
|
+
const fresh = Boolean(req.fresh || req.country);
|
|
95
|
+
const english = isEnglish(req.lang);
|
|
96
|
+
const route = routes.find(
|
|
97
|
+
(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"))
|
|
98
|
+
) ?? routes[routes.length - 1];
|
|
99
|
+
let chain = route.chain.filter((p) => english || p !== "cloudflare:ceramic");
|
|
100
|
+
chain = chain.filter((p) => p !== "cloudflare:exa");
|
|
101
|
+
if (req.zdr) chain = chain.filter((p) => ZDR_PROVIDERS.has(p));
|
|
102
|
+
return chain;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/search/cache.ts
|
|
106
|
+
var SEARCH_CACHE_TTL_MS = {
|
|
107
|
+
monitor: 5 * 6e4,
|
|
108
|
+
agent: 60 * 6e4,
|
|
109
|
+
grounding: 60 * 6e4,
|
|
110
|
+
discovery: 7 * 24 * 60 * 6e4
|
|
111
|
+
};
|
|
112
|
+
function searchCacheKey(provider, req) {
|
|
113
|
+
const q = req.query.normalize("NFKC").trim().toLowerCase().replace(/\s+/g, " ");
|
|
114
|
+
return JSON.stringify([provider, req.lang ?? "", req.country ?? "", req.limit ?? 10, q]);
|
|
115
|
+
}
|
|
116
|
+
function memorySearchCache(max = 1e3) {
|
|
117
|
+
const m = /* @__PURE__ */ new Map();
|
|
118
|
+
return {
|
|
119
|
+
get(k) {
|
|
120
|
+
const e = m.get(k);
|
|
121
|
+
if (!e) return void 0;
|
|
122
|
+
if (Date.now() > e.until) {
|
|
123
|
+
m.delete(k);
|
|
124
|
+
return void 0;
|
|
125
|
+
}
|
|
126
|
+
return e.v;
|
|
127
|
+
},
|
|
128
|
+
set(k, v, ttlMs) {
|
|
129
|
+
if (m.size >= max) m.delete(m.keys().next().value);
|
|
130
|
+
m.set(k, { v, until: Date.now() + ttlMs });
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// src/cost/failure.ts
|
|
136
|
+
function classifyFailure(err) {
|
|
137
|
+
const e = err;
|
|
138
|
+
const name = e?.name ?? "";
|
|
139
|
+
const message = String(e?.message ?? "");
|
|
140
|
+
if (name === "AbortError" || name === "TimeoutError" || /timed? ?out/i.test(message.split("\n")[0] ?? "")) {
|
|
141
|
+
return { errorCode: "timeout", errorKind: "timeout" };
|
|
142
|
+
}
|
|
143
|
+
let status = typeof e?.status === "number" ? e.status : void 0;
|
|
144
|
+
if (status === void 0) {
|
|
145
|
+
const m = /(?:^|\s)([45]\d{2})(?=[:\s]|$)/.exec(message.split("\n")[0] ?? "");
|
|
146
|
+
if (m) status = Number(m[1]);
|
|
147
|
+
}
|
|
148
|
+
if (status !== void 0) {
|
|
149
|
+
const kind = status === 401 || status === 403 ? "auth" : status === 404 ? "not_found" : status === 429 ? "rate_limit" : status >= 500 ? "server" : "other";
|
|
150
|
+
return { errorCode: String(status), errorKind: kind };
|
|
151
|
+
}
|
|
152
|
+
if (name === "TypeError" && /fetch failed|network|ECONN|ENOTFOUND/i.test(message + (e?.cause?.code ?? ""))) {
|
|
153
|
+
return { errorCode: "network", errorKind: "network" };
|
|
154
|
+
}
|
|
155
|
+
return { errorCode: "unknown", errorKind: "other" };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/search/types.ts
|
|
159
|
+
var SearchKeyMissingError = class extends Error {
|
|
160
|
+
constructor(provider, envVar) {
|
|
161
|
+
super(`search: ${provider} needs ${envVar} (env or options.credentials)`);
|
|
162
|
+
this.provider = provider;
|
|
163
|
+
this.envVar = envVar;
|
|
164
|
+
this.name = "SearchKeyMissingError";
|
|
165
|
+
}
|
|
166
|
+
provider;
|
|
167
|
+
envVar;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// src/search/index.ts
|
|
171
|
+
var sharedCache = memorySearchCache();
|
|
172
|
+
async function callProvider(provider, req, opts) {
|
|
173
|
+
const f = opts.fetch ?? fetch;
|
|
174
|
+
const c = opts.credentials ?? {};
|
|
175
|
+
if (provider === "brave") {
|
|
176
|
+
const key = c.braveApiKey ?? process.env.BRAVE_API_KEY;
|
|
177
|
+
if (!key) throw new SearchKeyMissingError(provider, "BRAVE_API_KEY");
|
|
178
|
+
return braveSearch({ ...req, provider }, key, f);
|
|
179
|
+
}
|
|
180
|
+
if (provider.startsWith("cloudflare:")) {
|
|
181
|
+
const accountId = c.cloudflareAccountId ?? process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
182
|
+
const apiToken = c.cloudflareApiToken ?? process.env.CLOUDFLARE_API_TOKEN;
|
|
183
|
+
if (!accountId) throw new SearchKeyMissingError(provider, "CLOUDFLARE_ACCOUNT_ID");
|
|
184
|
+
if (!apiToken) throw new SearchKeyMissingError(provider, "CLOUDFLARE_API_TOKEN");
|
|
185
|
+
return cloudflareSearch({ ...req, provider }, { accountId, apiToken }, f);
|
|
186
|
+
}
|
|
187
|
+
throw new Error(`search: unknown provider "${String(provider)}"`);
|
|
188
|
+
}
|
|
189
|
+
function usageRow(provider, req, costUsd, latencyMs) {
|
|
190
|
+
return {
|
|
191
|
+
provider,
|
|
192
|
+
model: "web-search",
|
|
193
|
+
region: "unknown",
|
|
194
|
+
// Brave and Cloudflare's gateway do not let us say where a query is served
|
|
195
|
+
transport: "http",
|
|
196
|
+
inputTokens: 0,
|
|
197
|
+
outputTokens: 0,
|
|
198
|
+
cacheReadTokens: 0,
|
|
199
|
+
cacheCreationTokens: 0,
|
|
200
|
+
costUsd,
|
|
201
|
+
costBasis: "computed",
|
|
202
|
+
latencyMs,
|
|
203
|
+
capability: "search",
|
|
204
|
+
...req.purpose ? { purpose: req.purpose } : {},
|
|
205
|
+
...req.labels ? { labels: req.labels } : {},
|
|
206
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
async function search(req, opts = {}) {
|
|
210
|
+
const chain = routeSearch(req);
|
|
211
|
+
if (chain.length === 0) throw new Error("search: no provider fits this request (zdr excludes every candidate)");
|
|
212
|
+
const cache = opts.cache === false ? void 0 : opts.cache ?? sharedCache;
|
|
213
|
+
const ttl = SEARCH_CACHE_TTL_MS[req.purpose ?? "agent"];
|
|
214
|
+
const sink = opts.costSink;
|
|
215
|
+
let lastErr;
|
|
216
|
+
for (const provider of chain) {
|
|
217
|
+
const key = searchCacheKey(provider, req);
|
|
218
|
+
const hit = cache?.get(key);
|
|
219
|
+
if (hit) return { items: hit.items, meta: { ...hit.meta, cached: true, costUsd: 0, latencyMs: 0 } };
|
|
220
|
+
const t0 = performance.now();
|
|
221
|
+
try {
|
|
222
|
+
const out = await callProvider(provider, req, opts);
|
|
223
|
+
const latencyMs = Math.round(performance.now() - t0);
|
|
224
|
+
const result = {
|
|
225
|
+
items: dedupe(out.items),
|
|
226
|
+
meta: { provider, latencyMs, cached: false, costUsd: SEARCH_PRICE_USD[provider], ...out.requestId ? { requestId: out.requestId } : {} }
|
|
227
|
+
};
|
|
228
|
+
cache?.set(key, result, ttl);
|
|
229
|
+
try {
|
|
230
|
+
await sink?.record(usageRow(provider, req, result.meta.costUsd, latencyMs));
|
|
231
|
+
} catch {
|
|
232
|
+
}
|
|
233
|
+
return result;
|
|
234
|
+
} catch (e) {
|
|
235
|
+
lastErr = e;
|
|
236
|
+
if (sink?.recordFailure) {
|
|
237
|
+
try {
|
|
238
|
+
await sink.recordFailure({
|
|
239
|
+
provider,
|
|
240
|
+
model: "web-search",
|
|
241
|
+
transport: "http",
|
|
242
|
+
capability: "search",
|
|
243
|
+
...req.purpose ? { purpose: req.purpose } : {},
|
|
244
|
+
...req.labels ? { labels: req.labels } : {},
|
|
245
|
+
latencyMs: Math.round(performance.now() - t0),
|
|
246
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
247
|
+
...classifyFailure(e)
|
|
248
|
+
});
|
|
249
|
+
} catch {
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
throw lastErr;
|
|
255
|
+
}
|
|
256
|
+
function dedupe(items) {
|
|
257
|
+
const seen = /* @__PURE__ */ new Set();
|
|
258
|
+
return items.filter((i) => seen.has(i.url) ? false : (seen.add(i.url), true));
|
|
259
|
+
}
|
|
260
|
+
|
|
29
261
|
// src/cost/default-hosts.ts
|
|
30
262
|
var DEFAULT_BASE_URLS = {
|
|
31
263
|
anthropic: "https://api.anthropic.com",
|
|
@@ -3548,8 +3780,8 @@ var aiConfigSchema = z.object({
|
|
|
3548
3780
|
import { randomUUID } from "crypto";
|
|
3549
3781
|
|
|
3550
3782
|
// src/version.ts
|
|
3551
|
-
var VERSION = "0.
|
|
3552
|
-
var SDK_TAG = "@broberg/ai-sdk@0.
|
|
3783
|
+
var VERSION = "0.58.0";
|
|
3784
|
+
var SDK_TAG = "@broberg/ai-sdk@0.58.0";
|
|
3553
3785
|
|
|
3554
3786
|
// src/cost/sinks/upmetrics.ts
|
|
3555
3787
|
function isRetryableStatus(status) {
|
|
@@ -3830,29 +4062,6 @@ function assertByokProviders(providers) {
|
|
|
3830
4062
|
}
|
|
3831
4063
|
}
|
|
3832
4064
|
|
|
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
4065
|
// src/client.ts
|
|
3857
4066
|
var DEFAULT_IMAGE_SPEC = {
|
|
3858
4067
|
provider: "fal",
|
|
@@ -4364,6 +4573,10 @@ function createAI(config = {}) {
|
|
|
4364
4573
|
}
|
|
4365
4574
|
});
|
|
4366
4575
|
},
|
|
4576
|
+
async search(req, opts) {
|
|
4577
|
+
const labels = { ...cfg.labels, ...req.labels };
|
|
4578
|
+
return search({ ...req, ...Object.keys(labels).length ? { labels } : {} }, { ...opts, ...costSink ? { costSink } : {} });
|
|
4579
|
+
},
|
|
4367
4580
|
async judge(input) {
|
|
4368
4581
|
input = judgeInputSchema.parse(input);
|
|
4369
4582
|
const stateText = typeof input.state === "string" ? input.state : JSON.stringify(input.state);
|
|
@@ -5094,103 +5307,6 @@ function wouldRouteTo(tier) {
|
|
|
5094
5307
|
if (!spec) return { kind: "unknown-provider", provider: String(tier), onlyIf: [...ASSUMPTIONS] };
|
|
5095
5308
|
return wouldProviderRouteTo(spec.provider);
|
|
5096
5309
|
}
|
|
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
5310
|
export {
|
|
5195
5311
|
AZURE_DANISH_VOICES,
|
|
5196
5312
|
AZURE_DANISH_VOICE_LIST,
|
|
@@ -5199,6 +5315,7 @@ export {
|
|
|
5199
5315
|
CONFIG_DERIVED_HOSTS,
|
|
5200
5316
|
DEFAULT_BASE_URLS,
|
|
5201
5317
|
DEFAULT_CLIP_SEC,
|
|
5318
|
+
DEFAULT_SEARCH_ROUTES,
|
|
5202
5319
|
DEFAULT_TIER_MAP,
|
|
5203
5320
|
ELEVENLABS_DANISH_VOICES,
|
|
5204
5321
|
LOCALLY_PINNED_HOSTS,
|
|
@@ -5206,12 +5323,14 @@ export {
|
|
|
5206
5323
|
ModelUnavailableError,
|
|
5207
5324
|
PRICING_STALE_AFTER_DAYS,
|
|
5208
5325
|
SDK_TAG,
|
|
5326
|
+
SEARCH_CACHE_TTL_MS,
|
|
5209
5327
|
SEARCH_PRICE_USD,
|
|
5210
5328
|
SearchKeyMissingError,
|
|
5211
5329
|
StreamHttpError,
|
|
5212
5330
|
UpmetricsCostError,
|
|
5213
5331
|
VERSION,
|
|
5214
5332
|
VoiceUnavailableError,
|
|
5333
|
+
ZDR_PROVIDERS,
|
|
5215
5334
|
aiConfigSchema,
|
|
5216
5335
|
alignWordTimings,
|
|
5217
5336
|
anthropicAdapter,
|
|
@@ -5254,6 +5373,7 @@ export {
|
|
|
5254
5373
|
makeContracts,
|
|
5255
5374
|
makeOpenAICompatibleAdapter,
|
|
5256
5375
|
matchLabel,
|
|
5376
|
+
memorySearchCache,
|
|
5257
5377
|
messageSchema,
|
|
5258
5378
|
mistralAdapter,
|
|
5259
5379
|
mistralStubAdapter,
|
|
@@ -5276,6 +5396,7 @@ export {
|
|
|
5276
5396
|
resolveModel,
|
|
5277
5397
|
resolveTier,
|
|
5278
5398
|
resolveVoice,
|
|
5399
|
+
routeSearch,
|
|
5279
5400
|
search,
|
|
5280
5401
|
sqliteBudgetStore,
|
|
5281
5402
|
sqliteSink,
|