@copilotkit/runtime
Version:
<img src="https://github.com/user-attachments/assets/0a6b64d9-e193-4940-a3f6-60334ac34084" alt="banner" style="border-radius: 12px; border: 2px solid #d6d4fa;" />
189 lines (187 loc) • 5.87 kB
JavaScript
import "reflect-metadata";
import { parseJson } from "@copilotkit/shared";
//#region src/service-adapters/openai/utils.ts
/**
* Type guard: checks whether the OpenAI client has the v4-era `beta.chat`
* namespace. Returns `false` for v5+ clients where `beta.chat` was removed.
*/
function hasV4BetaChat(beta) {
return beta != null && "chat" in beta && beta.chat != null;
}
/**
* Detects whether the provided OpenAI client is v5+ by checking for the
* removal of the `beta.chat` namespace (which was promoted to `chat` in v5).
*/
function isOpenAIV5(openai) {
return !hasV4BetaChat(openai.beta);
}
/**
* Returns the chat completions object that supports `.stream()`.
* In v4 this lives under `openai.beta.chat.completions`;
* in v5 it was promoted to `openai.chat.completions`.
*/
function getChatCompletionsForStreaming(openai) {
if (hasV4BetaChat(openai.beta)) return openai.beta.chat.completions;
return openai.chat.completions;
}
/**
* Retrieves a thread run, handling the v4→v5 API signature change.
* v4: retrieve(threadId, runId)
* v5: retrieve(runId, { thread_id: threadId })
*/
async function retrieveThreadRun(openai, threadId, runId) {
if (isOpenAIV5(openai)) {
const retrieve = openai.beta.threads.runs.retrieve;
return retrieve(runId, { thread_id: threadId });
}
return openai.beta.threads.runs.retrieve(threadId, runId);
}
/**
* Submits tool outputs as a stream, handling the v4→v5 API signature change.
* v4: submitToolOutputsStream(threadId, runId, body)
* v5: submitToolOutputsStream(runId, { thread_id, ...body })
*/
function submitToolOutputsStream(openai, threadId, runId, body) {
if (isOpenAIV5(openai)) {
const submit = openai.beta.threads.runs.submitToolOutputsStream;
return submit(runId, {
thread_id: threadId,
...body
});
}
return openai.beta.threads.runs.submitToolOutputsStream(threadId, runId, body);
}
function limitMessagesToTokenCount(messages, tools, model, maxTokens) {
maxTokens ||= maxTokensForOpenAIModel(model);
const result = [];
const toolsNumTokens = countToolsTokens(model, tools);
if (toolsNumTokens > maxTokens) throw new Error(`Too many tokens in function definitions: ${toolsNumTokens} > ${maxTokens}`);
maxTokens -= toolsNumTokens;
for (const message of messages) if (["system", "developer"].includes(message.role)) {
const numTokens = countMessageTokens(model, message);
maxTokens -= numTokens;
if (maxTokens < 0) throw new Error("Not enough tokens for system message.");
}
let cutoff = false;
const reversedMessages = [...messages].toReversed();
for (const message of reversedMessages) {
if (["system", "developer"].includes(message.role)) {
result.unshift(message);
continue;
} else if (cutoff) continue;
let numTokens = countMessageTokens(model, message);
if (maxTokens < numTokens) {
cutoff = true;
continue;
}
result.unshift(message);
maxTokens -= numTokens;
}
return result;
}
function maxTokensForOpenAIModel(model) {
return maxTokensByModel[model] || DEFAULT_MAX_TOKENS;
}
const DEFAULT_MAX_TOKENS = 128e3;
const maxTokensByModel = {
o1: 2e5,
"o1-2024-12-17": 2e5,
"o1-mini": 128e3,
"o1-mini-2024-09-12": 128e3,
"o1-preview": 128e3,
"o1-preview-2024-09-12": 128e3,
"o3-mini": 2e5,
"o3-mini-2025-01-31": 2e5,
"gpt-4o": 128e3,
"chatgpt-4o-latest": 128e3,
"gpt-4o-2024-08-06": 128e3,
"gpt-4o-2024-05-13": 128e3,
"gpt-4o-mini": 128e3,
"gpt-4o-mini-2024-07-18": 128e3,
"gpt-4-turbo": 128e3,
"gpt-4-turbo-2024-04-09": 128e3,
"gpt-4-0125-preview": 128e3,
"gpt-4-turbo-preview": 128e3,
"gpt-4-1106-preview": 128e3,
"gpt-4-vision-preview": 128e3,
"gpt-4-1106-vision-preview": 128e3,
"gpt-4-32k": 32768,
"gpt-4-32k-0613": 32768,
"gpt-4-32k-0314": 32768,
"gpt-4": 8192,
"gpt-4-0613": 8192,
"gpt-4-0314": 8192,
"gpt-3.5-turbo-0125": 16385,
"gpt-3.5-turbo": 16385,
"gpt-3.5-turbo-1106": 16385,
"gpt-3.5-turbo-instruct": 4096,
"gpt-3.5-turbo-16k": 16385,
"gpt-3.5-turbo-0613": 4096,
"gpt-3.5-turbo-16k-0613": 16385,
"gpt-3.5-turbo-0301": 4097
};
function countToolsTokens(model, tools) {
if (tools.length === 0) return 0;
return countTokens(model, JSON.stringify(tools));
}
function countMessageTokens(model, message) {
return countTokens(model, message.content || "");
}
function countTokens(model, text) {
return text.length / 3;
}
function convertActionInputToOpenAITool(action) {
return {
type: "function",
function: {
name: action.name,
description: action.description,
parameters: parseJson(action.jsonSchema, {})
}
};
}
function convertMessageToOpenAIMessage(message, options) {
const { keepSystemRole } = options || { keepSystemRole: false };
if (message.isTextMessage()) {
let role = message.role;
if (message.role === "system" && !keepSystemRole) role = "developer";
return {
role,
content: message.content
};
} else if (message.isImageMessage()) return {
role: "user",
content: [{
type: "image_url",
image_url: { url: `data:image/${message.format};base64,${message.bytes}` }
}]
};
else if (message.isActionExecutionMessage()) return {
role: "assistant",
tool_calls: [{
id: message.id,
type: "function",
function: {
name: message.name,
arguments: JSON.stringify(message.arguments)
}
}]
};
else if (message.isResultMessage()) return {
role: "tool",
content: message.result,
tool_call_id: message.actionExecutionId
};
}
function convertSystemMessageToAssistantAPI(message) {
return {
...message,
...["system", "developer"].includes(message.role) && {
role: "assistant",
content: "THE FOLLOWING MESSAGE IS A SYSTEM MESSAGE: " + message.content
}
};
}
//#endregion
export { convertActionInputToOpenAITool, convertMessageToOpenAIMessage, convertSystemMessageToAssistantAPI, getChatCompletionsForStreaming, limitMessagesToTokenCount, retrieveThreadRun, submitToolOutputsStream };
//# sourceMappingURL=utils.mjs.map