@pamelafox this looks correct.
We have a pre-built package for this ( GitHub - langchain-ai/langgraph-supervisor-py ); however, we will likely end up recommending that users do exactly what you did in your example.
The reason is that with the custom @tool it’s really obvious how to do all the context engineering.
@tool
def meal_agent_tool(query: str) -> str:
"""Invoke the recipe planning agent and return its final response as plain text."""
logger.info("Tool:meal_agent invoked")
response = meal_agent.invoke({"messages": [HumanMessage(content=query)]})
final = response["messages"][-1].content
return final
Can be changed to take multiple inputs (e.g., a budget), incorporate state or config information
@tool
def plan_recipe(recipe_request: str, .. can insert memory or config .. or additional input parameters for recipe planning (e.g., budget)):
"""Plan a recipe given the user request."""
logger.info("Tool:meal_agent invoked")
# agent can be created dynamically here in the extreme case
response = meal_agent.invoke({"messages": [HumanMessage(content=query)]})
# final can be just the answer, or it could incorporate more of the reasoning of the agent (to pass it to the original supervisor)
result = response["messages"][-1].content
# Alternatively, could also return a langgraph command to update short term memory etc.
result = Command(..)
return result
One suggestion is to keep the function names and the doc-strings LLM facing rather than developer facing (i.e., not meal_agent_tool , but plan_recipe ) – these are the names that LLMs