litellmts-core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -0
- package/README.md +266 -0
- package/dist/auth/anthropic.d.ts +7 -0
- package/dist/auth/anthropic.js +83 -0
- package/dist/auth/copilot.d.ts +9 -0
- package/dist/auth/copilot.js +138 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.js +14 -0
- package/dist/auth/refresh.d.ts +2 -0
- package/dist/auth/refresh.js +54 -0
- package/dist/auth/store.d.ts +19 -0
- package/dist/auth/store.js +91 -0
- package/dist/bin/litellm.d.ts +2 -0
- package/dist/bin/litellm.js +45 -0
- package/dist/completion.d.ts +24 -0
- package/dist/completion.js +15 -0
- package/dist/embedding.d.ts +15 -0
- package/dist/embedding.js +26 -0
- package/dist/handlers/ai21.d.ts +2 -0
- package/dist/handlers/ai21.js +87 -0
- package/dist/handlers/anthropic.d.ts +2 -0
- package/dist/handlers/anthropic.js +85 -0
- package/dist/handlers/cohere.d.ts +2 -0
- package/dist/handlers/cohere.js +85 -0
- package/dist/handlers/copilot.d.ts +2 -0
- package/dist/handlers/copilot.js +136 -0
- package/dist/handlers/deepinfra.d.ts +2 -0
- package/dist/handlers/deepinfra.js +56 -0
- package/dist/handlers/gemini.d.ts +2 -0
- package/dist/handlers/gemini.js +102 -0
- package/dist/handlers/geminiEmbedding.d.ts +2 -0
- package/dist/handlers/geminiEmbedding.js +29 -0
- package/dist/handlers/getHandler.d.ts +11 -0
- package/dist/handlers/getHandler.js +24 -0
- package/dist/handlers/index.d.ts +16 -0
- package/dist/handlers/index.js +18 -0
- package/dist/handlers/mistral.d.ts +2 -0
- package/dist/handlers/mistral.js +56 -0
- package/dist/handlers/mistralEmbedding.d.ts +2 -0
- package/dist/handlers/mistralEmbedding.js +31 -0
- package/dist/handlers/ollama.d.ts +2 -0
- package/dist/handlers/ollama.js +89 -0
- package/dist/handlers/ollamaEmbedding.d.ts +2 -0
- package/dist/handlers/ollamaEmbedding.js +36 -0
- package/dist/handlers/openai.d.ts +2 -0
- package/dist/handlers/openai.js +76 -0
- package/dist/handlers/openaiEmbedding.d.ts +2 -0
- package/dist/handlers/openaiEmbedding.js +18 -0
- package/dist/handlers/openaiLike.d.ts +3 -0
- package/dist/handlers/openaiLike.js +22 -0
- package/dist/handlers/openaiLikeEmbedding.d.ts +3 -0
- package/dist/handlers/openaiLikeEmbedding.js +22 -0
- package/dist/handlers/replicate.d.ts +2 -0
- package/dist/handlers/replicate.js +98 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +19 -0
- package/dist/mappings/openaiLike.d.ts +6 -0
- package/dist/mappings/openaiLike.js +190 -0
- package/dist/registry.d.ts +15 -0
- package/dist/registry.js +30 -0
- package/dist/types.d.ts +104 -0
- package/dist/types.js +2 -0
- package/dist/utils/combinePrompts.d.ts +10 -0
- package/dist/utils/combinePrompts.js +19 -0
- package/dist/utils/encoders.d.ts +2 -0
- package/dist/utils/encoders.js +9 -0
- package/dist/utils/getUnixTimestamp.d.ts +1 -0
- package/dist/utils/getUnixTimestamp.js +6 -0
- package/dist/utils/sse.d.ts +12 -0
- package/dist/utils/sse.js +41 -0
- package/dist/utils/toUsage.d.ts +12 -0
- package/dist/utils/toUsage.js +35 -0
- package/package.json +63 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeepInfraHandler = DeepInfraHandler;
|
|
4
|
+
const sse_1 = require("../utils/sse");
|
|
5
|
+
async function getDeepInfraResponse(model, messages, baseUrl, apiKey, stream) {
|
|
6
|
+
return fetch(`${baseUrl}/v1/openai/chat/completions`, {
|
|
7
|
+
method: 'POST',
|
|
8
|
+
headers: {
|
|
9
|
+
'Content-Type': 'application/json',
|
|
10
|
+
Authorization: `Bearer ${apiKey}`,
|
|
11
|
+
},
|
|
12
|
+
body: JSON.stringify({
|
|
13
|
+
messages,
|
|
14
|
+
model,
|
|
15
|
+
stream,
|
|
16
|
+
}),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async function DeepInfraHandler(params) {
|
|
20
|
+
const baseUrl = params.baseUrl ?? 'https://api.deepinfra.com';
|
|
21
|
+
const apiKey = params.apiKey ?? process.env.DEEPINFRA_API_KEY;
|
|
22
|
+
if (!apiKey)
|
|
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.split('deepinfra/')[1];
|
|
25
|
+
const res = await getDeepInfraResponse(model, params.messages, baseUrl, apiKey, params.stream ?? false);
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
throw new Error(`DeepInfra API error: ${res.status} ${res.statusText}`);
|
|
28
|
+
}
|
|
29
|
+
if (params.stream) {
|
|
30
|
+
return (0, sse_1.iterateSSEStream)(res, (payload) => JSON.parse(payload));
|
|
31
|
+
}
|
|
32
|
+
const body = await res.json();
|
|
33
|
+
const result = {
|
|
34
|
+
created: body.created,
|
|
35
|
+
model: body.model,
|
|
36
|
+
choices: body.choices.map((c) => ({
|
|
37
|
+
finish_reason: c.finish_reason,
|
|
38
|
+
index: c.index,
|
|
39
|
+
message: {
|
|
40
|
+
role: c.message.role,
|
|
41
|
+
content: c.message.content,
|
|
42
|
+
function_call: c.message.function_call ?? undefined,
|
|
43
|
+
},
|
|
44
|
+
})),
|
|
45
|
+
usage: body.usage
|
|
46
|
+
? {
|
|
47
|
+
prompt_tokens: body.usage.prompt_tokens,
|
|
48
|
+
completion_tokens: body.usage.completion_tokens,
|
|
49
|
+
total_tokens: body.usage.total_tokens,
|
|
50
|
+
}
|
|
51
|
+
: undefined,
|
|
52
|
+
};
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
const registry_1 = require("../registry");
|
|
56
|
+
(0, registry_1.registerCompletionHandler)('deepinfra/', DeepInfraHandler);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
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) {
|
|
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: undefined,
|
|
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
|
+
}
|
|
76
|
+
async function GeminiHandler(params) {
|
|
77
|
+
const apiKey = params.apiKey ?? process.env.GEMINI_API_KEY;
|
|
78
|
+
if (!apiKey)
|
|
79
|
+
throw new Error('Gemini requires an API key. Set GEMINI_API_KEY environment variable or pass apiKey in params.');
|
|
80
|
+
const modelName = params.model.startsWith('gemini/')
|
|
81
|
+
? params.model.slice(7)
|
|
82
|
+
: 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);
|
|
94
|
+
if (params.stream) {
|
|
95
|
+
const result = await model.generateContentStream({ contents });
|
|
96
|
+
return toStreamingResponse(result.stream);
|
|
97
|
+
}
|
|
98
|
+
const result = await model.generateContent({ contents });
|
|
99
|
+
return toResponse(result.response, modelName);
|
|
100
|
+
}
|
|
101
|
+
const registry_1 = require("../registry");
|
|
102
|
+
(0, registry_1.registerCompletionHandler)('gemini/', GeminiHandler);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GeminiEmbeddingHandler = GeminiEmbeddingHandler;
|
|
4
|
+
const generative_ai_1 = require("@google/generative-ai");
|
|
5
|
+
async function GeminiEmbeddingHandler(params) {
|
|
6
|
+
const apiKey = params.apiKey ?? process.env.GEMINI_API_KEY;
|
|
7
|
+
if (!apiKey)
|
|
8
|
+
throw new Error('Gemini requires an API key. Set GEMINI_API_KEY environment variable or pass apiKey in params.');
|
|
9
|
+
const modelName = params.model.startsWith('gemini/')
|
|
10
|
+
? params.model.slice(7)
|
|
11
|
+
: params.model;
|
|
12
|
+
const genAI = new generative_ai_1.GoogleGenerativeAI(apiKey);
|
|
13
|
+
const model = genAI.getGenerativeModel({ model: modelName });
|
|
14
|
+
const input = typeof params.input === 'string'
|
|
15
|
+
? params.input
|
|
16
|
+
: params.input.join(' ');
|
|
17
|
+
const result = await model.embedContent({
|
|
18
|
+
content: {
|
|
19
|
+
role: 'user',
|
|
20
|
+
parts: [{ text: input }],
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
model: modelName,
|
|
25
|
+
data: [{ embedding: result.embedding.values, index: 0 }],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const registry_1 = require("../registry");
|
|
29
|
+
(0, registry_1.registerEmbeddingHandler)('gemini/', GeminiEmbeddingHandler);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find a handler function by matching the model name against registered prefix patterns.
|
|
3
|
+
*
|
|
4
|
+
* Each handler registers itself with a prefix (e.g. `'gpt-'`, `'claude-'`). This function
|
|
5
|
+
* checks if the model name starts with any registered prefix and returns the matching handler.
|
|
6
|
+
*
|
|
7
|
+
* @param model - The model name to look up (e.g. `'gpt-4'`, `'claude-3-opus'`)
|
|
8
|
+
* @param mapping - A record of prefix → handler function
|
|
9
|
+
* @returns The matching handler, or `null` if no prefix matches
|
|
10
|
+
*/
|
|
11
|
+
export declare function getHandler<T>(model: string, mapping: Record<string, T>): T | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getHandler = getHandler;
|
|
4
|
+
/**
|
|
5
|
+
* Find a handler function by matching the model name against registered prefix patterns.
|
|
6
|
+
*
|
|
7
|
+
* Each handler registers itself with a prefix (e.g. `'gpt-'`, `'claude-'`). This function
|
|
8
|
+
* checks if the model name starts with any registered prefix and returns the matching handler.
|
|
9
|
+
*
|
|
10
|
+
* @param model - The model name to look up (e.g. `'gpt-4'`, `'claude-3-opus'`)
|
|
11
|
+
* @param mapping - A record of prefix → handler function
|
|
12
|
+
* @returns The matching handler, or `null` if no prefix matches
|
|
13
|
+
*/
|
|
14
|
+
function getHandler(model, mapping) {
|
|
15
|
+
const patterns = Object.keys(mapping);
|
|
16
|
+
const handlerKey = patterns.find((pattern) => {
|
|
17
|
+
const regex = new RegExp(`^${pattern}`);
|
|
18
|
+
return model.match(regex);
|
|
19
|
+
});
|
|
20
|
+
if (!handlerKey) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return mapping[handlerKey];
|
|
24
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import './anthropic';
|
|
2
|
+
import './cohere';
|
|
3
|
+
import './ollama';
|
|
4
|
+
import './openai';
|
|
5
|
+
import './ai21';
|
|
6
|
+
import './replicate';
|
|
7
|
+
import './deepinfra';
|
|
8
|
+
import './mistral';
|
|
9
|
+
import './gemini';
|
|
10
|
+
import './copilot';
|
|
11
|
+
import './openaiLike';
|
|
12
|
+
import './openaiEmbedding';
|
|
13
|
+
import './ollamaEmbedding';
|
|
14
|
+
import './mistralEmbedding';
|
|
15
|
+
import './geminiEmbedding';
|
|
16
|
+
import './openaiLikeEmbedding';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
require("./anthropic");
|
|
4
|
+
require("./cohere");
|
|
5
|
+
require("./ollama");
|
|
6
|
+
require("./openai");
|
|
7
|
+
require("./ai21");
|
|
8
|
+
require("./replicate");
|
|
9
|
+
require("./deepinfra");
|
|
10
|
+
require("./mistral");
|
|
11
|
+
require("./gemini");
|
|
12
|
+
require("./copilot");
|
|
13
|
+
require("./openaiLike");
|
|
14
|
+
require("./openaiEmbedding");
|
|
15
|
+
require("./ollamaEmbedding");
|
|
16
|
+
require("./mistralEmbedding");
|
|
17
|
+
require("./geminiEmbedding");
|
|
18
|
+
require("./openaiLikeEmbedding");
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MistralHandler = MistralHandler;
|
|
4
|
+
const sse_1 = require("../utils/sse");
|
|
5
|
+
async function getMistralResponse(model, messages, baseUrl, apiKey, stream) {
|
|
6
|
+
return fetch(`${baseUrl}/v1/chat/completions`, {
|
|
7
|
+
method: 'POST',
|
|
8
|
+
headers: {
|
|
9
|
+
'Content-Type': 'application/json',
|
|
10
|
+
Authorization: `Bearer ${apiKey}`,
|
|
11
|
+
},
|
|
12
|
+
body: JSON.stringify({
|
|
13
|
+
messages,
|
|
14
|
+
model,
|
|
15
|
+
stream,
|
|
16
|
+
}),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async function MistralHandler(params) {
|
|
20
|
+
const baseUrl = params.baseUrl ?? 'https://api.mistral.ai';
|
|
21
|
+
const apiKey = params.apiKey ?? process.env.MISTRAL_API_KEY;
|
|
22
|
+
if (!apiKey)
|
|
23
|
+
throw new Error('Mistral requires an API key. Set MISTRAL_API_KEY environment variable or pass apiKey in params.');
|
|
24
|
+
const model = params.model.split('mistral/')[1];
|
|
25
|
+
const res = await getMistralResponse(model, params.messages, baseUrl, apiKey, params.stream ?? false);
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
throw new Error(`Mistral API error: ${res.status} ${res.statusText}`);
|
|
28
|
+
}
|
|
29
|
+
if (params.stream) {
|
|
30
|
+
return (0, sse_1.iterateSSEStream)(res, (payload) => JSON.parse(payload));
|
|
31
|
+
}
|
|
32
|
+
const body = await res.json();
|
|
33
|
+
const result = {
|
|
34
|
+
created: body.created,
|
|
35
|
+
model: body.model,
|
|
36
|
+
choices: body.choices.map((c) => ({
|
|
37
|
+
finish_reason: c.finish_reason,
|
|
38
|
+
index: c.index,
|
|
39
|
+
message: {
|
|
40
|
+
role: c.message.role,
|
|
41
|
+
content: c.message.content,
|
|
42
|
+
function_call: c.message.function_call ?? undefined,
|
|
43
|
+
},
|
|
44
|
+
})),
|
|
45
|
+
usage: body.usage
|
|
46
|
+
? {
|
|
47
|
+
prompt_tokens: body.usage.prompt_tokens,
|
|
48
|
+
completion_tokens: body.usage.completion_tokens,
|
|
49
|
+
total_tokens: body.usage.total_tokens,
|
|
50
|
+
}
|
|
51
|
+
: undefined,
|
|
52
|
+
};
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
const registry_1 = require("../registry");
|
|
56
|
+
(0, registry_1.registerCompletionHandler)('mistral/', MistralHandler);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MistralEmbeddingHandler = MistralEmbeddingHandler;
|
|
4
|
+
async function getMistralResponse(model, input, baseUrl, apiKey) {
|
|
5
|
+
return fetch(`${baseUrl}/v1/embeddings`, {
|
|
6
|
+
method: 'POST',
|
|
7
|
+
headers: {
|
|
8
|
+
'Content-Type': 'application/json',
|
|
9
|
+
Authorization: `Bearer ${apiKey}`,
|
|
10
|
+
},
|
|
11
|
+
body: JSON.stringify({
|
|
12
|
+
model,
|
|
13
|
+
input: typeof input === 'string' ? [input] : input,
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
async function MistralEmbeddingHandler(params) {
|
|
18
|
+
const model = params.model.split('mistral/')[1];
|
|
19
|
+
const baseUrl = params.baseUrl ?? 'https://api.mistral.ai';
|
|
20
|
+
const apiKey = params.apiKey ?? process.env.MISTRAL_API_KEY;
|
|
21
|
+
if (!apiKey)
|
|
22
|
+
throw new Error('Mistral requires an API key. Set MISTRAL_API_KEY environment variable or pass apiKey in params.');
|
|
23
|
+
const response = await getMistralResponse(model, params.input, baseUrl, apiKey);
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
throw new Error(`Received an error with code ${response.status} from Mistral API.`);
|
|
26
|
+
}
|
|
27
|
+
const body = (await response.json());
|
|
28
|
+
return body;
|
|
29
|
+
}
|
|
30
|
+
const registry_1 = require("../registry");
|
|
31
|
+
(0, registry_1.registerEmbeddingHandler)('mistral/', MistralEmbeddingHandler);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OllamaHandler = OllamaHandler;
|
|
4
|
+
const combinePrompts_1 = require("../utils/combinePrompts");
|
|
5
|
+
const getUnixTimestamp_1 = require("../utils/getUnixTimestamp");
|
|
6
|
+
const toUsage_1 = require("../utils/toUsage");
|
|
7
|
+
function toStreamingChunk(ollamaResponse, model, prompt) {
|
|
8
|
+
return {
|
|
9
|
+
model: model,
|
|
10
|
+
created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
|
|
11
|
+
usage: (0, toUsage_1.toUsage)(prompt, ollamaResponse.response),
|
|
12
|
+
choices: [
|
|
13
|
+
{
|
|
14
|
+
delta: { content: ollamaResponse.response, role: 'assistant' },
|
|
15
|
+
finish_reason: 'stop',
|
|
16
|
+
index: 0,
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function toResponse(content, model, prompt) {
|
|
22
|
+
return {
|
|
23
|
+
model: model,
|
|
24
|
+
created: (0, getUnixTimestamp_1.getUnixTimestamp)(),
|
|
25
|
+
usage: (0, toUsage_1.toUsage)(prompt, content),
|
|
26
|
+
choices: [
|
|
27
|
+
{
|
|
28
|
+
message: { content, role: 'assistant' },
|
|
29
|
+
finish_reason: 'stop',
|
|
30
|
+
index: 0,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async function* iterateResponse(response, model, prompt) {
|
|
36
|
+
const reader = response.body?.getReader();
|
|
37
|
+
let done = false;
|
|
38
|
+
while (!done) {
|
|
39
|
+
const next = await reader?.read();
|
|
40
|
+
if (next?.value) {
|
|
41
|
+
const decoded = new TextDecoder().decode(next.value);
|
|
42
|
+
done = next.done;
|
|
43
|
+
const lines = decoded.split(/(?<!\\)\n/);
|
|
44
|
+
const ollamaResponses = lines
|
|
45
|
+
.map((line) => line.trim())
|
|
46
|
+
.filter((line) => line !== '')
|
|
47
|
+
.map((line) => JSON.parse(line))
|
|
48
|
+
.map((response) => toStreamingChunk(response, model, prompt));
|
|
49
|
+
yield* ollamaResponses;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
done = true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function getOllamaResponse(model, prompt, baseUrl) {
|
|
57
|
+
return fetch(`${baseUrl}/api/generate`, {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: {
|
|
60
|
+
'Content-Type': 'application/json',
|
|
61
|
+
},
|
|
62
|
+
body: JSON.stringify({
|
|
63
|
+
model,
|
|
64
|
+
prompt,
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async function OllamaHandler(params) {
|
|
69
|
+
const baseUrl = params.baseUrl ?? 'http://127.0.0.1:11434';
|
|
70
|
+
const model = params.model.split('ollama/')[1];
|
|
71
|
+
const prompt = (0, combinePrompts_1.combinePrompts)(params.messages);
|
|
72
|
+
const res = await getOllamaResponse(model, prompt, baseUrl);
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
throw new Error(`Received an error with code ${res.status} from Ollama API.`);
|
|
75
|
+
}
|
|
76
|
+
if (params.stream) {
|
|
77
|
+
return iterateResponse(res, model, prompt);
|
|
78
|
+
}
|
|
79
|
+
const chunks = [];
|
|
80
|
+
for await (const chunk of iterateResponse(res, model, prompt)) {
|
|
81
|
+
chunks.push(chunk);
|
|
82
|
+
}
|
|
83
|
+
const message = chunks.reduce((acc, chunk) => {
|
|
84
|
+
return (acc += chunk.choices[0].delta.content);
|
|
85
|
+
}, '');
|
|
86
|
+
return toResponse(message, model, prompt);
|
|
87
|
+
}
|
|
88
|
+
const registry_1 = require("../registry");
|
|
89
|
+
(0, registry_1.registerCompletionHandler)('ollama/', OllamaHandler);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OllamaEmbeddingHandler = OllamaEmbeddingHandler;
|
|
4
|
+
const toUsage_1 = require("../utils/toUsage");
|
|
5
|
+
async function getOllamaResponse(model, input, baseUrl) {
|
|
6
|
+
return fetch(`${baseUrl}/api/embeddings`, {
|
|
7
|
+
method: 'POST',
|
|
8
|
+
body: JSON.stringify({
|
|
9
|
+
model,
|
|
10
|
+
prompt: input,
|
|
11
|
+
stream: false,
|
|
12
|
+
headers: {
|
|
13
|
+
'Content-Type': 'application/json',
|
|
14
|
+
},
|
|
15
|
+
}),
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async function OllamaEmbeddingHandler(params) {
|
|
19
|
+
const model = params.model.split('ollama/')[1];
|
|
20
|
+
const baseUrl = params.baseUrl ?? 'http://127.0.0.1:11434';
|
|
21
|
+
const input = typeof params.input === 'string'
|
|
22
|
+
? params.input
|
|
23
|
+
: params.input.reduce((acc, curr) => (acc += curr), '');
|
|
24
|
+
const response = await getOllamaResponse(model, input, baseUrl);
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error(`Received an error with code ${response.status} from Ollama API.`);
|
|
27
|
+
}
|
|
28
|
+
const body = (await response.json());
|
|
29
|
+
return {
|
|
30
|
+
data: [{ embedding: body.embedding, index: 0 }],
|
|
31
|
+
model: model,
|
|
32
|
+
usage: (0, toUsage_1.toEmbeddingUsage)(input),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const registry_1 = require("../registry");
|
|
36
|
+
(0, registry_1.registerEmbeddingHandler)('ollama/', OllamaEmbeddingHandler);
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OpenAIHandler = OpenAIHandler;
|
|
7
|
+
const openai_1 = __importDefault(require("openai"));
|
|
8
|
+
function toOpenAIMessages(messages) {
|
|
9
|
+
return messages;
|
|
10
|
+
}
|
|
11
|
+
async function* toStreamingResponse(response) {
|
|
12
|
+
for await (const chunk of response) {
|
|
13
|
+
yield {
|
|
14
|
+
model: chunk.model,
|
|
15
|
+
created: chunk.created,
|
|
16
|
+
choices: chunk.choices.map((openAIChoice) => {
|
|
17
|
+
return {
|
|
18
|
+
delta: {
|
|
19
|
+
content: openAIChoice.delta.content,
|
|
20
|
+
role: openAIChoice.delta.role,
|
|
21
|
+
function_call: openAIChoice.delta.function_call,
|
|
22
|
+
},
|
|
23
|
+
index: openAIChoice.index,
|
|
24
|
+
finish_reason: openAIChoice.finish_reason,
|
|
25
|
+
};
|
|
26
|
+
}),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function OpenAIHandler(params) {
|
|
31
|
+
const { apiKey: providedApiKey, baseUrl: providedBaseUrl, ...completionsParams } = params;
|
|
32
|
+
const apiKey = providedApiKey ?? process.env.OPENAI_API_KEY;
|
|
33
|
+
const baseUrl = providedBaseUrl ?? 'https://api.openai.com/v1';
|
|
34
|
+
const openai = new openai_1.default({
|
|
35
|
+
apiKey: apiKey,
|
|
36
|
+
baseURL: baseUrl,
|
|
37
|
+
});
|
|
38
|
+
const messages = toOpenAIMessages(completionsParams.messages);
|
|
39
|
+
if (params.stream) {
|
|
40
|
+
const response = await openai.chat.completions.create({
|
|
41
|
+
...completionsParams,
|
|
42
|
+
stream: true,
|
|
43
|
+
messages,
|
|
44
|
+
});
|
|
45
|
+
return toStreamingResponse(response);
|
|
46
|
+
}
|
|
47
|
+
const response = await openai.chat.completions.create({
|
|
48
|
+
...completionsParams,
|
|
49
|
+
stream: false,
|
|
50
|
+
messages,
|
|
51
|
+
});
|
|
52
|
+
const result = {
|
|
53
|
+
created: response.created,
|
|
54
|
+
model: response.model,
|
|
55
|
+
choices: response.choices.map((c) => ({
|
|
56
|
+
finish_reason: c.finish_reason,
|
|
57
|
+
index: c.index,
|
|
58
|
+
message: {
|
|
59
|
+
role: c.message.role,
|
|
60
|
+
content: c.message.content,
|
|
61
|
+
function_call: c.message.function_call ?? undefined,
|
|
62
|
+
},
|
|
63
|
+
})),
|
|
64
|
+
usage: response.usage
|
|
65
|
+
? {
|
|
66
|
+
prompt_tokens: response.usage.prompt_tokens,
|
|
67
|
+
completion_tokens: response.usage.completion_tokens,
|
|
68
|
+
total_tokens: response.usage.total_tokens,
|
|
69
|
+
}
|
|
70
|
+
: undefined,
|
|
71
|
+
};
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
const registry_1 = require("../registry");
|
|
75
|
+
(0, registry_1.registerCompletionHandler)('gpt-', OpenAIHandler);
|
|
76
|
+
(0, registry_1.registerCompletionHandler)('openai/', OpenAIHandler);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OpenAIEmbeddingHandler = OpenAIEmbeddingHandler;
|
|
7
|
+
const openai_1 = __importDefault(require("openai"));
|
|
8
|
+
async function OpenAIEmbeddingHandler(params) {
|
|
9
|
+
const apiKey = params.apiKey ?? process.env.OPENAI_API_KEY;
|
|
10
|
+
const baseUrl = params.baseUrl;
|
|
11
|
+
const openai = new openai_1.default({
|
|
12
|
+
apiKey: apiKey,
|
|
13
|
+
baseURL: baseUrl,
|
|
14
|
+
});
|
|
15
|
+
return openai.embeddings.create({ input: params.input, model: params.model });
|
|
16
|
+
}
|
|
17
|
+
const registry_1 = require("../registry");
|
|
18
|
+
(0, registry_1.registerEmbeddingHandler)('text-embedding-', OpenAIEmbeddingHandler);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createOpenAILikeHandler = createOpenAILikeHandler;
|
|
4
|
+
const openai_1 = require("./openai");
|
|
5
|
+
function createOpenAILikeHandler(config) {
|
|
6
|
+
return async (params) => {
|
|
7
|
+
const apiKey = params.apiKey ?? process.env[config.apiKeyEnv];
|
|
8
|
+
if (!apiKey) {
|
|
9
|
+
throw new Error(`${config.name} requires an API key. Set the ${config.apiKeyEnv} environment variable or pass apiKey in params.`);
|
|
10
|
+
}
|
|
11
|
+
return (0, openai_1.OpenAIHandler)({
|
|
12
|
+
...params,
|
|
13
|
+
apiKey,
|
|
14
|
+
baseUrl: config.baseUrl,
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const openaiLike_1 = require("../mappings/openaiLike");
|
|
19
|
+
const registry_1 = require("../registry");
|
|
20
|
+
for (const [prefix, config] of Object.entries(openaiLike_1.OPENAI_LIKE_MAPPINGS)) {
|
|
21
|
+
(0, registry_1.registerCompletionHandler)(prefix, createOpenAILikeHandler(config));
|
|
22
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { EmbeddingParams, EmbeddingResponse } from '../types';
|
|
2
|
+
import type { OpenAILikeConfig } from '../mappings/openaiLike';
|
|
3
|
+
export declare function createOpenAILikeEmbeddingHandler(config: OpenAILikeConfig): (params: EmbeddingParams) => Promise<EmbeddingResponse>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createOpenAILikeEmbeddingHandler = createOpenAILikeEmbeddingHandler;
|
|
4
|
+
const openaiEmbedding_1 = require("./openaiEmbedding");
|
|
5
|
+
function createOpenAILikeEmbeddingHandler(config) {
|
|
6
|
+
return async (params) => {
|
|
7
|
+
const apiKey = params.apiKey ?? process.env[config.apiKeyEnv];
|
|
8
|
+
if (!apiKey) {
|
|
9
|
+
throw new Error(`${config.name} requires an API key. Set the ${config.apiKeyEnv} environment variable or pass apiKey in params.`);
|
|
10
|
+
}
|
|
11
|
+
return (0, openaiEmbedding_1.OpenAIEmbeddingHandler)({
|
|
12
|
+
...params,
|
|
13
|
+
apiKey,
|
|
14
|
+
baseUrl: config.baseUrl,
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const openaiLike_1 = require("../mappings/openaiLike");
|
|
19
|
+
const registry_1 = require("../registry");
|
|
20
|
+
for (const [prefix, config] of Object.entries(openaiLike_1.OPENAI_LIKE_MAPPINGS)) {
|
|
21
|
+
(0, registry_1.registerEmbeddingHandler)(prefix, createOpenAILikeEmbeddingHandler(config));
|
|
22
|
+
}
|