@node-llm/core 0.5.0 → 0.6.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 (70) hide show
  1. package/README.md +46 -7
  2. package/dist/chat/Chat.d.ts +5 -0
  3. package/dist/chat/Chat.d.ts.map +1 -1
  4. package/dist/chat/Chat.js +26 -4
  5. package/dist/chat/ChatOptions.d.ts +3 -0
  6. package/dist/chat/ChatOptions.d.ts.map +1 -1
  7. package/dist/chat/ChatResponse.d.ts +3 -0
  8. package/dist/chat/ChatResponse.d.ts.map +1 -1
  9. package/dist/chat/ChatResponse.js +3 -0
  10. package/dist/llm.d.ts +5 -1
  11. package/dist/llm.d.ts.map +1 -1
  12. package/dist/llm.js +18 -6
  13. package/dist/models/ModelRegistry.d.ts +39 -12
  14. package/dist/models/ModelRegistry.d.ts.map +1 -1
  15. package/dist/models/ModelRegistry.js +50 -40
  16. package/dist/models/models.d.ts +972 -0
  17. package/dist/models/models.d.ts.map +1 -0
  18. package/dist/models/models.js +7026 -0
  19. package/dist/models/types.d.ts +50 -0
  20. package/dist/models/types.d.ts.map +1 -0
  21. package/dist/models/types.js +1 -0
  22. package/dist/providers/Provider.d.ts +4 -0
  23. package/dist/providers/Provider.d.ts.map +1 -1
  24. package/dist/providers/anthropic/AnthropicProvider.d.ts.map +1 -1
  25. package/dist/providers/anthropic/AnthropicProvider.js +1 -3
  26. package/dist/providers/anthropic/Capabilities.d.ts +1 -37
  27. package/dist/providers/anthropic/Capabilities.d.ts.map +1 -1
  28. package/dist/providers/anthropic/Capabilities.js +59 -130
  29. package/dist/providers/anthropic/Chat.d.ts.map +1 -1
  30. package/dist/providers/anthropic/Chat.js +6 -2
  31. package/dist/providers/anthropic/Models.d.ts +1 -0
  32. package/dist/providers/anthropic/Models.d.ts.map +1 -1
  33. package/dist/providers/anthropic/Models.js +36 -41
  34. package/dist/providers/anthropic/Streaming.d.ts.map +1 -1
  35. package/dist/providers/anthropic/Streaming.js +10 -1
  36. package/dist/providers/gemini/Capabilities.d.ts +28 -7
  37. package/dist/providers/gemini/Capabilities.d.ts.map +1 -1
  38. package/dist/providers/gemini/Capabilities.js +32 -20
  39. package/dist/providers/gemini/Chat.d.ts.map +1 -1
  40. package/dist/providers/gemini/Chat.js +9 -11
  41. package/dist/providers/gemini/Models.d.ts +1 -0
  42. package/dist/providers/gemini/Models.d.ts.map +1 -1
  43. package/dist/providers/gemini/Models.js +46 -26
  44. package/dist/providers/openai/Capabilities.d.ts +3 -11
  45. package/dist/providers/openai/Capabilities.d.ts.map +1 -1
  46. package/dist/providers/openai/Capabilities.js +119 -122
  47. package/dist/providers/openai/Chat.d.ts.map +1 -1
  48. package/dist/providers/openai/Chat.js +19 -17
  49. package/dist/providers/openai/Embedding.d.ts.map +1 -1
  50. package/dist/providers/openai/Embedding.js +2 -1
  51. package/dist/providers/openai/Image.d.ts.map +1 -1
  52. package/dist/providers/openai/Image.js +2 -1
  53. package/dist/providers/openai/ModelDefinitions.d.ts +1 -24
  54. package/dist/providers/openai/ModelDefinitions.d.ts.map +1 -1
  55. package/dist/providers/openai/ModelDefinitions.js +1 -211
  56. package/dist/providers/openai/Models.d.ts +1 -0
  57. package/dist/providers/openai/Models.d.ts.map +1 -1
  58. package/dist/providers/openai/Models.js +46 -22
  59. package/dist/providers/openai/Moderation.d.ts.map +1 -1
  60. package/dist/providers/openai/Moderation.js +2 -1
  61. package/dist/providers/openai/Streaming.d.ts.map +1 -1
  62. package/dist/providers/openai/Streaming.js +5 -1
  63. package/dist/providers/openai/Transcription.d.ts.map +1 -1
  64. package/dist/providers/openai/Transcription.js +3 -2
  65. package/dist/providers/openai/index.d.ts.map +1 -1
  66. package/dist/providers/openai/index.js +2 -1
  67. package/dist/providers/openai/utils.d.ts +20 -0
  68. package/dist/providers/openai/utils.d.ts.map +1 -0
  69. package/dist/providers/openai/utils.js +25 -0
  70. package/package.json +1 -1
@@ -1,5 +1,7 @@
1
1
  import { Capabilities } from "./Capabilities.js";
2
2
  import { handleOpenAIError } from "./Errors.js";
3
+ import { ModelRegistry } from "../../models/ModelRegistry.js";
4
+ import { buildUrl } from "./utils.js";
3
5
  export class OpenAIChat {
4
6
  baseUrl;
5
7
  apiKey;
@@ -9,25 +11,24 @@ export class OpenAIChat {
9
11
  }
10
12
  async execute(request) {
11
13
  const temperature = Capabilities.normalizeTemperature(request.temperature, request.model);
14
+ const { model, messages, tools, temperature: _, max_tokens, response_format, headers, ...rest } = request;
12
15
  const body = {
13
- model: request.model,
14
- messages: request.messages,
16
+ model,
17
+ messages,
18
+ ...rest
15
19
  };
16
- if (temperature !== undefined) {
17
- if (temperature !== null) {
18
- body.temperature = temperature;
19
- }
20
+ if (temperature !== undefined && temperature !== null)
21
+ body.temperature = temperature;
22
+ if (max_tokens)
23
+ body.max_tokens = max_tokens;
24
+ if (tools)
25
+ body.tools = tools;
26
+ if (response_format)
27
+ body.response_format = response_format;
28
+ if (process.env.NODELLM_DEBUG === "true") {
29
+ console.log(`[OpenAI Request] ${JSON.stringify(body, null, 2)}`);
20
30
  }
21
- if (request.max_tokens) {
22
- body.max_tokens = request.max_tokens;
23
- }
24
- if (request.tools) {
25
- body.tools = request.tools;
26
- }
27
- if (request.response_format) {
28
- body.response_format = request.response_format;
29
- }
30
- const response = await fetch(`${this.baseUrl}/chat/completions`, {
31
+ const response = await fetch(buildUrl(this.baseUrl, '/chat/completions'), {
31
32
  method: "POST",
32
33
  headers: {
33
34
  "Authorization": `Bearer ${this.apiKey}`,
@@ -52,6 +53,7 @@ export class OpenAIChat {
52
53
  if (!content && !tool_calls) {
53
54
  throw new Error("OpenAI returned empty response");
54
55
  }
55
- return { content, tool_calls, usage };
56
+ const calculatedUsage = usage ? ModelRegistry.calculateCost(usage, model, "openai") : undefined;
57
+ return { content, tool_calls, usage: calculatedUsage };
56
58
  }
57
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Embedding.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Embedding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAKtE,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM;IAG3B,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA8CrE"}
1
+ {"version":3,"file":"Embedding.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Embedding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAMtE,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM;IAG3B,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA8CrE"}
@@ -1,6 +1,7 @@
1
1
  import { handleOpenAIError } from "./Errors.js";
2
2
  import { Capabilities } from "./Capabilities.js";
3
3
  import { DEFAULT_MODELS } from "../../constants.js";
4
+ import { buildUrl } from "./utils.js";
4
5
  export class OpenAIEmbedding {
5
6
  baseUrl;
6
7
  apiKey;
@@ -24,7 +25,7 @@ export class OpenAIEmbedding {
24
25
  if (request.user) {
25
26
  body.user = request.user;
26
27
  }
27
- const response = await fetch(`${this.baseUrl}/embeddings`, {
28
+ const response = await fetch(buildUrl(this.baseUrl, '/embeddings'), {
28
29
  method: "POST",
29
30
  headers: {
30
31
  "Authorization": `Bearer ${this.apiKey}`,
@@ -1 +1 @@
1
- {"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG7D,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;CAmC7D"}
1
+ {"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAI7D,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;CAmC7D"}
@@ -1,4 +1,5 @@
1
1
  import { handleOpenAIError } from "./Errors.js";
2
+ import { buildUrl } from "./utils.js";
2
3
  export class OpenAIImage {
3
4
  baseUrl;
4
5
  apiKey;
@@ -14,7 +15,7 @@ export class OpenAIImage {
14
15
  quality: request.quality || "standard",
15
16
  n: request.n || 1,
16
17
  };
17
- const response = await fetch(`${this.baseUrl}/images/generations`, {
18
+ const response = await fetch(buildUrl(this.baseUrl, '/images/generations'), {
18
19
  method: "POST",
19
20
  headers: {
20
21
  "Authorization": `Bearer ${this.apiKey}`,
@@ -1,25 +1,2 @@
1
- export interface ModelPricing {
2
- input?: number;
3
- output?: number;
4
- price?: number;
5
- cached_input?: number;
6
- audio_input?: number;
7
- audio_output?: number;
8
- }
9
- export interface ModelFeatures {
10
- vision?: boolean;
11
- tools?: boolean;
12
- structuredOutput?: boolean;
13
- jsonMode?: boolean;
14
- }
15
- export type ModelType = "chat" | "embedding" | "audio" | "image" | "moderation";
16
- export interface ModelFamilyDefinition {
17
- pattern: RegExp;
18
- contextWindow: number | null;
19
- maxOutputTokens: number | null;
20
- pricing: ModelPricing;
21
- features: ModelFeatures;
22
- type: ModelType;
23
- }
24
- export declare const OPENAI_MODELS: Record<string, ModelFamilyDefinition>;
1
+ export {};
25
2
  //# sourceMappingURL=ModelDefinitions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ModelDefinitions.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/ModelDefinitions.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,GAAG,YAAY,CAAC;AAEhF,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAE,YAAY,CAAC;IACtB,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAkN/D,CAAC"}
1
+ {"version":3,"file":"ModelDefinitions.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/ModelDefinitions.ts"],"names":[],"mappings":""}
@@ -1,211 +1 @@
1
- export const OPENAI_MODELS = {
2
- gpt5: {
3
- pattern: /^gpt-5/,
4
- contextWindow: 128_000,
5
- maxOutputTokens: 400_000,
6
- pricing: { input: 1.25, output: 10.0, cached_input: 0.125 },
7
- features: { vision: true, tools: true, structuredOutput: true },
8
- type: "chat"
9
- },
10
- gpt5_mini: {
11
- pattern: /^gpt-5-mini/,
12
- contextWindow: 128_000,
13
- maxOutputTokens: 400_000,
14
- pricing: { input: 0.25, output: 2.0, cached_input: 0.025 },
15
- features: { vision: true, tools: true, structuredOutput: true },
16
- type: "chat"
17
- },
18
- gpt5_nano: {
19
- pattern: /^gpt-5-nano/,
20
- contextWindow: 128_000,
21
- maxOutputTokens: 400_000,
22
- pricing: { input: 0.05, output: 0.4, cached_input: 0.005 },
23
- features: { vision: true, tools: true, structuredOutput: true },
24
- type: "chat"
25
- },
26
- gpt41: {
27
- pattern: /^gpt-4\.1(?!-(?:mini|nano))/,
28
- contextWindow: 1_047_576,
29
- maxOutputTokens: 32_768,
30
- pricing: { input: 2.0, output: 8.0, cached_input: 0.5 },
31
- features: { vision: true, tools: true, structuredOutput: true },
32
- type: "chat"
33
- },
34
- gpt41_mini: {
35
- pattern: /^gpt-4\.1-mini/,
36
- contextWindow: 1_047_576,
37
- maxOutputTokens: 32_768,
38
- pricing: { input: 0.4, output: 1.6, cached_input: 0.1 },
39
- features: { vision: true, tools: true, structuredOutput: true },
40
- type: "chat"
41
- },
42
- gpt41_nano: {
43
- pattern: /^gpt-4\.1-nano/,
44
- contextWindow: 1_047_576,
45
- maxOutputTokens: 32_768,
46
- pricing: { input: 0.1, output: 0.4 },
47
- features: { vision: true, tools: true, structuredOutput: true },
48
- type: "chat"
49
- },
50
- chatgpt4o: {
51
- pattern: /^chatgpt-4o/,
52
- contextWindow: 128_000,
53
- maxOutputTokens: 16_384,
54
- pricing: { input: 5.0, output: 15.0 },
55
- features: { vision: true, tools: false, structuredOutput: true },
56
- type: "chat"
57
- },
58
- gpt4: {
59
- pattern: /^gpt-4(?:-\d{6})?$/,
60
- contextWindow: 8_192,
61
- maxOutputTokens: 8_192,
62
- pricing: { input: 10.0, output: 30.0 },
63
- features: { vision: true, tools: true, structuredOutput: false },
64
- type: "chat"
65
- },
66
- gpt4_turbo: {
67
- pattern: /^gpt-4(?:\.5)?-(?:\d{6}-)?(preview|turbo)/,
68
- contextWindow: 128_000,
69
- maxOutputTokens: 4_096,
70
- pricing: { input: 10.0, output: 30.0 },
71
- features: { vision: true, tools: true, structuredOutput: false },
72
- type: "chat"
73
- },
74
- gpt45: {
75
- pattern: /^gpt-4\.5/, // Assuming pattern based on name, wasn't explicit in MODEL_PATTERNS but listed in type
76
- contextWindow: 128_000, // Guessing based on gpt-4-turbo
77
- maxOutputTokens: 4_096,
78
- pricing: { input: 75.0, output: 150.0 },
79
- features: { vision: true, tools: true, structuredOutput: true },
80
- type: "chat"
81
- },
82
- gpt35_turbo: {
83
- pattern: /^gpt-3\.5-turbo/,
84
- contextWindow: 16_385,
85
- maxOutputTokens: 4_096,
86
- pricing: { input: 0.5, output: 1.5 },
87
- features: { vision: false, tools: false, structuredOutput: false },
88
- type: "chat"
89
- },
90
- gpt4o: {
91
- pattern: /^gpt-4o(?!-(?:mini|audio|realtime|transcribe|tts|search))/,
92
- contextWindow: 128_000,
93
- maxOutputTokens: 16_384,
94
- pricing: { input: 2.5, output: 10.0 },
95
- features: { vision: true, tools: true, structuredOutput: true },
96
- type: "chat"
97
- },
98
- gpt4o_audio: {
99
- pattern: /^gpt-4o-(?:audio)/,
100
- contextWindow: 128_000,
101
- maxOutputTokens: 16_384, // Assuming same as gpt4o
102
- pricing: { input: 2.5, output: 10.0, audio_input: 40.0, audio_output: 80.0 },
103
- features: { vision: false, tools: false, structuredOutput: false }, // Check features
104
- type: "audio"
105
- },
106
- gpt4o_mini: {
107
- pattern: /^gpt-4o-mini(?!-(?:audio|realtime|transcribe|tts|search))/,
108
- contextWindow: 128_000,
109
- maxOutputTokens: 16_384,
110
- pricing: { input: 0.15, output: 0.6 },
111
- features: { vision: true, tools: true, structuredOutput: true },
112
- type: "chat"
113
- },
114
- o1: {
115
- pattern: /^o1(?!-(?:mini|pro))/,
116
- contextWindow: 200_000,
117
- maxOutputTokens: 100_000,
118
- pricing: { input: 15.0, output: 60.0 },
119
- features: { vision: true, tools: true, structuredOutput: true },
120
- type: "chat"
121
- },
122
- o1_mini: {
123
- pattern: /^o1-mini/,
124
- contextWindow: 128_000,
125
- maxOutputTokens: 65_536,
126
- pricing: { input: 1.1, output: 4.4 },
127
- features: { vision: false, tools: false, structuredOutput: false }, // Check features
128
- type: "chat"
129
- },
130
- o1_pro: {
131
- pattern: /^o1-pro/,
132
- contextWindow: 200_000,
133
- maxOutputTokens: 100_000,
134
- pricing: { input: 150.0, output: 600.0 },
135
- features: { vision: true, tools: true, structuredOutput: true },
136
- type: "chat"
137
- },
138
- o3_mini: {
139
- pattern: /^o3-mini/,
140
- contextWindow: 200_000,
141
- maxOutputTokens: 100_000,
142
- pricing: { input: 1.1, output: 4.4 },
143
- features: { vision: false, tools: true, structuredOutput: true },
144
- type: "chat"
145
- },
146
- embedding3_small: {
147
- pattern: /^text-embedding-3-small/,
148
- contextWindow: null,
149
- maxOutputTokens: null,
150
- pricing: { price: 0.02 },
151
- features: { vision: false, tools: false, structuredOutput: false },
152
- type: "embedding"
153
- },
154
- embedding3_large: {
155
- pattern: /^text-embedding-3-large/,
156
- contextWindow: null,
157
- maxOutputTokens: null,
158
- pricing: { price: 0.13 },
159
- features: { vision: false, tools: false, structuredOutput: false },
160
- type: "embedding"
161
- },
162
- embedding_ada: {
163
- pattern: /^text-embedding-ada/,
164
- contextWindow: null,
165
- maxOutputTokens: null,
166
- pricing: { price: 0.10 },
167
- features: { vision: false, tools: false, structuredOutput: false },
168
- type: "embedding"
169
- },
170
- moderation: {
171
- pattern: /^(?:omni|text)-moderation/,
172
- contextWindow: null,
173
- maxOutputTokens: null,
174
- pricing: { price: 0.0 },
175
- features: { vision: true, tools: false, structuredOutput: false },
176
- type: "moderation"
177
- },
178
- dall_e: {
179
- pattern: /^dall-e/,
180
- contextWindow: null,
181
- maxOutputTokens: null,
182
- pricing: {}, // Variable
183
- features: { vision: false, tools: false, structuredOutput: false },
184
- type: "image"
185
- },
186
- whisper: {
187
- pattern: /^whisper/,
188
- contextWindow: null,
189
- maxOutputTokens: null,
190
- pricing: { price: 0.006 },
191
- features: { vision: false, tools: false, structuredOutput: false },
192
- type: "audio"
193
- },
194
- tts1: {
195
- pattern: /^tts-1(?!-hd)/,
196
- contextWindow: null,
197
- maxOutputTokens: null,
198
- pricing: { price: 15.0 },
199
- features: { vision: false, tools: false, structuredOutput: false },
200
- type: "audio"
201
- },
202
- // Default fallback
203
- other: {
204
- pattern: /.*/,
205
- contextWindow: 4_096,
206
- maxOutputTokens: 16_384,
207
- pricing: { input: 0.5, output: 1.5 },
208
- features: { vision: false, tools: false, structuredOutput: false },
209
- type: "chat"
210
- }
211
- };
1
+ export {};
@@ -4,5 +4,6 @@ export declare class OpenAIModels {
4
4
  private readonly apiKey;
5
5
  constructor(baseUrl: string, apiKey: string);
6
6
  execute(): Promise<ModelInfo[]>;
7
+ find(modelId: string): import("../../models/types.js").Model | undefined;
7
8
  }
8
9
  //# sourceMappingURL=Models.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Models.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Models.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;CA4BtC"}
1
+ {"version":3,"file":"Models.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Models.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAM3C,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAkDrC,IAAI,CAAC,OAAO,EAAE,MAAM;CAGrB"}
@@ -1,4 +1,6 @@
1
1
  import { Capabilities } from "./Capabilities.js";
2
+ import { ModelRegistry } from "../../models/ModelRegistry.js";
3
+ import { buildUrl } from "./utils.js";
2
4
  export class OpenAIModels {
3
5
  baseUrl;
4
6
  apiKey;
@@ -7,29 +9,51 @@ export class OpenAIModels {
7
9
  this.apiKey = apiKey;
8
10
  }
9
11
  async execute() {
10
- const response = await fetch(`${this.baseUrl}/models`, {
11
- headers: {
12
- "Authorization": `Bearer ${this.apiKey}`,
13
- },
14
- });
15
- if (!response.ok) {
16
- const errorText = await response.text();
17
- throw new Error(`OpenAI error (${response.status}): ${errorText}`);
12
+ try {
13
+ const response = await fetch(buildUrl(this.baseUrl, '/models'), {
14
+ method: "GET",
15
+ headers: {
16
+ "Authorization": `Bearer ${this.apiKey}`,
17
+ "Content-Type": "application/json",
18
+ },
19
+ });
20
+ if (response.ok) {
21
+ const { data } = await response.json();
22
+ return data.map(m => {
23
+ const modelId = m.id;
24
+ const registryModel = ModelRegistry.find(modelId, "openai");
25
+ const info = {
26
+ id: modelId,
27
+ name: registryModel?.name || Capabilities.formatDisplayName(modelId),
28
+ provider: "openai",
29
+ family: registryModel?.family || modelId,
30
+ context_window: registryModel?.context_window || Capabilities.getContextWindow(modelId),
31
+ max_output_tokens: registryModel?.max_output_tokens || Capabilities.getMaxOutputTokens(modelId),
32
+ modalities: registryModel?.modalities || Capabilities.getModalities(modelId),
33
+ capabilities: Capabilities.getCapabilities(modelId),
34
+ pricing: registryModel?.pricing || Capabilities.getPricing(modelId),
35
+ metadata: {
36
+ ...(registryModel?.metadata || {}),
37
+ created: m.created,
38
+ owned_by: m.owned_by
39
+ }
40
+ };
41
+ return info;
42
+ });
43
+ }
18
44
  }
19
- const json = await response.json();
20
- return json.data.map((model) => ({
21
- id: model.id,
22
- name: Capabilities.formatDisplayName(model.id),
23
- provider: "openai",
24
- family: Capabilities.getFamily(model.id),
25
- context_window: Capabilities.getContextWindow(model.id),
26
- max_output_tokens: Capabilities.getMaxOutputTokens(model.id),
27
- modalities: Capabilities.getModalities(model.id),
28
- capabilities: Capabilities.getCapabilities(model.id),
29
- pricing: Capabilities.getPricing(model.id),
30
- metadata: {
31
- owned_by: model.owned_by,
32
- },
45
+ catch (_error) {
46
+ // Fallback to registry if API call fails (e.g. in tests without network)
47
+ }
48
+ // Fallback to registry data
49
+ return ModelRegistry.all()
50
+ .filter(m => m.provider === "openai")
51
+ .map(m => ({
52
+ ...m,
53
+ capabilities: Capabilities.getCapabilities(m.id)
33
54
  }));
34
55
  }
56
+ find(modelId) {
57
+ return ModelRegistry.find(modelId, "openai");
58
+ }
35
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Moderation.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Moderation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAIvE,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAmBvE"}
1
+ {"version":3,"file":"Moderation.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Moderation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAKvE,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAmBvE"}
@@ -1,5 +1,6 @@
1
1
  import { handleOpenAIError } from "./Errors.js";
2
2
  import { DEFAULT_MODELS } from "../../constants.js";
3
+ import { buildUrl } from "./utils.js";
3
4
  export class OpenAIModeration {
4
5
  baseUrl;
5
6
  apiKey;
@@ -8,7 +9,7 @@ export class OpenAIModeration {
8
9
  this.apiKey = apiKey;
9
10
  }
10
11
  async execute(request) {
11
- const response = await fetch(`${this.baseUrl}/moderations`, {
12
+ const response = await fetch(buildUrl(this.baseUrl, '/moderations'), {
12
13
  method: "POST",
13
14
  headers: {
14
15
  "Authorization": `Bearer ${this.apiKey}`,
@@ -1 +1 @@
1
- {"version":3,"file":"Streaming.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAIxD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEtE,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC;CAqEhE"}
1
+ {"version":3,"file":"Streaming.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAKxD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEtE,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC;CAyEhE"}
@@ -1,5 +1,6 @@
1
1
  import { Capabilities } from "./Capabilities.js";
2
2
  import { handleOpenAIError } from "./Errors.js";
3
+ import { buildUrl } from "./utils.js";
3
4
  export class OpenAIStreaming {
4
5
  baseUrl;
5
6
  apiKey;
@@ -20,7 +21,10 @@ export class OpenAIStreaming {
20
21
  if (request.max_tokens) {
21
22
  body.max_tokens = request.max_tokens;
22
23
  }
23
- const response = await fetch(`${this.baseUrl}/chat/completions`, {
24
+ if (request.response_format) {
25
+ body.response_format = request.response_format;
26
+ }
27
+ const response = await fetch(buildUrl(this.baseUrl, '/chat/completions'), {
24
28
  method: "POST",
25
29
  headers: {
26
30
  "Authorization": `Bearer ${this.apiKey}`,
@@ -1 +1 @@
1
- {"version":3,"file":"Transcription.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Transcription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAK7E,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;YAU9D,oBAAoB;YA4CpB,iBAAiB;CAwHhC"}
1
+ {"version":3,"file":"Transcription.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/Transcription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAM7E,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;YAU9D,oBAAoB;YA4CpB,iBAAiB;CAwHhC"}
@@ -1,6 +1,7 @@
1
1
  import { handleOpenAIError } from "./Errors.js";
2
2
  import { AudioUtils } from "../../utils/audio.js";
3
3
  import { DEFAULT_MODELS } from "../../constants.js";
4
+ import { buildUrl } from "./utils.js";
4
5
  export class OpenAITranscription {
5
6
  baseUrl;
6
7
  apiKey;
@@ -29,7 +30,7 @@ export class OpenAITranscription {
29
30
  if (request.language) {
30
31
  formData.append("language", request.language);
31
32
  }
32
- const response = await fetch(`${this.baseUrl}/audio/transcriptions`, {
33
+ const response = await fetch(buildUrl(this.baseUrl, '/audio/transcriptions'), {
33
34
  method: "POST",
34
35
  headers: {
35
36
  "Authorization": `Bearer ${this.apiKey}`,
@@ -119,7 +120,7 @@ export class OpenAITranscription {
119
120
  }
120
121
  ]
121
122
  };
122
- const response = await fetch(`${this.baseUrl}/chat/completions`, {
123
+ const response = await fetch(buildUrl(this.baseUrl, '/chat/completions'), {
123
124
  method: "POST",
124
125
  headers: {
125
126
  "Authorization": `Bearer ${this.apiKey}`,
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/index.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,wBAAgB,sBAAsB,SAcrC;AAED;;GAEG;AACH,eAAO,MAAM,sBAAsB,+BAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/index.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,wBAAgB,sBAAsB,SAerC;AAED;;GAEG;AACH,eAAO,MAAM,sBAAsB,+BAAyB,CAAC"}
@@ -10,10 +10,11 @@ export function registerOpenAIProvider() {
10
10
  return;
11
11
  providerRegistry.register("openai", () => {
12
12
  const apiKey = process.env.OPENAI_API_KEY;
13
+ const baseUrl = process.env.OPENAI_API_BASE;
13
14
  if (!apiKey) {
14
15
  throw new Error("OPENAI_API_KEY is not set");
15
16
  }
16
- return new OpenAIProvider({ apiKey });
17
+ return new OpenAIProvider({ apiKey, baseUrl });
17
18
  });
18
19
  registered = true;
19
20
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Builds a URL by appending an endpoint to a base URL.
3
+ * Handles query parameters correctly by inserting the endpoint before the query string.
4
+ *
5
+ * @param baseUrl - The base URL (may include query parameters)
6
+ * @param endpoint - The endpoint path to append (e.g., '/chat/completions')
7
+ * @returns The complete URL
8
+ *
9
+ * @example
10
+ * // Standard URL
11
+ * buildUrl('https://api.openai.com/v1', '/chat/completions')
12
+ * // => 'https://api.openai.com/v1/chat/completions'
13
+ *
14
+ * @example
15
+ * // URL with query params (Azure)
16
+ * buildUrl('https://resource.azure.com/openai/deployments/gpt-4?api-version=2024-08-01', '/chat/completions')
17
+ * // => 'https://resource.azure.com/openai/deployments/gpt-4/chat/completions?api-version=2024-08-01'
18
+ */
19
+ export declare function buildUrl(baseUrl: string, endpoint: string): string;
20
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/providers/openai/utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMlE"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Builds a URL by appending an endpoint to a base URL.
3
+ * Handles query parameters correctly by inserting the endpoint before the query string.
4
+ *
5
+ * @param baseUrl - The base URL (may include query parameters)
6
+ * @param endpoint - The endpoint path to append (e.g., '/chat/completions')
7
+ * @returns The complete URL
8
+ *
9
+ * @example
10
+ * // Standard URL
11
+ * buildUrl('https://api.openai.com/v1', '/chat/completions')
12
+ * // => 'https://api.openai.com/v1/chat/completions'
13
+ *
14
+ * @example
15
+ * // URL with query params (Azure)
16
+ * buildUrl('https://resource.azure.com/openai/deployments/gpt-4?api-version=2024-08-01', '/chat/completions')
17
+ * // => 'https://resource.azure.com/openai/deployments/gpt-4/chat/completions?api-version=2024-08-01'
18
+ */
19
+ export function buildUrl(baseUrl, endpoint) {
20
+ if (baseUrl.includes('?')) {
21
+ const [basePath, queryString] = baseUrl.split('?');
22
+ return `${basePath}${endpoint}?${queryString}`;
23
+ }
24
+ return `${baseUrl}${endpoint}`;
25
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-llm/core",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",