Contract for translating FrameworkConfig into a public v11 Agent.
Only named settings translate. Stock model and recursion values leave the
provider's model and native round budget in place; changed model fields apply
over the provider default. Unsupported active values refuse before Agent,
provider, memory, or tool construction. Inactive retired values ask for
nothing. A dependent of auto_consolidate is inert when that flag is off.
The two COMPOSITION_SWITCHES (auto_hydrate, lazy_tooling) may be False
without caller capabilities. Legacy automatic consolidation is retired:
auto_consolidate=False must be explicit for this migration adapter, even
when all other fields are stock. Native exact-case QUICK is composed through
AgentHost separately; no legacy default or PostgreSQL parity is inferred.
UnsupportedFrameworkSettingError
UnsupportedFrameworkSettingError(refused: Sequence[tuple[str, str]], *, composed: bool)
Bases: ConfigurationError
Active FrameworkConfig settings outside this boundary's contract.
Raised at composition, before any Agent exists. settings lists
every refused path at once, so a migration sees the whole set rather than
one field per attempt.
Source code in src/symfonic/migration/framework_config_contract.py
| def __init__(self, refused: Sequence[tuple[str, str]], *, composed: bool) -> None:
self.settings = tuple(path for path, _ in refused)
self.contract = FRAMEWORK_CONFIG_CONTRACT
self.line = LEVER_RETIREMENT_LINE
self.pin = LAST_PUBLISHED_HONOURING_LINE
details = "; ".join(f"{path}: {why}" for path, why in refused)
super().__init__(
f"agent_from_config ({self.contract}) refuses active FrameworkConfig "
f"settings this boundary does not support: {details}. Remove them, "
"or compose the native capability on the Agent where one exists; "
f"this composition does not read them. Settings retired on {self.line} "
f"are honoured only by symfonic-core {self.pin}."
+ (
" Composition switches are refused at False because the caller "
"composed capabilities this boundary does not inspect."
if composed and any(path in COMPOSITION_SWITCHES for path, _ in refused)
else ""
)
)
|
unsupported_settings
unsupported_settings(config: FrameworkConfig, *, composed: bool) -> tuple[tuple[str, str], ...]
Each refused (path, reason); empty when the config is composable.
Source code in src/symfonic/migration/framework_config_contract.py
| def unsupported_settings(config: FrameworkConfig, *, composed: bool) -> tuple[tuple[str, str], ...]:
"""Each refused ``(path, reason)``; empty when the config is composable."""
if type(config) is not FrameworkConfig:
# A subclass can move a stock default, which the baseline would hide.
why = f"{type(config).__name__} is a subclass; only an exact FrameworkConfig is translated"
return ((_CONFIG_TYPE_PATH, why),)
refused = _out_of_domain(config) + _model_refusals(config)
if config.auto_consolidate is not False or "auto_consolidate" not in config.model_fields_set:
refused.append(("auto_consolidate", _AUTO_CONSOLIDATE_REFUSAL))
for path, value in _differences(config):
if path == "auto_consolidate" and value is False:
continue
if path in TRANSLATED_SETTINGS:
continue
if path in COMPOSITION_SWITCHES and not composed:
continue
if config.auto_consolidate is False and path in _CONSOLIDATION_GATED:
continue
retired = RETIRED_SETTINGS.get(path)
if retired is not None and not retired.is_use(value):
continue
refused.append((path, _reason(path, value)))
return tuple(refused)
|