@broberg/ai-sdk 0.22.0 → 0.24.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
@@ -2017,8 +2017,8 @@ declare const falStubAdapter: ProviderAdapter;
2017
2017
  * wires the live adapters. */
2018
2018
  declare const stubProviders: Record<string, ProviderAdapter>;
2019
2019
 
2020
- declare const VERSION: "0.22.0";
2021
- declare const SDK_TAG: "@broberg/ai-sdk@0.22.0";
2020
+ declare const VERSION: "0.24.0";
2021
+ declare const SDK_TAG: "@broberg/ai-sdk@0.24.0";
2022
2022
 
2023
2023
  /** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
2024
2024
  * per-call override.
package/dist/index.js CHANGED
@@ -1735,7 +1735,12 @@ var FAL_IMAGE_PRICE_ESTIMATE = {
1735
1735
  "fal-ai/flux-pro/v1.1": 0.04
1736
1736
  };
1737
1737
  var FAL_TRAIN_PRICE_ESTIMATE = 2;
1738
- var FAL_VIDEO_PRICE_PER_SEC = {};
1738
+ var FAL_VIDEO_PRICE_PER_SEC = {
1739
+ // Kling 2.5 Turbo Pro i2v — the blessed FAL_KEY-only image→video route (F014
1740
+ // contentpush spike). $0.35 for the first 5 s + $0.07/additional s = a flat
1741
+ // $0.07/s (1080p); per-second-billed, commercial-use, not deprecated.
1742
+ "fal-ai/kling-video/v2.5-turbo/pro/image-to-video": 0.07
1743
+ };
1739
1744
  var FAL_VIDEO_DEFAULT_SEC = 8;
1740
1745
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
1741
1746
  function falAdapter(config = {}) {
@@ -2566,6 +2571,78 @@ var aiConfigSchema = z.object({
2566
2571
  availability: availabilitySchema.optional()
2567
2572
  });
2568
2573
 
2574
+ // src/version.ts
2575
+ var VERSION = "0.24.0";
2576
+ var SDK_TAG = "@broberg/ai-sdk@0.24.0";
2577
+
2578
+ // src/cost/sinks/upmetrics.ts
2579
+ function upmetricsSink(config) {
2580
+ const doFetch = config.fetch ?? fetch;
2581
+ const url = `${config.baseUrl.replace(/\/$/, "")}/api/agent`;
2582
+ return {
2583
+ async record(usage) {
2584
+ try {
2585
+ const startedAt = usage.ts || (/* @__PURE__ */ new Date()).toISOString();
2586
+ const endedAt = new Date(
2587
+ new Date(startedAt).getTime() + (usage.latencyMs || 0)
2588
+ ).toISOString();
2589
+ const agentKind = config.agentKind ?? (usage.capability === "embedding" ? "embedding" : "chatbot");
2590
+ const body = {
2591
+ mode: "record",
2592
+ agent_kind: agentKind,
2593
+ agent_name: config.agentName,
2594
+ provider: usage.provider,
2595
+ model: usage.model,
2596
+ status: "success",
2597
+ input_tokens: usage.inputTokens,
2598
+ output_tokens: usage.outputTokens,
2599
+ cache_read_tokens: usage.cacheReadTokens,
2600
+ cache_creation_tokens: usage.cacheCreationTokens,
2601
+ cost_usd: usage.costUsd,
2602
+ duration_ms: usage.latencyMs,
2603
+ started_at: startedAt,
2604
+ ended_at: endedAt,
2605
+ tags: {
2606
+ // Consumer attribution labels (e.g. tenantId) ride in tags so no new
2607
+ // top-level field risks the strict-shape ingest schema (F011). The
2608
+ // SDK-owned keys win — a label can never clobber capability/transport/sdk.
2609
+ ...usage.labels,
2610
+ capability: usage.capability,
2611
+ transport: usage.transport,
2612
+ sdk: SDK_TAG
2613
+ }
2614
+ };
2615
+ if (usage.tier !== void 0) body.tier = usage.tier;
2616
+ if (usage.purpose !== void 0) body.purpose = usage.purpose;
2617
+ if (usage.toolCalls) {
2618
+ body.tool_calls = usage.toolCalls.map((t) => ({
2619
+ name: t.name,
2620
+ count: t.count,
2621
+ error_count: t.errorCount ?? 0
2622
+ }));
2623
+ }
2624
+ void config.complianceMode;
2625
+ const res = await doFetch(url, {
2626
+ method: "POST",
2627
+ headers: {
2628
+ "content-type": "application/json",
2629
+ "X-Upmetrics-Key": config.apiKey
2630
+ },
2631
+ body: JSON.stringify(body)
2632
+ });
2633
+ if (!res.ok) {
2634
+ const text = await res.text().catch(() => "");
2635
+ config.onError?.(
2636
+ new Error(`upmetricsSink: ingest returned ${res.status}: ${text.slice(0, 200)}`)
2637
+ );
2638
+ }
2639
+ } catch (err) {
2640
+ config.onError?.(err);
2641
+ }
2642
+ }
2643
+ };
2644
+ }
2645
+
2569
2646
  // src/client.ts
2570
2647
  var DEFAULT_IMAGE_SPEC = {
2571
2648
  provider: "fal",
@@ -2603,9 +2680,20 @@ var DEFAULT_MODERATION_SPEC = { provider: "mistral", model: "mistral-moderation-
2603
2680
  var DEFAULT_PODCAST_SPEC = { provider: "elevenlabs", model: "eleven_v3", transport: "http" };
2604
2681
  var DEFAULT_TTS_SPEC = { provider: "elevenlabs", model: "eleven_multilingual_v2", transport: "http" };
2605
2682
  var DEFAULT_BATCH_SPEC = { provider: "mistral", model: "mistral-small-latest", transport: "http" };
2683
+ function defaultCostSink() {
2684
+ const apiKey = process.env.UPMETRICS_API_KEY;
2685
+ if (!apiKey) return void 0;
2686
+ return upmetricsSink({
2687
+ baseUrl: process.env.UPMETRICS_BASE_URL ?? "https://upmetrics.org",
2688
+ apiKey,
2689
+ agentName: process.env.UPMETRICS_AGENT_NAME ?? process.env.npm_package_name ?? "unknown",
2690
+ complianceMode: process.env.UPMETRICS_COMPLIANCE === "1"
2691
+ });
2692
+ }
2606
2693
  function createAI(config = {}) {
2607
2694
  const cfg = aiConfigSchema.parse(config);
2608
2695
  const providers = cfg.providers ?? defaultProviders;
2696
+ const costSink = cfg.costSink ?? defaultCostSink();
2609
2697
  const budget = cfg.budget ? new BudgetGuard(cfg.budget) : void 0;
2610
2698
  const estTokens = (s) => Math.ceil(s.length / 4);
2611
2699
  async function preflight(spec, estInTokens, estOutTokens) {
@@ -2634,9 +2722,9 @@ function createAI(config = {}) {
2634
2722
  return usage;
2635
2723
  }
2636
2724
  async function report(usage) {
2637
- if (!cfg.costSink) return;
2725
+ if (!costSink) return;
2638
2726
  try {
2639
- await cfg.costSink.record(usage);
2727
+ await costSink.record(usage);
2640
2728
  } catch {
2641
2729
  }
2642
2730
  }
@@ -3165,10 +3253,6 @@ var stubProviders = {
3165
3253
  fal: falStubAdapter
3166
3254
  };
3167
3255
 
3168
- // src/version.ts
3169
- var VERSION = "0.22.0";
3170
- var SDK_TAG = "@broberg/ai-sdk@0.22.0";
3171
-
3172
3256
  // src/availability/refresh.ts
3173
3257
  var NOT_REFRESHED = { refreshed: false, checked: 0, markedUnavailable: [] };
3174
3258
  var DEFAULT_TTL_MS = 60 * 60 * 1e3;
@@ -3258,74 +3342,6 @@ function multiSink(sinks) {
3258
3342
  };
3259
3343
  }
3260
3344
 
3261
- // src/cost/sinks/upmetrics.ts
3262
- function upmetricsSink(config) {
3263
- const doFetch = config.fetch ?? fetch;
3264
- const url = `${config.baseUrl.replace(/\/$/, "")}/api/agent`;
3265
- return {
3266
- async record(usage) {
3267
- try {
3268
- const startedAt = usage.ts || (/* @__PURE__ */ new Date()).toISOString();
3269
- const endedAt = new Date(
3270
- new Date(startedAt).getTime() + (usage.latencyMs || 0)
3271
- ).toISOString();
3272
- const agentKind = config.agentKind ?? (usage.capability === "embedding" ? "embedding" : "chatbot");
3273
- const body = {
3274
- mode: "record",
3275
- agent_kind: agentKind,
3276
- agent_name: config.agentName,
3277
- provider: usage.provider,
3278
- model: usage.model,
3279
- status: "success",
3280
- input_tokens: usage.inputTokens,
3281
- output_tokens: usage.outputTokens,
3282
- cache_read_tokens: usage.cacheReadTokens,
3283
- cache_creation_tokens: usage.cacheCreationTokens,
3284
- cost_usd: usage.costUsd,
3285
- duration_ms: usage.latencyMs,
3286
- started_at: startedAt,
3287
- ended_at: endedAt,
3288
- tags: {
3289
- // Consumer attribution labels (e.g. tenantId) ride in tags so no new
3290
- // top-level field risks the strict-shape ingest schema (F011). The
3291
- // SDK-owned keys win — a label can never clobber capability/transport/sdk.
3292
- ...usage.labels,
3293
- capability: usage.capability,
3294
- transport: usage.transport,
3295
- sdk: SDK_TAG
3296
- }
3297
- };
3298
- if (usage.tier !== void 0) body.tier = usage.tier;
3299
- if (usage.purpose !== void 0) body.purpose = usage.purpose;
3300
- if (usage.toolCalls) {
3301
- body.tool_calls = usage.toolCalls.map((t) => ({
3302
- name: t.name,
3303
- count: t.count,
3304
- error_count: t.errorCount ?? 0
3305
- }));
3306
- }
3307
- void config.complianceMode;
3308
- const res = await doFetch(url, {
3309
- method: "POST",
3310
- headers: {
3311
- "content-type": "application/json",
3312
- "X-Upmetrics-Key": config.apiKey
3313
- },
3314
- body: JSON.stringify(body)
3315
- });
3316
- if (!res.ok) {
3317
- const text = await res.text().catch(() => "");
3318
- config.onError?.(
3319
- new Error(`upmetricsSink: ingest returned ${res.status}: ${text.slice(0, 200)}`)
3320
- );
3321
- }
3322
- } catch (err) {
3323
- config.onError?.(err);
3324
- }
3325
- }
3326
- };
3327
- }
3328
-
3329
3345
  // src/cost/sinks/discord.ts
3330
3346
  function discordSink(config) {
3331
3347
  const doFetch = config.fetch ?? fetch;