1+ import graphviz
2+
3+ from src .agents .agent import Agent
4+
5+
6+ def get_main_graph (agent : Agent ) -> str :
7+ """
8+ Generates the main graph structure in DOT format for the given agent.
9+
10+ Args:
11+ agent (Agent): The agent for which the graph is to be generated.
12+
13+ Returns:
14+ str: The DOT format string representing the graph.
15+ """
16+ parts = ["""
17+ digraph G {
18+ graph [splines=true];
19+ node [fontname="Arial"];
20+ edge [penwidth=1.5];
21+
22+ "__start__" [shape=ellipse, style=filled, fillcolor=lightblue];
23+ "__end__" [shape=ellipse, style=filled, fillcolor=lightblue];
24+ """ ]
25+ parts .append (get_all_nodes (agent ))
26+ parts .append (get_all_edges (agent ))
27+ parts .append ("}" )
28+ return "" .join (parts )
29+
30+
31+ def get_all_nodes (agent : Agent , parent : Agent = None ) -> str :
32+ """
33+ Recursively generates the nodes for the given agent and its handoffs in DOT format.
34+
35+ Args:
36+ agent (Agent): The agent for which the nodes are to be generated.
37+
38+ Returns:
39+ str: The DOT format string representing the nodes.
40+ """
41+ parts = []
42+
43+ # Ensure parent agent node is colored
44+ if not parent :
45+ parts .append (f"""
46+ "{ agent .name } " [label="{ agent .name } ", shape=box, style=filled, fillcolor=lightyellow, width=1.5, height=0.8];""" )
47+
48+ # Smaller tools (ellipse, green)
49+ for tool in agent .tools :
50+ parts .append (f"""
51+ "{ tool .name } " [label="{ tool .name } ", shape=ellipse, style=filled, fillcolor=lightgreen, width=0.5, height=0.3];""" )
52+
53+ # Bigger handoffs (rounded box, yellow)
54+ for handoff in agent .handoffs :
55+ parts .append (f"""
56+ "{ handoff .name } " [label="{ handoff .name } ", shape=box, style=filled, style=rounded, fillcolor=lightyellow, width=1.5, height=0.8];""" )
57+ parts .append (get_all_nodes (handoff ))
58+
59+ return "" .join (parts )
60+
61+
62+ def get_all_edges (agent : Agent , parent : Agent = None ) -> str :
63+ """
64+ Recursively generates the edges for the given agent and its handoffs in DOT format.
65+
66+ Args:
67+ agent (Agent): The agent for which the edges are to be generated.
68+ parent (Agent, optional): The parent agent. Defaults to None.
69+
70+ Returns:
71+ str: The DOT format string representing the edges.
72+ """
73+ parts = []
74+
75+ if not parent :
76+ parts .append (f"""
77+ "__start__" -> "{ agent .name } ";""" )
78+
79+ for tool in agent .tools :
80+ parts .append (f"""
81+ "{ agent .name } " -> "{ tool .name } " [style=dotted, penwidth=1.5];
82+ "{ tool .name } " -> "{ agent .name } " [style=dotted, penwidth=1.5];""" )
83+
84+ if not agent .handoffs :
85+ parts .append (f"""
86+ "{ agent .name } " -> "__end__";""" )
87+
88+ for handoff in agent .handoffs :
89+ parts .append (f"""
90+ "{ agent .name } " -> "{ handoff .name } ";""" )
91+ parts .append (get_all_edges (handoff , agent ))
92+
93+ return "" .join (parts )
94+
95+
96+ def draw_graph (agent : Agent , filename : str = None ) -> graphviz .Source :
97+ """
98+ Draws the graph for the given agent and optionally saves it as a PNG file.
99+
100+ Args:
101+ agent (Agent): The agent for which the graph is to be drawn.
102+ filename (str): The name of the file to save the graph as a PNG.
103+
104+ Returns:
105+ graphviz.Source: The graphviz Source object representing the graph.
106+ """
107+ dot_code = get_main_graph (agent )
108+ graph = graphviz .Source (dot_code )
109+
110+ if filename :
111+ graph .render (filename , format = 'png' )
112+
113+ return graph
0 commit comments