Skip to content

manifest

Class info

Classes

Name Children Inherits
AgentConfig
llmling_agent.models.agents
Configuration for a single agent in the system.
    • NodeConfig
    AgentWorkerConfig
    llmling_agent_config.workers
    Configuration for agent workers.
      • BaseWorkerConfig
      AgentsManifest
      llmling_agent.models.manifest
      Complete agent configuration manifest defining all available agents.
        BaseMCPServerConfig
        llmling_agent_config.mcp_server
        Base model for MCP server configuration.
        • StdioMCPServerConfig
        • SSEMCPServerConfig
        BaseProviderConfig
        llmling_agent_config.providers
        Base configuration for agent providers.
        • PydanticAIProviderConfig
        • LiteLLMProviderConfig
        • HumanProviderConfig
        • CallbackProviderConfig
        BaseWorkerConfig
        llmling_agent_config.workers
        Base configuration for workers.
        • TeamWorkerConfig
        • AgentWorkerConfig
        ConversionConfig
        llmling_agent_config.converters
        Global conversion configuration.
          Job
          llmling_agent_config.task
          A task is a piece of work that can be executed by an agent.
            ObservabilityConfig
            llmling_agent_config.observability
            Global observability configuration.
              PoolServerConfig
              llmling_agent_config.mcp_server
              Configuration for pool-based MCP server.
                PromptConfig
                llmling_agent_config.prompts
                Complete prompt configuration.
                  ResourceRegistry
                  llmling_agent.resource_registry
                  Registry for filesystem resources.
                    SourceResourceConfig
                    llmling_agent_config.resources
                    Configuration for a single filesystem source.
                      • BaseResourceConfig
                      StdioMCPServerConfig
                      llmling_agent_config.mcp_server
                      MCP server started via stdio.
                        • BaseMCPServerConfig
                        StdlibUIConfig
                        llmling_agent_config.ui
                        Configuration for basic CLI interface.
                          • BaseUIConfig
                          StorageConfig
                          llmling_agent_config.storage
                          Global storage configuration.
                            TeamConfig
                            llmling_agent_config.teams
                            Configuration for a team or chain of message nodes.
                              • NodeConfig
                              TeamWorkerConfig
                              llmling_agent_config.workers
                              Configuration for team workers.
                                • BaseWorkerConfig

                                🛈 DocStrings

                                Models for agent configuration.

                                AgentsManifest

                                Bases: ConfigModel

                                Complete agent configuration manifest defining all available agents.

                                This is the root configuration that: - Defines available response types (both inline and imported) - Configures all agent instances and their settings - Sets up custom role definitions and capabilities - Manages environment configurations

                                A single manifest can define multiple agents that can work independently or collaborate through the orchestrator.

                                Source code in src/llmling_agent/models/manifest.py
                                 47
                                 48
                                 49
                                 50
                                 51
                                 52
                                 53
                                 54
                                 55
                                 56
                                 57
                                 58
                                 59
                                 60
                                 61
                                 62
                                 63
                                 64
                                 65
                                 66
                                 67
                                 68
                                 69
                                 70
                                 71
                                 72
                                 73
                                 74
                                 75
                                 76
                                 77
                                 78
                                 79
                                 80
                                 81
                                 82
                                 83
                                 84
                                 85
                                 86
                                 87
                                 88
                                 89
                                 90
                                 91
                                 92
                                 93
                                 94
                                 95
                                 96
                                 97
                                 98
                                 99
                                100
                                101
                                102
                                103
                                104
                                105
                                106
                                107
                                108
                                109
                                110
                                111
                                112
                                113
                                114
                                115
                                116
                                117
                                118
                                119
                                120
                                121
                                122
                                123
                                124
                                125
                                126
                                127
                                128
                                129
                                130
                                131
                                132
                                133
                                134
                                135
                                136
                                137
                                138
                                139
                                140
                                141
                                142
                                143
                                144
                                145
                                146
                                147
                                148
                                149
                                150
                                151
                                152
                                153
                                154
                                155
                                156
                                157
                                158
                                159
                                160
                                161
                                162
                                163
                                164
                                165
                                166
                                167
                                168
                                169
                                170
                                171
                                172
                                173
                                174
                                175
                                176
                                177
                                178
                                179
                                180
                                181
                                182
                                183
                                184
                                185
                                186
                                187
                                188
                                189
                                190
                                191
                                192
                                193
                                194
                                195
                                196
                                197
                                198
                                199
                                200
                                201
                                202
                                203
                                204
                                205
                                206
                                207
                                208
                                209
                                210
                                211
                                212
                                213
                                214
                                215
                                216
                                217
                                218
                                219
                                220
                                221
                                222
                                223
                                224
                                225
                                226
                                227
                                228
                                229
                                230
                                231
                                232
                                233
                                234
                                235
                                236
                                237
                                238
                                239
                                240
                                241
                                242
                                243
                                244
                                245
                                246
                                247
                                248
                                249
                                250
                                251
                                252
                                253
                                254
                                255
                                256
                                257
                                258
                                259
                                260
                                261
                                262
                                263
                                264
                                265
                                266
                                267
                                268
                                269
                                270
                                271
                                272
                                273
                                274
                                275
                                276
                                277
                                278
                                279
                                280
                                281
                                282
                                283
                                284
                                285
                                286
                                287
                                288
                                289
                                290
                                291
                                292
                                293
                                294
                                295
                                296
                                297
                                298
                                299
                                300
                                301
                                302
                                303
                                304
                                305
                                306
                                307
                                308
                                309
                                310
                                311
                                312
                                313
                                314
                                315
                                316
                                317
                                318
                                319
                                320
                                321
                                322
                                323
                                324
                                325
                                326
                                327
                                328
                                329
                                330
                                331
                                332
                                333
                                334
                                335
                                336
                                337
                                338
                                339
                                340
                                341
                                342
                                343
                                344
                                345
                                346
                                347
                                348
                                349
                                350
                                351
                                352
                                353
                                354
                                355
                                356
                                357
                                358
                                359
                                360
                                361
                                362
                                363
                                364
                                365
                                366
                                367
                                368
                                369
                                370
                                371
                                372
                                373
                                374
                                375
                                376
                                377
                                378
                                379
                                380
                                381
                                382
                                383
                                384
                                385
                                386
                                387
                                388
                                389
                                390
                                391
                                392
                                393
                                394
                                395
                                396
                                397
                                398
                                399
                                400
                                401
                                402
                                403
                                404
                                405
                                406
                                407
                                408
                                409
                                410
                                411
                                412
                                413
                                414
                                415
                                416
                                417
                                418
                                419
                                420
                                421
                                422
                                423
                                424
                                425
                                426
                                427
                                428
                                429
                                430
                                431
                                432
                                433
                                434
                                435
                                436
                                437
                                438
                                439
                                440
                                441
                                442
                                443
                                444
                                445
                                446
                                447
                                448
                                449
                                450
                                451
                                452
                                453
                                454
                                455
                                456
                                457
                                458
                                459
                                460
                                461
                                462
                                463
                                464
                                465
                                466
                                467
                                468
                                469
                                470
                                471
                                472
                                473
                                474
                                475
                                476
                                477
                                478
                                479
                                480
                                481
                                482
                                483
                                484
                                485
                                class AgentsManifest(ConfigModel):
                                    """Complete agent configuration manifest defining all available agents.
                                
                                    This is the root configuration that:
                                    - Defines available response types (both inline and imported)
                                    - Configures all agent instances and their settings
                                    - Sets up custom role definitions and capabilities
                                    - Manages environment configurations
                                
                                    A single manifest can define multiple agents that can work independently
                                    or collaborate through the orchestrator.
                                    """
                                
                                    INHERIT: str | list[str] | None = None
                                    """Inheritance references."""
                                
                                    resources: dict[str, ResourceConfig | str] = Field(default_factory=dict)
                                    """Resource configurations defining available filesystems.
                                
                                    Supports both full config and URI shorthand:
                                        resources:
                                          docs: "file://./docs"  # shorthand
                                          data:  # full config
                                            type: "source"
                                            uri: "s3://bucket/data"
                                            cached: true
                                    """
                                
                                    ui: UIConfig = Field(default_factory=StdlibUIConfig)
                                    """UI configuration."""
                                
                                    agents: dict[str, AgentConfig] = Field(default_factory=dict)
                                    """Mapping of agent IDs to their configurations"""
                                
                                    teams: dict[str, TeamConfig] = Field(default_factory=dict)
                                    """Mapping of team IDs to their configurations"""
                                
                                    storage: StorageConfig = Field(default_factory=StorageConfig)
                                    """Storage provider configuration."""
                                
                                    observability: ObservabilityConfig = Field(default_factory=ObservabilityConfig)
                                    """Observability provider configuration."""
                                
                                    conversion: ConversionConfig = Field(default_factory=ConversionConfig)
                                    """Document conversion configuration."""
                                
                                    responses: dict[str, ResponseDefinition] = Field(default_factory=dict)
                                    """Mapping of response names to their definitions"""
                                
                                    jobs: dict[str, Job] = Field(default_factory=dict)
                                    """Pre-defined jobs, ready to be used by nodes."""
                                
                                    mcp_servers: list[str | MCPServerConfig] = Field(default_factory=list)
                                    """List of MCP server configurations:
                                
                                    These MCP servers are used to provide tools and other resources to the nodes.
                                    """
                                    pool_server: PoolServerConfig = Field(default_factory=PoolServerConfig)
                                    """Pool server configuration.
                                
                                    This MCP server configuration is used for the pool MCP server,
                                    which exposes pool functionality to other applications / clients."""
                                
                                    prompts: PromptConfig = Field(default_factory=PromptConfig)
                                
                                    model_config = ConfigDict(use_attribute_docstrings=True, extra="forbid")
                                
                                    @model_validator(mode="before")
                                    @classmethod
                                    def normalize_workers(cls, data: dict[str, Any]) -> dict[str, Any]:
                                        """Convert string workers to appropriate WorkerConfig for all agents."""
                                        teams = data.get("teams", {})
                                        agents = data.get("agents", {})
                                
                                        # Process workers for all agents that have them
                                        for agent_name, agent_config in agents.items():
                                            if isinstance(agent_config, dict):
                                                workers = agent_config.get("workers", [])
                                            else:
                                                workers = agent_config.workers
                                
                                            if workers:
                                                normalized: list[BaseWorkerConfig] = []
                                
                                                for worker in workers:
                                                    match worker:
                                                        case str() as name:
                                                            # Determine type based on presence in teams/agents
                                                            if name in teams:
                                                                normalized.append(TeamWorkerConfig(name=name))
                                                            elif name in agents:
                                                                normalized.append(AgentWorkerConfig(name=name))
                                                            else:
                                                                # Default to agent if type can't be determined
                                                                normalized.append(AgentWorkerConfig(name=name))
                                
                                                        case dict() as config:
                                                            # If type is explicitly specified, use it
                                                            if worker_type := config.get("type"):
                                                                match worker_type:
                                                                    case "team":
                                                                        normalized.append(TeamWorkerConfig(**config))
                                                                    case "agent":
                                                                        normalized.append(AgentWorkerConfig(**config))
                                                                    case _:
                                                                        msg = f"Invalid worker type: {worker_type}"
                                                                        raise ValueError(msg)
                                                            else:
                                                                # Determine type based on worker name
                                                                worker_name = config.get("name")
                                                                if not worker_name:
                                                                    msg = "Worker config missing name"
                                                                    raise ValueError(msg)
                                
                                                                if worker_name in teams:
                                                                    normalized.append(TeamWorkerConfig(**config))
                                                                else:
                                                                    normalized.append(AgentWorkerConfig(**config))
                                
                                                        case BaseWorkerConfig():  # Already normalized
                                                            normalized.append(worker)
                                
                                                        case _:
                                                            msg = f"Invalid worker configuration: {worker}"
                                                            raise ValueError(msg)
                                
                                                if isinstance(agent_config, dict):
                                                    agent_config["workers"] = normalized
                                                else:
                                                    # Need to create a new dict with updated workers
                                                    agent_dict = agent_config.model_dump()
                                                    agent_dict["workers"] = normalized
                                                    agents[agent_name] = agent_dict
                                
                                        return data
                                
                                    @cached_property
                                    def resource_registry(self) -> ResourceRegistry:
                                        """Get registry with all configured resources."""
                                        registry = ResourceRegistry()
                                        for name, config in self.resources.items():
                                            if isinstance(config, str):
                                                # Convert URI shorthand to SourceResourceConfig
                                                config = SourceResourceConfig(uri=config)
                                            registry.register_from_config(name, config)
                                        return registry
                                
                                    def clone_agent_config(
                                        self,
                                        name: str,
                                        new_name: str | None = None,
                                        *,
                                        template_context: dict[str, Any] | None = None,
                                        **overrides: Any,
                                    ) -> str:
                                        """Create a copy of an agent configuration.
                                
                                        Args:
                                            name: Name of agent to clone
                                            new_name: Optional new name (auto-generated if None)
                                            template_context: Variables for template rendering
                                            **overrides: Configuration overrides for the clone
                                
                                        Returns:
                                            Name of the new agent
                                
                                        Raises:
                                            KeyError: If original agent not found
                                            ValueError: If new name already exists or if overrides invalid
                                        """
                                        if name not in self.agents:
                                            msg = f"Agent {name} not found"
                                            raise KeyError(msg)
                                
                                        actual_name = new_name or f"{name}_copy_{len(self.agents)}"
                                        if actual_name in self.agents:
                                            msg = f"Agent {actual_name} already exists"
                                            raise ValueError(msg)
                                
                                        # Deep copy the configuration
                                        config = self.agents[name].model_copy(deep=True)
                                
                                        # Apply overrides
                                        for key, value in overrides.items():
                                            if not hasattr(config, key):
                                                msg = f"Invalid override: {key}"
                                                raise ValueError(msg)
                                            setattr(config, key, value)
                                
                                        # Handle template rendering if context provided
                                        if template_context:
                                            # Apply name from context if not explicitly overridden
                                            if "name" in template_context and "name" not in overrides:
                                                config.name = template_context["name"]
                                
                                            # Render system prompts
                                            config.system_prompts = config.render_system_prompts(template_context)
                                
                                        self.agents[actual_name] = config
                                        return actual_name
                                
                                    @model_validator(mode="before")
                                    @classmethod
                                    def resolve_inheritance(cls, data: dict) -> dict:
                                        """Resolve agent inheritance chains."""
                                        nodes = data.get("agents", {})
                                        resolved: dict[str, dict] = {}
                                        seen: set[str] = set()
                                
                                        def resolve_node(name: str) -> dict:
                                            if name in resolved:
                                                return resolved[name]
                                
                                            if name in seen:
                                                msg = f"Circular inheritance detected: {name}"
                                                raise ValueError(msg)
                                
                                            seen.add(name)
                                            config = (
                                                nodes[name].model_copy()
                                                if hasattr(nodes[name], "model_copy")
                                                else nodes[name].copy()
                                            )
                                            inherit = (
                                                config.get("inherits") if isinstance(config, dict) else config.inherits
                                            )
                                            if inherit:
                                                if inherit not in nodes:
                                                    msg = f"Parent agent {inherit} not found"
                                                    raise ValueError(msg)
                                
                                                # Get resolved parent config
                                                parent = resolve_node(inherit)
                                                # Merge parent with child (child overrides parent)
                                                merged = parent.copy()
                                                merged.update(config)
                                                config = merged
                                
                                            seen.remove(name)
                                            resolved[name] = config
                                            return config
                                
                                        # Resolve all nodes
                                        for name in nodes:
                                            resolved[name] = resolve_node(name)
                                
                                        # Update nodes with resolved configs
                                        data["agents"] = resolved
                                        return data
                                
                                    @model_validator(mode="after")
                                    def set_instrument_libraries(self) -> Self:
                                        """Auto-set libraries to instrument based on used providers."""
                                        if (
                                            not self.observability.enabled
                                            or self.observability.instrument_libraries is not None
                                        ):
                                            return self
                                        self.observability.instrument_libraries = list(self.get_used_providers())
                                        return self
                                
                                    @property
                                    def node_names(self) -> list[str]:
                                        """Get list of all agent and team names."""
                                        return list(self.agents.keys()) + list(self.teams.keys())
                                
                                    @property
                                    def nodes(self) -> dict[str, Any]:
                                        """Get all agent and team configurations."""
                                        return {**self.agents, **self.teams}
                                
                                    def get_mcp_servers(self) -> list[MCPServerConfig]:
                                        """Get processed MCP server configurations.
                                
                                        Converts string entries to StdioMCPServerConfig configs by splitting
                                        into command and arguments.
                                
                                        Returns:
                                            List of MCPServerConfig instances
                                
                                        Raises:
                                            ValueError: If string entry is empty
                                        """
                                        configs: list[MCPServerConfig] = []
                                
                                        for server in self.mcp_servers:
                                            match server:
                                                case str():
                                                    parts = server.split()
                                                    if not parts:
                                                        msg = "Empty MCP server command"
                                                        raise ValueError(msg)
                                
                                                    configs.append(StdioMCPServerConfig(command=parts[0], args=parts[1:]))
                                                case BaseMCPServerConfig():
                                                    configs.append(server)
                                
                                        return configs
                                
                                    @cached_property
                                    def prompt_manager(self) -> PromptManager:
                                        """Get prompt manager for this manifest."""
                                        from llmling_agent.prompts.manager import PromptManager
                                
                                        return PromptManager(self.prompts)
                                
                                    # @model_validator(mode="after")
                                    # def validate_response_types(self) -> AgentsManifest:
                                    #     """Ensure all agent result_types exist in responses or are inline."""
                                    #     for agent_id, agent in self.agents.items():
                                    #         if (
                                    #             isinstance(agent.result_type, str)
                                    #             and agent.result_type not in self.responses
                                    #         ):
                                    #             msg = f"'{agent.result_type=}' for '{agent_id=}' not found in responses"
                                    #             raise ValueError(msg)
                                    #     return self
                                
                                    def get_agent[TAgentDeps](
                                        self, name: str, deps: TAgentDeps | None = None
                                    ) -> AnyAgent[TAgentDeps, Any]:
                                        from llmling import RuntimeConfig
                                
                                        from llmling_agent import Agent, AgentContext
                                
                                        config = self.agents[name]
                                        # Create runtime without async context
                                        cfg = config.get_config()
                                        runtime = RuntimeConfig.from_config(cfg)
                                
                                        # Create context with config path and capabilities
                                        context = AgentContext[TAgentDeps](
                                            node_name=name,
                                            data=deps,
                                            capabilities=config.capabilities,
                                            definition=self,
                                            config=config,
                                            runtime=runtime,
                                            # pool=self,
                                            # confirmation_callback=confirmation_callback,
                                        )
                                
                                        sys_prompts = config.system_prompts.copy()
                                        # Library prompts
                                        if config.library_system_prompts:
                                            for prompt_ref in config.library_system_prompts:
                                                try:
                                                    content = self.prompt_manager.get_sync(prompt_ref)
                                                    sys_prompts.append(content)
                                                except Exception as e:
                                                    msg = f"Failed to load library prompt {prompt_ref!r} for agent {name}"
                                                    logger.exception(msg)
                                                    raise ValueError(msg) from e
                                        # Create agent with runtime and context
                                        agent = Agent[Any](
                                            runtime=runtime,
                                            context=context,
                                            provider=config.get_provider(),
                                            system_prompt=sys_prompts,
                                            name=name,
                                            description=config.description,
                                            retries=config.retries,
                                            session=config.get_session_config(),
                                            result_retries=config.result_retries,
                                            end_strategy=config.end_strategy,
                                            capabilities=config.capabilities,
                                            debug=config.debug,
                                            # name=config.name or name,
                                        )
                                        if result_type := self.get_result_type(name):
                                            return agent.to_structured(result_type)
                                        return agent
                                
                                    def get_used_providers(self) -> set[str]:
                                        """Get all providers configured in this manifest."""
                                        providers = set[str]()
                                
                                        for agent_config in self.agents.values():
                                            match agent_config.provider:
                                                case "pydantic_ai":
                                                    providers.add("pydantic_ai")
                                                case "litellm":
                                                    providers.add("litellm")
                                                case BaseProviderConfig():
                                                    providers.add(agent_config.provider.type)
                                        return providers
                                
                                    @classmethod
                                    def from_file(cls, path: StrPath) -> Self:
                                        """Load agent configuration from YAML file.
                                
                                        Args:
                                            path: Path to the configuration file
                                
                                        Returns:
                                            Loaded agent definition
                                
                                        Raises:
                                            ValueError: If loading fails
                                        """
                                        import yamling
                                
                                        try:
                                            data = yamling.load_yaml_file(path, resolve_inherit=True)
                                            agent_def = cls.model_validate(data)
                                            # Update all agents with the config file path and ensure names
                                            agents = {
                                                name: config.model_copy(update={"config_file_path": str(path)})
                                                for name, config in agent_def.agents.items()
                                            }
                                            return agent_def.model_copy(update={"agents": agents})
                                        except Exception as exc:
                                            msg = f"Failed to load agent config from {path}"
                                            raise ValueError(msg) from exc
                                
                                    @cached_property
                                    def pool(self) -> AgentPool:
                                        """Create an agent pool from this manifest.
                                
                                        Returns:
                                            Configured agent pool
                                        """
                                        from llmling_agent import AgentPool
                                
                                        return AgentPool(manifest=self)
                                
                                    def get_result_type(self, agent_name: str) -> type[Any] | None:
                                        """Get the resolved result type for an agent.
                                
                                        Returns None if no result type is configured.
                                        """
                                        agent_config = self.agents[agent_name]
                                        if not agent_config.result_type:
                                            return None
                                        logger.debug("Building response model for %r", agent_config.result_type)
                                        if isinstance(agent_config.result_type, str):
                                            response_def = self.responses[agent_config.result_type]
                                            return response_def.create_model()  # type: ignore
                                        return agent_config.result_type.create_model()  # type: ignore
                                

                                INHERIT class-attribute instance-attribute

                                INHERIT: str | list[str] | None = None
                                

                                Inheritance references.

                                agents class-attribute instance-attribute

                                agents: dict[str, AgentConfig] = Field(default_factory=dict)
                                

                                Mapping of agent IDs to their configurations

                                conversion class-attribute instance-attribute

                                conversion: ConversionConfig = Field(default_factory=ConversionConfig)
                                

                                Document conversion configuration.

                                jobs class-attribute instance-attribute

                                jobs: dict[str, Job] = Field(default_factory=dict)
                                

                                Pre-defined jobs, ready to be used by nodes.

                                mcp_servers class-attribute instance-attribute

                                mcp_servers: list[str | MCPServerConfig] = Field(default_factory=list)
                                

                                List of MCP server configurations:

                                These MCP servers are used to provide tools and other resources to the nodes.

                                node_names property

                                node_names: list[str]
                                

                                Get list of all agent and team names.

                                nodes property

                                nodes: dict[str, Any]
                                

                                Get all agent and team configurations.

                                observability class-attribute instance-attribute

                                observability: ObservabilityConfig = Field(default_factory=ObservabilityConfig)
                                

                                Observability provider configuration.

                                pool cached property

                                pool: AgentPool
                                

                                Create an agent pool from this manifest.

                                Returns:

                                Type Description
                                AgentPool

                                Configured agent pool

                                pool_server class-attribute instance-attribute

                                pool_server: PoolServerConfig = Field(default_factory=PoolServerConfig)
                                

                                Pool server configuration.

                                This MCP server configuration is used for the pool MCP server, which exposes pool functionality to other applications / clients.

                                prompt_manager cached property

                                prompt_manager: PromptManager
                                

                                Get prompt manager for this manifest.

                                resource_registry cached property

                                resource_registry: ResourceRegistry
                                

                                Get registry with all configured resources.

                                resources class-attribute instance-attribute

                                resources: dict[str, ResourceConfig | str] = Field(default_factory=dict)
                                

                                Resource configurations defining available filesystems.

                                Supports both full config and URI shorthand

                                resources: docs: "file://./docs" # shorthand data: # full config type: "source" uri: "s3://bucket/data" cached: true

                                responses class-attribute instance-attribute

                                responses: dict[str, ResponseDefinition] = Field(default_factory=dict)
                                

                                Mapping of response names to their definitions

                                storage class-attribute instance-attribute

                                storage: StorageConfig = Field(default_factory=StorageConfig)
                                

                                Storage provider configuration.

                                teams class-attribute instance-attribute

                                teams: dict[str, TeamConfig] = Field(default_factory=dict)
                                

                                Mapping of team IDs to their configurations

                                ui class-attribute instance-attribute

                                ui: UIConfig = Field(default_factory=StdlibUIConfig)
                                

                                UI configuration.

                                clone_agent_config

                                clone_agent_config(
                                    name: str,
                                    new_name: str | None = None,
                                    *,
                                    template_context: dict[str, Any] | None = None,
                                    **overrides: Any,
                                ) -> str
                                

                                Create a copy of an agent configuration.

                                Parameters:

                                Name Type Description Default
                                name str

                                Name of agent to clone

                                required
                                new_name str | None

                                Optional new name (auto-generated if None)

                                None
                                template_context dict[str, Any] | None

                                Variables for template rendering

                                None
                                **overrides Any

                                Configuration overrides for the clone

                                {}

                                Returns:

                                Type Description
                                str

                                Name of the new agent

                                Raises:

                                Type Description
                                KeyError

                                If original agent not found

                                ValueError

                                If new name already exists or if overrides invalid

                                Source code in src/llmling_agent/models/manifest.py
                                194
                                195
                                196
                                197
                                198
                                199
                                200
                                201
                                202
                                203
                                204
                                205
                                206
                                207
                                208
                                209
                                210
                                211
                                212
                                213
                                214
                                215
                                216
                                217
                                218
                                219
                                220
                                221
                                222
                                223
                                224
                                225
                                226
                                227
                                228
                                229
                                230
                                231
                                232
                                233
                                234
                                235
                                236
                                237
                                238
                                239
                                240
                                241
                                242
                                243
                                244
                                245
                                246
                                def clone_agent_config(
                                    self,
                                    name: str,
                                    new_name: str | None = None,
                                    *,
                                    template_context: dict[str, Any] | None = None,
                                    **overrides: Any,
                                ) -> str:
                                    """Create a copy of an agent configuration.
                                
                                    Args:
                                        name: Name of agent to clone
                                        new_name: Optional new name (auto-generated if None)
                                        template_context: Variables for template rendering
                                        **overrides: Configuration overrides for the clone
                                
                                    Returns:
                                        Name of the new agent
                                
                                    Raises:
                                        KeyError: If original agent not found
                                        ValueError: If new name already exists or if overrides invalid
                                    """
                                    if name not in self.agents:
                                        msg = f"Agent {name} not found"
                                        raise KeyError(msg)
                                
                                    actual_name = new_name or f"{name}_copy_{len(self.agents)}"
                                    if actual_name in self.agents:
                                        msg = f"Agent {actual_name} already exists"
                                        raise ValueError(msg)
                                
                                    # Deep copy the configuration
                                    config = self.agents[name].model_copy(deep=True)
                                
                                    # Apply overrides
                                    for key, value in overrides.items():
                                        if not hasattr(config, key):
                                            msg = f"Invalid override: {key}"
                                            raise ValueError(msg)
                                        setattr(config, key, value)
                                
                                    # Handle template rendering if context provided
                                    if template_context:
                                        # Apply name from context if not explicitly overridden
                                        if "name" in template_context and "name" not in overrides:
                                            config.name = template_context["name"]
                                
                                        # Render system prompts
                                        config.system_prompts = config.render_system_prompts(template_context)
                                
                                    self.agents[actual_name] = config
                                    return actual_name
                                

                                from_file classmethod

                                from_file(path: StrPath) -> Self
                                

                                Load agent configuration from YAML file.

                                Parameters:

                                Name Type Description Default
                                path StrPath

                                Path to the configuration file

                                required

                                Returns:

                                Type Description
                                Self

                                Loaded agent definition

                                Raises:

                                Type Description
                                ValueError

                                If loading fails

                                Source code in src/llmling_agent/models/manifest.py
                                434
                                435
                                436
                                437
                                438
                                439
                                440
                                441
                                442
                                443
                                444
                                445
                                446
                                447
                                448
                                449
                                450
                                451
                                452
                                453
                                454
                                455
                                456
                                457
                                458
                                459
                                460
                                @classmethod
                                def from_file(cls, path: StrPath) -> Self:
                                    """Load agent configuration from YAML file.
                                
                                    Args:
                                        path: Path to the configuration file
                                
                                    Returns:
                                        Loaded agent definition
                                
                                    Raises:
                                        ValueError: If loading fails
                                    """
                                    import yamling
                                
                                    try:
                                        data = yamling.load_yaml_file(path, resolve_inherit=True)
                                        agent_def = cls.model_validate(data)
                                        # Update all agents with the config file path and ensure names
                                        agents = {
                                            name: config.model_copy(update={"config_file_path": str(path)})
                                            for name, config in agent_def.agents.items()
                                        }
                                        return agent_def.model_copy(update={"agents": agents})
                                    except Exception as exc:
                                        msg = f"Failed to load agent config from {path}"
                                        raise ValueError(msg) from exc
                                

                                get_mcp_servers

                                get_mcp_servers() -> list[MCPServerConfig]
                                

                                Get processed MCP server configurations.

                                Converts string entries to StdioMCPServerConfig configs by splitting into command and arguments.

                                Returns:

                                Type Description
                                list[MCPServerConfig]

                                List of MCPServerConfig instances

                                Raises:

                                Type Description
                                ValueError

                                If string entry is empty

                                Source code in src/llmling_agent/models/manifest.py
                                318
                                319
                                320
                                321
                                322
                                323
                                324
                                325
                                326
                                327
                                328
                                329
                                330
                                331
                                332
                                333
                                334
                                335
                                336
                                337
                                338
                                339
                                340
                                341
                                342
                                343
                                344
                                def get_mcp_servers(self) -> list[MCPServerConfig]:
                                    """Get processed MCP server configurations.
                                
                                    Converts string entries to StdioMCPServerConfig configs by splitting
                                    into command and arguments.
                                
                                    Returns:
                                        List of MCPServerConfig instances
                                
                                    Raises:
                                        ValueError: If string entry is empty
                                    """
                                    configs: list[MCPServerConfig] = []
                                
                                    for server in self.mcp_servers:
                                        match server:
                                            case str():
                                                parts = server.split()
                                                if not parts:
                                                    msg = "Empty MCP server command"
                                                    raise ValueError(msg)
                                
                                                configs.append(StdioMCPServerConfig(command=parts[0], args=parts[1:]))
                                            case BaseMCPServerConfig():
                                                configs.append(server)
                                
                                    return configs
                                

                                get_result_type

                                get_result_type(agent_name: str) -> type[Any] | None
                                

                                Get the resolved result type for an agent.

                                Returns None if no result type is configured.

                                Source code in src/llmling_agent/models/manifest.py
                                473
                                474
                                475
                                476
                                477
                                478
                                479
                                480
                                481
                                482
                                483
                                484
                                485
                                def get_result_type(self, agent_name: str) -> type[Any] | None:
                                    """Get the resolved result type for an agent.
                                
                                    Returns None if no result type is configured.
                                    """
                                    agent_config = self.agents[agent_name]
                                    if not agent_config.result_type:
                                        return None
                                    logger.debug("Building response model for %r", agent_config.result_type)
                                    if isinstance(agent_config.result_type, str):
                                        response_def = self.responses[agent_config.result_type]
                                        return response_def.create_model()  # type: ignore
                                    return agent_config.result_type.create_model()  # type: ignore
                                

                                get_used_providers

                                get_used_providers() -> set[str]
                                

                                Get all providers configured in this manifest.

                                Source code in src/llmling_agent/models/manifest.py
                                420
                                421
                                422
                                423
                                424
                                425
                                426
                                427
                                428
                                429
                                430
                                431
                                432
                                def get_used_providers(self) -> set[str]:
                                    """Get all providers configured in this manifest."""
                                    providers = set[str]()
                                
                                    for agent_config in self.agents.values():
                                        match agent_config.provider:
                                            case "pydantic_ai":
                                                providers.add("pydantic_ai")
                                            case "litellm":
                                                providers.add("litellm")
                                            case BaseProviderConfig():
                                                providers.add(agent_config.provider.type)
                                    return providers
                                

                                normalize_workers classmethod

                                normalize_workers(data: dict[str, Any]) -> dict[str, Any]
                                

                                Convert string workers to appropriate WorkerConfig for all agents.

                                Source code in src/llmling_agent/models/manifest.py
                                114
                                115
                                116
                                117
                                118
                                119
                                120
                                121
                                122
                                123
                                124
                                125
                                126
                                127
                                128
                                129
                                130
                                131
                                132
                                133
                                134
                                135
                                136
                                137
                                138
                                139
                                140
                                141
                                142
                                143
                                144
                                145
                                146
                                147
                                148
                                149
                                150
                                151
                                152
                                153
                                154
                                155
                                156
                                157
                                158
                                159
                                160
                                161
                                162
                                163
                                164
                                165
                                166
                                167
                                168
                                169
                                170
                                171
                                172
                                173
                                174
                                175
                                176
                                177
                                178
                                179
                                180
                                181
                                @model_validator(mode="before")
                                @classmethod
                                def normalize_workers(cls, data: dict[str, Any]) -> dict[str, Any]:
                                    """Convert string workers to appropriate WorkerConfig for all agents."""
                                    teams = data.get("teams", {})
                                    agents = data.get("agents", {})
                                
                                    # Process workers for all agents that have them
                                    for agent_name, agent_config in agents.items():
                                        if isinstance(agent_config, dict):
                                            workers = agent_config.get("workers", [])
                                        else:
                                            workers = agent_config.workers
                                
                                        if workers:
                                            normalized: list[BaseWorkerConfig] = []
                                
                                            for worker in workers:
                                                match worker:
                                                    case str() as name:
                                                        # Determine type based on presence in teams/agents
                                                        if name in teams:
                                                            normalized.append(TeamWorkerConfig(name=name))
                                                        elif name in agents:
                                                            normalized.append(AgentWorkerConfig(name=name))
                                                        else:
                                                            # Default to agent if type can't be determined
                                                            normalized.append(AgentWorkerConfig(name=name))
                                
                                                    case dict() as config:
                                                        # If type is explicitly specified, use it
                                                        if worker_type := config.get("type"):
                                                            match worker_type:
                                                                case "team":
                                                                    normalized.append(TeamWorkerConfig(**config))
                                                                case "agent":
                                                                    normalized.append(AgentWorkerConfig(**config))
                                                                case _:
                                                                    msg = f"Invalid worker type: {worker_type}"
                                                                    raise ValueError(msg)
                                                        else:
                                                            # Determine type based on worker name
                                                            worker_name = config.get("name")
                                                            if not worker_name:
                                                                msg = "Worker config missing name"
                                                                raise ValueError(msg)
                                
                                                            if worker_name in teams:
                                                                normalized.append(TeamWorkerConfig(**config))
                                                            else:
                                                                normalized.append(AgentWorkerConfig(**config))
                                
                                                    case BaseWorkerConfig():  # Already normalized
                                                        normalized.append(worker)
                                
                                                    case _:
                                                        msg = f"Invalid worker configuration: {worker}"
                                                        raise ValueError(msg)
                                
                                            if isinstance(agent_config, dict):
                                                agent_config["workers"] = normalized
                                            else:
                                                # Need to create a new dict with updated workers
                                                agent_dict = agent_config.model_dump()
                                                agent_dict["workers"] = normalized
                                                agents[agent_name] = agent_dict
                                
                                    return data
                                

                                resolve_inheritance classmethod

                                resolve_inheritance(data: dict) -> dict
                                

                                Resolve agent inheritance chains.

                                Source code in src/llmling_agent/models/manifest.py
                                248
                                249
                                250
                                251
                                252
                                253
                                254
                                255
                                256
                                257
                                258
                                259
                                260
                                261
                                262
                                263
                                264
                                265
                                266
                                267
                                268
                                269
                                270
                                271
                                272
                                273
                                274
                                275
                                276
                                277
                                278
                                279
                                280
                                281
                                282
                                283
                                284
                                285
                                286
                                287
                                288
                                289
                                290
                                291
                                292
                                293
                                294
                                295
                                @model_validator(mode="before")
                                @classmethod
                                def resolve_inheritance(cls, data: dict) -> dict:
                                    """Resolve agent inheritance chains."""
                                    nodes = data.get("agents", {})
                                    resolved: dict[str, dict] = {}
                                    seen: set[str] = set()
                                
                                    def resolve_node(name: str) -> dict:
                                        if name in resolved:
                                            return resolved[name]
                                
                                        if name in seen:
                                            msg = f"Circular inheritance detected: {name}"
                                            raise ValueError(msg)
                                
                                        seen.add(name)
                                        config = (
                                            nodes[name].model_copy()
                                            if hasattr(nodes[name], "model_copy")
                                            else nodes[name].copy()
                                        )
                                        inherit = (
                                            config.get("inherits") if isinstance(config, dict) else config.inherits
                                        )
                                        if inherit:
                                            if inherit not in nodes:
                                                msg = f"Parent agent {inherit} not found"
                                                raise ValueError(msg)
                                
                                            # Get resolved parent config
                                            parent = resolve_node(inherit)
                                            # Merge parent with child (child overrides parent)
                                            merged = parent.copy()
                                            merged.update(config)
                                            config = merged
                                
                                        seen.remove(name)
                                        resolved[name] = config
                                        return config
                                
                                    # Resolve all nodes
                                    for name in nodes:
                                        resolved[name] = resolve_node(name)
                                
                                    # Update nodes with resolved configs
                                    data["agents"] = resolved
                                    return data
                                

                                set_instrument_libraries

                                set_instrument_libraries() -> Self
                                

                                Auto-set libraries to instrument based on used providers.

                                Source code in src/llmling_agent/models/manifest.py
                                297
                                298
                                299
                                300
                                301
                                302
                                303
                                304
                                305
                                306
                                @model_validator(mode="after")
                                def set_instrument_libraries(self) -> Self:
                                    """Auto-set libraries to instrument based on used providers."""
                                    if (
                                        not self.observability.enabled
                                        or self.observability.instrument_libraries is not None
                                    ):
                                        return self
                                    self.observability.instrument_libraries = list(self.get_used_providers())
                                    return self