|
35 | 35 | from pydantic import ConfigDict |
36 | 36 | from pydantic import Field |
37 | 37 | from pydantic import field_validator |
| 38 | +from typing_extensions import deprecated |
38 | 39 | from typing_extensions import override |
39 | 40 | from typing_extensions import TypeAlias |
40 | 41 |
|
|
45 | 46 | from ..telemetry import _instrumentation |
46 | 47 | from ..utils.context_utils import Aclosing |
47 | 48 | from ..workflow._base_node import BaseNode |
| 49 | +from .base_agent_config import BaseAgentConfig |
48 | 50 | from .callback_context import CallbackContext |
49 | 51 | from .context import Context |
50 | 52 |
|
@@ -92,6 +94,25 @@ class BaseAgent(BaseNode): |
92 | 94 | ) |
93 | 95 | """The pydantic model config.""" |
94 | 96 |
|
| 97 | + config_type: ClassVar[type[BaseAgentConfig]] = BaseAgentConfig |
| 98 | + """The config type for this agent. |
| 99 | +
|
| 100 | + DEPRECATED: This attribute is deprecated and will be removed in a future |
| 101 | + version, along with the AgentConfig YAML loader. |
| 102 | +
|
| 103 | + Sub-classes should override this to specify their own config type. |
| 104 | +
|
| 105 | + Example: |
| 106 | +
|
| 107 | + ``` |
| 108 | + class MyAgentConfig(BaseAgentConfig): |
| 109 | + my_field: str = '' |
| 110 | +
|
| 111 | + class MyAgent(BaseAgent): |
| 112 | + config_type: ClassVar[type[BaseAgentConfig]] = MyAgentConfig |
| 113 | + ``` |
| 114 | + """ |
| 115 | + |
95 | 116 | name: str |
96 | 117 | """The agent's name. |
97 | 118 |
|
@@ -619,3 +640,93 @@ def __set_parent_agent_for_sub_agents(self) -> BaseAgent: |
619 | 640 | ) |
620 | 641 | sub_agent.parent_agent = self |
621 | 642 | return self |
| 643 | + |
| 644 | + @classmethod |
| 645 | + @deprecated( |
| 646 | + 'BaseAgent.from_config is deprecated and will be removed in future' |
| 647 | + ' versions.' |
| 648 | + ) |
| 649 | + @experimental(FeatureName.AGENT_CONFIG) |
| 650 | + def from_config( |
| 651 | + cls: Type[SelfAgent], |
| 652 | + config: BaseAgentConfig, |
| 653 | + config_abs_path: str, |
| 654 | + ) -> SelfAgent: |
| 655 | + """Creates an agent from a config. |
| 656 | +
|
| 657 | + If sub-classes use a custom agent config, override `_parse_config` to |
| 658 | + return updated kwargs for the agent constructor. |
| 659 | +
|
| 660 | + Args: |
| 661 | + config: The config to create the agent from. |
| 662 | + config_abs_path: The absolute path to the config file that contains the |
| 663 | + agent config. |
| 664 | +
|
| 665 | + Returns: |
| 666 | + The created agent. |
| 667 | + """ |
| 668 | + kwargs = cls.__create_kwargs(config, config_abs_path) |
| 669 | + kwargs = cls._parse_config(config, config_abs_path, kwargs) |
| 670 | + return cls(**kwargs) |
| 671 | + |
| 672 | + @classmethod |
| 673 | + @experimental(FeatureName.AGENT_CONFIG) |
| 674 | + def _parse_config( |
| 675 | + cls: Type[SelfAgent], |
| 676 | + config: BaseAgentConfig, |
| 677 | + config_abs_path: str, |
| 678 | + kwargs: Dict[str, Any], |
| 679 | + ) -> Dict[str, Any]: |
| 680 | + """Parses the config and returns updated kwargs to construct the agent. |
| 681 | +
|
| 682 | + Sub-classes should override this method to use a custom agent config class. |
| 683 | +
|
| 684 | + Args: |
| 685 | + config: The config to parse. |
| 686 | + config_abs_path: The absolute path to the config file that contains the |
| 687 | + agent config. |
| 688 | + kwargs: The keyword arguments used for agent constructor. |
| 689 | +
|
| 690 | + Returns: |
| 691 | + The updated keyword arguments used for agent constructor. |
| 692 | + """ |
| 693 | + return kwargs |
| 694 | + |
| 695 | + @classmethod |
| 696 | + def __create_kwargs( |
| 697 | + cls, |
| 698 | + config: BaseAgentConfig, |
| 699 | + config_abs_path: str, |
| 700 | + ) -> Dict[str, Any]: |
| 701 | + """Creates kwargs for the fields of BaseAgent.""" |
| 702 | + |
| 703 | + from .config_agent_utils import resolve_agent_reference |
| 704 | + from .config_agent_utils import resolve_callbacks |
| 705 | + |
| 706 | + kwargs: Dict[str, Any] = { |
| 707 | + 'name': config.name, |
| 708 | + 'description': config.description, |
| 709 | + } |
| 710 | + if config.sub_agents: |
| 711 | + sub_agents = [] |
| 712 | + for sub_agent_config in config.sub_agents: |
| 713 | + sub_agent = resolve_agent_reference(sub_agent_config, config_abs_path) |
| 714 | + sub_agents.append(sub_agent) |
| 715 | + kwargs['sub_agents'] = sub_agents |
| 716 | + |
| 717 | + if config.before_agent_callbacks: |
| 718 | + kwargs['before_agent_callback'] = resolve_callbacks( |
| 719 | + config.before_agent_callbacks |
| 720 | + ) |
| 721 | + if config.after_agent_callbacks: |
| 722 | + kwargs['after_agent_callback'] = resolve_callbacks( |
| 723 | + config.after_agent_callbacks |
| 724 | + ) |
| 725 | + |
| 726 | + # Preserves 1.x AgentConfigMapper behavior: extra YAML fields that match |
| 727 | + # a constructor parameter pass through automatically. |
| 728 | + if config.model_extra: |
| 729 | + for key, value in config.model_extra.items(): |
| 730 | + if key in cls.model_fields and key not in kwargs: |
| 731 | + kwargs[key] = value |
| 732 | + return kwargs |
0 commit comments