@node-llm/core 1.5.2 → 1.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/README.md +42 -84
- package/dist/chat/Chat.d.ts +1 -0
- package/dist/chat/Chat.d.ts.map +1 -1
- package/dist/chat/Chat.js +9 -2
- package/dist/chat/ChatStream.d.ts.map +1 -1
- package/dist/chat/ChatStream.js +2 -1
- package/dist/chat/ToolHandler.d.ts.map +1 -1
- package/dist/chat/ToolHandler.js +2 -1
- package/dist/chat/Validation.d.ts.map +1 -1
- package/dist/chat/Validation.js +4 -3
- package/dist/llm.d.ts.map +1 -1
- package/dist/llm.js +5 -4
- package/dist/providers/gemini/Image.js +1 -1
- package/dist/providers/openai/Chat.d.ts.map +1 -1
- package/dist/providers/openai/Chat.js +2 -1
- package/dist/providers/openai/Streaming.js +1 -1
- package/dist/utils/Binary.d.ts.map +1 -1
- package/dist/utils/Binary.js +10 -11
- package/dist/utils/audio.js +1 -1
- package/dist/utils/fetch.d.ts.map +1 -1
- package/dist/utils/fetch.js +13 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<p align="left">
|
|
2
2
|
<a href="https://node-llm.eshaiju.com/">
|
|
3
|
-
<img src="
|
|
3
|
+
<img src="docs/assets/images/logo.jpg" alt="NodeLLM logo" width="300" />
|
|
4
4
|
</a>
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
# NodeLLM
|
|
8
8
|
|
|
9
|
-
**An
|
|
9
|
+
**An architectural layer for integrating Large Language Models in Node.js.**
|
|
10
10
|
|
|
11
11
|
**Provider-agnostic by design.**
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Integrating multiple LLM providers often means juggling different SDKs, API styles, and update cycles. NodeLLM provides a single, unified, production-oriented API for interacting with over 540+ models across multiple providers (OpenAI, Gemini, Anthropic, DeepSeek, OpenRouter, Ollama, etc.) that stays consistent even when providers change.
|
|
14
14
|
|
|
15
15
|
<p align="left">
|
|
16
16
|
<img src="https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/openai.svg" height="28" />
|
|
@@ -52,14 +52,14 @@ NodeLLM is **NOT**:
|
|
|
52
52
|
|
|
53
53
|
## 🏗️ Why NodeLLM?
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
Direct integrations often become tightly coupled to specific providers, making it difficult to adapt as models evolve. **LLMs should be treated as infrastructure**, and NodeLLM helps you build a stable foundation that persists regardless of which model is currently "state of the art."
|
|
56
56
|
|
|
57
|
-
NodeLLM
|
|
57
|
+
NodeLLM helps solve **architectural problems**, not just provide API access. It serves as the core integration layer for LLMs in the Node.js ecosystem.
|
|
58
58
|
|
|
59
59
|
### Strategic Goals
|
|
60
60
|
- **Provider Isolation**: Decouple your services from vendor SDKs.
|
|
61
|
-
- **Production-Ready**: Native support for streaming, retries, and unified error handling.
|
|
62
|
-
- **Predictable API**: Consistent behavior for Tools, Vision, and Structured Outputs across all models
|
|
61
|
+
- **Production-Ready**: Native support for streaming, automatic retries, and unified error handling.
|
|
62
|
+
- **Predictable API**: Consistent behavior for Tools, Vision, and Structured Outputs across all models, **now including full parity for streaming**.
|
|
63
63
|
|
|
64
64
|
---
|
|
65
65
|
|
|
@@ -68,7 +68,7 @@ NodeLLM exists to solve **architectural problems**, not just provide API access.
|
|
|
68
68
|
```ts
|
|
69
69
|
import { NodeLLM } from "@node-llm/core";
|
|
70
70
|
|
|
71
|
-
// 1. Configure once
|
|
71
|
+
// 1. Configure once (Safe for ESM + dotenv race conditions)
|
|
72
72
|
NodeLLM.configure({ provider: "openai" });
|
|
73
73
|
|
|
74
74
|
// 2. Chat (High-level request/response)
|
|
@@ -77,29 +77,37 @@ const response = await chat.ask("Explain event-driven architecture");
|
|
|
77
77
|
console.log(response.content);
|
|
78
78
|
|
|
79
79
|
// 3. Streaming (Standard AsyncIterator)
|
|
80
|
+
// NOW with full support for Tools, Vision, and Schemas!
|
|
80
81
|
for await (const chunk of chat.stream("Explain event-driven architecture")) {
|
|
81
82
|
process.stdout.write(chunk.content);
|
|
82
83
|
}
|
|
83
84
|
```
|
|
84
85
|
|
|
86
|
+
### 🎯 Real-World Example: Brand Perception Checker
|
|
87
|
+
|
|
88
|
+
Built with NodeLLM - Multi-provider AI analysis, tool calling, and structured outputs working together:
|
|
89
|
+
|
|
90
|
+
<p align="center">
|
|
91
|
+
<img src="assets/brand-perception-checker.png" alt="Brand Perception Checker" width="800" />
|
|
92
|
+
</p>
|
|
93
|
+
|
|
94
|
+
**[View Example →](examples/brand-perception-checker/)**
|
|
95
|
+
|
|
85
96
|
|
|
86
97
|
---
|
|
87
98
|
|
|
88
99
|
## 🔧 Strategic Configuration
|
|
89
100
|
|
|
90
|
-
NodeLLM provides a flexible configuration system designed for enterprise usage
|
|
101
|
+
NodeLLM provides a flexible, **lazy-initialized** configuration system designed for enterprise usage. It is safe for ESM and resolved only when your first request is made, eliminating the common `dotenv` race condition.
|
|
91
102
|
|
|
92
103
|
```ts
|
|
93
104
|
// Recommended for multi-provider pipelines
|
|
94
|
-
NodeLLM.configure(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
105
|
+
NodeLLM.configure({
|
|
106
|
+
openaiApiKey: process.env.OPENAI_API_KEY,
|
|
107
|
+
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
|
|
108
|
+
ollamaApiBase: process.env.OLLAMA_API_BASE,
|
|
98
109
|
});
|
|
99
110
|
|
|
100
|
-
// Switch providers at the framework level
|
|
101
|
-
NodeLLM.configure({ provider: "anthropic" });
|
|
102
|
-
|
|
103
111
|
// Support for Custom Endpoints (e.g., Azure or LocalAI)
|
|
104
112
|
NodeLLM.configure({
|
|
105
113
|
openaiApiKey: process.env.AZURE_KEY,
|
|
@@ -107,7 +115,7 @@ NodeLLM.configure({
|
|
|
107
115
|
});
|
|
108
116
|
```
|
|
109
117
|
|
|
110
|
-
**[Full Configuration Guide →](
|
|
118
|
+
**[Full Configuration Guide →](docs/getting_started/configuration.md)**
|
|
111
119
|
|
|
112
120
|
---
|
|
113
121
|
|
|
@@ -123,7 +131,7 @@ await chat.ask("Hello world");
|
|
|
123
131
|
```
|
|
124
132
|
|
|
125
133
|
### 👁️ Smart Vision & Files
|
|
126
|
-
Pass images, PDFs, or audio files directly
|
|
134
|
+
Pass images, PDFs, or audio files directly to **both `ask()` and `stream()`**. We handle the heavy lifting: fetching remote URLs, base64 encoding, and MIME type mapping.
|
|
127
135
|
```ts
|
|
128
136
|
await chat.ask("Analyze this interface", {
|
|
129
137
|
files: ["./screenshot.png", "https://example.com/spec.pdf"]
|
|
@@ -142,42 +150,18 @@ class WeatherTool extends Tool {
|
|
|
142
150
|
description = "Get current weather";
|
|
143
151
|
schema = z.object({ location: z.string() });
|
|
144
152
|
|
|
145
|
-
async
|
|
153
|
+
async execute({ location }) {
|
|
146
154
|
return `Sunny in ${location}`;
|
|
147
155
|
}
|
|
148
156
|
}
|
|
149
157
|
|
|
150
158
|
// Now the model can use it automatically
|
|
151
159
|
await chat.withTool(WeatherTool).ask("What's the weather in Tokyo?");
|
|
152
|
-
```
|
|
153
160
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
NodeLLM provides **defense-in-depth** security that you can configure globally or per-request:
|
|
158
|
-
|
|
159
|
-
```ts
|
|
160
|
-
// 1. Global config
|
|
161
|
-
NodeLLM.configure({
|
|
162
|
-
requestTimeout: 30000, // Timeout requests after 30 seconds (default)
|
|
163
|
-
maxToolCalls: 5, // Stop after 5 sequential tool execution turns
|
|
164
|
-
maxRetries: 2, // Retry provider-level errors up to 2 times
|
|
165
|
-
maxTokens: 4096 // Limit output to 4K tokens (default)
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
// 2. Per request override
|
|
169
|
-
await chat.ask("Deep search task", {
|
|
170
|
-
requestTimeout: 120000, // 2 minutes for this request
|
|
171
|
-
maxToolCalls: 10,
|
|
172
|
-
maxTokens: 8192 // 8K tokens for this request
|
|
173
|
-
});
|
|
161
|
+
// Lifecycle Hooks for Error & Flow Control
|
|
162
|
+
chat.onToolCallError((call, err) => "STOP");
|
|
174
163
|
```
|
|
175
|
-
|
|
176
|
-
**Security Benefits:**
|
|
177
|
-
- **`requestTimeout`**: Prevents DoS attacks and hanging requests
|
|
178
|
-
- **`maxToolCalls`**: Prevents infinite tool execution loops
|
|
179
|
-
- **`maxRetries`**: Prevents retry storms during outages
|
|
180
|
-
- **`maxTokens`**: Prevents excessive output and cost overruns
|
|
164
|
+
**[Full Tool Calling Guide →](https://node-llm.eshaiju.com/core-features/tool-calling)**
|
|
181
165
|
|
|
182
166
|
### 🔍 Comprehensive Debug Logging
|
|
183
167
|
Enable detailed logging for all API requests and responses across every feature and provider:
|
|
@@ -193,42 +177,6 @@ process.env.NODELLM_DEBUG = "true";
|
|
|
193
177
|
```
|
|
194
178
|
**Covers:** Chat, Streaming, Images, Embeddings, Transcription, Moderation - across all providers!
|
|
195
179
|
|
|
196
|
-
### 🛡️ Content Policy Hooks
|
|
197
|
-
NodeLLM provides pluggable hooks to implement custom security, compliance, and moderation logic. Instead of hard-coded rules, you can inject your own policies at the edge.
|
|
198
|
-
|
|
199
|
-
- **`beforeRequest()`**: Intercept and modify messages before they hit the LLM (e.g., PII detection/redaction).
|
|
200
|
-
- **`afterResponse()`**: Process the final response before it returns to your code (e.g., output masking or compliance checks).
|
|
201
|
-
|
|
202
|
-
```ts
|
|
203
|
-
chat
|
|
204
|
-
.beforeRequest(async (messages) => {
|
|
205
|
-
// Detect PII and redact
|
|
206
|
-
return redactSSN(messages);
|
|
207
|
-
})
|
|
208
|
-
.afterResponse(async (response) => {
|
|
209
|
-
// Ensure output compliance
|
|
210
|
-
return response.withContent(maskSensitiveData(response.content));
|
|
211
|
-
});
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### 🧱 Smart Context Isolation
|
|
215
|
-
Stop worrying about prompt injection or instruction drift. NodeLLM automatically separates system instructions from the conversation history, providing a higher level of protection and strictness.
|
|
216
|
-
|
|
217
|
-
- **Zero-Config Security**: Enabled by default for all chats. No special flags required.
|
|
218
|
-
- **Smart Model Mapping**: Automatically uses OpenAI's modern `developer` role for compatible models (GPT-4o, o1, o3) while safely falling back to the standard `system` role for older or local models (Ollama, DeepSeek, etc.).
|
|
219
|
-
- **Universal Context**: Instructions stay separated internally, ensuring they are always prioritized by the model and never accidentally overridden by user messages.
|
|
220
|
-
- **Provider Agnostic**: Write instructions once; NodeLLM handles the specific role requirements for every major provider (OpenAI, Anthropic, Gemini).
|
|
221
|
-
|
|
222
|
-
### 🔍 Observability & Tool Auditing
|
|
223
|
-
For enterprise compliance, NodeLLM provides deep visibility into the tool execution lifecycle. You can monitor, log, and audit every step of a tool's execution.
|
|
224
|
-
|
|
225
|
-
```ts
|
|
226
|
-
chat
|
|
227
|
-
.onToolCallStart((call) => log(`Starting tool: ${call.function.name}`))
|
|
228
|
-
.onToolCallEnd((call, res) => log(`Tool ${call.id} finished with: ${res}`))
|
|
229
|
-
.onToolCallError((call, err) => alert(`Tool ${call.function.name} failed: ${err.message}`));
|
|
230
|
-
```
|
|
231
|
-
|
|
232
180
|
### ✨ Structured Output
|
|
233
181
|
Get type-safe, validated JSON back using **Zod** schemas.
|
|
234
182
|
```ts
|
|
@@ -285,7 +233,7 @@ console.log(res.reasoning); // Chain-of-thought
|
|
|
285
233
|
|
|
286
234
|
| Provider | Supported Features |
|
|
287
235
|
| :--- | :--- |
|
|
288
|
-
| <img src="https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/openai.svg" height="18"> **OpenAI** | Chat, **Streaming + Tools**, Vision, Audio, Images, Transcription, **Reasoning
|
|
236
|
+
| <img src="https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/openai.svg" height="18"> **OpenAI** | Chat, **Streaming + Tools**, Vision, Audio, Images, Transcription, **Reasoning** |
|
|
289
237
|
| <img src="https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/gemini-color.svg" height="18"> **Gemini** | Chat, **Streaming + Tools**, Vision, Audio, Video, Embeddings |
|
|
290
238
|
| <img src="https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/anthropic-text.svg" height="12"> **Anthropic** | Chat, **Streaming + Tools**, Vision, PDF, Structured Output |
|
|
291
239
|
| <img src="https://registry.npmmirror.com/@lobehub/icons-static-svg/latest/files/icons/deepseek-color.svg" height="18"> **DeepSeek** | Chat (V3), **Reasoning (R1)**, **Streaming + Tools** |
|
|
@@ -302,11 +250,21 @@ npm install @node-llm/core
|
|
|
302
250
|
|
|
303
251
|
**[View Full Documentation ↗](https://node-llm.eshaiju.com/)**
|
|
304
252
|
|
|
253
|
+
### 🍿 Try the Live Demo
|
|
254
|
+
Want to see it in action? Run this in your terminal:
|
|
255
|
+
```bash
|
|
256
|
+
git clone https://github.com/node-llm/node-llm.git
|
|
257
|
+
cd node-llm
|
|
258
|
+
npm install
|
|
259
|
+
npm run demo
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
|
|
305
263
|
---
|
|
306
264
|
|
|
307
265
|
## 🤝 Contributing
|
|
308
266
|
|
|
309
|
-
We welcome contributions! Please see our **[Contributing Guide](
|
|
267
|
+
We welcome contributions! Please see our **[Contributing Guide](CONTRIBUTING.md)** for more details on how to get started.
|
|
310
268
|
|
|
311
269
|
---
|
|
312
270
|
|
package/dist/chat/Chat.d.ts
CHANGED
package/dist/chat/Chat.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../src/chat/Chat.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAA4C,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAGtE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAwB,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../src/chat/Chat.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAA4C,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAGtE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAwB,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAMpD,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,qBAAa,IAAI;IAMb,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,QAAQ,CAAC,OAAO;IAP1B,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAW;gBAGR,QAAQ,EAAE,QAAQ,EAC3B,KAAK,EAAE,MAAM,EACJ,OAAO,GAAE,WAAgB,EAC1C,WAAW,GAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAgC;IAgClF;;OAEG;IACH,IAAI,OAAO,IAAI,SAAS,OAAO,EAAE,CAEhC;IAED,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,KAAK,CAetB;IAED;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAIlC;;;;;;;KAOC;IACH,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAkBzE;;;;OAIG;IACH,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAW5E;;OAEG;IACH,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAI5E;;;OAGG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKnC;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK9B;;;OAGG;IACH,kBAAkB,CAAC,OAAO,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,cAAc,CAAC,EAAE,GAAG,CAAA;KAAE,GAAG,IAAI;IAU7F;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAK7C;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI;IAkB9E,YAAY,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAKvC,YAAY,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,GAAG,IAAI;IAKlE,UAAU,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAIlD,YAAY,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAIlD;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAKvD;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAKlE,eAAe,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,KAAK,MAAM,GAAG,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC,GAAG,IAAI;IAKjI;;;;;OAKG;IACH,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAKhD;;;OAGG;IACH,iBAAiB,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,IAAI;IAK/E;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI;IAKhF;;;OAGG;IACH,aAAa,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,IAAI;IAKlG;;OAEG;IACG,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,EAAE,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAoOrF;;OAEG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,EAAE,OAAO,GAAE,UAAe,GAAG,MAAM,CAAC,SAAS,CAAC;IAKpF;;OAEG;IACH,OAAO,CAAC,aAAa;CAuCtB"}
|
package/dist/chat/Chat.js
CHANGED
|
@@ -10,6 +10,7 @@ import { ToolExecutionMode } from "../constants.js";
|
|
|
10
10
|
import { ConfigurationError } from "../errors/index.js";
|
|
11
11
|
import { ChatValidator } from "./Validation.js";
|
|
12
12
|
import { ToolHandler } from "./ToolHandler.js";
|
|
13
|
+
import { logger } from "../utils/logger.js";
|
|
13
14
|
import { ChatResponseString } from "./ChatResponse.js";
|
|
14
15
|
export class Chat {
|
|
15
16
|
provider;
|
|
@@ -285,6 +286,7 @@ export class Chat {
|
|
|
285
286
|
headers: { ...this.options.headers, ...options?.headers },
|
|
286
287
|
response_format: responseFormat, // Pass to provider
|
|
287
288
|
requestTimeout: options?.requestTimeout ?? this.options.requestTimeout ?? config.requestTimeout,
|
|
289
|
+
signal: options?.signal,
|
|
288
290
|
...this.options.params,
|
|
289
291
|
};
|
|
290
292
|
// --- Content Policy Hooks (Input) ---
|
|
@@ -378,15 +380,20 @@ export class Chat {
|
|
|
378
380
|
if (isFatal) {
|
|
379
381
|
throw error;
|
|
380
382
|
}
|
|
381
|
-
|
|
383
|
+
logger.error(`Tool execution failed for '${toolCall.function.name}':`, error);
|
|
382
384
|
}
|
|
383
385
|
}
|
|
384
386
|
response = await this.executor.executeChat({
|
|
385
387
|
model: this.model,
|
|
386
388
|
messages: [...this.systemMessages, ...this.messages],
|
|
387
389
|
tools: this.options.tools,
|
|
390
|
+
temperature: options?.temperature ?? this.options.temperature,
|
|
391
|
+
max_tokens: options?.maxTokens ?? this.options.maxTokens ?? config.maxTokens,
|
|
388
392
|
headers: this.options.headers,
|
|
393
|
+
response_format: responseFormat,
|
|
389
394
|
requestTimeout: options?.requestTimeout ?? this.options.requestTimeout ?? config.requestTimeout,
|
|
395
|
+
signal: options?.signal,
|
|
396
|
+
...this.options.params,
|
|
390
397
|
});
|
|
391
398
|
trackUsage(response.usage);
|
|
392
399
|
assistantMessage = new ChatResponseString(response.content ?? "", response.usage ?? { input_tokens: 0, output_tokens: 0, total_tokens: 0 }, this.model, this.provider.id, response.reasoning);
|
|
@@ -429,7 +436,7 @@ export class Chat {
|
|
|
429
436
|
toolInstance = new tool();
|
|
430
437
|
}
|
|
431
438
|
catch (e) {
|
|
432
|
-
|
|
439
|
+
logger.error(`Failed to instantiate tool class: ${tool.name}`, e);
|
|
433
440
|
return null;
|
|
434
441
|
}
|
|
435
442
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatStream.d.ts","sourceRoot":"","sources":["../../src/chat/ChatStream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAA4C,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAS,MAAM,0BAA0B,CAAC;AAEtE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAGhD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"ChatStream.d.ts","sourceRoot":"","sources":["../../src/chat/ChatStream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAA4C,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAS,MAAM,0BAA0B,CAAC;AAEtE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAGhD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAQvC;;;GAGG;AACH,qBAAa,UAAU;IAKnB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAN1B,OAAO,CAAC,QAAQ,CAAY;IAC5B,OAAO,CAAC,cAAc,CAAY;gBAGf,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,WAAgB,EAC1C,QAAQ,CAAC,EAAE,OAAO,EAAE,EACpB,cAAc,CAAC,EAAE,OAAO,EAAE;IA6B5B,IAAI,OAAO,IAAI,SAAS,OAAO,EAAE,CAEhC;IAED,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,EAAE,OAAO,GAAE,UAAe,GAAG,MAAM,CAAC,SAAS,CAAC;CAsOrF"}
|
package/dist/chat/ChatStream.js
CHANGED
|
@@ -7,6 +7,7 @@ import { FileLoader } from "../utils/FileLoader.js";
|
|
|
7
7
|
import { toJsonSchema } from "../schema/to-json-schema.js";
|
|
8
8
|
import { ChatValidator } from "./Validation.js";
|
|
9
9
|
import { ToolHandler } from "./ToolHandler.js";
|
|
10
|
+
import { logger } from "../utils/logger.js";
|
|
10
11
|
/**
|
|
11
12
|
* Internal handler for chat streaming logic.
|
|
12
13
|
* Wraps the provider's stream with side effects like history updates and events.
|
|
@@ -210,7 +211,7 @@ export class ChatStream {
|
|
|
210
211
|
if (isFatal) {
|
|
211
212
|
throw error;
|
|
212
213
|
}
|
|
213
|
-
|
|
214
|
+
logger.error(`Tool execution failed for '${toolCall.function.name}':`, error);
|
|
214
215
|
}
|
|
215
216
|
}
|
|
216
217
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolHandler.d.ts","sourceRoot":"","sources":["../../src/chat/ToolHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGpD,qBAAa,WAAW;IACtB,MAAM,CAAC,kBAAkB,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,SAAS,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,OAAO;WAM7E,uBAAuB,CAClC,QAAQ,EAAE,GAAG,EACb,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,GACpD,OAAO,CAAC,OAAO,CAAC;WAMN,OAAO,CAClB,QAAQ,EAAE,GAAG,EACb,KAAK,EAAE,GAAG,EAAE,GAAG,SAAS,EACxB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,EAC7B,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,IAAI,GACvC,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"ToolHandler.d.ts","sourceRoot":"","sources":["../../src/chat/ToolHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGpD,qBAAa,WAAW;IACtB,MAAM,CAAC,kBAAkB,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,SAAS,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,OAAO;WAM7E,uBAAuB,CAClC,QAAQ,EAAE,GAAG,EACb,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,GACpD,OAAO,CAAC,OAAO,CAAC;WAMN,OAAO,CAClB,QAAQ,EAAE,GAAG,EACb,KAAK,EAAE,GAAG,EAAE,GAAG,SAAS,EACxB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,EAC7B,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,IAAI,GACvC,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAyBpE"}
|
package/dist/chat/ToolHandler.js
CHANGED
|
@@ -22,12 +22,13 @@ export class ToolHandler {
|
|
|
22
22
|
try {
|
|
23
23
|
const args = JSON.parse(toolCall.function.arguments);
|
|
24
24
|
const result = await tool.handler(args);
|
|
25
|
+
const safeResult = typeof result === 'string' ? result : JSON.stringify(result);
|
|
25
26
|
if (onEnd)
|
|
26
27
|
onEnd(toolCall, result);
|
|
27
28
|
return {
|
|
28
29
|
role: "tool",
|
|
29
30
|
tool_call_id: toolCall.id,
|
|
30
|
-
content:
|
|
31
|
+
content: safeResult,
|
|
31
32
|
};
|
|
32
33
|
}
|
|
33
34
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Validation.d.ts","sourceRoot":"","sources":["../../src/chat/Validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"Validation.d.ts","sourceRoot":"","sources":["../../src/chat/Validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,qBAAa,aAAa;IACxB,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB;IAYvG,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB;IAYrG,MAAM,CAAC,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB;CAWlH"}
|
package/dist/chat/Validation.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logger } from "../utils/logger.js";
|
|
1
2
|
export class ChatValidator {
|
|
2
3
|
static validateVision(provider, model, hasBinary, options) {
|
|
3
4
|
if (!hasBinary)
|
|
@@ -6,7 +7,7 @@ export class ChatValidator {
|
|
|
6
7
|
throw new Error(`Model ${model} does not support vision/binary files.`);
|
|
7
8
|
}
|
|
8
9
|
if (options.assumeModelExists) {
|
|
9
|
-
|
|
10
|
+
logger.warn(`Skipping vision capability validation for model ${model}`);
|
|
10
11
|
}
|
|
11
12
|
}
|
|
12
13
|
static validateTools(provider, model, hasTools, options) {
|
|
@@ -16,7 +17,7 @@ export class ChatValidator {
|
|
|
16
17
|
throw new Error(`Model ${model} does not support tool calling.`);
|
|
17
18
|
}
|
|
18
19
|
if (options.assumeModelExists) {
|
|
19
|
-
|
|
20
|
+
logger.warn(`Skipping tool capability validation for model ${model}`);
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
static validateStructuredOutput(provider, model, hasSchema, options) {
|
|
@@ -26,7 +27,7 @@ export class ChatValidator {
|
|
|
26
27
|
throw new Error(`Model ${model} does not support structured output.`);
|
|
27
28
|
}
|
|
28
29
|
if (options.assumeModelExists) {
|
|
29
|
-
|
|
30
|
+
logger.warn(`Skipping structured output capability validation for model ${model}`);
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
}
|
package/dist/llm.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EACL,QAAQ,EACR,SAAS,EAIV,MAAM,yBAAyB,CAAC;AAUjC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"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"}
|
package/dist/llm.js
CHANGED
|
@@ -7,6 +7,7 @@ import { Moderation } from "./moderation/Moderation.js";
|
|
|
7
7
|
import { Embedding } from "./embedding/Embedding.js";
|
|
8
8
|
import { ProviderNotConfiguredError, UnsupportedFeatureError, ModelCapabilityError } from "./errors/index.js";
|
|
9
9
|
import { resolveModelAlias } from "./model_aliases.js";
|
|
10
|
+
import { logger } from "./utils/logger.js";
|
|
10
11
|
import { config, Configuration } from "./config.js";
|
|
11
12
|
// Provider registration map
|
|
12
13
|
const PROVIDER_REGISTRARS = {
|
|
@@ -165,7 +166,7 @@ export class NodeLLMCore {
|
|
|
165
166
|
const rawModel = options?.model;
|
|
166
167
|
const model = resolveModelAlias(rawModel || "", provider.id);
|
|
167
168
|
if (options?.assumeModelExists) {
|
|
168
|
-
|
|
169
|
+
logger.warn(`Skipping validation for model ${model}`);
|
|
169
170
|
}
|
|
170
171
|
else if (model && provider.capabilities && !provider.capabilities.supportsImageGeneration(model)) {
|
|
171
172
|
throw new ModelCapabilityError(model, "image generation");
|
|
@@ -183,7 +184,7 @@ export class NodeLLMCore {
|
|
|
183
184
|
const rawModel = options?.model || this.defaultTranscriptionModelId || "";
|
|
184
185
|
const model = resolveModelAlias(rawModel, provider.id);
|
|
185
186
|
if (options?.assumeModelExists) {
|
|
186
|
-
|
|
187
|
+
logger.warn(`Skipping validation for model ${model}`);
|
|
187
188
|
}
|
|
188
189
|
else if (model && provider.capabilities && !provider.capabilities.supportsTranscription(model)) {
|
|
189
190
|
throw new ModelCapabilityError(model, "transcription");
|
|
@@ -213,7 +214,7 @@ export class NodeLLMCore {
|
|
|
213
214
|
const rawModel = options?.model || this.defaultModerationModelId || "";
|
|
214
215
|
const model = resolveModelAlias(rawModel, provider.id);
|
|
215
216
|
if (options?.assumeModelExists) {
|
|
216
|
-
|
|
217
|
+
logger.warn(`Skipping validation for model ${model}`);
|
|
217
218
|
}
|
|
218
219
|
else if (model && provider.capabilities && !provider.capabilities.supportsModeration(model)) {
|
|
219
220
|
throw new ModelCapabilityError(model, "moderation");
|
|
@@ -237,7 +238,7 @@ export class NodeLLMCore {
|
|
|
237
238
|
requestTimeout: options?.requestTimeout ?? this.config.requestTimeout,
|
|
238
239
|
};
|
|
239
240
|
if (options?.assumeModelExists) {
|
|
240
|
-
|
|
241
|
+
logger.warn(`Skipping validation for model ${request.model}`);
|
|
241
242
|
}
|
|
242
243
|
else if (request.model && provider.capabilities && !provider.capabilities.supportsEmbeddings(request.model)) {
|
|
243
244
|
throw new ModelCapabilityError(request.model, "embeddings");
|
|
@@ -11,7 +11,7 @@ export class GeminiImage {
|
|
|
11
11
|
const modelId = request.model || "imagen-4.0-generate-001";
|
|
12
12
|
const url = `${this.baseUrl}/models/${modelId}:predict?key=${this.apiKey}`;
|
|
13
13
|
if (request.size) {
|
|
14
|
-
|
|
14
|
+
logger.warn(`[Gemini] Ignoring size ${request.size}. Gemini does not support image size customization.`);
|
|
15
15
|
}
|
|
16
16
|
const body = {
|
|
17
17
|
instances: [
|
|
@@ -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;AASlE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,qBAAa,UAAU;IAGT,OAAO,CAAC,QAAQ,CAAC,aAAa;IAA2B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAF5F,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAEJ,aAAa,EAAE,cAAc,GAAG,MAAM,EAAmB,MAAM,EAAE,MAAM;IAI9F,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,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;AASlE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,qBAAa,UAAU;IAGT,OAAO,CAAC,QAAQ,CAAC,aAAa;IAA2B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAF5F,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAEJ,aAAa,EAAE,cAAc,GAAG,MAAM,EAAmB,MAAM,EAAE,MAAM;IAI9F,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;CA2E3D"}
|
|
@@ -20,7 +20,7 @@ export class OpenAIChat {
|
|
|
20
20
|
const supportsDeveloperRole = isMainOpenAI && (typeof this.providerOrUrl === "string"
|
|
21
21
|
? Capabilities.supportsDeveloperRole(request.model)
|
|
22
22
|
: this.providerOrUrl.capabilities?.supportsDeveloperRole(request.model));
|
|
23
|
-
const { model, messages, tools, temperature: _, max_tokens, response_format, headers, requestTimeout, ...rest } = request;
|
|
23
|
+
const { model, messages, tools, temperature: _, max_tokens, response_format, headers, requestTimeout, signal, ...rest } = request;
|
|
24
24
|
const mappedMessages = mapSystemMessages(messages, !!supportsDeveloperRole);
|
|
25
25
|
const body = {
|
|
26
26
|
model,
|
|
@@ -51,6 +51,7 @@ export class OpenAIChat {
|
|
|
51
51
|
...request.headers,
|
|
52
52
|
},
|
|
53
53
|
body: JSON.stringify(body),
|
|
54
|
+
signal,
|
|
54
55
|
}, request.requestTimeout);
|
|
55
56
|
if (!response.ok) {
|
|
56
57
|
await handleOpenAIError(response, request.model);
|
|
@@ -15,7 +15,7 @@ export class OpenAIStreaming {
|
|
|
15
15
|
this.baseUrl = typeof providerOrUrl === "string" ? providerOrUrl : providerOrUrl.apiBase();
|
|
16
16
|
}
|
|
17
17
|
async *execute(request, controller) {
|
|
18
|
-
const abortController = controller || new AbortController();
|
|
18
|
+
const abortController = controller || (request.signal ? { signal: request.signal } : new AbortController());
|
|
19
19
|
const temperature = Capabilities.normalizeTemperature(request.temperature, request.model);
|
|
20
20
|
const isMainOpenAI = this.baseUrl.includes("api.openai.com");
|
|
21
21
|
const supportsDeveloperRole = isMainOpenAI && (typeof this.providerOrUrl === "string"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Binary.d.ts","sourceRoot":"","sources":["../../src/utils/Binary.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Binary.d.ts","sourceRoot":"","sources":["../../src/utils/Binary.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,WAAW;IACtB;;OAEG;WACU,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IA0C9D,OAAO,CAAC,MAAM,CAAC,aAAa;CAgB7B"}
|
package/dist/utils/Binary.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
+
import { logger } from "./logger.js";
|
|
3
4
|
export class BinaryUtils {
|
|
4
5
|
/**
|
|
5
6
|
* Converts a URL (data:, http:, or local path) to a base64 string and mime type.
|
|
@@ -28,25 +29,23 @@ export class BinaryUtils {
|
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
31
|
catch (e) {
|
|
31
|
-
|
|
32
|
+
logger.error("Error converting URL to base64:", e);
|
|
32
33
|
return null;
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
else {
|
|
36
37
|
// Assume local file path
|
|
37
38
|
try {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
};
|
|
46
|
-
}
|
|
39
|
+
const buffer = await fs.promises.readFile(url);
|
|
40
|
+
const base64 = buffer.toString("base64");
|
|
41
|
+
const mimeType = this.guessMimeType(url);
|
|
42
|
+
return {
|
|
43
|
+
mimeType,
|
|
44
|
+
data: base64,
|
|
45
|
+
};
|
|
47
46
|
}
|
|
48
47
|
catch (e) {
|
|
49
|
-
|
|
48
|
+
logger.error("Error reading local file for base64:", e);
|
|
50
49
|
return null;
|
|
51
50
|
}
|
|
52
51
|
}
|
package/dist/utils/audio.js
CHANGED
|
@@ -15,7 +15,7 @@ export class AudioUtils {
|
|
|
15
15
|
fileName = path.basename(urlPath) || "audio.mp3";
|
|
16
16
|
}
|
|
17
17
|
else {
|
|
18
|
-
const buffer = fs.
|
|
18
|
+
const buffer = await fs.promises.readFile(filePath);
|
|
19
19
|
data = new Uint8Array(buffer);
|
|
20
20
|
fileName = path.basename(filePath);
|
|
21
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/utils/fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,WAAgB,EACzB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/utils/fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,WAAgB,EACzB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,QAAQ,CAAC,CAuCnB"}
|
package/dist/utils/fetch.js
CHANGED
|
@@ -9,7 +9,12 @@
|
|
|
9
9
|
* @throws Error if the request times out
|
|
10
10
|
*/
|
|
11
11
|
export async function fetchWithTimeout(url, options = {}, timeoutMs) {
|
|
12
|
-
|
|
12
|
+
const userSignal = options.signal;
|
|
13
|
+
// If no timeout is specified and no user signal, use standard fetch
|
|
14
|
+
if ((!timeoutMs || timeoutMs <= 0) && !userSignal) {
|
|
15
|
+
return fetch(url, options);
|
|
16
|
+
}
|
|
17
|
+
// If only user signal (no timeout), use it directly
|
|
13
18
|
if (!timeoutMs || timeoutMs <= 0) {
|
|
14
19
|
return fetch(url, options);
|
|
15
20
|
}
|
|
@@ -18,17 +23,21 @@ export async function fetchWithTimeout(url, options = {}, timeoutMs) {
|
|
|
18
23
|
if (timeoutId.unref)
|
|
19
24
|
timeoutId.unref();
|
|
20
25
|
try {
|
|
26
|
+
// Merge user signal with timeout signal
|
|
27
|
+
const mergedSignal = userSignal
|
|
28
|
+
? AbortSignal.any([userSignal, controller.signal])
|
|
29
|
+
: controller.signal;
|
|
21
30
|
const response = await fetch(url, {
|
|
22
31
|
...options,
|
|
23
|
-
signal:
|
|
32
|
+
signal: mergedSignal,
|
|
24
33
|
});
|
|
25
34
|
clearTimeout(timeoutId);
|
|
26
35
|
return response;
|
|
27
36
|
}
|
|
28
37
|
catch (error) {
|
|
29
38
|
clearTimeout(timeoutId);
|
|
30
|
-
// Check if the error was due to abort
|
|
31
|
-
if (error.name === 'AbortError') {
|
|
39
|
+
// Check if the error was due to timeout abort
|
|
40
|
+
if (error.name === 'AbortError' && controller.signal.aborted) {
|
|
32
41
|
throw new Error(`Request timeout after ${timeoutMs}ms`);
|
|
33
42
|
}
|
|
34
43
|
throw error;
|