Skip to content

[Visualization Extension] Enhance agent graph visualization to prevent infinite recursion, add mermaid graph#445

Closed
ashish-dahal wants to merge 9 commits intoopenai:mainfrom
ashish-dahal:ashish-dahal/recursive-agents-visualization
Closed

[Visualization Extension] Enhance agent graph visualization to prevent infinite recursion, add mermaid graph#445
ashish-dahal wants to merge 9 commits intoopenai:mainfrom
ashish-dahal:ashish-dahal/recursive-agents-visualization

Conversation

@ashish-dahal
Copy link
Copy Markdown

Improves agent graph visualization logic:

  • Safely handles recursive agent handoffs during visualization
  • Adds a test case for recursive handoff loops
  • Cleans up redundant code and improves readability in the visualization test

Improves on PR #387, addressing pending change requests.

@ashish-dahal
Copy link
Copy Markdown
Author

Hey @rm-openai I noticed the original PR hasn’t had updates, so I’ve created a follow-up here with additional fixes and improvements. Happy to adjust things if needed.

@ashish-dahal
Copy link
Copy Markdown
Author

Addressed #387 (comment) and #387 (comment)

@ashish-dahal ashish-dahal changed the title [Visualization Extension] Enhance agent graph visualization to prevent infinite recursion for agents with recursive handoffs [Visualization Extension] Enhance agent graph visualization to prevent infinite recursion, add mermaid graph Apr 6, 2025
Copy link
Copy Markdown
Collaborator

@rm-openai rm-openai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, PR is looking great! Some changes requested inline

Comment thread src/agents/extensions/visualization.py Outdated

@dataclass(frozen=True)
class Edge:
source: str
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't these be Node not str?

def _add_agent_nodes_and_edges(
self,
agent: Agent,
parent: Optional[Agent],
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you use Agent | None instead?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment

Comment thread src/agents/extensions/visualization.py Outdated
graph: Graph,
) -> None:
# Add agent node
graph.add_node(Node(agent.name, agent.name, NodeType.AGENT))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using agent.name as the ID isn't safe unfortunately, since agents can have the same name. You'd need to do an instance equality check everywhere instead.

Copy link
Copy Markdown
Author

@ashish-dahal ashish-dahal Apr 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works when agent.handoffs have Agent instances. but apparently it's a bit tricky when Handoff objects are passed. It only has the target agent's name (handoff.agent_name), not an Agent instance. The instance itself only gets resolved at runtime with handoff.on_invoke_handoff. so we can't consistently do instance equality checks to link Handoff instances back to the Agent instances at build time if we consider cases with recursive handoffs. The only option I see is to resolve this using agent names but mention the caveat in the docs. any suggestions?

Comment thread src/agents/extensions/visualization.py Outdated


def draw_graph(
agent: Agent, filename: Optional[str] = None, renderer: str = "graphviz"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renderer should be either a Literal or an enum here

Also please add str | None = None instead of Optional

Copy link
Copy Markdown
Collaborator

@rm-openai rm-openai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as before

@ashish-dahal
Copy link
Copy Markdown
Author

should be looking good now

Comment on lines +277 to +278
response = requests.get(f"https://mermaid.ink/img/{base64_string}")
response.raise_for_status()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love this - relying on a 3rd party service that could return anything or leak information.

I'd actually prefer if we got rid of the Renderer base class, and instead had:

class GraphVizRenderer:
  @classmethod 
  def render_to_file(...)

  @classmethod 
  def render_to_object(...)

class MermaidRenderer:
  @classmethod 
  def render_mermaid_ink_link(...)

  @classmethod 
  def render_mermaid_text(...)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, on it!

Copy link
Copy Markdown
Collaborator

@rm-openai rm-openai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one more change sorry!

@github-actions
Copy link
Copy Markdown
Contributor

This PR is stale because it has been open for 10 days with no activity.

@github-actions github-actions Bot added the stale label Apr 25, 2025
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 2, 2025

This PR was closed because it has been inactive for 7 days since being marked as stale.

@github-actions github-actions Bot closed this May 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants