Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AttributeError: 'Command' object has no attribute 'content' #3281

Open
4 tasks done
nick-youngblut opened this issue Feb 2, 2025 · 4 comments
Open
4 tasks done

AttributeError: 'Command' object has no attribute 'content' #3281

nick-youngblut opened this issue Feb 2, 2025 · 4 comments
Labels
question Further information is requested

Comments

@nick-youngblut
Copy link

Checked other resources

  • This is a bug, not a usage question. For questions, please use GitHub Discussions.
  • I added a clear and detailed title that summarizes the issue.
  • I read what a minimal reproducible example is (https://stackoverflow.com/help/minimal-reproducible-example).
  • I included a self-contained, minimal example that demonstrates the issue INCLUDING all the relevant imports. The code run AS IS to reproduce the issue.

Example Code

from typing import Annotated, List
from langgraph.types import Command
from langchain_core.tools import tool
from langchain_core.messages import AIMessage

def create_handoff_tool(agent_list: List[str]):
    """Create a tool that can return handoff via a Command"""
    available_agents = agent_list + ["__end__"]
    
    @tool
    def handoff_to_agent(
        agent_name: Annotated[str, "The name of the agent to handoff to"]
    ):
        """Handoff to another agent or end the task."""
        # check if agent name in the list
        if agent_name not in available_agents:
            error_message = f"Agent {agent_name} is not available. Choose one of: {', '.join(available_agents)}",
            return Command(
                goto=Command.PARENT, 
                graph=Command.PARENT,
                update={"messages": [AIMessage(content=error_message)]},
            )

        # return the routing command
        return Command(
            goto=agent_name,
            graph=Command.PARENT,
            update={"messages": [AIMessage(content=f"Successfully transferred to {agent_name}")]},
        )
    
    # dynamically modify doc string
    handoff_to_agent.__doc__ = "\n".join([
        "Transfer to another agent or end the task.",
        f"Available agents: {', '.join(available_agents)}.",
        "If you want to end the task, use '__end__'."
     ])
    
    return handoff_to_agent

Error Message and Stack Trace (if applicable)

Traceback (most recent call last):
  File "/Users/nickyoungblut/mambaforge/envs/genomics-guide2/lib/python3.11/site-packages/streamlit/runtime/scriptrunner/exec_code.py", line 88, in exec_func_with_error_handling
    result = func()
             ^^^^^^
  File "/Users/nickyoungblut/mambaforge/envs/genomics-guide2/lib/python3.11/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 579, in code_to_exec
    exec(code, module.__dict__)
  File "/Users/nickyoungblut/dev/python/streamlit/genomics_guide2/app.py", line 133, in <module>
    response = asyncio.run(
               ^^^^^^^^^^^^
  File "/Users/nickyoungblut/mambaforge/envs/genomics-guide2/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/Users/nickyoungblut/mambaforge/envs/genomics-guide2/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/nickyoungblut/mambaforge/envs/genomics-guide2/lib/python3.11/asyncio/base_events.py", line 654, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/Users/nickyoungblut/dev/python/streamlit/genomics_guide2/genomics_guide2/astream_event_handler.py", line 49, in astream_graph
    output_placeholder.code(event['data'].get('output').content)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Command' object has no attribute 'content'

Description

Command is not working with this simple example, and output_placeholder.code(event['data'].get('output').content) is not very helpful for determining the cause of the error.

System Info

System Information

OS: Darwin
OS Version: Darwin Kernel Version 24.2.0: Fri Dec 6 18:56:34 PST 2024; root:xnu-11215.61.5~2/RELEASE_ARM64_T6020
Python Version: 3.11.11 | packaged by conda-forge | (main, Dec 5 2024, 14:21:42) [Clang 18.1.8 ]

Package Information

langchain_core: 0.3.33
langchain: 0.3.17
langchain_community: 0.3.13
langsmith: 0.1.147
langchain_groq: 0.2.2
langchain_openai: 0.3.3
langchain_text_splitters: 0.3.4
langchain_weaviate: 0.0.3
langchainhub: 0.1.21
langgraph_sdk: 0.1.48

Optional packages not installed

langserve

Other Dependencies

aiohttp: 3.11.11
async-timeout: Installed. No version info available.
dataclasses-json: 0.6.7
groq: 0.13.1
httpx: 0.27.0
httpx-sse: 0.4.0
jsonpatch: 1.33
langsmith-pyo3: Installed. No version info available.
numpy: 1.26.4
openai: 1.61.0
orjson: 3.10.12
packaging: 24.2
pydantic: 2.10.4
pydantic-settings: 2.7.0
PyYAML: 6.0.2
requests: 2.32.3
requests-toolbelt: 1.0.0
simsimd: 4.4.0
SQLAlchemy: 2.0.36
tenacity: 8.5.0
tiktoken: 0.8.0
types-requests: 2.32.0.20241016
typing-extensions: 4.12.2
weaviate-client: 4.8.1

@nick-youngblut
Copy link
Author

nick-youngblut commented Feb 2, 2025

Also, it appears that Command cannot handle a goto back to the tool-calling agent, which is useful when the tool calling agent calls the wrong goto agent, so you want the tool calling agent to try again:

if agent_name not in available_agents:
    error_message = f"Agent {agent_name} is not available. Choose one of: {', '.join(available_agents)}",
    return Command(
       goto="AGENT_THAT_CALLED_THIS_TOOL", 
       update={"messages": [AIMessage(content=error_message)]},
    )

The error is: KeyError: 'branch:tools:__self__:AGENT_THAT_CALLED_THIS_TOOL

@vbarda
Copy link
Collaborator

vbarda commented Feb 3, 2025

This looks like error in your code and not in langgraph -- Command object never had a content field:

  File "/Users/nickyoungblut/dev/python/streamlit/genomics_guide2/genomics_guide2/astream_event_handler.py", line 49, in astream_graph
    output_placeholder.code(event['data'].get('output').content)

Also, it appears that Command cannot handle a goto back to the tool-calling agent, which is useful when the tool calling agent calls the wrong goto agent, so you want the tool calling agent to try again:

You would need to implement custom logic for this, Command is a general-purpose abstraction for combining navigation and state updates, it doesn't have anything specific to tool-calling. Here is how you could achieve desired behavior:

option 1: keep track of the currently active agent (either in the state or in AIMessage.name field)

agent_that_called = get_active_agent_name()
if agent_name not in available_agents:
    error_message = f"Agent {agent_name} is not available. Choose one of: {', '.join(available_agents)}",
    return Command(
       goto=agent_that_called, 
       update={"messages": [ToolMessage(content=error_message, tool_call_id=...)]},
    )

option 2: if you're using the prebuilt ToolNode, you can just raise the error before returning Command and ToolNode will automatically send ToolMessage with error content to the currently active agent, without navigating :

if agent_name not in available_agents:
    raise ValueError(" f"Agent {agent_name} is not available. Choose one of: {', '.join(available_agents)}")

...
return Command(...)

lastly, i think you have a typo in your original code example:

return Command(goto=Command.PARENT, ) <-- unless you have a node called "parent" in your graph, this is not going to work

@vbarda vbarda added the question Further information is requested label Feb 3, 2025
@vbarda
Copy link
Collaborator

vbarda commented Feb 13, 2025

@nick-youngblut did you manage to resolve your issue?

@nick-youngblut
Copy link
Author

@vbarda no, I gave up on using Command

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants