@hashbrownai/openai
Version:
OpenAI provider for Hashbrown AI
207 lines • 9.46 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.text = text;
const tslib_1 = require("tslib");
const core_1 = require("@hashbrownai/core");
const openai_1 = require("openai");
function text(options) {
return tslib_1.__asyncGenerator(this, arguments, function* text_1() {
var _a, e_1, _b, _c;
var _d, _e;
const { apiKey, baseURL, request, transformRequestOptions, loadThread, saveThread, } = options;
const { model, tools, responseFormat, toolChoice, system } = request;
const threadId = request.threadId;
let loadedThread = [];
let effectiveThreadId = threadId;
const openai = new openai_1.default({
apiKey,
baseURL: baseURL,
});
// Thread loading (both load-thread op and generate op with threadId)
const shouldLoadThread = Boolean(request.threadId);
const shouldHydrateThreadOnTheClient = Boolean(request.operation === 'load-thread');
if (shouldLoadThread) {
yield yield tslib_1.__await((0, core_1.encodeFrame)({ type: 'thread-load-start' }));
if (!loadThread) {
yield yield tslib_1.__await((0, core_1.encodeFrame)({
type: 'thread-load-failure',
error: 'Thread loading is not available for this transport.',
}));
return yield tslib_1.__await(void 0);
}
const loadFn = loadThread;
try {
loadedThread = yield tslib_1.__await(loadFn(request.threadId));
if (shouldHydrateThreadOnTheClient) {
yield yield tslib_1.__await((0, core_1.encodeFrame)({
type: 'thread-load-success',
thread: loadedThread,
}));
}
else {
yield yield tslib_1.__await((0, core_1.encodeFrame)({
type: 'thread-load-success',
}));
}
}
catch (error) {
const { message, stack } = normalizeError(error);
yield yield tslib_1.__await((0, core_1.encodeFrame)({
type: 'thread-load-failure',
error: message,
stacktrace: stack,
}));
return yield tslib_1.__await(void 0);
}
}
if (request.operation === 'load-thread') {
return yield tslib_1.__await(void 0);
}
const mergedMessages = request.threadId && shouldLoadThread
? (0, core_1.mergeMessagesForThread)(loadedThread, (_d = request.messages) !== null && _d !== void 0 ? _d : [])
: ((_e = request.messages) !== null && _e !== void 0 ? _e : []);
let assistantMessage = null;
try {
const baseOptions = {
stream: true,
model: model,
messages: [
{
role: 'system',
content: system,
},
...mergedMessages.map((message) => {
if (message.role === 'user') {
return {
role: message.role,
content: message.content,
};
}
if (message.role === 'assistant') {
return {
role: message.role,
content: message.content && typeof message.content !== 'string'
? JSON.stringify(message.content)
: message.content,
tool_calls: message.toolCalls && message.toolCalls.length > 0
? message.toolCalls.map((toolCall) => (Object.assign(Object.assign({}, toolCall), { type: 'function', function: Object.assign(Object.assign({}, toolCall.function), { arguments: JSON.stringify(toolCall.function.arguments) }) })))
: undefined,
};
}
if (message.role === 'tool') {
return {
role: message.role,
content: JSON.stringify(message.content),
tool_call_id: message.toolCallId,
};
}
throw new Error(`Invalid message role`);
}),
],
tools: tools && tools.length > 0
? tools.map((tool) => ({
type: 'function',
function: {
name: tool.name,
description: tool.description,
parameters: tool.parameters,
strict: true,
},
}))
: undefined,
tool_choice: toolChoice,
response_format: responseFormat
? {
type: 'json_schema',
json_schema: {
strict: true,
name: 'schema',
description: '',
schema: responseFormat,
},
}
: undefined,
};
const resolvedOptions = transformRequestOptions
? yield tslib_1.__await(transformRequestOptions(baseOptions))
: baseOptions;
const stream = openai.chat.completions.stream(resolvedOptions);
yield yield tslib_1.__await((0, core_1.encodeFrame)({ type: 'generation-start' }));
try {
for (var _f = true, stream_1 = tslib_1.__asyncValues(stream), stream_1_1; stream_1_1 = yield tslib_1.__await(stream_1.next()), _a = stream_1_1.done, !_a; _f = true) {
_c = stream_1_1.value;
_f = false;
const chunk = _c;
const chunkMessage = {
choices: chunk.choices.map((choice) => ({
index: choice.index,
delta: {
content: choice.delta.content,
role: choice.delta.role,
toolCalls: choice.delta.tool_calls,
},
finishReason: choice.finish_reason,
})),
};
const frame = {
type: 'generation-chunk',
chunk: chunkMessage,
};
assistantMessage = (0, core_1.updateAssistantMessage)(assistantMessage, chunkMessage);
yield yield tslib_1.__await((0, core_1.encodeFrame)(frame));
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_f && !_a && (_b = stream_1.return)) yield tslib_1.__await(_b.call(stream_1));
}
finally { if (e_1) throw e_1.error; }
}
yield yield tslib_1.__await((0, core_1.encodeFrame)({ type: 'generation-finish' }));
}
catch (error) {
const { message, stack } = normalizeError(error);
const frame = {
type: 'generation-error',
error: message,
stacktrace: stack,
};
yield yield tslib_1.__await((0, core_1.encodeFrame)(frame));
return yield tslib_1.__await(void 0);
}
if (saveThread) {
const threadToSave = (0, core_1.mergeMessagesForThread)(mergedMessages, [
...(assistantMessage ? [assistantMessage] : []),
]);
yield yield tslib_1.__await((0, core_1.encodeFrame)({ type: 'thread-save-start' }));
try {
const savedThreadId = yield tslib_1.__await(saveThread(threadToSave, effectiveThreadId));
if (effectiveThreadId && savedThreadId !== effectiveThreadId) {
throw new Error('Save returned a different threadId than the existing thread');
}
effectiveThreadId = savedThreadId;
yield yield tslib_1.__await((0, core_1.encodeFrame)({
type: 'thread-save-success',
threadId: savedThreadId,
}));
}
catch (error) {
const { message, stack } = normalizeError(error);
yield yield tslib_1.__await((0, core_1.encodeFrame)({
type: 'thread-save-failure',
error: message,
stacktrace: stack,
}));
return yield tslib_1.__await(void 0);
}
}
});
}
function normalizeError(error) {
if (error instanceof Error) {
return { message: error.message, stack: error.stack };
}
return { message: String(error) };
}
//# sourceMappingURL=text.fn.js.map