Skip to content

symfonic.agent.builder

builder

Fluent AgentBuilder -- a convenience facade over the agent surface.

v9.2.0 (issue #31). AgentBuilder composes the settled additive surface (provider, model, domain, tools, memory, and declarative sub-agents) into a readable chain, then hands off to the same SymfonicAgent / FrameworkConfig / HMSFactory primitives you'd call directly -- it adds NO behaviour of its own, so anything the builder does you can also do by constructing SymfonicAgent(...) by hand.

Example::

from symfonic.agent import AgentBuilder, SubAgentSpec
from symfonic.core.providers import AnthropicProvider

agent = (
    AgentBuilder()
    .provider(AnthropicProvider())
    .model("claude-sonnet-4-5", temperature=0.4)
    .domain("support", "A customer-support assistant.")
    .tools(lookup_order, issue_refund)
    .enable_hms()
    .memory(embeddings=embedder)          # in-memory HMS
    .sub_agent("researcher", "Deep web research.", tools=[web_search])
    .build()
)

AgentBuilder

AgentBuilder(*, config: FrameworkConfig | None = None)

Chainable builder that assembles a :class:SymfonicAgent.

Every method returns self for chaining; :meth:build produces the agent. A ModelProvider is the only hard requirement.

Start a builder, optionally extending an existing base config.

Parameters:

Name Type Description Default
config FrameworkConfig | None

A base :class:FrameworkConfig to layer overrides onto. Defaults to FrameworkConfig(). Anything the builder sets (model, domain, flags) overrides this base; everything else is inherited.

None
Source code in src/symfonic/agent/builder.py
def __init__(self, *, config: FrameworkConfig | None = None) -> None:
    """Start a builder, optionally extending an existing base config.

    Args:
        config: A base :class:`FrameworkConfig` to layer overrides onto.
            Defaults to ``FrameworkConfig()``. Anything the builder sets
            (model, domain, flags) overrides this base; everything else is
            inherited.
    """
    self._base_config = config
    self._provider: ModelProvider | None = None
    self._tools: list[Any] = []
    self._sub_specs: list[SubAgentSpec] = []
    self._overrides: dict[str, Any] = {}
    self._model_overrides: dict[str, Any] = {}
    self._domain: DomainTemplate | None = None
    self._domain_name: str | None = None
    self._domain_description: str | None = None
    self._orchestrator: MemoryOrchestrator | None = None
    self._embeddings: EmbeddingProvider | None = None
    self._in_memory: bool = False

build

build() -> SymfonicAgent

Construct the SymfonicAgent from the accumulated configuration.

Raises:

Type Description
ValueError

If no provider was set.

Source code in src/symfonic/agent/builder.py
def build(self) -> SymfonicAgent:
    """Construct the ``SymfonicAgent`` from the accumulated configuration.

    Raises:
        ValueError: If no provider was set.
    """
    if self._provider is None:
        raise ValueError(
            "AgentBuilder requires a provider; call .provider(...) before "
            ".build()"
        )
    from symfonic.agent.engine import SymfonicAgent

    orchestrator = self._orchestrator
    if orchestrator is None and self._in_memory:
        from symfonic.agent.factory import HMSFactory

        orchestrator = HMSFactory.build_in_memory(
            embedding_provider=self._embeddings
        )

    return SymfonicAgent(
        model_provider=self._provider,
        config=self._assemble_config(),
        tools=self._tools or None,
        sub_agents=self._sub_specs or None,
        orchestrator=orchestrator,
    )

domain

domain(
    name: str | None = None,
    description: str | None = None,
    *,
    template: DomainTemplate | None = None,
) -> AgentBuilder

Set the agent's domain -- either a full template or name/desc.

Source code in src/symfonic/agent/builder.py
def domain(
    self,
    name: str | None = None,
    description: str | None = None,
    *,
    template: DomainTemplate | None = None,
) -> AgentBuilder:
    """Set the agent's domain -- either a full ``template`` or name/desc."""
    if template is not None:
        self._domain = template
    else:
        self._domain_name = name
        self._domain_description = description
    return self

enable_hms

enable_hms(on: bool = True) -> AgentBuilder

Toggle the HMS system-prompt pipeline (enable_hms_prompt).

Source code in src/symfonic/agent/builder.py
def enable_hms(self, on: bool = True) -> AgentBuilder:
    """Toggle the HMS system-prompt pipeline (``enable_hms_prompt``)."""
    self._overrides["enable_hms_prompt"] = on
    return self

lazy_tooling

lazy_tooling(on: bool = True) -> AgentBuilder

Toggle lazy tool routing (lazy_tooling).

Source code in src/symfonic/agent/builder.py
def lazy_tooling(self, on: bool = True) -> AgentBuilder:
    """Toggle lazy tool routing (``lazy_tooling``)."""
    self._overrides["lazy_tooling"] = on
    return self

memory

memory(
    orchestrator: MemoryOrchestrator | None = None,
    *,
    embeddings: EmbeddingProvider | None = None,
    auto_hydrate: bool = True,
    auto_consolidate: bool = True,
) -> AgentBuilder

Attach HMS memory.

Pass a pre-built orchestrator OR embeddings to build an in-memory HMS at :meth:build time (delegates to HMSFactory.build_in_memory). Enables auto_hydrate / auto_consolidate by default; override per call.

Source code in src/symfonic/agent/builder.py
def memory(
    self,
    orchestrator: MemoryOrchestrator | None = None,
    *,
    embeddings: EmbeddingProvider | None = None,
    auto_hydrate: bool = True,
    auto_consolidate: bool = True,
) -> AgentBuilder:
    """Attach HMS memory.

    Pass a pre-built ``orchestrator`` OR ``embeddings`` to build an
    in-memory HMS at :meth:`build` time (delegates to
    ``HMSFactory.build_in_memory``). Enables ``auto_hydrate`` /
    ``auto_consolidate`` by default; override per call.
    """
    if orchestrator is not None:
        self._orchestrator = orchestrator
    elif embeddings is not None:
        self._embeddings = embeddings
        self._in_memory = True
    self._overrides.setdefault("auto_hydrate", auto_hydrate)
    self._overrides.setdefault("auto_consolidate", auto_consolidate)
    return self

model

model(
    model_name: str | None = None,
    *,
    temperature: float | None = None,
    max_tokens: int | None = None,
    top_p: float | None = None,
    top_k: int | None = None,
) -> AgentBuilder

Override model knobs; unset ones inherit the base config's model.

Source code in src/symfonic/agent/builder.py
def model(
    self,
    model_name: str | None = None,
    *,
    temperature: float | None = None,
    max_tokens: int | None = None,
    top_p: float | None = None,
    top_k: int | None = None,
) -> AgentBuilder:
    """Override model knobs; unset ones inherit the base config's model."""
    for key, val in (
        ("model_name", model_name),
        ("temperature", temperature),
        ("max_tokens", max_tokens),
        ("top_p", top_p),
        ("top_k", top_k),
    ):
        if val is not None:
            self._model_overrides[key] = val
    return self

option

option(**overrides: Any) -> AgentBuilder

Set any other FrameworkConfig field(s) verbatim.

Source code in src/symfonic/agent/builder.py
def option(self, **overrides: Any) -> AgentBuilder:
    """Set any other ``FrameworkConfig`` field(s) verbatim."""
    self._overrides.update(overrides)
    return self

provider

provider(provider: ModelProvider) -> AgentBuilder

Set the LLM provider (required).

Source code in src/symfonic/agent/builder.py
def provider(self, provider: ModelProvider) -> AgentBuilder:
    """Set the LLM provider (required)."""
    self._provider = provider
    return self

sub_agent

sub_agent(
    name: str,
    description: str,
    *,
    when_to_use: str | None = None,
    tools: Any = (),
    domain_description: str | None = None,
    model_name: str | None = None,
    temperature: float | None = None,
    max_tokens: int | None = None,
    provider: ModelProvider | None = None,
) -> AgentBuilder

Declare a child agent as a :class:SubAgentSpec (repeatable).

Source code in src/symfonic/agent/builder.py
def sub_agent(
    self,
    name: str,
    description: str,
    *,
    when_to_use: str | None = None,
    tools: Any = (),
    domain_description: str | None = None,
    model_name: str | None = None,
    temperature: float | None = None,
    max_tokens: int | None = None,
    provider: ModelProvider | None = None,
) -> AgentBuilder:
    """Declare a child agent as a :class:`SubAgentSpec` (repeatable)."""
    self._sub_specs.append(
        SubAgentSpec(
            name=name,
            description=description,
            when_to_use=when_to_use,
            tools=tuple(tools),
            domain_description=domain_description,
            model_name=model_name,
            temperature=temperature,
            max_tokens=max_tokens,
            provider=provider,
        )
    )
    return self

sub_agent_spec

sub_agent_spec(spec: SubAgentSpec) -> AgentBuilder

Add a pre-constructed :class:SubAgentSpec.

Source code in src/symfonic/agent/builder.py
def sub_agent_spec(self, spec: SubAgentSpec) -> AgentBuilder:
    """Add a pre-constructed :class:`SubAgentSpec`."""
    self._sub_specs.append(spec)
    return self

tools

tools(*tools: Any) -> AgentBuilder

Add tools (repeatable; accepts multiple per call).

Source code in src/symfonic/agent/builder.py
def tools(self, *tools: Any) -> AgentBuilder:
    """Add tools (repeatable; accepts multiple per call)."""
    self._tools.extend(tools)
    return self