@broberg/ai-sdk 0.58.1 → 0.59.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 +33 -4
- package/dist/index.js +51 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -52,13 +52,33 @@ 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
|
+
* `reserve` must CHECK AND ADD in one atomic step (e.g. `UPDATE … SET spent = spent + ?
|
|
57
|
+
* WHERE spent + ? <= cap`) and say whether it fitted — a separate read-then-write lets
|
|
58
|
+
* parallel calls all pass a cap only one of them fits under. `release` gives a
|
|
59
|
+
* reservation back when the call fails. */
|
|
60
|
+
interface SearchCapStore {
|
|
61
|
+
reserve(key: string, usd: number, capUsd: number): boolean | Promise<boolean>;
|
|
62
|
+
release(key: string, usd: number): void | Promise<void>;
|
|
63
|
+
getSpent(key: string): number | Promise<number>;
|
|
64
|
+
}
|
|
55
65
|
interface SearchOptions {
|
|
56
66
|
/** false = no cache. Default: one in-process memory cache shared by all calls. */
|
|
57
67
|
cache?: SearchCache | false;
|
|
58
68
|
/** Where each call (and each failed attempt) is recorded. ai.search() passes the client's sink. */
|
|
59
69
|
costSink?: CostSink;
|
|
60
|
-
/** Explicit keys (BYOK); missing fields fall back to env. */
|
|
70
|
+
/** Explicit keys (BYOK); missing fields fall back to env — unless `byok` is set. */
|
|
61
71
|
credentials?: SearchCredentials;
|
|
72
|
+
/** F078.3 — customer-key mode: keys come ONLY from `credentials`, env is never read,
|
|
73
|
+
* so a tenant whose key is missing cannot run on the fleet's account. */
|
|
74
|
+
byok?: boolean;
|
|
75
|
+
/** F078.3 — hard ceiling in USD per tenant (`labels.tenantId`) per calendar day in
|
|
76
|
+
* Europe/Copenhagen. A call that would cross it throws before any request. */
|
|
77
|
+
dailyCapUsd?: number;
|
|
78
|
+
/** Where the day's spend is kept. Default: in-process memory shared by all calls. */
|
|
79
|
+
capStore?: SearchCapStore;
|
|
80
|
+
/** Clock for the day boundary (tests). */
|
|
81
|
+
now?: () => Date;
|
|
62
82
|
/** Injectable fetch (tests, proxies) — same contract as the model adapters (F073). */
|
|
63
83
|
fetch?: typeof fetch;
|
|
64
84
|
}
|
|
@@ -68,6 +88,15 @@ declare class SearchKeyMissingError extends Error {
|
|
|
68
88
|
readonly envVar: string;
|
|
69
89
|
constructor(provider: SearchProviderId, envVar: string);
|
|
70
90
|
}
|
|
91
|
+
/** Thrown before any request when the tenant's daily ceiling would be crossed. */
|
|
92
|
+
declare class SearchBudgetExceededError extends Error {
|
|
93
|
+
readonly tenant: string;
|
|
94
|
+
readonly day: string;
|
|
95
|
+
readonly capUsd: number;
|
|
96
|
+
readonly spentUsd: number;
|
|
97
|
+
readonly requestedUsd: number;
|
|
98
|
+
constructor(tenant: string, day: string, capUsd: number, spentUsd: number, requestedUsd: number);
|
|
99
|
+
}
|
|
71
100
|
|
|
72
101
|
interface MockupInput {
|
|
73
102
|
description: string;
|
|
@@ -2301,8 +2330,8 @@ declare const falStubAdapter: ProviderAdapter;
|
|
|
2301
2330
|
* wires the live adapters. */
|
|
2302
2331
|
declare const stubProviders: Record<string, ProviderAdapter>;
|
|
2303
2332
|
|
|
2304
|
-
declare const VERSION: "0.
|
|
2305
|
-
declare const SDK_TAG: "@broberg/ai-sdk@0.
|
|
2333
|
+
declare const VERSION: "0.59.1";
|
|
2334
|
+
declare const SDK_TAG: "@broberg/ai-sdk@0.59.1";
|
|
2306
2335
|
|
|
2307
2336
|
/** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
|
|
2308
2337
|
* per-call override.
|
|
@@ -2849,4 +2878,4 @@ declare function memorySearchCache(max?: number): SearchCache;
|
|
|
2849
2878
|
|
|
2850
2879
|
declare function search(req: SearchRequest, opts?: SearchOptions): Promise<SearchResult>;
|
|
2851
2880
|
|
|
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 };
|
|
2881
|
+
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
|
@@ -171,20 +171,54 @@ var SearchKeyMissingError = class extends Error {
|
|
|
171
171
|
provider;
|
|
172
172
|
envVar;
|
|
173
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
|
+
};
|
|
174
190
|
|
|
175
191
|
// src/search/index.ts
|
|
176
192
|
var sharedCache = memorySearchCache();
|
|
193
|
+
var sharedCapStore = /* @__PURE__ */ (() => {
|
|
194
|
+
const m = /* @__PURE__ */ new Map();
|
|
195
|
+
return {
|
|
196
|
+
// Synchronous, so check-and-add cannot interleave with another call.
|
|
197
|
+
reserve: (k, usd, cap) => {
|
|
198
|
+
const s = m.get(k) ?? 0;
|
|
199
|
+
if (s + usd > cap) return false;
|
|
200
|
+
m.set(k, s + usd);
|
|
201
|
+
return true;
|
|
202
|
+
},
|
|
203
|
+
release: (k, usd) => {
|
|
204
|
+
m.set(k, (m.get(k) ?? 0) - usd);
|
|
205
|
+
},
|
|
206
|
+
getSpent: (k) => m.get(k) ?? 0
|
|
207
|
+
};
|
|
208
|
+
})();
|
|
209
|
+
var copenhagenDay = (d) => new Intl.DateTimeFormat("en-CA", { timeZone: "Europe/Copenhagen" }).format(d);
|
|
177
210
|
async function callProvider(provider, req, opts) {
|
|
178
211
|
const f = opts.fetch ?? fetch;
|
|
179
212
|
const c = opts.credentials ?? {};
|
|
213
|
+
const env = opts.byok ? {} : process.env;
|
|
180
214
|
if (provider === "brave") {
|
|
181
|
-
const key = c.braveApiKey ??
|
|
215
|
+
const key = c.braveApiKey ?? env.BRAVE_API_KEY;
|
|
182
216
|
if (!key) throw new SearchKeyMissingError(provider, "BRAVE_API_KEY");
|
|
183
217
|
return braveSearch({ ...req, provider }, key, f);
|
|
184
218
|
}
|
|
185
219
|
if (provider.startsWith("cloudflare:")) {
|
|
186
|
-
const accountId = c.cloudflareAccountId ??
|
|
187
|
-
const apiToken = c.cloudflareApiToken ??
|
|
220
|
+
const accountId = c.cloudflareAccountId ?? env.CLOUDFLARE_ACCOUNT_ID;
|
|
221
|
+
const apiToken = c.cloudflareApiToken ?? env.CLOUDFLARE_API_TOKEN;
|
|
188
222
|
if (!accountId) throw new SearchKeyMissingError(provider, "CLOUDFLARE_ACCOUNT_ID");
|
|
189
223
|
if (!apiToken) throw new SearchKeyMissingError(provider, "CLOUDFLARE_API_TOKEN");
|
|
190
224
|
return cloudflareSearch({ ...req, provider }, { accountId, apiToken }, f);
|
|
@@ -217,11 +251,20 @@ async function search(req, opts = {}) {
|
|
|
217
251
|
const cache = opts.cache === false ? void 0 : opts.cache ?? sharedCache;
|
|
218
252
|
const ttl = SEARCH_CACHE_TTL_MS[req.purpose ?? "agent"];
|
|
219
253
|
const sink = opts.costSink;
|
|
254
|
+
const capStore = opts.capStore ?? sharedCapStore;
|
|
255
|
+
const tenant = req.labels?.tenantId ?? "_";
|
|
256
|
+
const day = copenhagenDay((opts.now ?? (() => /* @__PURE__ */ new Date()))());
|
|
257
|
+
const capKey = JSON.stringify([tenant, day]);
|
|
220
258
|
let lastErr;
|
|
221
259
|
for (const provider of chain) {
|
|
222
260
|
const key = searchCacheKey(provider, req);
|
|
223
261
|
const hit = cache?.get(key);
|
|
224
262
|
if (hit) return { items: hit.items, meta: { ...hit.meta, cached: true, costUsd: 0, latencyMs: 0 } };
|
|
263
|
+
const price = SEARCH_PRICE_USD[provider];
|
|
264
|
+
const cap = opts.dailyCapUsd ?? Infinity;
|
|
265
|
+
if (!await capStore.reserve(capKey, price, cap)) {
|
|
266
|
+
throw new SearchBudgetExceededError(tenant, day, cap, await capStore.getSpent(capKey), price);
|
|
267
|
+
}
|
|
225
268
|
const t0 = performance.now();
|
|
226
269
|
try {
|
|
227
270
|
const out = await callProvider(provider, req, opts);
|
|
@@ -238,6 +281,7 @@ async function search(req, opts = {}) {
|
|
|
238
281
|
return result;
|
|
239
282
|
} catch (e) {
|
|
240
283
|
lastErr = e;
|
|
284
|
+
await capStore.release(capKey, price);
|
|
241
285
|
if (sink?.recordFailure) {
|
|
242
286
|
try {
|
|
243
287
|
await sink.recordFailure({
|
|
@@ -3785,8 +3829,8 @@ var aiConfigSchema = z.object({
|
|
|
3785
3829
|
import { randomUUID } from "crypto";
|
|
3786
3830
|
|
|
3787
3831
|
// src/version.ts
|
|
3788
|
-
var VERSION = "0.
|
|
3789
|
-
var SDK_TAG = "@broberg/ai-sdk@0.
|
|
3832
|
+
var VERSION = "0.59.1";
|
|
3833
|
+
var SDK_TAG = "@broberg/ai-sdk@0.59.1";
|
|
3790
3834
|
|
|
3791
3835
|
// src/cost/sinks/upmetrics.ts
|
|
3792
3836
|
function isRetryableStatus(status) {
|
|
@@ -4580,7 +4624,7 @@ function createAI(config = {}) {
|
|
|
4580
4624
|
},
|
|
4581
4625
|
async search(req, opts) {
|
|
4582
4626
|
const labels = { ...cfg.labels, ...req.labels };
|
|
4583
|
-
return search({ ...req, ...Object.keys(labels).length ? { labels } : {} }, { ...opts, ...costSink ? { costSink } : {} });
|
|
4627
|
+
return search({ ...req, ...Object.keys(labels).length ? { labels } : {} }, { ...opts, ...cfg.byok ? { byok: true } : {}, ...costSink ? { costSink } : {} });
|
|
4584
4628
|
},
|
|
4585
4629
|
async judge(input) {
|
|
4586
4630
|
input = judgeInputSchema.parse(input);
|
|
@@ -5330,6 +5374,7 @@ export {
|
|
|
5330
5374
|
SDK_TAG,
|
|
5331
5375
|
SEARCH_CACHE_TTL_MS,
|
|
5332
5376
|
SEARCH_PRICE_USD,
|
|
5377
|
+
SearchBudgetExceededError,
|
|
5333
5378
|
SearchKeyMissingError,
|
|
5334
5379
|
StreamHttpError,
|
|
5335
5380
|
UpmetricsCostError,
|