@convo-lang/convo-lang
Version:
The language of AI
202 lines • 8.32 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseOpenAiConvoConverter = void 0;
const convo_lang_1 = require("@convo-lang/convo-lang");
const common_1 = require("@iyio/common");
const json5_1 = require("@iyio/json5");
/**
* A conversation converter for OpenAI like APIs
*/
class BaseOpenAiConvoConverter {
supportedInputTypes;
supportedOutputTypes;
userRoles;
assistantRoles;
systemRoles;
functionRoles;
chatModel;
visionModel;
models;
hasVision;
transformInput;
transformOutput;
constructor({ chatModel, visionModel, supportedInputTypes, supportedOutputTypes, userRoles, assistantRoles, systemRoles, functionRoles, models, hasVision, transformInput, transformOutput, }) {
this.chatModel = chatModel;
this.visionModel = visionModel;
this.supportedInputTypes = supportedInputTypes ? [...supportedInputTypes] : [];
Object.freeze(this.supportedInputTypes);
this.supportedOutputTypes = supportedOutputTypes ? [...supportedOutputTypes] : [];
Object.freeze(this.supportedOutputTypes);
this.userRoles = userRoles ? [...userRoles] : ['user'];
Object.freeze(this.userRoles);
this.assistantRoles = assistantRoles ? [...assistantRoles] : ['assistant'];
Object.freeze(this.assistantRoles);
this.systemRoles = systemRoles ? [...systemRoles] : ['system'];
Object.freeze(this.systemRoles);
this.functionRoles = functionRoles ? [...functionRoles] : ['function'];
Object.freeze(this.functionRoles);
this.models = [...models];
Object.freeze(this.models);
this.hasVision = hasVision;
this.transformInput = transformInput;
this.transformOutput = transformOutput;
}
convertOutputToConvo(output, outputType, input, inputType, flat) {
if (this.transformOutput) {
output = this.transformOutput(output);
}
const msg = output.choices[0];
if (!msg) {
return [];
}
let params;
let callError;
;
const tool = msg.message.tool_calls?.find(t => t.function);
const toolFn = tool?.function;
let fnName = undefined;
const toolId = (tool && toolFn) ? tool.id : undefined;
if (toolFn) {
try {
fnName = toolFn.name;
params = (0, json5_1.parseJson5)(toolFn.arguments ?? '{}');
}
catch (ex) {
callError =
`Unable to parse arguments for ${toolFn.name} - ${(0, common_1.getErrorMessage)(ex)}\n${toolFn.arguments}`;
}
}
if (fnName) {
if (callError) {
return [(0, convo_lang_1.createTextConvoCompletionMessage)({
flat,
role: msg.message.role,
content: callError,
model: output.model,
models: this.models,
inputTokens: output.usage?.prompt_tokens,
outputTokens: output.usage?.completion_tokens,
})];
}
return [(0, convo_lang_1.createFunctionCallConvoCompletionMessage)({
flat,
callFn: fnName,
callParams: params,
toolId,
model: output.model,
models: this.models,
inputTokens: output.usage?.prompt_tokens,
outputTokens: output.usage?.completion_tokens,
})];
}
else {
return [(0, convo_lang_1.createTextConvoCompletionMessage)({
flat,
role: msg.message.role,
content: msg.message.content,
model: output.model,
models: this.models,
inputTokens: output.usage?.prompt_tokens,
outputTokens: output.usage?.completion_tokens,
})];
}
}
convertConvoToInput(flat, inputType) {
const messages = (0, convo_lang_1.getNormalizedFlatMessageList)(flat);
let visionCapable = flat.capabilities?.includes('vision');
const lastContentMessage = (0, convo_lang_1.getLastNonCalledConvoFlatMessage)(messages);
const model = flat?.responseModel ?? (visionCapable ? this.visionModel : this.chatModel);
if (!model) {
throw new Error('Chat AI model not defined');
}
const info = this.models.find(m => m.name === model);
if (info && info.inputCapabilities?.includes('image') || this.hasVision?.(model)) {
visionCapable = true;
}
const oMsgs = [];
const oFns = [];
for (const m of messages) {
if (m.fn) {
oFns.push({
type: "function",
function: (0, common_1.deleteUndefined)({
name: m.fn.name,
description: m.fn.description,
parameters: (m._fnParams ?? (m.fnParams ? ((0, common_1.zodTypeToJsonScheme)(m.fnParams) ?? {}) : {}))
})
});
}
else if (m.content !== undefined) {
let content;
const vc = (visionCapable || m.vision) && m.vision !== false && m.role !== 'system';
if (vc) {
const items = (0, common_1.parseMarkdownImages)(m.content ?? '', { requireImgProtocol: true });
if (items.length === 1 && (typeof items[0]?.text === 'string')) {
content = items[0]?.text ?? '';
}
else {
content = items.map(i => i.image ? {
type: 'image_url',
image_url: { url: i.image.url }
} : {
type: 'text',
text: i.text ?? ''
});
}
}
else {
content = m.content ?? '';
}
oMsgs.push((0, common_1.deleteUndefined)((0, common_1.asType)({
role: this.isKnownRole(m.role) ? m.role : 'user',
content
})));
}
else if (m.called) {
const toolId = m.tags?.['toolId'] ?? m.called.name;
oMsgs.push({
role: 'assistant',
content: null,
tool_calls: [{
id: toolId,
type: 'function',
function: {
name: m.called.name,
arguments: JSON.stringify(m.calledParams),
}
}]
});
oMsgs.push({
role: 'tool',
tool_call_id: toolId,
content: m.calledReturn === undefined ? 'function-called' : JSON.stringify(m.calledReturn),
});
}
}
const jsonMode = lastContentMessage?.responseFormat === 'json';
const cParams = {
model,
response_format: jsonMode ? { type: 'json_object' } : undefined,
stream: false,
messages: oMsgs,
tools: oFns?.length ? oFns : undefined,
user: flat?.userId,
tool_choice: flat.toolChoice ? ((typeof flat.toolChoice === 'string') ?
flat.toolChoice : { type: "function", "function": flat.toolChoice }) : undefined
};
if (this.transformInput) {
return this.transformInput(cParams);
}
else {
return cParams;
}
}
isKnownRole(role) {
return (this.userRoles.includes(role) ||
this.assistantRoles.includes(role) ||
this.systemRoles.includes(role) ||
this.functionRoles.includes(role));
}
}
exports.BaseOpenAiConvoConverter = BaseOpenAiConvoConverter;
//# sourceMappingURL=BaseOpenAiConvoConverter.js.map