@node-llm/core 0.7.0 → 1.0.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/README.md +67 -62
- package/dist/chat/Chat.d.ts +3 -2
- package/dist/chat/Chat.d.ts.map +1 -1
- package/dist/chat/Chat.js +4 -4
- package/dist/chat/ChatStream.d.ts +25 -0
- package/dist/chat/ChatStream.d.ts.map +1 -0
- package/dist/chat/ChatStream.js +93 -0
- package/dist/config.d.ts +6 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -0
- package/dist/embedding/Embedding.d.ts +1 -1
- package/dist/embedding/Embedding.d.ts.map +1 -1
- package/dist/errors/index.d.ts +22 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +32 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/llm.d.ts +3 -1
- package/dist/llm.d.ts.map +1 -1
- package/dist/llm.js +26 -24
- package/dist/models/ModelRegistry.d.ts +3 -2
- package/dist/models/ModelRegistry.d.ts.map +1 -1
- package/dist/models/ModelRegistry.js +15 -3
- package/dist/models/models.d.ts +729 -60
- package/dist/models/models.d.ts.map +1 -1
- package/dist/models/models.js +24809 -2410
- package/dist/models/types.d.ts +3 -3
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js +3 -0
- package/dist/providers/BaseProvider.d.ts +21 -0
- package/dist/providers/BaseProvider.d.ts.map +1 -0
- package/dist/providers/BaseProvider.js +28 -0
- package/dist/providers/Provider.d.ts +19 -1
- package/dist/providers/Provider.d.ts.map +1 -1
- package/dist/providers/anthropic/AnthropicProvider.d.ts +6 -7
- package/dist/providers/anthropic/AnthropicProvider.d.ts.map +1 -1
- package/dist/providers/anthropic/AnthropicProvider.js +16 -13
- package/dist/providers/anthropic/Streaming.d.ts +1 -1
- package/dist/providers/anthropic/Streaming.d.ts.map +1 -1
- package/dist/providers/anthropic/Streaming.js +80 -54
- package/dist/providers/deepseek/Capabilities.js +1 -1
- package/dist/providers/deepseek/DeepSeekProvider.d.ts +5 -1
- package/dist/providers/deepseek/DeepSeekProvider.d.ts.map +1 -1
- package/dist/providers/deepseek/DeepSeekProvider.js +15 -1
- package/dist/providers/deepseek/Streaming.d.ts +1 -1
- package/dist/providers/deepseek/Streaming.d.ts.map +1 -1
- package/dist/providers/deepseek/Streaming.js +80 -48
- package/dist/providers/gemini/Capabilities.d.ts.map +1 -1
- package/dist/providers/gemini/Embeddings.d.ts +1 -1
- package/dist/providers/gemini/Embeddings.d.ts.map +1 -1
- package/dist/providers/gemini/GeminiProvider.d.ts +6 -4
- package/dist/providers/gemini/GeminiProvider.d.ts.map +1 -1
- package/dist/providers/gemini/GeminiProvider.js +14 -4
- package/dist/providers/gemini/Streaming.d.ts +1 -1
- package/dist/providers/gemini/Streaming.d.ts.map +1 -1
- package/dist/providers/gemini/Streaming.js +62 -39
- package/dist/providers/ollama/Capabilities.d.ts +13 -0
- package/dist/providers/ollama/Capabilities.d.ts.map +1 -0
- package/dist/providers/ollama/Capabilities.js +54 -0
- package/dist/providers/ollama/Embedding.d.ts +6 -0
- package/dist/providers/ollama/Embedding.d.ts.map +1 -0
- package/dist/providers/ollama/Embedding.js +12 -0
- package/dist/providers/ollama/Models.d.ts +8 -0
- package/dist/providers/ollama/Models.d.ts.map +1 -0
- package/dist/providers/ollama/Models.js +31 -0
- package/dist/providers/ollama/OllamaProvider.d.ts +9 -0
- package/dist/providers/ollama/OllamaProvider.d.ts.map +1 -0
- package/dist/providers/ollama/OllamaProvider.js +31 -0
- package/dist/providers/ollama/index.d.ts +9 -0
- package/dist/providers/ollama/index.d.ts.map +1 -0
- package/dist/providers/ollama/index.js +17 -0
- package/dist/providers/openai/Capabilities.d.ts +1 -1
- package/dist/providers/openai/Capabilities.d.ts.map +1 -1
- package/dist/providers/openai/Capabilities.js +4 -2
- package/dist/providers/openai/Embedding.d.ts +5 -3
- package/dist/providers/openai/Embedding.d.ts.map +1 -1
- package/dist/providers/openai/Embedding.js +13 -8
- package/dist/providers/openai/Models.d.ts +12 -2
- package/dist/providers/openai/Models.d.ts.map +1 -1
- package/dist/providers/openai/Models.js +50 -16
- package/dist/providers/openai/OpenAIProvider.d.ts +22 -12
- package/dist/providers/openai/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/openai/OpenAIProvider.js +16 -2
- package/dist/providers/openai/Streaming.d.ts +1 -1
- package/dist/providers/openai/Streaming.d.ts.map +1 -1
- package/dist/providers/openai/Streaming.js +75 -43
- package/dist/providers/openrouter/Capabilities.d.ts +13 -0
- package/dist/providers/openrouter/Capabilities.d.ts.map +1 -0
- package/dist/providers/openrouter/Capabilities.js +67 -0
- package/dist/providers/openrouter/Models.d.ts +11 -0
- package/dist/providers/openrouter/Models.d.ts.map +1 -0
- package/dist/providers/openrouter/Models.js +88 -0
- package/dist/providers/openrouter/OpenRouterProvider.d.ts +21 -0
- package/dist/providers/openrouter/OpenRouterProvider.d.ts.map +1 -0
- package/dist/providers/openrouter/OpenRouterProvider.js +24 -0
- package/dist/providers/openrouter/index.d.ts +11 -0
- package/dist/providers/openrouter/index.d.ts.map +1 -0
- package/dist/providers/openrouter/index.js +26 -0
- package/dist/providers/registry.d.ts +11 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +14 -0
- package/dist/streaming/Stream.d.ts +29 -0
- package/dist/streaming/Stream.d.ts.map +1 -0
- package/dist/streaming/Stream.js +67 -0
- package/dist/utils/FileLoader.d.ts.map +1 -1
- package/dist/utils/FileLoader.js +34 -3
- package/dist/utils/logger.d.ts +13 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +24 -0
- package/package.json +1 -1
- package/dist/chat/Stream.d.ts +0 -21
- package/dist/chat/Stream.d.ts.map +0 -1
- package/dist/chat/Stream.js +0 -73
- package/dist/providers/Embedding.d.ts +0 -20
- package/dist/providers/Embedding.d.ts.map +0 -1
- package/dist/providers/Embedding.js +0 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export class OpenRouterModels {
|
|
2
|
+
baseUrl;
|
|
3
|
+
apiKey;
|
|
4
|
+
constructor(baseUrl, apiKey) {
|
|
5
|
+
this.baseUrl = baseUrl;
|
|
6
|
+
this.apiKey = apiKey;
|
|
7
|
+
}
|
|
8
|
+
async execute() {
|
|
9
|
+
const response = await fetch(`${this.baseUrl}/models`, {
|
|
10
|
+
headers: {
|
|
11
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
12
|
+
"Content-Type": "application/json",
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
throw new Error(`OpenRouter API error: ${response.status}`);
|
|
17
|
+
}
|
|
18
|
+
const data = await response.json();
|
|
19
|
+
return data.data.map((model) => this.parseModel(model));
|
|
20
|
+
}
|
|
21
|
+
parseModel(model) {
|
|
22
|
+
const family = model.id.split('/')[0] || "";
|
|
23
|
+
return {
|
|
24
|
+
id: model.id,
|
|
25
|
+
name: model.name,
|
|
26
|
+
provider: "openrouter",
|
|
27
|
+
family: family,
|
|
28
|
+
context_window: model.context_length,
|
|
29
|
+
max_output_tokens: model.top_provider?.max_completion_tokens ?? null,
|
|
30
|
+
modalities: {
|
|
31
|
+
input: model.architecture?.input_modalities || [],
|
|
32
|
+
output: model.architecture?.output_modalities || []
|
|
33
|
+
},
|
|
34
|
+
capabilities: this.parseCapabilities(model),
|
|
35
|
+
pricing: this.parsePricing(model.pricing),
|
|
36
|
+
metadata: {
|
|
37
|
+
created_at: model.created ? new Date(model.created * 1000) : undefined,
|
|
38
|
+
description: model.description,
|
|
39
|
+
architecture: model.architecture,
|
|
40
|
+
top_provider: model.top_provider,
|
|
41
|
+
supported_parameters: model.supported_parameters
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
parseCapabilities(model) {
|
|
46
|
+
const caps = [];
|
|
47
|
+
const params = model.supported_parameters || [];
|
|
48
|
+
const inputModalities = model.architecture?.input_modalities || [];
|
|
49
|
+
if (params.includes('tools') || params.includes('function_calling')) {
|
|
50
|
+
caps.push('tools');
|
|
51
|
+
}
|
|
52
|
+
if (inputModalities.includes('image')) {
|
|
53
|
+
caps.push('vision');
|
|
54
|
+
}
|
|
55
|
+
if (model.id.includes('embedding') || model.id.includes('text-sdk')) {
|
|
56
|
+
caps.push('embeddings');
|
|
57
|
+
}
|
|
58
|
+
// Heuristics for reasoning
|
|
59
|
+
if (model.id.includes('o1') || model.id.includes('o3') || model.id.includes('deepseek-r1') || model.id.includes('qwq')) {
|
|
60
|
+
caps.push('reasoning');
|
|
61
|
+
}
|
|
62
|
+
return caps;
|
|
63
|
+
}
|
|
64
|
+
parsePricing(pricing) {
|
|
65
|
+
const result = {
|
|
66
|
+
text_tokens: {
|
|
67
|
+
standard: {}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const prompt = parseFloat(pricing.prompt);
|
|
71
|
+
const completion = parseFloat(pricing.completion);
|
|
72
|
+
const cachedInput = pricing.input_cache_read ? parseFloat(pricing.input_cache_read) : 0;
|
|
73
|
+
const reasoning = pricing.internal_reasoning ? parseFloat(pricing.internal_reasoning) : 0;
|
|
74
|
+
if (prompt > 0) {
|
|
75
|
+
result.text_tokens.standard.input_per_million = prompt * 1_000_000;
|
|
76
|
+
}
|
|
77
|
+
if (completion > 0) {
|
|
78
|
+
result.text_tokens.standard.output_per_million = completion * 1_000_000;
|
|
79
|
+
}
|
|
80
|
+
if (cachedInput > 0) {
|
|
81
|
+
result.text_tokens.standard.cached_input_per_million = cachedInput * 1_000_000;
|
|
82
|
+
}
|
|
83
|
+
if (reasoning > 0) {
|
|
84
|
+
result.text_tokens.standard.reasoning_output_per_million = reasoning * 1_000_000;
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { OpenAIProvider } from "../openai/OpenAIProvider.js";
|
|
2
|
+
export interface OpenRouterProviderOptions {
|
|
3
|
+
apiKey: string;
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class OpenRouterProvider extends OpenAIProvider {
|
|
7
|
+
capabilities: {
|
|
8
|
+
supportsVision: (model: string) => boolean;
|
|
9
|
+
supportsTools: (model: string) => boolean;
|
|
10
|
+
supportsStructuredOutput: (model: string) => boolean;
|
|
11
|
+
supportsEmbeddings: (model: string) => boolean;
|
|
12
|
+
supportsImageGeneration: (model: string) => boolean;
|
|
13
|
+
supportsTranscription: (model: string) => boolean;
|
|
14
|
+
supportsModeration: (model: string) => boolean;
|
|
15
|
+
supportsReasoning: (model: string) => boolean;
|
|
16
|
+
getContextWindow: (model: string) => number | null;
|
|
17
|
+
};
|
|
18
|
+
constructor(options: OpenRouterProviderOptions);
|
|
19
|
+
protected providerName(): string;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=OpenRouterProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenRouterProvider.d.ts","sourceRoot":"","sources":["../../../src/providers/openrouter/OpenRouterProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAG7D,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,kBAAmB,SAAQ,cAAc;IAC7C,YAAY;gCACO,MAAM;+BACP,MAAM;0CACK,MAAM;oCACZ,MAAM;yCACD,MAAM;uCACR,MAAM;oCACT,MAAM;mCACP,MAAM;kCACP,MAAM;MAChC;gBAEU,OAAO,EAAE,yBAAyB;IAO9C,SAAS,CAAC,YAAY,IAAI,MAAM;CAGjC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { OpenAIProvider } from "../openai/OpenAIProvider.js";
|
|
2
|
+
import { OpenRouterCapabilities } from "./Capabilities.js";
|
|
3
|
+
export class OpenRouterProvider extends OpenAIProvider {
|
|
4
|
+
capabilities = {
|
|
5
|
+
supportsVision: (model) => OpenRouterCapabilities.supportsVision(model),
|
|
6
|
+
supportsTools: (model) => OpenRouterCapabilities.supportsTools(model),
|
|
7
|
+
supportsStructuredOutput: (model) => OpenRouterCapabilities.supportsStructuredOutput(model),
|
|
8
|
+
supportsEmbeddings: (model) => OpenRouterCapabilities.supportsEmbeddings(model),
|
|
9
|
+
supportsImageGeneration: (model) => OpenRouterCapabilities.supportsImageGeneration(model),
|
|
10
|
+
supportsTranscription: (model) => OpenRouterCapabilities.supportsTranscription(model),
|
|
11
|
+
supportsModeration: (model) => OpenRouterCapabilities.supportsModeration(model),
|
|
12
|
+
supportsReasoning: (model) => OpenRouterCapabilities.supportsReasoning(model),
|
|
13
|
+
getContextWindow: (model) => OpenRouterCapabilities.getContextWindow(model) || null,
|
|
14
|
+
};
|
|
15
|
+
constructor(options) {
|
|
16
|
+
super({
|
|
17
|
+
apiKey: options.apiKey,
|
|
18
|
+
baseUrl: options.baseUrl || "https://openrouter.ai/api/v1"
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
providerName() {
|
|
22
|
+
return "OpenRouter";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from "./OpenRouterProvider.js";
|
|
2
|
+
/**
|
|
3
|
+
* Idempotent registration of the OpenRouter provider.
|
|
4
|
+
* Automatically called by LLM.configure({ provider: 'openrouter' })
|
|
5
|
+
*/
|
|
6
|
+
export declare function registerOpenRouterProvider(): void;
|
|
7
|
+
/**
|
|
8
|
+
* Alias for registerOpenRouterProvider for internal use.
|
|
9
|
+
*/
|
|
10
|
+
export declare const ensureOpenRouterRegistered: typeof registerOpenRouterProvider;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/openrouter/index.ts"],"names":[],"mappings":"AAIA,cAAc,yBAAyB,CAAC;AAIxC;;;GAGG;AACH,wBAAgB,0BAA0B,SAezC;AAED;;GAEG;AACH,eAAO,MAAM,0BAA0B,mCAA6B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { config } from "../../config.js";
|
|
2
|
+
import { providerRegistry } from "../registry.js";
|
|
3
|
+
import { OpenRouterProvider } from "./OpenRouterProvider.js";
|
|
4
|
+
export * from "./OpenRouterProvider.js";
|
|
5
|
+
let registered = false;
|
|
6
|
+
/**
|
|
7
|
+
* Idempotent registration of the OpenRouter provider.
|
|
8
|
+
* Automatically called by LLM.configure({ provider: 'openrouter' })
|
|
9
|
+
*/
|
|
10
|
+
export function registerOpenRouterProvider() {
|
|
11
|
+
if (registered)
|
|
12
|
+
return;
|
|
13
|
+
providerRegistry.register("openrouter", () => {
|
|
14
|
+
const apiKey = config.openrouterApiKey;
|
|
15
|
+
const baseUrl = config.openrouterApiBase;
|
|
16
|
+
if (!apiKey) {
|
|
17
|
+
throw new Error("openrouterApiKey is not set in config or OPENROUTER_API_KEY environment variable");
|
|
18
|
+
}
|
|
19
|
+
return new OpenRouterProvider({ apiKey, baseUrl });
|
|
20
|
+
});
|
|
21
|
+
registered = true;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Alias for registerOpenRouterProvider for internal use.
|
|
25
|
+
*/
|
|
26
|
+
export const ensureOpenRouterRegistered = registerOpenRouterProvider;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { Provider } from "./Provider.js";
|
|
2
|
+
import { registerOpenAIProvider } from "./openai/index.js";
|
|
3
|
+
import { registerAnthropicProvider } from "./anthropic/index.js";
|
|
4
|
+
import { registerGeminiProvider } from "./gemini/index.js";
|
|
5
|
+
import { registerDeepSeekProvider } from "./deepseek/index.js";
|
|
6
|
+
import { registerOllamaProvider } from "./ollama/index.js";
|
|
7
|
+
import { registerOpenRouterProvider } from "./openrouter/index.js";
|
|
2
8
|
type ProviderFactory = () => Provider;
|
|
3
9
|
declare class ProviderRegistry {
|
|
4
10
|
private providers;
|
|
@@ -10,11 +16,15 @@ declare class ProviderRegistry {
|
|
|
10
16
|
* Resolve a provider by name
|
|
11
17
|
*/
|
|
12
18
|
resolve(name: string): Provider;
|
|
19
|
+
/**
|
|
20
|
+
* Check if a provider is registered
|
|
21
|
+
*/
|
|
22
|
+
has(name: string): boolean;
|
|
13
23
|
/**
|
|
14
24
|
* Introspection / debugging
|
|
15
25
|
*/
|
|
16
26
|
list(): string[];
|
|
17
27
|
}
|
|
18
28
|
export declare const providerRegistry: ProviderRegistry;
|
|
19
|
-
export {};
|
|
29
|
+
export { registerOpenAIProvider as ensureOpenAIRegistered, registerOpenAIProvider, registerAnthropicProvider, registerGeminiProvider, registerDeepSeekProvider, registerOllamaProvider, registerOpenRouterProvider };
|
|
20
30
|
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAEnE,KAAK,eAAe,GAAG,MAAM,QAAQ,CAAC;AAEtC,cAAM,gBAAgB;IACpB,OAAO,CAAC,SAAS,CAAsC;IAEvD;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAQtD;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ;IAU/B;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B;;OAEG;IACH,IAAI,IAAI,MAAM,EAAE;CAGjB;AAED,eAAO,MAAM,gBAAgB,kBAAyB,CAAC;AAGvD,OAAO,EACL,sBAAsB,IAAI,sBAAsB,EAChD,sBAAsB,EACtB,yBAAyB,EACzB,sBAAsB,EACtB,wBAAwB,EACxB,sBAAsB,EACtB,0BAA0B,EAC3B,CAAC"}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { registerOpenAIProvider } from "./openai/index.js";
|
|
2
|
+
import { registerAnthropicProvider } from "./anthropic/index.js";
|
|
3
|
+
import { registerGeminiProvider } from "./gemini/index.js";
|
|
4
|
+
import { registerDeepSeekProvider } from "./deepseek/index.js";
|
|
5
|
+
import { registerOllamaProvider } from "./ollama/index.js";
|
|
6
|
+
import { registerOpenRouterProvider } from "./openrouter/index.js";
|
|
1
7
|
class ProviderRegistry {
|
|
2
8
|
providers = new Map();
|
|
3
9
|
/**
|
|
@@ -19,6 +25,12 @@ class ProviderRegistry {
|
|
|
19
25
|
}
|
|
20
26
|
return factory();
|
|
21
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Check if a provider is registered
|
|
30
|
+
*/
|
|
31
|
+
has(name) {
|
|
32
|
+
return this.providers.has(name);
|
|
33
|
+
}
|
|
22
34
|
/**
|
|
23
35
|
* Introspection / debugging
|
|
24
36
|
*/
|
|
@@ -27,3 +39,5 @@ class ProviderRegistry {
|
|
|
27
39
|
}
|
|
28
40
|
}
|
|
29
41
|
export const providerRegistry = new ProviderRegistry();
|
|
42
|
+
// Exported registration functions (delegates to provider-specific index files)
|
|
43
|
+
export { registerOpenAIProvider as ensureOpenAIRegistered, registerOpenAIProvider, registerAnthropicProvider, registerGeminiProvider, registerDeepSeekProvider, registerOllamaProvider, registerOpenRouterProvider };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream wrapper class inspired by OpenAI SDK
|
|
3
|
+
* Provides utilities for working with async iterables
|
|
4
|
+
*/
|
|
5
|
+
export declare class Stream<T> implements AsyncIterable<T> {
|
|
6
|
+
private iterator;
|
|
7
|
+
private controller?;
|
|
8
|
+
private consumed;
|
|
9
|
+
constructor(iterator: () => AsyncIterator<T>, controller?: AbortController | undefined);
|
|
10
|
+
/**
|
|
11
|
+
* Create a Stream from an async generator
|
|
12
|
+
*/
|
|
13
|
+
static fromAsyncIterable<T>(iterable: AsyncIterable<T>, controller?: AbortController): Stream<T>;
|
|
14
|
+
[Symbol.asyncIterator](): AsyncIterator<T>;
|
|
15
|
+
/**
|
|
16
|
+
* Splits the stream into two streams which can be
|
|
17
|
+
* independently read from at different speeds.
|
|
18
|
+
*/
|
|
19
|
+
tee(): [Stream<T>, Stream<T>];
|
|
20
|
+
/**
|
|
21
|
+
* Collect all chunks into an array
|
|
22
|
+
*/
|
|
23
|
+
toArray(): Promise<T[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Abort the underlying stream
|
|
26
|
+
*/
|
|
27
|
+
abort(): void;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=Stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Stream.d.ts","sourceRoot":"","sources":["../../src/streaming/Stream.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,qBAAa,MAAM,CAAC,CAAC,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;IAI9C,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,UAAU,CAAC;IAJrB,OAAO,CAAC,QAAQ,CAAS;gBAGf,QAAQ,EAAE,MAAM,aAAa,CAAC,CAAC,CAAC,EAChC,UAAU,CAAC,EAAE,eAAe,YAAA;IAGtC;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,CAAC,EACxB,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAC1B,UAAU,CAAC,EAAE,eAAe,GAC3B,MAAM,CAAC,CAAC,CAAC;IAIZ,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC;IAQ1C;;;OAGG;IACH,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAwB7B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC;IAQ7B;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream wrapper class inspired by OpenAI SDK
|
|
3
|
+
* Provides utilities for working with async iterables
|
|
4
|
+
*/
|
|
5
|
+
export class Stream {
|
|
6
|
+
iterator;
|
|
7
|
+
controller;
|
|
8
|
+
consumed = false;
|
|
9
|
+
constructor(iterator, controller) {
|
|
10
|
+
this.iterator = iterator;
|
|
11
|
+
this.controller = controller;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create a Stream from an async generator
|
|
15
|
+
*/
|
|
16
|
+
static fromAsyncIterable(iterable, controller) {
|
|
17
|
+
return new Stream(() => iterable[Symbol.asyncIterator](), controller);
|
|
18
|
+
}
|
|
19
|
+
[Symbol.asyncIterator]() {
|
|
20
|
+
if (this.consumed) {
|
|
21
|
+
throw new Error('Cannot iterate over a consumed stream, use `.tee()` to split the stream.');
|
|
22
|
+
}
|
|
23
|
+
this.consumed = true;
|
|
24
|
+
return this.iterator();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Splits the stream into two streams which can be
|
|
28
|
+
* independently read from at different speeds.
|
|
29
|
+
*/
|
|
30
|
+
tee() {
|
|
31
|
+
const left = [];
|
|
32
|
+
const right = [];
|
|
33
|
+
const iterator = this.iterator();
|
|
34
|
+
const teeIterator = (queue) => {
|
|
35
|
+
return {
|
|
36
|
+
next: () => {
|
|
37
|
+
if (queue.length === 0) {
|
|
38
|
+
const result = iterator.next();
|
|
39
|
+
left.push(result);
|
|
40
|
+
right.push(result);
|
|
41
|
+
}
|
|
42
|
+
return queue.shift();
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
return [
|
|
47
|
+
new Stream(() => teeIterator(left), this.controller),
|
|
48
|
+
new Stream(() => teeIterator(right), this.controller),
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Collect all chunks into an array
|
|
53
|
+
*/
|
|
54
|
+
async toArray() {
|
|
55
|
+
const result = [];
|
|
56
|
+
for await (const chunk of this) {
|
|
57
|
+
result.push(chunk);
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Abort the underlying stream
|
|
63
|
+
*/
|
|
64
|
+
abort() {
|
|
65
|
+
this.controller?.abort();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileLoader.d.ts","sourceRoot":"","sources":["../../src/utils/FileLoader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA2CjD,qBAAa,UAAU;WACR,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"FileLoader.d.ts","sourceRoot":"","sources":["../../src/utils/FileLoader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA2CjD,qBAAa,UAAU;WACR,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAkF1D"}
|
package/dist/utils/FileLoader.js
CHANGED
|
@@ -41,9 +41,40 @@ const TEXT_EXTENSIONS = new Set([
|
|
|
41
41
|
]);
|
|
42
42
|
export class FileLoader {
|
|
43
43
|
static async load(filePath) {
|
|
44
|
-
if (filePath.startsWith("http")
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
if (filePath.startsWith("http")) {
|
|
45
|
+
try {
|
|
46
|
+
const response = await fetch(filePath);
|
|
47
|
+
if (!response.ok)
|
|
48
|
+
throw new Error(`Failed to fetch file: ${response.statusText}`);
|
|
49
|
+
const buffer = await response.arrayBuffer();
|
|
50
|
+
const contentType = response.headers.get("content-type") || "image/jpeg";
|
|
51
|
+
const base64 = Buffer.from(buffer).toString("base64");
|
|
52
|
+
const dataUri = `data:${contentType};base64,${base64}`;
|
|
53
|
+
if (contentType.startsWith("image/")) {
|
|
54
|
+
return { type: "image_url", image_url: { url: dataUri } };
|
|
55
|
+
}
|
|
56
|
+
if (contentType.startsWith("audio/")) {
|
|
57
|
+
const format = contentType.split("/")[1];
|
|
58
|
+
return {
|
|
59
|
+
type: "input_audio",
|
|
60
|
+
input_audio: {
|
|
61
|
+
data: base64,
|
|
62
|
+
format: (format === "mpeg" ? "mp3" : format) ?? "wav"
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (contentType.startsWith("video/")) {
|
|
67
|
+
return { type: "video_url", video_url: { url: dataUri } };
|
|
68
|
+
}
|
|
69
|
+
// Default to image_url for unknown binary or use as-is
|
|
70
|
+
return { type: "image_url", image_url: { url: dataUri } };
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
// Fallback to URL if fetch fails
|
|
74
|
+
return { type: "image_url", image_url: { url: filePath } };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (filePath.startsWith("data:")) {
|
|
47
78
|
return { type: "image_url", image_url: { url: filePath } };
|
|
48
79
|
}
|
|
49
80
|
const ext = path.extname(filePath).toLowerCase();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized logger for node-llm
|
|
3
|
+
*/
|
|
4
|
+
declare class Logger {
|
|
5
|
+
private isDebugEnabled;
|
|
6
|
+
debug(message: string, data?: any): void;
|
|
7
|
+
warn(message: string): void;
|
|
8
|
+
error(message: string, error?: Error): void;
|
|
9
|
+
info(message: string): void;
|
|
10
|
+
}
|
|
11
|
+
export declare const logger: Logger;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized logger for node-llm
|
|
3
|
+
*/
|
|
4
|
+
class Logger {
|
|
5
|
+
isDebugEnabled() {
|
|
6
|
+
return process.env.NODELLM_DEBUG === "true";
|
|
7
|
+
}
|
|
8
|
+
debug(message, data) {
|
|
9
|
+
if (this.isDebugEnabled()) {
|
|
10
|
+
const formattedData = data ? `\n${JSON.stringify(data, null, 2)}` : '';
|
|
11
|
+
console.log(`[NodeLLM Debug] ${message}${formattedData}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
warn(message) {
|
|
15
|
+
console.warn(`[NodeLLM] ${message}`);
|
|
16
|
+
}
|
|
17
|
+
error(message, error) {
|
|
18
|
+
console.error(`[NodeLLM Error] ${message}`, error || '');
|
|
19
|
+
}
|
|
20
|
+
info(message) {
|
|
21
|
+
console.log(`[NodeLLM] ${message}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export const logger = new Logger();
|
package/package.json
CHANGED
package/dist/chat/Stream.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Message } from "./Message.js";
|
|
2
|
-
import { ChatOptions } from "./ChatOptions.js";
|
|
3
|
-
import { Provider } from "../providers/Provider.js";
|
|
4
|
-
export declare class Stream {
|
|
5
|
-
private readonly provider;
|
|
6
|
-
private readonly model;
|
|
7
|
-
private readonly options;
|
|
8
|
-
private messages;
|
|
9
|
-
constructor(provider: Provider, model: string, options?: ChatOptions, messages?: Message[]);
|
|
10
|
-
/**
|
|
11
|
-
* Read-only access to message history
|
|
12
|
-
*/
|
|
13
|
-
get history(): readonly Message[];
|
|
14
|
-
/**
|
|
15
|
-
* Streams the model's response to a user question.
|
|
16
|
-
* @param content The user's question to send to the model.
|
|
17
|
-
* @returns An async generator yielding chunks of the assistant's response as strings.
|
|
18
|
-
*/
|
|
19
|
-
stream(content: string): AsyncGenerator<import("../providers/Provider.js").ChatChunk, void, unknown>;
|
|
20
|
-
}
|
|
21
|
-
//# sourceMappingURL=Stream.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Stream.d.ts","sourceRoot":"","sources":["../../src/chat/Stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAGpD,qBAAa,MAAM;IAIf,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAL1B,OAAO,CAAC,QAAQ,CAAY;gBAGT,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,WAAgB,EAC1C,QAAQ,CAAC,EAAE,OAAO,EAAE;IAmBtB;;OAEG;IACH,IAAI,OAAO,IAAI,SAAS,OAAO,EAAE,CAEhC;IAED;;;;OAIG;IACI,MAAM,CAAC,OAAO,EAAE,MAAM;CA+C9B"}
|
package/dist/chat/Stream.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { ChatResponseString } from "./ChatResponse.js";
|
|
2
|
-
export class Stream {
|
|
3
|
-
provider;
|
|
4
|
-
model;
|
|
5
|
-
options;
|
|
6
|
-
messages;
|
|
7
|
-
constructor(provider, model, options = {}, messages) {
|
|
8
|
-
this.provider = provider;
|
|
9
|
-
this.model = model;
|
|
10
|
-
this.options = options;
|
|
11
|
-
this.messages = messages ?? [];
|
|
12
|
-
// Only initialize if we're starting a new history
|
|
13
|
-
if (this.messages.length === 0) {
|
|
14
|
-
if (options.systemPrompt) {
|
|
15
|
-
this.messages.push({
|
|
16
|
-
role: "system",
|
|
17
|
-
content: options.systemPrompt,
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
if (options.messages) {
|
|
21
|
-
this.messages.push(...options.messages);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Read-only access to message history
|
|
27
|
-
*/
|
|
28
|
-
get history() {
|
|
29
|
-
return this.messages;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Streams the model's response to a user question.
|
|
33
|
-
* @param content The user's question to send to the model.
|
|
34
|
-
* @returns An async generator yielding chunks of the assistant's response as strings.
|
|
35
|
-
*/
|
|
36
|
-
async *stream(content) {
|
|
37
|
-
this.messages.push({ role: "user", content });
|
|
38
|
-
if (!this.provider.stream) {
|
|
39
|
-
throw new Error("Streaming not supported by provider");
|
|
40
|
-
}
|
|
41
|
-
let full = "";
|
|
42
|
-
let fullReasoning = "";
|
|
43
|
-
let isFirst = true;
|
|
44
|
-
for await (const chunk of this.provider.stream({
|
|
45
|
-
model: this.model,
|
|
46
|
-
messages: this.messages,
|
|
47
|
-
temperature: this.options.temperature,
|
|
48
|
-
max_tokens: this.options.maxTokens,
|
|
49
|
-
})) {
|
|
50
|
-
if (isFirst) {
|
|
51
|
-
if (this.options.onNewMessage)
|
|
52
|
-
this.options.onNewMessage();
|
|
53
|
-
isFirst = false;
|
|
54
|
-
}
|
|
55
|
-
if (chunk.content) {
|
|
56
|
-
full += chunk.content;
|
|
57
|
-
}
|
|
58
|
-
if (chunk.reasoning) {
|
|
59
|
-
fullReasoning += chunk.reasoning;
|
|
60
|
-
}
|
|
61
|
-
yield chunk;
|
|
62
|
-
}
|
|
63
|
-
this.messages.push({
|
|
64
|
-
role: "assistant",
|
|
65
|
-
content: full,
|
|
66
|
-
// @ts-ignore
|
|
67
|
-
reasoning: fullReasoning || undefined
|
|
68
|
-
});
|
|
69
|
-
if (this.options.onEndMessage) {
|
|
70
|
-
this.options.onEndMessage(new ChatResponseString(full, { input_tokens: 0, output_tokens: 0, total_tokens: 0 }, this.model, fullReasoning || undefined));
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export interface EmbeddingRequest {
|
|
2
|
-
input: string | string[];
|
|
3
|
-
model?: string;
|
|
4
|
-
dimensions?: number;
|
|
5
|
-
user?: string;
|
|
6
|
-
}
|
|
7
|
-
export interface EmbeddingVector {
|
|
8
|
-
embedding: number[];
|
|
9
|
-
index: number;
|
|
10
|
-
}
|
|
11
|
-
export interface EmbeddingResponse {
|
|
12
|
-
vectors: number[][];
|
|
13
|
-
model: string;
|
|
14
|
-
input_tokens: number;
|
|
15
|
-
dimensions: number;
|
|
16
|
-
}
|
|
17
|
-
export interface EmbeddingProvider {
|
|
18
|
-
embed(request: EmbeddingRequest): Promise<EmbeddingResponse>;
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=Embedding.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Embedding.d.ts","sourceRoot":"","sources":["../../src/providers/Embedding.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC9D"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|