1515from __future__ import annotations
1616
1717import importlib
18+ import inspect
1819import os
1920from typing import Any
2021from typing import List
2425from ..utils .feature_decorator import working_in_progress
2526from .agent_config import AgentConfig
2627from .base_agent import BaseAgent
28+ from .base_agent_config import BaseAgentConfig
2729from .common_configs import AgentRefConfig
2830from .common_configs import CodeConfig
29- from .llm_agent import LlmAgent
30- from .llm_agent_config import LlmAgentConfig
31- from .loop_agent import LoopAgent
32- from .loop_agent_config import LoopAgentConfig
33- from .parallel_agent import ParallelAgent
34- from .parallel_agent import ParallelAgentConfig
35- from .sequential_agent import SequentialAgent
36- from .sequential_agent import SequentialAgentConfig
3731
3832
3933@working_in_progress ("from_config is not ready for use." )
@@ -53,17 +47,36 @@ def from_config(config_path: str) -> BaseAgent:
5347 """
5448 abs_path = os .path .abspath (config_path )
5549 config = _load_config_from_path (abs_path )
56-
57- if isinstance (config .root , LlmAgentConfig ):
58- return LlmAgent .from_config (config .root , abs_path )
59- elif isinstance (config .root , LoopAgentConfig ):
60- return LoopAgent .from_config (config .root , abs_path )
61- elif isinstance (config .root , ParallelAgentConfig ):
62- return ParallelAgent .from_config (config .root , abs_path )
63- elif isinstance (config .root , SequentialAgentConfig ):
64- return SequentialAgent .from_config (config .root , abs_path )
50+ agent_config = config .root
51+
52+ # pylint: disable=unidiomatic-typecheck Needs exact class matching.
53+ if type (agent_config ) is BaseAgentConfig :
54+ # Resolve the concrete agent config for user-defined agent classes.
55+ agent_class = _resolve_agent_class (agent_config .agent_class )
56+ agent_config = agent_class .config_type .model_validate (
57+ agent_config .model_dump ()
58+ )
59+ return agent_class .from_config (agent_config , abs_path )
6560 else :
66- raise ValueError ("Unsupported config type" )
61+ # For built-in agent classes, no need to re-validate.
62+ agent_class = _resolve_agent_class (agent_config .agent_class )
63+ return agent_class .from_config (agent_config , abs_path )
64+
65+
66+ def _resolve_agent_class (agent_class : str ) -> type [BaseAgent ]:
67+ """Resolve the agent class from its fully qualified name."""
68+ agent_class_name = agent_class or "LlmAgent"
69+ if "." not in agent_class_name :
70+ agent_class_name = f"google.adk.agents.{ agent_class_name } "
71+
72+ agent_class = _resolve_fully_qualified_name (agent_class_name )
73+ if inspect .isclass (agent_class ) and issubclass (agent_class , BaseAgent ):
74+ return agent_class
75+
76+ raise ValueError (
77+ f"Invalid agent class `{ agent_class_name } `. It must be a subclass of"
78+ " BaseAgent."
79+ )
6780
6881
6982@working_in_progress ("_load_config_from_path is not ready for use." )
@@ -90,6 +103,16 @@ def _load_config_from_path(config_path: str) -> AgentConfig:
90103 return AgentConfig .model_validate (config_data )
91104
92105
106+ @working_in_progress ("_resolve_fully_qualified_name is not ready for use." )
107+ def _resolve_fully_qualified_name (name : str ) -> Any :
108+ try :
109+ module_path , obj_name = name .rsplit ("." , 1 )
110+ module = importlib .import_module (module_path )
111+ return getattr (module , obj_name )
112+ except Exception as e :
113+ raise ValueError (f"Invalid fully qualified name: { name } " ) from e
114+
115+
93116@working_in_progress ("resolve_agent_reference is not ready for use." )
94117def resolve_agent_reference (
95118 ref_config : AgentRefConfig , referencing_agent_config_abs_path : str
0 commit comments