@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.
@@ -107,12 +107,18 @@ async function* streamFromOpenAI(client, req, options) {
107
107
  let usage;
108
108
  let finalFinishReason = null;
109
109
  let finalRawReason;
110
+ let sawContent = false;
110
111
  try {
111
112
  for await (const chunk of stream) {
112
113
  if (req.signal?.aborted) {
113
114
  yield { type: "end", finishReason: "aborted" };
114
115
  return;
115
116
  }
117
+ const chunkError = chunk.error;
118
+ if (chunkError) {
119
+ const message = chunkError && typeof chunkError === "object" && "message" in chunkError ? String(chunkError.message) : JSON.stringify(chunkError);
120
+ throw new Error(`OpenAI-compatible stream returned an error: ${message}`);
121
+ }
116
122
  if (chunk.usage) {
117
123
  usage = {
118
124
  ...chunk.usage.prompt_tokens !== void 0 ? { inputTokens: chunk.usage.prompt_tokens } : {},
@@ -126,6 +132,7 @@ async function* streamFromOpenAI(client, req, options) {
126
132
  const finishReason = choice.finish_reason;
127
133
  if (delta?.content) {
128
134
  if (t2 === void 0) t2 = process.hrtime.bigint();
135
+ sawContent = true;
129
136
  yield { type: "token", text: delta.content };
130
137
  }
131
138
  if (delta?.tool_calls) {
@@ -183,6 +190,12 @@ async function* streamFromOpenAI(client, req, options) {
183
190
  }
184
191
  throw err;
185
192
  }
193
+ const producedNothing = finalFinishReason === null && !sawContent && toolCallsEmitted.size === 0 && startedIds.size === 0 && usage === void 0;
194
+ if (producedNothing) {
195
+ throw new Error(
196
+ "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."
197
+ );
198
+ }
186
199
  const endEvent = {
187
200
  type: "end",
188
201
  finishReason: finalFinishReason ?? "stop",
@@ -488,7 +501,7 @@ var OpenAIAdapter = class {
488
501
  }
489
502
  stream(req) {
490
503
  return streamFromOpenAI(this.ensureClient(), req, {
491
- knownModels: openAIManifest.knownModels,
504
+ knownModels: this.knownModels(),
492
505
  vendorMetadataExtractor: OPENAI_METADATA_EXTRACTOR
493
506
  });
494
507
  }
@@ -499,7 +512,16 @@ var OpenAIAdapter = class {
499
512
  return appendOpenAIToolResult(history, toolCallId, result);
500
513
  }
501
514
  async listAvailableModels() {
502
- return listOpenAICompatibleModels(this.ensureClient(), openAIManifest.knownModels);
515
+ return listOpenAICompatibleModels(this.ensureClient(), this.knownModels());
516
+ }
517
+ /**
518
+ * Capability table used to enrich both `stream()` (for tools/vision gating)
519
+ * and `listAvailableModels()` (for filling capability flags on live entries).
520
+ * Subclasses backed by the same OpenAI wire (DeepSeek, Baseten, …) override
521
+ * this so their own manifest entries are consulted instead of OpenAI's.
522
+ */
523
+ knownModels() {
524
+ return openAIManifest.knownModels;
503
525
  }
504
526
  async testCredential() {
505
527
  await this.ensureClient().models.list();
@@ -610,12 +632,311 @@ var DeepSeekAdapter = class extends OpenAIAdapter {
610
632
  client
611
633
  );
612
634
  }
635
+ knownModels() {
636
+ return deepseekManifest.knownModels;
637
+ }
613
638
  };
614
639
  var deepseekFactory = {
615
640
  vendor: deepseekManifest.vendor,
616
641
  manifest: deepseekManifest,
617
642
  create: () => new DeepSeekAdapter()
618
643
  };
644
+ var basetenManifest = {
645
+ vendor: "baseten",
646
+ displayName: "Baseten",
647
+ authKinds: [
648
+ {
649
+ kind: "apiKey",
650
+ displayName: "API Key",
651
+ fields: [
652
+ {
653
+ name: "apiKey",
654
+ label: "API Key",
655
+ type: "password",
656
+ required: true,
657
+ help: "Get an API key from https://app.baseten.co/settings/api_keys"
658
+ },
659
+ {
660
+ name: "baseURL",
661
+ label: "Base URL",
662
+ type: "url",
663
+ required: false,
664
+ default: "https://inference.baseten.co/v1",
665
+ help: "Defaults to Baseten Model APIs. Set to https://bridge.baseten.co/v1/direct to route to a dedicated deployment."
666
+ }
667
+ ]
668
+ }
669
+ ],
670
+ knownModels: [
671
+ {
672
+ id: "deepseek-ai/DeepSeek-V3.1",
673
+ displayName: "DeepSeek V3.1",
674
+ capabilities: {
675
+ streaming: true,
676
+ tools: true,
677
+ vision: false,
678
+ systemPrompt: true,
679
+ maxContextTokens: 163840
680
+ }
681
+ },
682
+ {
683
+ id: "deepseek-ai/DeepSeek-V4-Pro",
684
+ displayName: "DeepSeek V4 Pro",
685
+ capabilities: {
686
+ streaming: true,
687
+ tools: true,
688
+ vision: false,
689
+ systemPrompt: true,
690
+ maxContextTokens: 131072
691
+ }
692
+ },
693
+ {
694
+ id: "zai-org/GLM-4.7",
695
+ displayName: "GLM 4.7",
696
+ capabilities: {
697
+ streaming: true,
698
+ tools: true,
699
+ vision: false,
700
+ systemPrompt: true,
701
+ maxContextTokens: 2e5
702
+ }
703
+ },
704
+ {
705
+ id: "zai-org/GLM-5",
706
+ displayName: "GLM 5",
707
+ capabilities: {
708
+ streaming: true,
709
+ tools: true,
710
+ vision: false,
711
+ systemPrompt: true,
712
+ maxContextTokens: 202800
713
+ }
714
+ },
715
+ {
716
+ id: "moonshotai/Kimi-K2.5",
717
+ displayName: "Kimi K2.5",
718
+ capabilities: {
719
+ streaming: true,
720
+ tools: true,
721
+ vision: true,
722
+ systemPrompt: true,
723
+ maxContextTokens: 262e3
724
+ }
725
+ },
726
+ {
727
+ id: "moonshotai/Kimi-K2.6",
728
+ displayName: "Kimi K2.6",
729
+ capabilities: {
730
+ streaming: true,
731
+ tools: true,
732
+ vision: true,
733
+ systemPrompt: true,
734
+ maxContextTokens: 262e3
735
+ }
736
+ },
737
+ {
738
+ id: "MiniMaxAI/MiniMax-M2.5",
739
+ displayName: "MiniMax M2.5",
740
+ capabilities: {
741
+ streaming: true,
742
+ tools: true,
743
+ vision: false,
744
+ systemPrompt: true,
745
+ maxContextTokens: 204e3
746
+ }
747
+ },
748
+ {
749
+ id: "nvidia/Nemotron-120B-A12B",
750
+ displayName: "Nemotron Super",
751
+ capabilities: {
752
+ streaming: true,
753
+ tools: true,
754
+ vision: false,
755
+ systemPrompt: true,
756
+ maxContextTokens: 202800
757
+ }
758
+ },
759
+ {
760
+ id: "openai/gpt-oss-120b",
761
+ displayName: "OpenAI GPT 120B",
762
+ capabilities: {
763
+ streaming: true,
764
+ tools: true,
765
+ vision: false,
766
+ systemPrompt: true,
767
+ maxContextTokens: 128072
768
+ }
769
+ }
770
+ ],
771
+ supportsModelListing: true,
772
+ docsUrl: "https://docs.baseten.co/inference/model-apis/overview"
773
+ };
774
+ var BasetenAdapter = class extends OpenAIAdapter {
775
+ vendor = basetenManifest.vendor;
776
+ init(auth, client) {
777
+ super.init(
778
+ {
779
+ ...auth,
780
+ baseURL: auth.baseURL ?? "https://inference.baseten.co/v1"
781
+ },
782
+ client
783
+ );
784
+ }
785
+ knownModels() {
786
+ return basetenManifest.knownModels;
787
+ }
788
+ };
789
+ var basetenFactory = {
790
+ vendor: basetenManifest.vendor,
791
+ manifest: basetenManifest,
792
+ create: () => new BasetenAdapter()
793
+ };
794
+ var moonshotManifest = {
795
+ vendor: "moonshot",
796
+ displayName: "Moonshot (Kimi)",
797
+ authKinds: [
798
+ {
799
+ kind: "apiKey",
800
+ displayName: "API Key",
801
+ fields: [
802
+ {
803
+ name: "apiKey",
804
+ label: "API Key",
805
+ type: "password",
806
+ required: true,
807
+ help: "Get an API key from https://platform.moonshot.ai/console/api-keys"
808
+ },
809
+ {
810
+ name: "baseURL",
811
+ label: "Base URL",
812
+ type: "url",
813
+ required: false,
814
+ default: "https://api.moonshot.ai/v1",
815
+ help: "Defaults to the global endpoint. Set to https://api.moonshot.cn/v1 for the China endpoint."
816
+ }
817
+ ]
818
+ }
819
+ ],
820
+ knownModels: [
821
+ {
822
+ id: "kimi-k2.6",
823
+ displayName: "Kimi K2.6",
824
+ capabilities: {
825
+ streaming: true,
826
+ tools: true,
827
+ vision: true,
828
+ systemPrompt: true,
829
+ maxContextTokens: 262144
830
+ }
831
+ },
832
+ {
833
+ id: "kimi-k2.5",
834
+ displayName: "Kimi K2.5",
835
+ capabilities: {
836
+ streaming: true,
837
+ tools: true,
838
+ vision: true,
839
+ systemPrompt: true,
840
+ maxContextTokens: 262144
841
+ }
842
+ }
843
+ ],
844
+ supportsModelListing: true,
845
+ docsUrl: "https://platform.moonshot.ai/docs"
846
+ };
847
+ var MoonshotAdapter = class extends OpenAIAdapter {
848
+ vendor = moonshotManifest.vendor;
849
+ init(auth, client) {
850
+ super.init(
851
+ {
852
+ ...auth,
853
+ baseURL: auth.baseURL ?? "https://api.moonshot.ai/v1"
854
+ },
855
+ client
856
+ );
857
+ }
858
+ knownModels() {
859
+ return moonshotManifest.knownModels;
860
+ }
861
+ };
862
+ var moonshotFactory = {
863
+ vendor: moonshotManifest.vendor,
864
+ manifest: moonshotManifest,
865
+ create: () => new MoonshotAdapter()
866
+ };
867
+ var zaiManifest = {
868
+ vendor: "zai",
869
+ displayName: "Z.ai (GLM)",
870
+ authKinds: [
871
+ {
872
+ kind: "apiKey",
873
+ displayName: "API Key",
874
+ fields: [
875
+ {
876
+ name: "apiKey",
877
+ label: "API Key",
878
+ type: "password",
879
+ required: true,
880
+ help: "Get an API key from https://z.ai/manage-apikey/apikey-list"
881
+ },
882
+ {
883
+ name: "baseURL",
884
+ label: "Base URL",
885
+ type: "url",
886
+ required: false,
887
+ default: "https://api.z.ai/api/paas/v4",
888
+ help: "Defaults to the general API. Coding-Plan keys must use https://api.z.ai/api/coding/paas/v4."
889
+ }
890
+ ]
891
+ }
892
+ ],
893
+ knownModels: [
894
+ {
895
+ id: "glm-5.2",
896
+ displayName: "GLM-5.2",
897
+ capabilities: {
898
+ streaming: true,
899
+ tools: true,
900
+ vision: false,
901
+ systemPrompt: true,
902
+ maxContextTokens: 1e6
903
+ }
904
+ },
905
+ {
906
+ id: "glm-4.7",
907
+ displayName: "GLM-4.7",
908
+ capabilities: {
909
+ streaming: true,
910
+ tools: true,
911
+ vision: false,
912
+ systemPrompt: true,
913
+ maxContextTokens: 2e5
914
+ }
915
+ }
916
+ ],
917
+ supportsModelListing: false,
918
+ docsUrl: "https://docs.z.ai/"
919
+ };
920
+ var ZaiAdapter = class extends OpenAIAdapter {
921
+ vendor = zaiManifest.vendor;
922
+ init(auth, client) {
923
+ super.init(
924
+ {
925
+ ...auth,
926
+ baseURL: auth.baseURL ?? "https://api.z.ai/api/paas/v4"
927
+ },
928
+ client
929
+ );
930
+ }
931
+ knownModels() {
932
+ return zaiManifest.knownModels;
933
+ }
934
+ };
935
+ var zaiFactory = {
936
+ vendor: zaiManifest.vendor,
937
+ manifest: zaiManifest,
938
+ create: () => new ZaiAdapter()
939
+ };
619
940
 
620
941
  // src/adapters/anthropic/adapter.ts
621
942
  import Anthropic from "@anthropic-ai/sdk";
@@ -2794,6 +3115,9 @@ var huggingfaceFactory = {
2794
3115
  // src/adapters/index.ts
2795
3116
  registerAdapter(openAIFactory);
2796
3117
  registerAdapter(deepseekFactory);
3118
+ registerAdapter(basetenFactory);
3119
+ registerAdapter(moonshotFactory);
3120
+ registerAdapter(zaiFactory);
2797
3121
  registerAdapter(anthropicFactory);
2798
3122
  registerAdapter(googleFactory);
2799
3123
  registerAdapter(vertexGeminiFactory);