@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.
Files changed (117) hide show
  1. package/README.md +67 -62
  2. package/dist/chat/Chat.d.ts +3 -2
  3. package/dist/chat/Chat.d.ts.map +1 -1
  4. package/dist/chat/Chat.js +4 -4
  5. package/dist/chat/ChatStream.d.ts +25 -0
  6. package/dist/chat/ChatStream.d.ts.map +1 -0
  7. package/dist/chat/ChatStream.js +93 -0
  8. package/dist/config.d.ts +6 -2
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/config.js +3 -0
  11. package/dist/embedding/Embedding.d.ts +1 -1
  12. package/dist/embedding/Embedding.d.ts.map +1 -1
  13. package/dist/errors/index.d.ts +22 -0
  14. package/dist/errors/index.d.ts.map +1 -1
  15. package/dist/errors/index.js +32 -0
  16. package/dist/index.d.ts +5 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +5 -1
  19. package/dist/llm.d.ts +3 -1
  20. package/dist/llm.d.ts.map +1 -1
  21. package/dist/llm.js +26 -24
  22. package/dist/models/ModelRegistry.d.ts +3 -2
  23. package/dist/models/ModelRegistry.d.ts.map +1 -1
  24. package/dist/models/ModelRegistry.js +15 -3
  25. package/dist/models/models.d.ts +729 -60
  26. package/dist/models/models.d.ts.map +1 -1
  27. package/dist/models/models.js +24809 -2410
  28. package/dist/models/types.d.ts +3 -3
  29. package/dist/models/types.d.ts.map +1 -1
  30. package/dist/models/types.js +3 -0
  31. package/dist/providers/BaseProvider.d.ts +21 -0
  32. package/dist/providers/BaseProvider.d.ts.map +1 -0
  33. package/dist/providers/BaseProvider.js +28 -0
  34. package/dist/providers/Provider.d.ts +19 -1
  35. package/dist/providers/Provider.d.ts.map +1 -1
  36. package/dist/providers/anthropic/AnthropicProvider.d.ts +6 -7
  37. package/dist/providers/anthropic/AnthropicProvider.d.ts.map +1 -1
  38. package/dist/providers/anthropic/AnthropicProvider.js +16 -13
  39. package/dist/providers/anthropic/Streaming.d.ts +1 -1
  40. package/dist/providers/anthropic/Streaming.d.ts.map +1 -1
  41. package/dist/providers/anthropic/Streaming.js +80 -54
  42. package/dist/providers/deepseek/Capabilities.js +1 -1
  43. package/dist/providers/deepseek/DeepSeekProvider.d.ts +5 -1
  44. package/dist/providers/deepseek/DeepSeekProvider.d.ts.map +1 -1
  45. package/dist/providers/deepseek/DeepSeekProvider.js +15 -1
  46. package/dist/providers/deepseek/Streaming.d.ts +1 -1
  47. package/dist/providers/deepseek/Streaming.d.ts.map +1 -1
  48. package/dist/providers/deepseek/Streaming.js +80 -48
  49. package/dist/providers/gemini/Capabilities.d.ts.map +1 -1
  50. package/dist/providers/gemini/Embeddings.d.ts +1 -1
  51. package/dist/providers/gemini/Embeddings.d.ts.map +1 -1
  52. package/dist/providers/gemini/GeminiProvider.d.ts +6 -4
  53. package/dist/providers/gemini/GeminiProvider.d.ts.map +1 -1
  54. package/dist/providers/gemini/GeminiProvider.js +14 -4
  55. package/dist/providers/gemini/Streaming.d.ts +1 -1
  56. package/dist/providers/gemini/Streaming.d.ts.map +1 -1
  57. package/dist/providers/gemini/Streaming.js +62 -39
  58. package/dist/providers/ollama/Capabilities.d.ts +13 -0
  59. package/dist/providers/ollama/Capabilities.d.ts.map +1 -0
  60. package/dist/providers/ollama/Capabilities.js +54 -0
  61. package/dist/providers/ollama/Embedding.d.ts +6 -0
  62. package/dist/providers/ollama/Embedding.d.ts.map +1 -0
  63. package/dist/providers/ollama/Embedding.js +12 -0
  64. package/dist/providers/ollama/Models.d.ts +8 -0
  65. package/dist/providers/ollama/Models.d.ts.map +1 -0
  66. package/dist/providers/ollama/Models.js +31 -0
  67. package/dist/providers/ollama/OllamaProvider.d.ts +9 -0
  68. package/dist/providers/ollama/OllamaProvider.d.ts.map +1 -0
  69. package/dist/providers/ollama/OllamaProvider.js +31 -0
  70. package/dist/providers/ollama/index.d.ts +9 -0
  71. package/dist/providers/ollama/index.d.ts.map +1 -0
  72. package/dist/providers/ollama/index.js +17 -0
  73. package/dist/providers/openai/Capabilities.d.ts +1 -1
  74. package/dist/providers/openai/Capabilities.d.ts.map +1 -1
  75. package/dist/providers/openai/Capabilities.js +4 -2
  76. package/dist/providers/openai/Embedding.d.ts +5 -3
  77. package/dist/providers/openai/Embedding.d.ts.map +1 -1
  78. package/dist/providers/openai/Embedding.js +13 -8
  79. package/dist/providers/openai/Models.d.ts +12 -2
  80. package/dist/providers/openai/Models.d.ts.map +1 -1
  81. package/dist/providers/openai/Models.js +50 -16
  82. package/dist/providers/openai/OpenAIProvider.d.ts +22 -12
  83. package/dist/providers/openai/OpenAIProvider.d.ts.map +1 -1
  84. package/dist/providers/openai/OpenAIProvider.js +16 -2
  85. package/dist/providers/openai/Streaming.d.ts +1 -1
  86. package/dist/providers/openai/Streaming.d.ts.map +1 -1
  87. package/dist/providers/openai/Streaming.js +75 -43
  88. package/dist/providers/openrouter/Capabilities.d.ts +13 -0
  89. package/dist/providers/openrouter/Capabilities.d.ts.map +1 -0
  90. package/dist/providers/openrouter/Capabilities.js +67 -0
  91. package/dist/providers/openrouter/Models.d.ts +11 -0
  92. package/dist/providers/openrouter/Models.d.ts.map +1 -0
  93. package/dist/providers/openrouter/Models.js +88 -0
  94. package/dist/providers/openrouter/OpenRouterProvider.d.ts +21 -0
  95. package/dist/providers/openrouter/OpenRouterProvider.d.ts.map +1 -0
  96. package/dist/providers/openrouter/OpenRouterProvider.js +24 -0
  97. package/dist/providers/openrouter/index.d.ts +11 -0
  98. package/dist/providers/openrouter/index.d.ts.map +1 -0
  99. package/dist/providers/openrouter/index.js +26 -0
  100. package/dist/providers/registry.d.ts +11 -1
  101. package/dist/providers/registry.d.ts.map +1 -1
  102. package/dist/providers/registry.js +14 -0
  103. package/dist/streaming/Stream.d.ts +29 -0
  104. package/dist/streaming/Stream.d.ts.map +1 -0
  105. package/dist/streaming/Stream.js +67 -0
  106. package/dist/utils/FileLoader.d.ts.map +1 -1
  107. package/dist/utils/FileLoader.js +34 -3
  108. package/dist/utils/logger.d.ts +13 -0
  109. package/dist/utils/logger.d.ts.map +1 -0
  110. package/dist/utils/logger.js +24 -0
  111. package/package.json +1 -1
  112. package/dist/chat/Stream.d.ts +0 -21
  113. package/dist/chat/Stream.d.ts.map +0 -1
  114. package/dist/chat/Stream.js +0 -73
  115. package/dist/providers/Embedding.d.ts +0 -20
  116. package/dist/providers/Embedding.d.ts.map +0 -1
  117. 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;AAEzC,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,IAAI,IAAI,MAAM,EAAE;CAGjB;AAED,eAAO,MAAM,gBAAgB,kBAAyB,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;CA+C1D"}
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"}
@@ -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") || filePath.startsWith("data:")) {
45
- // Assume image URL for now if it looks like a URL
46
- // TODO: Better detection for remote file types
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-llm/core",
3
- "version": "0.7.0",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -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"}
@@ -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 {};