@broberg/ai-sdk 0.58.0 → 0.59.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 +28 -4
- package/dist/index.js +47 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -52,13 +52,28 @@ interface SearchCache {
|
|
|
52
52
|
get(key: string): SearchResult | undefined;
|
|
53
53
|
set(key: string, value: SearchResult, ttlMs: number): void;
|
|
54
54
|
}
|
|
55
|
+
/** Running spend per key (tenant + day). Async allowed, so it can live in a database. */
|
|
56
|
+
interface SearchCapStore {
|
|
57
|
+
getSpent(key: string): number | Promise<number>;
|
|
58
|
+
addSpent(key: string, usd: number): void | Promise<void>;
|
|
59
|
+
}
|
|
55
60
|
interface SearchOptions {
|
|
56
61
|
/** false = no cache. Default: one in-process memory cache shared by all calls. */
|
|
57
62
|
cache?: SearchCache | false;
|
|
58
63
|
/** Where each call (and each failed attempt) is recorded. ai.search() passes the client's sink. */
|
|
59
64
|
costSink?: CostSink;
|
|
60
|
-
/** Explicit keys (BYOK); missing fields fall back to env. */
|
|
65
|
+
/** Explicit keys (BYOK); missing fields fall back to env — unless `byok` is set. */
|
|
61
66
|
credentials?: SearchCredentials;
|
|
67
|
+
/** F078.3 — customer-key mode: keys come ONLY from `credentials`, env is never read,
|
|
68
|
+
* so a tenant whose key is missing cannot run on the fleet's account. */
|
|
69
|
+
byok?: boolean;
|
|
70
|
+
/** F078.3 — hard ceiling in USD per tenant (`labels.tenantId`) per calendar day in
|
|
71
|
+
* Europe/Copenhagen. A call that would cross it throws before any request. */
|
|
72
|
+
dailyCapUsd?: number;
|
|
73
|
+
/** Where the day's spend is kept. Default: in-process memory shared by all calls. */
|
|
74
|
+
capStore?: SearchCapStore;
|
|
75
|
+
/** Clock for the day boundary (tests). */
|
|
76
|
+
now?: () => Date;
|
|
62
77
|
/** Injectable fetch (tests, proxies) — same contract as the model adapters (F073). */
|
|
63
78
|
fetch?: typeof fetch;
|
|
64
79
|
}
|
|
@@ -68,6 +83,15 @@ declare class SearchKeyMissingError extends Error {
|
|
|
68
83
|
readonly envVar: string;
|
|
69
84
|
constructor(provider: SearchProviderId, envVar: string);
|
|
70
85
|
}
|
|
86
|
+
/** Thrown before any request when the tenant's daily ceiling would be crossed. */
|
|
87
|
+
declare class SearchBudgetExceededError extends Error {
|
|
88
|
+
readonly tenant: string;
|
|
89
|
+
readonly day: string;
|
|
90
|
+
readonly capUsd: number;
|
|
91
|
+
readonly spentUsd: number;
|
|
92
|
+
readonly requestedUsd: number;
|
|
93
|
+
constructor(tenant: string, day: string, capUsd: number, spentUsd: number, requestedUsd: number);
|
|
94
|
+
}
|
|
71
95
|
|
|
72
96
|
interface MockupInput {
|
|
73
97
|
description: string;
|
|
@@ -2301,8 +2325,8 @@ declare const falStubAdapter: ProviderAdapter;
|
|
|
2301
2325
|
* wires the live adapters. */
|
|
2302
2326
|
declare const stubProviders: Record<string, ProviderAdapter>;
|
|
2303
2327
|
|
|
2304
|
-
declare const VERSION: "0.
|
|
2305
|
-
declare const SDK_TAG: "@broberg/ai-sdk@0.
|
|
2328
|
+
declare const VERSION: "0.59.0";
|
|
2329
|
+
declare const SDK_TAG: "@broberg/ai-sdk@0.59.0";
|
|
2306
2330
|
|
|
2307
2331
|
/** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
|
|
2308
2332
|
* per-call override.
|
|
@@ -2849,4 +2873,4 @@ declare function memorySearchCache(max?: number): SearchCache;
|
|
|
2849
2873
|
|
|
2850
2874
|
declare function search(req: SearchRequest, opts?: SearchOptions): Promise<SearchResult>;
|
|
2851
2875
|
|
|
2852
|
-
export { AZURE_DANISH_VOICES, AZURE_DANISH_VOICE_LIST, type AiClient, type AiConfig, type AzureVoiceInfo, BatchJob, BatchRequestItem, BatchResultItem, type BflAdapterConfig, type BflCredits, BudgetConfig, BudgetExceededError, BudgetGuard, BudgetStore, CONFIG_DERIVED_HOSTS, Capability, type ChatInput, ChatResult, ChatStreamEvent, type CheckVoiceOptions, type ClassifyInput, type ClassifyResult, type Contracts, type CostQuery, CostSink, type CostSummary, type CostSummaryQuery, type CostTimeseriesQuery, DEFAULT_BASE_URLS, DEFAULT_SEARCH_ROUTES, DEFAULT_TIER_MAP, type DesignInput, type DesignResult, type DiscordSinkConfig, ELEVENLABS_DANISH_VOICES, type EmbeddingInput, EmbeddingResult, type ExtractInput, type ExtractResult, type FalAdapterConfig, type FixedHostProvider, type HttpResponse, type ImageInput, ImageResult, type JudgeInput, JudgeResult, LOCALLY_PINNED_HOSTS, type MockupInput, type MockupResult, type ModerationInput, ModerationResult, type OcrInput, OcrResult, type OpenAICompatibleConfig, type PodcastInput, PodcastResult, type PriceDriftResult, type PriceDriftRow, type PricingEntry, ProviderAdapter, type RefreshOptions, type RefreshResult, Region, type RerankInput, type RerankResult, type RouteForecast, SDK_TAG, SEARCH_CACHE_TTL_MS, SEARCH_PRICE_USD, type SearchCache, type SearchCredentials, type SearchItem, SearchKeyMissingError, type SearchOptions, type SearchProviderId, type SearchPurpose, type SearchRequest, type SearchResult, type SearchRoute, type SqliteBudgetStoreConfig, type SqliteSinkConfig, StreamHttpError, type SubprocessResponse, Tier, TierSpec, Tool, ToolCall, type TrainStyleInput, TrainStyleResult, type TranscribeInput, TranscribeResult, type TranslateInput, TranslateResult, Transport, type TransportRequest, type TransportResponse, type TtsInput, type UpmetricsCostClientConfig, UpmetricsCostError, type UpmetricsCostRow, type UpmetricsCostSummary, type UpmetricsCostTimeseries, type UpmetricsSink, type UpmetricsSinkConfig, type UpmetricsSinkStats, Usage, VERSION, type VideoInput, type VisionInput, type VoiceInfo, type VoiceProvider, type VoiceResolveResult, type VoiceStatus, VoiceUnavailableError, ZDR_PROVIDERS, aiConfigSchema, anthropicAdapter, anthropicApiAdapter, anthropicSubprocessAdapter, azureAdapter, bflAdapter, bflCredits, byokAdapter, chatInputSchema, checkPriceDrift, checkVoice, computeCost, createAI, deepinfraAdapter, deeplAdapter, deepseekAdapter, defaultBaseUrl, defaultProviders, discordSink, elevenlabsAdapter, embeddingInputSchema, falAdapter, falStubAdapter, freshUsage, fromProviderToolCall, geminiAdapter, getCostSummary, getPrice, httpTransport, imageInputSchema, isByokKeyed, listAzureDanishVoices, listVoices, makeContracts, makeOpenAICompatibleAdapter, matchLabel, memorySearchCache, messageSchema, mistralAdapter, mistralStubAdapter, multiSink, noopSink, openaiAdapter, openaiStubAdapter, openrouterAdapter, parseClaudeCliJson, parseJsonLoose, refreshAvailability, requestyAdapter, resetRefreshState, resetRegistry, resolveAzureVoice, resolveTier, resolveVoice, routeSearch, search, sqliteBudgetStore, sqliteSink, streamTransport, stubProviders, subprocessTransport, tierSpecSchema, toProviderTools, toolSchema, translateInputSchema, typesafeAdapter, upmetricsCostClient, upmetricsSink, usdFromMicro, vertexAdapter, visionInputSchema, wouldProviderRouteTo, wouldRouteTo };
|
|
2876
|
+
export { AZURE_DANISH_VOICES, AZURE_DANISH_VOICE_LIST, type AiClient, type AiConfig, type AzureVoiceInfo, BatchJob, BatchRequestItem, BatchResultItem, type BflAdapterConfig, type BflCredits, BudgetConfig, BudgetExceededError, BudgetGuard, BudgetStore, CONFIG_DERIVED_HOSTS, Capability, type ChatInput, ChatResult, ChatStreamEvent, type CheckVoiceOptions, type ClassifyInput, type ClassifyResult, type Contracts, type CostQuery, CostSink, type CostSummary, type CostSummaryQuery, type CostTimeseriesQuery, DEFAULT_BASE_URLS, DEFAULT_SEARCH_ROUTES, DEFAULT_TIER_MAP, type DesignInput, type DesignResult, type DiscordSinkConfig, ELEVENLABS_DANISH_VOICES, type EmbeddingInput, EmbeddingResult, type ExtractInput, type ExtractResult, type FalAdapterConfig, type FixedHostProvider, type HttpResponse, type ImageInput, ImageResult, type JudgeInput, JudgeResult, LOCALLY_PINNED_HOSTS, type MockupInput, type MockupResult, type ModerationInput, ModerationResult, type OcrInput, OcrResult, type OpenAICompatibleConfig, type PodcastInput, PodcastResult, type PriceDriftResult, type PriceDriftRow, type PricingEntry, ProviderAdapter, type RefreshOptions, type RefreshResult, Region, type RerankInput, type RerankResult, type RouteForecast, SDK_TAG, SEARCH_CACHE_TTL_MS, SEARCH_PRICE_USD, SearchBudgetExceededError, type SearchCache, type SearchCapStore, type SearchCredentials, type SearchItem, SearchKeyMissingError, type SearchOptions, type SearchProviderId, type SearchPurpose, type SearchRequest, type SearchResult, type SearchRoute, type SqliteBudgetStoreConfig, type SqliteSinkConfig, StreamHttpError, type SubprocessResponse, Tier, TierSpec, Tool, ToolCall, type TrainStyleInput, TrainStyleResult, type TranscribeInput, TranscribeResult, type TranslateInput, TranslateResult, Transport, type TransportRequest, type TransportResponse, type TtsInput, type UpmetricsCostClientConfig, UpmetricsCostError, type UpmetricsCostRow, type UpmetricsCostSummary, type UpmetricsCostTimeseries, type UpmetricsSink, type UpmetricsSinkConfig, type UpmetricsSinkStats, Usage, VERSION, type VideoInput, type VisionInput, type VoiceInfo, type VoiceProvider, type VoiceResolveResult, type VoiceStatus, VoiceUnavailableError, ZDR_PROVIDERS, aiConfigSchema, anthropicAdapter, anthropicApiAdapter, anthropicSubprocessAdapter, azureAdapter, bflAdapter, bflCredits, byokAdapter, chatInputSchema, checkPriceDrift, checkVoice, computeCost, createAI, deepinfraAdapter, deeplAdapter, deepseekAdapter, defaultBaseUrl, defaultProviders, discordSink, elevenlabsAdapter, embeddingInputSchema, falAdapter, falStubAdapter, freshUsage, fromProviderToolCall, geminiAdapter, getCostSummary, getPrice, httpTransport, imageInputSchema, isByokKeyed, listAzureDanishVoices, listVoices, makeContracts, makeOpenAICompatibleAdapter, matchLabel, memorySearchCache, messageSchema, mistralAdapter, mistralStubAdapter, multiSink, noopSink, openaiAdapter, openaiStubAdapter, openrouterAdapter, parseClaudeCliJson, parseJsonLoose, refreshAvailability, requestyAdapter, resetRefreshState, resetRegistry, resolveAzureVoice, resolveTier, resolveVoice, routeSearch, search, sqliteBudgetStore, sqliteSink, streamTransport, stubProviders, subprocessTransport, tierSpecSchema, toProviderTools, toolSchema, translateInputSchema, typesafeAdapter, upmetricsCostClient, upmetricsSink, usdFromMicro, vertexAdapter, visionInputSchema, wouldProviderRouteTo, wouldRouteTo };
|
package/dist/index.js
CHANGED
|
@@ -90,7 +90,12 @@ var DEFAULT_SEARCH_ROUTES = [
|
|
|
90
90
|
var ZDR_PROVIDERS = /* @__PURE__ */ new Set(["cloudflare:ceramic", "cloudflare:linkup"]);
|
|
91
91
|
var isEnglish = (lang) => !lang || /^en\b/i.test(lang);
|
|
92
92
|
function routeSearch(req, routes = DEFAULT_SEARCH_ROUTES) {
|
|
93
|
-
if (req.provider)
|
|
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
|
+
}
|
|
94
99
|
const fresh = Boolean(req.fresh || req.country);
|
|
95
100
|
const english = isEnglish(req.lang);
|
|
96
101
|
const route = routes.find(
|
|
@@ -166,20 +171,44 @@ var SearchKeyMissingError = class extends Error {
|
|
|
166
171
|
provider;
|
|
167
172
|
envVar;
|
|
168
173
|
};
|
|
174
|
+
var SearchBudgetExceededError = class extends Error {
|
|
175
|
+
constructor(tenant, day, capUsd, spentUsd, requestedUsd) {
|
|
176
|
+
super(`search: daily cap $${capUsd} for tenant "${tenant}" on ${day} reached ($${spentUsd.toFixed(5)} spent, this call $${requestedUsd})`);
|
|
177
|
+
this.tenant = tenant;
|
|
178
|
+
this.day = day;
|
|
179
|
+
this.capUsd = capUsd;
|
|
180
|
+
this.spentUsd = spentUsd;
|
|
181
|
+
this.requestedUsd = requestedUsd;
|
|
182
|
+
this.name = "SearchBudgetExceededError";
|
|
183
|
+
}
|
|
184
|
+
tenant;
|
|
185
|
+
day;
|
|
186
|
+
capUsd;
|
|
187
|
+
spentUsd;
|
|
188
|
+
requestedUsd;
|
|
189
|
+
};
|
|
169
190
|
|
|
170
191
|
// src/search/index.ts
|
|
171
192
|
var sharedCache = memorySearchCache();
|
|
193
|
+
var sharedCapStore = /* @__PURE__ */ (() => {
|
|
194
|
+
const m = /* @__PURE__ */ new Map();
|
|
195
|
+
return { getSpent: (k) => m.get(k) ?? 0, addSpent: (k, usd) => {
|
|
196
|
+
m.set(k, (m.get(k) ?? 0) + usd);
|
|
197
|
+
} };
|
|
198
|
+
})();
|
|
199
|
+
var copenhagenDay = (d) => new Intl.DateTimeFormat("en-CA", { timeZone: "Europe/Copenhagen" }).format(d);
|
|
172
200
|
async function callProvider(provider, req, opts) {
|
|
173
201
|
const f = opts.fetch ?? fetch;
|
|
174
202
|
const c = opts.credentials ?? {};
|
|
203
|
+
const env = opts.byok ? {} : process.env;
|
|
175
204
|
if (provider === "brave") {
|
|
176
|
-
const key = c.braveApiKey ??
|
|
205
|
+
const key = c.braveApiKey ?? env.BRAVE_API_KEY;
|
|
177
206
|
if (!key) throw new SearchKeyMissingError(provider, "BRAVE_API_KEY");
|
|
178
207
|
return braveSearch({ ...req, provider }, key, f);
|
|
179
208
|
}
|
|
180
209
|
if (provider.startsWith("cloudflare:")) {
|
|
181
|
-
const accountId = c.cloudflareAccountId ??
|
|
182
|
-
const apiToken = c.cloudflareApiToken ??
|
|
210
|
+
const accountId = c.cloudflareAccountId ?? env.CLOUDFLARE_ACCOUNT_ID;
|
|
211
|
+
const apiToken = c.cloudflareApiToken ?? env.CLOUDFLARE_API_TOKEN;
|
|
183
212
|
if (!accountId) throw new SearchKeyMissingError(provider, "CLOUDFLARE_ACCOUNT_ID");
|
|
184
213
|
if (!apiToken) throw new SearchKeyMissingError(provider, "CLOUDFLARE_API_TOKEN");
|
|
185
214
|
return cloudflareSearch({ ...req, provider }, { accountId, apiToken }, f);
|
|
@@ -212,11 +241,20 @@ async function search(req, opts = {}) {
|
|
|
212
241
|
const cache = opts.cache === false ? void 0 : opts.cache ?? sharedCache;
|
|
213
242
|
const ttl = SEARCH_CACHE_TTL_MS[req.purpose ?? "agent"];
|
|
214
243
|
const sink = opts.costSink;
|
|
244
|
+
const capStore = opts.capStore ?? sharedCapStore;
|
|
245
|
+
const tenant = req.labels?.tenantId ?? "_";
|
|
246
|
+
const day = copenhagenDay((opts.now ?? (() => /* @__PURE__ */ new Date()))());
|
|
247
|
+
const capKey = JSON.stringify([tenant, day]);
|
|
215
248
|
let lastErr;
|
|
216
249
|
for (const provider of chain) {
|
|
217
250
|
const key = searchCacheKey(provider, req);
|
|
218
251
|
const hit = cache?.get(key);
|
|
219
252
|
if (hit) return { items: hit.items, meta: { ...hit.meta, cached: true, costUsd: 0, latencyMs: 0 } };
|
|
253
|
+
if (opts.dailyCapUsd !== void 0) {
|
|
254
|
+
const spent = await capStore.getSpent(capKey);
|
|
255
|
+
const price = SEARCH_PRICE_USD[provider];
|
|
256
|
+
if (spent + price > opts.dailyCapUsd) throw new SearchBudgetExceededError(tenant, day, opts.dailyCapUsd, spent, price);
|
|
257
|
+
}
|
|
220
258
|
const t0 = performance.now();
|
|
221
259
|
try {
|
|
222
260
|
const out = await callProvider(provider, req, opts);
|
|
@@ -226,6 +264,7 @@ async function search(req, opts = {}) {
|
|
|
226
264
|
meta: { provider, latencyMs, cached: false, costUsd: SEARCH_PRICE_USD[provider], ...out.requestId ? { requestId: out.requestId } : {} }
|
|
227
265
|
};
|
|
228
266
|
cache?.set(key, result, ttl);
|
|
267
|
+
await capStore.addSpent(capKey, result.meta.costUsd);
|
|
229
268
|
try {
|
|
230
269
|
await sink?.record(usageRow(provider, req, result.meta.costUsd, latencyMs));
|
|
231
270
|
} catch {
|
|
@@ -3780,8 +3819,8 @@ var aiConfigSchema = z.object({
|
|
|
3780
3819
|
import { randomUUID } from "crypto";
|
|
3781
3820
|
|
|
3782
3821
|
// src/version.ts
|
|
3783
|
-
var VERSION = "0.
|
|
3784
|
-
var SDK_TAG = "@broberg/ai-sdk@0.
|
|
3822
|
+
var VERSION = "0.59.0";
|
|
3823
|
+
var SDK_TAG = "@broberg/ai-sdk@0.59.0";
|
|
3785
3824
|
|
|
3786
3825
|
// src/cost/sinks/upmetrics.ts
|
|
3787
3826
|
function isRetryableStatus(status) {
|
|
@@ -4575,7 +4614,7 @@ function createAI(config = {}) {
|
|
|
4575
4614
|
},
|
|
4576
4615
|
async search(req, opts) {
|
|
4577
4616
|
const labels = { ...cfg.labels, ...req.labels };
|
|
4578
|
-
return search({ ...req, ...Object.keys(labels).length ? { labels } : {} }, { ...opts, ...costSink ? { costSink } : {} });
|
|
4617
|
+
return search({ ...req, ...Object.keys(labels).length ? { labels } : {} }, { ...opts, ...cfg.byok ? { byok: true } : {}, ...costSink ? { costSink } : {} });
|
|
4579
4618
|
},
|
|
4580
4619
|
async judge(input) {
|
|
4581
4620
|
input = judgeInputSchema.parse(input);
|
|
@@ -5325,6 +5364,7 @@ export {
|
|
|
5325
5364
|
SDK_TAG,
|
|
5326
5365
|
SEARCH_CACHE_TTL_MS,
|
|
5327
5366
|
SEARCH_PRICE_USD,
|
|
5367
|
+
SearchBudgetExceededError,
|
|
5328
5368
|
SearchKeyMissingError,
|
|
5329
5369
|
StreamHttpError,
|
|
5330
5370
|
UpmetricsCostError,
|