langchain
Version:
Typescript bindings for langchain
1 lines • 6.36 kB
Source Map (JSON)
{"version":3,"file":"utils.cjs","names":["isLangChainTool","convertToOpenAITool","AIMessage","ToolMessage"],"sources":["../../../src/agents/middleware/utils.ts"],"sourcesContent":["import {\n AIMessage,\n ToolMessage,\n type BaseMessage,\n} from \"@langchain/core/messages\";\nimport { isLangChainTool } from \"@langchain/core/tools\";\nimport { convertToOpenAITool } from \"@langchain/core/utils/function_calling\";\nimport {\n AfterModelHook,\n AfterAgentHook,\n BeforeAgentHook,\n BeforeModelHook,\n} from \"./types.js\";\nimport { JumpToTarget } from \"../constants.js\";\n\n/**\n * Default token counter that approximates based on character count.\n *\n * If tools are provided, the token count also includes stringified tool schemas.\n *\n * @param messages Messages to count tokens for\n * @param tools Optional list of tools to include in the token count. Each tool\n * can be either a LangChain tool instance or a dict representing a tool schema.\n * LangChain tool instances are converted to OpenAI tool format before counting.\n * @returns Approximate token count\n */\nexport function countTokensApproximately(\n messages: BaseMessage[],\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n tools?: Array<Record<string, any>> | null\n): number {\n const charsPerToken = 4;\n let totalChars = 0;\n\n // Count tokens for tools if provided\n if (tools && tools.length > 0) {\n let toolsChars = 0;\n for (const tool of tools) {\n const toolDict = isLangChainTool(tool) ? convertToOpenAITool(tool) : tool;\n toolsChars += JSON.stringify(toolDict).length;\n }\n totalChars += toolsChars;\n }\n\n for (const msg of messages) {\n let textContent: string;\n if (typeof msg.content === \"string\") {\n textContent = msg.content;\n } else if (Array.isArray(msg.content)) {\n textContent = msg.content\n .map((item) => {\n if (typeof item === \"string\") return item;\n if (item.type === \"text\" && \"text\" in item) return item.text;\n return \"\";\n })\n .join(\"\");\n } else {\n textContent = \"\";\n }\n\n if (\n AIMessage.isInstance(msg) &&\n Array.isArray(msg.tool_calls) &&\n msg.tool_calls.length > 0\n ) {\n textContent += JSON.stringify(msg.tool_calls);\n }\n\n if (ToolMessage.isInstance(msg)) {\n textContent += msg.tool_call_id ?? \"\";\n }\n\n totalChars += textContent.length;\n }\n // Approximate 1 token = 4 characters\n return Math.ceil(totalChars / charsPerToken);\n}\n\nexport function getHookConstraint(\n hook:\n | BeforeAgentHook\n | BeforeModelHook\n | AfterAgentHook\n | AfterModelHook\n | undefined\n): JumpToTarget[] | undefined {\n if (!hook || typeof hook === \"function\") {\n return undefined;\n }\n return hook.canJumpTo;\n}\n\nexport function getHookFunction(\n arg: BeforeAgentHook | BeforeModelHook | AfterAgentHook | AfterModelHook\n) {\n if (typeof arg === \"function\") {\n return arg;\n }\n return arg.hook;\n}\n\n/**\n * Sleep for the specified number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay for a retry attempt with exponential backoff and jitter.\n *\n * @param retryNumber - The retry attempt number (0-indexed)\n * @param config - Configuration for backoff calculation\n * @param retryAfterMs - A provider-supplied wait hint, e.g. from a `Retry-After`\n * header. Used as a floor so we never retry sooner than the server asked.\n * @returns Delay in milliseconds before next retry\n *\n * @internal Exported for testing purposes\n */\nexport function calculateRetryDelay(\n config: {\n backoffFactor: number;\n initialDelayMs: number;\n maxDelayMs: number;\n jitter: boolean;\n },\n retryNumber: number,\n retryAfterMs?: number\n): number {\n const { backoffFactor, initialDelayMs, maxDelayMs, jitter } = config;\n\n let delay: number;\n if (backoffFactor === 0.0) {\n delay = initialDelayMs;\n } else {\n delay = initialDelayMs * backoffFactor ** retryNumber;\n }\n\n // Cap at maxDelayMs\n delay = Math.min(delay, maxDelayMs);\n\n if (jitter && delay > 0) {\n const jitterAmount = delay * 0.25;\n delay = delay + (Math.random() * 2 - 1) * jitterAmount;\n // Ensure delay is not negative after jitter\n delay = Math.max(0, delay);\n }\n\n return Math.max(delay, retryAfterMs ?? 0);\n}\n\nexport function getRetryAfterMs(error: unknown): number | undefined {\n if (typeof error !== \"object\" || error === null) {\n return undefined;\n }\n const { retryAfterMs } = error as { retryAfterMs?: unknown };\n return typeof retryAfterMs === \"number\" && retryAfterMs >= 0\n ? retryAfterMs\n : undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;AA0BA,SAAgB,yBACd,UAEA,OACQ;CACR,MAAM,gBAAgB;CACtB,IAAI,aAAa;CAGjB,IAAI,SAAS,MAAM,SAAS,GAAG;EAC7B,IAAI,aAAa;EACjB,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,YAAA,GAAWA,sBAAAA,gBAAAA,CAAgB,IAAI,KAAA,GAAIC,uCAAAA,oBAAAA,CAAoB,IAAI,IAAI;GACrE,cAAc,KAAK,UAAU,QAAQ,CAAC,CAAC;EACzC;EACA,cAAc;CAChB;CAEA,KAAK,MAAM,OAAO,UAAU;EAC1B,IAAI;EACJ,IAAI,OAAO,IAAI,YAAY,UACzB,cAAc,IAAI;OACb,IAAI,MAAM,QAAQ,IAAI,OAAO,GAClC,cAAc,IAAI,QACf,KAAK,SAAS;GACb,IAAI,OAAO,SAAS,UAAU,OAAO;GACrC,IAAI,KAAK,SAAS,UAAU,UAAU,MAAM,OAAO,KAAK;GACxD,OAAO;EACT,CAAC,CAAC,CACD,KAAK,EAAE;OAEV,cAAc;EAGhB,IACEC,yBAAAA,UAAU,WAAW,GAAG,KACxB,MAAM,QAAQ,IAAI,UAAU,KAC5B,IAAI,WAAW,SAAS,GAExB,eAAe,KAAK,UAAU,IAAI,UAAU;EAG9C,IAAIC,yBAAAA,YAAY,WAAW,GAAG,GAC5B,eAAe,IAAI,gBAAgB;EAGrC,cAAc,YAAY;CAC5B;CAEA,OAAO,KAAK,KAAK,aAAa,aAAa;AAC7C;AAEA,SAAgB,kBACd,MAM4B;CAC5B,IAAI,CAAC,QAAQ,OAAO,SAAS,YAC3B;CAEF,OAAO,KAAK;AACd;AAEA,SAAgB,gBACd,KACA;CACA,IAAI,OAAO,QAAQ,YACjB,OAAO;CAET,OAAO,IAAI;AACb;;;;AAKA,SAAgB,MAAM,IAA2B;CAC/C,OAAO,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;;;;;;;;;;;;AAaA,SAAgB,oBACd,QAMA,aACA,cACQ;CACR,MAAM,EAAE,eAAe,gBAAgB,YAAY,WAAW;CAE9D,IAAI;CACJ,IAAI,kBAAkB,GACpB,QAAQ;MAER,QAAQ,iBAAiB,iBAAiB;CAI5C,QAAQ,KAAK,IAAI,OAAO,UAAU;CAElC,IAAI,UAAU,QAAQ,GAAG;EACvB,MAAM,eAAe,QAAQ;EAC7B,QAAQ,SAAS,KAAK,OAAO,IAAI,IAAI,KAAK;EAE1C,QAAQ,KAAK,IAAI,GAAG,KAAK;CAC3B;CAEA,OAAO,KAAK,IAAI,OAAO,gBAAgB,CAAC;AAC1C;AAEA,SAAgB,gBAAgB,OAAoC;CAClE,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC;CAEF,MAAM,EAAE,iBAAiB;CACzB,OAAO,OAAO,iBAAiB,YAAY,gBAAgB,IACvD,eACA,KAAA;AACN"}