@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.cjs CHANGED
@@ -159,12 +159,18 @@ async function* streamFromOpenAI(client, req, options) {
159
159
  let usage;
160
160
  let finalFinishReason = null;
161
161
  let finalRawReason;
162
+ let sawContent = false;
162
163
  try {
163
164
  for await (const chunk of stream) {
164
165
  if (req.signal?.aborted) {
165
166
  yield { type: "end", finishReason: "aborted" };
166
167
  return;
167
168
  }
169
+ const chunkError = chunk.error;
170
+ if (chunkError) {
171
+ const message = chunkError && typeof chunkError === "object" && "message" in chunkError ? String(chunkError.message) : JSON.stringify(chunkError);
172
+ throw new Error(`OpenAI-compatible stream returned an error: ${message}`);
173
+ }
168
174
  if (chunk.usage) {
169
175
  usage = {
170
176
  ...chunk.usage.prompt_tokens !== void 0 ? { inputTokens: chunk.usage.prompt_tokens } : {},
@@ -178,6 +184,7 @@ async function* streamFromOpenAI(client, req, options) {
178
184
  const finishReason = choice.finish_reason;
179
185
  if (delta?.content) {
180
186
  if (t2 === void 0) t2 = process.hrtime.bigint();
187
+ sawContent = true;
181
188
  yield { type: "token", text: delta.content };
182
189
  }
183
190
  if (delta?.tool_calls) {
@@ -235,6 +242,12 @@ async function* streamFromOpenAI(client, req, options) {
235
242
  }
236
243
  throw err;
237
244
  }
245
+ const producedNothing = finalFinishReason === null && !sawContent && toolCallsEmitted.size === 0 && startedIds.size === 0 && usage === void 0;
246
+ if (producedNothing) {
247
+ throw new Error(
248
+ "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."
249
+ );
250
+ }
238
251
  const endEvent = {
239
252
  type: "end",
240
253
  finishReason: finalFinishReason ?? "stop",
@@ -540,7 +553,7 @@ var OpenAIAdapter = class {
540
553
  }
541
554
  stream(req) {
542
555
  return streamFromOpenAI(this.ensureClient(), req, {
543
- knownModels: openAIManifest.knownModels,
556
+ knownModels: this.knownModels(),
544
557
  vendorMetadataExtractor: OPENAI_METADATA_EXTRACTOR
545
558
  });
546
559
  }
@@ -551,7 +564,16 @@ var OpenAIAdapter = class {
551
564
  return appendOpenAIToolResult(history, toolCallId, result);
552
565
  }
553
566
  async listAvailableModels() {
554
- return listOpenAICompatibleModels(this.ensureClient(), openAIManifest.knownModels);
567
+ return listOpenAICompatibleModels(this.ensureClient(), this.knownModels());
568
+ }
569
+ /**
570
+ * Capability table used to enrich both `stream()` (for tools/vision gating)
571
+ * and `listAvailableModels()` (for filling capability flags on live entries).
572
+ * Subclasses backed by the same OpenAI wire (DeepSeek, Baseten, …) override
573
+ * this so their own manifest entries are consulted instead of OpenAI's.
574
+ */
575
+ knownModels() {
576
+ return openAIManifest.knownModels;
555
577
  }
556
578
  async testCredential() {
557
579
  await this.ensureClient().models.list();
@@ -662,12 +684,311 @@ var DeepSeekAdapter = class extends OpenAIAdapter {
662
684
  client
663
685
  );
664
686
  }
687
+ knownModels() {
688
+ return deepseekManifest.knownModels;
689
+ }
665
690
  };
666
691
  var deepseekFactory = {
667
692
  vendor: deepseekManifest.vendor,
668
693
  manifest: deepseekManifest,
669
694
  create: () => new DeepSeekAdapter()
670
695
  };
696
+ var basetenManifest = {
697
+ vendor: "baseten",
698
+ displayName: "Baseten",
699
+ authKinds: [
700
+ {
701
+ kind: "apiKey",
702
+ displayName: "API Key",
703
+ fields: [
704
+ {
705
+ name: "apiKey",
706
+ label: "API Key",
707
+ type: "password",
708
+ required: true,
709
+ help: "Get an API key from https://app.baseten.co/settings/api_keys"
710
+ },
711
+ {
712
+ name: "baseURL",
713
+ label: "Base URL",
714
+ type: "url",
715
+ required: false,
716
+ default: "https://inference.baseten.co/v1",
717
+ help: "Defaults to Baseten Model APIs. Set to https://bridge.baseten.co/v1/direct to route to a dedicated deployment."
718
+ }
719
+ ]
720
+ }
721
+ ],
722
+ knownModels: [
723
+ {
724
+ id: "deepseek-ai/DeepSeek-V3.1",
725
+ displayName: "DeepSeek V3.1",
726
+ capabilities: {
727
+ streaming: true,
728
+ tools: true,
729
+ vision: false,
730
+ systemPrompt: true,
731
+ maxContextTokens: 163840
732
+ }
733
+ },
734
+ {
735
+ id: "deepseek-ai/DeepSeek-V4-Pro",
736
+ displayName: "DeepSeek V4 Pro",
737
+ capabilities: {
738
+ streaming: true,
739
+ tools: true,
740
+ vision: false,
741
+ systemPrompt: true,
742
+ maxContextTokens: 131072
743
+ }
744
+ },
745
+ {
746
+ id: "zai-org/GLM-4.7",
747
+ displayName: "GLM 4.7",
748
+ capabilities: {
749
+ streaming: true,
750
+ tools: true,
751
+ vision: false,
752
+ systemPrompt: true,
753
+ maxContextTokens: 2e5
754
+ }
755
+ },
756
+ {
757
+ id: "zai-org/GLM-5",
758
+ displayName: "GLM 5",
759
+ capabilities: {
760
+ streaming: true,
761
+ tools: true,
762
+ vision: false,
763
+ systemPrompt: true,
764
+ maxContextTokens: 202800
765
+ }
766
+ },
767
+ {
768
+ id: "moonshotai/Kimi-K2.5",
769
+ displayName: "Kimi K2.5",
770
+ capabilities: {
771
+ streaming: true,
772
+ tools: true,
773
+ vision: true,
774
+ systemPrompt: true,
775
+ maxContextTokens: 262e3
776
+ }
777
+ },
778
+ {
779
+ id: "moonshotai/Kimi-K2.6",
780
+ displayName: "Kimi K2.6",
781
+ capabilities: {
782
+ streaming: true,
783
+ tools: true,
784
+ vision: true,
785
+ systemPrompt: true,
786
+ maxContextTokens: 262e3
787
+ }
788
+ },
789
+ {
790
+ id: "MiniMaxAI/MiniMax-M2.5",
791
+ displayName: "MiniMax M2.5",
792
+ capabilities: {
793
+ streaming: true,
794
+ tools: true,
795
+ vision: false,
796
+ systemPrompt: true,
797
+ maxContextTokens: 204e3
798
+ }
799
+ },
800
+ {
801
+ id: "nvidia/Nemotron-120B-A12B",
802
+ displayName: "Nemotron Super",
803
+ capabilities: {
804
+ streaming: true,
805
+ tools: true,
806
+ vision: false,
807
+ systemPrompt: true,
808
+ maxContextTokens: 202800
809
+ }
810
+ },
811
+ {
812
+ id: "openai/gpt-oss-120b",
813
+ displayName: "OpenAI GPT 120B",
814
+ capabilities: {
815
+ streaming: true,
816
+ tools: true,
817
+ vision: false,
818
+ systemPrompt: true,
819
+ maxContextTokens: 128072
820
+ }
821
+ }
822
+ ],
823
+ supportsModelListing: true,
824
+ docsUrl: "https://docs.baseten.co/inference/model-apis/overview"
825
+ };
826
+ var BasetenAdapter = class extends OpenAIAdapter {
827
+ vendor = basetenManifest.vendor;
828
+ init(auth, client) {
829
+ super.init(
830
+ {
831
+ ...auth,
832
+ baseURL: auth.baseURL ?? "https://inference.baseten.co/v1"
833
+ },
834
+ client
835
+ );
836
+ }
837
+ knownModels() {
838
+ return basetenManifest.knownModels;
839
+ }
840
+ };
841
+ var basetenFactory = {
842
+ vendor: basetenManifest.vendor,
843
+ manifest: basetenManifest,
844
+ create: () => new BasetenAdapter()
845
+ };
846
+ var moonshotManifest = {
847
+ vendor: "moonshot",
848
+ displayName: "Moonshot (Kimi)",
849
+ authKinds: [
850
+ {
851
+ kind: "apiKey",
852
+ displayName: "API Key",
853
+ fields: [
854
+ {
855
+ name: "apiKey",
856
+ label: "API Key",
857
+ type: "password",
858
+ required: true,
859
+ help: "Get an API key from https://platform.moonshot.ai/console/api-keys"
860
+ },
861
+ {
862
+ name: "baseURL",
863
+ label: "Base URL",
864
+ type: "url",
865
+ required: false,
866
+ default: "https://api.moonshot.ai/v1",
867
+ help: "Defaults to the global endpoint. Set to https://api.moonshot.cn/v1 for the China endpoint."
868
+ }
869
+ ]
870
+ }
871
+ ],
872
+ knownModels: [
873
+ {
874
+ id: "kimi-k2.6",
875
+ displayName: "Kimi K2.6",
876
+ capabilities: {
877
+ streaming: true,
878
+ tools: true,
879
+ vision: true,
880
+ systemPrompt: true,
881
+ maxContextTokens: 262144
882
+ }
883
+ },
884
+ {
885
+ id: "kimi-k2.5",
886
+ displayName: "Kimi K2.5",
887
+ capabilities: {
888
+ streaming: true,
889
+ tools: true,
890
+ vision: true,
891
+ systemPrompt: true,
892
+ maxContextTokens: 262144
893
+ }
894
+ }
895
+ ],
896
+ supportsModelListing: true,
897
+ docsUrl: "https://platform.moonshot.ai/docs"
898
+ };
899
+ var MoonshotAdapter = class extends OpenAIAdapter {
900
+ vendor = moonshotManifest.vendor;
901
+ init(auth, client) {
902
+ super.init(
903
+ {
904
+ ...auth,
905
+ baseURL: auth.baseURL ?? "https://api.moonshot.ai/v1"
906
+ },
907
+ client
908
+ );
909
+ }
910
+ knownModels() {
911
+ return moonshotManifest.knownModels;
912
+ }
913
+ };
914
+ var moonshotFactory = {
915
+ vendor: moonshotManifest.vendor,
916
+ manifest: moonshotManifest,
917
+ create: () => new MoonshotAdapter()
918
+ };
919
+ var zaiManifest = {
920
+ vendor: "zai",
921
+ displayName: "Z.ai (GLM)",
922
+ authKinds: [
923
+ {
924
+ kind: "apiKey",
925
+ displayName: "API Key",
926
+ fields: [
927
+ {
928
+ name: "apiKey",
929
+ label: "API Key",
930
+ type: "password",
931
+ required: true,
932
+ help: "Get an API key from https://z.ai/manage-apikey/apikey-list"
933
+ },
934
+ {
935
+ name: "baseURL",
936
+ label: "Base URL",
937
+ type: "url",
938
+ required: false,
939
+ default: "https://api.z.ai/api/paas/v4",
940
+ help: "Defaults to the general API. Coding-Plan keys must use https://api.z.ai/api/coding/paas/v4."
941
+ }
942
+ ]
943
+ }
944
+ ],
945
+ knownModels: [
946
+ {
947
+ id: "glm-5.2",
948
+ displayName: "GLM-5.2",
949
+ capabilities: {
950
+ streaming: true,
951
+ tools: true,
952
+ vision: false,
953
+ systemPrompt: true,
954
+ maxContextTokens: 1e6
955
+ }
956
+ },
957
+ {
958
+ id: "glm-4.7",
959
+ displayName: "GLM-4.7",
960
+ capabilities: {
961
+ streaming: true,
962
+ tools: true,
963
+ vision: false,
964
+ systemPrompt: true,
965
+ maxContextTokens: 2e5
966
+ }
967
+ }
968
+ ],
969
+ supportsModelListing: false,
970
+ docsUrl: "https://docs.z.ai/"
971
+ };
972
+ var ZaiAdapter = class extends OpenAIAdapter {
973
+ vendor = zaiManifest.vendor;
974
+ init(auth, client) {
975
+ super.init(
976
+ {
977
+ ...auth,
978
+ baseURL: auth.baseURL ?? "https://api.z.ai/api/paas/v4"
979
+ },
980
+ client
981
+ );
982
+ }
983
+ knownModels() {
984
+ return zaiManifest.knownModels;
985
+ }
986
+ };
987
+ var zaiFactory = {
988
+ vendor: zaiManifest.vendor,
989
+ manifest: zaiManifest,
990
+ create: () => new ZaiAdapter()
991
+ };
671
992
 
672
993
  // src/adapters/anthropic/adapter.ts
673
994
  var import_sdk = __toESM(require("@anthropic-ai/sdk"), 1);
@@ -2840,6 +3161,9 @@ var huggingfaceFactory = {
2840
3161
  // src/adapters/index.ts
2841
3162
  registerAdapter(openAIFactory);
2842
3163
  registerAdapter(deepseekFactory);
3164
+ registerAdapter(basetenFactory);
3165
+ registerAdapter(moonshotFactory);
3166
+ registerAdapter(zaiFactory);
2843
3167
  registerAdapter(anthropicFactory);
2844
3168
  registerAdapter(googleFactory);
2845
3169
  registerAdapter(vertexGeminiFactory);
@@ -2862,6 +3186,11 @@ function normalizeAuth(vendor, raw) {
2862
3186
  ...requireApiKey(vendor, raw),
2863
3187
  baseURL: raw.api_url ?? "https://api.deepseek.com/v1"
2864
3188
  };
3189
+ case "baseten":
3190
+ return {
3191
+ ...requireApiKey(vendor, raw),
3192
+ baseURL: raw.api_url ?? "https://inference.baseten.co/v1"
3193
+ };
2865
3194
  case "google":
2866
3195
  return normalizeGoogle(raw);
2867
3196
  case "vertex":