litellmts-core 1.1.0 → 2.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 (40) hide show
  1. package/README.md +44 -19
  2. package/dist/handlers/ai21.js +7 -5
  3. package/dist/handlers/anthropic.d.ts +1 -1
  4. package/dist/handlers/anthropic.js +22 -103
  5. package/dist/handlers/cohere.js +21 -5
  6. package/dist/handlers/copilot.js +4 -2
  7. package/dist/handlers/deepinfra.js +15 -2
  8. package/dist/handlers/gemini.d.ts +1 -1
  9. package/dist/handlers/gemini.js +41 -89
  10. package/dist/handlers/geminiEmbedding.d.ts +1 -1
  11. package/dist/handlers/geminiEmbedding.js +6 -9
  12. package/dist/handlers/mistral.js +15 -2
  13. package/dist/handlers/ollama.js +18 -8
  14. package/dist/handlers/openai.js +18 -3
  15. package/dist/handlers/openaiEmbedding.js +5 -2
  16. package/dist/handlers/openaiLike.d.ts +1 -1
  17. package/dist/handlers/openaiLike.js +26 -3
  18. package/dist/handlers/openaiLikeEmbedding.d.ts +1 -1
  19. package/dist/handlers/openaiLikeEmbedding.js +6 -2
  20. package/dist/handlers/replicate.js +15 -2
  21. package/dist/handlers/vertexAnthropic.d.ts +2 -0
  22. package/dist/handlers/vertexAnthropic.js +43 -0
  23. package/dist/handlers/vertexai.d.ts +2 -0
  24. package/dist/handlers/vertexai.js +51 -0
  25. package/dist/handlers/vertexaiEmbedding.d.ts +2 -0
  26. package/dist/handlers/vertexaiEmbedding.js +31 -0
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.js +5 -1
  29. package/dist/mappings/openaiLike.js +0 -5
  30. package/dist/models/index.d.ts +2 -0
  31. package/dist/models/index.js +7 -0
  32. package/dist/models/registry.d.ts +13 -0
  33. package/dist/models/registry.js +73 -0
  34. package/dist/models/types.d.ts +9 -0
  35. package/dist/models/types.js +2 -0
  36. package/dist/utils/anthropic.d.ts +10 -0
  37. package/dist/utils/anthropic.js +99 -0
  38. package/dist/utils/gemini.d.ts +12 -0
  39. package/dist/utils/gemini.js +73 -0
  40. package/package.json +2 -2
package/README.md CHANGED
@@ -42,7 +42,7 @@ npm install litellmts-core
42
42
  import { completion } from 'litellmts-core';
43
43
 
44
44
  const response = await completion({
45
- model: 'gpt-4o-mini',
45
+ model: 'openai/gpt-4o-mini',
46
46
  messages: [{ role: 'user', content: 'Hello!' }],
47
47
  });
48
48
 
@@ -53,7 +53,7 @@ Swap providers by changing just the model string:
53
53
 
54
54
  ```ts
55
55
  // Same code, different provider:
56
- await completion({ model: 'claude-sonnet-4-20250514', ... });
56
+ await completion({ model: 'anthropic/claude-sonnet-4-20250514', ... });
57
57
  await completion({ model: 'gemini/gemini-2.5-pro', ... });
58
58
  await completion({ model: 'groq/llama-3.3-70b', ... });
59
59
  await completion({ model: 'deepseek/deepseek-chat', ... });
@@ -63,6 +63,8 @@ await completion({ model: 'deepseek/deepseek-chat', ... });
63
63
 
64
64
  - **Unified API** — same `completion()` / `embedding()` for every provider
65
65
  - **Streaming** — all providers support `stream: true`
66
+ - **Model listing** — `listModels('openai')` fetches available models from each provider's API
67
+ - **Provider discovery** — `listProviders()` returns all configured providers
66
68
  - **TypeScript first** — full type safety with auto-completion
67
69
  - **45+ providers** — from OpenAI to niche OpenAI-compatible APIs
68
70
  - **No SDK sprawl** — one dependency replaces 10+ vendor SDKs
@@ -77,7 +79,7 @@ await completion({ model: 'deepseek/deepseek-chat', ... });
77
79
  import { completion } from 'litellmts-core';
78
80
 
79
81
  const response = await completion({
80
- model: 'gpt-4o-mini',
82
+ model: 'openai/gpt-4o-mini',
81
83
  messages: [
82
84
  { role: 'system', content: 'You are a helpful assistant.' },
83
85
  { role: 'user', content: 'What is TypeScript?' },
@@ -96,7 +98,7 @@ console.log(response.usage);
96
98
 
97
99
  ```ts
98
100
  const stream = await completion({
99
- model: 'claude-sonnet-4-20250514',
101
+ model: 'anthropic/claude-sonnet-4-20250514',
100
102
  messages: [{ role: 'user', content: 'Write a poem' }],
101
103
  stream: true,
102
104
  });
@@ -112,13 +114,33 @@ for await (const chunk of stream) {
112
114
  import { embedding } from 'litellmts-core';
113
115
 
114
116
  const result = await embedding({
115
- model: 'text-embedding-3-small',
117
+ model: 'openai/text-embedding-3-small',
116
118
  input: 'Hello world',
117
119
  });
118
120
 
119
121
  console.log(result.data[0].embedding); // number[]
120
122
  ```
121
123
 
124
+ ### Model Discovery
125
+
126
+ ```ts
127
+ import { listModels, listProviders, clearModelCache } from 'litellmts-core';
128
+
129
+ // List all available models for a provider (fetched live from their API)
130
+ const models = await listModels('openai');
131
+ // => [{ id: 'gpt-4o', provider: 'openai', created: 1700000000 }, ...]
132
+
133
+ // List all configured providers
134
+ const providers = listProviders();
135
+ // => [{ name: 'openai', hasModelList: true }, { name: 'groq', hasModelList: true }, ...]
136
+
137
+ // Get models for a specific provider with apiKey override
138
+ const groqModels = await listModels('groq', { apiKey: 'gsk_...' });
139
+
140
+ // Clear cached model lists (re-fetches on next call)
141
+ clearModelCache();
142
+ ```
143
+
122
144
  ### API Keys
123
145
 
124
146
  Keys are read from environment variables by default:
@@ -153,17 +175,17 @@ npx litellm login anthropic
153
175
 
154
176
  ### Dedicated Handlers
155
177
 
156
- | Provider | Prefix | Completion | Streaming | Embedding | API Key Env |
157
- |---|---|---|---|---|---|
158
- | OpenAI | `gpt-*`, `openai/` | ✅ | ✅ | ✅ | `OPENAI_API_KEY` |
159
- | Anthropic | `claude-*` | ✅ | ✅ | ❌ | `ANTHROPIC_API_KEY` |
178
+ | Provider | Model prefix | Completion | Streaming | Embedding | API Key Env |
179
+ |---|---|---|---|---|---|---|
180
+ | OpenAI | `openai/` | ✅ | ✅ | ✅ | `OPENAI_API_KEY` |
181
+ | Anthropic | `anthropic/` | ✅ | ✅ | ❌ | `ANTHROPIC_API_KEY` |
160
182
  | Google Gemini | `gemini/` | ✅ | ✅ | ✅ | `GEMINI_API_KEY` |
161
183
  | GitHub Copilot | `copilot/` | ✅ | ✅ | ❌ | (OAuth) |
162
184
  | Mistral | `mistral/` | ✅ | ✅ | ✅ | `MISTRAL_API_KEY` |
163
- | Cohere | `command*` | ✅ | ✅ | ❌ | `COHERE_API_KEY` |
185
+ | Cohere | `cohere/` | ✅ | ✅ | ❌ | `COHERE_API_KEY` |
164
186
  | DeepInfra | `deepinfra/` | ✅ | ✅ | ❌ | `DEEPINFRA_API_KEY` |
165
187
  | Replicate | `replicate/` | ✅ | ✅ | ❌ | `REPLICATE_API_KEY` |
166
- | AI21 Labs | `j2-*`, `ai21/` | ✅ | ✅ | ❌ | `AI21_API_KEY` |
188
+ | AI21 Labs | `ai21/` | ✅ | ✅ | ❌ | `AI21_API_KEY` |
167
189
  | Ollama (local) | `ollama/` | ✅ | ✅ | ✅ | — |
168
190
 
169
191
  ### OpenAI-Compatible (38 providers)
@@ -213,16 +235,19 @@ npx litellm login anthropic
213
235
  ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐
214
236
  │ completion() │────▶│ getHandler() │────▶│ OpenAIHandler │
215
237
  │ embedding() │ │ (prefix │ │ AnthropicHandler│
216
- │ │ matching) │ │ GeminiHandler │
217
- │ │ │ │ OpenAILikeHandler│
238
+ listModels() │ │ matching) │ │ GeminiHandler │
239
+ listProviders│ │ │ │ OpenAILikeHandler│
218
240
  └──────────────┘ └──────────────┘ └─────────────────┘
219
241
 
220
- ┌──────┴──────┐
221
- │ Registry │
222
- groq/ → .
223
- claude-
224
- gpt- → ..
225
- └─────────────┘
242
+ ┌──────┴──────┐ ┌──────────────────┐
243
+ │ Registry │ │ Model Registry │
244
+ openai/ → │ │ (in-memory │
245
+ anthropic/ │ cache + TTL) │
246
+ groq/ → .. │ │
247
+ └─────────────┘ │ listModels() │
248
+ │ listProviders() │
249
+ │ clearModelCache()│
250
+ └──────────────────┘
226
251
  ```
227
252
 
228
253
  ## Development
@@ -56,9 +56,11 @@ async function AI21Handler(params) {
56
56
  const apiKey = params.apiKey ?? process.env.AI21_API_KEY;
57
57
  if (!apiKey)
58
58
  throw new Error('AI21 requires an API key. Set AI21_API_KEY environment variable or pass apiKey in params.');
59
- const model = params.model;
59
+ const modelName = params.model.startsWith('ai21/')
60
+ ? params.model.slice(5)
61
+ : params.model;
60
62
  const prompt = (0, combinePrompts_1.combinePrompts)(params.messages);
61
- const res = await getAI21Response(model, prompt, baseUrl, apiKey, params.stream ?? false);
63
+ const res = await getAI21Response(modelName, prompt, baseUrl, apiKey, params.stream ?? false);
62
64
  if (!res.ok) {
63
65
  throw new Error(`Received an error with code ${res.status} from AI21 API.`);
64
66
  }
@@ -66,7 +68,7 @@ async function AI21Handler(params) {
66
68
  return (0, sse_1.iterateSSEStream)(res, (payload) => {
67
69
  const parsed = JSON.parse(payload);
68
70
  return {
69
- model,
71
+ model: modelName,
70
72
  created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
71
73
  choices: [
72
74
  {
@@ -81,7 +83,7 @@ async function AI21Handler(params) {
81
83
  });
82
84
  }
83
85
  const body = (await res.json());
84
- return toResponse(body, model);
86
+ return toResponse(body, modelName);
85
87
  }
86
88
  const registry_1 = require("../registry");
87
- (0, registry_1.registerCompletionHandler)('j2-', AI21Handler);
89
+ (0, registry_1.registerCompletionHandler)('ai21/', AI21Handler);
@@ -1,2 +1,2 @@
1
- import { HandlerParams, ResultStreaming, ResultNotStreaming } from '../types';
1
+ import type { HandlerParams, ResultNotStreaming, ResultStreaming } from '../types';
2
2
  export declare function AnthropicHandler(params: HandlerParams): Promise<ResultNotStreaming | ResultStreaming>;
@@ -5,109 +5,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.AnthropicHandler = AnthropicHandler;
7
7
  const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
8
- const getUnixTimestamp_1 = require("../utils/getUnixTimestamp");
8
+ const anthropic_1 = require("../utils/anthropic");
9
9
  const auth_1 = require("../auth");
10
- function toMessages(input) {
11
- let system;
12
- const messages = [];
13
- for (const msg of input) {
14
- if (msg.role === 'system') {
15
- system = (system ? system + '\n' : '') + (msg.content ?? '');
16
- continue;
17
- }
18
- if (msg.role === 'user' || msg.role === 'assistant') {
19
- messages.push({
20
- role: msg.role,
21
- content: msg.content ?? '',
22
- });
23
- }
24
- }
25
- return { system, messages };
26
- }
27
- function toFinishReason(reason) {
28
- if (reason === 'max_tokens') {
29
- return 'length';
30
- }
31
- return 'stop';
32
- }
33
- function getTextContent(content) {
34
- return content
35
- .filter((block) => block.type === 'text')
36
- .map((block) => block.text)
37
- .join('');
38
- }
39
- function toResponse(message) {
40
- return {
41
- model: message.model,
42
- created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
43
- usage: {
44
- prompt_tokens: message.usage.input_tokens,
45
- completion_tokens: message.usage.output_tokens,
46
- total_tokens: message.usage.input_tokens + message.usage.output_tokens,
47
- },
48
- choices: [
49
- {
50
- message: {
51
- content: getTextContent(message.content),
52
- role: 'assistant',
53
- },
54
- finish_reason: toFinishReason(message.stop_reason),
55
- index: 0,
56
- },
57
- ],
58
- };
59
- }
60
- async function* toStreamingResponse(stream) {
61
- let model = '';
62
- let stopReason;
63
- for await (const event of stream) {
64
- switch (event.type) {
65
- case 'message_start':
66
- model = event.message.model;
67
- stopReason = event.message.stop_reason;
68
- break;
69
- case 'content_block_delta':
70
- if (event.delta.type === 'text_delta') {
71
- yield {
72
- model,
73
- created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
74
- choices: [
75
- {
76
- delta: { content: event.delta.text, role: 'assistant' },
77
- finish_reason: null,
78
- index: 0,
79
- },
80
- ],
81
- };
82
- }
83
- break;
84
- case 'message_delta':
85
- stopReason = event.delta.stop_reason;
86
- break;
87
- case 'message_stop':
88
- yield {
89
- model,
90
- created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
91
- choices: [
92
- {
93
- delta: { content: '', role: 'assistant' },
94
- finish_reason: toFinishReason(stopReason),
95
- index: 0,
96
- },
97
- ],
98
- };
99
- break;
100
- }
101
- }
102
- }
10
+ const registry_1 = require("../models/registry");
103
11
  async function AnthropicHandler(params) {
104
12
  const apiKey = params.apiKey ?? process.env.ANTHROPIC_API_KEY ?? (await (0, auth_1.getAnthropicKey)());
105
- const anthropic = new sdk_1.default({
106
- apiKey: apiKey,
107
- });
108
- const { system, messages } = toMessages(params.messages);
13
+ const modelName = params.model.startsWith('anthropic/')
14
+ ? params.model.slice(10)
15
+ : params.model;
16
+ const anthropic = new sdk_1.default({ apiKey });
17
+ const { system, messages } = (0, anthropic_1.toAnthropicMessages)(params.messages);
109
18
  const anthropicParams = {
110
- model: params.model,
19
+ model: modelName,
111
20
  max_tokens: params.max_tokens ?? 300,
112
21
  messages,
113
22
  ...(system ? { system } : {}),
@@ -118,14 +27,24 @@ async function AnthropicHandler(params) {
118
27
  ...anthropicParams,
119
28
  stream: true,
120
29
  });
121
- return toStreamingResponse(stream);
30
+ return (0, anthropic_1.toAnthropicStreamingResponse)(stream);
122
31
  }
123
32
  const message = await anthropic.messages.create(anthropicParams);
124
- return toResponse(message);
33
+ return (0, anthropic_1.toAnthropicResponse)(message);
125
34
  }
126
35
  catch (err) {
127
36
  throw new Error(`Anthropic API error: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
128
37
  }
129
38
  }
130
- const registry_1 = require("../registry");
131
- (0, registry_1.registerCompletionHandler)('claude-', AnthropicHandler);
39
+ (0, registry_1.registerModelProvider)('anthropic', async ({ apiKey } = {}) => {
40
+ const key = apiKey ?? process.env.ANTHROPIC_API_KEY;
41
+ if (!key)
42
+ return [];
43
+ const res = await fetch('https://api.anthropic.com/v1/models', {
44
+ headers: { 'x-api-key': key, 'anthropic-version': '2023-06-01' },
45
+ });
46
+ const { data } = await res.json();
47
+ return data.map((m) => ({ id: m.id, provider: 'anthropic' }));
48
+ });
49
+ const registry_2 = require("../registry");
50
+ (0, registry_2.registerCompletionHandler)('anthropic/', AnthropicHandler);
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CohereHandler = CohereHandler;
4
4
  const cohere_ai_1 = require("cohere-ai");
5
5
  const getUnixTimestamp_1 = require("../utils/getUnixTimestamp");
6
+ const registry_1 = require("../models/registry");
6
7
  function toChatHistory(messages) {
7
8
  let system;
8
9
  const chatMessages = [];
@@ -43,10 +44,13 @@ async function CohereHandler(params) {
43
44
  const apiKey = params.apiKey ?? process.env.COHERE_API_KEY;
44
45
  if (!apiKey)
45
46
  throw new Error('Cohere requires an API key. Set COHERE_API_KEY environment variable or pass apiKey in params.');
47
+ const modelName = params.model.startsWith('cohere/')
48
+ ? params.model.slice(7)
49
+ : params.model;
46
50
  const cohere = new cohere_ai_1.CohereClient({ token: apiKey });
47
51
  const { message, chatHistory, preamble } = toChatHistory(params.messages);
48
52
  const chatParams = {
49
- model: params.model,
53
+ model: modelName,
50
54
  message,
51
55
  ...(chatHistory ? { chatHistory } : {}),
52
56
  ...(preamble ? { preamble } : {}),
@@ -58,11 +62,11 @@ async function CohereHandler(params) {
58
62
  const stream = await cohere.chatStream({
59
63
  ...chatParams,
60
64
  });
61
- return toStreamingResponse(stream, params.model);
65
+ return toStreamingResponse(stream, modelName);
62
66
  }
63
67
  const { text, finishReason, meta } = await cohere.chat(chatParams);
64
68
  return {
65
- model: params.model,
69
+ model: modelName,
66
70
  created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
67
71
  usage: meta?.tokens
68
72
  ? {
@@ -126,5 +130,17 @@ async function* toStreamingResponse(stream, model) {
126
130
  }
127
131
  }
128
132
  }
129
- const registry_1 = require("../registry");
130
- (0, registry_1.registerCompletionHandler)('command', CohereHandler);
133
+ (0, registry_1.registerModelProvider)('cohere', async ({ apiKey } = {}) => {
134
+ const key = apiKey ?? process.env.COHERE_API_KEY;
135
+ if (!key)
136
+ return [];
137
+ const res = await fetch('https://api.cohere.com/v1/models', {
138
+ headers: { Authorization: `Bearer ${key}` },
139
+ });
140
+ if (!res.ok)
141
+ return [];
142
+ const json = await res.json();
143
+ return (json.models ?? []).map((m) => ({ id: m.id, provider: 'cohere' }));
144
+ });
145
+ const registry_2 = require("../registry");
146
+ (0, registry_2.registerCompletionHandler)('cohere/', CohereHandler);
@@ -132,5 +132,7 @@ async function CopilotHandler(params) {
132
132
  };
133
133
  return result;
134
134
  }
135
- const registry_1 = require("../registry");
136
- (0, registry_1.registerCompletionHandler)('copilot/', CopilotHandler);
135
+ const registry_1 = require("../models/registry");
136
+ (0, registry_1.registerModelProvider)('copilot', async () => []);
137
+ const registry_2 = require("../registry");
138
+ (0, registry_2.registerCompletionHandler)('copilot/', CopilotHandler);
@@ -54,5 +54,18 @@ async function DeepInfraHandler(params) {
54
54
  };
55
55
  return result;
56
56
  }
57
- const registry_1 = require("../registry");
58
- (0, registry_1.registerCompletionHandler)('deepinfra/', DeepInfraHandler);
57
+ const registry_1 = require("../models/registry");
58
+ (0, registry_1.registerModelProvider)('deepinfra', async ({ apiKey } = {}) => {
59
+ const key = apiKey ?? process.env.DEEPINFRA_API_KEY;
60
+ if (!key)
61
+ return [];
62
+ const res = await fetch('https://api.deepinfra.com/v1/openai/models', {
63
+ headers: { Authorization: `Bearer ${key}` },
64
+ });
65
+ if (!res.ok)
66
+ return [];
67
+ const { data } = await res.json();
68
+ return (data ?? []).map((m) => ({ id: m.id, provider: 'deepinfra' }));
69
+ });
70
+ const registry_2 = require("../registry");
71
+ (0, registry_2.registerCompletionHandler)('deepinfra/', DeepInfraHandler);
@@ -1,2 +1,2 @@
1
- import { HandlerParams, ResultNotStreaming, ResultStreaming } from '../types';
1
+ import type { HandlerParams, ResultNotStreaming, ResultStreaming } from '../types';
2
2
  export declare function GeminiHandler(params: HandlerParams): Promise<ResultNotStreaming | ResultStreaming>;
@@ -1,78 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GeminiHandler = GeminiHandler;
4
- const generative_ai_1 = require("@google/generative-ai");
5
- const getUnixTimestamp_1 = require("../utils/getUnixTimestamp");
6
- function toGeminiContent(messages) {
7
- return messages.map((msg) => {
8
- const parts = [];
9
- if (msg.content) {
10
- parts.push({ text: msg.content });
11
- }
12
- return {
13
- role: msg.role === 'assistant' ? 'model' : msg.role,
14
- parts,
15
- };
16
- });
17
- }
18
- function toFinishReason(reason) {
19
- switch (reason) {
20
- case 'STOP':
21
- return 'stop';
22
- case 'MAX_TOKENS':
23
- return 'length';
24
- default:
25
- return 'stop';
26
- }
27
- }
28
- function toUsage(meta) {
29
- if (!meta)
30
- return undefined;
31
- return {
32
- prompt_tokens: meta.promptTokenCount,
33
- completion_tokens: meta.candidatesTokenCount,
34
- total_tokens: meta.totalTokenCount,
35
- };
36
- }
37
- function toResponse(response, model) {
38
- const candidate = response.candidates?.[0];
39
- return {
40
- model: model,
41
- created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
42
- usage: toUsage(response.usageMetadata),
43
- choices: [
44
- {
45
- index: candidate?.index ?? 0,
46
- finish_reason: toFinishReason(candidate?.finishReason),
47
- message: {
48
- role: 'assistant',
49
- content: candidate ? candidate.content.parts.map((p) => 'text' in p ? p.text : '').join('') : null,
50
- },
51
- },
52
- ],
53
- };
54
- }
55
- async function* toStreamingResponse(stream, model) {
56
- for await (const chunk of stream) {
57
- const candidate = chunk.candidates?.[0];
58
- const deltaContent = candidate?.content.parts.map((p) => 'text' in p ? p.text : '').join('') ?? '';
59
- yield {
60
- model,
61
- created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
62
- usage: toUsage(chunk.usageMetadata),
63
- choices: [
64
- {
65
- index: candidate?.index ?? 0,
66
- finish_reason: toFinishReason(candidate?.finishReason),
67
- delta: {
68
- content: deltaContent,
69
- role: 'assistant',
70
- },
71
- },
72
- ],
73
- };
74
- }
75
- }
4
+ const genai_1 = require("@google/genai");
5
+ const gemini_1 = require("../utils/gemini");
76
6
  async function GeminiHandler(params) {
77
7
  const apiKey = params.apiKey ?? process.env.GEMINI_API_KEY;
78
8
  if (!apiKey)
@@ -80,28 +10,50 @@ async function GeminiHandler(params) {
80
10
  const modelName = params.model.startsWith('gemini/')
81
11
  ? params.model.slice(7)
82
12
  : params.model;
83
- const genAI = new generative_ai_1.GoogleGenerativeAI(apiKey);
84
- const model = genAI.getGenerativeModel({
85
- model: modelName,
86
- generationConfig: {
87
- temperature: params.temperature ?? undefined,
88
- topP: params.top_p ?? undefined,
89
- maxOutputTokens: params.max_tokens ?? undefined,
90
- stopSequences: params.stop ? (Array.isArray(params.stop) ? params.stop : [params.stop]) : undefined,
91
- },
92
- });
93
- const contents = toGeminiContent(params.messages);
13
+ const client = new genai_1.GoogleGenAI({ apiKey });
14
+ const contents = (0, gemini_1.toGeminiContent)(params.messages);
94
15
  try {
95
16
  if (params.stream) {
96
- const result = await model.generateContentStream({ contents });
97
- return toStreamingResponse(result.stream, modelName);
17
+ const stream = await client.models.generateContentStream({
18
+ model: modelName,
19
+ contents,
20
+ config: {
21
+ temperature: params.temperature ?? undefined,
22
+ topP: params.top_p ?? undefined,
23
+ maxOutputTokens: params.max_tokens ?? undefined,
24
+ stopSequences: params.stop ? (Array.isArray(params.stop) ? params.stop : [params.stop]) : undefined,
25
+ },
26
+ });
27
+ return (0, gemini_1.toStreamingResponse)(stream, modelName);
98
28
  }
99
- const result = await model.generateContent({ contents });
100
- return toResponse(result.response, modelName);
29
+ const response = await client.models.generateContent({
30
+ model: modelName,
31
+ contents,
32
+ config: {
33
+ temperature: params.temperature ?? undefined,
34
+ topP: params.top_p ?? undefined,
35
+ maxOutputTokens: params.max_tokens ?? undefined,
36
+ stopSequences: params.stop ? (Array.isArray(params.stop) ? params.stop : [params.stop]) : undefined,
37
+ },
38
+ });
39
+ return (0, gemini_1.toResponse)(response, modelName);
101
40
  }
102
41
  catch (err) {
103
42
  throw new Error(`Gemini API error: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
104
43
  }
105
44
  }
106
- const registry_1 = require("../registry");
107
- (0, registry_1.registerCompletionHandler)('gemini/', GeminiHandler);
45
+ const registry_1 = require("../models/registry");
46
+ (0, registry_1.registerModelProvider)('gemini', async ({ apiKey } = {}) => {
47
+ const key = apiKey ?? process.env.GEMINI_API_KEY;
48
+ if (!key)
49
+ return [];
50
+ const client = new genai_1.GoogleGenAI({ apiKey: key });
51
+ const pager = await client.models.list();
52
+ const models = [];
53
+ for await (const m of pager) {
54
+ models.push({ id: m.name ?? m.displayName, provider: 'gemini' });
55
+ }
56
+ return models;
57
+ });
58
+ const registry_2 = require("../registry");
59
+ (0, registry_2.registerCompletionHandler)('gemini/', GeminiHandler);
@@ -1,2 +1,2 @@
1
- import { EmbeddingParams, EmbeddingResponse } from '../types';
1
+ import type { EmbeddingParams, EmbeddingResponse } from '../types';
2
2
  export declare function GeminiEmbeddingHandler(params: EmbeddingParams): Promise<EmbeddingResponse>;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GeminiEmbeddingHandler = GeminiEmbeddingHandler;
4
- const generative_ai_1 = require("@google/generative-ai");
4
+ const genai_1 = require("@google/genai");
5
5
  async function GeminiEmbeddingHandler(params) {
6
6
  const apiKey = params.apiKey ?? process.env.GEMINI_API_KEY;
7
7
  if (!apiKey)
@@ -9,20 +9,17 @@ async function GeminiEmbeddingHandler(params) {
9
9
  const modelName = params.model.startsWith('gemini/')
10
10
  ? params.model.slice(7)
11
11
  : params.model;
12
- const genAI = new generative_ai_1.GoogleGenerativeAI(apiKey);
13
- const model = genAI.getGenerativeModel({ model: modelName });
12
+ const client = new genai_1.GoogleGenAI({ apiKey });
14
13
  const input = typeof params.input === 'string'
15
14
  ? params.input
16
15
  : params.input.join(' ');
17
- const result = await model.embedContent({
18
- content: {
19
- role: 'user',
20
- parts: [{ text: input }],
21
- },
16
+ const result = await client.models.embedContent({
17
+ model: modelName,
18
+ contents: [{ role: 'user', parts: [{ text: input }] }],
22
19
  });
23
20
  return {
24
21
  model: modelName,
25
- data: [{ embedding: result.embedding.values, index: 0 }],
22
+ data: [{ embedding: result.embeddings?.[0]?.values ?? [], index: 0 }],
26
23
  };
27
24
  }
28
25
  const registry_1 = require("../registry");
@@ -54,5 +54,18 @@ async function MistralHandler(params) {
54
54
  };
55
55
  return result;
56
56
  }
57
- const registry_1 = require("../registry");
58
- (0, registry_1.registerCompletionHandler)('mistral/', MistralHandler);
57
+ const registry_1 = require("../models/registry");
58
+ (0, registry_1.registerModelProvider)('mistral', async ({ apiKey } = {}) => {
59
+ const key = apiKey ?? process.env.MISTRAL_API_KEY;
60
+ if (!key)
61
+ return [];
62
+ const res = await fetch('https://api.mistral.ai/v1/models', {
63
+ headers: { Authorization: `Bearer ${key}` },
64
+ });
65
+ if (!res.ok)
66
+ return [];
67
+ const { data } = await res.json();
68
+ return (data ?? []).map((m) => ({ id: m.id, provider: 'mistral' }));
69
+ });
70
+ const registry_2 = require("../registry");
71
+ (0, registry_2.registerCompletionHandler)('mistral/', MistralHandler);