@broberg/ai-sdk 0.30.1 → 0.31.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
@@ -130,6 +130,11 @@ interface ChatRequest {
130
130
  * (components' requirement while building @broberg/chat, 2026-08-27, where two
131
131
  * knowledge bases are written for readers with different permissions.) */
132
132
  promptCacheKey?: string;
133
+ /** F039.2 — prompt caching is ON by default where the provider supports it.
134
+ * Set false to opt out (e.g. a one-shot call whose prefix will never repeat).
135
+ * Off has no cost benefit and no penalty; a cache MISS was measured to cost
136
+ * exactly the same as a call with no key at all. */
137
+ promptCache?: boolean;
133
138
  temperature?: number;
134
139
  /** "json" → request JSON-object output where the provider supports it (F009). */
135
140
  responseFormat?: "json" | "text";
@@ -546,7 +551,6 @@ declare const messageSchema: z.ZodObject<{
546
551
  }>, "many">>;
547
552
  toolCallId: z.ZodOptional<z.ZodString>;
548
553
  }, "strip", z.ZodTypeAny, {
549
- role: "system" | "user" | "assistant" | "tool";
550
554
  content: string | ({
551
555
  text: string;
552
556
  type: "text";
@@ -555,6 +559,7 @@ declare const messageSchema: z.ZodObject<{
555
559
  type: "image";
556
560
  mimeType?: string | undefined;
557
561
  })[];
562
+ role: "system" | "user" | "assistant" | "tool";
558
563
  toolCalls?: {
559
564
  id: string;
560
565
  name: string;
@@ -562,7 +567,6 @@ declare const messageSchema: z.ZodObject<{
562
567
  }[] | undefined;
563
568
  toolCallId?: string | undefined;
564
569
  }, {
565
- role: "system" | "user" | "assistant" | "tool";
566
570
  content: string | ({
567
571
  text: string;
568
572
  type: "text";
@@ -571,6 +575,7 @@ declare const messageSchema: z.ZodObject<{
571
575
  type: "image";
572
576
  mimeType?: string | undefined;
573
577
  })[];
578
+ role: "system" | "user" | "assistant" | "tool";
574
579
  toolCalls?: {
575
580
  id: string;
576
581
  name: string;
@@ -613,6 +618,9 @@ declare const chatInputSchema: z.ZodObject<{
613
618
  * Derive it from (tenant, conversation): the key is a shared-prefix identity,
614
619
  * so two tenants with identical transcripts must get different keys. */
615
620
  promptCacheKey: z.ZodOptional<z.ZodString>;
621
+ /** F039.2 — prompt caching is ON by default on providers that support it.
622
+ * false opts out; an explicit promptCacheKey always wins. */
623
+ promptCache: z.ZodOptional<z.ZodBoolean>;
616
624
  prompt: z.ZodOptional<z.ZodString>;
617
625
  messages: z.ZodOptional<z.ZodArray<z.ZodObject<{
618
626
  role: z.ZodEnum<["system", "user", "assistant", "tool"]>;
@@ -653,7 +661,6 @@ declare const chatInputSchema: z.ZodObject<{
653
661
  }>, "many">>;
654
662
  toolCallId: z.ZodOptional<z.ZodString>;
655
663
  }, "strip", z.ZodTypeAny, {
656
- role: "system" | "user" | "assistant" | "tool";
657
664
  content: string | ({
658
665
  text: string;
659
666
  type: "text";
@@ -662,6 +669,7 @@ declare const chatInputSchema: z.ZodObject<{
662
669
  type: "image";
663
670
  mimeType?: string | undefined;
664
671
  })[];
672
+ role: "system" | "user" | "assistant" | "tool";
665
673
  toolCalls?: {
666
674
  id: string;
667
675
  name: string;
@@ -669,7 +677,6 @@ declare const chatInputSchema: z.ZodObject<{
669
677
  }[] | undefined;
670
678
  toolCallId?: string | undefined;
671
679
  }, {
672
- role: "system" | "user" | "assistant" | "tool";
673
680
  content: string | ({
674
681
  text: string;
675
682
  type: "text";
@@ -678,6 +685,7 @@ declare const chatInputSchema: z.ZodObject<{
678
685
  type: "image";
679
686
  mimeType?: string | undefined;
680
687
  })[];
688
+ role: "system" | "user" | "assistant" | "tool";
681
689
  toolCalls?: {
682
690
  id: string;
683
691
  name: string;
@@ -708,7 +716,6 @@ declare const chatInputSchema: z.ZodObject<{
708
716
  tier?: "fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | undefined;
709
717
  prompt?: string | undefined;
710
718
  messages?: {
711
- role: "system" | "user" | "assistant" | "tool";
712
719
  content: string | ({
713
720
  text: string;
714
721
  type: "text";
@@ -717,6 +724,7 @@ declare const chatInputSchema: z.ZodObject<{
717
724
  type: "image";
718
725
  mimeType?: string | undefined;
719
726
  })[];
727
+ role: "system" | "user" | "assistant" | "tool";
720
728
  toolCalls?: {
721
729
  id: string;
722
730
  name: string;
@@ -732,6 +740,7 @@ declare const chatInputSchema: z.ZodObject<{
732
740
  temperature?: number | undefined;
733
741
  purpose?: string | undefined;
734
742
  promptCacheKey?: string | undefined;
743
+ promptCache?: boolean | undefined;
735
744
  maxTokens?: number | undefined;
736
745
  responseFormat?: "text" | "json" | undefined;
737
746
  override?: {
@@ -750,7 +759,6 @@ declare const chatInputSchema: z.ZodObject<{
750
759
  tier?: "fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding" | undefined;
751
760
  prompt?: string | undefined;
752
761
  messages?: {
753
- role: "system" | "user" | "assistant" | "tool";
754
762
  content: string | ({
755
763
  text: string;
756
764
  type: "text";
@@ -759,6 +767,7 @@ declare const chatInputSchema: z.ZodObject<{
759
767
  type: "image";
760
768
  mimeType?: string | undefined;
761
769
  })[];
770
+ role: "system" | "user" | "assistant" | "tool";
762
771
  toolCalls?: {
763
772
  id: string;
764
773
  name: string;
@@ -774,6 +783,7 @@ declare const chatInputSchema: z.ZodObject<{
774
783
  temperature?: number | undefined;
775
784
  purpose?: string | undefined;
776
785
  promptCacheKey?: string | undefined;
786
+ promptCache?: boolean | undefined;
777
787
  maxTokens?: number | undefined;
778
788
  responseFormat?: "text" | "json" | undefined;
779
789
  override?: {
@@ -1716,6 +1726,9 @@ declare const ttsInputSchema: z.ZodObject<{
1716
1726
  rate?: number | undefined;
1717
1727
  }>;
1718
1728
  declare const aiConfigSchema: z.ZodObject<{
1729
+ /** F039.2 — client-wide opt-out from prompt caching (default: on where the
1730
+ * provider supports it). A per-call `promptCache` wins over this. */
1731
+ promptCache: z.ZodOptional<z.ZodBoolean>;
1719
1732
  defaults: z.ZodOptional<z.ZodRecord<z.ZodEnum<["fast", "smart", "powerful", "cheap", "vision", "video", "embedding"]>, z.ZodObject<{
1720
1733
  provider: z.ZodString;
1721
1734
  model: z.ZodString;
@@ -1755,6 +1768,7 @@ declare const aiConfigSchema: z.ZodObject<{
1755
1768
  autoResolve?: boolean | undefined;
1756
1769
  }>>;
1757
1770
  }, "strip", z.ZodTypeAny, {
1771
+ promptCache?: boolean | undefined;
1758
1772
  defaults?: Partial<Record<"fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding", {
1759
1773
  provider: string;
1760
1774
  model: string;
@@ -1771,6 +1785,7 @@ declare const aiConfigSchema: z.ZodObject<{
1771
1785
  autoResolve?: boolean | undefined;
1772
1786
  } | undefined;
1773
1787
  }, {
1788
+ promptCache?: boolean | undefined;
1774
1789
  defaults?: Partial<Record<"fast" | "smart" | "powerful" | "cheap" | "vision" | "video" | "embedding", {
1775
1790
  provider: string;
1776
1791
  model: string;
@@ -2060,6 +2075,13 @@ interface OpenAICompatibleConfig {
2060
2075
  * response's `usage.cost` (USD) as costUsd, falling back to the pricing table.
2061
2076
  * Only OpenRouter returns this field — openai/deepinfra leave it false. */
2062
2077
  costFromResponseField?: boolean;
2078
+ /** F039.2 — this provider accepts `prompt_cache_key` and caches a shared prefix
2079
+ * on it. Mistral only, deliberately: an unknown field is ignored by some
2080
+ * OpenAI-compatible servers and rejected with a 400 by others, so sending it
2081
+ * everywhere would trade a saving for an outage. Providers that cache
2082
+ * AUTOMATICALLY (openai, deepseek, gemini) need no key — they only need their
2083
+ * cached counts read back, which happens for every provider below. */
2084
+ supportsPromptCacheKey?: boolean;
2063
2085
  }
2064
2086
  declare function makeOpenAICompatibleAdapter(config: OpenAICompatibleConfig): ProviderAdapter;
2065
2087
 
@@ -2081,8 +2103,8 @@ declare const falStubAdapter: ProviderAdapter;
2081
2103
  * wires the live adapters. */
2082
2104
  declare const stubProviders: Record<string, ProviderAdapter>;
2083
2105
 
2084
- declare const VERSION: "0.30.1";
2085
- declare const SDK_TAG: "@broberg/ai-sdk@0.30.1";
2106
+ declare const VERSION: "0.31.0";
2107
+ declare const SDK_TAG: "@broberg/ai-sdk@0.31.0";
2086
2108
 
2087
2109
  /** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
2088
2110
  * per-call override.
package/dist/index.js CHANGED
@@ -485,6 +485,16 @@ function mapAnthropicStop(reason) {
485
485
  }
486
486
 
487
487
  // src/providers/openai-compatible.ts
488
+ function autoCacheKey(messages) {
489
+ const system = messages.find((m) => m.role === "system");
490
+ if (!system || typeof system.content !== "string" || system.content.length < 200) return void 0;
491
+ let h = 2166136261;
492
+ for (let i = 0; i < system.content.length; i++) {
493
+ h ^= system.content.charCodeAt(i);
494
+ h = Math.imul(h, 16777619) >>> 0;
495
+ }
496
+ return `ai-sdk-auto-${h.toString(16)}-${system.content.length}`;
497
+ }
488
498
  function toOpenAIMessage(m) {
489
499
  if (typeof m.content === "string") {
490
500
  const base = { role: m.role, content: m.content };
@@ -523,7 +533,10 @@ function makeOpenAICompatibleAdapter(config) {
523
533
  if (req.maxTokens !== void 0) body.max_tokens = req.maxTokens;
524
534
  if (req.temperature !== void 0) body.temperature = req.temperature;
525
535
  if (req.responseFormat === "json") body.response_format = { type: "json_object" };
526
- if (req.promptCacheKey !== void 0) body.prompt_cache_key = req.promptCacheKey;
536
+ if (config.supportsPromptCacheKey && req.promptCache !== false) {
537
+ const k = req.promptCacheKey ?? autoCacheKey(req.messages);
538
+ if (k !== void 0) body.prompt_cache_key = k;
539
+ }
527
540
  if (config.costFromResponseField) body.usage = { include: true };
528
541
  const res = await httpTransport({
529
542
  spec: req.spec,
@@ -1150,7 +1163,7 @@ var VOXTRAL_PRICE_PER_MIN = {
1150
1163
  };
1151
1164
  function mistralAdapter(config = {}) {
1152
1165
  const baseUrl = config.baseUrl ?? "https://api.mistral.ai/v1";
1153
- const base = makeOpenAICompatibleAdapter({ name: "mistral", baseUrl, apiKey: config.apiKey });
1166
+ const base = makeOpenAICompatibleAdapter({ name: "mistral", baseUrl, apiKey: config.apiKey, supportsPromptCacheKey: true });
1154
1167
  function key() {
1155
1168
  const k = config.apiKey ?? process.env.MISTRAL_API_KEY;
1156
1169
  if (!k) throw new Error("mistral adapter: API key not set (env MISTRAL_API_KEY)");
@@ -2631,6 +2644,9 @@ var chatInputSchema = z.object({
2631
2644
  * Derive it from (tenant, conversation): the key is a shared-prefix identity,
2632
2645
  * so two tenants with identical transcripts must get different keys. */
2633
2646
  promptCacheKey: z.string().optional(),
2647
+ /** F039.2 — prompt caching is ON by default on providers that support it.
2648
+ * false opts out; an explicit promptCacheKey always wins. */
2649
+ promptCache: z.boolean().optional(),
2634
2650
  prompt: z.string().optional(),
2635
2651
  messages: z.array(messageSchema).optional(),
2636
2652
  system: z.string().optional(),
@@ -2779,6 +2795,9 @@ var availabilitySchema = z.object({
2779
2795
  fallback: z.union([z.string(), z.array(z.string())]).optional()
2780
2796
  });
2781
2797
  var aiConfigSchema = z.object({
2798
+ /** F039.2 — client-wide opt-out from prompt caching (default: on where the
2799
+ * provider supports it). A per-call `promptCache` wins over this. */
2800
+ promptCache: z.boolean().optional(),
2782
2801
  defaults: z.record(tierSchema, tierSpecSchema).optional(),
2783
2802
  // Functions can't be deeply validated — z.custom asserts the TS type and
2784
2803
  // passes the value through untouched.
@@ -2792,8 +2811,8 @@ var aiConfigSchema = z.object({
2792
2811
  });
2793
2812
 
2794
2813
  // src/version.ts
2795
- var VERSION = "0.30.1";
2796
- var SDK_TAG = "@broberg/ai-sdk@0.30.1";
2814
+ var VERSION = "0.31.0";
2815
+ var SDK_TAG = "@broberg/ai-sdk@0.31.0";
2797
2816
 
2798
2817
  // src/cost/sinks/upmetrics.ts
2799
2818
  function upmetricsSink(config) {
@@ -3077,7 +3096,7 @@ function createAI(config = {}) {
3077
3096
  invoke: async (spec) => {
3078
3097
  const adapter = pickProvider(spec.provider);
3079
3098
  if (!adapter.chat) throw new Error(`createAI: provider "${spec.provider}" does not support chat`);
3080
- return adapter.chat({ messages, spec, tools: input.tools, maxTokens: input.maxTokens, temperature: input.temperature, responseFormat: input.responseFormat, promptCacheKey: input.promptCacheKey });
3099
+ return adapter.chat({ messages, spec, tools: input.tools, maxTokens: input.maxTokens, temperature: input.temperature, responseFormat: input.responseFormat, promptCacheKey: input.promptCacheKey, promptCache: input.promptCache ?? cfg.promptCache });
3081
3100
  }
3082
3101
  });
3083
3102
  },