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

Cannot use Enums for node names #2964

Open
4 tasks done
laurencejennings opened this issue Jan 9, 2025 · 3 comments
Open
4 tasks done

Cannot use Enums for node names #2964

laurencejennings opened this issue Jan 9, 2025 · 3 comments

Comments

@laurencejennings
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 enum import Enum
from langchain_core.messages import HumanMessage
from langgraph.graph import StateGraph, START, END
from langgraph.prebuilt import create_react_agent

from typing import Literal
from typing_extensions import TypedDict

from langchain_openai import ChatOpenAI
from langgraph.graph import MessagesState, END
from langgraph.types import Command

class Members(Enum):
    researcher="researcher"
    coder="coder"

members = [Members.researcher, Members.coder]
# Our team supervisor is an LLM node. It just picks the next agent to process
# and decides when the work is completed
options = members + ["FINISH"]

system_prompt = (
    "You are a supervisor tasked with managing a conversation between the"
    f" following workers: {members}. Given the following user request,"
    " respond with the worker to act next. Each worker will perform a"
    " task and respond with their results and status. When finished,"
    " respond with FINISH."
)


class Router(TypedDict):
    """Worker to route to next. If no workers needed, route to FINISH."""

    next: Literal[*options]


llm = ChatOpenAI(model="gpt-4o")


def supervisor_node(state: MessagesState) -> Command[Literal[*members, "__end__"]]:
    messages = [
        {"role": "system", "content": system_prompt},
    ] + state["messages"]
    response = llm.with_structured_output(Router).invoke(messages)
    goto = response["next"]
    if goto == "FINISH":
        goto = END

    return Command(goto=goto)
research_agent = create_react_agent(
    llm, tools=[], state_modifier="You are a researcher. DO NOT do any math."
)


def research_node(state: MessagesState) -> Command[Literal["supervisor"]]:
    result = research_agent.invoke(state)
    return Command(
        update={
            "messages": [
                HumanMessage(content=result["messages"][-1].content, name="researcher")
            ]
        },
        goto="supervisor",
    )


# NOTE: THIS PERFORMS ARBITRARY CODE EXECUTION, WHICH CAN BE UNSAFE WHEN NOT SANDBOXED
code_agent = create_react_agent(llm, tools=[])


def code_node(state: MessagesState) -> Command[Literal["supervisor"]]:
    result = code_agent.invoke(state)
    return Command(
        update={
            "messages": [
                HumanMessage(content=result["messages"][-1].content, name="coder")
            ]
        },
        goto="supervisor",
    )


builder = StateGraph(MessagesState)
builder.add_edge(START, "supervisor")
builder.add_node("supervisor", supervisor_node)
builder.add_node("researcher", research_node)
builder.add_node("coder", code_node)
graph = builder.compile()

Error Message and Stack Trace (if applicable)

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[4], line 90
     88 builder.add_node("researcher", research_node)
     89 builder.add_node("coder", code_node)
---> 90 graph = builder.compile()

File ~/projects/ditto/poc/assignments/venv/lib/python3.11/site-packages/langgraph/graph/state.py:510, in StateGraph.compile(self, checkpointer, store, interrupt_before, interrupt_after, debug)
    507 interrupt_after = interrupt_after or []
    509 # validate the graph
--> 510 self.validate(
    511     interrupt=(
    512         (interrupt_before if interrupt_before != "*" else []) + interrupt_after
    513         if interrupt_after != "*"
    514         else []
    515     )
    516 )
    518 # prepare output channels
    519 output_channels = (
    520     "__root__"
    521     if len(self.schemas[self.output]) == 1
   (...)
    527     ]
    528 )

File ~/projects/ditto/poc/assignments/venv/lib/python3.11/site-packages/langgraph/graph/graph.py:405, in Graph.validate(self, interrupt)
    403 for target in all_targets:
    404     if target not in self.nodes and target != END:
--> 405         raise ValueError(f"Found edge ending at unknown node `{target}`")
    406 # validate interrupts
    407 if interrupt:

ValueError: Found edge ending at unknown node `Members.coder`

Description

I'm trying to use an Enum for my node/agent names to make the code more maintainable, but it seems the graph is looking for a node with the actual name of the enum variable not the value.

System Info

System Information

OS: Darwin
OS Version: Darwin Kernel Version 22.5.0: Mon Apr 24 20:51:50 PDT 2023; root:xnu-8796.121.2~5/RELEASE_X86_64
Python Version: 3.11.6 (v3.11.6:8b6ee5ba3b, Oct 2 2023, 11:18:21) [Clang 13.0.0 (clang-1300.0.29.30)]

Package Information

langchain_core: 0.3.29
langchain: 0.3.9
langchain_community: 0.3.8
langsmith: 0.1.147
langchain_openai: 0.2.10
langchain_text_splitters: 0.3.2
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
httpx: 0.28.1
httpx-sse: 0.4.0
jsonpatch: 1.33
langsmith-pyo3: Installed. No version info available.
numpy: 1.26.4
openai: 1.59.3
orjson: 3.10.13
packaging: 24.2
pydantic: 2.10.4
pydantic-settings: 2.7.1
PyYAML: 6.0.2
requests: 2.32.3
requests-toolbelt: 1.0.0
SQLAlchemy: 2.0.35
tenacity: 9.0.0
tiktoken: 0.8.0
typing-extensions: 4.12.2

@vbarda
Copy link
Collaborator

vbarda commented Jan 9, 2025

hm, i can't reproduce the exact issue you're running, but i would recommend using StrEnum instead of Enum. if you still want to use enums. let me know if this resolves it

@gbaian10
Copy link
Contributor

gbaian10 commented Jan 9, 2025

You can try the following two methods.

class Members(str, Enum):
    ....

or

from enum import StrEnum
class Members(StrEnum):
    ...

@vbarda
Copy link
Collaborator

vbarda commented Jan 10, 2025

@laurencejennings does this resolve your issue?

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

No branches or pull requests

3 participants