Source code for ralph.agents.invoke._resolved_invocation_runtime
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Callable
[docs]
@dataclass(frozen=True)
class ResolvedInvocationRuntime:
"""Resolved runtime configuration for a single agent invocation.
The optional ``cleanup`` hook is invoked by ``invoke_agent`` in its
``finally`` block after the agent subprocess has finished (success,
failure, or cancellation). It is the documented release path for
transport-specific resources allocated during ``resolve()`` — the
primary example is the per-invocation Codex ``CODEX_HOME``
directory allocated by ``CodexRuntimeResolver`` (see
``ralph.mcp.transport.codex.release_codex_home``).
Lifetime contract:
- ``cleanup`` MUST be safe to call exactly ONCE; ``invoke_agent``
treats it as idempotent only via the implementation (e.g.
``release_codex_home`` returns ``False`` on a second call
without raising, so it is safe even if a caller races the
finally block).
- ``cleanup`` MAY be ``None`` for resolvers that allocate no
per-invocation resources (Claude, OpenCode, Nanocoder, Agy,
Generic, Pi). The ``invoke_agent`` finally block tolerates a
``None`` hook.
- ``cleanup`` is INVOKED EVEN IF THE SUBPROCESS RAISES. The
hook is the mechanism that prevents a long-lived process from
accumulating per-invocation temp directories (or other
transport resources) when an agent run crashes.
Why a callable and not a single-method protocol: the resolver
closes over whatever transport-specific state it needs to release
(for Codex, the ``codex_home`` path string). Encoding the
per-invocation lifetime into a closure keeps the seam narrow
without leaking the resource registry's mutable state into the
public API.
"""
agent_env: dict[str, str] | None = None
server_env: dict[str, str] | None = None
mcp_endpoint: str | None = None
cleanup: Callable[[], None] | None = None