Skip to content

Commit 2d7d76f

Browse files
google-genai-botcopybara-github
authored andcommitted
feat: enable LoopAgent configuration
PiperOrigin-RevId: 846216015
1 parent 2e1b09f commit 2d7d76f

File tree

5 files changed

+103
-1
lines changed

5 files changed

+103
-1
lines changed

core/src/main/java/com/google/adk/agents/ConfigAgentUtils.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,10 @@ private static Class<? extends BaseAgentConfig> getConfigClassForAgent(
307307
return ParallelAgentConfig.class;
308308
}
309309

310+
if (agentClass == LoopAgent.class) {
311+
return LoopAgentConfig.class;
312+
}
313+
310314
// TODO: Add more agent class to config class mappings as needed
311315
// Example:
312316
// if (agentClass == CustomAgent.class) {

core/src/main/java/com/google/adk/agents/LoopAgent.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616

1717
package com.google.adk.agents;
1818

19+
import com.google.adk.agents.ConfigAgentUtils.ConfigurationException;
1920
import com.google.adk.events.Event;
2021
import com.google.errorprone.annotations.CanIgnoreReturnValue;
2122
import io.reactivex.rxjava3.core.Flowable;
2223
import java.util.List;
2324
import java.util.Optional;
25+
import org.slf4j.Logger;
26+
import org.slf4j.LoggerFactory;
2427

2528
/**
2629
* An agent that runs its sub-agents sequentially in a loop.
@@ -29,6 +32,7 @@
2932
* reached (if specified).
3033
*/
3134
public class LoopAgent extends BaseAgent {
35+
private static final Logger logger = LoggerFactory.getLogger(LoopAgent.class);
3236

3337
private final Optional<Integer> maxIterations;
3438

@@ -82,6 +86,35 @@ public static Builder builder() {
8286
return new Builder();
8387
}
8488

89+
/**
90+
* Creates a LoopAgent from configuration.
91+
*
92+
* @param config The agent configuration.
93+
* @param configAbsPath The absolute path to the agent config file.
94+
* @return the configured LoopAgent
95+
* @throws ConfigurationException if the configuration is invalid
96+
*/
97+
public static LoopAgent fromConfig(LoopAgentConfig config, String configAbsPath)
98+
throws ConfigurationException {
99+
logger.debug("Creating LoopAgent from config: {}", config.name());
100+
101+
Builder builder = builder();
102+
ConfigAgentUtils.resolveAndSetCommonAgentFields(builder, config, configAbsPath);
103+
104+
if (config.maxIterations() != null) {
105+
builder.maxIterations(config.maxIterations());
106+
}
107+
108+
// Build and return the agent
109+
LoopAgent agent = builder.build();
110+
logger.info(
111+
"Successfully created LoopAgent: {} with {} subagents",
112+
agent.name(),
113+
agent.subAgents() != null ? agent.subAgents().size() : 0);
114+
115+
return agent;
116+
}
117+
85118
@Override
86119
protected Flowable<Event> runAsyncImpl(InvocationContext invocationContext) {
87120
List<? extends BaseAgent> subAgents = subAgents();
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.adk.agents;
18+
19+
/** Configuration for LoopAgent. */
20+
public class LoopAgentConfig extends BaseAgentConfig {
21+
private Integer maxIterations;
22+
23+
public LoopAgentConfig() {
24+
super("LoopAgent");
25+
}
26+
27+
public Integer maxIterations() {
28+
return maxIterations;
29+
}
30+
31+
public void setMaxIterations(Integer maxIterations) {
32+
this.maxIterations = maxIterations;
33+
}
34+
}

core/src/main/java/com/google/adk/tools/ExitLoopTool.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ public final class ExitLoopTool {
4242
name = "exit_loop",
4343
description = "Exits the loop.\n\nCall this function only when you are instructed to do so.")
4444
public static void exitLoop(ToolContext toolContext) {
45-
toolContext.setActions(toolContext.actions().toBuilder().escalate(true).build());
45+
toolContext.setActions(
46+
toolContext.actions().toBuilder().escalate(true).skipSummarization(true).build());
4647
}
4748

4849
private ExitLoopTool() {}

core/src/test/java/com/google/adk/agents/ConfigAgentUtilsTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,4 +1381,34 @@ public void testCallbackRefAccessors() {
13811381
callbackRef.setName("updated-name");
13821382
assertThat(callbackRef.name()).isEqualTo("updated-name");
13831383
}
1384+
1385+
@Test
1386+
public void fromConfig_validYamlLoopAgent_createsLoopAgent()
1387+
throws IOException, ConfigurationException {
1388+
File subAgentFile = tempFolder.newFile("sub_agent.yaml");
1389+
Files.writeString(
1390+
subAgentFile.toPath(),
1391+
"""
1392+
agent_class: LlmAgent
1393+
name: sub_agent
1394+
description: A test subagent
1395+
instruction: You are a helpful subagent
1396+
""");
1397+
1398+
File configFile = tempFolder.newFile("loop_agent.yaml");
1399+
Files.writeString(
1400+
configFile.toPath(),
1401+
"""
1402+
name: testLoopAgent
1403+
description: A test loop agent
1404+
agent_class: LoopAgent
1405+
max_iterations: 5
1406+
sub_agents:
1407+
- config_path: sub_agent.yaml
1408+
""");
1409+
String configPath = configFile.getAbsolutePath();
1410+
BaseAgent agent = ConfigAgentUtils.fromConfig(configPath);
1411+
assertThat(agent).isNotNull();
1412+
assertThat(agent).isInstanceOf(LoopAgent.class);
1413+
}
13841414
}

0 commit comments

Comments
 (0)