{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Component config\n", "\n", "AutoGen components are able to be declaratively configured in a generic fashion. This is to support configuration based experiences, such as AutoGen studio, but it is also useful for many other scenarios.\n", "\n", "The system that provides this is called \"component configuration\". In AutoGen, a component is simply something that can be created from a config object and itself can be dumped to a config object. In this way, you can define a component in code and then get the config object from it.\n", "\n", "This system is generic and allows for components defined outside of AutoGen itself (such as extensions) to be configured in the same way.\n", "\n", "## How does this differ from state?\n", "\n", "This is a very important point to clarify. When we talk about serializing an object, we must include *all* data that makes that object itself. Including things like message history etc. When deserializing from serialized state, you must get back the *exact* same object. This is not the case with component configuration.\n", "\n", "Component configuration should be thought of as the blueprint for an object, and can be stamped out many times to create many instances of the same configured object.\n", "\n", "## Usage\n", "\n", "If you have a component in Python ad want to get the config for it, simply call {py:meth}`~autogen_core.ComponentConfig.dump_component` on it. The resulting object can be passed back into {py:meth}`~autogen_core.ComponentLoader.load_component` to get the component back.\n", "\n", "## Creating a component\n", "\n", "To add component functionality to a given class:\n", "\n", "1. Add a call to {py:meth}`~autogen_core.Component` in the class inheritance list.\n", "2. Implment the {py:meth}`~autogen_core.ComponentConfigImpl._to_config` and {py:meth}`~autogen_core.ComponentConfigImpl._from_config` methods\n", "\n", "For example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from __future__ import annotations\n", "\n", "from autogen_core import Component\n", "from pydantic import BaseModel\n", "\n", "\n", "class Config(BaseModel):\n", " value: str\n", "\n", "\n", "class MyComponent(Component[Config]):\n", " component_type = \"custom\"\n", " config_schema = Config\n", "\n", " def __init__(self, value: str):\n", " self.value = value\n", "\n", " def _to_config(self) -> Config:\n", " return Config(value=self.value)\n", "\n", " @classmethod\n", " def _from_config(cls, config: Config) -> MyComponent:\n", " return cls(value=config.value)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## Secrets\n", "\n", "If a field of a config object is a secret value, it should be marked using [`SecretStr`](https://docs.pydantic.dev/latest/api/types/#pydantic.types.SecretStr), this will ensure that the value will not be dumped to the config object.\n", "\n", "For example:\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from pydantic import BaseModel, SecretStr\n", "\n", "\n", "class ClientConfig(BaseModel):\n", " endpoint: str\n", " api_key: SecretStr" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.7" } }, "nbformat": 4, "nbformat_minor": 2 }