@jambonz/llm 0.4.5 → 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.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as ServiceAccountJson, A as AuthSpec, a as AuthKindSchema, P as PromptRequest, b as AdapterFactory, c as AdapterManifest, C as CreateLlmArgs, L as LlmAdapter } from './types-DbqWrdT6.cjs';
2
- export { d as ApiKeyAuth, e as AuthKind, f as AzureOpenAIApiKeyAuth, B as BedrockApiKeyAuth, g as BedrockIamAuth, h as ClientOptions, i as ContentBlock, F as FinishReason, j as FormField, k as FormFieldType, G as GoogleApiKeyAuth, l as GoogleServiceAccountAuth, J as JsonSchema, m as LlmEvent, M as Message, n as ModelCapabilities, o as ModelInfo, R as Role, T as Tool, p as ToolCallEvent, U as Usage, V as VertexServiceAccountAuth } from './types-DbqWrdT6.cjs';
1
+ import { S as ServiceAccountJson, A as AuthSpec, a as AuthKindSchema, P as PromptRequest, b as AdapterFactory, c as AdapterManifest, C as CreateLlmArgs, L as LlmAdapter } from './types-BWsmVtXv.cjs';
2
+ export { d as ApiKeyAuth, e as AuthKind, f as AzureOpenAIApiKeyAuth, B as BedrockApiKeyAuth, g as BedrockIamAuth, h as ClientOptions, i as ContentBlock, F as FinishReason, j as FormField, k as FormFieldType, G as GoogleApiKeyAuth, l as GoogleServiceAccountAuth, J as JsonSchema, m as LlmEvent, M as Message, n as ModelCapabilities, o as ModelInfo, R as Role, T as Tool, p as ToolCallEvent, U as Usage, V as VertexServiceAccountAuth } from './types-BWsmVtXv.cjs';
3
3
 
4
4
  /**
5
5
  * The loose "DB-shape" input accepted by `normalizeAuth`.
@@ -33,7 +33,7 @@ interface RawCredential {
33
33
  *
34
34
  * Supported vendors: openai, deepseek, anthropic, google, vertex (alias for
35
35
  * vertex-gemini + vertex-openai — both accept the same auth shape), vertex-gemini,
36
- * vertex-openai, bedrock, azure-openai, groq.
36
+ * vertex-openai, bedrock, azure-openai, groq, huggingface.
37
37
  *
38
38
  * Throws with a clear message if the raw credential is missing required fields.
39
39
  */
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as ServiceAccountJson, A as AuthSpec, a as AuthKindSchema, P as PromptRequest, b as AdapterFactory, c as AdapterManifest, C as CreateLlmArgs, L as LlmAdapter } from './types-DbqWrdT6.js';
2
- export { d as ApiKeyAuth, e as AuthKind, f as AzureOpenAIApiKeyAuth, B as BedrockApiKeyAuth, g as BedrockIamAuth, h as ClientOptions, i as ContentBlock, F as FinishReason, j as FormField, k as FormFieldType, G as GoogleApiKeyAuth, l as GoogleServiceAccountAuth, J as JsonSchema, m as LlmEvent, M as Message, n as ModelCapabilities, o as ModelInfo, R as Role, T as Tool, p as ToolCallEvent, U as Usage, V as VertexServiceAccountAuth } from './types-DbqWrdT6.js';
1
+ import { S as ServiceAccountJson, A as AuthSpec, a as AuthKindSchema, P as PromptRequest, b as AdapterFactory, c as AdapterManifest, C as CreateLlmArgs, L as LlmAdapter } from './types-BWsmVtXv.js';
2
+ export { d as ApiKeyAuth, e as AuthKind, f as AzureOpenAIApiKeyAuth, B as BedrockApiKeyAuth, g as BedrockIamAuth, h as ClientOptions, i as ContentBlock, F as FinishReason, j as FormField, k as FormFieldType, G as GoogleApiKeyAuth, l as GoogleServiceAccountAuth, J as JsonSchema, m as LlmEvent, M as Message, n as ModelCapabilities, o as ModelInfo, R as Role, T as Tool, p as ToolCallEvent, U as Usage, V as VertexServiceAccountAuth } from './types-BWsmVtXv.js';
3
3
 
4
4
  /**
5
5
  * The loose "DB-shape" input accepted by `normalizeAuth`.
@@ -33,7 +33,7 @@ interface RawCredential {
33
33
  *
34
34
  * Supported vendors: openai, deepseek, anthropic, google, vertex (alias for
35
35
  * vertex-gemini + vertex-openai — both accept the same auth shape), vertex-gemini,
36
- * vertex-openai, bedrock, azure-openai, groq.
36
+ * vertex-openai, bedrock, azure-openai, groq, huggingface.
37
37
  *
38
38
  * Throws with a clear message if the raw credential is missing required fields.
39
39
  */
package/dist/index.js CHANGED
@@ -86,8 +86,17 @@ async function* streamFromOpenAI(client, req, options) {
86
86
  body[param] = effectiveMaxTokens;
87
87
  }
88
88
  let stream;
89
+ let responseHeaders;
89
90
  try {
90
- stream = await client.chat.completions.create(body, { signal: req.signal });
91
+ const apiPromise = client.chat.completions.create(body, { signal: req.signal });
92
+ const maybeWithResponse = apiPromise.withResponse;
93
+ if (typeof maybeWithResponse === "function") {
94
+ const result = await maybeWithResponse.call(apiPromise);
95
+ stream = result.data;
96
+ responseHeaders = result.response?.headers;
97
+ } else {
98
+ stream = await apiPromise;
99
+ }
91
100
  } catch (err) {
92
101
  if (isAbortError(err)) {
93
102
  yield { type: "end", finishReason: "aborted" };
@@ -182,6 +191,12 @@ async function* streamFromOpenAI(client, req, options) {
182
191
  ...usage ? { usage } : {},
183
192
  ...finalRawReason ? { rawReason: finalRawReason } : {}
184
193
  };
194
+ if (options.vendorMetadataExtractor && responseHeaders) {
195
+ const metadata = options.vendorMetadataExtractor(responseHeaders);
196
+ if (metadata && Object.keys(metadata).length > 0) {
197
+ endEvent.vendorMetadata = metadata;
198
+ }
199
+ }
185
200
  yield endEvent;
186
201
  }
187
202
  function appendOpenAIAssistantToolCall(history, toolCalls) {
@@ -309,6 +324,40 @@ function isAbortError(err) {
309
324
  return e.name === "APIUserAbortError" || e.name === "AbortError" || e.code === "ABORT_ERR" || typeof e.message === "string" && /aborted/i.test(e.message);
310
325
  }
311
326
 
327
+ // src/adapters/_metadata.ts
328
+ function makeMetadataExtractor(fields) {
329
+ return (headers) => {
330
+ const out = {};
331
+ for (const f of fields) {
332
+ const raw = headers.get(f.header);
333
+ if (raw === null || raw === void 0 || raw === "") continue;
334
+ if (f.numeric) {
335
+ const n = Number(raw);
336
+ if (Number.isFinite(n)) out[f.key] = n;
337
+ } else {
338
+ out[f.key] = raw;
339
+ }
340
+ }
341
+ return out;
342
+ };
343
+ }
344
+ function extractMetadata(fields, headers) {
345
+ const headersInstance = headers instanceof Headers ? headers : recordToHeaders(headers);
346
+ return makeMetadataExtractor(fields)(headersInstance);
347
+ }
348
+ function recordToHeaders(record) {
349
+ const h = new Headers();
350
+ for (const [name, value] of Object.entries(record)) {
351
+ if (value === void 0) continue;
352
+ if (Array.isArray(value)) {
353
+ for (const v of value) h.append(name, v);
354
+ } else {
355
+ h.set(name, value);
356
+ }
357
+ }
358
+ return h;
359
+ }
360
+
312
361
  // src/adapters/openai/manifest.ts
313
362
  var OPENAI_KNOWN_MODELS = [
314
363
  {
@@ -410,6 +459,12 @@ var openAIManifest = {
410
459
  };
411
460
 
412
461
  // src/adapters/openai/adapter.ts
462
+ var OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
463
+ { header: "x-request-id", key: "request_id" },
464
+ { header: "openai-processing-ms", key: "processing_ms", numeric: true },
465
+ { header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
466
+ { header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
467
+ ]);
413
468
  var OpenAIAdapter = class {
414
469
  vendor = openAIManifest.vendor;
415
470
  acceptedAuth = ["apiKey"];
@@ -427,7 +482,8 @@ var OpenAIAdapter = class {
427
482
  }
428
483
  stream(req) {
429
484
  return streamFromOpenAI(this.ensureClient(), req, {
430
- knownModels: openAIManifest.knownModels
485
+ knownModels: openAIManifest.knownModels,
486
+ vendorMetadataExtractor: OPENAI_METADATA_EXTRACTOR
431
487
  });
432
488
  }
433
489
  appendAssistantToolCall(history, toolCalls) {
@@ -659,6 +715,12 @@ var anthropicManifest = {
659
715
  };
660
716
 
661
717
  // src/adapters/anthropic/adapter.ts
718
+ var ANTHROPIC_METADATA_EXTRACTOR = makeMetadataExtractor([
719
+ { header: "request-id", key: "request_id" },
720
+ { header: "anthropic-ratelimit-requests-remaining", key: "requests_remaining", numeric: true },
721
+ { header: "anthropic-ratelimit-input-tokens-remaining", key: "input_tokens_remaining", numeric: true },
722
+ { header: "anthropic-ratelimit-output-tokens-remaining", key: "output_tokens_remaining", numeric: true }
723
+ ]);
662
724
  var AnthropicAdapter = class {
663
725
  vendor = anthropicManifest.vendor;
664
726
  acceptedAuth = ["apiKey"];
@@ -693,11 +755,20 @@ var AnthropicAdapter = class {
693
755
  if (tools) body.tools = tools;
694
756
  if (req.temperature !== void 0) body.temperature = req.temperature;
695
757
  let stream;
758
+ let responseHeaders;
696
759
  try {
697
- stream = await client.messages.create(
760
+ const apiPromise = client.messages.create(
698
761
  body,
699
762
  { signal: req.signal }
700
763
  );
764
+ const maybeWithResponse = apiPromise.withResponse;
765
+ if (typeof maybeWithResponse === "function") {
766
+ const result = await maybeWithResponse.call(apiPromise);
767
+ stream = result.data;
768
+ responseHeaders = result.response?.headers;
769
+ } else {
770
+ stream = await apiPromise;
771
+ }
701
772
  } catch (err) {
702
773
  if (isAbortError2(err)) {
703
774
  yield { type: "end", finishReason: "aborted" };
@@ -808,6 +879,12 @@ var AnthropicAdapter = class {
808
879
  ...usage ? { usage } : {},
809
880
  ...stopReason ? { rawReason: stopReason } : {}
810
881
  };
882
+ if (responseHeaders) {
883
+ const metadata = ANTHROPIC_METADATA_EXTRACTOR(responseHeaders);
884
+ if (Object.keys(metadata).length > 0) {
885
+ endEvent.vendorMetadata = metadata;
886
+ }
887
+ }
811
888
  yield endEvent;
812
889
  }
813
890
  appendAssistantToolCall(history, toolCalls) {
@@ -1600,6 +1677,9 @@ var vertexOpenAIManifest = {
1600
1677
  };
1601
1678
 
1602
1679
  // src/adapters/vertex-openai/adapter.ts
1680
+ var VERTEX_OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
1681
+ { header: "x-request-id", key: "request_id" }
1682
+ ]);
1603
1683
  var VertexOpenAIAdapter = class {
1604
1684
  vendor = vertexOpenAIManifest.vendor;
1605
1685
  acceptedAuth = ["vertexServiceAccount"];
@@ -1652,7 +1732,8 @@ var VertexOpenAIAdapter = class {
1652
1732
  // endpoint predates `max_completion_tokens` and may not recognize it.
1653
1733
  // The model-id heuristic wouldn't catch a partner model named in the
1654
1734
  // OpenAI style (unlikely today, but defensive).
1655
- tokensParam: "max_tokens"
1735
+ tokensParam: "max_tokens",
1736
+ vendorMetadataExtractor: VERTEX_OPENAI_METADATA_EXTRACTOR
1656
1737
  });
1657
1738
  }
1658
1739
  appendAssistantToolCall(history, toolCalls) {
@@ -2116,6 +2197,21 @@ var BedrockAdapter = class {
2116
2197
  ...usage ? { usage } : {},
2117
2198
  ...stopReason ? { rawReason: stopReason } : {}
2118
2199
  };
2200
+ const httpHeaders = response.$metadata?.httpHeaders;
2201
+ if (httpHeaders) {
2202
+ const metadata = extractMetadata(
2203
+ [
2204
+ { header: "x-amzn-bedrock-invocation-latency", key: "invocation_latency_ms", numeric: true },
2205
+ { header: "x-amzn-bedrock-cache-read-input-token-count", key: "cache_read_input_tokens", numeric: true },
2206
+ { header: "x-amzn-bedrock-cache-write-input-token-count", key: "cache_write_input_tokens", numeric: true },
2207
+ { header: "x-amzn-bedrock-trace-id", key: "trace_id" }
2208
+ ],
2209
+ httpHeaders
2210
+ );
2211
+ if (Object.keys(metadata).length > 0) {
2212
+ endEvent.vendorMetadata = metadata;
2213
+ }
2214
+ }
2119
2215
  yield endEvent;
2120
2216
  }
2121
2217
  appendAssistantToolCall(history, toolCalls) {
@@ -2367,6 +2463,14 @@ var azureOpenAIManifest = {
2367
2463
  };
2368
2464
 
2369
2465
  // src/adapters/azure-openai/adapter.ts
2466
+ var AZURE_OPENAI_METADATA_EXTRACTOR = makeMetadataExtractor([
2467
+ { header: "x-ms-region", key: "region" },
2468
+ { header: "x-ms-deployment-name", key: "deployment" },
2469
+ { header: "apim-request-id", key: "request_id" },
2470
+ { header: "azureml-model-session", key: "model_session" },
2471
+ { header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
2472
+ { header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
2473
+ ]);
2370
2474
  var AzureOpenAIAdapter = class {
2371
2475
  vendor = azureOpenAIManifest.vendor;
2372
2476
  acceptedAuth = ["azureOpenAIApiKey"];
@@ -2401,7 +2505,8 @@ var AzureOpenAIAdapter = class {
2401
2505
  stream(req) {
2402
2506
  return streamFromOpenAI(this.ensureClient(), req, {
2403
2507
  knownModels: azureOpenAIManifest.knownModels,
2404
- tokensParam: "max_completion_tokens"
2508
+ tokensParam: "max_completion_tokens",
2509
+ vendorMetadataExtractor: AZURE_OPENAI_METADATA_EXTRACTOR
2405
2510
  });
2406
2511
  }
2407
2512
  appendAssistantToolCall(history, toolCalls) {
@@ -2526,6 +2631,12 @@ var groqManifest = {
2526
2631
  };
2527
2632
 
2528
2633
  // src/adapters/groq/adapter.ts
2634
+ var GROQ_METADATA_EXTRACTOR = makeMetadataExtractor([
2635
+ { header: "x-request-id", key: "request_id" },
2636
+ { header: "x-groq-region", key: "region" },
2637
+ { header: "x-ratelimit-remaining-requests", key: "requests_remaining", numeric: true },
2638
+ { header: "x-ratelimit-remaining-tokens", key: "tokens_remaining", numeric: true }
2639
+ ]);
2529
2640
  var GroqAdapter = class extends OpenAIAdapter {
2530
2641
  vendor = groqManifest.vendor;
2531
2642
  init(auth, client) {
@@ -2537,6 +2648,12 @@ var GroqAdapter = class extends OpenAIAdapter {
2537
2648
  client
2538
2649
  );
2539
2650
  }
2651
+ stream(req) {
2652
+ return streamFromOpenAI(this.ensureClient(), req, {
2653
+ knownModels: groqManifest.knownModels,
2654
+ vendorMetadataExtractor: GROQ_METADATA_EXTRACTOR
2655
+ });
2656
+ }
2540
2657
  };
2541
2658
 
2542
2659
  // src/adapters/groq/factory.ts
@@ -2546,6 +2663,127 @@ var groqFactory = {
2546
2663
  create: () => new GroqAdapter()
2547
2664
  };
2548
2665
 
2666
+ // src/adapters/huggingface/manifest.ts
2667
+ var HF_KNOWN_MODELS = [
2668
+ {
2669
+ id: "meta-llama/Llama-3.3-70B-Instruct",
2670
+ displayName: "Llama 3.3 70B Instruct (HF Providers)",
2671
+ capabilities: {
2672
+ streaming: true,
2673
+ tools: true,
2674
+ vision: false,
2675
+ systemPrompt: true,
2676
+ maxContextTokens: 128e3
2677
+ }
2678
+ },
2679
+ {
2680
+ id: "meta-llama/Llama-3.1-8B-Instruct",
2681
+ displayName: "Llama 3.1 8B Instruct (HF Providers)",
2682
+ capabilities: {
2683
+ streaming: true,
2684
+ tools: true,
2685
+ vision: false,
2686
+ systemPrompt: true,
2687
+ maxContextTokens: 128e3
2688
+ }
2689
+ },
2690
+ {
2691
+ id: "Qwen/Qwen2.5-72B-Instruct",
2692
+ displayName: "Qwen 2.5 72B Instruct (HF Providers)",
2693
+ capabilities: {
2694
+ streaming: true,
2695
+ tools: true,
2696
+ vision: false,
2697
+ systemPrompt: true,
2698
+ maxContextTokens: 128e3
2699
+ }
2700
+ },
2701
+ {
2702
+ id: "mistralai/Mistral-7B-Instruct-v0.3",
2703
+ displayName: "Mistral 7B Instruct v0.3 (HF Providers)",
2704
+ capabilities: {
2705
+ streaming: true,
2706
+ tools: true,
2707
+ vision: false,
2708
+ systemPrompt: true,
2709
+ maxContextTokens: 32e3
2710
+ }
2711
+ },
2712
+ {
2713
+ id: "deepseek-ai/DeepSeek-V3",
2714
+ displayName: "DeepSeek V3 (HF Providers)",
2715
+ capabilities: {
2716
+ streaming: true,
2717
+ tools: true,
2718
+ vision: false,
2719
+ systemPrompt: true,
2720
+ maxContextTokens: 64e3
2721
+ }
2722
+ }
2723
+ ];
2724
+ var huggingfaceManifest = {
2725
+ vendor: "huggingface",
2726
+ displayName: "HuggingFace Inference Providers",
2727
+ authKinds: [
2728
+ {
2729
+ kind: "apiKey",
2730
+ displayName: "API Key",
2731
+ fields: [
2732
+ {
2733
+ name: "apiKey",
2734
+ label: "HuggingFace Token",
2735
+ type: "password",
2736
+ required: true,
2737
+ help: "Get a token from https://huggingface.co/settings/tokens (Read scope is sufficient). Inference Providers requires a credit balance \u2014 claim the free monthly tier or attach a payment method at https://huggingface.co/billing."
2738
+ },
2739
+ {
2740
+ name: "baseURL",
2741
+ label: "Base URL",
2742
+ type: "url",
2743
+ required: false,
2744
+ default: "https://router.huggingface.co/v1",
2745
+ help: "Override only for proxies. Default is the HF Providers router endpoint."
2746
+ }
2747
+ ]
2748
+ }
2749
+ ],
2750
+ knownModels: HF_KNOWN_MODELS,
2751
+ // The HF router exposes /v1/models with the same Bearer auth.
2752
+ supportsModelListing: true,
2753
+ docsUrl: "https://huggingface.co/docs/inference-providers"
2754
+ };
2755
+
2756
+ // src/adapters/huggingface/adapter.ts
2757
+ var HUGGINGFACE_METADATA_EXTRACTOR = makeMetadataExtractor([
2758
+ { header: "x-inference-provider", key: "provider" },
2759
+ { header: "x-request-id", key: "request_id" }
2760
+ ]);
2761
+ var HuggingfaceAdapter = class extends OpenAIAdapter {
2762
+ vendor = huggingfaceManifest.vendor;
2763
+ init(auth, client) {
2764
+ super.init(
2765
+ {
2766
+ ...auth,
2767
+ baseURL: auth.baseURL ?? "https://router.huggingface.co/v1"
2768
+ },
2769
+ client
2770
+ );
2771
+ }
2772
+ stream(req) {
2773
+ return streamFromOpenAI(this.ensureClient(), req, {
2774
+ knownModels: huggingfaceManifest.knownModels,
2775
+ vendorMetadataExtractor: HUGGINGFACE_METADATA_EXTRACTOR
2776
+ });
2777
+ }
2778
+ };
2779
+
2780
+ // src/adapters/huggingface/factory.ts
2781
+ var huggingfaceFactory = {
2782
+ vendor: huggingfaceManifest.vendor,
2783
+ manifest: huggingfaceManifest,
2784
+ create: () => new HuggingfaceAdapter()
2785
+ };
2786
+
2549
2787
  // src/adapters/index.ts
2550
2788
  registerAdapter(openAIFactory);
2551
2789
  registerAdapter(deepseekFactory);
@@ -2556,6 +2794,7 @@ registerAdapter(vertexOpenAIFactory);
2556
2794
  registerAdapter(bedrockFactory);
2557
2795
  registerAdapter(azureOpenAIFactory);
2558
2796
  registerAdapter(groqFactory);
2797
+ registerAdapter(huggingfaceFactory);
2559
2798
 
2560
2799
  // src/normalize-auth.ts
2561
2800
  function normalizeAuth(vendor, raw) {
@@ -2563,6 +2802,7 @@ function normalizeAuth(vendor, raw) {
2563
2802
  case "openai":
2564
2803
  case "anthropic":
2565
2804
  case "groq":
2805
+ case "huggingface":
2566
2806
  return requireApiKey(vendor, raw);
2567
2807
  case "deepseek":
2568
2808
  return {