mirror of
https://github.com/encounter/adk-python.git
synced 2026-07-09 18:19:28 -07:00
feat(config): add APIs for building config agents
Including basic fields in configs, the from_config() methods and the JSON schema. Other fields will be added in following PRs. PiperOrigin-RevId: 781660569
This commit is contained in:
committed by
Copybara-Service
parent
fb2415395f
commit
ca396a3ab1
@@ -0,0 +1,42 @@
|
||||
# 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
|
||||
|
||||
from typing import Union
|
||||
|
||||
from pydantic import RootModel
|
||||
|
||||
from ..utils.feature_decorator import working_in_progress
|
||||
from .llm_agent import LlmAgentConfig
|
||||
from .loop_agent import LoopAgentConfig
|
||||
|
||||
# A discriminated union of all possible agent configurations.
|
||||
ConfigsUnion = Union[
|
||||
LlmAgentConfig,
|
||||
LoopAgentConfig,
|
||||
]
|
||||
|
||||
|
||||
# Use a RootModel to represent the agent directly at the top level.
|
||||
# The `discriminator` is applied to the union within the RootModel.
|
||||
@working_in_progress("AgentConfig is not ready for use.")
|
||||
class AgentConfig(RootModel[ConfigsUnion]):
|
||||
"""The config for the YAML schema to create an agent."""
|
||||
|
||||
class Config:
|
||||
# Pydantic v2 requires this for discriminated unions on RootModel
|
||||
# This tells the model to look at the 'agent_class' field of the input
|
||||
# data to decide which model from the `ConfigsUnion` to use.
|
||||
discriminator = "agent_class"
|
||||
@@ -19,9 +19,12 @@ from typing import Any
|
||||
from typing import AsyncGenerator
|
||||
from typing import Awaitable
|
||||
from typing import Callable
|
||||
from typing import Dict
|
||||
from typing import final
|
||||
from typing import Literal
|
||||
from typing import Mapping
|
||||
from typing import Optional
|
||||
from typing import Type
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TypeVar
|
||||
from typing import Union
|
||||
@@ -36,6 +39,7 @@ from typing_extensions import override
|
||||
from typing_extensions import TypeAlias
|
||||
|
||||
from ..events.event import Event
|
||||
from ..utils.feature_decorator import working_in_progress
|
||||
from .callback_context import CallbackContext
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -439,3 +443,49 @@ class BaseAgent(BaseModel):
|
||||
)
|
||||
sub_agent.parent_agent = self
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
@working_in_progress('BaseAgent.from_config is not ready for use.')
|
||||
def from_config(
|
||||
cls: Type[SelfAgent],
|
||||
config: BaseAgentConfig,
|
||||
) -> SelfAgent:
|
||||
"""Creates an agent from a config.
|
||||
|
||||
This method converts fields in a config to the corresponding
|
||||
fields in an agent.
|
||||
|
||||
Child classes should re-implement this method to support loading from their
|
||||
custom config types.
|
||||
|
||||
Args:
|
||||
config: The config to create the agent from.
|
||||
|
||||
Returns:
|
||||
The created agent.
|
||||
"""
|
||||
kwargs: Dict[str, Any] = {
|
||||
'name': config.name,
|
||||
'description': config.description,
|
||||
}
|
||||
return cls(**kwargs)
|
||||
|
||||
|
||||
@working_in_progress('BaseAgentConfig is not ready for use.')
|
||||
class BaseAgentConfig(BaseModel):
|
||||
"""The config for the YAML schema of a BaseAgent.
|
||||
|
||||
Do not use this class directly. It's the base class for all agent configs.
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(extra='forbid')
|
||||
|
||||
agent_class: Literal['BaseAgent'] = 'BaseAgent'
|
||||
"""Required. The class of the agent. The value is used to differentiate
|
||||
among different agent classes."""
|
||||
|
||||
name: str
|
||||
"""Required. The name of the agent."""
|
||||
|
||||
description: str = ''
|
||||
"""Optional. The description of the agent."""
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"$defs": {
|
||||
"LlmAgentConfig": {
|
||||
"additionalProperties": false,
|
||||
"description": "The config for the YAML schema of a LlmAgent.",
|
||||
"properties": {
|
||||
"agent_class": {
|
||||
"default": "LlmAgent",
|
||||
"enum": [
|
||||
"LlmAgent",
|
||||
""
|
||||
],
|
||||
"title": "Agent Class",
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"title": "Name",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"default": "",
|
||||
"title": "Description",
|
||||
"type": "string"
|
||||
},
|
||||
"model": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null,
|
||||
"title": "Model"
|
||||
},
|
||||
"instruction": {
|
||||
"title": "Instruction",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"instruction"
|
||||
],
|
||||
"title": "LlmAgentConfig",
|
||||
"type": "object"
|
||||
},
|
||||
"LoopAgentConfig": {
|
||||
"additionalProperties": false,
|
||||
"description": "The config for the YAML schema of a LoopAgent.",
|
||||
"properties": {
|
||||
"agent_class": {
|
||||
"const": "LoopAgent",
|
||||
"default": "LoopAgent",
|
||||
"title": "Agent Class",
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"title": "Name",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"default": "",
|
||||
"title": "Description",
|
||||
"type": "string"
|
||||
},
|
||||
"max_iterations": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null,
|
||||
"title": "Max Iterations"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"title": "LoopAgentConfig",
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/$defs/LlmAgentConfig"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/LoopAgentConfig"
|
||||
}
|
||||
],
|
||||
"description": "The config for the YAML schema to create an agent.",
|
||||
"title": "AgentConfig"
|
||||
}
|
||||
@@ -20,8 +20,10 @@ from typing import Any
|
||||
from typing import AsyncGenerator
|
||||
from typing import Awaitable
|
||||
from typing import Callable
|
||||
from typing import Dict
|
||||
from typing import Literal
|
||||
from typing import Optional
|
||||
from typing import Type
|
||||
from typing import Union
|
||||
|
||||
from google.genai import types
|
||||
@@ -48,7 +50,9 @@ from ..tools.base_tool import BaseTool
|
||||
from ..tools.base_toolset import BaseToolset
|
||||
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 import BaseAgentConfig
|
||||
from .callback_context import CallbackContext
|
||||
from .invocation_context import InvocationContext
|
||||
from .readonly_context import ReadonlyContext
|
||||
@@ -516,5 +520,34 @@ class LlmAgent(BaseAgent):
|
||||
)
|
||||
return generate_content_config
|
||||
|
||||
@classmethod
|
||||
@override
|
||||
@working_in_progress('LlmAgent.from_config is not ready for use.')
|
||||
def from_config(
|
||||
cls: Type[LlmAgent],
|
||||
config: LlmAgentConfig,
|
||||
) -> LlmAgent:
|
||||
agent = super().from_config(config)
|
||||
if config.model:
|
||||
agent.model = config.model
|
||||
if config.instruction:
|
||||
agent.instruction = config.instruction
|
||||
return agent
|
||||
|
||||
|
||||
Agent: TypeAlias = LlmAgent
|
||||
|
||||
|
||||
class LlmAgentConfig(BaseAgentConfig):
|
||||
"""The config for the YAML schema of a LlmAgent."""
|
||||
|
||||
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."""
|
||||
|
||||
@@ -16,14 +16,20 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from typing import AsyncGenerator
|
||||
from typing import Dict
|
||||
from typing import Literal
|
||||
from typing import Optional
|
||||
from typing import Type
|
||||
|
||||
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 import BaseAgentConfig
|
||||
|
||||
|
||||
class LoopAgent(BaseAgent):
|
||||
@@ -60,3 +66,25 @@ class LoopAgent(BaseAgent):
|
||||
) -> AsyncGenerator[Event, None]:
|
||||
raise NotImplementedError('This is not supported yet for LoopAgent.')
|
||||
yield # AsyncGenerator requires having at least one yield statement
|
||||
|
||||
@classmethod
|
||||
@override
|
||||
@working_in_progress('LoopAgent.from_config is not ready for use.')
|
||||
def from_config(
|
||||
cls: Type[LoopAgent],
|
||||
config: LoopAgentConfig,
|
||||
) -> LoopAgent:
|
||||
agent = super().from_config(config)
|
||||
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."""
|
||||
|
||||
agent_class: Literal['LoopAgent'] = 'LoopAgent'
|
||||
|
||||
max_iterations: Optional[int] = None
|
||||
"""Optional. LoopAgent.max_iterations."""
|
||||
|
||||
Reference in New Issue
Block a user