@broberg/ai-sdk 0.29.0 → 0.30.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.
@@ -73,31 +73,34 @@ var PRICING = {
73
73
  // $0, which is worse than no tracking (a confident wrong number).
74
74
  "vertex:gemini-2.5-flash": { inputPer1M: 0.3, outputPer1M: 2.5, version: V },
75
75
  "vertex:gemini-2.5-flash-lite": { inputPer1M: 0.1, outputPer1M: 0.4, version: "2026-06-04-or-xref" },
76
+ // Cached prompt tokens bill at 10% of the input rate (F039, measured 2026-08-27:
77
+ // an 8,810-token prefix reported 8,784 cached on the second call WITH a
78
+ // prompt_cache_key, and 0 without one at every size up to 57k).
76
79
  // Mistral (direct, La Plateforme). Official prices from mistral.ai/pricing
77
80
  // (2026-06-04, per Christian's CD report). EU/Paris-hosted — the designated
78
81
  // GDPR-safe provider for client/personal-data workloads (see F015). NB:
79
82
  // medium-3.5 is the premium "Vibe" coding tier ($1.5/$7.5); Large 3 ($0.5/$1.5)
80
83
  // is the cheaper frontier general-purpose model despite the higher number.
81
- "mistral:mistral-large-latest": { inputPer1M: 0.5, outputPer1M: 1.5, version: MS },
82
- "mistral:mistral-large-2512": { inputPer1M: 0.5, outputPer1M: 1.5, version: MS },
83
- "mistral:mistral-medium-latest": { inputPer1M: 1.5, outputPer1M: 7.5, version: MS },
84
- "mistral:mistral-medium-3.5": { inputPer1M: 1.5, outputPer1M: 7.5, version: MS },
85
- "mistral:mistral-medium-3": { inputPer1M: 0.4, outputPer1M: 2, version: "2026-06-04-or-xref" },
86
- "mistral:mistral-small-latest": { inputPer1M: 0.1, outputPer1M: 0.3, version: MS },
87
- "mistral:mistral-small-2603": { inputPer1M: 0.1, outputPer1M: 0.3, version: MS },
88
- "mistral:ministral-3b-latest": { inputPer1M: 0.1, outputPer1M: 0.1, version: MS },
89
- "mistral:ministral-8b-latest": { inputPer1M: 0.15, outputPer1M: 0.15, version: MS },
90
- "mistral:ministral-14b-latest": { inputPer1M: 0.2, outputPer1M: 0.2, version: MS },
91
- "mistral:magistral-medium-latest": { inputPer1M: 2, outputPer1M: 5, version: MS },
92
- "mistral:magistral-small-latest": { inputPer1M: 0.5, outputPer1M: 1.5, version: MS },
93
- "mistral:devstral-latest": { inputPer1M: 0.4, outputPer1M: 2, version: MS },
94
- "mistral:codestral-latest": { inputPer1M: 0.3, outputPer1M: 0.9, version: MS },
95
- "mistral:open-mistral-nemo": { inputPer1M: 0.15, outputPer1M: 0.15, version: MS },
84
+ "mistral:mistral-large-latest": { inputPer1M: 0.5, cacheReadPer1M: 0.05, outputPer1M: 1.5, version: MS },
85
+ "mistral:mistral-large-2512": { inputPer1M: 0.5, cacheReadPer1M: 0.05, outputPer1M: 1.5, version: MS },
86
+ "mistral:mistral-medium-latest": { inputPer1M: 1.5, cacheReadPer1M: 0.15, outputPer1M: 7.5, version: MS },
87
+ "mistral:mistral-medium-3.5": { inputPer1M: 1.5, cacheReadPer1M: 0.15, outputPer1M: 7.5, version: MS },
88
+ "mistral:mistral-medium-3": { inputPer1M: 0.4, cacheReadPer1M: 0.04, outputPer1M: 2, version: "2026-06-04-or-xref" },
89
+ "mistral:mistral-small-latest": { inputPer1M: 0.1, cacheReadPer1M: 0.01, outputPer1M: 0.3, version: MS },
90
+ "mistral:mistral-small-2603": { inputPer1M: 0.1, cacheReadPer1M: 0.01, outputPer1M: 0.3, version: MS },
91
+ "mistral:ministral-3b-latest": { inputPer1M: 0.1, cacheReadPer1M: 0.01, outputPer1M: 0.1, version: MS },
92
+ "mistral:ministral-8b-latest": { inputPer1M: 0.15, cacheReadPer1M: 0.015, outputPer1M: 0.15, version: MS },
93
+ "mistral:ministral-14b-latest": { inputPer1M: 0.2, cacheReadPer1M: 0.02, outputPer1M: 0.2, version: MS },
94
+ "mistral:magistral-medium-latest": { inputPer1M: 2, cacheReadPer1M: 0.2, outputPer1M: 5, version: MS },
95
+ "mistral:magistral-small-latest": { inputPer1M: 0.5, cacheReadPer1M: 0.05, outputPer1M: 1.5, version: MS },
96
+ "mistral:devstral-latest": { inputPer1M: 0.4, cacheReadPer1M: 0.04, outputPer1M: 2, version: MS },
97
+ "mistral:codestral-latest": { inputPer1M: 0.3, cacheReadPer1M: 0.03, outputPer1M: 0.9, version: MS },
98
+ "mistral:open-mistral-nemo": { inputPer1M: 0.15, cacheReadPer1M: 0.015, outputPer1M: 0.15, version: MS },
96
99
  // Moderation (F016.4) — per input token; output 0. (OCR is per-page in the adapter.)
97
- "mistral:mistral-moderation-latest": { inputPer1M: 0.1, outputPer1M: 0, version: MS },
100
+ "mistral:mistral-moderation-latest": { inputPer1M: 0.1, cacheReadPer1M: 0.01, outputPer1M: 0, version: MS },
98
101
  // Embeddings (F016.5) — per input token.
99
- "mistral:mistral-embed": { inputPer1M: 0.1, outputPer1M: 0, version: MS },
100
- "mistral:codestral-embed": { inputPer1M: 0.15, outputPer1M: 0, version: MS }
102
+ "mistral:mistral-embed": { inputPer1M: 0.1, cacheReadPer1M: 0.01, outputPer1M: 0, version: MS },
103
+ "mistral:codestral-embed": { inputPer1M: 0.15, cacheReadPer1M: 0.015, outputPer1M: 0, version: MS }
101
104
  };
102
105
  function getPrice(provider, model) {
103
106
  const exact = PRICING[`${provider}:${model}`];
@@ -111,4 +114,4 @@ export {
111
114
  PRICING,
112
115
  getPrice
113
116
  };
114
- //# sourceMappingURL=chunk-LUPUAAHZ.js.map
117
+ //# sourceMappingURL=chunk-LKVCPMVI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cost/pricing.ts"],"sourcesContent":["// Versioned per-(provider, model) pricing. F3.6 populates the table + adds tests\n// + MiniMax coverage. F3.1 ships the type + lookup with an empty table, so\n// computeCost returns 0 for every model until F3.6 lands (calls still complete).\nexport interface PricingEntry {\n /** USD per 1M input tokens. */\n inputPer1M: number;\n /** USD per 1M output tokens. */\n outputPer1M: number;\n /** USD per 1M cache-read tokens (falls back to input rate if unset). */\n cacheReadPer1M?: number;\n /** USD per 1M cache-write/creation tokens (falls back to input rate if unset). */\n cacheWritePer1M?: number;\n /** Pricing snapshot version (date or tag) so stale entries are detectable. */\n version: string;\n}\n\n// USD per 1M tokens. Anthropic cache multipliers follow the standard model:\n// cache-read ≈ 0.1× input, cache-write ≈ 1.25× input. Verified against the\n// pricing tables in cms (packages/cms-ai/src/providers) + trail (model-lab).\n// MiniMax M2.7 is an estimate pending confirmation against OpenRouter's live\n// price page — flagged in its version string.\nconst V = \"2026-06-02\";\n// Mistral prices come straight from mistral.ai/pricing (per Christian's CD report).\nconst MS = \"2026-06-04-mistral.ai\";\n\n/** Keyed `${provider}:${model}`. Exported so the catalogue-research job (F014)\n * can enumerate every priced entry and diff it against the live provider lists. */\nexport const PRICING: Record<string, PricingEntry> = {\n // Anthropic (direct API). DEFAULT_TIER_MAP: fast/cheap=haiku, smart/vision=sonnet, powerful=opus.\n \"anthropic:claude-haiku-4-5\": {\n inputPer1M: 0.8,\n outputPer1M: 4.0,\n cacheReadPer1M: 0.08,\n cacheWritePer1M: 1.0,\n version: V,\n },\n \"anthropic:claude-sonnet-4-6\": {\n inputPer1M: 3.0,\n outputPer1M: 15.0,\n cacheReadPer1M: 0.3,\n cacheWritePer1M: 3.75,\n version: V,\n },\n \"anthropic:claude-opus-4-8\": {\n inputPer1M: 15.0,\n outputPer1M: 75.0,\n cacheReadPer1M: 1.5,\n cacheWritePer1M: 18.75,\n version: V,\n },\n\n // OpenAI. embedding default tier = text-embedding-3-small (no output tokens).\n \"openai:text-embedding-3-small\": { inputPer1M: 0.02, outputPer1M: 0, version: V },\n \"openai:text-embedding-3-large\": { inputPer1M: 0.13, outputPer1M: 0, version: V },\n \"openai:gpt-4o\": { inputPer1M: 2.5, outputPer1M: 10.0, version: V },\n \"openai:gpt-4o-mini\": { inputPer1M: 0.15, outputPer1M: 0.6, version: V },\n // Whisper is priced per minute, not per token — not representable here; transcribe\n // (F5.6) computes its own cost. Listed as 0 so token-based compute never charges it.\n \"openai:whisper-1\": { inputPer1M: 0, outputPer1M: 0, version: V },\n\n // OpenRouter (meta-router — model slugs include the upstream vendor). Slugs use\n // dots (claude-sonnet-4.6) to match OpenRouter's live ids; the dashed forms\n // never matched a real call. Caught by the F014 catalogue research.\n \"openrouter:anthropic/claude-sonnet-4.6\": { inputPer1M: 3.0, outputPer1M: 15.0, version: V },\n // OpenRouter ground-truth $1/$5 — a markup over Anthropic-direct's $0.8/$4\n // (the `anthropic:` entry above). Was masked while the slug used dashes.\n \"openrouter:anthropic/claude-haiku-4.5\": { inputPer1M: 1.0, outputPer1M: 5.0, version: \"2026-06-04\" },\n \"openrouter:google/gemini-2.5-flash\": { inputPer1M: 0.3, outputPer1M: 2.5, version: V },\n // Ground-truth from OpenRouter /api/v1/models (was a 0.3 estimate; now 0.279).\n \"openrouter:minimax/minimax-m2.7\": {\n inputPer1M: 0.279,\n outputPer1M: 1.2,\n version: \"2026-06-04\",\n },\n // DeepSeek V4 (CN-hosted — NOT GDPR-safe; non-personal-data workloads only).\n // On 2026-05-22 DeepSeek made the \"75% off\" promo the permanent official price.\n // V4-Pro $0.435/$0.87 is ~34x cheaper than GPT-5.5 on output; flash is cheaper\n // still. Numbers match OpenRouter /api/v1/models 1:1 (no router markup). A strong\n // cheap route for fleet background work once `claude -p` is API-billed (15 Jun).\n \"openrouter:deepseek/deepseek-v4-pro\": { inputPer1M: 0.435, outputPer1M: 0.87, version: \"2026-05-22-deepseek-official\" },\n \"openrouter:deepseek/deepseek-v4-flash\": { inputPer1M: 0.0983, outputPer1M: 0.1966, version: \"2026-05-22-deepseek-official\" },\n // DeepSeek DIRECT API (provider \"deepseek\", F030 non-PII secondary). Rates from\n // api-docs.deepseek.com 2026-06-30 ($0.14/$0.28 per 1M; both map to deepseek-v4-flash).\n // `deepseek-chat` (non-thinking) + `deepseek-reasoner` (thinking) DEPRECATE 2026-07-24.\n // (The bare `deepseek-v4-flash` basename is already priced via the openrouter entry\n // above — kept distinct here to avoid a basename collision in the F027 pricing-API.)\n // Verify against a real key when it lands.\n \"deepseek:deepseek-chat\": { inputPer1M: 0.14, outputPer1M: 0.28, version: \"2026-06-30-deepseek-direct\" },\n \"deepseek:deepseek-reasoner\": { inputPer1M: 0.14, outputPer1M: 0.28, version: \"2026-06-30-deepseek-direct\" },\n\n // Google Gemini (direct). Provider key is \"gemini\" — matches the adapter's\n // usage.provider + the override.provider callers pass. (Image-gen models are\n // priced per-image in the adapter, not here.)\n \"gemini:gemini-2.5-flash\": { inputPer1M: 0.3, outputPer1M: 2.5, version: V },\n // flash-lite is the default `video` tier (F019) — cheap native video understanding.\n \"gemini:gemini-2.5-flash-lite\": { inputPer1M: 0.1, outputPer1M: 0.4, version: \"2026-06-04-or-xref\" },\n\n // Vertex AI (F038) — the EU-resident route to the SAME Gemini models, so Google's\n // published Gemini token prices apply. Listed separately because cost lookups key on\n // `provider:model`: without these rows an EU vision/video call would silently log\n // $0, which is worse than no tracking (a confident wrong number).\n \"vertex:gemini-2.5-flash\": { inputPer1M: 0.3, outputPer1M: 2.5, version: V },\n \"vertex:gemini-2.5-flash-lite\": { inputPer1M: 0.1, outputPer1M: 0.4, version: \"2026-06-04-or-xref\" },\n\n // Cached prompt tokens bill at 10% of the input rate (F039, measured 2026-08-27:\n // an 8,810-token prefix reported 8,784 cached on the second call WITH a\n // prompt_cache_key, and 0 without one at every size up to 57k).\n // Mistral (direct, La Plateforme). Official prices from mistral.ai/pricing\n // (2026-06-04, per Christian's CD report). EU/Paris-hosted — the designated\n // GDPR-safe provider for client/personal-data workloads (see F015). NB:\n // medium-3.5 is the premium \"Vibe\" coding tier ($1.5/$7.5); Large 3 ($0.5/$1.5)\n // is the cheaper frontier general-purpose model despite the higher number.\n \"mistral:mistral-large-latest\": { inputPer1M: 0.5, cacheReadPer1M: 0.05, outputPer1M: 1.5, version: MS },\n \"mistral:mistral-large-2512\": { inputPer1M: 0.5, cacheReadPer1M: 0.05, outputPer1M: 1.5, version: MS },\n \"mistral:mistral-medium-latest\": { inputPer1M: 1.5, cacheReadPer1M: 0.15, outputPer1M: 7.5, version: MS },\n \"mistral:mistral-medium-3.5\": { inputPer1M: 1.5, cacheReadPer1M: 0.15, outputPer1M: 7.5, version: MS },\n \"mistral:mistral-medium-3\": { inputPer1M: 0.4, cacheReadPer1M: 0.04, outputPer1M: 2.0, version: \"2026-06-04-or-xref\" },\n \"mistral:mistral-small-latest\": { inputPer1M: 0.1, cacheReadPer1M: 0.01, outputPer1M: 0.3, version: MS },\n \"mistral:mistral-small-2603\": { inputPer1M: 0.1, cacheReadPer1M: 0.01, outputPer1M: 0.3, version: MS },\n \"mistral:ministral-3b-latest\": { inputPer1M: 0.1, cacheReadPer1M: 0.01, outputPer1M: 0.1, version: MS },\n \"mistral:ministral-8b-latest\": { inputPer1M: 0.15, cacheReadPer1M: 0.015, outputPer1M: 0.15, version: MS },\n \"mistral:ministral-14b-latest\": { inputPer1M: 0.2, cacheReadPer1M: 0.02, outputPer1M: 0.2, version: MS },\n \"mistral:magistral-medium-latest\": { inputPer1M: 2.0, cacheReadPer1M: 0.2, outputPer1M: 5.0, version: MS },\n \"mistral:magistral-small-latest\": { inputPer1M: 0.5, cacheReadPer1M: 0.05, outputPer1M: 1.5, version: MS },\n \"mistral:devstral-latest\": { inputPer1M: 0.4, cacheReadPer1M: 0.04, outputPer1M: 2.0, version: MS },\n \"mistral:codestral-latest\": { inputPer1M: 0.3, cacheReadPer1M: 0.03, outputPer1M: 0.9, version: MS },\n \"mistral:open-mistral-nemo\": { inputPer1M: 0.15, cacheReadPer1M: 0.015, outputPer1M: 0.15, version: MS },\n // Moderation (F016.4) — per input token; output 0. (OCR is per-page in the adapter.)\n \"mistral:mistral-moderation-latest\": { inputPer1M: 0.1, cacheReadPer1M: 0.01, outputPer1M: 0, version: MS },\n // Embeddings (F016.5) — per input token.\n \"mistral:mistral-embed\": { inputPer1M: 0.1, cacheReadPer1M: 0.01, outputPer1M: 0, version: MS },\n \"mistral:codestral-embed\": { inputPer1M: 0.15, cacheReadPer1M: 0.015, outputPer1M: 0, version: MS },\n};\n\nexport function getPrice(provider: string, model: string): PricingEntry | undefined {\n const exact = PRICING[`${provider}:${model}`];\n if (exact) return exact;\n // Providers ship dated model snapshots, e.g. \"claude-haiku-4-5-20251001\".\n // Strip a trailing -YYYYMMDD and retry the base lookup so a dated variant\n // prices the same as its base model instead of falling through to 0 — a real\n // paid call must never be logged as $0 (F012). Covers openrouter slugs too.\n const base = model.replace(/-\\d{8}$/, \"\");\n if (base !== model) return PRICING[`${provider}:${base}`];\n return undefined;\n}\n"],"mappings":";AAqBA,IAAM,IAAI;AAEV,IAAM,KAAK;AAIJ,IAAM,UAAwC;AAAA;AAAA,EAEnD,8BAA8B;AAAA,IAC5B,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,SAAS;AAAA,EACX;AAAA,EACA,+BAA+B;AAAA,IAC7B,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,SAAS;AAAA,EACX;AAAA,EACA,6BAA6B;AAAA,IAC3B,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,SAAS;AAAA,EACX;AAAA;AAAA,EAGA,iCAAiC,EAAE,YAAY,MAAM,aAAa,GAAG,SAAS,EAAE;AAAA,EAChF,iCAAiC,EAAE,YAAY,MAAM,aAAa,GAAG,SAAS,EAAE;AAAA,EAChF,iBAAiB,EAAE,YAAY,KAAK,aAAa,IAAM,SAAS,EAAE;AAAA,EAClE,sBAAsB,EAAE,YAAY,MAAM,aAAa,KAAK,SAAS,EAAE;AAAA;AAAA;AAAA,EAGvE,oBAAoB,EAAE,YAAY,GAAG,aAAa,GAAG,SAAS,EAAE;AAAA;AAAA;AAAA;AAAA,EAKhE,0CAA0C,EAAE,YAAY,GAAK,aAAa,IAAM,SAAS,EAAE;AAAA;AAAA;AAAA,EAG3F,yCAAyC,EAAE,YAAY,GAAK,aAAa,GAAK,SAAS,aAAa;AAAA,EACpG,sCAAsC,EAAE,YAAY,KAAK,aAAa,KAAK,SAAS,EAAE;AAAA;AAAA,EAEtF,mCAAmC;AAAA,IACjC,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,uCAAuC,EAAE,YAAY,OAAO,aAAa,MAAM,SAAS,+BAA+B;AAAA,EACvH,yCAAyC,EAAE,YAAY,QAAQ,aAAa,QAAQ,SAAS,+BAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO5H,0BAA0B,EAAE,YAAY,MAAM,aAAa,MAAM,SAAS,6BAA6B;AAAA,EACvG,8BAA8B,EAAE,YAAY,MAAM,aAAa,MAAM,SAAS,6BAA6B;AAAA;AAAA;AAAA;AAAA,EAK3G,2BAA2B,EAAE,YAAY,KAAK,aAAa,KAAK,SAAS,EAAE;AAAA;AAAA,EAE3E,gCAAgC,EAAE,YAAY,KAAK,aAAa,KAAK,SAAS,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMnG,2BAA2B,EAAE,YAAY,KAAK,aAAa,KAAK,SAAS,EAAE;AAAA,EAC3E,gCAAgC,EAAE,YAAY,KAAK,aAAa,KAAK,SAAS,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUnG,gCAAgC,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,KAAK,SAAS,GAAG;AAAA,EACvG,8BAA8B,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,KAAK,SAAS,GAAG;AAAA,EACrG,iCAAiC,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,KAAK,SAAS,GAAG;AAAA,EACxG,8BAA8B,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,KAAK,SAAS,GAAG;AAAA,EACrG,4BAA4B,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,GAAK,SAAS,qBAAqB;AAAA,EACrH,gCAAgC,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,KAAK,SAAS,GAAG;AAAA,EACvG,8BAA8B,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,KAAK,SAAS,GAAG;AAAA,EACrG,+BAA+B,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,KAAK,SAAS,GAAG;AAAA,EACtG,+BAA+B,EAAE,YAAY,MAAM,gBAAgB,OAAO,aAAa,MAAM,SAAS,GAAG;AAAA,EACzG,gCAAgC,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,KAAK,SAAS,GAAG;AAAA,EACvG,mCAAmC,EAAE,YAAY,GAAK,gBAAgB,KAAK,aAAa,GAAK,SAAS,GAAG;AAAA,EACzG,kCAAkC,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,KAAK,SAAS,GAAG;AAAA,EACzG,2BAA2B,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,GAAK,SAAS,GAAG;AAAA,EAClG,4BAA4B,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,KAAK,SAAS,GAAG;AAAA,EACnG,6BAA6B,EAAE,YAAY,MAAM,gBAAgB,OAAO,aAAa,MAAM,SAAS,GAAG;AAAA;AAAA,EAEvG,qCAAqC,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,GAAG,SAAS,GAAG;AAAA;AAAA,EAE1G,yBAAyB,EAAE,YAAY,KAAK,gBAAgB,MAAM,aAAa,GAAG,SAAS,GAAG;AAAA,EAC9F,2BAA2B,EAAE,YAAY,MAAM,gBAAgB,OAAO,aAAa,GAAG,SAAS,GAAG;AACpG;AAEO,SAAS,SAAS,UAAkB,OAAyC;AAClF,QAAM,QAAQ,QAAQ,GAAG,QAAQ,IAAI,KAAK,EAAE;AAC5C,MAAI,MAAO,QAAO;AAKlB,QAAM,OAAO,MAAM,QAAQ,WAAW,EAAE;AACxC,MAAI,SAAS,MAAO,QAAO,QAAQ,GAAG,QAAQ,IAAI,IAAI,EAAE;AACxD,SAAO;AACT;","names":[]}
package/dist/index.d.ts CHANGED
@@ -117,6 +117,19 @@ interface ChatRequest {
117
117
  spec: TierSpec;
118
118
  tools?: Tool[];
119
119
  maxTokens?: number;
120
+ /** F039 — Mistral prompt caching. A stable application-level id for "the same
121
+ * conversation" (a conversation id, a session id). Requests sharing a prefix AND
122
+ * this key reuse the cached prefix at 10% of the input rate. Not auto-generated:
123
+ * only the caller knows what "the same conversation" means, and an SDK-invented
124
+ * key would either collide across tenants or never hit.
125
+ *
126
+ * BIND IT TO THE TENANT, not only to the conversation. This key IS a shared-prefix
127
+ * identity: two callers passing the same key can be served each other's cached
128
+ * prefix. So two tenants with identical transcripts must still get DIFFERENT keys
129
+ * — derive it from (tenant, conversation), never from the conversation alone.
130
+ * (components' requirement while building @broberg/chat, 2026-08-27, where two
131
+ * knowledge bases are written for readers with different permissions.) */
132
+ promptCacheKey?: string;
120
133
  temperature?: number;
121
134
  /** "json" → request JSON-object output where the provider supports it (F009). */
122
135
  responseFormat?: "json" | "text";
@@ -595,6 +608,11 @@ declare const chatInputSchema: z.ZodObject<{
595
608
  }>]>, "many">>;
596
609
  purpose: z.ZodOptional<z.ZodString>;
597
610
  labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
611
+ /** F039 — reuse a cached prompt prefix on Mistral at 10% of the input rate.
612
+ * A stable id for "the same conversation" (conversation id, session id).
613
+ * Derive it from (tenant, conversation): the key is a shared-prefix identity,
614
+ * so two tenants with identical transcripts must get different keys. */
615
+ promptCacheKey: z.ZodOptional<z.ZodString>;
598
616
  prompt: z.ZodOptional<z.ZodString>;
599
617
  messages: z.ZodOptional<z.ZodArray<z.ZodObject<{
600
618
  role: z.ZodEnum<["system", "user", "assistant", "tool"]>;
@@ -713,6 +731,7 @@ declare const chatInputSchema: z.ZodObject<{
713
731
  }[] | undefined;
714
732
  temperature?: number | undefined;
715
733
  purpose?: string | undefined;
734
+ promptCacheKey?: string | undefined;
716
735
  maxTokens?: number | undefined;
717
736
  responseFormat?: "text" | "json" | undefined;
718
737
  override?: {
@@ -754,6 +773,7 @@ declare const chatInputSchema: z.ZodObject<{
754
773
  }[] | undefined;
755
774
  temperature?: number | undefined;
756
775
  purpose?: string | undefined;
776
+ promptCacheKey?: string | undefined;
757
777
  maxTokens?: number | undefined;
758
778
  responseFormat?: "text" | "json" | undefined;
759
779
  override?: {
@@ -2061,8 +2081,8 @@ declare const falStubAdapter: ProviderAdapter;
2061
2081
  * wires the live adapters. */
2062
2082
  declare const stubProviders: Record<string, ProviderAdapter>;
2063
2083
 
2064
- declare const VERSION: "0.29.0";
2065
- declare const SDK_TAG: "@broberg/ai-sdk@0.29.0";
2084
+ declare const VERSION: "0.30.1";
2085
+ declare const SDK_TAG: "@broberg/ai-sdk@0.30.1";
2066
2086
 
2067
2087
  /** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
2068
2088
  * per-call override.
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-V2PD522L.js";
11
11
  import {
12
12
  getPrice
13
- } from "./chunk-LUPUAAHZ.js";
13
+ } from "./chunk-LKVCPMVI.js";
14
14
 
15
15
  // src/transport/http.ts
16
16
  async function httpTransport(req) {
@@ -523,6 +523,7 @@ function makeOpenAICompatibleAdapter(config) {
523
523
  if (req.maxTokens !== void 0) body.max_tokens = req.maxTokens;
524
524
  if (req.temperature !== void 0) body.temperature = req.temperature;
525
525
  if (req.responseFormat === "json") body.response_format = { type: "json_object" };
526
+ if (req.promptCacheKey !== void 0) body.prompt_cache_key = req.promptCacheKey;
526
527
  if (config.costFromResponseField) body.usage = { include: true };
527
528
  const res = await httpTransport({
528
529
  spec: req.spec,
@@ -545,13 +546,19 @@ function makeOpenAICompatibleAdapter(config) {
545
546
  const toolCalls = msg?.tool_calls?.map(
546
547
  (tc) => fromProviderToolCall(tc, "openai")
547
548
  );
549
+ const cachedIn = data.usage?.prompt_tokens_details?.cached_tokens;
548
550
  const usage = freshUsage({
549
551
  provider: config.name,
550
552
  model: req.spec.model,
551
553
  transport: "http",
552
554
  capability: "chat",
553
- inputTokens: data.usage?.prompt_tokens ?? 0,
554
- outputTokens: data.usage?.completion_tokens ?? 0
555
+ // prompt_tokens INCLUDES the cached ones; computeCost adds cacheReadTokens on
556
+ // top of inputTokens, so billing the raw figure would charge the cached prefix
557
+ // twice — at full rate AND at the cache rate.
558
+ inputTokens: (data.usage?.prompt_tokens ?? 0) - (cachedIn ?? 0),
559
+ outputTokens: data.usage?.completion_tokens ?? 0,
560
+ // Absent field stays undefined: "not reported" is not the same as "zero cached".
561
+ ...cachedIn === void 0 ? {} : { cacheReadTokens: cachedIn }
555
562
  });
556
563
  if (config.costFromResponseField && typeof data.usage?.cost === "number") {
557
564
  usage.costUsd = data.usage.cost;
@@ -2619,6 +2626,11 @@ var callOptions = {
2619
2626
  labels: z.record(z.string(), z.string()).optional()
2620
2627
  };
2621
2628
  var chatInputSchema = z.object({
2629
+ /** F039 — reuse a cached prompt prefix on Mistral at 10% of the input rate.
2630
+ * A stable id for "the same conversation" (conversation id, session id).
2631
+ * Derive it from (tenant, conversation): the key is a shared-prefix identity,
2632
+ * so two tenants with identical transcripts must get different keys. */
2633
+ promptCacheKey: z.string().optional(),
2622
2634
  prompt: z.string().optional(),
2623
2635
  messages: z.array(messageSchema).optional(),
2624
2636
  system: z.string().optional(),
@@ -2780,8 +2792,8 @@ var aiConfigSchema = z.object({
2780
2792
  });
2781
2793
 
2782
2794
  // src/version.ts
2783
- var VERSION = "0.29.0";
2784
- var SDK_TAG = "@broberg/ai-sdk@0.29.0";
2795
+ var VERSION = "0.30.1";
2796
+ var SDK_TAG = "@broberg/ai-sdk@0.30.1";
2785
2797
 
2786
2798
  // src/cost/sinks/upmetrics.ts
2787
2799
  function upmetricsSink(config) {
@@ -3065,7 +3077,7 @@ function createAI(config = {}) {
3065
3077
  invoke: async (spec) => {
3066
3078
  const adapter = pickProvider(spec.provider);
3067
3079
  if (!adapter.chat) throw new Error(`createAI: provider "${spec.provider}" does not support chat`);
3068
- return adapter.chat({ messages, spec, tools: input.tools, maxTokens: input.maxTokens, temperature: input.temperature, responseFormat: input.responseFormat });
3080
+ return adapter.chat({ messages, spec, tools: input.tools, maxTokens: input.maxTokens, temperature: input.temperature, responseFormat: input.responseFormat, promptCacheKey: input.promptCacheKey });
3069
3081
  }
3070
3082
  });
3071
3083
  },