@node-llm/core 1.1.0 → 1.2.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.
- package/dist/chat/ChatStream.d.ts.map +1 -1
- package/dist/chat/ChatStream.js +85 -34
- package/dist/config.d.ts +1 -1
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.js +2 -2
- package/dist/models/models.js +15 -15
- package/dist/providers/BaseProvider.d.ts +1 -1
- package/dist/providers/BaseProvider.js +1 -1
- package/dist/providers/Provider.d.ts +1 -0
- package/dist/providers/Provider.d.ts.map +1 -1
- package/dist/providers/anthropic/Chat.d.ts.map +1 -1
- package/dist/providers/anthropic/Chat.js +5 -1
- package/dist/providers/anthropic/Streaming.d.ts.map +1 -1
- package/dist/providers/anthropic/Streaming.js +49 -2
- package/dist/providers/deepseek/Chat.d.ts.map +1 -1
- package/dist/providers/deepseek/Chat.js +5 -4
- package/dist/providers/deepseek/Streaming.d.ts.map +1 -1
- package/dist/providers/deepseek/Streaming.js +49 -3
- package/dist/providers/gemini/Chat.d.ts.map +1 -1
- package/dist/providers/gemini/Chat.js +3 -0
- package/dist/providers/gemini/Embeddings.d.ts.map +1 -1
- package/dist/providers/gemini/Embeddings.js +3 -0
- package/dist/providers/gemini/Image.d.ts.map +1 -1
- package/dist/providers/gemini/Image.js +3 -0
- package/dist/providers/gemini/Streaming.d.ts.map +1 -1
- package/dist/providers/gemini/Streaming.js +32 -1
- package/dist/providers/gemini/Transcription.d.ts.map +1 -1
- package/dist/providers/gemini/Transcription.js +3 -0
- package/dist/providers/openai/Chat.d.ts.map +1 -1
- package/dist/providers/openai/Chat.js +5 -4
- package/dist/providers/openai/Embedding.d.ts.map +1 -1
- package/dist/providers/openai/Embedding.js +5 -1
- package/dist/providers/openai/Image.d.ts.map +1 -1
- package/dist/providers/openai/Image.js +5 -1
- package/dist/providers/openai/Moderation.d.ts.map +1 -1
- package/dist/providers/openai/Moderation.js +12 -6
- package/dist/providers/openai/Streaming.d.ts.map +1 -1
- package/dist/providers/openai/Streaming.js +53 -4
- package/dist/providers/openai/Transcription.d.ts.map +1 -1
- package/dist/providers/openai/Transcription.js +9 -2
- package/dist/providers/registry.js +1 -1
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +22 -0
- package/package.json +2 -2
|
@@ -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
|
|
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
|
|
74
|
-
const
|
|
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;
|
|
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;
|
|
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,
|
|
@@ -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;
|
|
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;
|
|
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;
|
|
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,
|
|
@@ -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;
|
|
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
|
-
|
|
29
|
-
|
|
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;
|
|
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
|
|
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;
|
|
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
|
|
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;
|
|
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
|
|
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
|
-
|
|
30
|
+
const json = await response.json();
|
|
31
|
+
logger.logResponse("OpenAI", response.status, response.statusText, json);
|
|
32
|
+
return json;
|
|
27
33
|
}
|
|
28
34
|
}
|
|
@@ -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;
|
|
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
|
|
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
|
|
78
|
-
|
|
79
|
-
|
|
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;
|
|
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"}
|
|
@@ -2,6 +2,7 @@ import { handleOpenAIError } from "./Errors.js";
|
|
|
2
2
|
import { AudioUtils } from "../../utils/audio.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 OpenAITranscription {
|
|
6
7
|
baseUrl;
|
|
7
8
|
apiKey;
|
|
@@ -30,7 +31,9 @@ export class OpenAITranscription {
|
|
|
30
31
|
if (request.language) {
|
|
31
32
|
formData.append("language", request.language);
|
|
32
33
|
}
|
|
33
|
-
const
|
|
34
|
+
const url = buildUrl(this.baseUrl, '/audio/transcriptions');
|
|
35
|
+
logger.logRequest("OpenAI", "POST", url, { model: request.model || DEFAULT_MODELS.TRANSCRIPTION, file: fileName });
|
|
36
|
+
const response = await fetch(url, {
|
|
34
37
|
method: "POST",
|
|
35
38
|
headers: {
|
|
36
39
|
"Authorization": `Bearer ${this.apiKey}`,
|
|
@@ -41,6 +44,7 @@ export class OpenAITranscription {
|
|
|
41
44
|
await handleOpenAIError(response, request.model || DEFAULT_MODELS.TRANSCRIPTION);
|
|
42
45
|
}
|
|
43
46
|
const json = (await response.json());
|
|
47
|
+
logger.logResponse("OpenAI", response.status, response.statusText, json);
|
|
44
48
|
return {
|
|
45
49
|
text: json.text,
|
|
46
50
|
model: json.model || request.model || DEFAULT_MODELS.TRANSCRIPTION,
|
|
@@ -120,7 +124,9 @@ export class OpenAITranscription {
|
|
|
120
124
|
}
|
|
121
125
|
]
|
|
122
126
|
};
|
|
123
|
-
const
|
|
127
|
+
const url = buildUrl(this.baseUrl, '/chat/completions');
|
|
128
|
+
logger.logRequest("OpenAI", "POST", url, body);
|
|
129
|
+
const response = await fetch(url, {
|
|
124
130
|
method: "POST",
|
|
125
131
|
headers: {
|
|
126
132
|
"Authorization": `Bearer ${this.apiKey}`,
|
|
@@ -132,6 +138,7 @@ export class OpenAITranscription {
|
|
|
132
138
|
await handleOpenAIError(response, actualModel);
|
|
133
139
|
}
|
|
134
140
|
const json = await response.json();
|
|
141
|
+
logger.logResponse("OpenAI", response.status, response.statusText, json);
|
|
135
142
|
const content = json.choices[0]?.message?.content || "";
|
|
136
143
|
let text = content;
|
|
137
144
|
let segments = [];
|
package/dist/utils/logger.d.ts
CHANGED
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
declare class Logger {
|
|
5
5
|
private isDebugEnabled;
|
|
6
6
|
debug(message: string, data?: any): void;
|
|
7
|
+
/**
|
|
8
|
+
* Log HTTP request details for debugging
|
|
9
|
+
*/
|
|
10
|
+
logRequest(provider: string, method: string, url: string, body?: any): void;
|
|
11
|
+
/**
|
|
12
|
+
* Log HTTP response details for debugging
|
|
13
|
+
*/
|
|
14
|
+
logResponse(provider: string, status: number, statusText: string, body?: any): void;
|
|
7
15
|
warn(message: string): void;
|
|
8
16
|
error(message: string, error?: Error): void;
|
|
9
17
|
info(message: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAM,MAAM;IACV,OAAO,CAAC,cAAc;IAItB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI;IAOxC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI3B,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI;IAI3C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAG5B;AAED,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAM,MAAM;IACV,OAAO,CAAC,cAAc;IAItB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI;IAOxC;;OAEG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI;IAS3E;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI;IASnF,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI3B,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI;IAI3C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAG5B;AAED,eAAO,MAAM,MAAM,QAAe,CAAC"}
|
package/dist/utils/logger.js
CHANGED
|
@@ -11,6 +11,28 @@ class Logger {
|
|
|
11
11
|
console.log(`[NodeLLM Debug] ${message}${formattedData}`);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Log HTTP request details for debugging
|
|
16
|
+
*/
|
|
17
|
+
logRequest(provider, method, url, body) {
|
|
18
|
+
if (this.isDebugEnabled()) {
|
|
19
|
+
console.log(`[NodeLLM] [${provider}] Request: ${method} ${url}`);
|
|
20
|
+
if (body) {
|
|
21
|
+
console.log(JSON.stringify(body, null, 2));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Log HTTP response details for debugging
|
|
27
|
+
*/
|
|
28
|
+
logResponse(provider, status, statusText, body) {
|
|
29
|
+
if (this.isDebugEnabled()) {
|
|
30
|
+
console.log(`[NodeLLM] [${provider}] Response: ${status} ${statusText}`);
|
|
31
|
+
if (body) {
|
|
32
|
+
console.log(JSON.stringify(body, null, 2));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
14
36
|
warn(message) {
|
|
15
37
|
console.warn(`[NodeLLM] ${message}`);
|
|
16
38
|
}
|