jorel
Version:
The easiest way to use LLMs, including streams, images, documents, tools and various agent scenarios.
175 lines (174 loc) • 6.95 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenAIProvider = void 0;
const openai_1 = require("openai");
const shared_1 = require("../../shared");
const providers_1 = require("../../providers");
const convert_llm_message_1 = require("./convert-llm-message");
const tools_1 = require("../../tools");
const convert_inputs_1 = require("./convert-inputs");
/** Provides access to OpenAI and other compatible services */
class OpenAIProvider {
constructor({ apiKey, apiUrl, name } = {}) {
this.name = name || "openai";
this.client = new openai_1.OpenAI({
apiKey: apiKey ?? process.env.OPENAI_API_KEY,
baseURL: apiUrl,
});
}
async generateResponse(model, messages, config = {}) {
const start = Date.now();
const temperature = config.temperature ?? undefined;
const response = await this.client.chat.completions.create({
model,
messages: await (0, convert_llm_message_1.convertLlmMessagesToOpenAiMessages)(messages),
temperature,
response_format: (0, convert_inputs_1.jsonResponseToOpenAi)(config.json, config.jsonDescription),
max_tokens: config.maxTokens,
parallel_tool_calls: config.tools && config.tools.hasTools ? config.tools.allowParallelCalls : undefined,
tool_choice: (0, convert_inputs_1.toolChoiceToOpenAi)(config.toolChoice),
tools: config.tools?.asLlmFunctions,
});
const durationMs = Date.now() - start;
const inputTokens = response.usage?.prompt_tokens;
const outputTokens = response.usage?.completion_tokens;
const message = response.choices[0].message;
const toolCalls = message.tool_calls?.map((call) => {
return {
id: (0, shared_1.generateUniqueId)(),
request: {
id: call.id,
function: {
name: call.function.name,
arguments: tools_1.LlmToolKit.deserialize(call.function.arguments),
},
},
approvalState: config.tools?.getTool(call.function.name)?.requiresConfirmation
? "requiresApproval"
: "noApprovalRequired",
executionState: "pending",
result: null,
error: null,
};
});
const provider = this.name;
return {
...(0, providers_1.generateAssistantMessage)(message.content, toolCalls),
meta: {
model,
provider,
temperature,
durationMs,
inputTokens,
outputTokens,
},
};
}
async *generateResponseStream(model, messages, config = {}) {
const start = Date.now();
const temperature = config.temperature ?? undefined;
const response = await this.client.chat.completions.create({
model,
messages: await (0, convert_llm_message_1.convertLlmMessagesToOpenAiMessages)(messages),
temperature,
response_format: (0, convert_inputs_1.jsonResponseToOpenAi)(config.json, config.jsonDescription),
max_tokens: config.maxTokens,
stream: true,
tools: config.tools?.asLlmFunctions,
parallel_tool_calls: config.tools && config.tools.hasTools ? config.tools.allowParallelCalls : undefined,
tool_choice: (0, convert_inputs_1.toolChoiceToOpenAi)(config.toolChoice),
stream_options: {
include_usage: true,
},
});
let inputTokens;
let outputTokens;
const _toolCalls = [];
let content = "";
for await (const chunk of response) {
const delta = (0, shared_1.firstEntry)(chunk.choices)?.delta;
if (delta?.content) {
content += delta.content;
yield { type: "chunk", content: delta.content };
}
if (delta?.tool_calls) {
for (const toolCall of delta.tool_calls) {
const _toolCall = _toolCalls[toolCall.index] || { id: "", function: { name: "", arguments: "" } };
if (toolCall.id)
_toolCall.id += toolCall.id;
if (toolCall.function) {
if (toolCall.function.name)
_toolCall.function.name += toolCall.function.name;
if (toolCall.function.arguments)
_toolCall.function.arguments += toolCall.function.arguments;
}
_toolCalls[toolCall.index] = _toolCall;
}
}
if (chunk.usage) {
inputTokens = chunk.usage?.prompt_tokens;
outputTokens = chunk.usage?.completion_tokens;
}
}
const durationMs = Date.now() - start;
const provider = this.name;
const toolCalls = _toolCalls.map((call) => {
return {
id: (0, shared_1.generateUniqueId)(),
request: {
id: call.id,
function: {
name: call.function.name,
arguments: tools_1.LlmToolKit.deserialize(call.function.arguments),
},
},
approvalState: config.tools?.getTool(call.function.name)?.requiresConfirmation
? "requiresApproval"
: "noApprovalRequired",
executionState: "pending",
result: null,
error: null,
};
});
const meta = {
model,
provider,
temperature,
durationMs,
inputTokens,
outputTokens,
};
if (_toolCalls.length > 0) {
yield {
type: "response",
role: "assistant_with_tools",
content,
toolCalls,
meta,
};
}
else {
yield {
type: "response",
role: "assistant",
content,
meta,
};
}
}
async getAvailableModels() {
const models = await this.client.models.list();
return models.data.map((model) => model.id);
}
async createEmbedding(model, text) {
const response = await this.client.embeddings.create({
model,
input: text,
});
if (!response || !response.data || !response.data || response.data.length === 0) {
throw new Error("Failed to create embedding");
}
return response.data[0].embedding;
}
}
exports.OpenAIProvider = OpenAIProvider;