diff --git a/core/src/main/java/com/google/adk/agents/BaseAgentConfig.java b/core/src/main/java/com/google/adk/agents/BaseAgentConfig.java index c66b48829..7f2f3df7c 100644 --- a/core/src/main/java/com/google/adk/agents/BaseAgentConfig.java +++ b/core/src/main/java/com/google/adk/agents/BaseAgentConfig.java @@ -17,10 +17,12 @@ package com.google.adk.agents; import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.adk.utils.FeatureDecorator.WorkInProgress; -/** Base configuration for all agents. */ -@WorkInProgress +/** + * Base configuration for all agents. + * + *

workInProgress: Config agent features are not yet ready for public use. + */ public class BaseAgentConfig { private String name; private String description = ""; diff --git a/core/src/main/java/com/google/adk/agents/LlmAgentConfig.java b/core/src/main/java/com/google/adk/agents/LlmAgentConfig.java index e9d4ed47b..74a360c16 100644 --- a/core/src/main/java/com/google/adk/agents/LlmAgentConfig.java +++ b/core/src/main/java/com/google/adk/agents/LlmAgentConfig.java @@ -17,10 +17,12 @@ package com.google.adk.agents; import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.adk.utils.FeatureDecorator.WorkInProgress; -/** Configuration for LlmAgent. */ -@WorkInProgress +/** + * Configuration for LlmAgent. + * + *

workInProgress: Config agent features are not yet ready for public use. + */ public class LlmAgentConfig extends BaseAgentConfig { private String model; private String instruction; diff --git a/core/src/main/java/com/google/adk/utils/FeatureDecorator.java b/core/src/main/java/com/google/adk/utils/FeatureDecorator.java deleted file mode 100644 index 3f5e5c057..000000000 --- a/core/src/main/java/com/google/adk/utils/FeatureDecorator.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.adk.utils; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.util.Locale; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A utility class for handling feature decorators. - * - *

This class provides methods for checking for feature decorators on classes and methods and - * handling them appropriately. - */ -public final class FeatureDecorator { - - /** - * Mark a class or a function as a work in progress. - * - *

By default, decorated functions/classes will raise RuntimeError when used. Set - * ADK_ALLOW_WIP_FEATURES=true environment variable to bypass this restriction. ADK users are not - * supposed to set this environment variable. - * - *

Sample usage: - * - *

-   * {@literal @}WorkInProgress("This feature is not ready for production use.")
-   * public void myWipFunction() {
-   *   // ...
-   * }
-   * 
- */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR}) - public @interface WorkInProgress { - /** - * The message to be displayed when the feature is used. If not provided, a default message will - * be used. - */ - String value() default - "This feature is a work in progress and is not working completely. ADK users are not" - + " supposed to use it."; - } - - /** - * Mark a class or a function as an experimental feature. - * - *

Sample usage: - * - *

-   * // Use with default message
-   * {@literal @}Experimental
-   * public class ExperimentalClass {
-   *   // ...
-   * }
-   *
-   * // Use with custom message
-   * {@literal @}Experimental("This API may have breaking change in the future.")
-   * public class CustomExperimentalClass {
-   *   // ...
-   * }
-   * 
- */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR}) - public @interface Experimental { - /** - * The message to be displayed when the feature is used. If not provided, a default message will - * be used. - */ - String value() default - "This feature is experimental and may change or be removed in future versions without" - + " notice. It may introduce breaking changes at any time."; - } - - private static final Logger logger = LoggerFactory.getLogger(FeatureDecorator.class); - - /** - * Handles the feature decorators for the given class. - * - * @param clazz the class to handle the decorators for - */ - public static void handle(Class clazz) { - handleExperimental(clazz); - handleWorkInProgress(clazz); - } - - /** - * Handles the feature decorators for the given method. - * - * @param method the method to handle the decorators for - */ - public static void handle(Method method) { - handleExperimental(method); - handleWorkInProgress(method); - } - - /** - * Handles the feature decorators for the given constructor. - * - * @param constructor the constructor to handle the decorators for - */ - public static void handle(Constructor constructor) { - handleExperimental(constructor); - handleWorkInProgress(constructor); - } - - private static void handleExperimental(AnnotatedElement element) { - if (element.isAnnotationPresent(Experimental.class)) { - Experimental annotation = element.getAnnotation(Experimental.class); - String message = annotation.value(); - logger.warn("[EXPERIMENTAL] {}: {}", getElementName(element), message); - } - } - - private static void handleWorkInProgress(AnnotatedElement element) { - if (element.isAnnotationPresent(WorkInProgress.class)) { - String bypassEnvVar = "ADK_ALLOW_WIP_FEATURES"; - String envValue = System.getenv(bypassEnvVar); - if (envValue == null || !envValue.toLowerCase(Locale.ROOT).equals("true")) { - WorkInProgress annotation = element.getAnnotation(WorkInProgress.class); - String message = annotation.value(); - throw new UnsupportedOperationException( - "[WIP] " + getElementName(element) + ": " + message); - } - } - } - - private static String getElementName(AnnotatedElement element) { - if (element instanceof Class) { - return ((Class) element).getSimpleName(); - } else if (element instanceof Method method) { - return method.getName(); - } else if (element instanceof Constructor) { - return ((Constructor) element).getDeclaringClass().getSimpleName(); - } - return "UnknownElement"; - } - - private FeatureDecorator() {} -} diff --git a/core/src/test/java/com/google/adk/utils/FeatureDecoratorTest.java b/core/src/test/java/com/google/adk/utils/FeatureDecoratorTest.java deleted file mode 100644 index d77f5af20..000000000 --- a/core/src/test/java/com/google/adk/utils/FeatureDecoratorTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.adk.utils; - -import static org.junit.Assert.assertThrows; -import static org.junit.Assert.assertTrue; - -import com.google.adk.utils.FeatureDecorator.Experimental; -import com.google.adk.utils.FeatureDecorator.WorkInProgress; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public final class FeatureDecoratorTest { - - @WorkInProgress("This is a WIP class.") - private static class WipClass {} - - @Experimental("This is an experimental class.") - private static class ExperimentalClass {} - - private static class TestClass { - @WorkInProgress("This is a WIP method.") - @SuppressWarnings("unused") // Used via reflection in tests - private void wipMethod() {} - - @Experimental("This is an experimental method.") - @SuppressWarnings("unused") // Used via reflection in tests - private void experimentalMethod() {} - } - - @Test - public void handle_wipClass_throwsException() { - UnsupportedOperationException exception = - assertThrows( - UnsupportedOperationException.class, () -> FeatureDecorator.handle(WipClass.class)); - - assertTrue(exception.getMessage().contains("[WIP] WipClass: This is a WIP class.")); - } - - @Test - public void handle_wipMethod_throwsException() throws NoSuchMethodException { - UnsupportedOperationException exception = - assertThrows( - UnsupportedOperationException.class, - () -> FeatureDecorator.handle(TestClass.class.getDeclaredMethod("wipMethod"))); - - assertTrue(exception.getMessage().contains("[WIP] wipMethod: This is a WIP method.")); - } - - @Test - public void handle_experimentalClass_doesNotThrow() { - // Simply verify that handling experimental classes doesn't throw - FeatureDecorator.handle(ExperimentalClass.class); - // If we get here without exception, the test passes - } - - @Test - public void handle_experimentalMethod_doesNotThrow() throws NoSuchMethodException { - // Simply verify that handling experimental methods doesn't throw - FeatureDecorator.handle(TestClass.class.getDeclaredMethod("experimentalMethod")); - // If we get here without exception, the test passes - } - - @Test - public void handle_normalClass_doesNotThrow() { - // Verify that handling non-annotated classes works fine - FeatureDecorator.handle(TestClass.class); - } -}