@node-llm/core 1.1.0 → 1.3.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.
Files changed (75) hide show
  1. package/README.md +243 -0
  2. package/dist/chat/Chat.d.ts +11 -8
  3. package/dist/chat/Chat.d.ts.map +1 -1
  4. package/dist/chat/Chat.js +24 -14
  5. package/dist/chat/ChatOptions.d.ts +2 -2
  6. package/dist/chat/ChatOptions.d.ts.map +1 -1
  7. package/dist/chat/ChatStream.d.ts.map +1 -1
  8. package/dist/chat/ChatStream.js +85 -34
  9. package/dist/chat/Tool.d.ts +35 -1
  10. package/dist/chat/Tool.d.ts.map +1 -1
  11. package/dist/chat/Tool.js +38 -1
  12. package/dist/config.d.ts +1 -1
  13. package/dist/errors/index.d.ts +2 -2
  14. package/dist/errors/index.js +3 -3
  15. package/dist/llm.d.ts +27 -15
  16. package/dist/llm.d.ts.map +1 -1
  17. package/dist/llm.js +37 -5
  18. package/dist/models/models.js +15 -15
  19. package/dist/providers/BaseProvider.d.ts +2 -1
  20. package/dist/providers/BaseProvider.d.ts.map +1 -1
  21. package/dist/providers/BaseProvider.js +4 -1
  22. package/dist/providers/Provider.d.ts +4 -2
  23. package/dist/providers/Provider.d.ts.map +1 -1
  24. package/dist/providers/anthropic/AnthropicProvider.d.ts +1 -0
  25. package/dist/providers/anthropic/AnthropicProvider.d.ts.map +1 -1
  26. package/dist/providers/anthropic/AnthropicProvider.js +3 -0
  27. package/dist/providers/anthropic/Chat.d.ts.map +1 -1
  28. package/dist/providers/anthropic/Chat.js +5 -1
  29. package/dist/providers/anthropic/Streaming.d.ts.map +1 -1
  30. package/dist/providers/anthropic/Streaming.js +49 -2
  31. package/dist/providers/deepseek/Chat.d.ts.map +1 -1
  32. package/dist/providers/deepseek/Chat.js +5 -4
  33. package/dist/providers/deepseek/DeepSeekProvider.d.ts +1 -0
  34. package/dist/providers/deepseek/DeepSeekProvider.d.ts.map +1 -1
  35. package/dist/providers/deepseek/DeepSeekProvider.js +3 -0
  36. package/dist/providers/deepseek/Streaming.d.ts.map +1 -1
  37. package/dist/providers/deepseek/Streaming.js +49 -3
  38. package/dist/providers/gemini/Chat.d.ts.map +1 -1
  39. package/dist/providers/gemini/Chat.js +3 -0
  40. package/dist/providers/gemini/Embeddings.d.ts.map +1 -1
  41. package/dist/providers/gemini/Embeddings.js +3 -0
  42. package/dist/providers/gemini/GeminiProvider.d.ts +1 -0
  43. package/dist/providers/gemini/GeminiProvider.d.ts.map +1 -1
  44. package/dist/providers/gemini/GeminiProvider.js +3 -0
  45. package/dist/providers/gemini/Image.d.ts.map +1 -1
  46. package/dist/providers/gemini/Image.js +3 -0
  47. package/dist/providers/gemini/Streaming.d.ts.map +1 -1
  48. package/dist/providers/gemini/Streaming.js +32 -1
  49. package/dist/providers/gemini/Transcription.d.ts.map +1 -1
  50. package/dist/providers/gemini/Transcription.js +3 -0
  51. package/dist/providers/ollama/OllamaProvider.d.ts +1 -0
  52. package/dist/providers/ollama/OllamaProvider.d.ts.map +1 -1
  53. package/dist/providers/ollama/OllamaProvider.js +3 -0
  54. package/dist/providers/openai/Chat.d.ts.map +1 -1
  55. package/dist/providers/openai/Chat.js +5 -4
  56. package/dist/providers/openai/Embedding.d.ts.map +1 -1
  57. package/dist/providers/openai/Embedding.js +5 -1
  58. package/dist/providers/openai/Image.d.ts.map +1 -1
  59. package/dist/providers/openai/Image.js +5 -1
  60. package/dist/providers/openai/Moderation.d.ts.map +1 -1
  61. package/dist/providers/openai/Moderation.js +12 -6
  62. package/dist/providers/openai/OpenAIProvider.d.ts +1 -0
  63. package/dist/providers/openai/OpenAIProvider.d.ts.map +1 -1
  64. package/dist/providers/openai/OpenAIProvider.js +3 -0
  65. package/dist/providers/openai/Streaming.d.ts.map +1 -1
  66. package/dist/providers/openai/Streaming.js +53 -4
  67. package/dist/providers/openai/Transcription.d.ts.map +1 -1
  68. package/dist/providers/openai/Transcription.js +9 -2
  69. package/dist/providers/registry.js +1 -1
  70. package/dist/utils/FileLoader.d.ts.map +1 -1
  71. package/dist/utils/FileLoader.js +2 -1
  72. package/dist/utils/logger.d.ts +9 -1
  73. package/dist/utils/logger.d.ts.map +1 -1
  74. package/dist/utils/logger.js +23 -1
  75. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"Streaming.d.ts","sourceRoot":"","sources":["../../../src/providers/deepseek/Streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGxD,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEtE,OAAO,CACZ,OAAO,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,eAAe,GAC3B,cAAc,CAAC,SAAS,CAAC;CA8G7B"}
1
+ {"version":3,"file":"Streaming.d.ts","sourceRoot":"","sources":["../../../src/providers/deepseek/Streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAIxD,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEtE,OAAO,CACZ,OAAO,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,eAAe,GAC3B,cAAc,CAAC,SAAS,CAAC;CA+J7B"}
@@ -1,4 +1,5 @@
1
1
  import { APIError } from "../../errors/index.js";
2
+ import { logger } from "../../utils/logger.js";
2
3
  export class DeepSeekStreaming {
3
4
  baseUrl;
4
5
  apiKey;
@@ -22,8 +23,12 @@ export class DeepSeekStreaming {
22
23
  if (response_format)
23
24
  body.response_format = response_format;
24
25
  let done = false;
26
+ // Track tool calls being built across chunks
27
+ const toolCallsMap = new Map();
25
28
  try {
26
- const response = await fetch(`${this.baseUrl}/chat/completions`, {
29
+ const url = `${this.baseUrl}/chat/completions`;
30
+ logger.logRequest("DeepSeek", "POST", url, body);
31
+ const response = await fetch(url, {
27
32
  method: "POST",
28
33
  headers: {
29
34
  "Authorization": `Bearer ${this.apiKey}`,
@@ -37,6 +42,7 @@ export class DeepSeekStreaming {
37
42
  const errorText = await response.text();
38
43
  throw new Error(`DeepSeek API error: ${response.status} - ${errorText}`);
39
44
  }
45
+ logger.debug("DeepSeek streaming started", { status: response.status, statusText: response.statusText });
40
46
  if (!response.body) {
41
47
  throw new Error("No response body for streaming");
42
48
  }
@@ -62,6 +68,18 @@ export class DeepSeekStreaming {
62
68
  const data = trimmed.replace("data: ", "").trim();
63
69
  if (data === "[DONE]") {
64
70
  done = true;
71
+ // Yield final tool calls if any were accumulated
72
+ if (toolCallsMap.size > 0) {
73
+ const toolCalls = Array.from(toolCallsMap.values()).map(tc => ({
74
+ id: tc.id,
75
+ type: "function",
76
+ function: {
77
+ name: tc.function.name,
78
+ arguments: tc.function.arguments
79
+ }
80
+ }));
81
+ yield { content: "", tool_calls: toolCalls, done: true };
82
+ }
65
83
  return;
66
84
  }
67
85
  try {
@@ -70,14 +88,42 @@ export class DeepSeekStreaming {
70
88
  if (json.error) {
71
89
  throw new APIError("DeepSeek", response.status, json.error.message || "Stream error");
72
90
  }
73
- const deltaContent = json.choices?.[0]?.delta?.content;
74
- const deltaReasoning = json.choices?.[0]?.delta?.reasoning_content;
91
+ const delta = json.choices?.[0]?.delta;
92
+ const deltaContent = delta?.content;
93
+ const deltaReasoning = delta?.reasoning_content;
75
94
  if (deltaContent || deltaReasoning) {
76
95
  yield {
77
96
  content: deltaContent || "",
78
97
  reasoning: deltaReasoning || ""
79
98
  };
80
99
  }
100
+ // Handle tool calls delta
101
+ if (delta?.tool_calls) {
102
+ for (const toolCallDelta of delta.tool_calls) {
103
+ const index = toolCallDelta.index;
104
+ if (!toolCallsMap.has(index)) {
105
+ toolCallsMap.set(index, {
106
+ id: toolCallDelta.id || "",
107
+ type: "function",
108
+ function: {
109
+ name: toolCallDelta.function?.name || "",
110
+ arguments: toolCallDelta.function?.arguments || ""
111
+ }
112
+ });
113
+ }
114
+ else {
115
+ const existing = toolCallsMap.get(index);
116
+ if (toolCallDelta.id)
117
+ existing.id = toolCallDelta.id;
118
+ if (toolCallDelta.function?.name) {
119
+ existing.function.name += toolCallDelta.function.name;
120
+ }
121
+ if (toolCallDelta.function?.arguments) {
122
+ existing.function.arguments += toolCallDelta.function.arguments;
123
+ }
124
+ }
125
+ }
126
+ }
81
127
  }
82
128
  catch (e) {
83
129
  // Re-throw APIError
@@ -1 +1 @@
1
- {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAS,MAAM,gBAAgB,CAAC;AAOlE,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAyF1D,OAAO,CAAC,cAAc;CAwBvB"}
1
+ {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAS,MAAM,gBAAgB,CAAC;AAQlE,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA4F1D,OAAO,CAAC,cAAc;CAwBvB"}
@@ -2,6 +2,7 @@ import { Capabilities } from "./Capabilities.js";
2
2
  import { handleGeminiError } from "./Errors.js";
3
3
  import { GeminiChatUtils } from "./ChatUtils.js";
4
4
  import { ModelRegistry } from "../../models/ModelRegistry.js";
5
+ import { logger } from "../../utils/logger.js";
5
6
  export class GeminiChat {
6
7
  baseUrl;
7
8
  apiKey;
@@ -49,6 +50,7 @@ export class GeminiChat {
49
50
  },
50
51
  ];
51
52
  }
53
+ logger.logRequest("Gemini", "POST", url, payload);
52
54
  const response = await fetch(url, {
53
55
  method: "POST",
54
56
  headers: {
@@ -60,6 +62,7 @@ export class GeminiChat {
60
62
  await handleGeminiError(response, request.model);
61
63
  }
62
64
  const json = (await response.json());
65
+ logger.logResponse("Gemini", response.status, response.statusText, json);
63
66
  const candidate = json.candidates?.[0];
64
67
  const content = candidate?.content?.parts
65
68
  ?.filter(p => p.text)
@@ -1 +1 @@
1
- {"version":3,"file":"Embeddings.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Embeddings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAIrE,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAwCrE"}
1
+ {"version":3,"file":"Embeddings.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Embeddings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAKrE,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA2CrE"}
@@ -1,4 +1,5 @@
1
1
  import { handleGeminiError } from "./Errors.js";
2
+ import { logger } from "../../utils/logger.js";
2
3
  export class GeminiEmbeddings {
3
4
  baseUrl;
4
5
  apiKey;
@@ -24,6 +25,7 @@ export class GeminiEmbeddings {
24
25
  return item;
25
26
  })
26
27
  };
28
+ logger.logRequest("Gemini", "POST", url, payload);
27
29
  const response = await fetch(url, {
28
30
  method: "POST",
29
31
  headers: { "Content-Type": "application/json" },
@@ -33,6 +35,7 @@ export class GeminiEmbeddings {
33
35
  await handleGeminiError(response, modelId);
34
36
  }
35
37
  const json = (await response.json());
38
+ logger.logResponse("Gemini", response.status, response.statusText, json);
36
39
  const vectors = json.embeddings?.map(e => e.values) || [];
37
40
  return {
38
41
  model: modelId,
@@ -28,6 +28,7 @@ export declare class GeminiProvider extends BaseProvider implements Provider {
28
28
  apiBase(): string;
29
29
  headers(): Record<string, string>;
30
30
  protected providerName(): string;
31
+ defaultModel(feature?: string): string;
31
32
  chat(request: ChatRequest): Promise<ChatResponse>;
32
33
  stream(request: ChatRequest): AsyncGenerator<ChatChunk>;
33
34
  listModels(): Promise<ModelInfo[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"GeminiProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/GeminiProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,SAAS,EACT,SAAS,EACT,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EAGrB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AASlD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAe,SAAQ,YAAa,YAAW,QAAQ;IAqBtD,OAAO,CAAC,QAAQ,CAAC,OAAO;IApBpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IACnD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAsB;IAEpD,YAAY;gCACO,MAAM;+BACP,MAAM;0CACK,MAAM;oCACZ,MAAM;yCACD,MAAM;uCACR,MAAM;oCACT,MAAM;oCACN,MAAM;kCACR,MAAM;MAChC;gBAE2B,OAAO,EAAE,qBAAqB;IAWpD,OAAO,IAAI,MAAM;IAIjB,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAMxC,SAAS,CAAC,YAAY,IAAI,MAAM;IAI1B,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAIhD,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC;IAIxD,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAIlC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAIpD,KAAK,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAI5D,UAAU,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAKhF"}
1
+ {"version":3,"file":"GeminiProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/GeminiProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,SAAS,EACT,SAAS,EACT,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EAGrB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AASlD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAe,SAAQ,YAAa,YAAW,QAAQ;IAqBtD,OAAO,CAAC,QAAQ,CAAC,OAAO;IApBpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IACnD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAsB;IAEpD,YAAY;gCACO,MAAM;+BACP,MAAM;0CACK,MAAM;oCACZ,MAAM;yCACD,MAAM;uCACR,MAAM;oCACT,MAAM;oCACN,MAAM;kCACR,MAAM;MAChC;gBAE2B,OAAO,EAAE,qBAAqB;IAWpD,OAAO,IAAI,MAAM;IAIjB,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAMxC,SAAS,CAAC,YAAY,IAAI,MAAM;IAIhB,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM;IAIhD,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAIhD,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC;IAIxD,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAIlC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAIpD,KAAK,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAI5D,UAAU,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAKhF"}
@@ -48,6 +48,9 @@ export class GeminiProvider extends BaseProvider {
48
48
  providerName() {
49
49
  return "Gemini";
50
50
  }
51
+ defaultModel(feature) {
52
+ return "gemini-2.0-flash-exp";
53
+ }
51
54
  async chat(request) {
52
55
  return this.chatHandler.execute(request);
53
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG7D,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;CA8C7D"}
1
+ {"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAI7D,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;CAiD7D"}
@@ -1,4 +1,5 @@
1
1
  import { handleGeminiError } from "./Errors.js";
2
+ import { logger } from "../../utils/logger.js";
2
3
  export class GeminiImage {
3
4
  baseUrl;
4
5
  apiKey;
@@ -22,6 +23,7 @@ export class GeminiImage {
22
23
  sampleCount: 1,
23
24
  },
24
25
  };
26
+ logger.logRequest("Gemini", "POST", url, body);
25
27
  const response = await fetch(url, {
26
28
  method: "POST",
27
29
  headers: {
@@ -33,6 +35,7 @@ export class GeminiImage {
33
35
  await handleGeminiError(response, modelId);
34
36
  }
35
37
  const json = await response.json();
38
+ logger.logResponse("Gemini", response.status, response.statusText, json);
36
39
  const imageData = json.predictions?.[0];
37
40
  if (!imageData || !imageData.bytesBase64Encoded) {
38
41
  throw new Error("Unexpected response format from Gemini image generation API");
@@ -1 +1 @@
1
- {"version":3,"file":"Streaming.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAMxD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEtE,OAAO,CACZ,OAAO,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,eAAe,GAC3B,cAAc,CAAC,SAAS,CAAC;IAuG5B,OAAO,CAAC,cAAc;CAwBvB"}
1
+ {"version":3,"file":"Streaming.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAOxD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEtE,OAAO,CACZ,OAAO,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,eAAe,GAC3B,cAAc,CAAC,SAAS,CAAC;IAyI5B,OAAO,CAAC,cAAc;CAwBvB"}
@@ -1,6 +1,7 @@
1
1
  import { Capabilities } from "./Capabilities.js";
2
2
  import { handleGeminiError } from "./Errors.js";
3
3
  import { GeminiChatUtils } from "./ChatUtils.js";
4
+ import { logger } from "../../utils/logger.js";
4
5
  export class GeminiStreaming {
5
6
  baseUrl;
6
7
  apiKey;
@@ -33,8 +34,21 @@ export class GeminiStreaming {
33
34
  if (systemInstructionParts.length > 0) {
34
35
  payload.systemInstruction = { parts: systemInstructionParts };
35
36
  }
37
+ if (request.tools && request.tools.length > 0) {
38
+ payload.tools = [
39
+ {
40
+ functionDeclarations: request.tools.map((t) => ({
41
+ name: t.function.name,
42
+ description: t.function.description,
43
+ parameters: t.function.parameters,
44
+ })),
45
+ },
46
+ ];
47
+ }
36
48
  let done = false;
49
+ const toolCalls = [];
37
50
  try {
51
+ logger.logRequest("Gemini", "POST", url, payload);
38
52
  const response = await fetch(url, {
39
53
  method: "POST",
40
54
  headers: {
@@ -46,6 +60,7 @@ export class GeminiStreaming {
46
60
  if (!response.ok) {
47
61
  await handleGeminiError(response, request.model);
48
62
  }
63
+ logger.debug("Gemini streaming started", { status: response.status, statusText: response.statusText });
49
64
  if (!response.body) {
50
65
  throw new Error("No response body for streaming");
51
66
  }
@@ -54,8 +69,13 @@ export class GeminiStreaming {
54
69
  let buffer = "";
55
70
  while (true) {
56
71
  const { value, done: readerDone } = await reader.read();
57
- if (readerDone)
72
+ if (readerDone) {
73
+ // Yield tool calls if any were collected
74
+ if (toolCalls.length > 0) {
75
+ yield { content: "", tool_calls: toolCalls, done: true };
76
+ }
58
77
  break;
78
+ }
59
79
  buffer += decoder.decode(value, { stream: true });
60
80
  let lineEnd;
61
81
  while ((lineEnd = buffer.indexOf("\n")) !== -1) {
@@ -76,6 +96,17 @@ export class GeminiStreaming {
76
96
  if (part.text) {
77
97
  yield { content: part.text };
78
98
  }
99
+ // Handle function calls
100
+ if (part.functionCall) {
101
+ toolCalls.push({
102
+ id: part.functionCall.name, // Gemini uses name as ID
103
+ type: "function",
104
+ function: {
105
+ name: part.functionCall.name,
106
+ arguments: JSON.stringify(part.functionCall.args || {})
107
+ }
108
+ });
109
+ }
79
110
  }
80
111
  }
81
112
  catch (e) {
@@ -1 +1 @@
1
- {"version":3,"file":"Transcription.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Transcription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAK7E,qBAAa,mBAAmB;IAGlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFrE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAA8E;gBAEvF,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CA2D7E"}
1
+ {"version":3,"file":"Transcription.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Transcription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAM7E,qBAAa,mBAAmB;IAGlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFrE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAA8E;gBAEvF,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CA8D7E"}
@@ -1,5 +1,6 @@
1
1
  import { handleGeminiError } from "./Errors.js";
2
2
  import { BinaryUtils } from "../../utils/Binary.js";
3
+ import { logger } from "../../utils/logger.js";
3
4
  export class GeminiTranscription {
4
5
  baseUrl;
5
6
  apiKey;
@@ -42,6 +43,7 @@ export class GeminiTranscription {
42
43
  responseMimeType: "text/plain",
43
44
  },
44
45
  };
46
+ logger.logRequest("Gemini", "POST", url, payload);
45
47
  const response = await fetch(url, {
46
48
  method: "POST",
47
49
  headers: {
@@ -53,6 +55,7 @@ export class GeminiTranscription {
53
55
  await handleGeminiError(response, model);
54
56
  }
55
57
  const json = (await response.json());
58
+ logger.logResponse("Gemini", response.status, response.statusText, json);
56
59
  const text = json.candidates?.[0]?.content?.parts?.map(p => p.text).join("") || "";
57
60
  return {
58
61
  text,
@@ -5,5 +5,6 @@ export interface OllamaProviderOptions {
5
5
  export declare class OllamaProvider extends OpenAIProvider {
6
6
  constructor(options?: OllamaProviderOptions);
7
7
  protected providerName(): string;
8
+ defaultModel(feature?: string): string;
8
9
  }
9
10
  //# sourceMappingURL=OllamaProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"OllamaProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/ollama/OllamaProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAM7D,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAe,SAAQ,cAAc;gBACpC,OAAO,GAAE,qBAA0B;IAwB/C,SAAS,CAAC,YAAY,IAAI,MAAM;CAGjC"}
1
+ {"version":3,"file":"OllamaProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/ollama/OllamaProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAM7D,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAe,SAAQ,cAAc;gBACpC,OAAO,GAAE,qBAA0B;IAwB/C,SAAS,CAAC,YAAY,IAAI,MAAM;IAIhB,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM;CAGvD"}
@@ -28,4 +28,7 @@ export class OllamaProvider extends OpenAIProvider {
28
28
  providerName() {
29
29
  return "Ollama";
30
30
  }
31
+ defaultModel(feature) {
32
+ return "llama3";
33
+ }
31
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAS,MAAM,gBAAgB,CAAC;AAOlE,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;CAsD3D"}
1
+ {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAS,MAAM,gBAAgB,CAAC;AAQlE,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;CAuD3D"}
@@ -2,6 +2,7 @@ import { Capabilities } from "./Capabilities.js";
2
2
  import { handleOpenAIError } from "./Errors.js";
3
3
  import { ModelRegistry } from "../../models/ModelRegistry.js";
4
4
  import { buildUrl } from "./utils.js";
5
+ import { logger } from "../../utils/logger.js";
5
6
  export class OpenAIChat {
6
7
  baseUrl;
7
8
  apiKey;
@@ -25,10 +26,9 @@ export class OpenAIChat {
25
26
  body.tools = tools;
26
27
  if (response_format)
27
28
  body.response_format = response_format;
28
- if (process.env.NODELLM_DEBUG === "true") {
29
- console.log(`[OpenAI Request] ${JSON.stringify(body, null, 2)}`);
30
- }
31
- const response = await fetch(buildUrl(this.baseUrl, '/chat/completions'), {
29
+ const url = buildUrl(this.baseUrl, '/chat/completions');
30
+ logger.logRequest("OpenAI", "POST", url, body);
31
+ const response = await fetch(url, {
32
32
  method: "POST",
33
33
  headers: {
34
34
  "Authorization": `Bearer ${this.apiKey}`,
@@ -41,6 +41,7 @@ export class OpenAIChat {
41
41
  await handleOpenAIError(response, request.model);
42
42
  }
43
43
  const json = (await response.json());
44
+ logger.logResponse("OpenAI", response.status, response.statusText, json);
44
45
  const message = json.choices[0]?.message;
45
46
  const content = message?.content ?? null;
46
47
  const tool_calls = message?.tool_calls;
@@ -1 +1 @@
1
- {"version":3,"file":"Embedding.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Embedding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAMrE,qBAAa,eAAe;IAExB,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM;IAClC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM;gBADd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM;IAGnC,SAAS,CAAC,eAAe,IAAI,MAAM;IAInC,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAMtC,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA2CrE"}
1
+ {"version":3,"file":"Embedding.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Embedding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAOrE,qBAAa,eAAe;IAExB,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM;IAClC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM;gBADd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM;IAGnC,SAAS,CAAC,eAAe,IAAI,MAAM;IAInC,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAMtC,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA+CrE"}
@@ -2,6 +2,7 @@ import { handleOpenAIError } from "./Errors.js";
2
2
  import { Capabilities } from "./Capabilities.js";
3
3
  import { DEFAULT_MODELS } from "../../constants.js";
4
4
  import { buildUrl } from "./utils.js";
5
+ import { logger } from "../../utils/logger.js";
5
6
  export class OpenAIEmbedding {
6
7
  baseUrl;
7
8
  apiKey;
@@ -30,7 +31,9 @@ export class OpenAIEmbedding {
30
31
  if (request.user) {
31
32
  body.user = request.user;
32
33
  }
33
- const response = await fetch(buildUrl(this.baseUrl, '/embeddings'), {
34
+ const url = buildUrl(this.baseUrl, '/embeddings');
35
+ logger.logRequest("OpenAI", "POST", url, body);
36
+ const response = await fetch(url, {
34
37
  method: "POST",
35
38
  headers: {
36
39
  "Authorization": `Bearer ${this.apiKey}`,
@@ -42,6 +45,7 @@ export class OpenAIEmbedding {
42
45
  await handleOpenAIError(response, request.model || DEFAULT_MODELS.EMBEDDING);
43
46
  }
44
47
  const { data, model: responseModel, usage } = await response.json();
48
+ logger.logResponse("OpenAI", response.status, response.statusText, { data, model: responseModel, usage });
45
49
  // Extract vectors from the response
46
50
  const vectors = data.map((item) => item.embedding);
47
51
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAI7D,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;CAmC7D"}
1
+ {"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAK7D,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;CAuC7D"}
@@ -1,5 +1,6 @@
1
1
  import { handleOpenAIError } from "./Errors.js";
2
2
  import { buildUrl } from "./utils.js";
3
+ import { logger } from "../../utils/logger.js";
3
4
  export class OpenAIImage {
4
5
  baseUrl;
5
6
  apiKey;
@@ -15,7 +16,9 @@ export class OpenAIImage {
15
16
  quality: request.quality || "standard",
16
17
  n: request.n || 1,
17
18
  };
18
- const response = await fetch(buildUrl(this.baseUrl, '/images/generations'), {
19
+ const url = buildUrl(this.baseUrl, '/images/generations');
20
+ logger.logRequest("OpenAI", "POST", url, body);
21
+ const response = await fetch(url, {
19
22
  method: "POST",
20
23
  headers: {
21
24
  "Authorization": `Bearer ${this.apiKey}`,
@@ -27,6 +30,7 @@ export class OpenAIImage {
27
30
  await handleOpenAIError(response, request.model);
28
31
  }
29
32
  const json = await response.json();
33
+ logger.logResponse("OpenAI", response.status, response.statusText, json);
30
34
  const data = json.data?.[0];
31
35
  if (!data) {
32
36
  throw new Error("OpenAI returned empty image response");
@@ -1 +1 @@
1
- {"version":3,"file":"Moderation.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Moderation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAKvE,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAmBvE"}
1
+ {"version":3,"file":"Moderation.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Moderation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAMvE,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CA0BvE"}
@@ -1,6 +1,7 @@
1
1
  import { handleOpenAIError } from "./Errors.js";
2
2
  import { DEFAULT_MODELS } from "../../constants.js";
3
3
  import { buildUrl } from "./utils.js";
4
+ import { logger } from "../../utils/logger.js";
4
5
  export class OpenAIModeration {
5
6
  baseUrl;
6
7
  apiKey;
@@ -9,20 +10,25 @@ export class OpenAIModeration {
9
10
  this.apiKey = apiKey;
10
11
  }
11
12
  async execute(request) {
12
- const response = await fetch(buildUrl(this.baseUrl, '/moderations'), {
13
+ const body = {
14
+ input: request.input,
15
+ model: request.model || DEFAULT_MODELS.MODERATION,
16
+ };
17
+ const url = buildUrl(this.baseUrl, '/moderations');
18
+ logger.logRequest("OpenAI", "POST", url, body);
19
+ const response = await fetch(url, {
13
20
  method: "POST",
14
21
  headers: {
15
22
  "Authorization": `Bearer ${this.apiKey}`,
16
23
  "Content-Type": "application/json",
17
24
  },
18
- body: JSON.stringify({
19
- input: request.input,
20
- model: request.model || DEFAULT_MODELS.MODERATION,
21
- }),
25
+ body: JSON.stringify(body),
22
26
  });
23
27
  if (!response.ok) {
24
28
  await handleOpenAIError(response, request.model || DEFAULT_MODELS.MODERATION);
25
29
  }
26
- return (await response.json());
30
+ const json = await response.json();
31
+ logger.logResponse("OpenAI", response.status, response.statusText, json);
32
+ return json;
27
33
  }
28
34
  }
@@ -37,6 +37,7 @@ export declare class OpenAIProvider extends BaseProvider implements Provider {
37
37
  apiBase(): string;
38
38
  headers(): Record<string, string>;
39
39
  protected providerName(): string;
40
+ defaultModel(feature?: string): string;
40
41
  chat(request: ChatRequest): Promise<ChatResponse>;
41
42
  stream(request: ChatRequest): AsyncGenerator<ChatChunk>;
42
43
  listModels(): Promise<ModelInfo[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"OpenAIProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/OpenAIProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACpM,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE7E,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAe,SAAQ,YAAa,YAAW,QAAQ;IAsBtD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,qBAAqB;IArB7D,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC;IAClC,SAAS,CAAC,gBAAgB,EAAE,eAAe,CAAC;IAC5C,SAAS,CAAC,aAAa,EAAE,YAAY,CAAC;IACtC,SAAS,CAAC,YAAY,EAAE,WAAW,CAAC;IACpC,SAAS,CAAC,oBAAoB,EAAE,mBAAmB,CAAC;IACpD,SAAS,CAAC,iBAAiB,EAAE,gBAAgB,CAAC;IAC9C,SAAS,CAAC,gBAAgB,EAAE,eAAe,CAAC;IAErC,YAAY;gCACO,MAAM;+BACP,MAAM;0CACK,MAAM;oCACZ,MAAM;yCACD,MAAM;uCACR,MAAM;oCACT,MAAM;mCACP,MAAM;kCACP,MAAM;MAChC;gBAE6B,OAAO,EAAE,qBAAqB;IAYtD,OAAO,IAAI,MAAM;IAIjB,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAOxC,SAAS,CAAC,YAAY,IAAI,MAAM;IAI1B,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAIhD,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC;IAIxD,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAIlC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAIpD,UAAU,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAIzE,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAIjE,KAAK,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAGnE"}
1
+ {"version":3,"file":"OpenAIProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/OpenAIProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACpM,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE7E,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAe,SAAQ,YAAa,YAAW,QAAQ;IAsBtD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,qBAAqB;IArB7D,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC;IAClC,SAAS,CAAC,gBAAgB,EAAE,eAAe,CAAC;IAC5C,SAAS,CAAC,aAAa,EAAE,YAAY,CAAC;IACtC,SAAS,CAAC,YAAY,EAAE,WAAW,CAAC;IACpC,SAAS,CAAC,oBAAoB,EAAE,mBAAmB,CAAC;IACpD,SAAS,CAAC,iBAAiB,EAAE,gBAAgB,CAAC;IAC9C,SAAS,CAAC,gBAAgB,EAAE,eAAe,CAAC;IAErC,YAAY;gCACO,MAAM;+BACP,MAAM;0CACK,MAAM;oCACZ,MAAM;yCACD,MAAM;uCACR,MAAM;oCACT,MAAM;mCACP,MAAM;kCACP,MAAM;MAChC;gBAE6B,OAAO,EAAE,qBAAqB;IAYtD,OAAO,IAAI,MAAM;IAIjB,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAOxC,SAAS,CAAC,YAAY,IAAI,MAAM;IAIhB,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM;IAIhD,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAIhD,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC;IAIxD,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAIlC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAIpD,UAAU,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAIzE,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAIjE,KAAK,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAGnE"}
@@ -52,6 +52,9 @@ export class OpenAIProvider extends BaseProvider {
52
52
  providerName() {
53
53
  return "OpenAI";
54
54
  }
55
+ defaultModel(feature) {
56
+ return "gpt-4o";
57
+ }
55
58
  async chat(request) {
56
59
  return this.chatHandler.execute(request);
57
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Streaming.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAMxD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEtE,OAAO,CACZ,OAAO,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,eAAe,GAC3B,cAAc,CAAC,SAAS,CAAC;CAgH7B"}
1
+ {"version":3,"file":"Streaming.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAOxD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEtE,OAAO,CACZ,OAAO,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,eAAe,GAC3B,cAAc,CAAC,SAAS,CAAC;CAqK7B"}
@@ -2,6 +2,7 @@ import { Capabilities } from "./Capabilities.js";
2
2
  import { handleOpenAIError } from "./Errors.js";
3
3
  import { buildUrl } from "./utils.js";
4
4
  import { APIError } from "../../errors/index.js";
5
+ import { logger } from "../../utils/logger.js";
5
6
  export class OpenAIStreaming {
6
7
  baseUrl;
7
8
  apiKey;
@@ -26,9 +27,16 @@ export class OpenAIStreaming {
26
27
  if (request.response_format) {
27
28
  body.response_format = request.response_format;
28
29
  }
30
+ if (request.tools && request.tools.length > 0) {
31
+ body.tools = request.tools;
32
+ }
29
33
  let done = false;
34
+ // Track tool calls being built across chunks
35
+ const toolCallsMap = new Map();
30
36
  try {
31
- const response = await fetch(buildUrl(this.baseUrl, '/chat/completions'), {
37
+ const url = buildUrl(this.baseUrl, '/chat/completions');
38
+ logger.logRequest("OpenAI", "POST", url, body);
39
+ const response = await fetch(url, {
32
40
  method: "POST",
33
41
  headers: {
34
42
  "Authorization": `Bearer ${this.apiKey}`,
@@ -41,6 +49,7 @@ export class OpenAIStreaming {
41
49
  if (!response.ok) {
42
50
  await handleOpenAIError(response, request.model);
43
51
  }
52
+ logger.debug("OpenAI streaming started", { status: response.status, statusText: response.statusText });
44
53
  if (!response.body) {
45
54
  throw new Error("No response body for streaming");
46
55
  }
@@ -66,6 +75,18 @@ export class OpenAIStreaming {
66
75
  const data = trimmed.replace("data: ", "").trim();
67
76
  if (data === "[DONE]") {
68
77
  done = true;
78
+ // Yield final tool calls if any were accumulated
79
+ if (toolCallsMap.size > 0) {
80
+ const toolCalls = Array.from(toolCallsMap.values()).map(tc => ({
81
+ id: tc.id,
82
+ type: "function",
83
+ function: {
84
+ name: tc.function.name,
85
+ arguments: tc.function.arguments
86
+ }
87
+ }));
88
+ yield { content: "", tool_calls: toolCalls, done: true };
89
+ }
69
90
  return;
70
91
  }
71
92
  try {
@@ -74,9 +95,37 @@ export class OpenAIStreaming {
74
95
  if (json.error) {
75
96
  throw new APIError("OpenAI", response.status, json.error.message || "Stream error");
76
97
  }
77
- const delta = json.choices?.[0]?.delta?.content;
78
- if (delta) {
79
- yield { content: delta };
98
+ const delta = json.choices?.[0]?.delta;
99
+ // Handle content delta
100
+ if (delta?.content) {
101
+ yield { content: delta.content };
102
+ }
103
+ // Handle tool calls delta
104
+ if (delta?.tool_calls) {
105
+ for (const toolCallDelta of delta.tool_calls) {
106
+ const index = toolCallDelta.index;
107
+ if (!toolCallsMap.has(index)) {
108
+ toolCallsMap.set(index, {
109
+ id: toolCallDelta.id || "",
110
+ type: "function",
111
+ function: {
112
+ name: toolCallDelta.function?.name || "",
113
+ arguments: toolCallDelta.function?.arguments || ""
114
+ }
115
+ });
116
+ }
117
+ else {
118
+ const existing = toolCallsMap.get(index);
119
+ if (toolCallDelta.id)
120
+ existing.id = toolCallDelta.id;
121
+ if (toolCallDelta.function?.name) {
122
+ existing.function.name += toolCallDelta.function.name;
123
+ }
124
+ if (toolCallDelta.function?.arguments) {
125
+ existing.function.arguments += toolCallDelta.function.arguments;
126
+ }
127
+ }
128
+ }
80
129
  }
81
130
  }
82
131
  catch (e) {
@@ -1 +1 @@
1
- {"version":3,"file":"Transcription.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Transcription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAM7E,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;YAU9D,oBAAoB;YA4CpB,iBAAiB;CAwHhC"}
1
+ {"version":3,"file":"Transcription.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Transcription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAO7E,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;YAU9D,oBAAoB;YAgDpB,iBAAiB;CA4HhC"}