@@ -79,32 +79,33 @@ def test_gepa_with_tool_optimization_enabled():
7979
8080def test_gepa_with_multi_agent_architecture ():
8181 """Test that tool optimization discovers tools from nested subagent modules."""
82+
8283 class MultiAgentSystem (dspy .Module ):
8384 def __init__ (self ):
8485 super ().__init__ ()
8586 # Subagent as module attribute (reuse existing search function)
8687 search_tool = dspy .Tool (search , name = "search" , desc = "Searches" )
8788 self .subagent = dspy .ReAct ("task -> result" , tools = [search_tool ])
88-
89+
8990 # Main agent with subagent wrapped as tool
9091 def spawn_subagent (task : str ) -> str :
9192 return self .subagent (task = task ).result
92-
93+
9394 spawn_tool = dspy .Tool (spawn_subagent , name = "spawn_subagent" , desc = "Spawns subagent" )
9495 calc_tool = dspy .Tool (calculator , name = "calculator" , desc = "Does math" )
9596 self .main_agent = dspy .ReAct ("q -> a" , tools = [spawn_tool , calc_tool ])
96-
97+
9798 system = MultiAgentSystem ()
98-
99+
99100 # Test extraction using named_sub_modules pattern
100101 tool_descriptions = {}
101102 for _ , module in system .named_sub_modules ():
102- if hasattr (module , ' tools' ):
103+ if hasattr (module , " tools" ):
103104 for tool_name , tool in module .tools .items ():
104105 tool_key = f"tool:{ tool_name } "
105106 if tool_key not in tool_descriptions :
106107 tool_descriptions [tool_key ] = tool .desc
107-
108+
108109 # All tools from all nested agents should be discovered
109110 assert "tool:calculator" in tool_descriptions
110111 assert "tool:spawn_subagent" in tool_descriptions
@@ -114,40 +115,41 @@ def spawn_subagent(task: str) -> str:
114115
115116def test_gepa_optimizes_multi_agent_system_end_to_end ():
116117 """Test GEPA.compile() optimizes ALL tools from nested multi-agent system."""
118+
117119 class MultiAgentSystem (dspy .Module ):
118120 def __init__ (self ):
119121 super ().__init__ ()
120122 search_tool = dspy .Tool (search , name = "search" , desc = "Searches" )
121123 self .subagent = dspy .ReAct ("task -> result" , tools = [search_tool ])
122-
124+
123125 def spawn_subagent (task : str ) -> str :
124126 return self .subagent (task = task ).result
125-
127+
126128 spawn_tool = dspy .Tool (spawn_subagent , name = "spawn_subagent" , desc = "Spawns subagent" )
127129 calc_tool = dspy .Tool (calculator , name = "calculator" , desc = "Does math" )
128130 self .main_agent = dspy .ReAct ("q -> a" , tools = [spawn_tool , calc_tool ])
129-
131+
130132 def forward (self , question ):
131133 return self .main_agent (q = question )
132-
134+
133135 system = MultiAgentSystem ()
134-
136+
135137 # Setup LMs
136138 lm = DummyLM ([{"q" : "question" , "a" : "answer" }])
137139 reflection_lm = DummyLM ([{"improved_instruction" : "Better" }])
138140 dspy .settings .configure (lm = lm )
139-
141+
140142 # Run GEPA optimization
141143 optimizer = dspy .GEPA (
142144 metric = simple_metric ,
143145 reflection_lm = reflection_lm ,
144146 max_metric_calls = 3 ,
145147 optimize_tool_descriptions = True ,
146148 )
147-
149+
148150 trainset = [Example (question = "test" , answer = "answer" ).with_inputs ("question" )]
149151 optimized = optimizer .compile (system , trainset = trainset )
150-
152+
151153 # Verify optimized system preserves structure with all tools
152154 assert "search" in optimized .subagent .tools
153155 assert "calculator" in optimized .main_agent .tools
0 commit comments