diff --git a/src/google/adk/agents/agent_config.py b/src/google/adk/agents/agent_config.py index 1d9f36fb..9e1e1d43 100644 --- a/src/google/adk/agents/agent_config.py +++ b/src/google/adk/agents/agent_config.py @@ -22,8 +22,8 @@ from pydantic import RootModel from ..utils.feature_decorator import working_in_progress from .base_agent import BaseAgentConfig -from .llm_agent import LlmAgentConfig -from .loop_agent import LoopAgentConfig +from .llm_agent_config import LlmAgentConfig +from .loop_agent_config import LoopAgentConfig from .parallel_agent import ParallelAgentConfig from .sequential_agent import SequentialAgentConfig diff --git a/src/google/adk/agents/config_agent_utils.py b/src/google/adk/agents/config_agent_utils.py index 5da6a211..9e590136 100644 --- a/src/google/adk/agents/config_agent_utils.py +++ b/src/google/adk/agents/config_agent_utils.py @@ -27,9 +27,9 @@ from .base_agent import BaseAgent from .base_agent_config import SubAgentConfig from .common_configs import CodeConfig from .llm_agent import LlmAgent -from .llm_agent import LlmAgentConfig +from .llm_agent_config import LlmAgentConfig from .loop_agent import LoopAgent -from .loop_agent import LoopAgentConfig +from .loop_agent_config import LoopAgentConfig from .parallel_agent import ParallelAgent from .parallel_agent import ParallelAgentConfig from .sequential_agent import SequentialAgent diff --git a/src/google/adk/agents/llm_agent.py b/src/google/adk/agents/llm_agent.py index b193f577..170bec5e 100644 --- a/src/google/adk/agents/llm_agent.py +++ b/src/google/adk/agents/llm_agent.py @@ -21,7 +21,6 @@ from typing import Any from typing import AsyncGenerator from typing import Awaitable from typing import Callable -from typing import List from typing import Literal from typing import Optional from typing import Type @@ -29,7 +28,6 @@ from typing import Union from google.genai import types from pydantic import BaseModel -from pydantic import ConfigDict from pydantic import Field from pydantic import field_validator from pydantic import model_validator @@ -54,10 +52,10 @@ from ..tools.function_tool import FunctionTool from ..tools.tool_context import ToolContext from ..utils.feature_decorator import working_in_progress from .base_agent import BaseAgent -from .base_agent_config import BaseAgentConfig from .callback_context import CallbackContext from .common_configs import CodeConfig from .invocation_context import InvocationContext +from .llm_agent_config import LlmAgentConfig from .readonly_context import ReadonlyContext logger = logging.getLogger('google_adk.' + __name__) @@ -603,115 +601,3 @@ class LlmAgent(BaseAgent): Agent: TypeAlias = LlmAgent - - -class LlmAgentConfig(BaseAgentConfig): - """The config for the YAML schema of a LlmAgent.""" - - model_config = ConfigDict( - extra='forbid', - ) - - agent_class: Literal['LlmAgent', ''] = 'LlmAgent' - """The value is used to uniquely identify the LlmAgent class. If it is - empty, it is by default an LlmAgent.""" - - model: Optional[str] = None - """Optional. LlmAgent.model. If not set, the model will be inherited from - the ancestor.""" - - instruction: str - """Required. LlmAgent.instruction.""" - - disallow_transfer_to_parent: Optional[bool] = None - """Optional. LlmAgent.disallow_transfer_to_parent.""" - - disallow_transfer_to_peers: Optional[bool] = None - """Optional. LlmAgent.disallow_transfer_to_peers.""" - - input_schema: Optional[CodeConfig] = None - """Optional. LlmAgent.input_schema.""" - - output_schema: Optional[CodeConfig] = None - """Optional. LlmAgent.output_schema.""" - - output_key: Optional[str] = None - """Optional. LlmAgent.output_key.""" - - include_contents: Literal['default', 'none'] = 'default' - """Optional. LlmAgent.include_contents.""" - - tools: Optional[list[CodeConfig]] = None - """Optional. LlmAgent.tools. - - Examples: - - For ADK built-in tools in `google.adk.tools` package, they can be referenced - directly with the name: - - ``` - tools: - - name: google_search - - name: load_memory - ``` - - For user-defined tools, they can be referenced with fully qualified name: - - ``` - tools: - - name: my_library.my_tools.my_tool - ``` - - For tools that needs to be created via functions: - - ``` - tools: - - name: my_library.my_tools.create_tool - args: - - name: param1 - value: value1 - - name: param2 - value: value2 - ``` - - For more advanced tools, instead of specifying arguments in config, it's - recommended to define them in Python files and reference them. E.g., - - ``` - # tools.py - my_mcp_toolset = MCPToolset( - connection_params=StdioServerParameters( - command="npx", - args=["-y", "@notionhq/notion-mcp-server"], - env={"OPENAPI_MCP_HEADERS": NOTION_HEADERS}, - ) - ) - ``` - - Then, reference the toolset in config: - - ``` - tools: - - name: tools.my_mcp_toolset - ``` - """ - - before_model_callbacks: Optional[List[CodeConfig]] = None - """Optional. LlmAgent.before_model_callbacks. - - Example: - - ``` - before_model_callbacks: - - name: my_library.callbacks.before_model_callback - ``` - """ - - after_model_callbacks: Optional[List[CodeConfig]] = None - """Optional. LlmAgent.after_model_callbacks.""" - - before_tool_callbacks: Optional[List[CodeConfig]] = None - """Optional. LlmAgent.before_tool_callbacks.""" - - after_tool_callbacks: Optional[List[CodeConfig]] = None - """Optional. LlmAgent.after_tool_callbacks.""" diff --git a/src/google/adk/agents/llm_agent_config.py b/src/google/adk/agents/llm_agent_config.py new file mode 100644 index 00000000..a99ea3ce --- /dev/null +++ b/src/google/adk/agents/llm_agent_config.py @@ -0,0 +1,139 @@ +# 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. + +from __future__ import annotations + +import logging +from typing import List +from typing import Literal +from typing import Optional + +from pydantic import ConfigDict + +from .base_agent_config import BaseAgentConfig +from .common_configs import CodeConfig + +logger = logging.getLogger('google_adk.' + __name__) + + +class LlmAgentConfig(BaseAgentConfig): + """The config for the YAML schema of a LlmAgent.""" + + model_config = ConfigDict( + extra='forbid', + ) + + agent_class: Literal['LlmAgent', ''] = 'LlmAgent' + """The value is used to uniquely identify the LlmAgent class. If it is + empty, it is by default an LlmAgent.""" + + model: Optional[str] = None + """Optional. LlmAgent.model. If not set, the model will be inherited from + the ancestor.""" + + instruction: str + """Required. LlmAgent.instruction.""" + + disallow_transfer_to_parent: Optional[bool] = None + """Optional. LlmAgent.disallow_transfer_to_parent.""" + + disallow_transfer_to_peers: Optional[bool] = None + """Optional. LlmAgent.disallow_transfer_to_peers.""" + + input_schema: Optional[CodeConfig] = None + """Optional. LlmAgent.input_schema.""" + + output_schema: Optional[CodeConfig] = None + """Optional. LlmAgent.output_schema.""" + + output_key: Optional[str] = None + """Optional. LlmAgent.output_key.""" + + include_contents: Literal['default', 'none'] = 'default' + """Optional. LlmAgent.include_contents.""" + + tools: Optional[list[CodeConfig]] = None + """Optional. LlmAgent.tools. + + Examples: + + For ADK built-in tools in `google.adk.tools` package, they can be referenced + directly with the name: + + ``` + tools: + - name: google_search + - name: load_memory + ``` + + For user-defined tools, they can be referenced with fully qualified name: + + ``` + tools: + - name: my_library.my_tools.my_tool + ``` + + For tools that needs to be created via functions: + + ``` + tools: + - name: my_library.my_tools.create_tool + args: + - name: param1 + value: value1 + - name: param2 + value: value2 + ``` + + For more advanced tools, instead of specifying arguments in config, it's + recommended to define them in Python files and reference them. E.g., + + ``` + # tools.py + my_mcp_toolset = MCPToolset( + connection_params=StdioServerParameters( + command="npx", + args=["-y", "@notionhq/notion-mcp-server"], + env={"OPENAPI_MCP_HEADERS": NOTION_HEADERS}, + ) + ) + ``` + + Then, reference the toolset in config: + + ``` + tools: + - name: tools.my_mcp_toolset + ``` + """ + + before_model_callbacks: Optional[List[CodeConfig]] = None + """Optional. LlmAgent.before_model_callbacks. + + Example: + + ``` + before_model_callbacks: + - name: my_library.callbacks.before_model_callback + ``` + """ + + after_model_callbacks: Optional[List[CodeConfig]] = None + """Optional. LlmAgent.after_model_callbacks.""" + + before_tool_callbacks: Optional[List[CodeConfig]] = None + """Optional. LlmAgent.before_tool_callbacks.""" + + after_tool_callbacks: Optional[List[CodeConfig]] = None + """Optional. LlmAgent.after_tool_callbacks.""" diff --git a/src/google/adk/agents/loop_agent.py b/src/google/adk/agents/loop_agent.py index 4fc0f166..c093c4ac 100644 --- a/src/google/adk/agents/loop_agent.py +++ b/src/google/adk/agents/loop_agent.py @@ -17,18 +17,16 @@ from __future__ import annotations from typing import AsyncGenerator -from typing import Literal from typing import Optional from typing import Type -from pydantic import ConfigDict from typing_extensions import override from ..agents.invocation_context import InvocationContext from ..events.event import Event from ..utils.feature_decorator import working_in_progress from .base_agent import BaseAgent -from .base_agent_config import BaseAgentConfig +from .loop_agent_config import LoopAgentConfig class LoopAgent(BaseAgent): @@ -83,17 +81,3 @@ class LoopAgent(BaseAgent): if config.max_iterations: agent.max_iterations = config.max_iterations return agent - - -@working_in_progress('LoopAgentConfig is not ready for use.') -class LoopAgentConfig(BaseAgentConfig): - """The config for the YAML schema of a LoopAgent.""" - - model_config = ConfigDict( - extra='forbid', - ) - - agent_class: Literal['LoopAgent'] = 'LoopAgent' - - max_iterations: Optional[int] = None - """Optional. LoopAgent.max_iterations.""" diff --git a/src/google/adk/agents/loop_agent_config.py b/src/google/adk/agents/loop_agent_config.py new file mode 100644 index 00000000..c50785c7 --- /dev/null +++ b/src/google/adk/agents/loop_agent_config.py @@ -0,0 +1,39 @@ +# 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. + +"""Loop agent implementation.""" + +from __future__ import annotations + +from typing import Literal +from typing import Optional + +from pydantic import ConfigDict + +from ..utils.feature_decorator import working_in_progress +from .base_agent_config import BaseAgentConfig + + +@working_in_progress('LoopAgentConfig is not ready for use.') +class LoopAgentConfig(BaseAgentConfig): + """The config for the YAML schema of a LoopAgent.""" + + model_config = ConfigDict( + extra='forbid', + ) + + agent_class: Literal['LoopAgent'] = 'LoopAgent' + + max_iterations: Optional[int] = None + """Optional. LoopAgent.max_iterations.""" diff --git a/src/google/adk/agents/parallel_agent.py b/src/google/adk/agents/parallel_agent.py index 99f4f486..cb747bcb 100644 --- a/src/google/adk/agents/parallel_agent.py +++ b/src/google/adk/agents/parallel_agent.py @@ -18,17 +18,15 @@ from __future__ import annotations import asyncio from typing import AsyncGenerator -from typing import Literal from typing import Type -from pydantic import ConfigDict from typing_extensions import override -from ..agents.base_agent import working_in_progress -from ..agents.base_agent_config import BaseAgentConfig -from ..agents.invocation_context import InvocationContext from ..events.event import Event +from ..utils.feature_decorator import working_in_progress from .base_agent import BaseAgent +from .invocation_context import InvocationContext +from .parallel_agent_config import ParallelAgentConfig def _create_branch_ctx_for_sub_agent( @@ -126,14 +124,3 @@ class ParallelAgent(BaseAgent): config_abs_path: str, ) -> ParallelAgent: return super().from_config(config, config_abs_path) - - -@working_in_progress('ParallelAgentConfig is not ready for use.') -class ParallelAgentConfig(BaseAgentConfig): - """The config for the YAML schema of a ParallelAgent.""" - - model_config = ConfigDict( - extra='forbid', - ) - - agent_class: Literal['ParallelAgent'] = 'ParallelAgent' diff --git a/src/google/adk/agents/parallel_agent_config.py b/src/google/adk/agents/parallel_agent_config.py new file mode 100644 index 00000000..ce6a936e --- /dev/null +++ b/src/google/adk/agents/parallel_agent_config.py @@ -0,0 +1,35 @@ +# 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. + +"""Parallel agent implementation.""" + +from __future__ import annotations + +from typing import Literal + +from pydantic import ConfigDict + +from ..utils.feature_decorator import working_in_progress +from .base_agent_config import BaseAgentConfig + + +@working_in_progress('ParallelAgentConfig is not ready for use.') +class ParallelAgentConfig(BaseAgentConfig): + """The config for the YAML schema of a ParallelAgent.""" + + model_config = ConfigDict( + extra='forbid', + ) + + agent_class: Literal['ParallelAgent'] = 'ParallelAgent' diff --git a/src/google/adk/agents/sequential_agent.py b/src/google/adk/agents/sequential_agent.py index 4ca282de..e5b7bdd2 100644 --- a/src/google/adk/agents/sequential_agent.py +++ b/src/google/adk/agents/sequential_agent.py @@ -17,18 +17,16 @@ from __future__ import annotations from typing import AsyncGenerator -from typing import Literal from typing import Type -from pydantic import ConfigDict from typing_extensions import override -from ..agents.base_agent import working_in_progress -from ..agents.base_agent_config import BaseAgentConfig -from ..agents.invocation_context import InvocationContext from ..events.event import Event +from ..utils.feature_decorator import working_in_progress from .base_agent import BaseAgent +from .invocation_context import InvocationContext from .llm_agent import LlmAgent +from .sequential_agent_config import SequentialAgentConfig class SequentialAgent(BaseAgent): @@ -89,14 +87,3 @@ class SequentialAgent(BaseAgent): config_abs_path: str, ) -> SequentialAgent: return super().from_config(config, config_abs_path) - - -@working_in_progress('SequentialAgentConfig is not ready for use.') -class SequentialAgentConfig(BaseAgentConfig): - """The config for the YAML schema of a SequentialAgent.""" - - model_config = ConfigDict( - extra='forbid', - ) - - agent_class: Literal['SequentialAgent'] = 'SequentialAgent' diff --git a/src/google/adk/agents/sequential_agent_config.py b/src/google/adk/agents/sequential_agent_config.py new file mode 100644 index 00000000..d8660aea --- /dev/null +++ b/src/google/adk/agents/sequential_agent_config.py @@ -0,0 +1,35 @@ +# 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. + +"""Config definition for SequentialAgent.""" + +from __future__ import annotations + +from typing import Literal + +from pydantic import ConfigDict + +from ..agents.base_agent import working_in_progress +from ..agents.base_agent_config import BaseAgentConfig + + +@working_in_progress('SequentialAgentConfig is not ready for use.') +class SequentialAgentConfig(BaseAgentConfig): + """The config for the YAML schema of a SequentialAgent.""" + + model_config = ConfigDict( + extra='forbid', + ) + + agent_class: Literal['SequentialAgent'] = 'SequentialAgent' diff --git a/tests/unittests/agents/test_agent_config.py b/tests/unittests/agents/test_agent_config.py index 38954eab..b24f8728 100644 --- a/tests/unittests/agents/test_agent_config.py +++ b/tests/unittests/agents/test_agent_config.py @@ -1,11 +1,11 @@ from typing import Literal from google.adk.agents.agent_config import AgentConfig -from google.adk.agents.agent_config import LlmAgentConfig -from google.adk.agents.agent_config import LoopAgentConfig -from google.adk.agents.agent_config import ParallelAgentConfig -from google.adk.agents.agent_config import SequentialAgentConfig from google.adk.agents.base_agent_config import BaseAgentConfig +from google.adk.agents.llm_agent_config import LlmAgentConfig +from google.adk.agents.loop_agent_config import LoopAgentConfig +from google.adk.agents.parallel_agent_config import ParallelAgentConfig +from google.adk.agents.sequential_agent_config import SequentialAgentConfig import yaml