24Arys11 commited on
Commit
bea2d8c
·
1 Parent(s): d426005

Trying something new - an agent builder...

Browse files
agent_builder.py ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ import yaml
3
+ from typing import Dict, List, Any
4
+
5
+
6
+ class AgentBuilder:
7
+ @staticmethod
8
+ def initialize(agent_name: str):
9
+ """Create agent folder and an empty 'yaml' file
10
+
11
+ Args:
12
+ agent_name: Name of the agent to create
13
+ """
14
+ # Create base agents directory if it doesn't exist
15
+ agents_base_dir = Path("agents")
16
+ agents_base_dir.mkdir(exist_ok=True)
17
+
18
+ # Create agent-specific directory
19
+ agent_dir = agents_base_dir / agent_name
20
+ agent_dir.mkdir(exist_ok=True)
21
+
22
+ # Create YAML file with initial content
23
+ yaml_file = agent_dir / f"design.yaml"
24
+
25
+ # Initial YAML content with nodes list and example node
26
+ initial_content = {
27
+ "nodes": [
28
+ {
29
+ "name": "START",
30
+ "connections": ["example_node"],
31
+ "description": "This is the mandatory initial node `START` !"
32
+ },
33
+ {
34
+ "name": "example_node",
35
+ "connections": [],
36
+ "description": "This is an example node"
37
+ }
38
+ ]
39
+ }
40
+
41
+ # Write the YAML content to the file
42
+ with open(yaml_file, "w") as f:
43
+ yaml.dump(initial_content, f, default_flow_style=False, sort_keys=False)
44
+
45
+ @classmethod
46
+ def setup(cls, agent_name: str):
47
+ """Create the graph and the test python files as well as a 'puml' diagram
48
+
49
+ Args:
50
+ agent_name: Name of the agent to set up
51
+ """
52
+ design_data = cls._validate_design(agent_name)
53
+
54
+ cls._create_graph_file(agent_name, design_data)
55
+ cls._create_test_file(agent_name)
56
+ cls._create_puml_file(agent_name, design_data)
57
+
58
+ @classmethod
59
+ def _validate_design(cls, agent_name: str) -> Dict[str, List[Dict[str, Any]]]:
60
+ """Validate the design.yaml file structure
61
+
62
+ Args:
63
+ agent_name: Name of the agent to validate
64
+
65
+ Returns:
66
+ The parsed design data if valid
67
+
68
+ Raises:
69
+ ValueError: If design file is invalid or missing required elements
70
+ """
71
+ yaml_path = Path(f"agents/{agent_name}/design.yaml")
72
+
73
+ if not yaml_path.exists():
74
+ raise ValueError(f"Design file not found at {yaml_path}")
75
+
76
+ with open(yaml_path, 'r') as f:
77
+ design_data = yaml.safe_load(f)
78
+
79
+ # Check if nodes list exists
80
+ if not design_data or 'nodes' not in design_data or not isinstance(design_data['nodes'], list):
81
+ raise ValueError("Design file must contain a 'nodes' list")
82
+
83
+ # Check if START node is defined
84
+ start_node_exists = any(node.get('name') == "START" for node in design_data['nodes'])
85
+ if not start_node_exists:
86
+ raise ValueError("Design file must contain a 'START' node")
87
+
88
+ # Validate each node
89
+ for i, node in enumerate(design_data['nodes']):
90
+ if not isinstance(node, dict):
91
+ raise ValueError(f"Node at index {i} must be a dictionary")
92
+
93
+ if 'name' not in node:
94
+ raise ValueError(f"Node at index {i} is missing a 'name' field")
95
+
96
+ if 'description' not in node:
97
+ raise ValueError(f"Node '{node.get('name', f'at index {i}')}' is missing a 'description' field")
98
+
99
+ if 'connections' not in node or not isinstance(node['connections'], list):
100
+ raise ValueError(f"Node '{node.get('name')}' must have a 'connections' list")
101
+
102
+ return design_data
103
+
104
+ @classmethod
105
+ def _create_graph_file(cls, agent_name: str, design_data: Dict[str, List[Dict[str, Any]]]):
106
+ """Create the graph.py file with the necessary classes
107
+
108
+ Args:
109
+ agent_name: Name of the agent
110
+ design_data: The validated design data
111
+ """
112
+ nodes = design_data['nodes']
113
+
114
+ # Prepare node methods and conditional edge methods
115
+ node_methods = []
116
+ edge_methods = []
117
+
118
+ # Generate node method for each node
119
+ for node in nodes:
120
+ node_name = node['name']
121
+ node_desc = node['description']
122
+
123
+ node_method = f'''
124
+ def {node_name}_node(self, state):
125
+ """
126
+ {node_desc}
127
+ """
128
+ # TODO: To implement...
129
+ pass
130
+ '''
131
+ if node_name != "START":
132
+ node_methods.append(node_method)
133
+
134
+ # Check if this node has more than one connection (needs conditional edge)
135
+ if len(node['connections']) > 1:
136
+ connections_str = ", ".join([f'"{conn}"' for conn in node['connections']])
137
+ edge_method = f'''
138
+ def {node_name}_edge(self, state):
139
+ """
140
+ Conditional edge for {node_name} node.
141
+ Returns one of: {connections_str}
142
+ """
143
+ # TODO: To implement...
144
+ pass
145
+ '''
146
+ edge_methods.append(edge_method)
147
+
148
+ # Build the file content
149
+ file_content = f'''from typing import Dict, Any
150
+ from langgraph.graph import StateGraph, END, START
151
+ from langgraph.graph.state import CompiledStateGraph
152
+
153
+
154
+ class State:
155
+ """
156
+ State class for the agent graph.
157
+ """
158
+ # TODO: Define state structure
159
+ pass
160
+
161
+
162
+ class Nodes:
163
+ """
164
+ Collection of node functions for the agent graph.
165
+ """
166
+ {"".join(node_methods)}
167
+
168
+
169
+ class Edges:
170
+ """
171
+ Collection of conditional edge functions for the agent graph.
172
+ """
173
+ {"".join(edge_methods)}
174
+
175
+
176
+ class GraphBuilder:
177
+ def __init__(self):
178
+ """
179
+ Initializes the GraphBuilder.
180
+ """
181
+ self.nodes = Nodes()
182
+ self.edges = Edges()
183
+ # TODO: Implement the desired constructor.
184
+ pass
185
+
186
+ def build_agent_graph(self) -> CompiledStateGraph:
187
+ """Build and return the agent graph."""
188
+ graph = StateGraph(State)
189
+
190
+ # Add all nodes
191
+ {cls._generate_add_nodes_code(nodes)}
192
+
193
+ # Add edges
194
+ {cls._generate_regular_edges_code(nodes)}
195
+ {cls._generate_conditional_edges_code(nodes)}
196
+ return graph.compile()
197
+ '''
198
+ # Write to file
199
+ graph_file_path = Path(f"agents/{agent_name}/graph.py")
200
+ with open(graph_file_path, 'w') as f:
201
+ f.write(file_content)
202
+
203
+ @staticmethod
204
+ def _generate_add_nodes_code(nodes):
205
+ """Generate code for adding nodes to the graph"""
206
+ code_lines = []
207
+ for node in nodes:
208
+ if node["name"] != "START":
209
+ code_lines.append(f' graph.add_node("{node["name"]}", self.nodes.{node["name"]}_node)')
210
+ return "\n".join(code_lines)
211
+
212
+ @staticmethod
213
+ def _generate_conditional_edges_code(nodes):
214
+ """Generate code for adding conditional edges to the graph"""
215
+ code_lines = []
216
+ for node in nodes:
217
+ if len(node['connections']) > 1:
218
+ destinations = ", ".join([f'{conn}: {conn}' if conn in ["START", "END"] else f'"{conn}": "{conn}"' for conn in node['connections']])
219
+ code_lines.append(f''' graph.add_conditional_edges(
220
+ "{node["name"]}",
221
+ self.edges.{node["name"]}_edge,
222
+ {{
223
+ {destinations}
224
+ }}
225
+ )''')
226
+ return "\n".join(code_lines) if code_lines else ""
227
+
228
+ @staticmethod
229
+ def _generate_regular_edges_code(nodes):
230
+ """Generate code for adding regular edges to the graph"""
231
+ code_lines = []
232
+ for node in nodes:
233
+ if len(node['connections']) == 1:
234
+ start_key = node["name"] if node["name"] in ["START", "END"] else f'"{node["name"]}"'
235
+ end_key = node["connections"][0] if node["connections"][0] in ["START", "END"] else f'"{node["connections"][0]}"'
236
+ code_lines.append(f' graph.add_edge({start_key}, {end_key})')
237
+ return "\n".join(code_lines) if code_lines else ""
238
+
239
+ @staticmethod
240
+ def _create_test_file(agent_name: str):
241
+ """Create the test.py file
242
+
243
+ Args:
244
+ agent_name: Name of the agent
245
+ """
246
+ test_file_content = f'''# Test file for {agent_name} agent
247
+ from graph import GraphBuilder
248
+
249
+ def test_agent():
250
+ """
251
+ Test the {agent_name} agent functionality.
252
+ """
253
+ # Create the graph
254
+ builder = GraphBuilder()
255
+ graph = builder.build_agent_graph()
256
+
257
+ # TODO: Add test code here
258
+ print("Testing {agent_name} agent...")
259
+
260
+ # Example test
261
+ # result = graph.invoke({{"input": "Test input"}})
262
+ # print(f"Result: {{result}}")
263
+
264
+ if __name__ == "__main__":
265
+ test_agent()
266
+ '''
267
+
268
+ # Write to file
269
+ test_file_path = Path(f"agents/{agent_name}/test.py")
270
+ with open(test_file_path, 'w') as f:
271
+ f.write(test_file_content)
272
+
273
+ @staticmethod
274
+ def _create_puml_file(agent_name: str, design_data: Dict[str, List[Dict[str, Any]]]):
275
+ """Create the design.puml file for diagram visualization
276
+
277
+ Args:
278
+ agent_name: Name of the agent
279
+ design_data: The validated design data
280
+ """
281
+ nodes = design_data['nodes']
282
+
283
+ # Start the PlantUML content
284
+ puml_content = f'''@startuml {agent_name}
285
+ !define NOT_IMPLEMENTED_NODE_COLOR #IndianRed
286
+ !define IMPLEMENTED_NODE_COLOR #Gold
287
+ !define TESTED_NODE_COLOR #LawnGreen
288
+ !define TERMINAL_NODE_COLOR #DodgerBlue
289
+
290
+ '''
291
+
292
+ # Add node descriptions
293
+ for node in nodes:
294
+ puml_content += f'node {node["name"]} {node["status"]}_NODE_COLOR[\n {node["description"]}\n]\n\n'
295
+ puml_content += f'node END TERMINAL_NODE_COLOR[\n This is the final Node !\n]\n\n'
296
+
297
+ # Add connections
298
+ for node in nodes:
299
+ node_name = node["name"]
300
+ for connection in node["connections"]:
301
+ if connection == "END":
302
+ puml_content += f'{node_name} --> END\n'
303
+ else:
304
+ puml_content += f'{node_name} --> {connection}\n'
305
+
306
+ # End the PlantUML content
307
+ puml_content += '\n@enduml'
308
+
309
+ # Write to file
310
+ puml_file_path = Path(f"agents/{agent_name}/design.puml")
311
+ with open(puml_file_path, 'w') as f:
312
+ f.write(puml_content)
313
+
314
+ @staticmethod
315
+ def validate(agent_name: str):
316
+ pass
317
+
318
+
319
+ if __name__ == "__main__":
320
+ # AgentBuilder.initialize("universal_solver")
321
+ AgentBuilder.setup("universal_solver")
agent_builder_template/design_puml.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @startuml universal_solver
2
+ !define NOT_IMPLEMENTED_NODE_COLOR #IndianRed
3
+ !define IMPLEMENTED_NODE_COLOR #Gold
4
+ !define TESTED_NODE_COLOR #LawnGreen
5
+ !define TERMINAL_NODE_COLOR #DodgerBlue
6
+
7
+ >>>>>NODES<<<<<
8
+
9
+ node END TERMINAL_NODE_COLOR[
10
+ This is the final Node !
11
+ ]
12
+
13
+ >>>>>EDGES<<<<<
14
+
15
+ @enduml
agent_builder_template/design_yaml.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ nodes:
2
+ - name: START
3
+ connections:
4
+ - example_node
5
+ description: This is the mandatory initial node `START` !
6
+ status: TERMINAL
7
+
8
+ - name: example_node
9
+ connections: [END]
10
+ description: This is an example node
11
+ status: NOT_IMPLEMENTED
agent_builder_template/graph.txt ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class State:
2
+ """
3
+ State class for the agent graph.
4
+ """
5
+ # TODO: Define state structure
6
+ pass
7
+
8
+
9
+ class Nodes:
10
+ """
11
+ Collection of node functions for the agent graph.
12
+ """
13
+ >>>>>NODE_METHODS<<<<<
14
+
15
+
16
+
17
+ class Edges:
18
+ """
19
+ Collection of conditional edge functions for the agent graph.
20
+ """
21
+ >>>>>CONDITIONAL_EDGE_METHODS<<<<<
agent_builder_template/graph_builder.txt ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Dict, Any
2
+ from langgraph.graph import StateGraph, END, START
3
+ from langgraph.graph.state import CompiledStateGraph
4
+
5
+
6
+ class GraphBuilder:
7
+ def __init__(self):
8
+ """
9
+ Initializes the GraphBuilder.
10
+ """
11
+ self.nodes = Nodes()
12
+ self.edges = Edges()
13
+ # TODO: Implement the desired constructor.
14
+ pass
15
+
16
+ def build_agent_graph(self) -> CompiledStateGraph:
17
+ """Build and return the agent graph."""
18
+ graph = StateGraph(State)
19
+
20
+ >>>>>NODES<<<<<
21
+
22
+ >>>>>EDGES<<<<<
23
+
24
+ return graph.compile()
agent_builder_template/test.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from graph import State, Nodes, Edges
2
+ from graph_builder import GraphBuilder
agents/universal_solver/design.puml ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @startuml universal_solver
2
+ !define NOT_IMPLEMENTED_NODE_COLOR #IndianRed
3
+ !define IMPLEMENTED_NODE_COLOR #Gold
4
+ !define TESTED_NODE_COLOR #LawnGreen
5
+ !define TERMINAL_NODE_COLOR #DodgerBlue
6
+
7
+ node START TERMINAL_NODE_COLOR[
8
+ This is the mandatory initial node `START` !
9
+ ]
10
+
11
+ node example_node_1 NOT_IMPLEMENTED_NODE_COLOR[
12
+ This is an example node
13
+ ]
14
+
15
+ node example_node_2 IMPLEMENTED_NODE_COLOR[
16
+ This is another example node
17
+ ]
18
+
19
+ node example_node_3 TESTED_NODE_COLOR[
20
+ This is yet another example node
21
+ ]
22
+
23
+ node END TERMINAL_NODE_COLOR[
24
+ This is the final Node !
25
+ ]
26
+
27
+ START --> example_node_1
28
+ example_node_1 --> example_node_2
29
+ example_node_2 --> example_node_3
30
+ example_node_3 --> END
31
+
32
+ @enduml
agents/universal_solver/design.yaml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ nodes:
2
+ - name: START
3
+ connections:
4
+ - example_node_1
5
+ description: This is the mandatory initial node `START` !
6
+ status: TERMINAL
7
+
8
+ - name: example_node_1
9
+ connections: [example_node_2]
10
+ description: This is an example node
11
+ status: NOT_IMPLEMENTED
12
+
13
+ - name: example_node_2
14
+ connections: [example_node_3]
15
+ description: This is another example node
16
+ status: IMPLEMENTED
17
+
18
+ - name: example_node_3
19
+ connections: [END]
20
+ description: This is yet another example node
21
+ status: TESTED
agents/universal_solver/graph.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Dict, Any
2
+ from langgraph.graph import StateGraph, END, START
3
+ from langgraph.graph.state import CompiledStateGraph
4
+
5
+
6
+ class State:
7
+ """
8
+ State class for the agent graph.
9
+ """
10
+ # TODO: Define state structure
11
+ pass
12
+
13
+
14
+ class Nodes:
15
+ """
16
+ Collection of node functions for the agent graph.
17
+ """
18
+
19
+ def example_node_1_node(self, state):
20
+ """
21
+ This is an example node
22
+ """
23
+ # TODO: To implement...
24
+ pass
25
+
26
+ def example_node_2_node(self, state):
27
+ """
28
+ This is another example node
29
+ """
30
+ # TODO: To implement...
31
+ pass
32
+
33
+ def example_node_3_node(self, state):
34
+ """
35
+ This is yet another example node
36
+ """
37
+ # TODO: To implement...
38
+ pass
39
+
40
+
41
+
42
+ class Edges:
43
+ """
44
+ Collection of conditional edge functions for the agent graph.
45
+ """
46
+
47
+
48
+
49
+ class GraphBuilder:
50
+ def __init__(self):
51
+ """
52
+ Initializes the GraphBuilder.
53
+ """
54
+ self.nodes = Nodes()
55
+ self.edges = Edges()
56
+ # TODO: Implement the desired constructor.
57
+ pass
58
+
59
+ def build_agent_graph(self) -> CompiledStateGraph:
60
+ """Build and return the agent graph."""
61
+ graph = StateGraph(State)
62
+
63
+ # Add all nodes
64
+ graph.add_node("example_node_1", self.nodes.example_node_1_node)
65
+ graph.add_node("example_node_2", self.nodes.example_node_2_node)
66
+ graph.add_node("example_node_3", self.nodes.example_node_3_node)
67
+
68
+ # Add edges
69
+ graph.add_edge(START, "example_node_1")
70
+ graph.add_edge("example_node_1", "example_node_2")
71
+ graph.add_edge("example_node_2", "example_node_3")
72
+ graph.add_edge("example_node_3", END)
73
+
74
+ return graph.compile()
agents/universal_solver/test.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Test file for universal_solver agent
2
+ from graph import GraphBuilder
3
+
4
+ def test_agent():
5
+ """
6
+ Test the universal_solver agent functionality.
7
+ """
8
+ # Create the graph
9
+ builder = GraphBuilder()
10
+ graph = builder.build_agent_graph()
11
+
12
+ # TODO: Add test code here
13
+ print("Testing universal_solver agent...")
14
+
15
+ # Example test
16
+ # result = graph.invoke({"input": "Test input"})
17
+ # print(f"Result: {result}")
18
+
19
+ if __name__ == "__main__":
20
+ test_agent()