@jambonz/llm 0.5.2 → 0.5.4

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
@@ -31,7 +31,7 @@ interface RawCredential {
31
31
  /**
32
32
  * Convert a vendor + raw credential into an `AuthSpec` discriminated union member.
33
33
  *
34
- * Supported vendors: openai, deepseek, anthropic, google, vertex (alias for
34
+ * Supported vendors: openai, deepseek, baseten, anthropic, google, vertex (alias for
35
35
  * vertex-gemini + vertex-openai — both accept the same auth shape), vertex-gemini,
36
36
  * vertex-openai, bedrock, azure-openai, groq, huggingface.
37
37
  *
package/dist/index.d.ts CHANGED
@@ -31,7 +31,7 @@ interface RawCredential {
31
31
  /**
32
32
  * Convert a vendor + raw credential into an `AuthSpec` discriminated union member.
33
33
  *
34
- * Supported vendors: openai, deepseek, anthropic, google, vertex (alias for
34
+ * Supported vendors: openai, deepseek, baseten, anthropic, google, vertex (alias for
35
35
  * vertex-gemini + vertex-openai — both accept the same auth shape), vertex-gemini,
36
36
  * vertex-openai, bedrock, azure-openai, groq, huggingface.
37
37
  *
package/dist/index.js CHANGED
@@ -114,12 +114,18 @@ async function* streamFromOpenAI(client, req, options) {
114
114
  let usage;
115
115
  let finalFinishReason = null;
116
116
  let finalRawReason;
117
+ let sawContent = false;
117
118
  try {
118
119
  for await (const chunk of stream) {
119
120
  if (req.signal?.aborted) {
120
121
  yield { type: "end", finishReason: "aborted" };
121
122
  return;
122
123
  }
124
+ const chunkError = chunk.error;
125
+ if (chunkError) {
126
+ const message = chunkError && typeof chunkError === "object" && "message" in chunkError ? String(chunkError.message) : JSON.stringify(chunkError);
127
+ throw new Error(`OpenAI-compatible stream returned an error: ${message}`);
128
+ }
123
129
  if (chunk.usage) {
124
130
  usage = {
125
131
  ...chunk.usage.prompt_tokens !== void 0 ? { inputTokens: chunk.usage.prompt_tokens } : {},
@@ -133,6 +139,7 @@ async function* streamFromOpenAI(client, req, options) {
133
139
  const finishReason = choice.finish_reason;
134
140
  if (delta?.content) {
135
141
  if (t2 === void 0) t2 = process.hrtime.bigint();
142
+ sawContent = true;
136
143
  yield { type: "token", text: delta.content };
137
144
  }
138
145
  if (delta?.tool_calls) {
@@ -190,6 +197,12 @@ async function* streamFromOpenAI(client, req, options) {
190
197
  }
191
198
  throw err;
192
199
  }
200
+ const producedNothing = finalFinishReason === null && !sawContent && toolCallsEmitted.size === 0 && startedIds.size === 0 && usage === void 0;
201
+ if (producedNothing) {
202
+ throw new Error(
203
+ "OpenAI-compatible stream produced no data (no content, tool calls, usage, or finish reason). This usually means a misconfigured base URL or a vendor error returned in an HTTP 200 body. Verify the base URL and credentials."
204
+ );
205
+ }
193
206
  const endEvent = {
194
207
  type: "end",
195
208
  finishReason: finalFinishReason ?? "stop",
@@ -495,7 +508,7 @@ var OpenAIAdapter = class {
495
508
  }
496
509
  stream(req) {
497
510
  return streamFromOpenAI(this.ensureClient(), req, {
498
- knownModels: openAIManifest.knownModels,
511
+ knownModels: this.knownModels(),
499
512
  vendorMetadataExtractor: OPENAI_METADATA_EXTRACTOR
500
513
  });
501
514
  }
@@ -506,7 +519,16 @@ var OpenAIAdapter = class {
506
519
  return appendOpenAIToolResult(history, toolCallId, result);
507
520
  }
508
521
  async listAvailableModels() {
509
- return listOpenAICompatibleModels(this.ensureClient(), openAIManifest.knownModels);
522
+ return listOpenAICompatibleModels(this.ensureClient(), this.knownModels());
523
+ }
524
+ /**
525
+ * Capability table used to enrich both `stream()` (for tools/vision gating)
526
+ * and `listAvailableModels()` (for filling capability flags on live entries).
527
+ * Subclasses backed by the same OpenAI wire (DeepSeek, Baseten, …) override
528
+ * this so their own manifest entries are consulted instead of OpenAI's.
529
+ */
530
+ knownModels() {
531
+ return openAIManifest.knownModels;
510
532
  }
511
533
  async testCredential() {
512
534
  await this.ensureClient().models.list();
@@ -617,12 +639,311 @@ var DeepSeekAdapter = class extends OpenAIAdapter {
617
639
  client
618
640
  );
619
641
  }
642
+ knownModels() {
643
+ return deepseekManifest.knownModels;
644
+ }
620
645
  };
621
646
  var deepseekFactory = {
622
647
  vendor: deepseekManifest.vendor,
623
648
  manifest: deepseekManifest,
624
649
  create: () => new DeepSeekAdapter()
625
650
  };
651
+ var basetenManifest = {
652
+ vendor: "baseten",
653
+ displayName: "Baseten",
654
+ authKinds: [
655
+ {
656
+ kind: "apiKey",
657
+ displayName: "API Key",
658
+ fields: [
659
+ {
660
+ name: "apiKey",
661
+ label: "API Key",
662
+ type: "password",
663
+ required: true,
664
+ help: "Get an API key from https://app.baseten.co/settings/api_keys"
665
+ },
666
+ {
667
+ name: "baseURL",
668
+ label: "Base URL",
669
+ type: "url",
670
+ required: false,
671
+ default: "https://inference.baseten.co/v1",
672
+ help: "Defaults to Baseten Model APIs. Set to https://bridge.baseten.co/v1/direct to route to a dedicated deployment."
673
+ }
674
+ ]
675
+ }
676
+ ],
677
+ knownModels: [
678
+ {
679
+ id: "deepseek-ai/DeepSeek-V3.1",
680
+ displayName: "DeepSeek V3.1",
681
+ capabilities: {
682
+ streaming: true,
683
+ tools: true,
684
+ vision: false,
685
+ systemPrompt: true,
686
+ maxContextTokens: 163840
687
+ }
688
+ },
689
+ {
690
+ id: "deepseek-ai/DeepSeek-V4-Pro",
691
+ displayName: "DeepSeek V4 Pro",
692
+ capabilities: {
693
+ streaming: true,
694
+ tools: true,
695
+ vision: false,
696
+ systemPrompt: true,
697
+ maxContextTokens: 131072
698
+ }
699
+ },
700
+ {
701
+ id: "zai-org/GLM-4.7",
702
+ displayName: "GLM 4.7",
703
+ capabilities: {
704
+ streaming: true,
705
+ tools: true,
706
+ vision: false,
707
+ systemPrompt: true,
708
+ maxContextTokens: 2e5
709
+ }
710
+ },
711
+ {
712
+ id: "zai-org/GLM-5",
713
+ displayName: "GLM 5",
714
+ capabilities: {
715
+ streaming: true,
716
+ tools: true,
717
+ vision: false,
718
+ systemPrompt: true,
719
+ maxContextTokens: 202800
720
+ }
721
+ },
722
+ {
723
+ id: "moonshotai/Kimi-K2.5",
724
+ displayName: "Kimi K2.5",
725
+ capabilities: {
726
+ streaming: true,
727
+ tools: true,
728
+ vision: true,
729
+ systemPrompt: true,
730
+ maxContextTokens: 262e3
731
+ }
732
+ },
733
+ {
734
+ id: "moonshotai/Kimi-K2.6",
735
+ displayName: "Kimi K2.6",
736
+ capabilities: {
737
+ streaming: true,
738
+ tools: true,
739
+ vision: true,
740
+ systemPrompt: true,
741
+ maxContextTokens: 262e3
742
+ }
743
+ },
744
+ {
745
+ id: "MiniMaxAI/MiniMax-M2.5",
746
+ displayName: "MiniMax M2.5",
747
+ capabilities: {
748
+ streaming: true,
749
+ tools: true,
750
+ vision: false,
751
+ systemPrompt: true,
752
+ maxContextTokens: 204e3
753
+ }
754
+ },
755
+ {
756
+ id: "nvidia/Nemotron-120B-A12B",
757
+ displayName: "Nemotron Super",
758
+ capabilities: {
759
+ streaming: true,
760
+ tools: true,
761
+ vision: false,
762
+ systemPrompt: true,
763
+ maxContextTokens: 202800
764
+ }
765
+ },
766
+ {
767
+ id: "openai/gpt-oss-120b",
768
+ displayName: "OpenAI GPT 120B",
769
+ capabilities: {
770
+ streaming: true,
771
+ tools: true,
772
+ vision: false,
773
+ systemPrompt: true,
774
+ maxContextTokens: 128072
775
+ }
776
+ }
777
+ ],
778
+ supportsModelListing: true,
779
+ docsUrl: "https://docs.baseten.co/inference/model-apis/overview"
780
+ };
781
+ var BasetenAdapter = class extends OpenAIAdapter {
782
+ vendor = basetenManifest.vendor;
783
+ init(auth, client) {
784
+ super.init(
785
+ {
786
+ ...auth,
787
+ baseURL: auth.baseURL ?? "https://inference.baseten.co/v1"
788
+ },
789
+ client
790
+ );
791
+ }
792
+ knownModels() {
793
+ return basetenManifest.knownModels;
794
+ }
795
+ };
796
+ var basetenFactory = {
797
+ vendor: basetenManifest.vendor,
798
+ manifest: basetenManifest,
799
+ create: () => new BasetenAdapter()
800
+ };
801
+ var moonshotManifest = {
802
+ vendor: "moonshot",
803
+ displayName: "Moonshot (Kimi)",
804
+ authKinds: [
805
+ {
806
+ kind: "apiKey",
807
+ displayName: "API Key",
808
+ fields: [
809
+ {
810
+ name: "apiKey",
811
+ label: "API Key",
812
+ type: "password",
813
+ required: true,
814
+ help: "Get an API key from https://platform.moonshot.ai/console/api-keys"
815
+ },
816
+ {
817
+ name: "baseURL",
818
+ label: "Base URL",
819
+ type: "url",
820
+ required: false,
821
+ default: "https://api.moonshot.ai/v1",
822
+ help: "Defaults to the global endpoint. Set to https://api.moonshot.cn/v1 for the China endpoint."
823
+ }
824
+ ]
825
+ }
826
+ ],
827
+ knownModels: [
828
+ {
829
+ id: "kimi-k2.6",
830
+ displayName: "Kimi K2.6",
831
+ capabilities: {
832
+ streaming: true,
833
+ tools: true,
834
+ vision: true,
835
+ systemPrompt: true,
836
+ maxContextTokens: 262144
837
+ }
838
+ },
839
+ {
840
+ id: "kimi-k2.5",
841
+ displayName: "Kimi K2.5",
842
+ capabilities: {
843
+ streaming: true,
844
+ tools: true,
845
+ vision: true,
846
+ systemPrompt: true,
847
+ maxContextTokens: 262144
848
+ }
849
+ }
850
+ ],
851
+ supportsModelListing: true,
852
+ docsUrl: "https://platform.moonshot.ai/docs"
853
+ };
854
+ var MoonshotAdapter = class extends OpenAIAdapter {
855
+ vendor = moonshotManifest.vendor;
856
+ init(auth, client) {
857
+ super.init(
858
+ {
859
+ ...auth,
860
+ baseURL: auth.baseURL ?? "https://api.moonshot.ai/v1"
861
+ },
862
+ client
863
+ );
864
+ }
865
+ knownModels() {
866
+ return moonshotManifest.knownModels;
867
+ }
868
+ };
869
+ var moonshotFactory = {
870
+ vendor: moonshotManifest.vendor,
871
+ manifest: moonshotManifest,
872
+ create: () => new MoonshotAdapter()
873
+ };
874
+ var zaiManifest = {
875
+ vendor: "zai",
876
+ displayName: "Z.ai (GLM)",
877
+ authKinds: [
878
+ {
879
+ kind: "apiKey",
880
+ displayName: "API Key",
881
+ fields: [
882
+ {
883
+ name: "apiKey",
884
+ label: "API Key",
885
+ type: "password",
886
+ required: true,
887
+ help: "Get an API key from https://z.ai/manage-apikey/apikey-list"
888
+ },
889
+ {
890
+ name: "baseURL",
891
+ label: "Base URL",
892
+ type: "url",
893
+ required: false,
894
+ default: "https://api.z.ai/api/paas/v4",
895
+ help: "Defaults to the general API. Coding-Plan keys must use https://api.z.ai/api/coding/paas/v4."
896
+ }
897
+ ]
898
+ }
899
+ ],
900
+ knownModels: [
901
+ {
902
+ id: "glm-5.2",
903
+ displayName: "GLM-5.2",
904
+ capabilities: {
905
+ streaming: true,
906
+ tools: true,
907
+ vision: false,
908
+ systemPrompt: true,
909
+ maxContextTokens: 1e6
910
+ }
911
+ },
912
+ {
913
+ id: "glm-4.7",
914
+ displayName: "GLM-4.7",
915
+ capabilities: {
916
+ streaming: true,
917
+ tools: true,
918
+ vision: false,
919
+ systemPrompt: true,
920
+ maxContextTokens: 2e5
921
+ }
922
+ }
923
+ ],
924
+ supportsModelListing: false,
925
+ docsUrl: "https://docs.z.ai/"
926
+ };
927
+ var ZaiAdapter = class extends OpenAIAdapter {
928
+ vendor = zaiManifest.vendor;
929
+ init(auth, client) {
930
+ super.init(
931
+ {
932
+ ...auth,
933
+ baseURL: auth.baseURL ?? "https://api.z.ai/api/paas/v4"
934
+ },
935
+ client
936
+ );
937
+ }
938
+ knownModels() {
939
+ return zaiManifest.knownModels;
940
+ }
941
+ };
942
+ var zaiFactory = {
943
+ vendor: zaiManifest.vendor,
944
+ manifest: zaiManifest,
945
+ create: () => new ZaiAdapter()
946
+ };
626
947
 
627
948
  // src/adapters/anthropic/adapter.ts
628
949
  import Anthropic from "@anthropic-ai/sdk";
@@ -2801,6 +3122,9 @@ var huggingfaceFactory = {
2801
3122
  // src/adapters/index.ts
2802
3123
  registerAdapter(openAIFactory);
2803
3124
  registerAdapter(deepseekFactory);
3125
+ registerAdapter(basetenFactory);
3126
+ registerAdapter(moonshotFactory);
3127
+ registerAdapter(zaiFactory);
2804
3128
  registerAdapter(anthropicFactory);
2805
3129
  registerAdapter(googleFactory);
2806
3130
  registerAdapter(vertexGeminiFactory);
@@ -2823,6 +3147,11 @@ function normalizeAuth(vendor, raw) {
2823
3147
  ...requireApiKey(vendor, raw),
2824
3148
  baseURL: raw.api_url ?? "https://api.deepseek.com/v1"
2825
3149
  };
3150
+ case "baseten":
3151
+ return {
3152
+ ...requireApiKey(vendor, raw),
3153
+ baseURL: raw.api_url ?? "https://inference.baseten.co/v1"
3154
+ };
2826
3155
  case "google":
2827
3156
  return normalizeGoogle(raw);
2828
3157
  case "vertex":