@threaded/ai 1.0.8 → 1.0.9

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
@@ -376,6 +376,16 @@ var generateImage = async (model2, prompt, config) => {
376
376
  };
377
377
 
378
378
  // src/providers/openai.ts
379
+ var getApiKey2 = (configApiKey) => {
380
+ if (configApiKey) return configApiKey;
381
+ try {
382
+ return getKey("openai");
383
+ } catch {
384
+ const key = process.env.OPENAI_API_KEY || "";
385
+ if (!key) throw new Error("OpenAI API key not found");
386
+ return key;
387
+ }
388
+ };
379
389
  var appendToolCalls = (toolCalls, tcchunklist) => {
380
390
  for (const tcchunk of tcchunklist) {
381
391
  while (toolCalls.length <= tcchunk.index) {
@@ -394,10 +404,7 @@ var appendToolCalls = (toolCalls, tcchunklist) => {
394
404
  };
395
405
  var callOpenAI = async (config, ctx) => {
396
406
  const { model: model2, instructions, schema, apiKey: configApiKey } = config;
397
- const apiKey = configApiKey || getKey("openai") || process.env.OPENAI_API_KEY;
398
- if (!apiKey) {
399
- throw new Error("OpenAI API key not found");
400
- }
407
+ const apiKey = getApiKey2(configApiKey);
401
408
  const messages = [];
402
409
  if (instructions) {
403
410
  messages.push({ role: "system", content: instructions });
@@ -510,6 +517,16 @@ var handleOpenAIStream = async (response, ctx) => {
510
517
  };
511
518
 
512
519
  // src/providers/anthropic.ts
520
+ var getApiKey3 = (configApiKey) => {
521
+ if (configApiKey) return configApiKey;
522
+ try {
523
+ return getKey("anthropic");
524
+ } catch {
525
+ const key = process.env.ANTHROPIC_API_KEY || "";
526
+ if (!key) throw new Error("Anthropic API key not found");
527
+ return key;
528
+ }
529
+ };
513
530
  var convertToAnthropicFormat = (messages) => {
514
531
  const result = [];
515
532
  let i = 0;
@@ -561,10 +578,7 @@ var convertToAnthropicFormat = (messages) => {
561
578
  };
562
579
  var callAnthropic = async (config, ctx) => {
563
580
  const { model: model2, instructions, schema, apiKey: configApiKey } = config;
564
- const apiKey = configApiKey || getKey("anthropic") || process.env.ANTHROPIC_API_KEY;
565
- if (!apiKey) {
566
- throw new Error("Anthropic API key not found");
567
- }
581
+ const apiKey = getApiKey3(configApiKey);
568
582
  let system = instructions;
569
583
  if (ctx.history[0]?.role === "system") {
570
584
  system = ctx.history[0].content;
@@ -709,12 +723,19 @@ var handleAnthropicStream = async (response, ctx) => {
709
723
  };
710
724
 
711
725
  // src/providers/google.ts
726
+ var getApiKey4 = (configApiKey) => {
727
+ if (configApiKey) return configApiKey;
728
+ try {
729
+ return getKey("google");
730
+ } catch {
731
+ const key = process.env.GEMINI_API_KEY || process.env.GOOGLE_AI_API_KEY || "";
732
+ if (!key) throw new Error("Google API key not found");
733
+ return key;
734
+ }
735
+ };
712
736
  var callGoogle = async (config, ctx) => {
713
737
  const { model: model2, instructions, apiKey: configApiKey } = config;
714
- const apiKey = configApiKey || getKey("google") || process.env.GOOGLE_AI_API_KEY;
715
- if (!apiKey) {
716
- throw new Error("Google API key not found");
717
- }
738
+ const apiKey = getApiKey4(configApiKey);
718
739
  const contents = [];
719
740
  if (instructions) {
720
741
  contents.push({
@@ -860,6 +881,147 @@ var callHuggingFace = async (config, ctx) => {
860
881
  );
861
882
  };
862
883
 
884
+ // src/providers/xai.ts
885
+ var appendToolCalls2 = (toolCalls, tcchunklist) => {
886
+ for (const tcchunk of tcchunklist) {
887
+ while (toolCalls.length <= tcchunk.index) {
888
+ toolCalls.push({
889
+ id: "",
890
+ type: "function",
891
+ function: { name: "", arguments: "" }
892
+ });
893
+ }
894
+ const tc = toolCalls[tcchunk.index];
895
+ tc.id += tcchunk.id || "";
896
+ tc.function.name += tcchunk.function?.name || "";
897
+ tc.function.arguments += tcchunk.function?.arguments || "";
898
+ }
899
+ return toolCalls;
900
+ };
901
+ var getApiKey5 = (configApiKey) => {
902
+ if (configApiKey) return configApiKey;
903
+ try {
904
+ return getKey("xai");
905
+ } catch {
906
+ const key = process.env.XAI_API_KEY || "";
907
+ if (!key) throw new Error("xAI API key not found");
908
+ return key;
909
+ }
910
+ };
911
+ var callXAI = async (config, ctx) => {
912
+ const { model: model2, instructions, schema, apiKey: configApiKey } = config;
913
+ const apiKey = getApiKey5(configApiKey);
914
+ const messages = [];
915
+ if (instructions) {
916
+ messages.push({ role: "system", content: instructions });
917
+ }
918
+ messages.push(...ctx.history);
919
+ const body = {
920
+ model: model2,
921
+ messages,
922
+ stream: !!ctx.stream
923
+ };
924
+ if (schema) {
925
+ body.response_format = {
926
+ type: "json_schema",
927
+ json_schema: {
928
+ name: schema.name,
929
+ schema: { ...schema.schema, additionalProperties: false },
930
+ strict: true
931
+ }
932
+ };
933
+ }
934
+ if (ctx.tools && ctx.tools.length > 0) {
935
+ body.tools = ctx.tools;
936
+ body.tool_choice = "auto";
937
+ }
938
+ const response = await fetch("https://api.x.ai/v1/chat/completions", {
939
+ method: "POST",
940
+ headers: {
941
+ "Content-Type": "application/json",
942
+ Authorization: `Bearer ${apiKey}`
943
+ },
944
+ body: JSON.stringify(body),
945
+ signal: ctx.abortSignal
946
+ });
947
+ if (!response.ok) {
948
+ const error = await response.text();
949
+ throw new Error(`xAI API error: ${error}`);
950
+ }
951
+ if (ctx.stream) {
952
+ return handleXAIStream(response, ctx);
953
+ }
954
+ const data = await response.json();
955
+ const choice = data.choices[0];
956
+ const { message } = choice;
957
+ const msg = {
958
+ role: "assistant",
959
+ content: message.content || ""
960
+ };
961
+ if (message.tool_calls) {
962
+ msg.tool_calls = message.tool_calls;
963
+ }
964
+ return {
965
+ ...ctx,
966
+ lastResponse: msg,
967
+ history: [...ctx.history, msg]
968
+ };
969
+ };
970
+ var handleXAIStream = async (response, ctx) => {
971
+ const reader = response.body.getReader();
972
+ const decoder = new TextDecoder();
973
+ let fullContent = "";
974
+ let toolCalls = [];
975
+ let buffer = "";
976
+ try {
977
+ while (true) {
978
+ if (ctx.abortSignal?.aborted) {
979
+ break;
980
+ }
981
+ const { done, value } = await reader.read();
982
+ if (done) break;
983
+ buffer += decoder.decode(value, { stream: true });
984
+ const lines = buffer.split("\n");
985
+ buffer = lines.pop() || "";
986
+ for (const line of lines) {
987
+ if (line.startsWith("data: ")) {
988
+ const data = line.slice(6).trim();
989
+ if (data === "[DONE]") continue;
990
+ if (!data) continue;
991
+ try {
992
+ const parsed = JSON.parse(data);
993
+ const delta = parsed.choices?.[0]?.delta;
994
+ if (delta?.content) {
995
+ fullContent += delta.content;
996
+ if (ctx.stream) {
997
+ ctx.stream({ type: "content", content: delta.content });
998
+ }
999
+ }
1000
+ if (delta?.tool_calls) {
1001
+ toolCalls = appendToolCalls2(toolCalls, delta.tool_calls);
1002
+ }
1003
+ } catch (e) {
1004
+ }
1005
+ }
1006
+ }
1007
+ }
1008
+ } finally {
1009
+ reader.releaseLock();
1010
+ }
1011
+ const msg = {
1012
+ role: "assistant",
1013
+ content: fullContent
1014
+ };
1015
+ if (toolCalls.length > 0) {
1016
+ msg.tool_calls = toolCalls;
1017
+ }
1018
+ return {
1019
+ ...ctx,
1020
+ lastResponse: msg,
1021
+ history: [...ctx.history, msg]
1022
+ };
1023
+ };
1024
+
863
1025
  // src/providers/index.ts
864
1026
  var callProvider = async (config, ctx) => {
865
1027
  const { provider, model: model2 } = parseModelName(config.model);
@@ -871,6 +1033,8 @@ var callProvider = async (config, ctx) => {
871
1033
  return callAnthropic(providerConfig, ctx);
872
1034
  case "google":
873
1035
  return callGoogle(providerConfig, ctx);
1036
+ case "xai":
1037
+ return callXAI(providerConfig, ctx);
874
1038
  case "huggingface":
875
1039
  default:
876
1040
  return callHuggingFace(providerConfig, ctx);