diff --git a/core/src/main/java/com/google/adk/agents/LlmAgent.java b/core/src/main/java/com/google/adk/agents/LlmAgent.java index 89024a59b..b387aee34 100644 --- a/core/src/main/java/com/google/adk/agents/LlmAgent.java +++ b/core/src/main/java/com/google/adk/agents/LlmAgent.java @@ -594,40 +594,6 @@ protected void validate() { this.disallowTransferToParent != null && this.disallowTransferToParent; this.disallowTransferToPeers = this.disallowTransferToPeers != null && this.disallowTransferToPeers; - - if (this.outputSchema != null) { - if (!this.disallowTransferToParent || !this.disallowTransferToPeers) { - logger.warn( - "Invalid config for agent {}: outputSchema cannot co-exist with agent transfer" - + " configurations. Setting disallowTransferToParent=true and" - + " disallowTransferToPeers=true.", - this.name); - this.disallowTransferToParent = true; - this.disallowTransferToPeers = true; - } - - if (this.subAgents != null && !this.subAgents.isEmpty()) { - throw new IllegalArgumentException( - "Invalid config for agent " - + this.name - + ": if outputSchema is set, subAgents must be empty to disable agent" - + " transfer."); - } - if (this.toolsUnion != null && !this.toolsUnion.isEmpty()) { - boolean hasOtherTools = - this.toolsUnion.stream() - .anyMatch( - tool -> - !(tool instanceof BaseTool baseTool) - || !baseTool.name().equals("example_tool")); - if (hasOtherTools) { - throw new IllegalArgumentException( - "Invalid config for agent " - + this.name - + ": if outputSchema is set, tools must be empty."); - } - } - } } @Override diff --git a/core/src/test/java/com/google/adk/agents/LlmAgentTest.java b/core/src/test/java/com/google/adk/agents/LlmAgentTest.java index c193e4a65..a9e7a6f8d 100644 --- a/core/src/test/java/com/google/adk/agents/LlmAgentTest.java +++ b/core/src/test/java/com/google/adk/agents/LlmAgentTest.java @@ -26,7 +26,6 @@ import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; import com.google.adk.agents.Callbacks.AfterModelCallback; import com.google.adk.agents.Callbacks.AfterToolCallback; @@ -52,9 +51,9 @@ import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.genai.types.Content; -import com.google.genai.types.FunctionDeclaration; import com.google.genai.types.Part; import com.google.genai.types.Schema; +import com.google.genai.types.Type; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule; @@ -63,7 +62,6 @@ import io.reactivex.rxjava3.core.Maybe; import io.reactivex.rxjava3.core.Single; import java.util.List; -import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.After; @@ -213,75 +211,6 @@ public void run_withToolsAndMaxSteps_stopsAfterMaxSteps() { assertEqualIgnoringFunctionIds(events.get(3).content().get(), expectedFunctionResponseContent); } - @Test - public void build_withOutputSchemaAndTools_throwsIllegalArgumentException() { - BaseTool tool = - new BaseTool("test_tool", "test_description") { - @Override - public Optional declaration() { - return Optional.empty(); - } - }; - - Schema outputSchema = - Schema.builder() - .type("OBJECT") - .properties(ImmutableMap.of("status", Schema.builder().type("STRING").build())) - .required(ImmutableList.of("status")) - .build(); - - // Expecting an IllegalArgumentException when building the agent - IllegalArgumentException exception = - assertThrows( - IllegalArgumentException.class, - () -> - LlmAgent.builder() // Use the agent builder directly - .name("agent with invalid tool config") - .outputSchema(outputSchema) // Set the output schema - .tools(ImmutableList.of(tool)) // Set tools (this should cause the error) - .build()); // Attempt to build the agent - - assertThat(exception) - .hasMessageThat() - .contains( - "Invalid config for agent agent with invalid tool config: if outputSchema is set, tools" - + " must be empty"); - } - - @Test - public void build_withOutputSchemaAndSubAgents_throwsIllegalArgumentException() { - ImmutableList subAgents = - ImmutableList.of( - createTestAgentBuilder(createTestLlm(LlmResponse.builder().build())) - .name("test_sub_agent") - .description("test_sub_agent_description") - .build()); - - Schema outputSchema = - Schema.builder() - .type("OBJECT") - .properties(ImmutableMap.of("status", Schema.builder().type("STRING").build())) - .required(ImmutableList.of("status")) - .build(); - - // Expecting an IllegalArgumentException when building the agent - IllegalArgumentException exception = - assertThrows( - IllegalArgumentException.class, - () -> - LlmAgent.builder() // Use the agent builder directly - .name("agent with invalid tool config") - .outputSchema(outputSchema) // Set the output schema - .subAgents(subAgents) // Set subAgents (this should cause the error) - .build()); // Attempt to build the agent - - assertThat(exception) - .hasMessageThat() - .contains( - "Invalid config for agent agent with invalid tool config: if outputSchema is set," - + " subAgents must be empty to disable agent transfer."); - } - @Test public void testBuild_withNullInstruction_setsInstructionToEmptyString() { LlmAgent agent = @@ -645,6 +574,31 @@ public void runAsync_withSubAgents_createsSpans() throws InterruptedException { assertThat(llmSpans).hasSize(2); // One for main agent, one for sub agent } + @Test + public void run_outputSchemaWithTools_allowed() { + Schema personShema = + Schema.builder() + .type(Type.Known.OBJECT) + .properties( + ImmutableMap.of( + "name", Schema.builder().type(Type.Known.STRING).build(), + "age", Schema.builder().type(Type.Known.INTEGER).build(), + "city", Schema.builder().type(Type.Known.STRING).build())) + .build(); + LlmAgent agent = + createTestAgentBuilder(createTestLlm(LlmResponse.builder().build())) + .outputSchema(personShema) + .tools(new EchoTool()) + .build(); + assertThat(agent.outputSchema()).hasValue(personShema); + assertThat( + agent + .canonicalTools(new ReadonlyContext(createInvocationContext(agent))) + .count() + .blockingGet()) + .isEqualTo(1); + } + private List findSpansByName(List spans, String name) { return spans.stream().filter(s -> s.getName().equals(name)).toList(); }