@jambonz/llm 0.6.4 → 0.6.6

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.
@@ -118,6 +118,9 @@ async function* streamFromOpenAI(client, req, options) {
118
118
  if (req.cacheKey && options.includeCacheKey !== false) {
119
119
  body.prompt_cache_key = req.cacheKey;
120
120
  }
121
+ if (req.cacheKey && options.openRouterAutoCache && /^~?anthropic\//.test(req.model)) {
122
+ body.cache_control = { type: "ephemeral" };
123
+ }
121
124
  const effectiveMaxTokens = req.maxTokens ?? options.defaultMaxTokens;
122
125
  if (effectiveMaxTokens !== void 0) {
123
126
  const param = options.tokensParam ?? (needsMaxCompletionTokens(req.model) ? "max_completion_tokens" : "max_tokens");
@@ -171,12 +174,20 @@ async function* streamFromOpenAI(client, req, options) {
171
174
  throw new Error(`OpenAI-compatible stream returned an error: ${message}`);
172
175
  }
173
176
  if (chunk.usage) {
174
- const cachedTokens = chunk.usage.prompt_tokens_details?.cached_tokens;
177
+ const details = chunk.usage.prompt_tokens_details;
178
+ const cachedTokens = details?.cached_tokens;
179
+ const cacheWriteTokens = details?.cache_write_tokens;
175
180
  usage = {
176
- ...chunk.usage.prompt_tokens !== void 0 ? { inputTokens: chunk.usage.prompt_tokens - (cachedTokens ?? 0) } : {},
181
+ ...chunk.usage.prompt_tokens !== void 0 ? {
182
+ inputTokens: Math.max(
183
+ 0,
184
+ chunk.usage.prompt_tokens - (cachedTokens ?? 0) - (cacheWriteTokens ?? 0)
185
+ )
186
+ } : {},
177
187
  ...chunk.usage.completion_tokens !== void 0 ? { outputTokens: chunk.usage.completion_tokens } : {},
178
188
  ...chunk.usage.total_tokens !== void 0 ? { totalTokens: chunk.usage.total_tokens } : {},
179
- ...cachedTokens !== void 0 ? { cacheReadTokens: cachedTokens } : {}
189
+ ...cachedTokens !== void 0 ? { cacheReadTokens: cachedTokens } : {},
190
+ ...cacheWriteTokens !== void 0 ? { cacheWriteTokens } : {}
180
191
  };
181
192
  }
182
193
  const choice = chunk.choices?.[0];
@@ -542,10 +553,13 @@ var OpenAIAdapter = class {
542
553
  vendor = openAIManifest.vendor;
543
554
  acceptedAuth = ["apiKey"];
544
555
  client;
556
+ /** baseURL is OpenRouter: enables its automatic prompt caching for Anthropic models. */
557
+ isOpenRouter = false;
545
558
  init(auth, client) {
546
559
  if (!auth.apiKey) {
547
560
  throw new Error("OpenAIAdapter: apiKey is required");
548
561
  }
562
+ this.isOpenRouter = /(^|\/\/|\.)openrouter\.ai(\/|:|$)/i.test(auth.baseURL ?? "");
549
563
  this.client = new import_openai.default({
550
564
  apiKey: auth.apiKey,
551
565
  ...auth.baseURL ? { baseURL: auth.baseURL } : {},
@@ -557,7 +571,8 @@ var OpenAIAdapter = class {
557
571
  return streamFromOpenAI(this.ensureClient(), req, {
558
572
  knownModels: this.knownModels(),
559
573
  vendorMetadataExtractor: OPENAI_METADATA_EXTRACTOR,
560
- includeCacheKey: this.forwardCacheKey()
574
+ includeCacheKey: this.forwardCacheKey(),
575
+ openRouterAutoCache: this.isOpenRouter
561
576
  });
562
577
  }
563
578
  appendAssistantToolCall(history, toolCalls, assistantText) {