@maximai/maxim-js
Version:
Maxim AI JS SDK. Visit https://getmaxim.ai for more info.
605 lines • 24.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenAIUtils = void 0;
/**
* Utility functions for OpenAI integration with Maxim logging.
*/
class OpenAIUtils {
/**
* Parse OpenAI message params to Maxim's message format.
*/
static parseMessageParam(messages, overrideRole) {
const parsedMessages = [];
for (const msg of messages) {
const role = overrideRole || msg.role;
const content = "content" in msg ? msg.content : "";
if (Array.isArray(content)) {
// Handle content blocks for multimodal
const parsedContent = [];
let textContent = "";
for (const block of content) {
if (typeof block === "object" && block !== null && "type" in block) {
if (block.type === "text" && "text" in block) {
textContent += block.text;
parsedContent.push({
type: "text",
text: block.text,
});
}
else if (block.type === "image_url" && "image_url" in block) {
const imageUrl = block.image_url;
parsedContent.push({
type: "image_url",
image_url: {
url: imageUrl.url,
detail: imageUrl.detail,
},
});
}
}
}
if (role === "assistant") {
// Assistant messages use string content only
parsedMessages.push({
role: "assistant",
content: textContent,
tool_calls: "tool_calls" in msg ? convertToolCalls(msg.tool_calls) : undefined,
});
}
else {
// Non-assistant messages can have multimodal content
parsedMessages.push({
role: role,
content: parsedContent.length > 0 ? parsedContent : textContent,
});
}
}
else {
const contentStr = content !== null && content !== undefined ? String(content) : "";
if (role === "assistant") {
parsedMessages.push({
role: "assistant",
content: contentStr,
tool_calls: "tool_calls" in msg ? convertToolCalls(msg.tool_calls) : undefined,
});
}
else {
parsedMessages.push({
role: role,
content: contentStr,
});
}
}
}
return parsedMessages;
}
/**
* Extract model parameters from OpenAI request options.
*/
static getModelParams(options) {
const modelParams = {};
const skipKeys = ["messages", "model", "extra_headers", "extra_body", "extra_query"];
const paramKeys = [
"temperature",
"top_p",
"presence_penalty",
"frequency_penalty",
"response_format",
"tool_choice",
"max_tokens",
"max_completion_tokens",
"n",
"stop",
"seed",
"logprobs",
"top_logprobs",
"logit_bias",
"user",
"tools",
];
for (const key of paramKeys) {
if (key in options && options[key] !== undefined && options[key] !== null) {
modelParams[key] = options[key];
}
}
// Include any additional parameters not in the known lists
for (const [key, value] of Object.entries(options)) {
if (!paramKeys.includes(key) && !skipKeys.includes(key) && value !== undefined && value !== null) {
modelParams[key] = value;
}
}
return modelParams;
}
/**
* Parse a non-streaming ChatCompletion response to Maxim's result format.
*/
static parseCompletion(completion) {
return {
id: completion.id,
object: completion.object,
created: completion.created,
model: completion.model,
choices: completion.choices.map((choice) => {
var _a, _b;
return ({
index: choice.index,
message: {
role: choice.message.role,
content: choice.message.content,
tool_calls: convertToolCalls(choice.message.tool_calls),
function_call: choice.message.function_call
? {
name: choice.message.function_call.name,
arguments: choice.message.function_call.arguments,
}
: undefined,
},
logprobs: choice.logprobs
? {
tokens: (_a = choice.logprobs.content) === null || _a === void 0 ? void 0 : _a.map((c) => c.token),
token_logprobs: (_b = choice.logprobs.content) === null || _b === void 0 ? void 0 : _b.map((c) => c.logprob),
}
: null,
finish_reason: choice.finish_reason || "stop",
});
}),
usage: completion.usage
? {
prompt_tokens: completion.usage.prompt_tokens,
completion_tokens: completion.usage.completion_tokens,
total_tokens: completion.usage.total_tokens,
}
: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
};
}
/**
* Parse streaming chunks into a combined ChatCompletionResult.
*/
static parseCompletionFromChunks(chunks) {
var _a, _b, _c, _d, _e;
if (chunks.length === 0) {
return {
id: "",
object: "chat.completion",
created: Math.floor(Date.now() / 1000),
model: "",
choices: [],
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
};
}
const lastChunk = chunks[chunks.length - 1];
// Combine all content from chunks
let combinedContent = "";
for (const chunk of chunks) {
for (const choice of chunk.choices) {
if (choice.delta && choice.delta.content) {
combinedContent += choice.delta.content;
}
}
}
// Combine all tool calls from chunks
const toolCallsMap = new Map();
for (const chunk of chunks) {
for (const choice of chunk.choices) {
if (choice.delta && choice.delta.tool_calls) {
for (const toolCall of choice.delta.tool_calls) {
const existing = toolCallsMap.get(toolCall.index);
if (!existing) {
toolCallsMap.set(toolCall.index, {
index: toolCall.index,
id: toolCall.id || "",
type: toolCall.type || "function",
function: {
name: ((_a = toolCall.function) === null || _a === void 0 ? void 0 : _a.name) || "",
arguments: ((_b = toolCall.function) === null || _b === void 0 ? void 0 : _b.arguments) || "",
},
});
}
else {
if (toolCall.id) {
existing.id = toolCall.id;
}
if ((_c = toolCall.function) === null || _c === void 0 ? void 0 : _c.name) {
existing.function.name = toolCall.function.name;
}
if ((_d = toolCall.function) === null || _d === void 0 ? void 0 : _d.arguments) {
existing.function.arguments += toolCall.function.arguments;
}
}
}
}
}
}
const toolCalls = Array.from(toolCallsMap.values());
// Get finish reason from last chunk
const finishReason = ((_e = lastChunk.choices[0]) === null || _e === void 0 ? void 0 : _e.finish_reason) || "stop";
// Get usage from the last chunk (if stream_options.include_usage was set)
const usage = lastChunk.usage || { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 };
return {
id: lastChunk.id,
object: "chat.completion",
created: lastChunk.created,
model: lastChunk.model,
choices: [
{
index: 0,
message: {
role: "assistant",
content: toolCalls.length > 0 ? null : combinedContent,
tool_calls: toolCalls.length > 0
? toolCalls.map((tc) => ({
id: tc.id,
type: tc.type,
function: tc.function,
}))
: undefined,
},
logprobs: null,
finish_reason: finishReason,
},
],
usage: {
prompt_tokens: usage.prompt_tokens,
completion_tokens: usage.completion_tokens,
total_tokens: usage.total_tokens,
},
};
}
/**
* Extract combined text content from streaming chunks.
*/
static extractTextFromChunks(chunks) {
let combinedText = "";
for (const chunk of chunks) {
for (const choice of chunk.choices) {
if (choice.delta && choice.delta.content) {
combinedText += choice.delta.content;
}
}
}
return combinedText;
}
// ========================================
// Responses API Utilities
// ========================================
/**
* Parse Responses API input to generation messages format.
* Handles both simple string inputs and complex ResponseInputParam arrays.
*/
static parseResponsesInputToMessages(inputValue) {
if (inputValue === null || inputValue === undefined) {
return [];
}
// Simple string input
if (typeof inputValue === "string") {
return [{ role: "user", content: inputValue }];
}
// Not an array - wrap as user message
if (!Array.isArray(inputValue)) {
return [{ role: "user", content: String(inputValue) }];
}
const messages = [];
for (const item of inputValue) {
// String item
if (typeof item === "string") {
messages.push({ role: "user", content: item });
continue;
}
// Non-object item
if (!item || typeof item !== "object") {
messages.push({ role: "user", content: String(item) });
continue;
}
const itemType = item.type;
// EasyInputMessageParam or Message (both have role and content)
if ("role" in item && "content" in item && (itemType === undefined || itemType === "message")) {
let roleVal = item.role || "user";
if (typeof roleVal !== "string" || roleVal.trim() === "") {
roleVal = "user";
}
// Map developer -> system for internal roles
const roleMap = { developer: "system" };
const finalRole = roleMap[roleVal] || roleVal;
const contentVal = item.content;
if (typeof contentVal === "string") {
if (finalRole === "assistant") {
messages.push({ role: "assistant", content: contentVal });
}
else {
messages.push({ role: finalRole, content: contentVal });
}
}
else {
// Complex content - extract text parts
const textContent = extractContentFromInputMessageList(contentVal);
if (finalRole === "assistant") {
messages.push({ role: "assistant", content: textContent });
}
else {
messages.push({ role: finalRole, content: textContent });
}
}
continue;
}
// ResponseOutputMessageParam (assistant)
if (itemType === "message" && item.role === "assistant" && "content" in item) {
const assistantText = extractAssistantTextFromOutputMessage(item.content);
messages.push({ role: "assistant", content: assistantText });
continue;
}
// Function/tool CALL intents (assistant role)
if (itemType === "function_call" ||
itemType === "file_search_call" ||
itemType === "computer_call" ||
itemType === "code_interpreter_call" ||
itemType === "web_search_call" ||
itemType === "local_shell_call" ||
itemType === "image_generation_call") {
const name = item.name || itemType;
const args = item.arguments || item.queries || item.action;
const callId = item.call_id || item.id;
let summary = `${name} call`;
if (callId)
summary += ` id=${callId}`;
if (args !== undefined)
summary += ` args=${JSON.stringify(args)}`;
messages.push({ role: "assistant", content: summary });
continue;
}
// Tool OUTPUTS (tool role)
if (itemType === "function_call_output" || itemType === "local_shell_call_output" || itemType === "computer_call_output") {
if (itemType === "computer_call_output") {
const output = item.output;
if (output && typeof output === "object" && output.type === "computer_screenshot") {
const imageUrl = output.image_url;
if (typeof imageUrl === "string" && imageUrl) {
messages.push({
role: "tool",
content: [{ type: "image_url", image_url: { url: imageUrl } }],
});
continue;
}
}
}
// Default: pass raw output as string
const outVal = item.output;
messages.push({
role: "tool",
content: outVal !== undefined ? String(outVal) : "",
});
continue;
}
// MCP items
if (itemType === "mcp_list_tools" ||
itemType === "mcp_approval_request" ||
itemType === "mcp_approval_response" ||
itemType === "mcp_call") {
if (itemType === "mcp_call" && item.output !== undefined) {
messages.push({ role: "tool", content: String(item.output) });
}
else if (itemType === "mcp_approval_response") {
messages.push({ role: "tool", content: summarizeObject(item) });
}
else {
messages.push({ role: "assistant", content: summarizeObject(item) });
}
continue;
}
// Reasoning item -> assistant
if (itemType === "reasoning") {
const summary = item.summary;
let txt;
if (Array.isArray(summary)) {
txt = summary
.filter((s) => s && typeof s === "object")
.map((s) => s.text || "")
.join("");
}
else {
txt = String(summary);
}
messages.push({ role: "assistant", content: txt });
continue;
}
// Item reference -> assistant note
if (itemType === "item_reference" || ("id" in item && item.type === undefined && Object.keys(item).length === 1)) {
messages.push({ role: "assistant", content: `[item_reference] id=${item.id}` });
continue;
}
// Unknown dict item -> user as final fallback
messages.push({ role: "user", content: String(item) });
}
return messages;
}
/**
* Extract model parameters from Responses API request options.
* Skips input, extra_headers, and model.
*/
static getResponsesModelParams(options) {
const modelParams = {};
const skipKeys = ["input", "extra_headers", "model"];
for (const [key, value] of Object.entries(options)) {
if (!skipKeys.includes(key) && value !== undefined && value !== null) {
modelParams[key] = value;
}
}
return modelParams;
}
/**
* Extract text output from a Responses API response.
* Returns the output_text property if available, or null.
*/
static extractResponsesOutputText(response) {
try {
// Try output_text property (getter in OpenAI SDK Response objects)
const outputText = response === null || response === void 0 ? void 0 : response.output_text;
if (typeof outputText === "string" && outputText.length > 0) {
return outputText;
}
}
catch {
// Ignore
}
// Fallback for dict-like structure - handle nested message content
try {
if (response && typeof response === "object") {
const output = response.output;
if (Array.isArray(output)) {
const texts = [];
for (const item of output) {
if (item && typeof item === "object") {
// Handle direct output_text or text items
if (item.type === "output_text" || item.type === "text") {
const textVal = item.text || item.content;
if (typeof textVal === "string") {
texts.push(textVal);
}
}
// Handle message items with nested content array (actual Responses API structure)
else if (item.type === "message" && Array.isArray(item.content)) {
for (const contentItem of item.content) {
if (contentItem && typeof contentItem === "object") {
if (contentItem.type === "output_text" || contentItem.type === "text") {
const textVal = contentItem.text || contentItem.content;
if (typeof textVal === "string") {
texts.push(textVal);
}
}
}
}
}
}
}
if (texts.length > 0) {
return texts.join("");
}
}
}
}
catch {
// Ignore
}
return null;
}
}
exports.OpenAIUtils = OpenAIUtils;
/**
* Helper to extract text content from ResponseInputMessageContentListParam.
*/
function extractContentFromInputMessageList(items) {
if (!Array.isArray(items)) {
return String(items);
}
const contentList = [];
for (const item of items) {
if (!item || typeof item !== "object") {
contentList.push(String(item));
continue;
}
const t = item.type;
if (t === "input_text" && "text" in item) {
contentList.push(String(item.text || ""));
}
else if (t === "input_image") {
const imageUrl = item.image_url;
const fileId = item.file_id;
const urlVal = imageUrl || (fileId ? `file:${fileId}` : null);
if (urlVal) {
contentList.push(`[image:${urlVal}]`);
}
else {
contentList.push("[image]");
}
}
else if (t === "input_file") {
const name = item.filename || item.file_url || item.file_id;
contentList.push(`[file:${name}]`);
}
else {
contentList.push(String(item));
}
}
return contentList.join(" ");
}
/**
* Helper to extract text from assistant output message content.
*/
function extractAssistantTextFromOutputMessage(content) {
if (!Array.isArray(content)) {
return String(content);
}
const parts = [];
for (const c of content) {
if (c && typeof c === "object") {
const t = c.type;
if (t === "output_text") {
const txt = c.text;
if (typeof txt === "string") {
parts.push(txt);
}
}
else if (t === "refusal") {
const ref = c.refusal;
if (typeof ref === "string") {
parts.push(`[refusal] ${ref}`);
}
}
else {
parts.push(String(c));
}
}
else {
parts.push(String(c));
}
}
return parts.join("");
}
/**
* Helper to summarize an object for logging.
*/
function summarizeObject(obj) {
try {
const typ = obj["type"];
if (typ) {
const entries = Object.entries(obj)
.filter(([k]) => k !== "type")
.map(([k, v]) => `${k}=${JSON.stringify(v)}`)
.join(", ");
return `[${typ}] ${entries}`;
}
}
catch {
// Ignore
}
return String(obj);
}
/**
* Convert OpenAI tool calls to Maxim's format.
*/
function convertToolCalls(toolCalls) {
if (!toolCalls)
return undefined;
return toolCalls.map((tc) => {
// Handle both standard function tool calls and custom tool calls
if ("function" in tc && tc.function) {
return {
id: tc.id,
type: tc.type,
function: {
name: tc.function.name,
arguments: tc.function.arguments,
},
};
}
// Fallback for custom tool calls that may not have function property
return {
id: tc.id,
type: tc.type,
function: {
name: "",
arguments: "",
},
};
});
}
//# sourceMappingURL=utils.js.map