@jambonz/llm 0.4.6 → 0.5.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.
@@ -1,4 +1,4 @@
1
- import { b as AdapterFactory, e as AuthKind, A as AuthSpec, L as LlmAdapter, d as ApiKeyAuth, h as ClientOptions, P as PromptRequest, m as LlmEvent, M as Message, p as ToolCallEvent, o as ModelInfo, c as AdapterManifest } from '../types-DbqWrdT6.cjs';
1
+ import { b as AdapterFactory, e as AuthKind, A as AuthSpec, L as LlmAdapter, d as ApiKeyAuth, h as ClientOptions, P as PromptRequest, m as LlmEvent, M as Message, p as ToolCallEvent, o as ModelInfo, c as AdapterManifest } from '../types-BEgQaQIb.cjs';
2
2
 
3
3
  /**
4
4
  * Named scenarios the harness must be able to stage. Each scenario configures
@@ -1,4 +1,4 @@
1
- import { b as AdapterFactory, e as AuthKind, A as AuthSpec, L as LlmAdapter, d as ApiKeyAuth, h as ClientOptions, P as PromptRequest, m as LlmEvent, M as Message, p as ToolCallEvent, o as ModelInfo, c as AdapterManifest } from '../types-DbqWrdT6.js';
1
+ import { b as AdapterFactory, e as AuthKind, A as AuthSpec, L as LlmAdapter, d as ApiKeyAuth, h as ClientOptions, P as PromptRequest, m as LlmEvent, M as Message, p as ToolCallEvent, o as ModelInfo, c as AdapterManifest } from '../types-BEgQaQIb.js';
2
2
 
3
3
  /**
4
4
  * Named scenarios the harness must be able to stage. Each scenario configures
@@ -78,9 +78,22 @@ async function* streamFromOpenAI(client, req, options) {
78
78
  const param = options.tokensParam ?? (needsMaxCompletionTokens(req.model) ? "max_completion_tokens" : "max_tokens");
79
79
  body[param] = effectiveMaxTokens;
80
80
  }
81
+ const t0 = process.hrtime.bigint();
82
+ let t1;
83
+ let t2;
81
84
  let stream;
85
+ let responseHeaders;
82
86
  try {
83
- stream = await client.chat.completions.create(body, { signal: req.signal });
87
+ const apiPromise = client.chat.completions.create(body, { signal: req.signal });
88
+ const maybeWithResponse = apiPromise.withResponse;
89
+ if (typeof maybeWithResponse === "function") {
90
+ const result = await maybeWithResponse.call(apiPromise);
91
+ stream = result.data;
92
+ responseHeaders = result.response?.headers;
93
+ } else {
94
+ stream = await apiPromise;
95
+ }
96
+ t1 = process.hrtime.bigint();
84
97
  } catch (err) {
85
98
  if (isAbortError(err)) {
86
99
  yield { type: "end", finishReason: "aborted" };
@@ -112,6 +125,7 @@ async function* streamFromOpenAI(client, req, options) {
112
125
  const delta = choice.delta;
113
126
  const finishReason = choice.finish_reason;
114
127
  if (delta?.content) {
128
+ if (t2 === void 0) t2 = process.hrtime.bigint();
115
129
  yield { type: "token", text: delta.content };
116
130
  }
117
131
  if (delta?.tool_calls) {
@@ -175,6 +189,20 @@ async function* streamFromOpenAI(client, req, options) {
175
189
  ...usage ? { usage } : {},
176
190
  ...finalRawReason ? { rawReason: finalRawReason } : {}
177
191
  };
192
+ if (options.vendorMetadataExtractor && responseHeaders) {
193
+ const metadata = options.vendorMetadataExtractor(responseHeaders);
194
+ if (metadata && Object.keys(metadata).length > 0) {
195
+ endEvent.vendorMetadata = metadata;
196
+ }
197
+ }
198
+ if (t1 !== void 0) {
199
+ const t3 = process.hrtime.bigint();
200
+ endEvent.clientTiming = {
201
+ requestToHeadersMs: Number(t1 - t0) / 1e6,
202
+ ...t2 !== void 0 ? { headersToFirstTokenMs: Number(t2 - t1) / 1e6 } : {},
203
+ totalMs: Number(t3 - t0) / 1e6
204
+ };
205
+ }
178
206
  yield endEvent;
179
207
  }
180
208
  function appendOpenAIAssistantToolCall(history, toolCalls) {
@@ -302,6 +330,40 @@ function isAbortError(err) {
302
330
  return e.name === "APIUserAbortError" || e.name === "AbortError" || e.code === "ABORT_ERR" || typeof e.message === "string" && /aborted/i.test(e.message);
303
331
  }
304
332
 
333
+ // src/adapters/_metadata.ts
334
+ function makeMetadataExtractor(fields) {
335
+ return (headers) => {
336
+ const out = {};
337
+ for (const f of fields) {
338
+ const raw = headers.get(f.header);
339
+ if (raw === null || raw === void 0 || raw === "") continue;
340
+ if (f.numeric) {
341
+ const n = Number(raw);
342
+ if (Number.isFinite(n)) out[f.key] = n;
343
+ } else {
344
+ out[f.key] = raw;
345
+ }
346
+ }
347
+ return out;
348
+ };
349
+ }
350
+ function extractMetadata(fields, headers) {
351
+ const headersInstance = headers instanceof Headers ? headers : recordToHeaders(headers);
352
+ return makeMetadataExtractor(fields)(headersInstance);
353
+ }
354
+ function recordToHeaders(record) {
355
+ const h = new Headers();
356
+ for (const [name, value] of Object.entries(record)) {
357
+ if (value === void 0) continue;
358
+ if (Array.isArray(value)) {
359
+ for (const v of value) h.append(name, v);
360
+ } else {
361
+ h.set(name, value);
362
+ }
363
+ }
364
+ return h;
365
+ }
366
+
305
367
  // src/adapters/openai/manifest.ts
306
368
  var OPENAI_KNOWN_MODELS = [
307
369
  {
@@ -403,6 +465,12 @@ var openAIManifest = {
403
465
  };
404
466
 
405
467
  // src/adapters/openai/adapter.ts
468
+ var OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
469
+ { header: "x-request-id", key: "request_id" },
470
+ { header: "openai-processing-ms", key: "processing_ms", numeric: true },
471
+ { header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
472
+ { header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
473
+ ]);
406
474
  var OpenAIAdapter = class {
407
475
  vendor = openAIManifest.vendor;
408
476
  acceptedAuth = ["apiKey"];
@@ -420,7 +488,8 @@ var OpenAIAdapter = class {
420
488
  }
421
489
  stream(req) {
422
490
  return streamFromOpenAI(this.ensureClient(), req, {
423
- knownModels: openAIManifest.knownModels
491
+ knownModels: openAIManifest.knownModels,
492
+ vendorMetadataExtractor: OPENAI_METADATA_EXTRACTOR
424
493
  });
425
494
  }
426
495
  appendAssistantToolCall(history, toolCalls) {
@@ -652,6 +721,12 @@ var anthropicManifest = {
652
721
  };
653
722
 
654
723
  // src/adapters/anthropic/adapter.ts
724
+ var ANTHROPIC_METADATA_EXTRACTOR = makeMetadataExtractor([
725
+ { header: "request-id", key: "request_id" },
726
+ { header: "anthropic-ratelimit-requests-remaining", key: "requests_remaining", numeric: true },
727
+ { header: "anthropic-ratelimit-input-tokens-remaining", key: "input_tokens_remaining", numeric: true },
728
+ { header: "anthropic-ratelimit-output-tokens-remaining", key: "output_tokens_remaining", numeric: true }
729
+ ]);
655
730
  var AnthropicAdapter = class {
656
731
  vendor = anthropicManifest.vendor;
657
732
  acceptedAuth = ["apiKey"];
@@ -686,11 +761,20 @@ var AnthropicAdapter = class {
686
761
  if (tools) body.tools = tools;
687
762
  if (req.temperature !== void 0) body.temperature = req.temperature;
688
763
  let stream;
764
+ let responseHeaders;
689
765
  try {
690
- stream = await client.messages.create(
766
+ const apiPromise = client.messages.create(
691
767
  body,
692
768
  { signal: req.signal }
693
769
  );
770
+ const maybeWithResponse = apiPromise.withResponse;
771
+ if (typeof maybeWithResponse === "function") {
772
+ const result = await maybeWithResponse.call(apiPromise);
773
+ stream = result.data;
774
+ responseHeaders = result.response?.headers;
775
+ } else {
776
+ stream = await apiPromise;
777
+ }
694
778
  } catch (err) {
695
779
  if (isAbortError2(err)) {
696
780
  yield { type: "end", finishReason: "aborted" };
@@ -801,6 +885,12 @@ var AnthropicAdapter = class {
801
885
  ...usage ? { usage } : {},
802
886
  ...stopReason ? { rawReason: stopReason } : {}
803
887
  };
888
+ if (responseHeaders) {
889
+ const metadata = ANTHROPIC_METADATA_EXTRACTOR(responseHeaders);
890
+ if (Object.keys(metadata).length > 0) {
891
+ endEvent.vendorMetadata = metadata;
892
+ }
893
+ }
804
894
  yield endEvent;
805
895
  }
806
896
  appendAssistantToolCall(history, toolCalls) {
@@ -1593,6 +1683,9 @@ var vertexOpenAIManifest = {
1593
1683
  };
1594
1684
 
1595
1685
  // src/adapters/vertex-openai/adapter.ts
1686
+ var VERTEX_OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
1687
+ { header: "x-request-id", key: "request_id" }
1688
+ ]);
1596
1689
  var VertexOpenAIAdapter = class {
1597
1690
  vendor = vertexOpenAIManifest.vendor;
1598
1691
  acceptedAuth = ["vertexServiceAccount"];
@@ -1645,7 +1738,8 @@ var VertexOpenAIAdapter = class {
1645
1738
  // endpoint predates `max_completion_tokens` and may not recognize it.
1646
1739
  // The model-id heuristic wouldn't catch a partner model named in the
1647
1740
  // OpenAI style (unlikely today, but defensive).
1648
- tokensParam: "max_tokens"
1741
+ tokensParam: "max_tokens",
1742
+ vendorMetadataExtractor: VERTEX_OPENAI_METADATA_EXTRACTOR
1649
1743
  });
1650
1744
  }
1651
1745
  appendAssistantToolCall(history, toolCalls) {
@@ -2109,6 +2203,21 @@ var BedrockAdapter = class {
2109
2203
  ...usage ? { usage } : {},
2110
2204
  ...stopReason ? { rawReason: stopReason } : {}
2111
2205
  };
2206
+ const httpHeaders = response.$metadata?.httpHeaders;
2207
+ if (httpHeaders) {
2208
+ const metadata = extractMetadata(
2209
+ [
2210
+ { header: "x-amzn-bedrock-invocation-latency", key: "invocation_latency_ms", numeric: true },
2211
+ { header: "x-amzn-bedrock-cache-read-input-token-count", key: "cache_read_input_tokens", numeric: true },
2212
+ { header: "x-amzn-bedrock-cache-write-input-token-count", key: "cache_write_input_tokens", numeric: true },
2213
+ { header: "x-amzn-bedrock-trace-id", key: "trace_id" }
2214
+ ],
2215
+ httpHeaders
2216
+ );
2217
+ if (Object.keys(metadata).length > 0) {
2218
+ endEvent.vendorMetadata = metadata;
2219
+ }
2220
+ }
2112
2221
  yield endEvent;
2113
2222
  }
2114
2223
  appendAssistantToolCall(history, toolCalls) {
@@ -2360,6 +2469,14 @@ var azureOpenAIManifest = {
2360
2469
  };
2361
2470
 
2362
2471
  // src/adapters/azure-openai/adapter.ts
2472
+ var AZURE_OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
2473
+ { header: "x-ms-region", key: "region" },
2474
+ { header: "x-ms-deployment-name", key: "deployment" },
2475
+ { header: "apim-request-id", key: "request_id" },
2476
+ { header: "azureml-model-session", key: "model_session" },
2477
+ { header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
2478
+ { header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
2479
+ ]);
2363
2480
  var AzureOpenAIAdapter = class {
2364
2481
  vendor = azureOpenAIManifest.vendor;
2365
2482
  acceptedAuth = ["azureOpenAIApiKey"];
@@ -2394,7 +2511,8 @@ var AzureOpenAIAdapter = class {
2394
2511
  stream(req) {
2395
2512
  return streamFromOpenAI(this.ensureClient(), req, {
2396
2513
  knownModels: azureOpenAIManifest.knownModels,
2397
- tokensParam: "max_completion_tokens"
2514
+ tokensParam: "max_completion_tokens",
2515
+ vendorMetadataExtractor: AZURE_OPENAI_METADATA_EXTRACTOR
2398
2516
  });
2399
2517
  }
2400
2518
  appendAssistantToolCall(history, toolCalls) {
@@ -2519,6 +2637,12 @@ var groqManifest = {
2519
2637
  };
2520
2638
 
2521
2639
  // src/adapters/groq/adapter.ts
2640
+ var GROQ_METADATA_EXTRACTOR = makeMetadataExtractor([
2641
+ { header: "x-request-id", key: "request_id" },
2642
+ { header: "x-groq-region", key: "region" },
2643
+ { header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
2644
+ { header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
2645
+ ]);
2522
2646
  var GroqAdapter = class extends OpenAIAdapter {
2523
2647
  vendor = groqManifest.vendor;
2524
2648
  init(auth, client) {
@@ -2530,6 +2654,12 @@ var GroqAdapter = class extends OpenAIAdapter {
2530
2654
  client
2531
2655
  );
2532
2656
  }
2657
+ stream(req) {
2658
+ return streamFromOpenAI(this.ensureClient(), req, {
2659
+ knownModels: groqManifest.knownModels,
2660
+ vendorMetadataExtractor: GROQ_METADATA_EXTRACTOR
2661
+ });
2662
+ }
2533
2663
  };
2534
2664
 
2535
2665
  // src/adapters/groq/factory.ts
@@ -2630,6 +2760,10 @@ var huggingfaceManifest = {
2630
2760
  };
2631
2761
 
2632
2762
  // src/adapters/huggingface/adapter.ts
2763
+ var HUGGINGFACE_METADATA_EXTRACTOR = makeMetadataExtractor([
2764
+ { header: "x-inference-provider", key: "provider" },
2765
+ { header: "x-request-id", key: "request_id" }
2766
+ ]);
2633
2767
  var HuggingfaceAdapter = class extends OpenAIAdapter {
2634
2768
  vendor = huggingfaceManifest.vendor;
2635
2769
  init(auth, client) {
@@ -2641,6 +2775,12 @@ var HuggingfaceAdapter = class extends OpenAIAdapter {
2641
2775
  client
2642
2776
  );
2643
2777
  }
2778
+ stream(req) {
2779
+ return streamFromOpenAI(this.ensureClient(), req, {
2780
+ knownModels: huggingfaceManifest.knownModels,
2781
+ vendorMetadataExtractor: HUGGINGFACE_METADATA_EXTRACTOR
2782
+ });
2783
+ }
2644
2784
  };
2645
2785
 
2646
2786
  // src/adapters/huggingface/factory.ts