agent_from_config(config: FrameworkConfig, model_provider: Any, *, instructions: str | None = None, tools: Sequence[Any] = (), capabilities: Sequence[Any] = ()) -> Agent
Return an Agent honouring config's translated settings.
The caller must explicitly set auto_consolidate=False on the legacy
config: native QUICK requires separately proved exact-case AgentHost
composition. An omitted stock True refuses before Agent construction.
instructions, tools and capabilities are the caller's, passed
to Agent unchanged: the config never contributes a system prompt, a
tool or a memory port. Memory, sessions and history therefore work exactly
as they do on any Agent -- through the capabilities composed here and
the session_id/history arguments of each call.
agent.model and agent.recursion_limit at their stock values are not
requests: the Agent keeps its provider-declared model and native round
budget. agent.model is translated field by field: only the fields away
from ModelConfig() are applied, over the provider's declared default.
Raises:
| Type |
Description |
TypeError
|
config is not a FrameworkConfig.
|
UnsupportedFrameworkSettingError
|
an active setting is outside the
contract, or synthesize_on_empty_final is set beside a
TerminalSynthesisCapability the caller composed. Raised before
the Agent exists, so nothing reaches the provider, memory or a
tool.
|
Source code in src/symfonic/migration/framework_config.py
| def agent_from_config(
config: FrameworkConfig,
model_provider: Any,
*,
instructions: str | None = None,
tools: Sequence[Any] = (),
capabilities: Sequence[Any] = (),
) -> Agent:
"""Return an ``Agent`` honouring ``config``'s translated settings.
The caller must explicitly set ``auto_consolidate=False`` on the legacy
config: native QUICK requires separately proved exact-case AgentHost
composition. An omitted stock ``True`` refuses before Agent construction.
``instructions``, ``tools`` and ``capabilities`` are the caller's, passed
to ``Agent`` unchanged: the config never contributes a system prompt, a
tool or a memory port. Memory, sessions and history therefore work exactly
as they do on any ``Agent`` -- through the capabilities composed here and
the ``session_id``/``history`` arguments of each call.
``agent.model`` and ``agent.recursion_limit`` at their stock values are not
requests: the ``Agent`` keeps its provider-declared model and native round
budget. ``agent.model`` is translated field by field: only the fields away
from ``ModelConfig()`` are applied, over the provider's declared default.
Raises:
TypeError: ``config`` is not a ``FrameworkConfig``.
UnsupportedFrameworkSettingError: an active setting is outside the
contract, or ``synthesize_on_empty_final`` is set beside a
``TerminalSynthesisCapability`` the caller composed. Raised before
the ``Agent`` exists, so nothing reaches the provider, memory or a
tool.
"""
if not isinstance(config, FrameworkConfig):
raise TypeError(f"agent_from_config needs a FrameworkConfig, not {type(config).__name__}")
if config.auto_consolidate is not False or "auto_consolidate" not in config.model_fields_set:
# A caller-owned Sequence may do work while being inspected. Refuse
# legacy consolidation before touching it.
refused = unsupported_settings(config, composed=False)
raise UnsupportedFrameworkSettingError(refused, composed=False)
composed = tuple(capabilities)
refused = unsupported_settings(config, composed=bool(composed))
if config.synthesize_on_empty_final and any(
isinstance(cap, TerminalSynthesisCapability) for cap in composed
):
# The Agent would refuse the pair too, but unversioned: a host could
# not tell it from a failed turn. Refused here it maps like any other.
refused = (*refused, ("synthesize_on_empty_final", _DUPLICATE_SYNTHESIS))
if refused:
raise UnsupportedFrameworkSettingError(refused, composed=bool(composed))
if config.synthesize_on_empty_final:
composed = (*composed, TerminalSynthesisCapability())
stock = FrameworkConfig().agent
model, limit = config.agent.model, config.agent.recursion_limit
return Agent(
model_provider,
instructions=instructions,
model=_translated_model(model, model_provider),
tools=tools,
capabilities=composed,
max_model_rounds=(
None if equivalent(limit, stock.recursion_limit) else rounds_for_recursion_limit(limit)
),
)
|