@maximai/maxim-js
Version:
Maxim AI JS SDK. Visit https://getmaxim.ai for more info.
360 lines • 20.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertOpenAIResponsesToCompletionResult = convertOpenAIResponsesToCompletionResult;
exports.convertOpenAIResponsesMessagesToCompletionMessages = convertOpenAIResponsesMessagesToCompletionMessages;
const uuid_1 = require("uuid");
/**
* Convert an OpenAI Responses API object (or its `output` array) into a ChatCompletionResult.
*
* Accepts either the full Responses API response shape:
* {
* id, object: "response", created_at, model, output: Item[], usage?: { input_tokens?, output_tokens?, total_tokens? }
* }
* or a bare `output: Item[]` array.
*/
function convertOpenAIResponsesToCompletionResult(input) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18;
const isFullResponse = input && typeof input === "object" && (Array.isArray(input.output) || Array.isArray(input.output_text));
const outputItems = Array.isArray(input) ? input : isFullResponse && Array.isArray(input.output) ? input.output : [];
// Extract assistant text content (concatenate text parts) and tool calls if present
let accumulatedText = [];
let toolCalls = [];
for (const item of outputItems) {
// Responses API typically emits a `message` item containing `content`
if (item && item.type === "message" && Array.isArray(item.content)) {
for (const part of item.content) {
// Common text part shape: { type: 'output_text', text: string }
if (part && typeof part === "object") {
if (typeof part.text === "string") {
accumulatedText.push(part.text);
continue;
}
// Some SDKs may surface plain text as { type: 'text', text }
if (part.type === "text" && typeof part.text === "string") {
accumulatedText.push(part.text);
continue;
}
// Structured outputs may appear as an object; serialize for logging compatibility
if (part.type && part.type.toString().toLowerCase().includes("json")) {
const str = safeStringify((_b = (_a = part.object) !== null && _a !== void 0 ? _a : part.value) !== null && _b !== void 0 ? _b : part);
if (str)
accumulatedText.push(str);
continue;
}
// Tool/function call variants (best-effort support)
if ((part.type === "tool_call" || part.type === "tool-use" || part.type === "tool_use" || part.type === "function_call") &&
(part.name || ((_c = part.function) === null || _c === void 0 ? void 0 : _c.name))) {
const id = part.id || part.tool_call_id || part.call_id || part.callId || (0, uuid_1.v4)();
const name = (_f = (_d = part.name) !== null && _d !== void 0 ? _d : (_e = part.function) === null || _e === void 0 ? void 0 : _e.name) !== null && _f !== void 0 ? _f : "unknown_tool";
const rawArgs = (_k = (_h = (_g = part.arguments) !== null && _g !== void 0 ? _g : part.input) !== null && _h !== void 0 ? _h : (_j = part.function) === null || _j === void 0 ? void 0 : _j.arguments) !== null && _k !== void 0 ? _k : {};
const args = typeof rawArgs === "string" ? rawArgs : (_l = safeStringify(rawArgs)) !== null && _l !== void 0 ? _l : "{}";
toolCalls.push({ id, type: "function", function: { name, arguments: args } });
continue;
}
// Fallback: stringify anything else we don't recognize
const fallback = safeStringify(part);
if (fallback)
accumulatedText.push(fallback);
}
}
}
// Top-level function/tool calls may also be emitted directly in `output`.
// Normalize them into Chat Completions tool_calls for compatibility.
if (item && typeof item === "object") {
// function_call item from Responses API
if (item.type === "function_call" && (item.name || ((_m = item.function) === null || _m === void 0 ? void 0 : _m.name))) {
const id = item.callId || item.call_id || item.id || (0, uuid_1.v4)();
const name = (_q = (_o = item.name) !== null && _o !== void 0 ? _o : (_p = item.function) === null || _p === void 0 ? void 0 : _p.name) !== null && _q !== void 0 ? _q : "unknown_tool";
const rawArgs = (_u = (_s = (_r = item.arguments) !== null && _r !== void 0 ? _r : item.input) !== null && _s !== void 0 ? _s : (_t = item.function) === null || _t === void 0 ? void 0 : _t.arguments) !== null && _u !== void 0 ? _u : {};
const args = typeof rawArgs === "string" ? rawArgs : (_v = safeStringify(rawArgs)) !== null && _v !== void 0 ? _v : "{}";
toolCalls.push({ id, type: "function", function: { name, arguments: args } });
continue;
}
// Hosted/other tool call variants: map best-effort to function style for logging
if ((item.type === "tool_call" || item.type === "hosted_tool_call" || item.type === "tool-use" || item.type === "tool_use") &&
(item.name || ((_w = item.function) === null || _w === void 0 ? void 0 : _w.name))) {
const id = item.id || item.tool_call_id || item.call_id || item.callId || (0, uuid_1.v4)();
const name = (_z = (_x = item.name) !== null && _x !== void 0 ? _x : (_y = item.function) === null || _y === void 0 ? void 0 : _y.name) !== null && _z !== void 0 ? _z : "unknown_tool";
const rawArgs = (_5 = (_3 = (_1 = (_0 = item.arguments) !== null && _0 !== void 0 ? _0 : item.input) !== null && _1 !== void 0 ? _1 : (_2 = item.function) === null || _2 === void 0 ? void 0 : _2.arguments) !== null && _3 !== void 0 ? _3 : (_4 = item.providerData) === null || _4 === void 0 ? void 0 : _4.arguments) !== null && _5 !== void 0 ? _5 : {};
const args = typeof rawArgs === "string" ? rawArgs : (_6 = safeStringify(rawArgs)) !== null && _6 !== void 0 ? _6 : "{}";
toolCalls.push({ id, type: "function", function: { name, arguments: args } });
continue;
}
}
}
const message = {
role: "assistant",
content: accumulatedText.length ? accumulatedText.join("\n\n") : toolCalls.length ? null : "",
...(toolCalls.length ? { tool_calls: toolCalls } : {}),
};
const createdSeconds = isFullResponse && typeof input.created_at === "number" ? input.created_at : Math.floor(Date.now() / 1000);
const model = (isFullResponse && input.model) || "unknown";
const promptTokens = (_10 = (isFullResponse && ((_8 = (_7 = input.usage) === null || _7 === void 0 ? void 0 : _7.input_tokens) !== null && _8 !== void 0 ? _8 : (_9 = input.usage) === null || _9 === void 0 ? void 0 : _9.prompt_tokens))) !== null && _10 !== void 0 ? _10 : 0;
const completionTokens = (_14 = (isFullResponse && ((_12 = (_11 = input.usage) === null || _11 === void 0 ? void 0 : _11.output_tokens) !== null && _12 !== void 0 ? _12 : (_13 = input.usage) === null || _13 === void 0 ? void 0 : _13.completion_tokens))) !== null && _14 !== void 0 ? _14 : 0;
const totalTokens = (_17 = (isFullResponse && ((_16 = (_15 = input.usage) === null || _15 === void 0 ? void 0 : _15.total_tokens) !== null && _16 !== void 0 ? _16 : promptTokens + completionTokens))) !== null && _17 !== void 0 ? _17 : promptTokens + completionTokens;
const completionResult = {
id: (isFullResponse && input.id) || (0, uuid_1.v4)(),
object: "chat_completion",
created: createdSeconds,
model,
choices: [
{
index: 0,
message,
logprobs: null,
finish_reason: (_18 = inferFinishReason(input)) !== null && _18 !== void 0 ? _18 : "stop",
},
],
usage: {
prompt_tokens: promptTokens,
completion_tokens: completionTokens,
total_tokens: totalTokens,
},
};
const modelParameters = extractModelParametersFromResponses(input);
return { completionResult, modelParameters };
}
/**
* Convert an OpenAI Responses API-style messages array into a sequence of
* CompletionRequest / ChatCompletionMessage items compatible with Chat Completions.
*
* Input examples include items like:
* - { type: "message", role: "user" | "system" | "assistant", content: string | Part[] }
* - { type: "function_call" | "tool_call" | "tool-use", name, arguments, callId?, id? }
* - { type: "function_call_result" | "tool_result" | "tool-call-result", callId?, output }
*
* Mapping rules:
* - Consecutive function/tool call items are batched into one assistant message with tool_calls.
* - Each result item becomes a tool message with tool_call_id referring to its originating call.
* - Assistant message content is null when tool_calls are present, otherwise text if available.
*/
function convertOpenAIResponsesMessagesToCompletionMessages(items) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
const results = [];
// Track pending tool calls to batch consecutive calls
let pendingToolCalls = [];
// Map to resolve tool_call_id for results
const callKeyToId = new Map();
const flushPending = () => {
if (pendingToolCalls.length === 0)
return;
results.push({ role: "assistant", content: null, tool_calls: pendingToolCalls });
pendingToolCalls = [];
};
for (const item of items !== null && items !== void 0 ? items : []) {
if (!item || typeof item !== "object")
continue;
const type = String(item.type || "");
// 1) Raw chat message
if (type === "message") {
flushPending();
const role = String(item.role || "user");
let textParts = [];
const prevPendingCount = pendingToolCalls.length;
// Parse message.content for text AND embedded tool/function calls
if (Array.isArray(item.content)) {
for (const part of item.content) {
if (!part || typeof part !== "object") {
const s = safeStringify(part);
if (s)
textParts.push(s);
continue;
}
// Textual segments
if (typeof part.text === "string") {
textParts.push(part.text);
continue;
}
if (typeof part.content === "string") {
textParts.push(part.content);
continue;
}
// Embedded tool/function call variants
if ((part.type === "tool_call" ||
part.type === "tool-use" ||
part.type === "tool_use" ||
part.type === "function_call") &&
(part.name || ((_a = part.function) === null || _a === void 0 ? void 0 : _a.name))) {
const id = part.id || part.tool_call_id || part.call_id || part.callId || (0, uuid_1.v4)();
const name = (_d = (_b = part.name) !== null && _b !== void 0 ? _b : (_c = part.function) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : "unknown_tool";
const rawArgs = (_h = (_f = (_e = part.arguments) !== null && _e !== void 0 ? _e : part.input) !== null && _f !== void 0 ? _f : (_g = part.function) === null || _g === void 0 ? void 0 : _g.arguments) !== null && _h !== void 0 ? _h : {};
const args = typeof rawArgs === "string" ? rawArgs : (_j = safeStringify(rawArgs)) !== null && _j !== void 0 ? _j : "{}";
pendingToolCalls.push({ id, type: "function", function: { name, arguments: args } });
const callKey = String(part.callId || part.call_id || part.id || id);
callKeyToId.set(callKey, id);
continue;
}
// Fallback: stringify structured content
const fallback = safeStringify((_k = part.value) !== null && _k !== void 0 ? _k : part);
if (fallback)
textParts.push(fallback);
}
}
else {
// Non-array content: best-effort stringify or pass through if string
if (typeof item.content === "string") {
textParts.push(item.content);
}
else {
const s = safeStringify(item.content);
if (s)
textParts.push(s);
}
}
const finalText = textParts.join("\n\n");
if (role === "assistant") {
// If this message contributed embedded tool calls, emit them together with remaining text
if (pendingToolCalls.length > prevPendingCount) {
results.push({
role: "assistant",
content: finalText.length ? finalText : null,
tool_calls: pendingToolCalls,
});
pendingToolCalls = [];
}
else {
results.push({ role: "assistant", content: finalText });
}
}
else {
// user | system | tool | function
results.push({ role: role, content: finalText });
}
continue;
}
// 2) Function/tool call variants -> batch into assistant.tool_calls
if (type === "function_call" || type === "tool_call" || type === "hosted_tool_call" || type === "tool-use" || type === "tool_use") {
const id = item.callId || item.call_id || item.id || item.tool_call_id || (0, uuid_1.v4)();
const name = (_o = (_l = item.name) !== null && _l !== void 0 ? _l : (_m = item.function) === null || _m === void 0 ? void 0 : _m.name) !== null && _o !== void 0 ? _o : "unknown_tool";
const rawArgs = (_u = (_s = (_q = (_p = item.arguments) !== null && _p !== void 0 ? _p : item.input) !== null && _q !== void 0 ? _q : (_r = item.function) === null || _r === void 0 ? void 0 : _r.arguments) !== null && _s !== void 0 ? _s : (_t = item.providerData) === null || _t === void 0 ? void 0 : _t.arguments) !== null && _u !== void 0 ? _u : {};
const args = typeof rawArgs === "string" ? rawArgs : (_v = safeStringify(rawArgs)) !== null && _v !== void 0 ? _v : "{}";
pendingToolCalls.push({ id, type: "function", function: { name, arguments: args } });
// Use the most stable key present in result items to map back
const callKey = String(item.callId || item.call_id || item.id || id);
callKeyToId.set(callKey, id);
continue;
}
// 3) Function/tool result variants -> flush calls then add tool message
if (type === "function_call_result" || type === "tool_result" || type === "tool-call-result" || type === "tool_call_result") {
flushPending();
const callKey = String(item.callId || item.call_id || item.tool_call_id || item.id || "");
const mappedId = callKeyToId.get(callKey) || callKey || (0, uuid_1.v4)();
const content = extractTextFromToolOutput(item);
results.push({ role: "tool", content, tool_call_id: mappedId });
continue;
}
// 4) Fallback: unknown objects are stringified as a user message to preserve context
flushPending();
const fallback = (_w = safeStringify(item)) !== null && _w !== void 0 ? _w : "";
if (fallback)
results.push({ role: "user", content: fallback });
}
flushPending();
return results;
}
function safeStringify(value) {
try {
if (typeof value === "string")
return value;
return JSON.stringify(value);
}
catch {
return undefined;
}
}
function inferFinishReason(responseLike) {
if (!responseLike || typeof responseLike !== "object")
return undefined;
// Prefer per-item message status if available
const items = Array.isArray(responseLike.output) ? responseLike.output : [];
const msg = items.find((i) => i && i.type === "message");
if ((msg === null || msg === void 0 ? void 0 : msg.status) === "incomplete")
return "length";
if ((msg === null || msg === void 0 ? void 0 : msg.status) === "completed")
return "stop";
// Fall back to generic
return undefined;
}
function extractModelParametersFromResponses(responseLike) {
var _a;
if (!responseLike || typeof responseLike !== "object")
return {};
// Commonly surfaced parameters (best-effort — Responses API may not echo these back)
const params = {};
const assignIfPresent = (key, value) => {
if (value !== undefined && value !== null)
params[key] = value;
};
// Direct top-level in some SDKs
assignIfPresent("temperature", responseLike.temperature);
assignIfPresent("top_p", responseLike.top_p);
assignIfPresent("max_tokens", (_a = responseLike.max_tokens) !== null && _a !== void 0 ? _a : responseLike.max_output_tokens);
assignIfPresent("presence_penalty", responseLike.presence_penalty);
assignIfPresent("frequency_penalty", responseLike.frequency_penalty);
assignIfPresent("stop", responseLike.stop);
assignIfPresent("seed", responseLike.seed);
assignIfPresent("tool_choice", responseLike.tool_choice);
if (responseLike.tools && Array.isArray(responseLike.tools) && responseLike.tools.length) {
assignIfPresent("tools", responseLike.tools);
}
// Structured outputs: Chat Completions (response_format) vs Responses API (text.format)
if (responseLike.response_format) {
assignIfPresent("response_format", responseLike.response_format);
}
if (responseLike.text && typeof responseLike.text === "object" && responseLike.text.format) {
assignIfPresent("response_format", responseLike.text.format);
}
// Reasoning configs (if present)
if (responseLike.reasoning && typeof responseLike.reasoning === "object") {
assignIfPresent("reasoning", responseLike.reasoning);
}
return params;
}
function extractTextFromMessageContent(content) {
var _a;
if (typeof content === "string")
return content;
if (!content)
return "";
if (Array.isArray(content)) {
const parts = [];
for (const part of content) {
if (!part || typeof part !== "object")
continue;
const anyPart = part;
if (typeof anyPart.text === "string") {
parts.push(anyPart.text);
continue;
}
if (typeof anyPart.content === "string") {
parts.push(anyPart.content);
continue;
}
const s = safeStringify((_a = anyPart.value) !== null && _a !== void 0 ? _a : anyPart);
if (s)
parts.push(s);
}
return parts.join("\n\n");
}
const s = safeStringify(content);
return s !== null && s !== void 0 ? s : "";
}
function extractTextFromToolOutput(item) {
var _a;
if (!item)
return "";
if (typeof item.output === "string")
return item.output;
if (item.output && typeof item.output === "object") {
if (typeof item.output.text === "string")
return item.output.text;
const s = safeStringify((_a = item.output.value) !== null && _a !== void 0 ? _a : item.output);
if (s)
return s;
}
if (typeof item.text === "string")
return item.text;
const s = safeStringify(item);
return s !== null && s !== void 0 ? s : "";
}
//# sourceMappingURL=utils.js.map