@jambonz/llm 0.4.6 → 0.5.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.
@@ -118,8 +118,17 @@ async function* streamFromOpenAI(client, req, options) {
118
118
  body[param] = effectiveMaxTokens;
119
119
  }
120
120
  let stream;
121
+ let responseHeaders;
121
122
  try {
122
- stream = await client.chat.completions.create(body, { signal: req.signal });
123
+ const apiPromise = client.chat.completions.create(body, { signal: req.signal });
124
+ const maybeWithResponse = apiPromise.withResponse;
125
+ if (typeof maybeWithResponse === "function") {
126
+ const result = await maybeWithResponse.call(apiPromise);
127
+ stream = result.data;
128
+ responseHeaders = result.response?.headers;
129
+ } else {
130
+ stream = await apiPromise;
131
+ }
123
132
  } catch (err) {
124
133
  if (isAbortError(err)) {
125
134
  yield { type: "end", finishReason: "aborted" };
@@ -214,6 +223,12 @@ async function* streamFromOpenAI(client, req, options) {
214
223
  ...usage ? { usage } : {},
215
224
  ...finalRawReason ? { rawReason: finalRawReason } : {}
216
225
  };
226
+ if (options.vendorMetadataExtractor && responseHeaders) {
227
+ const metadata = options.vendorMetadataExtractor(responseHeaders);
228
+ if (metadata && Object.keys(metadata).length > 0) {
229
+ endEvent.vendorMetadata = metadata;
230
+ }
231
+ }
217
232
  yield endEvent;
218
233
  }
219
234
  function appendOpenAIAssistantToolCall(history, toolCalls) {
@@ -341,6 +356,40 @@ function isAbortError(err) {
341
356
  return e.name === "APIUserAbortError" || e.name === "AbortError" || e.code === "ABORT_ERR" || typeof e.message === "string" && /aborted/i.test(e.message);
342
357
  }
343
358
 
359
+ // src/adapters/_metadata.ts
360
+ function makeMetadataExtractor(fields) {
361
+ return (headers) => {
362
+ const out = {};
363
+ for (const f of fields) {
364
+ const raw = headers.get(f.header);
365
+ if (raw === null || raw === void 0 || raw === "") continue;
366
+ if (f.numeric) {
367
+ const n = Number(raw);
368
+ if (Number.isFinite(n)) out[f.key] = n;
369
+ } else {
370
+ out[f.key] = raw;
371
+ }
372
+ }
373
+ return out;
374
+ };
375
+ }
376
+ function extractMetadata(fields, headers) {
377
+ const headersInstance = headers instanceof Headers ? headers : recordToHeaders(headers);
378
+ return makeMetadataExtractor(fields)(headersInstance);
379
+ }
380
+ function recordToHeaders(record) {
381
+ const h = new Headers();
382
+ for (const [name, value] of Object.entries(record)) {
383
+ if (value === void 0) continue;
384
+ if (Array.isArray(value)) {
385
+ for (const v of value) h.append(name, v);
386
+ } else {
387
+ h.set(name, value);
388
+ }
389
+ }
390
+ return h;
391
+ }
392
+
344
393
  // src/adapters/openai/manifest.ts
345
394
  var OPENAI_KNOWN_MODELS = [
346
395
  {
@@ -442,6 +491,12 @@ var openAIManifest = {
442
491
  };
443
492
 
444
493
  // src/adapters/openai/adapter.ts
494
+ var OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
495
+ { header: "x-request-id", key: "request_id" },
496
+ { header: "openai-processing-ms", key: "processing_ms", numeric: true },
497
+ { header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
498
+ { header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
499
+ ]);
445
500
  var OpenAIAdapter = class {
446
501
  vendor = openAIManifest.vendor;
447
502
  acceptedAuth = ["apiKey"];
@@ -459,7 +514,8 @@ var OpenAIAdapter = class {
459
514
  }
460
515
  stream(req) {
461
516
  return streamFromOpenAI(this.ensureClient(), req, {
462
- knownModels: openAIManifest.knownModels
517
+ knownModels: openAIManifest.knownModels,
518
+ vendorMetadataExtractor: OPENAI_METADATA_EXTRACTOR
463
519
  });
464
520
  }
465
521
  appendAssistantToolCall(history, toolCalls) {
@@ -691,6 +747,12 @@ var anthropicManifest = {
691
747
  };
692
748
 
693
749
  // src/adapters/anthropic/adapter.ts
750
+ var ANTHROPIC_METADATA_EXTRACTOR = makeMetadataExtractor([
751
+ { header: "request-id", key: "request_id" },
752
+ { header: "anthropic-ratelimit-requests-remaining", key: "requests_remaining", numeric: true },
753
+ { header: "anthropic-ratelimit-input-tokens-remaining", key: "input_tokens_remaining", numeric: true },
754
+ { header: "anthropic-ratelimit-output-tokens-remaining", key: "output_tokens_remaining", numeric: true }
755
+ ]);
694
756
  var AnthropicAdapter = class {
695
757
  vendor = anthropicManifest.vendor;
696
758
  acceptedAuth = ["apiKey"];
@@ -725,11 +787,20 @@ var AnthropicAdapter = class {
725
787
  if (tools) body.tools = tools;
726
788
  if (req.temperature !== void 0) body.temperature = req.temperature;
727
789
  let stream;
790
+ let responseHeaders;
728
791
  try {
729
- stream = await client.messages.create(
792
+ const apiPromise = client.messages.create(
730
793
  body,
731
794
  { signal: req.signal }
732
795
  );
796
+ const maybeWithResponse = apiPromise.withResponse;
797
+ if (typeof maybeWithResponse === "function") {
798
+ const result = await maybeWithResponse.call(apiPromise);
799
+ stream = result.data;
800
+ responseHeaders = result.response?.headers;
801
+ } else {
802
+ stream = await apiPromise;
803
+ }
733
804
  } catch (err) {
734
805
  if (isAbortError2(err)) {
735
806
  yield { type: "end", finishReason: "aborted" };
@@ -840,6 +911,12 @@ var AnthropicAdapter = class {
840
911
  ...usage ? { usage } : {},
841
912
  ...stopReason ? { rawReason: stopReason } : {}
842
913
  };
914
+ if (responseHeaders) {
915
+ const metadata = ANTHROPIC_METADATA_EXTRACTOR(responseHeaders);
916
+ if (Object.keys(metadata).length > 0) {
917
+ endEvent.vendorMetadata = metadata;
918
+ }
919
+ }
843
920
  yield endEvent;
844
921
  }
845
922
  appendAssistantToolCall(history, toolCalls) {
@@ -1632,6 +1709,9 @@ var vertexOpenAIManifest = {
1632
1709
  };
1633
1710
 
1634
1711
  // src/adapters/vertex-openai/adapter.ts
1712
+ var VERTEX_OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
1713
+ { header: "x-request-id", key: "request_id" }
1714
+ ]);
1635
1715
  var VertexOpenAIAdapter = class {
1636
1716
  vendor = vertexOpenAIManifest.vendor;
1637
1717
  acceptedAuth = ["vertexServiceAccount"];
@@ -1684,7 +1764,8 @@ var VertexOpenAIAdapter = class {
1684
1764
  // endpoint predates `max_completion_tokens` and may not recognize it.
1685
1765
  // The model-id heuristic wouldn't catch a partner model named in the
1686
1766
  // OpenAI style (unlikely today, but defensive).
1687
- tokensParam: "max_tokens"
1767
+ tokensParam: "max_tokens",
1768
+ vendorMetadataExtractor: VERTEX_OPENAI_METADATA_EXTRACTOR
1688
1769
  });
1689
1770
  }
1690
1771
  appendAssistantToolCall(history, toolCalls) {
@@ -2142,6 +2223,21 @@ var BedrockAdapter = class {
2142
2223
  ...usage ? { usage } : {},
2143
2224
  ...stopReason ? { rawReason: stopReason } : {}
2144
2225
  };
2226
+ const httpHeaders = response.$metadata?.httpHeaders;
2227
+ if (httpHeaders) {
2228
+ const metadata = extractMetadata(
2229
+ [
2230
+ { header: "x-amzn-bedrock-invocation-latency", key: "invocation_latency_ms", numeric: true },
2231
+ { header: "x-amzn-bedrock-cache-read-input-token-count", key: "cache_read_input_tokens", numeric: true },
2232
+ { header: "x-amzn-bedrock-cache-write-input-token-count", key: "cache_write_input_tokens", numeric: true },
2233
+ { header: "x-amzn-bedrock-trace-id", key: "trace_id" }
2234
+ ],
2235
+ httpHeaders
2236
+ );
2237
+ if (Object.keys(metadata).length > 0) {
2238
+ endEvent.vendorMetadata = metadata;
2239
+ }
2240
+ }
2145
2241
  yield endEvent;
2146
2242
  }
2147
2243
  appendAssistantToolCall(history, toolCalls) {
@@ -2393,6 +2489,14 @@ var azureOpenAIManifest = {
2393
2489
  };
2394
2490
 
2395
2491
  // src/adapters/azure-openai/adapter.ts
2492
+ var AZURE_OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
2493
+ { header: "x-ms-region", key: "region" },
2494
+ { header: "x-ms-deployment-name", key: "deployment" },
2495
+ { header: "apim-request-id", key: "request_id" },
2496
+ { header: "azureml-model-session", key: "model_session" },
2497
+ { header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
2498
+ { header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
2499
+ ]);
2396
2500
  var AzureOpenAIAdapter = class {
2397
2501
  vendor = azureOpenAIManifest.vendor;
2398
2502
  acceptedAuth = ["azureOpenAIApiKey"];
@@ -2427,7 +2531,8 @@ var AzureOpenAIAdapter = class {
2427
2531
  stream(req) {
2428
2532
  return streamFromOpenAI(this.ensureClient(), req, {
2429
2533
  knownModels: azureOpenAIManifest.knownModels,
2430
- tokensParam: "max_completion_tokens"
2534
+ tokensParam: "max_completion_tokens",
2535
+ vendorMetadataExtractor: AZURE_OPENAI_METADATA_EXTRACTOR
2431
2536
  });
2432
2537
  }
2433
2538
  appendAssistantToolCall(history, toolCalls) {
@@ -2552,6 +2657,12 @@ var groqManifest = {
2552
2657
  };
2553
2658
 
2554
2659
  // src/adapters/groq/adapter.ts
2660
+ var GROQ_METADATA_EXTRACTOR = makeMetadataExtractor([
2661
+ { header: "x-request-id", key: "request_id" },
2662
+ { header: "x-groq-region", key: "region" },
2663
+ { header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
2664
+ { header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
2665
+ ]);
2555
2666
  var GroqAdapter = class extends OpenAIAdapter {
2556
2667
  vendor = groqManifest.vendor;
2557
2668
  init(auth, client) {
@@ -2563,6 +2674,12 @@ var GroqAdapter = class extends OpenAIAdapter {
2563
2674
  client
2564
2675
  );
2565
2676
  }
2677
+ stream(req) {
2678
+ return streamFromOpenAI(this.ensureClient(), req, {
2679
+ knownModels: groqManifest.knownModels,
2680
+ vendorMetadataExtractor: GROQ_METADATA_EXTRACTOR
2681
+ });
2682
+ }
2566
2683
  };
2567
2684
 
2568
2685
  // src/adapters/groq/factory.ts
@@ -2663,6 +2780,10 @@ var huggingfaceManifest = {
2663
2780
  };
2664
2781
 
2665
2782
  // src/adapters/huggingface/adapter.ts
2783
+ var HUGGINGFACE_METADATA_EXTRACTOR = makeMetadataExtractor([
2784
+ { header: "x-inference-provider", key: "provider" },
2785
+ { header: "x-request-id", key: "request_id" }
2786
+ ]);
2666
2787
  var HuggingfaceAdapter = class extends OpenAIAdapter {
2667
2788
  vendor = huggingfaceManifest.vendor;
2668
2789
  init(auth, client) {
@@ -2674,6 +2795,12 @@ var HuggingfaceAdapter = class extends OpenAIAdapter {
2674
2795
  client
2675
2796
  );
2676
2797
  }
2798
+ stream(req) {
2799
+ return streamFromOpenAI(this.ensureClient(), req, {
2800
+ knownModels: huggingfaceManifest.knownModels,
2801
+ vendorMetadataExtractor: HUGGINGFACE_METADATA_EXTRACTOR
2802
+ });
2803
+ }
2677
2804
  };
2678
2805
 
2679
2806
  // src/adapters/huggingface/factory.ts