@broberg/ai-sdk 0.59.1 → 0.61.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 CHANGED
@@ -3,7 +3,8 @@ export { p as AlignedWordTimings, q as AvailabilitySource, r as AvailabilityStat
3
3
  import { z } from 'zod';
4
4
  export { DEFAULT_CLIP_SEC, MEDIA_PRICING_CHECKED_AT, MediaPrice, MediaUnit, PRICING_STALE_AFTER_DAYS, PricingFreshness, UnitFreshness, getMediaPrice, listMediaPrices, pricingFreshness, pricingGeneratedAt } from './pricing.js';
5
5
 
6
- type SearchProviderId = "brave" | "cloudflare:ceramic" | "cloudflare:linkup" | "cloudflare:exa";
6
+ /** `tavily` is CMS-legacy only (F078.5): reachable by explicit provider, never routed to. */
7
+ type SearchProviderId = "brave" | "cloudflare:ceramic" | "cloudflare:linkup" | "cloudflare:exa" | "tavily";
7
8
  /** Why the search runs — picks the route and the cache lifetime (F078.2). */
8
9
  type SearchPurpose = "agent" | "grounding" | "discovery" | "monitor";
9
10
  interface SearchRequest {
@@ -47,6 +48,7 @@ interface SearchCredentials {
47
48
  braveApiKey?: string;
48
49
  cloudflareAccountId?: string;
49
50
  cloudflareApiToken?: string;
51
+ tavilyApiKey?: string;
50
52
  }
51
53
  interface SearchCache {
52
54
  get(key: string): SearchResult | undefined;
@@ -1882,8 +1884,9 @@ declare const aiConfigSchema: z.ZodObject<{
1882
1884
  }>>;
1883
1885
  }, "strip", z.ZodTypeAny, {
1884
1886
  labels?: Record<string, string> | undefined;
1885
- promptCache?: boolean | undefined;
1887
+ costSink?: CostSink | null | undefined;
1886
1888
  byok?: boolean | undefined;
1889
+ promptCache?: boolean | undefined;
1887
1890
  strictPinning?: boolean | undefined;
1888
1891
  defaults?: Partial<Record<"vision" | "video" | "embedding" | "fast" | "smart" | "powerful" | "cheap", {
1889
1892
  provider: string;
@@ -1891,7 +1894,6 @@ declare const aiConfigSchema: z.ZodObject<{
1891
1894
  transport: "http" | "subprocess";
1892
1895
  }>> | undefined;
1893
1896
  providers?: Record<string, ProviderAdapter> | undefined;
1894
- costSink?: CostSink | null | undefined;
1895
1897
  budget?: {
1896
1898
  perCallUsd?: number | undefined;
1897
1899
  rollingUsd?: number | undefined;
@@ -1902,8 +1904,9 @@ declare const aiConfigSchema: z.ZodObject<{
1902
1904
  } | undefined;
1903
1905
  }, {
1904
1906
  labels?: Record<string, string> | undefined;
1905
- promptCache?: boolean | undefined;
1907
+ costSink?: CostSink | null | undefined;
1906
1908
  byok?: boolean | undefined;
1909
+ promptCache?: boolean | undefined;
1907
1910
  strictPinning?: boolean | undefined;
1908
1911
  defaults?: Partial<Record<"vision" | "video" | "embedding" | "fast" | "smart" | "powerful" | "cheap", {
1909
1912
  provider: string;
@@ -1911,7 +1914,6 @@ declare const aiConfigSchema: z.ZodObject<{
1911
1914
  transport: "http" | "subprocess";
1912
1915
  }>> | undefined;
1913
1916
  providers?: Record<string, ProviderAdapter> | undefined;
1914
- costSink?: CostSink | null | undefined;
1915
1917
  budget?: {
1916
1918
  perCallUsd?: number | undefined;
1917
1919
  rollingUsd?: number | undefined;
@@ -2330,8 +2332,8 @@ declare const falStubAdapter: ProviderAdapter;
2330
2332
  * wires the live adapters. */
2331
2333
  declare const stubProviders: Record<string, ProviderAdapter>;
2332
2334
 
2333
- declare const VERSION: "0.59.1";
2334
- declare const SDK_TAG: "@broberg/ai-sdk@0.59.1";
2335
+ declare const VERSION: "0.61.0";
2336
+ declare const SDK_TAG: "@broberg/ai-sdk@0.61.0";
2335
2337
 
2336
2338
  /** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
2337
2339
  * per-call override.
@@ -2858,6 +2860,25 @@ declare function streamTransport(req: StreamTransportRequest): AsyncIterable<str
2858
2860
 
2859
2861
  declare const SEARCH_PRICE_USD: Record<SearchProviderId, number>;
2860
2862
 
2863
+ declare const webSearchTool: Tool;
2864
+ /** What the app decides — never the model. */
2865
+ interface WebSearchContext extends SearchOptions {
2866
+ /** Customer data may be in the query: only Zero-Data-Retention providers. */
2867
+ zdr?: boolean;
2868
+ /** Attribution, e.g. { tenantId } — also selects the tenant's daily cap. */
2869
+ labels?: Record<string, string>;
2870
+ }
2871
+ interface WebSearchToolResult {
2872
+ provider: string;
2873
+ results: {
2874
+ title: string;
2875
+ url: string;
2876
+ snippet: string;
2877
+ }[];
2878
+ }
2879
+ /** Run a `web_search` tool call. Throws on invalid arguments before any request. */
2880
+ declare function runWebSearch(args: Record<string, unknown>, ctx?: WebSearchContext): Promise<WebSearchToolResult>;
2881
+
2861
2882
  interface SearchRoute {
2862
2883
  /** Readable name — shows up in tests and in the reason a provider was picked. */
2863
2884
  name: string;
@@ -2878,4 +2899,4 @@ declare function memorySearchCache(max?: number): SearchCache;
2878
2899
 
2879
2900
  declare function search(req: SearchRequest, opts?: SearchOptions): Promise<SearchResult>;
2880
2901
 
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 };
2902
+ 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, type WebSearchContext, type WebSearchToolResult, 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, runWebSearch, search, sqliteBudgetStore, sqliteSink, streamTransport, stubProviders, subprocessTransport, tierSpecSchema, toProviderTools, toolSchema, translateInputSchema, typesafeAdapter, upmetricsCostClient, upmetricsSink, usdFromMicro, vertexAdapter, visionInputSchema, webSearchTool, wouldProviderRouteTo, wouldRouteTo };
package/dist/index.js CHANGED
@@ -72,12 +72,37 @@ async function cloudflareSearch(req, creds, f) {
72
72
  return { items, requestId: inner.metadata?.requestId };
73
73
  }
74
74
 
75
+ // src/search/tavily.ts
76
+ async function tavilySearch(req, apiKey, f) {
77
+ const res = await f("https://api.tavily.com/search", {
78
+ method: "POST",
79
+ headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
80
+ body: JSON.stringify({ query: req.query, max_results: Math.min(req.limit ?? 10, 20), search_depth: "basic" })
81
+ });
82
+ if (!res.ok) throw Object.assign(new Error(`tavily search: HTTP ${res.status} ${(await res.text()).slice(0, 200)}`), { status: res.status });
83
+ const body = await res.json();
84
+ const items = (body.results ?? []).map((r) => {
85
+ const published = r.published_date ? new Date(r.published_date) : void 0;
86
+ return {
87
+ title: r.title ?? "",
88
+ url: r.url ?? "",
89
+ description: r.content ?? "",
90
+ provider: "tavily",
91
+ ...published && !Number.isNaN(published.getTime()) ? { publishedAt: published.toISOString() } : {}
92
+ };
93
+ });
94
+ return { items, ...body.request_id ? { requestId: body.request_id } : {} };
95
+ }
96
+
75
97
  // src/search/prices.ts
76
98
  var SEARCH_PRICE_USD = {
77
99
  "cloudflare:ceramic": 25e-5,
78
100
  "cloudflare:linkup": 5e-3,
79
101
  "cloudflare:exa": 7e-3,
80
- brave: 5e-3
102
+ brave: 5e-3,
103
+ // 1 credit per basic search; $0.0075/credit on the entry plan, less on bigger plans
104
+ // (docs.tavily.com/documentation/api-credits, 2026-10-09).
105
+ tavily: 75e-4
81
106
  };
82
107
 
83
108
  // src/search/router.ts
@@ -102,7 +127,7 @@ function routeSearch(req, routes = DEFAULT_SEARCH_ROUTES) {
102
127
  (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
128
  ) ?? routes[routes.length - 1];
104
129
  let chain = route.chain.filter((p) => english || p !== "cloudflare:ceramic");
105
- chain = chain.filter((p) => p !== "cloudflare:exa");
130
+ chain = chain.filter((p) => p !== "cloudflare:exa" && p !== "tavily");
106
131
  if (req.zdr) chain = chain.filter((p) => ZDR_PROVIDERS.has(p));
107
132
  return chain;
108
133
  }
@@ -188,6 +213,45 @@ var SearchBudgetExceededError = class extends Error {
188
213
  requestedUsd;
189
214
  };
190
215
 
216
+ // src/search/tool.ts
217
+ var PURPOSES = ["agent", "grounding", "discovery", "monitor"];
218
+ var webSearchTool = {
219
+ name: "web_search",
220
+ description: "Search the open web. Returns up to 10 results with title, url and snippet. Set lang to the query's language (e.g. 'da', 'en'). Set fresh when the answer must be recent (news, prices, events).",
221
+ parameters: {
222
+ type: "object",
223
+ properties: {
224
+ query: { type: "string", minLength: 1, maxLength: 1024, description: "What to search for." },
225
+ lang: { type: "string", description: "Language of the query, e.g. 'da' or 'en'." },
226
+ limit: { type: "integer", minimum: 1, maximum: 10, description: "Number of results (default 10)." },
227
+ purpose: { type: "string", enum: PURPOSES, description: "agent (default), grounding, discovery or monitor." },
228
+ fresh: { type: "boolean", description: "Results must be recent." }
229
+ },
230
+ required: ["query"],
231
+ additionalProperties: false
232
+ }
233
+ };
234
+ async function runWebSearch(args, ctx = {}) {
235
+ const { query, lang, limit, purpose, fresh } = args;
236
+ if (typeof query !== "string" || query.trim() === "") throw new Error("web_search: `query` must be a non-empty string");
237
+ if (lang !== void 0 && typeof lang !== "string") throw new Error("web_search: `lang` must be a string");
238
+ if (limit !== void 0 && (!Number.isInteger(limit) || limit < 1 || limit > 10)) throw new Error("web_search: `limit` must be an integer 1\u201310");
239
+ if (purpose !== void 0 && !PURPOSES.includes(purpose)) throw new Error(`web_search: \`purpose\` must be one of ${PURPOSES.join(", ")}`);
240
+ if (fresh !== void 0 && typeof fresh !== "boolean") throw new Error("web_search: `fresh` must be a boolean");
241
+ const { zdr, labels, ...opts } = ctx;
242
+ const req = {
243
+ query,
244
+ ...lang !== void 0 ? { lang } : {},
245
+ ...limit !== void 0 ? { limit } : {},
246
+ ...purpose !== void 0 ? { purpose } : {},
247
+ ...fresh !== void 0 ? { fresh } : {},
248
+ ...zdr ? { zdr } : {},
249
+ ...labels ? { labels } : {}
250
+ };
251
+ const r = await search(req, opts);
252
+ return { provider: r.meta.provider, results: r.items.map((i) => ({ title: i.title, url: i.url, snippet: i.description })) };
253
+ }
254
+
191
255
  // src/search/index.ts
192
256
  var sharedCache = memorySearchCache();
193
257
  var sharedCapStore = /* @__PURE__ */ (() => {
@@ -216,6 +280,11 @@ async function callProvider(provider, req, opts) {
216
280
  if (!key) throw new SearchKeyMissingError(provider, "BRAVE_API_KEY");
217
281
  return braveSearch({ ...req, provider }, key, f);
218
282
  }
283
+ if (provider === "tavily") {
284
+ const key = c.tavilyApiKey ?? env.TAVILY_API_KEY;
285
+ if (!key) throw new SearchKeyMissingError(provider, "TAVILY_API_KEY");
286
+ return tavilySearch({ ...req, provider }, key, f);
287
+ }
219
288
  if (provider.startsWith("cloudflare:")) {
220
289
  const accountId = c.cloudflareAccountId ?? env.CLOUDFLARE_ACCOUNT_ID;
221
290
  const apiToken = c.cloudflareApiToken ?? env.CLOUDFLARE_API_TOKEN;
@@ -3829,8 +3898,8 @@ var aiConfigSchema = z.object({
3829
3898
  import { randomUUID } from "crypto";
3830
3899
 
3831
3900
  // src/version.ts
3832
- var VERSION = "0.59.1";
3833
- var SDK_TAG = "@broberg/ai-sdk@0.59.1";
3901
+ var VERSION = "0.61.0";
3902
+ var SDK_TAG = "@broberg/ai-sdk@0.61.0";
3834
3903
 
3835
3904
  // src/cost/sinks/upmetrics.ts
3836
3905
  function isRetryableStatus(status) {
@@ -5447,6 +5516,7 @@ export {
5447
5516
  resolveTier,
5448
5517
  resolveVoice,
5449
5518
  routeSearch,
5519
+ runWebSearch,
5450
5520
  search,
5451
5521
  sqliteBudgetStore,
5452
5522
  sqliteSink,
@@ -5463,6 +5533,7 @@ export {
5463
5533
  usdFromMicro,
5464
5534
  vertexAdapter,
5465
5535
  visionInputSchema,
5536
+ webSearchTool,
5466
5537
  wouldProviderRouteTo,
5467
5538
  wouldRouteTo
5468
5539
  };