Inner workers not invoked in supervisor of supervisors pattern #345

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

Originally created by @hitmands on GitHub (Aug 22, 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

Given The following Code:

/* eslint-disable no-console */
import { DynamicTool } from "@langchain/core/tools";
import { MemorySaver } from "@langchain/langgraph-checkpoint";
import { createSupervisor } from "@langchain/langgraph-supervisor";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import {
  AzureChatOpenAI,
} from '@langchain/openai';

const checkpointer = new MemorySaver();

const model = new AzureChatOpenAI({
  modelName: "gpt-4",
  temperature: 0,
  azureOpenAIApiVersion: "2024-10-21",
  azureOpenAIApiDeploymentName: "gpt-4.1",
  azureOpenAIApiInstanceName: "xyz",
  azureOpenAIApiKey: "XYZ"
});

const addition = new DynamicTool({
  name: "addition",
  description: "Add two numbers",
  func: async (input) => `Sum of two numbers: ${input}`,
});

const math = createReactAgent({
  name: "math",
  llm: model,
  tools: [addition],
  systemMessage: "You are a Math Agent, use the tool to sum two numbers",
});

const school = createSupervisor({
  llm: model,
  agents: [ math ],
  prompt: "You are a School Principal, choose which agent to use based on the task. Do not do the task yourself.",
  outputMode: "full_history",
  includeAgentName: "inline",
  handoffBackMessages: true,
  supervisorName: "school_supervisor"
}).compile({ checkpointer: true, name: "school" });

export const mainSupervisor = createSupervisor({
  llm: model,
  agents: [school],
  prompt: "You are the main supervisor. Assign the task to the appropriate agent. Do not do the task yourself.",
  handoffBackMessages: true,
  outputMode: "full_history",
  includeAgentName: "inline",
  supervisorName: "top_level_supervisor"
});

const graph = mainSupervisor.compile({ checkpointer, name: "top_level" });

const runExample = async () => {
  const tasks = [
    "What is it 2 + 2?",
  ];

  const config = {
    configurable: {
      thread_id: 'test'
    }
  };

  for (const task of tasks) {
    const result = await graph.invoke({
      messages: [{ role: "user", content: task }]
    }, config);

    console.log(`${JSON.stringify(result, null, 2)}\n`);
  }
};

runExample().catch(console.error);

Error Message and Stack Trace (if applicable)

No response

Description

Expected:

School supervisor to invoke Math Agent

GIVEN

School supervisor identifies the correct agent, no invocation happens

System Info

{
  "messages": [
    {
      "lc": 1,
      "type": "constructor",
      "id": [
        "langchain_core",
        "messages",
        "HumanMessage"
      ],
      "kwargs": {
        "content": "What is it 2 + 2?",
        "additional_kwargs": {},
        "response_metadata": {},
        "id": "e8bf7310-2c26-4040-bd6c-469b86f7adc5"
      }
    },
    {
      "lc": 1,
      "type": "constructor",
      "id": [
        "langchain_core",
        "messages",
        "AIMessage"
      ],
      "kwargs": {
        "content": "",
        "name": "top_level_supervisor",
        "additional_kwargs": {
          "tool_calls": [
            {
              "function": {
                "arguments": "{}",
                "name": "transfer_to_school"
              },
              "id": "call_CqUDeiRLLU9NGsikoRcQyU7z",
              "type": "function"
            }
          ]
        },
        "response_metadata": {
          "tokenUsage": {
            "promptTokens": 68,
            "completionTokens": 12,
            "totalTokens": 80
          },
          "finish_reason": "tool_calls",
          "model_name": "gpt-4.1-2025-04-14",
          "usage": {
            "completion_tokens": 12,
            "completion_tokens_details": {
              "accepted_prediction_tokens": 0,
              "audio_tokens": 0,
              "reasoning_tokens": 0,
              "rejected_prediction_tokens": 0
            },
            "prompt_tokens": 68,
            "prompt_tokens_details": {
              "audio_tokens": 0,
              "cached_tokens": 0
            },
            "total_tokens": 80
          },
          "system_fingerprint": "fp_c79ab13e31"
        },
        "id": "chatcmpl-C7Ip3PQb7NIy1OJHsdhgZjjQVB5Z2",
        "tool_calls": [
          {
            "name": "transfer_to_school",
            "args": {},
            "type": "tool_call",
            "id": "call_CqUDeiRLLU9NGsikoRcQyU7z"
          }
        ],
        "invalid_tool_calls": [],
        "usage_metadata": {
          "output_tokens": 12,
          "input_tokens": 68,
          "total_tokens": 80,
          "input_token_details": {
            "audio": 0,
            "cache_read": 0
          },
          "output_token_details": {
            "audio": 0,
            "reasoning": 0
          }
        }
      }
    },
    {
      "lc": 1,
      "type": "constructor",
      "id": [
        "langchain_core",
        "messages",
        "ToolMessage"
      ],
      "kwargs": {
        "content": "Successfully transferred to school",
        "name": "transfer_to_school",
        "tool_call_id": "call_CqUDeiRLLU9NGsikoRcQyU7z",
        "additional_kwargs": {},
        "response_metadata": {},
        "id": "cbab76f7-0e03-4d54-acda-afd54b3af790"
      }
    },
    {
      "lc": 1,
      "type": "constructor",
      "id": [
        "langchain_core",
        "messages",
        "AIMessage"
      ],
      "kwargs": {
        "content": "For math-related questions like \"What is 2 + 2?\", I will refer this to the Math agent for an accurate response.",
        "name": "school_supervisor",
        "additional_kwargs": {},
        "response_metadata": {
          "tokenUsage": {
            "promptTokens": 94,
            "completionTokens": 29,
            "totalTokens": 123
          },
          "finish_reason": "stop",
          "model_name": "gpt-4.1-2025-04-14",
          "usage": {
            "completion_tokens": 29,
            "completion_tokens_details": {
              "accepted_prediction_tokens": 0,
              "audio_tokens": 0,
              "reasoning_tokens": 0,
              "rejected_prediction_tokens": 0
            },
            "prompt_tokens": 94,
            "prompt_tokens_details": {
              "audio_tokens": 0,
              "cached_tokens": 0
            },
            "total_tokens": 123
          },
          "system_fingerprint": "fp_c79ab13e31"
        },
        "id": "chatcmpl-C7Ip4WlJPmOyUXADLRi7DkERQB8xY",
        "tool_calls": [],
        "invalid_tool_calls": [],
        "usage_metadata": {
          "output_tokens": 29,
          "input_tokens": 94,
          "total_tokens": 123,
          "input_token_details": {
            "audio": 0,
            "cache_read": 0
          },
          "output_token_details": {
            "audio": 0,
            "reasoning": 0
          }
        }
      }
    },
    {
      "lc": 1,
      "type": "constructor",
      "id": [
        "langchain_core",
        "messages",
        "AIMessage"
      ],
      "kwargs": {
        "content": "Transferring back to top_level_supervisor",
        "tool_calls": [
          {
            "name": "transfer_back_to_top_level_supervisor",
            "args": {},
            "id": "0c944a86-5f4e-4249-9693-ba1b2588d6d5"
          }
        ],
        "name": "school",
        "invalid_tool_calls": [],
        "additional_kwargs": {},
        "response_metadata": {},
        "id": "fd7f762c-4ed6-47d3-925a-9192b3e75dba"
      }
    },
    {
      "lc": 1,
      "type": "constructor",
      "id": [
        "langchain_core",
        "messages",
        "ToolMessage"
      ],
      "kwargs": {
        "content": "Successfully transferred back to top_level_supervisor",
        "name": "transfer_back_to_top_level_supervisor",
        "tool_call_id": "0c944a86-5f4e-4249-9693-ba1b2588d6d5",
        "additional_kwargs": {},
        "response_metadata": {},
        "id": "e67c9969-fb67-4d20-90ed-144723bf8c6d"
      }
    },
    {
      "lc": 1,
      "type": "constructor",
      "id": [
        "langchain_core",
        "messages",
        "AIMessage"
      ],
      "kwargs": {
        "content": "The task of answering \"What is 2 + 2?\" has been assigned to the appropriate agent in the school department. They will provide the correct answer.",
        "name": "top_level_supervisor",
        "additional_kwargs": {},
        "response_metadata": {
          "tokenUsage": {
            "promptTokens": 172,
            "completionTokens": 34,
            "totalTokens": 206
          },
          "finish_reason": "stop",
          "model_name": "gpt-4.1-2025-04-14",
          "usage": {
            "completion_tokens": 34,
            "completion_tokens_details": {
              "accepted_prediction_tokens": 0,
              "audio_tokens": 0,
              "reasoning_tokens": 0,
              "rejected_prediction_tokens": 0
            },
            "prompt_tokens": 172,
            "prompt_tokens_details": {
              "audio_tokens": 0,
              "cached_tokens": 0
            },
            "total_tokens": 206
          },
          "system_fingerprint": "fp_c79ab13e31"
        },
        "id": "chatcmpl-C7Ip5UwCWVUrP2OVqotjuCjtCLebx",
        "tool_calls": [],
        "invalid_tool_calls": [],
        "usage_metadata": {
          "output_tokens": 34,
          "input_tokens": 172,
          "total_tokens": 206,
          "input_token_details": {
            "audio": 0,
            "cache_read": 0
          },
          "output_token_details": {
            "audio": 0,
            "reasoning": 0
          }
        }
      }
    }
  ]
}
Originally created by @hitmands on GitHub (Aug 22, 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 Given The following Code: ```mjs /* eslint-disable no-console */ import { DynamicTool } from "@langchain/core/tools"; import { MemorySaver } from "@langchain/langgraph-checkpoint"; import { createSupervisor } from "@langchain/langgraph-supervisor"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { AzureChatOpenAI, } from '@langchain/openai'; const checkpointer = new MemorySaver(); const model = new AzureChatOpenAI({ modelName: "gpt-4", temperature: 0, azureOpenAIApiVersion: "2024-10-21", azureOpenAIApiDeploymentName: "gpt-4.1", azureOpenAIApiInstanceName: "xyz", azureOpenAIApiKey: "XYZ" }); const addition = new DynamicTool({ name: "addition", description: "Add two numbers", func: async (input) => `Sum of two numbers: ${input}`, }); const math = createReactAgent({ name: "math", llm: model, tools: [addition], systemMessage: "You are a Math Agent, use the tool to sum two numbers", }); const school = createSupervisor({ llm: model, agents: [ math ], prompt: "You are a School Principal, choose which agent to use based on the task. Do not do the task yourself.", outputMode: "full_history", includeAgentName: "inline", handoffBackMessages: true, supervisorName: "school_supervisor" }).compile({ checkpointer: true, name: "school" }); export const mainSupervisor = createSupervisor({ llm: model, agents: [school], prompt: "You are the main supervisor. Assign the task to the appropriate agent. Do not do the task yourself.", handoffBackMessages: true, outputMode: "full_history", includeAgentName: "inline", supervisorName: "top_level_supervisor" }); const graph = mainSupervisor.compile({ checkpointer, name: "top_level" }); const runExample = async () => { const tasks = [ "What is it 2 + 2?", ]; const config = { configurable: { thread_id: 'test' } }; for (const task of tasks) { const result = await graph.invoke({ messages: [{ role: "user", content: task }] }, config); console.log(`${JSON.stringify(result, null, 2)}\n`); } }; runExample().catch(console.error); ``` ### Error Message and Stack Trace (if applicable) _No response_ ### Description **Expected:** School supervisor to invoke `Math` Agent **GIVEN** School supervisor identifies the correct agent, no invocation happens ### System Info ```json { "messages": [ { "lc": 1, "type": "constructor", "id": [ "langchain_core", "messages", "HumanMessage" ], "kwargs": { "content": "What is it 2 + 2?", "additional_kwargs": {}, "response_metadata": {}, "id": "e8bf7310-2c26-4040-bd6c-469b86f7adc5" } }, { "lc": 1, "type": "constructor", "id": [ "langchain_core", "messages", "AIMessage" ], "kwargs": { "content": "", "name": "top_level_supervisor", "additional_kwargs": { "tool_calls": [ { "function": { "arguments": "{}", "name": "transfer_to_school" }, "id": "call_CqUDeiRLLU9NGsikoRcQyU7z", "type": "function" } ] }, "response_metadata": { "tokenUsage": { "promptTokens": 68, "completionTokens": 12, "totalTokens": 80 }, "finish_reason": "tool_calls", "model_name": "gpt-4.1-2025-04-14", "usage": { "completion_tokens": 12, "completion_tokens_details": { "accepted_prediction_tokens": 0, "audio_tokens": 0, "reasoning_tokens": 0, "rejected_prediction_tokens": 0 }, "prompt_tokens": 68, "prompt_tokens_details": { "audio_tokens": 0, "cached_tokens": 0 }, "total_tokens": 80 }, "system_fingerprint": "fp_c79ab13e31" }, "id": "chatcmpl-C7Ip3PQb7NIy1OJHsdhgZjjQVB5Z2", "tool_calls": [ { "name": "transfer_to_school", "args": {}, "type": "tool_call", "id": "call_CqUDeiRLLU9NGsikoRcQyU7z" } ], "invalid_tool_calls": [], "usage_metadata": { "output_tokens": 12, "input_tokens": 68, "total_tokens": 80, "input_token_details": { "audio": 0, "cache_read": 0 }, "output_token_details": { "audio": 0, "reasoning": 0 } } } }, { "lc": 1, "type": "constructor", "id": [ "langchain_core", "messages", "ToolMessage" ], "kwargs": { "content": "Successfully transferred to school", "name": "transfer_to_school", "tool_call_id": "call_CqUDeiRLLU9NGsikoRcQyU7z", "additional_kwargs": {}, "response_metadata": {}, "id": "cbab76f7-0e03-4d54-acda-afd54b3af790" } }, { "lc": 1, "type": "constructor", "id": [ "langchain_core", "messages", "AIMessage" ], "kwargs": { "content": "For math-related questions like \"What is 2 + 2?\", I will refer this to the Math agent for an accurate response.", "name": "school_supervisor", "additional_kwargs": {}, "response_metadata": { "tokenUsage": { "promptTokens": 94, "completionTokens": 29, "totalTokens": 123 }, "finish_reason": "stop", "model_name": "gpt-4.1-2025-04-14", "usage": { "completion_tokens": 29, "completion_tokens_details": { "accepted_prediction_tokens": 0, "audio_tokens": 0, "reasoning_tokens": 0, "rejected_prediction_tokens": 0 }, "prompt_tokens": 94, "prompt_tokens_details": { "audio_tokens": 0, "cached_tokens": 0 }, "total_tokens": 123 }, "system_fingerprint": "fp_c79ab13e31" }, "id": "chatcmpl-C7Ip4WlJPmOyUXADLRi7DkERQB8xY", "tool_calls": [], "invalid_tool_calls": [], "usage_metadata": { "output_tokens": 29, "input_tokens": 94, "total_tokens": 123, "input_token_details": { "audio": 0, "cache_read": 0 }, "output_token_details": { "audio": 0, "reasoning": 0 } } } }, { "lc": 1, "type": "constructor", "id": [ "langchain_core", "messages", "AIMessage" ], "kwargs": { "content": "Transferring back to top_level_supervisor", "tool_calls": [ { "name": "transfer_back_to_top_level_supervisor", "args": {}, "id": "0c944a86-5f4e-4249-9693-ba1b2588d6d5" } ], "name": "school", "invalid_tool_calls": [], "additional_kwargs": {}, "response_metadata": {}, "id": "fd7f762c-4ed6-47d3-925a-9192b3e75dba" } }, { "lc": 1, "type": "constructor", "id": [ "langchain_core", "messages", "ToolMessage" ], "kwargs": { "content": "Successfully transferred back to top_level_supervisor", "name": "transfer_back_to_top_level_supervisor", "tool_call_id": "0c944a86-5f4e-4249-9693-ba1b2588d6d5", "additional_kwargs": {}, "response_metadata": {}, "id": "e67c9969-fb67-4d20-90ed-144723bf8c6d" } }, { "lc": 1, "type": "constructor", "id": [ "langchain_core", "messages", "AIMessage" ], "kwargs": { "content": "The task of answering \"What is 2 + 2?\" has been assigned to the appropriate agent in the school department. They will provide the correct answer.", "name": "top_level_supervisor", "additional_kwargs": {}, "response_metadata": { "tokenUsage": { "promptTokens": 172, "completionTokens": 34, "totalTokens": 206 }, "finish_reason": "stop", "model_name": "gpt-4.1-2025-04-14", "usage": { "completion_tokens": 34, "completion_tokens_details": { "accepted_prediction_tokens": 0, "audio_tokens": 0, "reasoning_tokens": 0, "rejected_prediction_tokens": 0 }, "prompt_tokens": 172, "prompt_tokens_details": { "audio_tokens": 0, "cached_tokens": 0 }, "total_tokens": 206 }, "system_fingerprint": "fp_c79ab13e31" }, "id": "chatcmpl-C7Ip5UwCWVUrP2OVqotjuCjtCLebx", "tool_calls": [], "invalid_tool_calls": [], "usage_metadata": { "output_tokens": 34, "input_tokens": 172, "total_tokens": 206, "input_token_details": { "audio": 0, "cache_read": 0 }, "output_token_details": { "audio": 0, "reasoning": 0 } } } } ] } ```
yindo closed this issue 2026-02-15 18:16:03 -05:00
Author
Owner

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

Hello @hitmands! Thank you for the MRE. The issue here stems from the fact that the parent supervisor incorrectly hallucinates a response without an actual handoff call.

You can nudge the parent supervisor to use a more specific handoff call by passing a description field when compiling the inner supervisor. (available since @langchain/langgraph>=0.4.4)

/* eslint-disable no-console */
import { AIMessage } from "@langchain/core/messages";
import { tool } from "@langchain/core/tools";
import { MemorySaver } from "@langchain/langgraph";
import { createSupervisor } from "@langchain/langgraph-supervisor";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod/v4";

const checkpointer = new MemorySaver();
const model = new ChatOpenAI({
  modelName: "gpt-4o-mini",
  temperature: 0,
});

const addition = tool(({ a, b }) => a + b, {
  schema: z.object({
    a: z.number(),
    b: z.number(),
  }),
  name: "addition",
  description: "Add two numbers",
});

const math = createReactAgent({
  name: "math",
  llm: model,
  tools: [addition],
  prompt: "You are a Math Agent, use the tool to sum two numbers",
});

const school = createSupervisor({
  llm: model,
  agents: [math],
  prompt:
    "You are a School Principal, choose which agent to use based on the task. Do not do the task yourself.",
  outputMode: "full_history",
  includeAgentName: "inline",
  addHandoffBackMessages: true,
  supervisorName: "school_supervisor",
}).compile({
  name: "school",
  description:
    "You are a School Principal, choose which agent to use based on the task. Do not do the task yourself. You have two agents: math.",
});

export const mainSupervisor = createSupervisor({
  llm: model,
  agents: [school],
  prompt:
    "You are the main supervisor. Assign the task to the appropriate agent. Do not do the task yourself.",
  addHandoffBackMessages: true,
  outputMode: "full_history",
  includeAgentName: "inline",
  supervisorName: "top_level_supervisor",
});

const graph = mainSupervisor.compile({ checkpointer, name: "top_level" });

const runExample = async () => {
  const tasks = ["What is it 2 + 2?"];
  const config = { configurable: { thread_id: "test" } };

  for (const task of tasks) {
    const result = await graph.invoke(
      { messages: [{ role: "user", content: task }] },
      config,
    );

    console.log("=".repeat(30));
    for (const message of result.messages) {
      console.log(
        `${message.getType()}: ${message.text || JSON.stringify((message as AIMessage).tool_calls)}`,
      );
    }
  }

  console.log("--- over ---");
};

runExample().catch(console.error);

@dqbd commented on GitHub (Sep 11, 2025): Hello @hitmands! Thank you for the MRE. The issue here stems from the fact that the parent supervisor incorrectly hallucinates a response without an actual handoff call. You can nudge the parent supervisor to use a more specific handoff call by passing a `description` field when compiling the inner supervisor. (available since `@langchain/langgraph>=0.4.4`) ```typescript /* eslint-disable no-console */ import { AIMessage } from "@langchain/core/messages"; import { tool } from "@langchain/core/tools"; import { MemorySaver } from "@langchain/langgraph"; import { createSupervisor } from "@langchain/langgraph-supervisor"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { ChatOpenAI } from "@langchain/openai"; import { z } from "zod/v4"; const checkpointer = new MemorySaver(); const model = new ChatOpenAI({ modelName: "gpt-4o-mini", temperature: 0, }); const addition = tool(({ a, b }) => a + b, { schema: z.object({ a: z.number(), b: z.number(), }), name: "addition", description: "Add two numbers", }); const math = createReactAgent({ name: "math", llm: model, tools: [addition], prompt: "You are a Math Agent, use the tool to sum two numbers", }); const school = createSupervisor({ llm: model, agents: [math], prompt: "You are a School Principal, choose which agent to use based on the task. Do not do the task yourself.", outputMode: "full_history", includeAgentName: "inline", addHandoffBackMessages: true, supervisorName: "school_supervisor", }).compile({ name: "school", description: "You are a School Principal, choose which agent to use based on the task. Do not do the task yourself. You have two agents: math.", }); export const mainSupervisor = createSupervisor({ llm: model, agents: [school], prompt: "You are the main supervisor. Assign the task to the appropriate agent. Do not do the task yourself.", addHandoffBackMessages: true, outputMode: "full_history", includeAgentName: "inline", supervisorName: "top_level_supervisor", }); const graph = mainSupervisor.compile({ checkpointer, name: "top_level" }); const runExample = async () => { const tasks = ["What is it 2 + 2?"]; const config = { configurable: { thread_id: "test" } }; for (const task of tasks) { const result = await graph.invoke( { messages: [{ role: "user", content: task }] }, config, ); console.log("=".repeat(30)); for (const message of result.messages) { console.log( `${message.getType()}: ${message.text || JSON.stringify((message as AIMessage).tool_calls)}`, ); } } console.log("--- over ---"); }; runExample().catch(console.error); ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraphjs#345