litellmts-core 1.0.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -21
- package/dist/auth/copilot.js +3 -3
- package/dist/auth/store.d.ts +1 -0
- package/dist/auth/store.js +45 -5
- package/dist/handlers/ai21.js +7 -5
- package/dist/handlers/anthropic.d.ts +1 -1
- package/dist/handlers/anthropic.js +36 -71
- package/dist/handlers/cohere.js +104 -43
- package/dist/handlers/copilot.js +4 -2
- package/dist/handlers/deepinfra.js +18 -3
- package/dist/handlers/gemini.d.ts +1 -1
- package/dist/handlers/gemini.js +47 -90
- package/dist/handlers/geminiEmbedding.d.ts +1 -1
- package/dist/handlers/geminiEmbedding.js +6 -9
- package/dist/handlers/mistral.js +18 -3
- package/dist/handlers/mistralEmbedding.js +3 -1
- package/dist/handlers/ollama.js +14 -4
- package/dist/handlers/ollamaEmbedding.js +4 -2
- package/dist/handlers/openai.js +38 -11
- package/dist/handlers/openaiEmbedding.js +10 -2
- package/dist/handlers/openaiLike.d.ts +1 -1
- package/dist/handlers/openaiLike.js +26 -3
- package/dist/handlers/openaiLikeEmbedding.d.ts +1 -1
- package/dist/handlers/openaiLikeEmbedding.js +6 -2
- package/dist/handlers/replicate.js +41 -16
- package/dist/handlers/vertexAnthropic.d.ts +2 -0
- package/dist/handlers/vertexAnthropic.js +43 -0
- package/dist/handlers/vertexai.d.ts +2 -0
- package/dist/handlers/vertexai.js +51 -0
- package/dist/handlers/vertexaiEmbedding.d.ts +2 -0
- package/dist/handlers/vertexaiEmbedding.js +31 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -1
- package/dist/mappings/openaiLike.js +0 -5
- package/dist/models/index.d.ts +2 -0
- package/dist/models/index.js +7 -0
- package/dist/models/registry.d.ts +13 -0
- package/dist/models/registry.js +32 -0
- package/dist/models/types.d.ts +9 -0
- package/dist/models/types.js +2 -0
- package/dist/utils/anthropic.d.ts +10 -0
- package/dist/utils/anthropic.js +99 -0
- package/dist/utils/gemini.d.ts +12 -0
- package/dist/utils/gemini.js +73 -0
- package/dist/utils/sse.js +0 -1
- package/package.json +12 -18
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,11 +63,13 @@ 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
|
|
69
|
-
- **CLI auth** — built-in OAuth device flow for GitHub Copilot
|
|
70
|
-
- **
|
|
71
|
+
- **CLI auth** — built-in OAuth device flow for GitHub Copilot & API key setup for Anthropic
|
|
72
|
+
- **Encrypted auth store** — `~/.litellm/auth.json` protected with AES-256-GCM (key derived from machine + user)
|
|
71
73
|
|
|
72
74
|
## Usage
|
|
73
75
|
|
|
@@ -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 |
|
|
157
|
-
|
|
158
|
-
| OpenAI | `
|
|
159
|
-
| Anthropic | `
|
|
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 | `
|
|
185
|
+
| Cohere | `cohere/` | ✅ | ✅ | ❌ | `COHERE_API_KEY` |
|
|
164
186
|
| DeepInfra | `deepinfra/` | ✅ | ✅ | ❌ | `DEEPINFRA_API_KEY` |
|
|
165
187
|
| Replicate | `replicate/` | ✅ | ✅ | ❌ | `REPLICATE_API_KEY` |
|
|
166
|
-
| AI21 Labs | `
|
|
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
|
-
│
|
|
217
|
-
│
|
|
238
|
+
│ listModels() │ │ matching) │ │ GeminiHandler │
|
|
239
|
+
│ listProviders│ │ │ │ OpenAILikeHandler│
|
|
218
240
|
└──────────────┘ └──────────────┘ └─────────────────┘
|
|
219
241
|
│
|
|
220
|
-
┌──────┴──────┐
|
|
221
|
-
│ Registry │
|
|
222
|
-
│
|
|
223
|
-
│
|
|
224
|
-
│
|
|
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
|
package/dist/auth/copilot.js
CHANGED
|
@@ -18,13 +18,13 @@ function openBrowser(url) {
|
|
|
18
18
|
const platform = process.platform;
|
|
19
19
|
try {
|
|
20
20
|
if (platform === 'darwin') {
|
|
21
|
-
(0, node_child_process_1.
|
|
21
|
+
(0, node_child_process_1.execFileSync)('open', [url], { stdio: 'ignore' });
|
|
22
22
|
}
|
|
23
23
|
else if (platform === 'win32') {
|
|
24
|
-
(0, node_child_process_1.
|
|
24
|
+
(0, node_child_process_1.execFileSync)('cmd', ['/c', 'start', '', url], { stdio: 'ignore' });
|
|
25
25
|
}
|
|
26
26
|
else {
|
|
27
|
-
(0, node_child_process_1.
|
|
27
|
+
(0, node_child_process_1.execFileSync)('xdg-open', [url], { stdio: 'ignore' });
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
catch {
|
package/dist/auth/store.d.ts
CHANGED
package/dist/auth/store.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decrypt = decrypt;
|
|
3
4
|
exports.getProviderCredentials = getProviderCredentials;
|
|
4
5
|
exports.setProviderCredentials = setProviderCredentials;
|
|
5
6
|
exports.getCopilotCredentials = getCopilotCredentials;
|
|
@@ -10,6 +11,38 @@ exports.clearCredentials = clearCredentials;
|
|
|
10
11
|
const promises_1 = require("node:fs/promises");
|
|
11
12
|
const node_path_1 = require("node:path");
|
|
12
13
|
const node_os_1 = require("node:os");
|
|
14
|
+
const node_crypto_1 = require("node:crypto");
|
|
15
|
+
const ALGORITHM = 'aes-256-gcm';
|
|
16
|
+
const KEY_LENGTH = 32;
|
|
17
|
+
const IV_LENGTH = 16;
|
|
18
|
+
const PEPPER = 'litellmts-core@v1';
|
|
19
|
+
function deriveKey() {
|
|
20
|
+
const seed = `${(0, node_os_1.hostname)()}-${process.getuid?.() ?? process.pid}-${PEPPER}`;
|
|
21
|
+
return (0, node_crypto_1.scryptSync)(seed, 'credentials-key-salt', KEY_LENGTH);
|
|
22
|
+
}
|
|
23
|
+
function encrypt(plaintext) {
|
|
24
|
+
const key = deriveKey();
|
|
25
|
+
const iv = (0, node_crypto_1.randomBytes)(IV_LENGTH);
|
|
26
|
+
const cipher = (0, node_crypto_1.createCipheriv)(ALGORITHM, key, iv);
|
|
27
|
+
let encrypted = cipher.update(plaintext, 'utf-8', 'hex');
|
|
28
|
+
encrypted += cipher.final('hex');
|
|
29
|
+
const tag = cipher.getAuthTag().toString('hex');
|
|
30
|
+
return `${iv.toString('hex')}:${tag}:${encrypted}`;
|
|
31
|
+
}
|
|
32
|
+
function decrypt(payload) {
|
|
33
|
+
const parts = payload.split(':');
|
|
34
|
+
if (parts.length < 3)
|
|
35
|
+
throw new Error('Invalid encrypted payload');
|
|
36
|
+
const iv = Buffer.from(parts.shift(), 'hex');
|
|
37
|
+
const tag = Buffer.from(parts.shift(), 'hex');
|
|
38
|
+
const encrypted = parts.join(':');
|
|
39
|
+
const key = deriveKey();
|
|
40
|
+
const decipher = (0, node_crypto_1.createDecipheriv)(ALGORITHM, key, iv);
|
|
41
|
+
decipher.setAuthTag(tag);
|
|
42
|
+
let plaintext = decipher.update(encrypted, 'hex', 'utf-8');
|
|
43
|
+
plaintext += decipher.final('utf-8');
|
|
44
|
+
return plaintext;
|
|
45
|
+
}
|
|
13
46
|
const STORE_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), '.litellm');
|
|
14
47
|
const STORE_PATH = (0, node_path_1.join)(STORE_DIR, 'auth.json');
|
|
15
48
|
function isNotFound(err) {
|
|
@@ -20,8 +53,11 @@ async function ensureDir() {
|
|
|
20
53
|
}
|
|
21
54
|
async function readStore() {
|
|
22
55
|
try {
|
|
23
|
-
const
|
|
24
|
-
|
|
56
|
+
const raw = await (0, promises_1.readFile)(STORE_PATH, 'utf-8');
|
|
57
|
+
if (!raw.startsWith('{')) {
|
|
58
|
+
return JSON.parse(decrypt(raw));
|
|
59
|
+
}
|
|
60
|
+
return JSON.parse(raw);
|
|
25
61
|
}
|
|
26
62
|
catch (err) {
|
|
27
63
|
if (isNotFound(err))
|
|
@@ -29,6 +65,11 @@ async function readStore() {
|
|
|
29
65
|
throw err;
|
|
30
66
|
}
|
|
31
67
|
}
|
|
68
|
+
async function writeStore(data) {
|
|
69
|
+
const plaintext = JSON.stringify(data);
|
|
70
|
+
const encrypted = encrypt(plaintext);
|
|
71
|
+
await (0, promises_1.writeFile)(STORE_PATH, encrypted, 'utf-8');
|
|
72
|
+
}
|
|
32
73
|
async function getProviderCredentials(provider) {
|
|
33
74
|
try {
|
|
34
75
|
const store = await readStore();
|
|
@@ -47,9 +88,8 @@ async function setProviderCredentials(provider, creds) {
|
|
|
47
88
|
await ensureDir();
|
|
48
89
|
const store = await readStore();
|
|
49
90
|
store[provider] = creds;
|
|
50
|
-
await (
|
|
91
|
+
await writeStore(store);
|
|
51
92
|
}
|
|
52
|
-
// Backward-compat old single-provider format
|
|
53
93
|
async function getCopilotCredentials() {
|
|
54
94
|
const legacy = await getProviderCredentials('github-copilot');
|
|
55
95
|
if (legacy)
|
|
@@ -83,7 +123,7 @@ async function setAnthropicCredentials(creds) {
|
|
|
83
123
|
}
|
|
84
124
|
async function clearCredentials() {
|
|
85
125
|
try {
|
|
86
|
-
await (
|
|
126
|
+
await writeStore({});
|
|
87
127
|
}
|
|
88
128
|
catch {
|
|
89
129
|
// ignore
|
package/dist/handlers/ai21.js
CHANGED
|
@@ -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
|
|
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(
|
|
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,
|
|
86
|
+
return toResponse(body, modelName);
|
|
85
87
|
}
|
|
86
88
|
const registry_1 = require("../registry");
|
|
87
|
-
(0, registry_1.registerCompletionHandler)('
|
|
89
|
+
(0, registry_1.registerCompletionHandler)('ai21/', AI21Handler);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { HandlerParams,
|
|
1
|
+
import type { HandlerParams, ResultNotStreaming, ResultStreaming } from '../types';
|
|
2
2
|
export declare function AnthropicHandler(params: HandlerParams): Promise<ResultNotStreaming | ResultStreaming>;
|
|
@@ -5,81 +5,46 @@ 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
|
|
9
|
-
const toUsage_1 = require("../utils/toUsage");
|
|
8
|
+
const anthropic_1 = require("../utils/anthropic");
|
|
10
9
|
const auth_1 = require("../auth");
|
|
11
|
-
|
|
12
|
-
return messages
|
|
13
|
-
.map((msg) => {
|
|
14
|
-
const content = msg.content ?? '';
|
|
15
|
-
if (msg.role === 'assistant') {
|
|
16
|
-
return `${sdk_1.default.AI_PROMPT} ${content}`;
|
|
17
|
-
}
|
|
18
|
-
return `${sdk_1.default.HUMAN_PROMPT} ${content}`;
|
|
19
|
-
})
|
|
20
|
-
.join('') + sdk_1.default.AI_PROMPT;
|
|
21
|
-
}
|
|
22
|
-
function toFinishReson(string) {
|
|
23
|
-
if (string === 'max_tokens') {
|
|
24
|
-
return 'length';
|
|
25
|
-
}
|
|
26
|
-
return 'stop';
|
|
27
|
-
}
|
|
28
|
-
function toResponse(anthropicResponse, prompt) {
|
|
29
|
-
return {
|
|
30
|
-
model: anthropicResponse.model,
|
|
31
|
-
created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
|
|
32
|
-
usage: (0, toUsage_1.toUsage)(prompt, anthropicResponse.completion),
|
|
33
|
-
choices: [
|
|
34
|
-
{
|
|
35
|
-
message: {
|
|
36
|
-
content: anthropicResponse.completion,
|
|
37
|
-
role: 'assistant',
|
|
38
|
-
},
|
|
39
|
-
finish_reason: toFinishReson(anthropicResponse.stop_reason),
|
|
40
|
-
index: 0,
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
function toStreamingChunk(anthropicResponse) {
|
|
46
|
-
return {
|
|
47
|
-
model: anthropicResponse.model,
|
|
48
|
-
created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
|
|
49
|
-
choices: [
|
|
50
|
-
{
|
|
51
|
-
delta: { content: anthropicResponse.completion, role: 'assistant' },
|
|
52
|
-
finish_reason: toFinishReson(anthropicResponse.stop_reason),
|
|
53
|
-
index: 0,
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
async function* toStreamingResponse(stream) {
|
|
59
|
-
for await (const chunk of stream) {
|
|
60
|
-
yield toStreamingChunk(chunk);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
10
|
+
const registry_1 = require("../models/registry");
|
|
63
11
|
async function AnthropicHandler(params) {
|
|
64
12
|
const apiKey = params.apiKey ?? process.env.ANTHROPIC_API_KEY ?? (await (0, auth_1.getAnthropicKey)());
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
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);
|
|
69
18
|
const anthropicParams = {
|
|
70
|
-
model:
|
|
71
|
-
|
|
72
|
-
|
|
19
|
+
model: modelName,
|
|
20
|
+
max_tokens: params.max_tokens ?? 300,
|
|
21
|
+
messages,
|
|
22
|
+
...(system ? { system } : {}),
|
|
73
23
|
};
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
24
|
+
try {
|
|
25
|
+
if (params.stream) {
|
|
26
|
+
const stream = await anthropic.messages.create({
|
|
27
|
+
...anthropicParams,
|
|
28
|
+
stream: true,
|
|
29
|
+
});
|
|
30
|
+
return (0, anthropic_1.toAnthropicStreamingResponse)(stream);
|
|
31
|
+
}
|
|
32
|
+
const message = await anthropic.messages.create(anthropicParams);
|
|
33
|
+
return (0, anthropic_1.toAnthropicResponse)(message);
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
throw new Error(`Anthropic API error: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
80
37
|
}
|
|
81
|
-
const completion = await anthropic.completions.create(anthropicParams);
|
|
82
|
-
return toResponse(completion, prompt);
|
|
83
38
|
}
|
|
84
|
-
|
|
85
|
-
|
|
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);
|
package/dist/handlers/cohere.js
CHANGED
|
@@ -2,56 +2,110 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CohereHandler = CohereHandler;
|
|
4
4
|
const cohere_ai_1 = require("cohere-ai");
|
|
5
|
-
const combinePrompts_1 = require("../utils/combinePrompts");
|
|
6
5
|
const getUnixTimestamp_1 = require("../utils/getUnixTimestamp");
|
|
7
|
-
const
|
|
6
|
+
const registry_1 = require("../models/registry");
|
|
7
|
+
function toChatHistory(messages) {
|
|
8
|
+
let system;
|
|
9
|
+
const chatMessages = [];
|
|
10
|
+
for (const msg of messages) {
|
|
11
|
+
if (msg.role === 'system') {
|
|
12
|
+
system = (system ? system + '\n' : '') + (msg.content ?? '');
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
chatMessages.push(msg);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
let lastUserMessage = '';
|
|
19
|
+
const chatHistory = [];
|
|
20
|
+
for (let i = 0; i < chatMessages.length; i++) {
|
|
21
|
+
const msg = chatMessages[i];
|
|
22
|
+
const isLastUser = i === chatMessages.length - 1 && msg.role === 'user';
|
|
23
|
+
if (isLastUser) {
|
|
24
|
+
lastUserMessage = msg.content ?? '';
|
|
25
|
+
}
|
|
26
|
+
else if (msg.role === 'user') {
|
|
27
|
+
chatHistory.push({ role: 'USER', message: msg.content ?? '' });
|
|
28
|
+
}
|
|
29
|
+
else if (msg.role === 'assistant') {
|
|
30
|
+
chatHistory.push({ role: 'CHATBOT', message: msg.content ?? '' });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (!lastUserMessage && chatMessages.length > 0) {
|
|
34
|
+
const last = chatMessages[chatMessages.length - 1];
|
|
35
|
+
lastUserMessage = last.content ?? '';
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
message: lastUserMessage,
|
|
39
|
+
...(chatHistory.length > 0 ? { chatHistory } : {}),
|
|
40
|
+
...(system ? { preamble: system } : {}),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
8
43
|
async function CohereHandler(params) {
|
|
9
44
|
const apiKey = params.apiKey ?? process.env.COHERE_API_KEY;
|
|
10
45
|
if (!apiKey)
|
|
11
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;
|
|
12
50
|
const cohere = new cohere_ai_1.CohereClient({ token: apiKey });
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
model:
|
|
16
|
-
|
|
17
|
-
|
|
51
|
+
const { message, chatHistory, preamble } = toChatHistory(params.messages);
|
|
52
|
+
const chatParams = {
|
|
53
|
+
model: modelName,
|
|
54
|
+
message,
|
|
55
|
+
...(chatHistory ? { chatHistory } : {}),
|
|
56
|
+
...(preamble ? { preamble } : {}),
|
|
57
|
+
maxTokens: params.max_tokens ?? 50,
|
|
18
58
|
temperature: params.temperature ?? 1,
|
|
19
59
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
60
|
+
try {
|
|
61
|
+
if (params.stream) {
|
|
62
|
+
const stream = await cohere.chatStream({
|
|
63
|
+
...chatParams,
|
|
64
|
+
});
|
|
65
|
+
return toStreamingResponse(stream, modelName);
|
|
66
|
+
}
|
|
67
|
+
const { text, finishReason, meta } = await cohere.chat(chatParams);
|
|
68
|
+
return {
|
|
69
|
+
model: modelName,
|
|
70
|
+
created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
|
|
71
|
+
usage: meta?.tokens
|
|
72
|
+
? {
|
|
73
|
+
prompt_tokens: meta.tokens.inputTokens ?? 0,
|
|
74
|
+
completion_tokens: meta.tokens.outputTokens ?? 0,
|
|
75
|
+
total_tokens: (meta.tokens.inputTokens ?? 0) + (meta.tokens.outputTokens ?? 0),
|
|
76
|
+
}
|
|
77
|
+
: undefined,
|
|
78
|
+
choices: [
|
|
79
|
+
{
|
|
80
|
+
message: {
|
|
81
|
+
content: text,
|
|
82
|
+
role: 'assistant',
|
|
83
|
+
},
|
|
84
|
+
finish_reason: toFinishReason(finishReason),
|
|
85
|
+
index: 0,
|
|
39
86
|
},
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
throw new Error(`Cohere API error: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
92
|
+
}
|
|
45
93
|
}
|
|
46
|
-
|
|
47
|
-
|
|
94
|
+
function toFinishReason(reason) {
|
|
95
|
+
if (reason === 'MAX_TOKENS' || reason === 'ERROR_LIMIT') {
|
|
96
|
+
return 'length';
|
|
97
|
+
}
|
|
98
|
+
if (reason === 'ERROR_TOXIC') {
|
|
99
|
+
return 'content_filter';
|
|
100
|
+
}
|
|
101
|
+
return 'stop';
|
|
102
|
+
}
|
|
103
|
+
async function* toStreamingResponse(stream, model) {
|
|
48
104
|
for await (const event of stream) {
|
|
49
105
|
if (event.eventType === 'text-generation') {
|
|
50
|
-
fullText += event.text ?? '';
|
|
51
106
|
yield {
|
|
52
107
|
model,
|
|
53
108
|
created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
|
|
54
|
-
usage: (0, toUsage_1.toUsage)(prompt, fullText),
|
|
55
109
|
choices: [
|
|
56
110
|
{
|
|
57
111
|
delta: { content: event.text, role: 'assistant' },
|
|
@@ -65,21 +119,28 @@ async function* toRealStream(stream, model, prompt) {
|
|
|
65
119
|
yield {
|
|
66
120
|
model,
|
|
67
121
|
created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
|
|
68
|
-
usage: (0, toUsage_1.toUsage)(prompt, fullText),
|
|
69
122
|
choices: [
|
|
70
123
|
{
|
|
71
124
|
delta: { content: '', role: 'assistant' },
|
|
72
|
-
finish_reason:
|
|
125
|
+
finish_reason: toFinishReason(event.finishReason),
|
|
73
126
|
index: 0,
|
|
74
127
|
},
|
|
75
128
|
],
|
|
76
129
|
};
|
|
77
130
|
}
|
|
78
|
-
else if (event.eventType === 'stream-error') {
|
|
79
|
-
const msg = event.message ?? 'unknown';
|
|
80
|
-
throw new Error(`Cohere stream error: ${msg}`);
|
|
81
|
-
}
|
|
82
131
|
}
|
|
83
132
|
}
|
|
84
|
-
|
|
85
|
-
|
|
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);
|
package/dist/handlers/copilot.js
CHANGED
|
@@ -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.
|
|
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);
|
|
@@ -21,7 +21,9 @@ async function DeepInfraHandler(params) {
|
|
|
21
21
|
const apiKey = params.apiKey ?? process.env.DEEPINFRA_API_KEY;
|
|
22
22
|
if (!apiKey)
|
|
23
23
|
throw new Error('DeepInfra requires an API key. Set DEEPINFRA_API_KEY environment variable or pass apiKey in params.');
|
|
24
|
-
const model = params.model.
|
|
24
|
+
const model = params.model.startsWith('deepinfra/')
|
|
25
|
+
? params.model.slice(10)
|
|
26
|
+
: params.model;
|
|
25
27
|
const res = await getDeepInfraResponse(model, params.messages, baseUrl, apiKey, params.stream ?? false);
|
|
26
28
|
if (!res.ok) {
|
|
27
29
|
throw new Error(`DeepInfra API error: ${res.status} ${res.statusText}`);
|
|
@@ -52,5 +54,18 @@ async function DeepInfraHandler(params) {
|
|
|
52
54
|
};
|
|
53
55
|
return result;
|
|
54
56
|
}
|
|
55
|
-
const registry_1 = require("../registry");
|
|
56
|
-
(0, registry_1.
|
|
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>;
|