UNPKG

@langchain/langgraph

Version:

LangGraph

1 lines 7.8 kB
{"version":3,"file":"chat_agent_executor.cjs","names":["toolExecutor: ToolExecutor","toolClasses: Array<StructuredToolInterface | RunnableToolLike>","ToolExecutor","FunctionMessage","schema: StateGraphArgs<FunctionCallingExecutorState>[\"channels\"]","StateGraph","RunnableLambda","START","END"],"sources":["../../src/prebuilt/chat_agent_executor.ts"],"sourcesContent":["import { StructuredToolInterface } from \"@langchain/core/tools\";\nimport { convertToOpenAIFunction } from \"@langchain/core/utils/function_calling\";\nimport { AgentAction } from \"@langchain/core/agents\";\nimport { FunctionMessage, BaseMessage } from \"@langchain/core/messages\";\nimport {\n type RunnableConfig,\n RunnableLambda,\n RunnableToolLike,\n} from \"@langchain/core/runnables\";\nimport { ToolExecutor } from \"./tool_executor.js\";\nimport {\n CompiledStateGraph,\n StateGraph,\n StateGraphArgs,\n} from \"../graph/state.js\";\nimport { END, START } from \"../constants.js\";\n\n/** @deprecated Use {@link createReactAgent} instead with tool calling. */\nexport type FunctionCallingExecutorState = { messages: Array<BaseMessage> };\n\n/** @deprecated Use {@link createReactAgent} instead with tool calling. */\nexport function createFunctionCallingExecutor<Model extends object>({\n model,\n tools,\n}: {\n model: Model;\n tools: Array<StructuredToolInterface | RunnableToolLike> | ToolExecutor;\n}): CompiledStateGraph<\n FunctionCallingExecutorState,\n Partial<FunctionCallingExecutorState>,\n typeof START | \"agent\" | \"action\"\n> {\n let toolExecutor: ToolExecutor;\n let toolClasses: Array<StructuredToolInterface | RunnableToolLike>;\n if (!Array.isArray(tools)) {\n toolExecutor = tools;\n toolClasses = tools.tools;\n } else {\n toolExecutor = new ToolExecutor({\n tools,\n });\n toolClasses = tools;\n }\n\n if (!(\"bind\" in model) || typeof model.bind !== \"function\") {\n throw new Error(\"Model must be bindable\");\n }\n const toolsAsOpenAIFunctions = toolClasses.map((tool) =>\n convertToOpenAIFunction(tool)\n );\n const newModel = model.bind({\n functions: toolsAsOpenAIFunctions,\n });\n\n // Define the function that determines whether to continue or not\n const shouldContinue = (state: FunctionCallingExecutorState) => {\n const { messages } = state;\n const lastMessage = messages[messages.length - 1];\n // If there is no function call, then we finish\n if (\n !(\"function_call\" in lastMessage.additional_kwargs) ||\n !lastMessage.additional_kwargs.function_call\n ) {\n return \"end\";\n }\n // Otherwise if there is, we continue\n return \"continue\";\n };\n\n // Define the function that calls the model\n const callModel = async (\n state: FunctionCallingExecutorState,\n config?: RunnableConfig\n ) => {\n const { messages } = state;\n const response = await newModel.invoke(messages, config);\n // We return a list, because this will get added to the existing list\n return {\n messages: [response],\n };\n };\n\n // Define the function to execute tools\n const _getAction = (state: FunctionCallingExecutorState): AgentAction => {\n const { messages } = state;\n // Based on the continue condition\n // we know the last message involves a function call\n const lastMessage = messages[messages.length - 1];\n if (!lastMessage) {\n throw new Error(\"No messages found.\");\n }\n if (!lastMessage.additional_kwargs.function_call) {\n throw new Error(\"No function call found in message.\");\n }\n // We construct an AgentAction from the function_call\n return {\n tool: lastMessage.additional_kwargs.function_call.name,\n toolInput: JSON.stringify(\n lastMessage.additional_kwargs.function_call.arguments\n ),\n log: \"\",\n };\n };\n\n const callTool = async (\n state: FunctionCallingExecutorState,\n config?: RunnableConfig\n ) => {\n const action = _getAction(state);\n // We call the tool_executor and get back a response\n const response = await toolExecutor.invoke(action, config);\n // We use the response to create a FunctionMessage\n const functionMessage = new FunctionMessage({\n content: response,\n name: action.tool,\n });\n // We return a list, because this will get added to the existing list\n return { messages: [functionMessage] };\n };\n\n // We create the AgentState that we will pass around\n // This simply involves a list of messages\n // We want steps to return messages to append to the list\n // So we annotate the messages attribute with operator.add\n const schema: StateGraphArgs<FunctionCallingExecutorState>[\"channels\"] = {\n messages: {\n value: (x: BaseMessage[], y: BaseMessage[]) => x.concat(y),\n default: () => [],\n },\n };\n\n // Define a new graph\n const workflow = new StateGraph<FunctionCallingExecutorState>({\n channels: schema,\n })\n // Define the two nodes we will cycle between\n .addNode(\"agent\", new RunnableLambda({ func: callModel }))\n .addNode(\"action\", new RunnableLambda({ func: callTool }))\n // Set the entrypoint as `agent`\n // This means that this node is the first one called\n .addEdge(START, \"agent\")\n // We now add a conditional edge\n .addConditionalEdges(\n // First, we define the start node. We use `agent`.\n // This means these are the edges taken after the `agent` node is called.\n \"agent\",\n // Next, we pass in the function that will determine which node is called next.\n shouldContinue,\n // Finally we pass in a mapping.\n // The keys are strings, and the values are other nodes.\n // END is a special node marking that the graph should finish.\n // What will happen is we will call `should_continue`, and then the output of that\n // will be matched against the keys in this mapping.\n // Based on which one it matches, that node will then be called.\n {\n // If `tools`, then we call the tool node.\n continue: \"action\",\n // Otherwise we finish.\n end: END,\n }\n )\n // We now add a normal edge from `tools` to `agent`.\n // This means that after `tools` is called, `agent` node is called next.\n .addEdge(\"action\", \"agent\");\n\n // Finally, we compile it!\n // This compiles it into a LangChain Runnable,\n // meaning you can use it as you would any other runnable\n return workflow.compile();\n}\n"],"mappings":";;;;;;;;;;AAqBA,SAAgB,8BAAoD,EAClE,OACA,SAQA;CACA,IAAIA;CACJ,IAAIC;AACJ,KAAI,CAAC,MAAM,QAAQ,QAAQ;AACzB,iBAAe;AACf,gBAAc,MAAM;QACf;AACL,iBAAe,IAAIC,mCAAa,EAC9B;AAEF,gBAAc;;AAGhB,KAAI,EAAE,UAAU,UAAU,OAAO,MAAM,SAAS,WAC9C,OAAM,IAAI,MAAM;CAElB,MAAM,yBAAyB,YAAY,KAAK,8EACtB;CAE1B,MAAM,WAAW,MAAM,KAAK,EAC1B,WAAW;CAIb,MAAM,kBAAkB,UAAwC;EAC9D,MAAM,EAAE,aAAa;EACrB,MAAM,cAAc,SAAS,SAAS,SAAS;AAE/C,MACE,EAAE,mBAAmB,YAAY,sBACjC,CAAC,YAAY,kBAAkB,cAE/B,QAAO;AAGT,SAAO;;CAIT,MAAM,YAAY,OAChB,OACA,WACG;EACH,MAAM,EAAE,aAAa;EACrB,MAAM,WAAW,MAAM,SAAS,OAAO,UAAU;AAEjD,SAAO,EACL,UAAU,CAAC;;CAKf,MAAM,cAAc,UAAqD;EACvE,MAAM,EAAE,aAAa;EAGrB,MAAM,cAAc,SAAS,SAAS,SAAS;AAC/C,MAAI,CAAC,YACH,OAAM,IAAI,MAAM;AAElB,MAAI,CAAC,YAAY,kBAAkB,cACjC,OAAM,IAAI,MAAM;AAGlB,SAAO;GACL,MAAM,YAAY,kBAAkB,cAAc;GAClD,WAAW,KAAK,UACd,YAAY,kBAAkB,cAAc;GAE9C,KAAK;;;CAIT,MAAM,WAAW,OACf,OACA,WACG;EACH,MAAM,SAAS,WAAW;EAE1B,MAAM,WAAW,MAAM,aAAa,OAAO,QAAQ;EAEnD,MAAM,kBAAkB,IAAIC,0CAAgB;GAC1C,SAAS;GACT,MAAM,OAAO;;AAGf,SAAO,EAAE,UAAU,CAAC;;CAOtB,MAAMC,SAAmE,EACvE,UAAU;EACR,QAAQ,GAAkB,MAAqB,EAAE,OAAO;EACxD,eAAe;;CAKnB,MAAM,WAAW,IAAIC,yBAAyC,EAC5D,UAAU,UAGT,QAAQ,SAAS,IAAIC,0CAAe,EAAE,MAAM,cAC5C,QAAQ,UAAU,IAAIA,0CAAe,EAAE,MAAM,aAG7C,QAAQC,yBAAO,SAEf,oBAGC,SAEA,gBAOA;EAEE,UAAU;EAEV,KAAKC;IAKR,QAAQ,UAAU;AAKrB,QAAO,SAAS"}