createReactAgent doesn't bind tools when using function-based LLM provider #342

Closed
opened 2026-02-15 18:16:02 -05:00 by yindo · 1 comment
Owner

Originally created by @Wazbat on GitHub (Aug 19, 2025).

Checked other resources

  • I added a very descriptive title to this issue.
  • I searched the LangGraph.js documentation with the integrated search.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangGraph.js rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangGraph (or the specific integration package).

Example Code

import { createReactAgent } from '@langchain/langgraph/prebuilt';
import { ChatOpenAI } from '@langchain/openai';
import { tool } from '@langchain/core/tools';

// Simple test tool
const testTool = tool(
async () => "test result",
  {
    name: "test_tool",
    description: "A test tool"
});

// This WORKS - tools are bound correctly
const workingAgent = createReactAgent({
  llm: new ChatGoogle({ model: "gemini-2.5-flash" }), // Static LLM instance
  tools: [testTool],
});

// This FAILS - tools are NOT bound
const brokenAgent = createReactAgent({
  llm: async (_state, _runtime) => {
    return new ChatGoogle({ model: "gemini-2.5-flash" }); // Function returning LLM
  },
  tools: [testTool],
});

// When you invoke brokenAgent, it will either generate an empty response due to "UNEXPECTED_TOOL_CALL" (leading to an internal cannot read x of undefined error), or not try to call the tools at all because the LLM returned by the function doesn't have tools bound to it

Error Message and Stack Trace (if applicable)

No response

Description

Problem: When using createReactAgent with a function-based LLM provider (where llm is a function that returns a language model), the tools are not automatically bound to the returned LLM instance. This causes the agent to fail when trying to use tools.

Expected Behavior: Tools should be automatically bound to the LLM regardless of whether it's provided as a static instance or via a function.

Current Behavior:
When using a static LLM: Tools are bound correctly via _getStaticModel() which calls _shouldBindTools() and _bindTools()
When using a Function-based LLM: Tools are NOT bound because _getDynamicModel() skips the tool binding logic entirely
Root Cause:
In the React Agent Executor code, _getDynamicModel() only pipes the model through prompt handling but completely bypasses the tool binding logic that _getStaticModel() performs.
Current Workaround:
Manually bind tools in the function, as well as providing them to the react agent:

llm: async (_state, _runtime) => {
  const model = new ChatGoogle({ model: "gemini-2.5-flash" });
  return model.bindTools([testTool]); // Manual binding required
}

System Info

Node version: v22.12.0
Operating system: win32 x64
Package manager: npm
Package manager version: N/A
--------------------
@langchain/core -> @0.3.71, , @"^0.3.71", @">=0.3.58, @">=0.2.31, @"^0.3.40"
langsmith -> @0.3.61, , @"^0.3.46"
zod -> @3.25.76, , @"^3.25.76", @"^3.25.32", @"^3.23.8", @">=3.25.67", @5.0.3, @"^5.0.3", @"^3.24.1"
@langchain/google-gauth -> @0.2.16, , @"^0.2.16"
@langchain/google-common -> @0.2.16, , @"^0.2.16"
@langchain/langgraph-swarm -> @0.0.6, , @"^0.0.6"
@langchain/langgraph -> @0.4.5, , @"^0.4.5", @"^0.2.53
@langchain/langgraph-checkpoint -> @0.1.0, , @"^0.1.0"
@langchain/langgraph-sdk -> @0.0.107, , @"~0.0.107"
Originally created by @Wazbat on GitHub (Aug 19, 2025). ### Checked other resources - [x] I added a very descriptive title to this issue. - [x] I searched the LangGraph.js documentation with the integrated search. - [x] I used the GitHub search to find a similar question and didn't find it. - [x] I am sure that this is a bug in LangGraph.js rather than my code. - [x] The bug is not resolved by updating to the latest stable version of LangGraph (or the specific integration package). ### Example Code ```typescript import { createReactAgent } from '@langchain/langgraph/prebuilt'; import { ChatOpenAI } from '@langchain/openai'; import { tool } from '@langchain/core/tools'; // Simple test tool const testTool = tool( async () => "test result", { name: "test_tool", description: "A test tool" }); // This WORKS - tools are bound correctly const workingAgent = createReactAgent({ llm: new ChatGoogle({ model: "gemini-2.5-flash" }), // Static LLM instance tools: [testTool], }); // This FAILS - tools are NOT bound const brokenAgent = createReactAgent({ llm: async (_state, _runtime) => { return new ChatGoogle({ model: "gemini-2.5-flash" }); // Function returning LLM }, tools: [testTool], }); // When you invoke brokenAgent, it will either generate an empty response due to "UNEXPECTED_TOOL_CALL" (leading to an internal cannot read x of undefined error), or not try to call the tools at all because the LLM returned by the function doesn't have tools bound to it ``` ### Error Message and Stack Trace (if applicable) _No response_ ### Description **Problem:** When using createReactAgent with a function-based LLM provider (where llm is a function that returns a language model), the tools are not automatically bound to the returned LLM instance. This causes the agent to fail when trying to use tools. **Expected Behavior:** Tools should be automatically bound to the LLM regardless of whether it's provided as a static instance or via a function. **Current Behavior:** When using a static LLM: Tools are bound correctly via _getStaticModel() which calls _shouldBindTools() and _bindTools() When using a Function-based LLM: Tools are NOT bound because _getDynamicModel() skips the tool binding logic entirely **Root Cause:** In the React Agent Executor code, _getDynamicModel() only pipes the model through prompt handling but completely bypasses the tool binding logic that _getStaticModel() performs. **Current Workaround:** Manually bind tools in the function, as well as providing them to the react agent: ```typescript llm: async (_state, _runtime) => { const model = new ChatGoogle({ model: "gemini-2.5-flash" }); return model.bindTools([testTool]); // Manual binding required } ``` ### System Info ``` Node version: v22.12.0 Operating system: win32 x64 Package manager: npm Package manager version: N/A -------------------- @langchain/core -> @0.3.71, , @"^0.3.71", @">=0.3.58, @">=0.2.31, @"^0.3.40" langsmith -> @0.3.61, , @"^0.3.46" zod -> @3.25.76, , @"^3.25.76", @"^3.25.32", @"^3.23.8", @">=3.25.67", @5.0.3, @"^5.0.3", @"^3.24.1" @langchain/google-gauth -> @0.2.16, , @"^0.2.16" @langchain/google-common -> @0.2.16, , @"^0.2.16" @langchain/langgraph-swarm -> @0.0.6, , @"^0.0.6" @langchain/langgraph -> @0.4.5, , @"^0.4.5", @"^0.2.53 @langchain/langgraph-checkpoint -> @0.1.0, , @"^0.1.0" @langchain/langgraph-sdk -> @0.0.107, , @"~0.0.107" ```
yindo closed this issue 2026-02-15 18:16:02 -05:00
Author
Owner

@dqbd commented on GitHub (Sep 9, 2025):

Hello! This is the expected behaviour for dynamic LLM models. If you are only dealing with a single model, provide the model directly without wrapping it in a function, otherwise the workaround should suffice here.

@dqbd commented on GitHub (Sep 9, 2025): Hello! This is the expected behaviour for dynamic LLM models. If you are only dealing with a single model, provide the model directly without wrapping it in a function, otherwise the workaround should suffice here.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraphjs#342