UNPKG

langchain

Version:
1 lines 7.59 kB
{"version":3,"file":"toolEmulator.cjs","names":["options: ToolEmulatorOptions","agentModel: BaseChatModel | undefined","emulatorModel: BaseChatModel | undefined","initChatModel","createMiddleware","HumanMessage","ToolMessage"],"sources":["../../../src/agents/middleware/toolEmulator.ts"],"sourcesContent":["import { HumanMessage, ToolMessage } from \"@langchain/core/messages\";\nimport type { BaseChatModel } from \"@langchain/core/language_models/chat_models\";\nimport type { ClientTool, ServerTool } from \"@langchain/core/tools\";\nimport { initChatModel } from \"../../chat_models/universal.js\";\nimport { createMiddleware } from \"../middleware.js\";\n\n/**\n * Options for configuring the Tool Emulator middleware.\n */\nexport interface ToolEmulatorOptions {\n /**\n * List of tool names (string) or tool instances to emulate.\n * - If `undefined` (default), ALL tools will be emulated.\n * - If empty array, no tools will be emulated.\n * - If array with tool names/instances, only those tools will be emulated.\n */\n tools?: (string | ClientTool | ServerTool)[];\n\n /**\n * Model to use for emulation.\n * - Can be a model identifier string (e.g., \"anthropic:claude-sonnet-4-5-20250929\")\n * - Can be a BaseChatModel instance\n * - Defaults to agent model\n */\n model?: string | BaseChatModel;\n}\n\n/**\n * Middleware that emulates specified tools using an LLM instead of executing them.\n *\n * This middleware allows selective emulation of tools for testing purposes.\n * By default (when `tools` is undefined), all tools are emulated. You can specify\n * which tools to emulate by passing a list of tool names or tool instances.\n *\n * @param options - Configuration options for the middleware\n * @param options.tools - List of tool names or tool instances to emulate. If undefined, all tools are emulated.\n * @param options.model - Model to use for emulation. Defaults to \"anthropic:claude-sonnet-4-5-20250929\".\n *\n * @example Emulate all tools (default behavior)\n * ```ts\n * import { toolEmulatorMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * const middleware = toolEmulatorMiddleware();\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * tools: [getWeather, getUserLocation, calculator],\n * middleware: [middleware],\n * });\n * ```\n *\n * @example Emulate specific tools by name\n * ```ts\n * const middleware = toolEmulatorMiddleware({\n * tools: [\"get_weather\", \"get_user_location\"]\n * });\n * ```\n *\n * @example Use a custom model for emulation\n * ```ts\n * const middleware = toolEmulatorMiddleware({\n * tools: [\"get_weather\"],\n * model: \"anthropic:claude-sonnet-4-5-20250929\"\n * });\n * ```\n *\n * @example Emulate specific tools by passing tool instances\n * ```ts\n * const middleware = toolEmulatorMiddleware({\n * tools: [getWeather, getUserLocation]\n * });\n * ```\n */\nexport function toolEmulatorMiddleware(\n options: ToolEmulatorOptions = {}\n): ReturnType<typeof createMiddleware> {\n let agentModel: BaseChatModel | undefined;\n const { tools, model } = options;\n\n /**\n * Extract tool names from tools\n */\n const emulateAll = !tools || tools.length === 0;\n const toolsToEmulate = new Set<string>();\n\n if (!emulateAll && tools) {\n for (const tool of tools) {\n if (typeof tool === \"string\") {\n toolsToEmulate.add(tool);\n } else {\n // Assume tool instance with .name property\n const toolName =\n typeof tool.name === \"string\" ? tool.name : String(tool.name);\n toolsToEmulate.add(toolName);\n }\n }\n }\n\n /**\n * Initialize emulator model\n * We'll initialize it lazily in wrapToolCall to handle async initChatModel\n */\n let emulatorModel: BaseChatModel | undefined;\n const getEmulatorModel = async (): Promise<BaseChatModel> => {\n if (typeof model === \"object\") {\n return model;\n }\n if (typeof model === \"string\") {\n emulatorModel =\n emulatorModel ??\n (await initChatModel(model, { temperature: 1 }).catch((err) => {\n console.error(\n \"Error initializing emulator model, using agent model:\",\n err\n );\n return agentModel as BaseChatModel;\n }));\n return emulatorModel;\n }\n return agentModel as BaseChatModel;\n };\n\n return createMiddleware({\n name: \"ToolEmulatorMiddleware\",\n wrapModelCall: async (request, handler) => {\n agentModel = request.model as BaseChatModel;\n return handler(request);\n },\n wrapToolCall: async (request, handler) => {\n const toolName = request.toolCall.name;\n\n // Check if this tool should be emulated\n const shouldEmulate = emulateAll || toolsToEmulate.has(toolName);\n\n if (!shouldEmulate) {\n // Let it execute normally by calling the handler\n return handler(request);\n }\n\n // Extract tool information for emulation\n const toolArgs = request.toolCall.args;\n const toolDescription =\n request.tool.description || \"No description available\";\n\n // Build prompt for emulator LLM\n const toolArgsString =\n typeof toolArgs === \"string\" ? toolArgs : JSON.stringify(toolArgs);\n const prompt = `You are emulating a tool call for testing purposes.\n\nTool: ${toolName}\nDescription: ${toolDescription}\nArguments: ${toolArgsString}\n\nGenerate a realistic response that this tool would return given these arguments.\nReturn ONLY the tool's output, no explanation or preamble. Introduce variation into your responses.`;\n\n // Get emulated response from LLM\n const emulator = await getEmulatorModel();\n const response = await emulator.invoke([new HumanMessage(prompt)]);\n\n // Extract content from response\n const content =\n typeof response.content === \"string\"\n ? response.content\n : JSON.stringify(response.content);\n\n // Short-circuit: return emulated result without executing real tool\n return new ToolMessage({\n content,\n tool_call_id: request.toolCall.id ?? \"\",\n name: toolName,\n });\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0EA,SAAgB,uBACdA,UAA+B,CAAE,GACI;CACrC,IAAIC;CACJ,MAAM,EAAE,OAAO,OAAO,GAAG;;;;CAKzB,MAAM,aAAa,CAAC,SAAS,MAAM,WAAW;CAC9C,MAAM,iCAAiB,IAAI;AAE3B,KAAI,CAAC,cAAc,MACjB,MAAK,MAAM,QAAQ,MACjB,KAAI,OAAO,SAAS,UAClB,eAAe,IAAI,KAAK;MACnB;EAEL,MAAM,WACJ,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO,OAAO,KAAK,KAAK;EAC/D,eAAe,IAAI,SAAS;CAC7B;;;;;CAQL,IAAIC;CACJ,MAAM,mBAAmB,YAAoC;AAC3D,MAAI,OAAO,UAAU,SACnB,QAAO;AAET,MAAI,OAAO,UAAU,UAAU;GAC7B,gBACE,iBACC,MAAMC,4CAAc,OAAO,EAAE,aAAa,EAAG,EAAC,CAAC,MAAM,CAAC,QAAQ;IAC7D,QAAQ,MACN,yDACA,IACD;AACD,WAAO;GACR,EAAC;AACJ,UAAO;EACR;AACD,SAAO;CACR;AAED,QAAOC,oCAAiB;EACtB,MAAM;EACN,eAAe,OAAO,SAAS,YAAY;GACzC,aAAa,QAAQ;AACrB,UAAO,QAAQ,QAAQ;EACxB;EACD,cAAc,OAAO,SAAS,YAAY;GACxC,MAAM,WAAW,QAAQ,SAAS;GAGlC,MAAM,gBAAgB,cAAc,eAAe,IAAI,SAAS;AAEhE,OAAI,CAAC,cAEH,QAAO,QAAQ,QAAQ;GAIzB,MAAM,WAAW,QAAQ,SAAS;GAClC,MAAM,kBACJ,QAAQ,KAAK,eAAe;GAG9B,MAAM,iBACJ,OAAO,aAAa,WAAW,WAAW,KAAK,UAAU,SAAS;GACpE,MAAM,SAAS,CAAC;;MAEhB,EAAE,SAAS;aACJ,EAAE,gBAAgB;WACpB,EAAE,eAAe;;;mGAGuE,CAAC;GAG9F,MAAM,WAAW,MAAM,kBAAkB;GACzC,MAAM,WAAW,MAAM,SAAS,OAAO,CAAC,IAAIC,uCAAa,OAAQ,EAAC;GAGlE,MAAM,UACJ,OAAO,SAAS,YAAY,WACxB,SAAS,UACT,KAAK,UAAU,SAAS,QAAQ;AAGtC,UAAO,IAAIC,sCAAY;IACrB;IACA,cAAc,QAAQ,SAAS,MAAM;IACrC,MAAM;GACP;EACF;CACF,EAAC;AACH"}