@objectiveai/langchain
Version:
Objective AI integrations for LangChain.js
417 lines (416 loc) • 16.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueryObjectiveAI = void 0;
const chat_models_1 = require("@langchain/core/language_models/chat_models");
const messages_1 = require("@langchain/core/messages");
const objectiveai_1 = require("objectiveai");
const openai_1 = require("openai");
// TODO: support tools
class QueryObjectiveAI extends chat_models_1.BaseChatModel {
constructor(fields) {
super(fields);
Object.defineProperty(this, "chat_completion_create_params", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "openai", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.chat_completion_create_params = fields.chat_completion_create_params;
this.openai = fields.openai;
}
_llmType() {
return "objectiveai";
}
invocationParams(_options) {
// use params from constructor as base
const chat_completion_create_params = {
...this.chat_completion_create_params,
};
// override with params from call, except for undefined values
// to delete params from the base, pass in null
if (_options?.chat_completion_create_params) {
for (const [key, value] of Object.entries(_options.chat_completion_create_params)) {
if (value !== undefined) {
chat_completion_create_params[key] =
value;
}
}
}
// override with disableStreaming
if (this.disableStreaming) {
chat_completion_create_params.stream = false;
chat_completion_create_params.stream_options = undefined;
}
return {
chat_completion_create_params,
openai: this.openai,
};
}
async _generate(messages, options, _runManager) {
const { chat_completion_create_params: baseChatCompletionCreateParams, openai: openaiOptions, } = this.invocationParams(options);
const openai = new openai_1.OpenAI(openaiOptions);
const chatCompletionCreateParams = {
...baseChatCompletionCreateParams,
messages: messages.map(baseMessageToChatCompletionRequestMessage),
stream: false,
};
const completion = await objectiveai_1.Query.Completions.create(openai, chatCompletionCreateParams, {
...(options?.timeout !== undefined ? { timeout: options.timeout } : {}),
...(options?.signal !== undefined ? { signal: options.signal } : {}),
});
const baseMessage = queryCompletionResponseToBaseMessage(completion);
return {
generations: [
{
message: baseMessage,
text: baseMessage.content,
generationInfo: {
id: completion.id,
choices_count: completion.choices.length,
created: completion.created,
model: completion.model,
object: completion.object,
service_tier: completion.service_tier,
system_fingerprint: completion.system_fingerprint,
},
},
],
llmOutput: {
tokenUsage: completion.usage
? {
promptTokens: completion.usage.prompt_tokens,
completionTokens: completion.usage.completion_tokens,
totalTokens: completion.usage.total_tokens,
cost: completion.usage.cost,
}
: undefined,
},
};
}
}
exports.QueryObjectiveAI = QueryObjectiveAI;
function baseMessageToChatCompletionRequestMessage(message) {
function getMessageTypeOrRole(message) {
const type = message.getType();
if (type === "generic" && messages_1.ChatMessage.isInstance(message)) {
return message.role;
}
else {
return type;
}
}
function baseMessageContentToUserContent(content) {
if (typeof content === "string") {
return content;
}
else {
const parts = [];
for (const p of content) {
if (p.type === "text" && typeof p.text === "string") {
parts.push({
type: "text",
text: p.text,
});
}
else if (p.type === "image_url" && typeof p.image_url === "string") {
parts.push({
type: "image_url",
image_url: {
url: p.image_url,
},
});
}
else if (p.type === "image_url" &&
typeof p.image_url === "object" &&
p.image_url !== null &&
typeof p.image_url.url === "string") {
parts.push({
type: "image_url",
image_url: {
url: p.image_url.url,
detail: p.image_url.detail === "auto" ||
p.image_url.detail === "low" ||
p.image_url.detail === "high"
? p.image_url.detail
: undefined,
},
});
}
else if ("source_type" in p &&
p.source_type === "url" &&
"url" in p &&
typeof p.url === "string" &&
p.type === "image") {
parts.push({
type: "image_url",
image_url: {
url: p.url,
},
});
}
else if ("source_type" in p &&
p.source_type === "base64" &&
"data" in p &&
typeof p.data === "string" &&
p.type === "image") {
parts.push({
type: "image_url",
image_url: {
url: `data:${p.data}`,
},
});
}
else if ("source_type" in p &&
p.source_type === "base64" &&
"data" in p &&
typeof p.data === "string" &&
p.type === "audio") {
try {
const parsed = (0, messages_1.parseBase64DataUrl)({
dataUrl: p.data,
asTypedArray: false,
});
if (parsed) {
let { subtype } = (0, messages_1.parseMimeType)(parsed.mime_type);
subtype = subtype.toLowerCase();
let format;
if (subtype === "mpeg" || subtype === "mp3") {
format = "mp3";
}
else if (subtype === "wav" || subtype === "x-wav") {
format = "wav";
}
else {
throw new Error(`Unsupported audio format: ${subtype}`);
}
parts.push({
type: "input_audio",
input_audio: {
data: p.data,
format,
},
});
}
else {
throw new Error(`Failed to parse audio base64 data URL: ${p.data}`);
}
}
catch (e) {
throw new Error(`Unsupported audio content part: ${p}, error: ${e}`);
}
}
else if ("source_type" in p &&
p.source_type === "base64" &&
"data" in p &&
typeof p.data === "string" &&
p.type === "file") {
parts.push({
type: "file",
file: {
file_data: p.data,
},
});
}
else {
throw new Error(`Unsupported Human content part: ${p}`);
}
}
return parts;
}
}
function baseMessageContentToSimpleContent(content) {
if (typeof content === "string") {
return content;
}
else {
const parts = [];
for (const p of content) {
if (p.type === "text" && typeof p.text === "string") {
parts.push({
type: "text",
text: p.text,
});
}
else {
throw new Error(`Unsupported Non-Human content part: ${p}`);
}
}
return parts;
}
}
function baseMessageToChatCompletionRequestMessageAssistantToolCalls(message) {
if ("tool_calls" in message && Array.isArray(message.tool_calls)) {
const tool_calls = [];
for (const tc of message.tool_calls) {
if ("name" in tc &&
typeof tc.name === "string" &&
"args" in tc &&
typeof tc.args === "object" &&
tc.args !== null &&
"id" in tc &&
typeof tc.id === "string") {
try {
tool_calls.push({
type: "function",
id: tc.id,
function: {
name: tc.name,
arguments: JSON.stringify(tc.args),
},
});
}
catch (e) {
throw new Error(`Failed to serialize tool call args: ${tc.args}, error: ${e}`);
}
}
else {
throw new Error(`Unsupported tool call: ${tc}`);
}
}
if (tool_calls.length > 0) {
return tool_calls;
}
}
return undefined;
}
const typeOrRole = getMessageTypeOrRole(message);
if (typeOrRole === "human" || typeOrRole === "user") {
return {
role: "user",
content: baseMessageContentToUserContent(message.content),
name: message.name,
};
}
else if (typeOrRole === "ai" || typeOrRole === "assistant") {
return {
role: "assistant",
content: baseMessageContentToSimpleContent(message.content),
name: message.name,
tool_calls: baseMessageToChatCompletionRequestMessageAssistantToolCalls(message),
};
}
else if (typeOrRole === "developer") {
return {
role: "developer",
content: baseMessageContentToSimpleContent(message.content),
name: message.name,
};
}
else if (typeOrRole === "system") {
return {
role: "system",
content: baseMessageContentToSimpleContent(message.content),
name: message.name,
};
}
else if (typeOrRole === "tool" && messages_1.ToolMessage.isInstance(message)) {
return {
role: "tool",
content: baseMessageContentToSimpleContent(message.content),
tool_call_id: message.tool_call_id,
};
}
else {
throw new Error(`Unsupported message: ${message}`);
}
}
function queryCompletionResponseToBaseMessage(completion) {
function chatCompletionResponseMessageToBaseMessageToolCalls(message) {
const tool_calls = [];
const invalid_tool_calls = [];
for (const { id, function: { name, arguments: args }, } of message.tool_calls ?? []) {
try {
tool_calls.push({
name,
args: JSON.parse(args),
id,
type: "tool_call",
});
}
catch (e) {
invalid_tool_calls.push({
name,
args,
id,
error: `Failed to parse tool call args: ${args}, error: ${e}`,
type: "invalid_tool_call",
});
}
}
return {
tool_calls: tool_calls.length > 0 ? tool_calls : undefined,
invalid_tool_calls: invalid_tool_calls.length > 0 ? invalid_tool_calls : undefined,
};
}
// use winning choice for tool_calls and metadata
const choice = completion.choices[0];
const { tool_calls, invalid_tool_calls } = choice
? chatCompletionResponseMessageToBaseMessageToolCalls(choice.message)
: {};
// return each "generate" choice, including confidence and content
const content = [];
for (const c of completion.choices) {
if (c.generate_id && c.confidence !== null) {
content.push({
confidence: c.confidence,
output: c.message.content ?? "",
});
}
}
return new messages_1.AIMessage({
content: JSON.stringify(content),
tool_calls,
invalid_tool_calls,
id: completion.id,
response_metadata: {
id: completion.id,
choices_count: completion.choices.length,
created: completion.created,
model: completion.model,
object: completion.object,
service_tier: completion.service_tier,
system_fingerprint: completion.system_fingerprint,
choice: {
finish_reason: choice?.finish_reason,
index: choice?.index,
generate_id: choice?.generate_id,
confidence_id: choice?.confidence_id,
confidence_weight: choice?.confidence_weight,
confidence: choice?.confidence,
model: choice?.model,
model_index: choice?.model_index,
completion_metadata: {
id: choice?.completion_metadata.id,
created: choice?.completion_metadata.created,
model: choice?.completion_metadata.model,
service_tier: choice?.completion_metadata.service_tier,
system_fingerprint: choice?.completion_metadata.system_fingerprint,
provider: choice?.completion_metadata.provider,
},
},
},
usage_metadata: completion.usage
? {
input_tokens: completion.usage.prompt_tokens,
output_tokens: completion.usage.completion_tokens,
total_tokens: completion.usage.total_tokens,
input_token_details: completion.usage.prompt_tokens_details
? {
cache_read: completion.usage.prompt_tokens_details.cached_tokens,
}
: undefined,
output_token_details: completion.usage.completion_tokens_details
? {
reasoning: completion.usage.completion_tokens_details.reasoning_tokens,
}
: undefined,
}
: undefined,
});
}