@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.
@@ -79,6 +79,9 @@ async function* streamFromOpenAI(client, req, options) {
79
79
  if (req.cacheKey && options.includeCacheKey !== false) {
80
80
  body.prompt_cache_key = req.cacheKey;
81
81
  }
82
+ if (req.cacheKey && options.openRouterAutoCache && /^~?anthropic\//.test(req.model)) {
83
+ body.cache_control = { type: "ephemeral" };
84
+ }
82
85
  const effectiveMaxTokens = req.maxTokens ?? options.defaultMaxTokens;
83
86
  if (effectiveMaxTokens !== void 0) {
84
87
  const param = options.tokensParam ?? (needsMaxCompletionTokens(req.model) ? "max_completion_tokens" : "max_tokens");
@@ -132,12 +135,20 @@ async function* streamFromOpenAI(client, req, options) {
132
135
  throw new Error(`OpenAI-compatible stream returned an error: ${message}`);
133
136
  }
134
137
  if (chunk.usage) {
135
- const cachedTokens = chunk.usage.prompt_tokens_details?.cached_tokens;
138
+ const details = chunk.usage.prompt_tokens_details;
139
+ const cachedTokens = details?.cached_tokens;
140
+ const cacheWriteTokens = details?.cache_write_tokens;
136
141
  usage = {
137
- ...chunk.usage.prompt_tokens !== void 0 ? { inputTokens: chunk.usage.prompt_tokens - (cachedTokens ?? 0) } : {},
142
+ ...chunk.usage.prompt_tokens !== void 0 ? {
143
+ inputTokens: Math.max(
144
+ 0,
145
+ chunk.usage.prompt_tokens - (cachedTokens ?? 0) - (cacheWriteTokens ?? 0)
146
+ )
147
+ } : {},
138
148
  ...chunk.usage.completion_tokens !== void 0 ? { outputTokens: chunk.usage.completion_tokens } : {},
139
149
  ...chunk.usage.total_tokens !== void 0 ? { totalTokens: chunk.usage.total_tokens } : {},
140
- ...cachedTokens !== void 0 ? { cacheReadTokens: cachedTokens } : {}
150
+ ...cachedTokens !== void 0 ? { cacheReadTokens: cachedTokens } : {},
151
+ ...cacheWriteTokens !== void 0 ? { cacheWriteTokens } : {}
141
152
  };
142
153
  }
143
154
  const choice = chunk.choices?.[0];
@@ -503,10 +514,13 @@ var OpenAIAdapter = class {
503
514
  vendor = openAIManifest.vendor;
504
515
  acceptedAuth = ["apiKey"];
505
516
  client;
517
+ /** baseURL is OpenRouter: enables its automatic prompt caching for Anthropic models. */
518
+ isOpenRouter = false;
506
519
  init(auth, client) {
507
520
  if (!auth.apiKey) {
508
521
  throw new Error("OpenAIAdapter: apiKey is required");
509
522
  }
523
+ this.isOpenRouter = /(^|\/\/|\.)openrouter\.ai(\/|:|$)/i.test(auth.baseURL ?? "");
510
524
  this.client = new OpenAI({
511
525
  apiKey: auth.apiKey,
512
526
  ...auth.baseURL ? { baseURL: auth.baseURL } : {},
@@ -518,7 +532,8 @@ var OpenAIAdapter = class {
518
532
  return streamFromOpenAI(this.ensureClient(), req, {
519
533
  knownModels: this.knownModels(),
520
534
  vendorMetadataExtractor: OPENAI_METADATA_EXTRACTOR,
521
- includeCacheKey: this.forwardCacheKey()
535
+ includeCacheKey: this.forwardCacheKey(),
536
+ openRouterAutoCache: this.isOpenRouter
522
537
  });
523
538
  }
524
539
  appendAssistantToolCall(history, toolCalls, assistantText) {