UNPKG

langchain

Version:
81 lines (80 loc) 2.99 kB
import { AIMessage, ToolMessage } from "@langchain/core/messages"; import { isLangChainTool } from "@langchain/core/tools"; import { convertToOpenAITool } from "@langchain/core/utils/function_calling"; //#region src/agents/middleware/utils.ts /** * Default token counter that approximates based on character count. * * If tools are provided, the token count also includes stringified tool schemas. * * @param messages Messages to count tokens for * @param tools Optional list of tools to include in the token count. Each tool * can be either a LangChain tool instance or a dict representing a tool schema. * LangChain tool instances are converted to OpenAI tool format before counting. * @returns Approximate token count */ function countTokensApproximately(messages, tools) { const charsPerToken = 4; let totalChars = 0; if (tools && tools.length > 0) { let toolsChars = 0; for (const tool of tools) { const toolDict = isLangChainTool(tool) ? convertToOpenAITool(tool) : tool; toolsChars += JSON.stringify(toolDict).length; } totalChars += toolsChars; } for (const msg of messages) { let textContent; if (typeof msg.content === "string") textContent = msg.content; else if (Array.isArray(msg.content)) textContent = msg.content.map((item) => { if (typeof item === "string") return item; if (item.type === "text" && "text" in item) return item.text; return ""; }).join(""); else textContent = ""; if (AIMessage.isInstance(msg) && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0) textContent += JSON.stringify(msg.tool_calls); if (ToolMessage.isInstance(msg)) textContent += msg.tool_call_id ?? ""; totalChars += textContent.length; } return Math.ceil(totalChars / charsPerToken); } function getHookConstraint(hook) { if (!hook || typeof hook === "function") return; return hook.canJumpTo; } function getHookFunction(arg) { if (typeof arg === "function") return arg; return arg.hook; } /** * Sleep for the specified number of milliseconds. */ function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } /** * Calculate delay for a retry attempt with exponential backoff and jitter. * * @param retryNumber - The retry attempt number (0-indexed) * @param config - Configuration for backoff calculation * @returns Delay in milliseconds before next retry * * @internal Exported for testing purposes */ function calculateRetryDelay(config, retryNumber) { const { backoffFactor, initialDelayMs, maxDelayMs, jitter } = config; let delay; if (backoffFactor === 0) delay = initialDelayMs; else delay = initialDelayMs * backoffFactor ** retryNumber; delay = Math.min(delay, maxDelayMs); if (jitter && delay > 0) { const jitterAmount = delay * .25; delay = delay + (Math.random() * 2 - 1) * jitterAmount; delay = Math.max(0, delay); } return delay; } //#endregion export { calculateRetryDelay, countTokensApproximately, getHookConstraint, getHookFunction, sleep }; //# sourceMappingURL=utils.js.map