Skip to content

symfonic.agent.entry_point_removal

entry_point_removal

CORE-388 -- the refusal SymfonicAgent and AgentBuilder raise from 11.3.

Both entry points were public API through 11.2.6. The owner chose an explicit break inside 11.x rather than waiting for 12.0, and chose it without a compatibility shim: constructing either one raises :class:EntryPointRemovedError before any argument is read, anything is installed process-wide, or any legacy body can run.

The classes stay importable on purpose. from symfonic.agent import SymfonicAgent succeeding and the call refusing is what lets a caller read the migration message instead of an ImportError, and it is what lets the RET-6 reachability probe observe the refusal at construction rather than infer it from a missing name.

The message names only replacements the package already ships natively: symfonic.Agent, symfonic.platform.AgentHost, and symfonic.migration.agent_from_config for a caller carrying a FrameworkConfig -- that boundary honours each active setting it translates and refuses every other one by name (framework_config_agent.v1).

This is a refusal, not a retirement. The legacy bodies stay in the source and the package offers no supported admission, context or flag that turns the refusal off. It cannot stop an in-process monkeypatch of this module's private _refuse from restoring a legacy body; doing so is unsupported, and the suite's legacy_body opt-in (tests/_legacy_bodies.py) is exactly that test-only patch. Physical removal remains behind the fourteen-condition gate.

CORE-413: the refusal itself needs neither symfonic.agent.engine nor symfonic.agent.cutover. The public symfonic.agent.SymfonicAgent is the :class:SymfonicAgent tombstone below, and the pin the error names is carried here as :data:LAST_LEGACY_LINE, so the versioned message survives the deletion of either package instead of degrading to an ImportError. The tombstone does not consult :func:_refuse, so the legacy_body patch above reaches only the internal symfonic.agent.engine.SymfonicAgent and AgentBuilder.build, never the public name. That is a property of this refusal surface only; other package paths still import the engine or cutover.

CORE-25: the four HTTP sub-router factories create_agent_router mounted refuse here from 11.4 too, each under its own name. Their bodies are gone, so the error names the native create_kernel_agent_router ports (:data:REMOVED_HTTP_SUBROUTERS) and the routes no port serves (:data:UNSERVED_HTTP_ROUTES) instead of the constructor replacements.

EntryPointRemovedError

EntryPointRemovedError(entry_point: str)

Bases: ConfigurationError

A removed public entry point was called.

A ConfigurationError, so existing except ConfigurationError sites still catch it. The fields make it attributable without parsing the message: :attr:entry_point is the name the caller used, never the class a builder would have produced.

Source code in src/symfonic/agent/entry_point_removal.py
def __init__(self, entry_point: str) -> None:
    subrouter = REMOVED_HTTP_SUBROUTERS.get(entry_point)
    if entry_point not in (*REMOVED_ENTRY_POINTS, REMOVED_HTTP_FACTORY) and subrouter is None:
        raise ValueError(f"{entry_point!r} is not a removed entry point")
    self.entry_point = entry_point
    removal_line = (
        ENTRY_POINT_REMOVAL_LINE
        if entry_point in REMOVED_ENTRY_POINTS
        else HTTP_FACTORY_REMOVAL_LINE
    )
    self.removed_in = removal_line
    self.replacements = tuple(REPLACEMENTS)
    #: The ``create_kernel_agent_router`` ports that replace a sub-router.
    self.native_ports = tuple(subrouter or ())
    self.last_legacy_line = LAST_LEGACY_LINE
    pin = (
        f"To keep {entry_point} unchanged, pin symfonic-core=={LAST_LEGACY_LINE}.*, "
        "the newest public release line that serves it."
    )
    if subrouter is not None:
        super().__init__(
            f"{entry_point} was removed in symfonic-core {removal_line}. "
            f"{_native_composition(entry_point, subrouter)} {pin}"
        )
        return
    super().__init__(
        f"{entry_point} was removed in symfonic-core {removal_line}. "
        f"Use {REPLACEMENTS['Agent']} for one agent or "
        f"{REPLACEMENTS['AgentHost']} to host agents; an existing FrameworkConfig "
        f"carries over through {REPLACEMENTS['agent_from_config']}, which refuses "
        f"each setting it cannot honour. {pin}"
    )

SymfonicAgent

The public symfonic.agent.SymfonicAgent from 11.3: a tombstone.

Constructing it raises :class:EntryPointRemovedError naming SymfonicAgent before any argument is read, exactly as the legacy constructor does, without importing the engine. Its turn methods raise the same error, so an instance made around the constructor (object.__new__) serves no turn either. It is not the legacy class: nothing here reads configuration, holds state or runs a body.

Not in :data:__all__; the public import path is symfonic.agent.

It raises the error directly rather than through :func:_refuse, so the test-only legacy_body patch of :func:_refuse does not reach it: no patch of this module's private hook makes the public name construct, and nothing here imports or hands off to symfonic.agent.engine. A test whose subject is the legacy body imports symfonic.agent.engine.SymfonicAgent explicitly while that module exists.

resume

resume(*args: Any, **kwargs: Any) -> NoReturn

Refuses: SymfonicAgent serves no turn from 11.3.

Source code in src/symfonic/agent/entry_point_removal.py
def resume(self, *args: Any, **kwargs: Any) -> NoReturn:
    """Refuses: ``SymfonicAgent`` serves no turn from 11.3."""
    raise EntryPointRemovedError("SymfonicAgent")

resume_interrupt

resume_interrupt(*args: Any, **kwargs: Any) -> NoReturn

Refuses: SymfonicAgent serves no turn from 11.3.

Source code in src/symfonic/agent/entry_point_removal.py
def resume_interrupt(self, *args: Any, **kwargs: Any) -> NoReturn:
    """Refuses: ``SymfonicAgent`` serves no turn from 11.3."""
    raise EntryPointRemovedError("SymfonicAgent")

run

run(*args: Any, **kwargs: Any) -> NoReturn

Refuses: SymfonicAgent serves no turn from 11.3.

Source code in src/symfonic/agent/entry_point_removal.py
def run(self, *args: Any, **kwargs: Any) -> NoReturn:
    """Refuses: ``SymfonicAgent`` serves no turn from 11.3."""
    raise EntryPointRemovedError("SymfonicAgent")

stream

stream(*args: Any, **kwargs: Any) -> NoReturn

Refuses: SymfonicAgent serves no turn from 11.3.

Source code in src/symfonic/agent/entry_point_removal.py
def stream(self, *args: Any, **kwargs: Any) -> NoReturn:
    """Refuses: ``SymfonicAgent`` serves no turn from 11.3."""
    raise EntryPointRemovedError("SymfonicAgent")

stream_text

stream_text(*args: Any, **kwargs: Any) -> NoReturn

Refuses: SymfonicAgent serves no turn from 11.3.

Source code in src/symfonic/agent/entry_point_removal.py
def stream_text(self, *args: Any, **kwargs: Any) -> NoReturn:
    """Refuses: ``SymfonicAgent`` serves no turn from 11.3."""
    raise EntryPointRemovedError("SymfonicAgent")

stream_typed

stream_typed(*args: Any, **kwargs: Any) -> NoReturn

Refuses: SymfonicAgent serves no turn from 11.3.

Source code in src/symfonic/agent/entry_point_removal.py
def stream_typed(self, *args: Any, **kwargs: Any) -> NoReturn:
    """Refuses: ``SymfonicAgent`` serves no turn from 11.3."""
    raise EntryPointRemovedError("SymfonicAgent")