@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.
package/dist/index.cjs CHANGED
@@ -131,8 +131,17 @@ async function* streamFromOpenAI(client, req, options) {
131
131
  body[param] = effectiveMaxTokens;
132
132
  }
133
133
  let stream;
134
+ let responseHeaders;
134
135
  try {
135
- stream = await client.chat.completions.create(body, { signal: req.signal });
136
+ const apiPromise = client.chat.completions.create(body, { signal: req.signal });
137
+ const maybeWithResponse = apiPromise.withResponse;
138
+ if (typeof maybeWithResponse === "function") {
139
+ const result = await maybeWithResponse.call(apiPromise);
140
+ stream = result.data;
141
+ responseHeaders = result.response?.headers;
142
+ } else {
143
+ stream = await apiPromise;
144
+ }
136
145
  } catch (err) {
137
146
  if (isAbortError(err)) {
138
147
  yield { type: "end", finishReason: "aborted" };
@@ -227,6 +236,12 @@ async function* streamFromOpenAI(client, req, options) {
227
236
  ...usage ? { usage } : {},
228
237
  ...finalRawReason ? { rawReason: finalRawReason } : {}
229
238
  };
239
+ if (options.vendorMetadataExtractor && responseHeaders) {
240
+ const metadata = options.vendorMetadataExtractor(responseHeaders);
241
+ if (metadata && Object.keys(metadata).length > 0) {
242
+ endEvent.vendorMetadata = metadata;
243
+ }
244
+ }
230
245
  yield endEvent;
231
246
  }
232
247
  function appendOpenAIAssistantToolCall(history, toolCalls) {
@@ -354,6 +369,40 @@ function isAbortError(err) {
354
369
  return e.name === "APIUserAbortError" || e.name === "AbortError" || e.code === "ABORT_ERR" || typeof e.message === "string" && /aborted/i.test(e.message);
355
370
  }
356
371
 
372
+ // src/adapters/_metadata.ts
373
+ function makeMetadataExtractor(fields) {
374
+ return (headers) => {
375
+ const out = {};
376
+ for (const f of fields) {
377
+ const raw = headers.get(f.header);
378
+ if (raw === null || raw === void 0 || raw === "") continue;
379
+ if (f.numeric) {
380
+ const n = Number(raw);
381
+ if (Number.isFinite(n)) out[f.key] = n;
382
+ } else {
383
+ out[f.key] = raw;
384
+ }
385
+ }
386
+ return out;
387
+ };
388
+ }
389
+ function extractMetadata(fields, headers) {
390
+ const headersInstance = headers instanceof Headers ? headers : recordToHeaders(headers);
391
+ return makeMetadataExtractor(fields)(headersInstance);
392
+ }
393
+ function recordToHeaders(record) {
394
+ const h = new Headers();
395
+ for (const [name, value] of Object.entries(record)) {
396
+ if (value === void 0) continue;
397
+ if (Array.isArray(value)) {
398
+ for (const v of value) h.append(name, v);
399
+ } else {
400
+ h.set(name, value);
401
+ }
402
+ }
403
+ return h;
404
+ }
405
+
357
406
  // src/adapters/openai/manifest.ts
358
407
  var OPENAI_KNOWN_MODELS = [
359
408
  {
@@ -455,6 +504,12 @@ var openAIManifest = {
455
504
  };
456
505
 
457
506
  // src/adapters/openai/adapter.ts
507
+ var OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
508
+ { header: "x-request-id", key: "request_id" },
509
+ { header: "openai-processing-ms", key: "processing_ms", numeric: true },
510
+ { header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
511
+ { header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
512
+ ]);
458
513
  var OpenAIAdapter = class {
459
514
  vendor = openAIManifest.vendor;
460
515
  acceptedAuth = ["apiKey"];
@@ -472,7 +527,8 @@ var OpenAIAdapter = class {
472
527
  }
473
528
  stream(req) {
474
529
  return streamFromOpenAI(this.ensureClient(), req, {
475
- knownModels: openAIManifest.knownModels
530
+ knownModels: openAIManifest.knownModels,
531
+ vendorMetadataExtractor: OPENAI_METADATA_EXTRACTOR
476
532
  });
477
533
  }
478
534
  appendAssistantToolCall(history, toolCalls) {
@@ -704,6 +760,12 @@ var anthropicManifest = {
704
760
  };
705
761
 
706
762
  // src/adapters/anthropic/adapter.ts
763
+ var ANTHROPIC_METADATA_EXTRACTOR = makeMetadataExtractor([
764
+ { header: "request-id", key: "request_id" },
765
+ { header: "anthropic-ratelimit-requests-remaining", key: "requests_remaining", numeric: true },
766
+ { header: "anthropic-ratelimit-input-tokens-remaining", key: "input_tokens_remaining", numeric: true },
767
+ { header: "anthropic-ratelimit-output-tokens-remaining", key: "output_tokens_remaining", numeric: true }
768
+ ]);
707
769
  var AnthropicAdapter = class {
708
770
  vendor = anthropicManifest.vendor;
709
771
  acceptedAuth = ["apiKey"];
@@ -738,11 +800,20 @@ var AnthropicAdapter = class {
738
800
  if (tools) body.tools = tools;
739
801
  if (req.temperature !== void 0) body.temperature = req.temperature;
740
802
  let stream;
803
+ let responseHeaders;
741
804
  try {
742
- stream = await client.messages.create(
805
+ const apiPromise = client.messages.create(
743
806
  body,
744
807
  { signal: req.signal }
745
808
  );
809
+ const maybeWithResponse = apiPromise.withResponse;
810
+ if (typeof maybeWithResponse === "function") {
811
+ const result = await maybeWithResponse.call(apiPromise);
812
+ stream = result.data;
813
+ responseHeaders = result.response?.headers;
814
+ } else {
815
+ stream = await apiPromise;
816
+ }
746
817
  } catch (err) {
747
818
  if (isAbortError2(err)) {
748
819
  yield { type: "end", finishReason: "aborted" };
@@ -853,6 +924,12 @@ var AnthropicAdapter = class {
853
924
  ...usage ? { usage } : {},
854
925
  ...stopReason ? { rawReason: stopReason } : {}
855
926
  };
927
+ if (responseHeaders) {
928
+ const metadata = ANTHROPIC_METADATA_EXTRACTOR(responseHeaders);
929
+ if (Object.keys(metadata).length > 0) {
930
+ endEvent.vendorMetadata = metadata;
931
+ }
932
+ }
856
933
  yield endEvent;
857
934
  }
858
935
  appendAssistantToolCall(history, toolCalls) {
@@ -1645,6 +1722,9 @@ var vertexOpenAIManifest = {
1645
1722
  };
1646
1723
 
1647
1724
  // src/adapters/vertex-openai/adapter.ts
1725
+ var VERTEX_OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
1726
+ { header: "x-request-id", key: "request_id" }
1727
+ ]);
1648
1728
  var VertexOpenAIAdapter = class {
1649
1729
  vendor = vertexOpenAIManifest.vendor;
1650
1730
  acceptedAuth = ["vertexServiceAccount"];
@@ -1697,7 +1777,8 @@ var VertexOpenAIAdapter = class {
1697
1777
  // endpoint predates `max_completion_tokens` and may not recognize it.
1698
1778
  // The model-id heuristic wouldn't catch a partner model named in the
1699
1779
  // OpenAI style (unlikely today, but defensive).
1700
- tokensParam: "max_tokens"
1780
+ tokensParam: "max_tokens",
1781
+ vendorMetadataExtractor: VERTEX_OPENAI_METADATA_EXTRACTOR
1701
1782
  });
1702
1783
  }
1703
1784
  appendAssistantToolCall(history, toolCalls) {
@@ -2155,6 +2236,21 @@ var BedrockAdapter = class {
2155
2236
  ...usage ? { usage } : {},
2156
2237
  ...stopReason ? { rawReason: stopReason } : {}
2157
2238
  };
2239
+ const httpHeaders = response.$metadata?.httpHeaders;
2240
+ if (httpHeaders) {
2241
+ const metadata = extractMetadata(
2242
+ [
2243
+ { header: "x-amzn-bedrock-invocation-latency", key: "invocation_latency_ms", numeric: true },
2244
+ { header: "x-amzn-bedrock-cache-read-input-token-count", key: "cache_read_input_tokens", numeric: true },
2245
+ { header: "x-amzn-bedrock-cache-write-input-token-count", key: "cache_write_input_tokens", numeric: true },
2246
+ { header: "x-amzn-bedrock-trace-id", key: "trace_id" }
2247
+ ],
2248
+ httpHeaders
2249
+ );
2250
+ if (Object.keys(metadata).length > 0) {
2251
+ endEvent.vendorMetadata = metadata;
2252
+ }
2253
+ }
2158
2254
  yield endEvent;
2159
2255
  }
2160
2256
  appendAssistantToolCall(history, toolCalls) {
@@ -2406,6 +2502,14 @@ var azureOpenAIManifest = {
2406
2502
  };
2407
2503
 
2408
2504
  // src/adapters/azure-openai/adapter.ts
2505
+ var AZURE_OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
2506
+ { header: "x-ms-region", key: "region" },
2507
+ { header: "x-ms-deployment-name", key: "deployment" },
2508
+ { header: "apim-request-id", key: "request_id" },
2509
+ { header: "azureml-model-session", key: "model_session" },
2510
+ { header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
2511
+ { header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
2512
+ ]);
2409
2513
  var AzureOpenAIAdapter = class {
2410
2514
  vendor = azureOpenAIManifest.vendor;
2411
2515
  acceptedAuth = ["azureOpenAIApiKey"];
@@ -2440,7 +2544,8 @@ var AzureOpenAIAdapter = class {
2440
2544
  stream(req) {
2441
2545
  return streamFromOpenAI(this.ensureClient(), req, {
2442
2546
  knownModels: azureOpenAIManifest.knownModels,
2443
- tokensParam: "max_completion_tokens"
2547
+ tokensParam: "max_completion_tokens",
2548
+ vendorMetadataExtractor: AZURE_OPENAI_METADATA_EXTRACTOR
2444
2549
  });
2445
2550
  }
2446
2551
  appendAssistantToolCall(history, toolCalls) {
@@ -2565,6 +2670,12 @@ var groqManifest = {
2565
2670
  };
2566
2671
 
2567
2672
  // src/adapters/groq/adapter.ts
2673
+ var GROQ_METADATA_EXTRACTOR = makeMetadataExtractor([
2674
+ { header: "x-request-id", key: "request_id" },
2675
+ { header: "x-groq-region", key: "region" },
2676
+ { header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
2677
+ { header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
2678
+ ]);
2568
2679
  var GroqAdapter = class extends OpenAIAdapter {
2569
2680
  vendor = groqManifest.vendor;
2570
2681
  init(auth, client) {
@@ -2576,6 +2687,12 @@ var GroqAdapter = class extends OpenAIAdapter {
2576
2687
  client
2577
2688
  );
2578
2689
  }
2690
+ stream(req) {
2691
+ return streamFromOpenAI(this.ensureClient(), req, {
2692
+ knownModels: groqManifest.knownModels,
2693
+ vendorMetadataExtractor: GROQ_METADATA_EXTRACTOR
2694
+ });
2695
+ }
2579
2696
  };
2580
2697
 
2581
2698
  // src/adapters/groq/factory.ts
@@ -2676,6 +2793,10 @@ var huggingfaceManifest = {
2676
2793
  };
2677
2794
 
2678
2795
  // src/adapters/huggingface/adapter.ts
2796
+ var HUGGINGFACE_METADATA_EXTRACTOR = makeMetadataExtractor([
2797
+ { header: "x-inference-provider", key: "provider" },
2798
+ { header: "x-request-id", key: "request_id" }
2799
+ ]);
2679
2800
  var HuggingfaceAdapter = class extends OpenAIAdapter {
2680
2801
  vendor = huggingfaceManifest.vendor;
2681
2802
  init(auth, client) {
@@ -2687,6 +2808,12 @@ var HuggingfaceAdapter = class extends OpenAIAdapter {
2687
2808
  client
2688
2809
  );
2689
2810
  }
2811
+ stream(req) {
2812
+ return streamFromOpenAI(this.ensureClient(), req, {
2813
+ knownModels: huggingfaceManifest.knownModels,
2814
+ vendorMetadataExtractor: HUGGINGFACE_METADATA_EXTRACTOR
2815
+ });
2816
+ }
2690
2817
  };
2691
2818
 
2692
2819
  // src/adapters/huggingface/factory.ts