Skip to content

Commit d7e03ee

Browse files
google-genai-botcopybara-github
authored andcommitted
fix: Relaxing constraints for output schema
These changes are now in sync with Python ADK PiperOrigin-RevId: 886040294
1 parent 8b6b344 commit d7e03ee

2 files changed

Lines changed: 26 additions & 106 deletions

File tree

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

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -594,40 +594,6 @@ protected void validate() {
594594
this.disallowTransferToParent != null && this.disallowTransferToParent;
595595
this.disallowTransferToPeers =
596596
this.disallowTransferToPeers != null && this.disallowTransferToPeers;
597-
598-
if (this.outputSchema != null) {
599-
if (!this.disallowTransferToParent || !this.disallowTransferToPeers) {
600-
logger.warn(
601-
"Invalid config for agent {}: outputSchema cannot co-exist with agent transfer"
602-
+ " configurations. Setting disallowTransferToParent=true and"
603-
+ " disallowTransferToPeers=true.",
604-
this.name);
605-
this.disallowTransferToParent = true;
606-
this.disallowTransferToPeers = true;
607-
}
608-
609-
if (this.subAgents != null && !this.subAgents.isEmpty()) {
610-
throw new IllegalArgumentException(
611-
"Invalid config for agent "
612-
+ this.name
613-
+ ": if outputSchema is set, subAgents must be empty to disable agent"
614-
+ " transfer.");
615-
}
616-
if (this.toolsUnion != null && !this.toolsUnion.isEmpty()) {
617-
boolean hasOtherTools =
618-
this.toolsUnion.stream()
619-
.anyMatch(
620-
tool ->
621-
!(tool instanceof BaseTool baseTool)
622-
|| !baseTool.name().equals("example_tool"));
623-
if (hasOtherTools) {
624-
throw new IllegalArgumentException(
625-
"Invalid config for agent "
626-
+ this.name
627-
+ ": if outputSchema is set, tools must be empty.");
628-
}
629-
}
630-
}
631597
}
632598

633599
@Override

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

Lines changed: 26 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import static com.google.common.collect.Iterables.getOnlyElement;
2727
import static com.google.common.truth.Truth.assertThat;
2828
import static org.junit.Assert.assertEquals;
29-
import static org.junit.Assert.assertThrows;
3029

3130
import com.google.adk.agents.Callbacks.AfterModelCallback;
3231
import com.google.adk.agents.Callbacks.AfterToolCallback;
@@ -52,9 +51,9 @@
5251
import com.google.common.collect.ImmutableMap;
5352
import com.google.errorprone.annotations.CanIgnoreReturnValue;
5453
import com.google.genai.types.Content;
55-
import com.google.genai.types.FunctionDeclaration;
5654
import com.google.genai.types.Part;
5755
import com.google.genai.types.Schema;
56+
import com.google.genai.types.Type;
5857
import io.opentelemetry.api.trace.Span;
5958
import io.opentelemetry.api.trace.Tracer;
6059
import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule;
@@ -63,7 +62,6 @@
6362
import io.reactivex.rxjava3.core.Maybe;
6463
import io.reactivex.rxjava3.core.Single;
6564
import java.util.List;
66-
import java.util.Optional;
6765
import java.util.concurrent.ConcurrentHashMap;
6866
import java.util.concurrent.atomic.AtomicBoolean;
6967
import org.junit.After;
@@ -213,75 +211,6 @@ public void run_withToolsAndMaxSteps_stopsAfterMaxSteps() {
213211
assertEqualIgnoringFunctionIds(events.get(3).content().get(), expectedFunctionResponseContent);
214212
}
215213

216-
@Test
217-
public void build_withOutputSchemaAndTools_throwsIllegalArgumentException() {
218-
BaseTool tool =
219-
new BaseTool("test_tool", "test_description") {
220-
@Override
221-
public Optional<FunctionDeclaration> declaration() {
222-
return Optional.empty();
223-
}
224-
};
225-
226-
Schema outputSchema =
227-
Schema.builder()
228-
.type("OBJECT")
229-
.properties(ImmutableMap.of("status", Schema.builder().type("STRING").build()))
230-
.required(ImmutableList.of("status"))
231-
.build();
232-
233-
// Expecting an IllegalArgumentException when building the agent
234-
IllegalArgumentException exception =
235-
assertThrows(
236-
IllegalArgumentException.class,
237-
() ->
238-
LlmAgent.builder() // Use the agent builder directly
239-
.name("agent with invalid tool config")
240-
.outputSchema(outputSchema) // Set the output schema
241-
.tools(ImmutableList.of(tool)) // Set tools (this should cause the error)
242-
.build()); // Attempt to build the agent
243-
244-
assertThat(exception)
245-
.hasMessageThat()
246-
.contains(
247-
"Invalid config for agent agent with invalid tool config: if outputSchema is set, tools"
248-
+ " must be empty");
249-
}
250-
251-
@Test
252-
public void build_withOutputSchemaAndSubAgents_throwsIllegalArgumentException() {
253-
ImmutableList<BaseAgent> subAgents =
254-
ImmutableList.of(
255-
createTestAgentBuilder(createTestLlm(LlmResponse.builder().build()))
256-
.name("test_sub_agent")
257-
.description("test_sub_agent_description")
258-
.build());
259-
260-
Schema outputSchema =
261-
Schema.builder()
262-
.type("OBJECT")
263-
.properties(ImmutableMap.of("status", Schema.builder().type("STRING").build()))
264-
.required(ImmutableList.of("status"))
265-
.build();
266-
267-
// Expecting an IllegalArgumentException when building the agent
268-
IllegalArgumentException exception =
269-
assertThrows(
270-
IllegalArgumentException.class,
271-
() ->
272-
LlmAgent.builder() // Use the agent builder directly
273-
.name("agent with invalid tool config")
274-
.outputSchema(outputSchema) // Set the output schema
275-
.subAgents(subAgents) // Set subAgents (this should cause the error)
276-
.build()); // Attempt to build the agent
277-
278-
assertThat(exception)
279-
.hasMessageThat()
280-
.contains(
281-
"Invalid config for agent agent with invalid tool config: if outputSchema is set,"
282-
+ " subAgents must be empty to disable agent transfer.");
283-
}
284-
285214
@Test
286215
public void testBuild_withNullInstruction_setsInstructionToEmptyString() {
287216
LlmAgent agent =
@@ -645,6 +574,31 @@ public void runAsync_withSubAgents_createsSpans() throws InterruptedException {
645574
assertThat(llmSpans).hasSize(2); // One for main agent, one for sub agent
646575
}
647576

577+
@Test
578+
public void run_outputSchemaWithTools_allowed() {
579+
Schema personShema =
580+
Schema.builder()
581+
.type(Type.Known.OBJECT)
582+
.properties(
583+
ImmutableMap.of(
584+
"name", Schema.builder().type(Type.Known.STRING).build(),
585+
"age", Schema.builder().type(Type.Known.INTEGER).build(),
586+
"city", Schema.builder().type(Type.Known.STRING).build()))
587+
.build();
588+
LlmAgent agent =
589+
createTestAgentBuilder(createTestLlm(LlmResponse.builder().build()))
590+
.outputSchema(personShema)
591+
.tools(new EchoTool())
592+
.build();
593+
assertThat(agent.outputSchema()).hasValue(personShema);
594+
assertThat(
595+
agent
596+
.canonicalTools(new ReadonlyContext(createInvocationContext(agent)))
597+
.count()
598+
.blockingGet())
599+
.isEqualTo(1);
600+
}
601+
648602
private List<SpanData> findSpansByName(List<SpanData> spans, String name) {
649603
return spans.stream().filter(s -> s.getName().equals(name)).toList();
650604
}

0 commit comments

Comments
 (0)