@node-llm/core 0.8.0 → 1.1.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 (110) hide show
  1. package/README.md +0 -167
  2. package/dist/aliases.json +126 -0
  3. package/dist/chat/Chat.d.ts +7 -3
  4. package/dist/chat/Chat.d.ts.map +1 -1
  5. package/dist/chat/Chat.js +6 -7
  6. package/dist/chat/ChatStream.d.ts +25 -0
  7. package/dist/chat/ChatStream.d.ts.map +1 -0
  8. package/dist/chat/ChatStream.js +93 -0
  9. package/dist/config.d.ts +5 -3
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js +2 -0
  12. package/dist/embedding/Embedding.d.ts +1 -1
  13. package/dist/embedding/Embedding.d.ts.map +1 -1
  14. package/dist/errors/index.d.ts +22 -0
  15. package/dist/errors/index.d.ts.map +1 -1
  16. package/dist/errors/index.js +32 -0
  17. package/dist/index.d.ts +10 -15
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +10 -9
  20. package/dist/llm.d.ts +4 -3
  21. package/dist/llm.d.ts.map +1 -1
  22. package/dist/llm.js +44 -37
  23. package/dist/model_aliases.d.ts +3 -0
  24. package/dist/model_aliases.d.ts.map +1 -0
  25. package/dist/model_aliases.js +20 -0
  26. package/dist/models/ModelRegistry.d.ts +4 -0
  27. package/dist/models/ModelRegistry.d.ts.map +1 -1
  28. package/dist/models/ModelRegistry.js +15 -0
  29. package/dist/models/models.d.ts +729 -60
  30. package/dist/models/models.d.ts.map +1 -1
  31. package/dist/models/models.js +24375 -2312
  32. package/dist/models/types.d.ts +3 -3
  33. package/dist/models/types.d.ts.map +1 -1
  34. package/dist/models/types.js +3 -0
  35. package/dist/providers/BaseProvider.d.ts +23 -0
  36. package/dist/providers/BaseProvider.d.ts.map +1 -0
  37. package/dist/providers/BaseProvider.js +31 -0
  38. package/dist/providers/Provider.d.ts +17 -1
  39. package/dist/providers/Provider.d.ts.map +1 -1
  40. package/dist/providers/anthropic/AnthropicProvider.d.ts +6 -7
  41. package/dist/providers/anthropic/AnthropicProvider.d.ts.map +1 -1
  42. package/dist/providers/anthropic/AnthropicProvider.js +16 -13
  43. package/dist/providers/anthropic/Streaming.d.ts +1 -1
  44. package/dist/providers/anthropic/Streaming.d.ts.map +1 -1
  45. package/dist/providers/anthropic/Streaming.js +80 -54
  46. package/dist/providers/deepseek/Capabilities.js +1 -1
  47. package/dist/providers/deepseek/DeepSeekProvider.d.ts +5 -1
  48. package/dist/providers/deepseek/DeepSeekProvider.d.ts.map +1 -1
  49. package/dist/providers/deepseek/DeepSeekProvider.js +15 -1
  50. package/dist/providers/deepseek/Streaming.d.ts +1 -1
  51. package/dist/providers/deepseek/Streaming.d.ts.map +1 -1
  52. package/dist/providers/deepseek/Streaming.js +80 -48
  53. package/dist/providers/gemini/Capabilities.d.ts.map +1 -1
  54. package/dist/providers/gemini/Embeddings.d.ts +1 -1
  55. package/dist/providers/gemini/Embeddings.d.ts.map +1 -1
  56. package/dist/providers/gemini/GeminiProvider.d.ts +6 -4
  57. package/dist/providers/gemini/GeminiProvider.d.ts.map +1 -1
  58. package/dist/providers/gemini/GeminiProvider.js +14 -4
  59. package/dist/providers/gemini/Streaming.d.ts +1 -1
  60. package/dist/providers/gemini/Streaming.d.ts.map +1 -1
  61. package/dist/providers/gemini/Streaming.js +62 -39
  62. package/dist/providers/gemini/index.d.ts +1 -1
  63. package/dist/providers/gemini/index.js +1 -1
  64. package/dist/providers/ollama/Capabilities.d.ts.map +1 -1
  65. package/dist/providers/ollama/Capabilities.js +5 -1
  66. package/dist/providers/ollama/OllamaProvider.d.ts +1 -0
  67. package/dist/providers/ollama/OllamaProvider.d.ts.map +1 -1
  68. package/dist/providers/ollama/OllamaProvider.js +3 -0
  69. package/dist/providers/ollama/index.d.ts +1 -1
  70. package/dist/providers/ollama/index.js +1 -1
  71. package/dist/providers/openai/Embedding.d.ts +1 -1
  72. package/dist/providers/openai/Embedding.d.ts.map +1 -1
  73. package/dist/providers/openai/OpenAIProvider.d.ts +6 -3
  74. package/dist/providers/openai/OpenAIProvider.d.ts.map +1 -1
  75. package/dist/providers/openai/OpenAIProvider.js +15 -1
  76. package/dist/providers/openai/Streaming.d.ts +1 -1
  77. package/dist/providers/openai/Streaming.d.ts.map +1 -1
  78. package/dist/providers/openai/Streaming.js +75 -43
  79. package/dist/providers/openai/index.d.ts +1 -1
  80. package/dist/providers/openai/index.js +1 -1
  81. package/dist/providers/openrouter/Capabilities.d.ts +13 -0
  82. package/dist/providers/openrouter/Capabilities.d.ts.map +1 -0
  83. package/dist/providers/openrouter/Capabilities.js +67 -0
  84. package/dist/providers/openrouter/Models.d.ts +11 -0
  85. package/dist/providers/openrouter/Models.d.ts.map +1 -0
  86. package/dist/providers/openrouter/Models.js +88 -0
  87. package/dist/providers/openrouter/OpenRouterProvider.d.ts +21 -0
  88. package/dist/providers/openrouter/OpenRouterProvider.d.ts.map +1 -0
  89. package/dist/providers/openrouter/OpenRouterProvider.js +24 -0
  90. package/dist/providers/openrouter/index.d.ts +11 -0
  91. package/dist/providers/openrouter/index.d.ts.map +1 -0
  92. package/dist/providers/openrouter/index.js +26 -0
  93. package/dist/providers/registry.d.ts +11 -1
  94. package/dist/providers/registry.d.ts.map +1 -1
  95. package/dist/providers/registry.js +15 -1
  96. package/dist/streaming/Stream.d.ts +29 -0
  97. package/dist/streaming/Stream.d.ts.map +1 -0
  98. package/dist/streaming/Stream.js +67 -0
  99. package/dist/utils/FileLoader.d.ts.map +1 -1
  100. package/dist/utils/FileLoader.js +34 -3
  101. package/dist/utils/logger.d.ts +13 -0
  102. package/dist/utils/logger.d.ts.map +1 -0
  103. package/dist/utils/logger.js +24 -0
  104. package/package.json +2 -2
  105. package/dist/chat/Stream.d.ts +0 -21
  106. package/dist/chat/Stream.d.ts.map +0 -1
  107. package/dist/chat/Stream.js +0 -73
  108. package/dist/providers/Embedding.d.ts +0 -20
  109. package/dist/providers/Embedding.d.ts.map +0 -1
  110. package/dist/providers/Embedding.js +0 -1
@@ -1,6 +1,7 @@
1
1
  import { Capabilities } from "./Capabilities.js";
2
2
  import { handleOpenAIError } from "./Errors.js";
3
3
  import { buildUrl } from "./utils.js";
4
+ import { APIError } from "../../errors/index.js";
4
5
  export class OpenAIStreaming {
5
6
  baseUrl;
6
7
  apiKey;
@@ -8,7 +9,8 @@ export class OpenAIStreaming {
8
9
  this.baseUrl = baseUrl;
9
10
  this.apiKey = apiKey;
10
11
  }
11
- async *execute(request) {
12
+ async *execute(request, controller) {
13
+ const abortController = controller || new AbortController();
12
14
  const temperature = Capabilities.normalizeTemperature(request.temperature, request.model);
13
15
  const body = {
14
16
  model: request.model,
@@ -24,50 +26,80 @@ export class OpenAIStreaming {
24
26
  if (request.response_format) {
25
27
  body.response_format = request.response_format;
26
28
  }
27
- const response = await fetch(buildUrl(this.baseUrl, '/chat/completions'), {
28
- method: "POST",
29
- headers: {
30
- "Authorization": `Bearer ${this.apiKey}`,
31
- "Content-Type": "application/json",
32
- ...request.headers,
33
- },
34
- body: JSON.stringify(body),
35
- });
36
- if (!response.ok) {
37
- await handleOpenAIError(response, request.model);
38
- }
39
- if (!response.body) {
40
- throw new Error("No response body for streaming");
41
- }
42
- const reader = response.body.getReader();
43
- const decoder = new TextDecoder();
44
- let buffer = "";
45
- while (true) {
46
- const { value, done } = await reader.read();
47
- if (done)
48
- break;
49
- const chunk = decoder.decode(value, { stream: true });
50
- buffer += chunk;
51
- const lines = buffer.split("\n\n");
52
- buffer = lines.pop() || ""; // Keep the last incomplete part in the buffer
53
- for (const line of lines) {
54
- const trimmed = line.trim();
55
- if (!trimmed.startsWith("data: "))
56
- continue;
57
- const data = trimmed.replace("data: ", "").trim();
58
- if (data === "[DONE]")
59
- return;
60
- try {
61
- const json = JSON.parse(data);
62
- const delta = json.choices?.[0]?.delta?.content;
63
- if (delta) {
64
- yield { content: delta };
29
+ let done = false;
30
+ try {
31
+ const response = await fetch(buildUrl(this.baseUrl, '/chat/completions'), {
32
+ method: "POST",
33
+ headers: {
34
+ "Authorization": `Bearer ${this.apiKey}`,
35
+ "Content-Type": "application/json",
36
+ ...request.headers,
37
+ },
38
+ body: JSON.stringify(body),
39
+ signal: abortController.signal,
40
+ });
41
+ if (!response.ok) {
42
+ await handleOpenAIError(response, request.model);
43
+ }
44
+ if (!response.body) {
45
+ throw new Error("No response body for streaming");
46
+ }
47
+ const reader = response.body.getReader();
48
+ const decoder = new TextDecoder();
49
+ let buffer = "";
50
+ while (true) {
51
+ const { value, done: readerDone } = await reader.read();
52
+ if (readerDone)
53
+ break;
54
+ const chunk = decoder.decode(value, { stream: true });
55
+ buffer += chunk;
56
+ const lines = buffer.split("\n\n");
57
+ buffer = lines.pop() || ""; // Keep the last incomplete part in the buffer
58
+ for (const line of lines) {
59
+ let trimmed = line.trim();
60
+ // Handle carriage returns
61
+ if (trimmed.endsWith('\r')) {
62
+ trimmed = trimmed.substring(0, trimmed.length - 1);
63
+ }
64
+ if (!trimmed.startsWith("data: "))
65
+ continue;
66
+ const data = trimmed.replace("data: ", "").trim();
67
+ if (data === "[DONE]") {
68
+ done = true;
69
+ return;
70
+ }
71
+ try {
72
+ const json = JSON.parse(data);
73
+ // Check for errors in the data
74
+ if (json.error) {
75
+ throw new APIError("OpenAI", response.status, json.error.message || "Stream error");
76
+ }
77
+ const delta = json.choices?.[0]?.delta?.content;
78
+ if (delta) {
79
+ yield { content: delta };
80
+ }
81
+ }
82
+ catch (e) {
83
+ // Re-throw APIError
84
+ if (e instanceof APIError)
85
+ throw e;
86
+ // Ignore other parse errors
65
87
  }
66
88
  }
67
- catch (e) {
68
- // Ignore parse errors for now, or log them
69
- // console.warn("JSON parse error in stream:", e);
70
- }
89
+ }
90
+ done = true;
91
+ }
92
+ catch (e) {
93
+ // Graceful exit on abort
94
+ if (e instanceof Error && e.name === 'AbortError') {
95
+ return;
96
+ }
97
+ throw e;
98
+ }
99
+ finally {
100
+ // Cleanup: abort if user breaks early
101
+ if (!done) {
102
+ abortController.abort();
71
103
  }
72
104
  }
73
105
  }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Idempotent registration of the OpenAI provider.
3
- * Automatically called by LLM.configure({ provider: 'openai' })
3
+ * Automatically called by NodeLLM.configure({ provider: 'openai' })
4
4
  */
5
5
  export declare function registerOpenAIProvider(): void;
6
6
  /**
@@ -4,7 +4,7 @@ import { OpenAIProvider } from "./OpenAIProvider.js";
4
4
  let registered = false;
5
5
  /**
6
6
  * Idempotent registration of the OpenAI provider.
7
- * Automatically called by LLM.configure({ provider: 'openai' })
7
+ * Automatically called by NodeLLM.configure({ provider: 'openai' })
8
8
  */
9
9
  export function registerOpenAIProvider() {
10
10
  if (registered)
@@ -0,0 +1,13 @@
1
+ export declare class OpenRouterCapabilities {
2
+ private static findModel;
3
+ static supportsVision(model: string): boolean;
4
+ static supportsTools(model: string): boolean;
5
+ static supportsStructuredOutput(model: string): boolean;
6
+ static supportsEmbeddings(model: string): boolean;
7
+ static supportsImageGeneration(model: string): boolean;
8
+ static supportsTranscription(model: string): boolean;
9
+ static supportsModeration(model: string): boolean;
10
+ static supportsReasoning(model: string): boolean;
11
+ static getContextWindow(model: string): number | null;
12
+ }
13
+ //# sourceMappingURL=Capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Capabilities.d.ts","sourceRoot":"","sources":["../../../src/providers/openrouter/Capabilities.ts"],"names":[],"mappings":"AAEA,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAC,SAAS;IAIxB,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAc7C,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAS5C,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAUvD,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IASjD,MAAM,CAAC,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAItD,MAAM,CAAC,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIpD,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIjD,MAAM,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAWhD,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAItD"}
@@ -0,0 +1,67 @@
1
+ import { ModelRegistry } from "../../models/ModelRegistry.js";
2
+ export class OpenRouterCapabilities {
3
+ static findModel(model) {
4
+ return ModelRegistry.find(model, "openrouter");
5
+ }
6
+ static supportsVision(model) {
7
+ const info = this.findModel(model);
8
+ if (info)
9
+ return info.capabilities.includes('vision') || info.modalities.input.includes('image');
10
+ // Fallback heuristics
11
+ return model.includes('vision') ||
12
+ model.includes('gpt-4o') ||
13
+ model.includes('claude-3') ||
14
+ model.includes('gemini-1.5') ||
15
+ model.includes('gemini-2.0') ||
16
+ model.includes('flash') ||
17
+ model.includes('gemini-pro-vision');
18
+ }
19
+ static supportsTools(model) {
20
+ const info = this.findModel(model);
21
+ if (info)
22
+ return info.capabilities.includes('tools') || info.capabilities.includes('function_calling');
23
+ // Fallback: Default to true for OpenRouter as most models support tools
24
+ // but this is the "honest" check we wanted.
25
+ return true;
26
+ }
27
+ static supportsStructuredOutput(model) {
28
+ const info = this.findModel(model);
29
+ if (info)
30
+ return info.capabilities.includes('structured_output') || info.id.includes('gpt-4');
31
+ // Fallback heuristics
32
+ return model.includes('gpt-4') ||
33
+ model.includes('gpt-3.5') ||
34
+ model.includes('claude-3');
35
+ }
36
+ static supportsEmbeddings(model) {
37
+ const info = this.findModel(model);
38
+ if (info)
39
+ return info.capabilities.includes('embeddings');
40
+ // Fallback heuristics
41
+ return model.includes('embedding') ||
42
+ model.includes('text-sdk');
43
+ }
44
+ static supportsImageGeneration(model) {
45
+ return false;
46
+ }
47
+ static supportsTranscription(model) {
48
+ return false;
49
+ }
50
+ static supportsModeration(model) {
51
+ return false;
52
+ }
53
+ static supportsReasoning(model) {
54
+ const info = this.findModel(model);
55
+ if (info)
56
+ return info.capabilities.includes('reasoning');
57
+ // Fallback heuristics
58
+ return model.includes('o1') ||
59
+ model.includes('o3') ||
60
+ model.includes('deepseek-r1') ||
61
+ model.includes('qwq');
62
+ }
63
+ static getContextWindow(model) {
64
+ const info = this.findModel(model);
65
+ return info?.context_window ?? null;
66
+ }
67
+ }
@@ -0,0 +1,11 @@
1
+ import { ModelInfo } from "../Provider.js";
2
+ export declare class OpenRouterModels {
3
+ private readonly baseUrl;
4
+ private readonly apiKey;
5
+ constructor(baseUrl: string, apiKey: string);
6
+ execute(): Promise<ModelInfo[]>;
7
+ private parseModel;
8
+ private parseCapabilities;
9
+ private parsePricing;
10
+ }
11
+ //# sourceMappingURL=Models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Models.d.ts","sourceRoot":"","sources":["../../../src/providers/openrouter/Models.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAwB3C,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM;IAG3B,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAiBrC,OAAO,CAAC,UAAU;IA0BlB,OAAO,CAAC,iBAAiB;IAyBzB,OAAO,CAAC,YAAY;CA2BrB"}
@@ -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 NodeLLM.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 NodeLLM.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
  /**
@@ -15,10 +21,16 @@ class ProviderRegistry {
15
21
  resolve(name) {
16
22
  const factory = this.providers.get(name);
17
23
  if (!factory) {
18
- throw new Error(`Unknown LLM provider '${name}'`);
24
+ throw new Error(`Unknown NodeLLM provider '${name}'`);
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"}