feat: modularize fast_api.py to allow simpler construction of API Server

PiperOrigin-RevId: 786646546
This commit is contained in:
Google Team Member
2025-07-24 04:02:26 -07:00
committed by Copybara-Service
parent 5e8aa15a50
commit bfc203a92f
7 changed files with 901 additions and 1175 deletions
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -19,11 +19,11 @@ from typing import Union
import graphviz
from ..agents.base_agent import BaseAgent
from ..agents import BaseAgent
from ..agents import LoopAgent
from ..agents import ParallelAgent
from ..agents import SequentialAgent
from ..agents.llm_agent import LlmAgent
from ..agents.loop_agent import LoopAgent
from ..agents.parallel_agent import ParallelAgent
from ..agents.sequential_agent import SequentialAgent
from ..tools.agent_tool import AgentTool
from ..tools.base_tool import BaseTool
from ..tools.function_tool import FunctionTool
File diff suppressed because it is too large Load Diff
+25 -1
View File
@@ -18,8 +18,32 @@ from typing import Optional
from ...agents.base_agent import BaseAgent
from ...agents.llm_agent import LlmAgent
from .state import create_empty_state
__all__ = [
'create_empty_state',
]
def _create_empty_state(agent: BaseAgent, all_state: dict[str, Any]):
for sub_agent in agent.sub_agents:
_create_empty_state(sub_agent, all_state)
if (
isinstance(agent, LlmAgent)
and agent.instruction
and isinstance(agent.instruction, str)
):
for key in re.findall(r'{([\w]+)}', agent.instruction):
all_state[key] = ''
def create_empty_state(
agent: BaseAgent, initialized_states: Optional[dict[str, Any]] = None
) -> dict[str, Any]:
"""Creates empty str for non-initialized states."""
non_initialized_states = {}
_create_empty_state(agent, non_initialized_states)
for key in initialized_states or {}:
if key in non_initialized_states:
del non_initialized_states[key]
return non_initialized_states
@@ -1,45 +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.
"""File system event handler for agent changes to trigger hot reload for agents."""
from __future__ import annotations
import logging
from watchdog.events import FileSystemEventHandler
from .agent_loader import AgentLoader
from .shared_value import SharedValue
logger = logging.getLogger("google_adk." + __name__)
class AgentChangeEventHandler(FileSystemEventHandler):
def __init__(
self,
agent_loader: AgentLoader,
runners_to_clean: set[str],
current_app_name_ref: SharedValue[str],
):
self.agent_loader = agent_loader
self.runners_to_clean = runners_to_clean
self.current_app_name_ref = current_app_name_ref
def on_modified(self, event):
if not (event.src_path.endswith(".py") or event.src_path.endswith(".yaml")):
return
logger.info("Change detected in agents directory: %s", event.src_path)
self.agent_loader.remove_agent_from_cache(self.current_app_name_ref.value)
self.runners_to_clean.add(self.current_app_name_ref.value)
-30
View File
@@ -1,30 +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.
from __future__ import annotations
from typing import Generic
from typing import TypeVar
import pydantic
T = TypeVar("T")
class SharedValue(pydantic.BaseModel, Generic[T]):
"""Simple wrapper around a value to allow modifying it from callbacks."""
model_config = pydantic.ConfigDict(
arbitrary_types_allowed=True,
)
value: T
-47
View File
@@ -1,47 +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.
from __future__ import annotations
import re
from typing import Any
from typing import Optional
from ...agents.base_agent import BaseAgent
from ...agents.llm_agent import LlmAgent
def _create_empty_state(agent: BaseAgent, all_state: dict[str, Any]):
for sub_agent in agent.sub_agents:
_create_empty_state(sub_agent, all_state)
if (
isinstance(agent, LlmAgent)
and agent.instruction
and isinstance(agent.instruction, str)
):
for key in re.findall(r'{([\w]+)}', agent.instruction):
all_state[key] = ''
def create_empty_state(
agent: BaseAgent, initialized_states: Optional[dict[str, Any]] = None
) -> dict[str, Any]:
"""Creates empty str for non-initialized states."""
non_initialized_states = {}
_create_empty_state(agent, non_initialized_states)
for key in initialized_states or {}:
if key in non_initialized_states:
del non_initialized_states[key]
return non_initialized_states