Skip to content

reach.runtime

Agent execution runtime interfaces, selection outcomes, and driver options models.

Define the core AgentRuntime interface and shared runtime agent helpers.

AgentOptions

Bases: BaseModel

Base configuration common to all agent drivers.

Source code in src/reach/runtime/__init__.py
class AgentOptions(BaseModel):
    """Base configuration common to all agent drivers."""

    model_config = ConfigDict(frozen=True, extra="forbid", str_strip_whitespace=True)

    model: str = ""
    effort: str | None = None
    provider: str | None = None
    max_turns: int = Field(default=3, ge=1)
    early_exit: bool = True
    allowed_tools: tuple[str, ...] | None = None
    blocked_env_vars: tuple[str, ...] | None = None
    api_key: str | None = None
    use_symlinks: bool = True
    isolate_config_dir: bool = True
    auto_clean: bool = False
    json_schema: str | None = None

    #: Name of the field configuring an explicit isolation directory, if supported.
    isolation_dir_field: ClassVar[str | None] = None

    @property
    def custom_isolation_dir(self) -> Path | None:
        """Return custom isolation directory path configured on this options instance, if any."""
        if self.isolation_dir_field:
            val = getattr(self, self.isolation_dir_field, None)
            return Path(val) if val is not None else None
        return None

    @model_validator(mode="after")
    def _validate_isolation_dir_boundary(self) -> Self:
        """Validate that custom isolation directory does not point to active home or root."""
        if self.isolation_dir_field and self.custom_isolation_dir is not None:
            from reach.runtime._fs import validate_isolated_directory

            validate_isolated_directory(self.custom_isolation_dir, self.isolation_dir_field)
        return self

custom_isolation_dir property

custom_isolation_dir: Path | None

Return custom isolation directory path configured on this options instance, if any.

AgentRuntime

Bases: ABC

Define standard abstract base class for agent runtime implementations.

Source code in src/reach/runtime/__init__.py
class AgentRuntime[OptionsT: AgentOptions](ABC):
    """Define standard abstract base class for agent runtime implementations."""

    name: str
    settings: RuntimeSettings | None = None
    options: OptionsT = cast("Any", AgentOptions())
    api_key_env_var: str | None = None
    _resident: tuple[str, ...] = ()
    is_dynamic: bool = False

    def __init__(
        self,
        settings: RuntimeSettings | None = None,
        options: OptionsT | None = None,
    ) -> None:
        """Initialize agent runtime settings and options."""
        agent_name = getattr(self, "name", "agent")
        self.settings = settings
        if options is not None:
            self.options = options
        elif settings is not None:
            resolved = resolve_options(settings)
            opt_cls = options_model(agent_name)
            if opt_cls is not None and issubclass(opt_cls, AgentOptions):
                self.options = cast(
                    "OptionsT",
                    resolved
                    if isinstance(resolved, opt_cls)
                    else opt_cls.model_validate(dict(settings.options or {})),
                )
            else:
                self.options = cast(
                    "OptionsT",
                    resolved
                    if isinstance(resolved, AgentOptions)
                    else AgentOptions.model_validate(dict(settings.options or {})),
                )
        else:
            opt_cls = options_model(agent_name)
            if opt_cls is not None and issubclass(opt_cls, AgentOptions):
                self.options = cast("OptionsT", opt_cls())
            else:
                self.options = cast("OptionsT", AgentOptions())
        self._resident = ()

    @property
    def timeout_s(self) -> int | None:
        """Return per-probe execution timeout in seconds from settings."""
        return self.settings.timeout_s if self.settings is not None else None

    @property
    def skills_subpath(self) -> str:
        """Return relative skill directory subpath from profile or runtime default."""
        profile = agent_profiles().get(self.name)

        if profile is not None and profile.skills_dir:
            return profile.skills_dir
        if subpath := getattr(self, "_skills_subpath", None):
            return str(subpath)
        return ""

    @property
    def model(self) -> str:
        """Return the identifier of the model being evaluated."""
        return self.options.model

    @model.setter
    def model(self, value: str) -> None:
        """Update the configured model identifier in options."""
        self.options = self.options.model_copy(update={"model": value})

    @property
    def effort(self) -> str | None:
        """Return the reasoning effort tier being evaluated."""
        return self.options.effort

    @property
    def provider(self) -> str | None:
        """Return the model provider identifier being evaluated."""
        return self.options.provider

    @property
    def max_turns(self) -> int:
        """Return the maximum turns configured on the runtime options."""
        return self.options.max_turns

    @property
    def early_exit(self) -> bool:
        """Return whether early exit is enabled on the runtime options."""
        return self.options.early_exit

    @property
    def api_key(self) -> str | None:
        """Return the API key string configured on the runtime options."""
        return self.options.api_key

    @property
    def allowed_tools(self) -> tuple[str, ...] | None:
        """Return explicit allowed tools override from options or settings."""
        return (
            self.options.allowed_tools
            if self.options.allowed_tools is not None
            else getattr(self.settings, "allowed_tools", None)
        )

    @property
    def blocked_env_vars(self) -> tuple[str, ...] | None:
        """Return explicit blocked environment variables override from options or settings."""
        return resolve_blocked_env_vars(self.options, self.settings)

    @property
    def use_symlinks(self) -> bool:
        """Return whether symlink installation is enabled on the runtime options."""
        return self.options.use_symlinks

    @property
    def isolate_config_dir(self) -> bool:
        """Return whether isolated runtime config is enabled on the runtime options."""
        return self.options.isolate_config_dir

    @property
    def auto_clean(self) -> bool:
        """Return whether automatic post-probe cleanup is enabled on the runtime options."""
        return self.options.auto_clean

    @property
    def rations_catalog(self) -> bool:
        """Return True if this runtime actively rations skill listing budgets."""
        return False

    @property
    def is_cli(self) -> bool:
        """Return True if this runtime executes via a CLI subprocess."""
        return False

    @property
    def isolation_dir_field(self) -> str | None:
        """Return the options field name used for custom directory isolation, if supported."""
        return getattr(self.options, "isolation_dir_field", None)

    @property
    def custom_isolation_dir(self) -> Path | None:
        """Return the configured custom isolation directory path, or None."""
        return getattr(self.options, "custom_isolation_dir", None)

    def skills_dir(self, workdir: Path) -> Path:
        """Return standard skill directory path in the workspace."""
        return Path(workdir) / self.skills_subpath

    def skill_roots(self, workdir: Path) -> tuple[SkillRoot, ...]:
        """Return discovery directories where runtime searches for skills."""
        here = self.skills_dir(resolve_path(workdir))
        return (SkillRoot(path=here, scope="project", precedence=0),) if here.is_dir() else ()

    def fit(self, catalog: Catalog, skills: Iterable[Skill]) -> CatalogFit:  # noqa: ARG002
        """Evaluate whether a catalog fits listing budgets without materializing."""
        return CatalogFit()

    def install(self, catalog: Catalog, skills: Iterable[Skill], workdir: Path) -> Path:
        """Materialize resident skills in workspace and return workspace path."""
        target = resolve_path(workdir)
        self._validate_install(target)
        by_name = resolve_catalog_skills(catalog, skills)
        self._resident = install_skills(
            catalog,
            by_name,
            self.skills_dir(target),
            use_symlinks=self.use_symlinks,
        )
        self._post_install(target)
        return target

    def _validate_install(self, workdir: Path) -> None:
        """Validate workspace preconditions before installation."""
        del workdir

    def _post_install(self, workdir: Path) -> None:
        """Configure permissions or settings after installation."""
        del workdir

    def post_probe(self, workdir: Path) -> None:
        """Execute post-probe cleanup actions."""
        del workdir

    def clone_isolated(self) -> Self:
        """Create a thread-local isolated clone of this runtime."""
        clone = copy.copy(self)
        clone._resident = ()  # noqa: SLF001
        return clone

    def cleanup(self) -> None:  # noqa: B027
        """Release any isolated temporary resources owned by this runtime."""

    def build_env(self, workdir: Path | None = None) -> dict[str, str]:
        """Assemble process environment with API keys and workspace overrides."""
        del workdir
        env = dict(os.environ)
        if (home_dir := getattr(self.options, "home_dir", None)) is not None:
            env["HOME"] = str(home_dir)
        if api_key_var := self.api_key_env_var:
            if (api_key := self.api_key) is not None:
                env[api_key_var] = str(api_key)
            elif not env.get(api_key_var) and (resolved := resolve_env_secret(env, api_key_var)):
                env[api_key_var] = resolved
            env.pop(f"{api_key_var}_FILE", None)
        return sanitize_subprocess_env(env, blocked_env_vars=self.blocked_env_vars)

    def _make_tracker(self, target_skill: str | None = None) -> TrajectoryTracker:
        """Create a TrajectoryTracker configured with this runtime's turn and early-exit options."""
        return TrajectoryTracker(
            target_skill=target_skill,
            max_turns=self.options.max_turns,
            early_exit=self.options.early_exit,
        )

    @abstractmethod
    def select(
        self,
        query_text: str,
        workdir: Path,
        target_skill: str | None = None,
    ) -> SelectionOutcome:
        """Execute a single query probe and return the observed skill selection."""
        ...

    @property
    def effective_effort(self) -> str | None:
        """Return configured reasoning effort or default from model profile."""
        options = getattr(self, "options", None)
        if options is not None and (effort := getattr(options, "effort", None)):
            return None if effort.lower() in ("none", "off") else effort
        try:
            return model_profile(self.model).effort
        except (KeyError, ValueError):
            return None

    def resident_skill_paths(self, workdir: Path) -> frozenset[Path]:
        """Return set of valid filesystem directory paths for resident skills."""
        skills_dir = self.skills_dir(resolve_path(workdir))
        return frozenset(resolve_path(skills_dir / name) for name in self._resident)

    def parse_stream(
        self,
        lines: Iterable[str],
        resident: Sequence[str] = (),
        early_exit: bool = False,
    ) -> SessionSummary:
        """Parse transcript or log lines into a standardized SessionSummary.

        Default implementation records early_exit and assigns SUCCESS status
        if lines were produced. Subclasses override this to extract tool
        invocations, reasoning, and telemetry.
        """
        del resident
        line_list = list(lines)
        return SessionSummary(
            early_exit=early_exit,
            status=SessionStatus.SUCCESS if line_list else None,
        )

allowed_tools property

allowed_tools: tuple[str, ...] | None

Return explicit allowed tools override from options or settings.

api_key property

api_key: str | None

Return the API key string configured on the runtime options.

auto_clean property

auto_clean: bool

Return whether automatic post-probe cleanup is enabled on the runtime options.

blocked_env_vars property

blocked_env_vars: tuple[str, ...] | None

Return explicit blocked environment variables override from options or settings.

custom_isolation_dir property

custom_isolation_dir: Path | None

Return the configured custom isolation directory path, or None.

early_exit property

early_exit: bool

Return whether early exit is enabled on the runtime options.

effective_effort property

effective_effort: str | None

Return configured reasoning effort or default from model profile.

effort property

effort: str | None

Return the reasoning effort tier being evaluated.

is_cli property

is_cli: bool

Return True if this runtime executes via a CLI subprocess.

isolate_config_dir property

isolate_config_dir: bool

Return whether isolated runtime config is enabled on the runtime options.

isolation_dir_field property

isolation_dir_field: str | None

Return the options field name used for custom directory isolation, if supported.

max_turns property

max_turns: int

Return the maximum turns configured on the runtime options.

model property writable

model: str

Return the identifier of the model being evaluated.

provider property

provider: str | None

Return the model provider identifier being evaluated.

rations_catalog property

rations_catalog: bool

Return True if this runtime actively rations skill listing budgets.

skills_subpath property

skills_subpath: str

Return relative skill directory subpath from profile or runtime default.

timeout_s property

timeout_s: int | None

Return per-probe execution timeout in seconds from settings.

use_symlinks: bool

Return whether symlink installation is enabled on the runtime options.

__init__

__init__(
    settings: RuntimeSettings | None = None,
    options: OptionsT | None = None,
) -> None

Initialize agent runtime settings and options.

Source code in src/reach/runtime/__init__.py
def __init__(
    self,
    settings: RuntimeSettings | None = None,
    options: OptionsT | None = None,
) -> None:
    """Initialize agent runtime settings and options."""
    agent_name = getattr(self, "name", "agent")
    self.settings = settings
    if options is not None:
        self.options = options
    elif settings is not None:
        resolved = resolve_options(settings)
        opt_cls = options_model(agent_name)
        if opt_cls is not None and issubclass(opt_cls, AgentOptions):
            self.options = cast(
                "OptionsT",
                resolved
                if isinstance(resolved, opt_cls)
                else opt_cls.model_validate(dict(settings.options or {})),
            )
        else:
            self.options = cast(
                "OptionsT",
                resolved
                if isinstance(resolved, AgentOptions)
                else AgentOptions.model_validate(dict(settings.options or {})),
            )
    else:
        opt_cls = options_model(agent_name)
        if opt_cls is not None and issubclass(opt_cls, AgentOptions):
            self.options = cast("OptionsT", opt_cls())
        else:
            self.options = cast("OptionsT", AgentOptions())
    self._resident = ()

build_env

build_env(workdir: Path | None = None) -> dict[str, str]

Assemble process environment with API keys and workspace overrides.

Source code in src/reach/runtime/__init__.py
def build_env(self, workdir: Path | None = None) -> dict[str, str]:
    """Assemble process environment with API keys and workspace overrides."""
    del workdir
    env = dict(os.environ)
    if (home_dir := getattr(self.options, "home_dir", None)) is not None:
        env["HOME"] = str(home_dir)
    if api_key_var := self.api_key_env_var:
        if (api_key := self.api_key) is not None:
            env[api_key_var] = str(api_key)
        elif not env.get(api_key_var) and (resolved := resolve_env_secret(env, api_key_var)):
            env[api_key_var] = resolved
        env.pop(f"{api_key_var}_FILE", None)
    return sanitize_subprocess_env(env, blocked_env_vars=self.blocked_env_vars)

cleanup

cleanup() -> None

Release any isolated temporary resources owned by this runtime.

Source code in src/reach/runtime/__init__.py
def cleanup(self) -> None:  # noqa: B027
    """Release any isolated temporary resources owned by this runtime."""

clone_isolated

clone_isolated() -> Self

Create a thread-local isolated clone of this runtime.

Source code in src/reach/runtime/__init__.py
def clone_isolated(self) -> Self:
    """Create a thread-local isolated clone of this runtime."""
    clone = copy.copy(self)
    clone._resident = ()  # noqa: SLF001
    return clone

fit

fit(
    catalog: Catalog, skills: Iterable[Skill]
) -> CatalogFit

Evaluate whether a catalog fits listing budgets without materializing.

Source code in src/reach/runtime/__init__.py
def fit(self, catalog: Catalog, skills: Iterable[Skill]) -> CatalogFit:  # noqa: ARG002
    """Evaluate whether a catalog fits listing budgets without materializing."""
    return CatalogFit()

install

install(
    catalog: Catalog, skills: Iterable[Skill], workdir: Path
) -> Path

Materialize resident skills in workspace and return workspace path.

Source code in src/reach/runtime/__init__.py
def install(self, catalog: Catalog, skills: Iterable[Skill], workdir: Path) -> Path:
    """Materialize resident skills in workspace and return workspace path."""
    target = resolve_path(workdir)
    self._validate_install(target)
    by_name = resolve_catalog_skills(catalog, skills)
    self._resident = install_skills(
        catalog,
        by_name,
        self.skills_dir(target),
        use_symlinks=self.use_symlinks,
    )
    self._post_install(target)
    return target

parse_stream

parse_stream(
    lines: Iterable[str],
    resident: Sequence[str] = (),
    early_exit: bool = False,
) -> SessionSummary

Parse transcript or log lines into a standardized SessionSummary.

Default implementation records early_exit and assigns SUCCESS status if lines were produced. Subclasses override this to extract tool invocations, reasoning, and telemetry.

Source code in src/reach/runtime/__init__.py
def parse_stream(
    self,
    lines: Iterable[str],
    resident: Sequence[str] = (),
    early_exit: bool = False,
) -> SessionSummary:
    """Parse transcript or log lines into a standardized SessionSummary.

    Default implementation records early_exit and assigns SUCCESS status
    if lines were produced. Subclasses override this to extract tool
    invocations, reasoning, and telemetry.
    """
    del resident
    line_list = list(lines)
    return SessionSummary(
        early_exit=early_exit,
        status=SessionStatus.SUCCESS if line_list else None,
    )

post_probe

post_probe(workdir: Path) -> None

Execute post-probe cleanup actions.

Source code in src/reach/runtime/__init__.py
def post_probe(self, workdir: Path) -> None:
    """Execute post-probe cleanup actions."""
    del workdir

resident_skill_paths

resident_skill_paths(workdir: Path) -> frozenset[Path]

Return set of valid filesystem directory paths for resident skills.

Source code in src/reach/runtime/__init__.py
def resident_skill_paths(self, workdir: Path) -> frozenset[Path]:
    """Return set of valid filesystem directory paths for resident skills."""
    skills_dir = self.skills_dir(resolve_path(workdir))
    return frozenset(resolve_path(skills_dir / name) for name in self._resident)

select abstractmethod

select(
    query_text: str,
    workdir: Path,
    target_skill: str | None = None,
) -> SelectionOutcome

Execute a single query probe and return the observed skill selection.

Source code in src/reach/runtime/__init__.py
@abstractmethod
def select(
    self,
    query_text: str,
    workdir: Path,
    target_skill: str | None = None,
) -> SelectionOutcome:
    """Execute a single query probe and return the observed skill selection."""
    ...

skill_roots

skill_roots(workdir: Path) -> tuple[SkillRoot, ...]

Return discovery directories where runtime searches for skills.

Source code in src/reach/runtime/__init__.py
def skill_roots(self, workdir: Path) -> tuple[SkillRoot, ...]:
    """Return discovery directories where runtime searches for skills."""
    here = self.skills_dir(resolve_path(workdir))
    return (SkillRoot(path=here, scope="project", precedence=0),) if here.is_dir() else ()

skills_dir

skills_dir(workdir: Path) -> Path

Return standard skill directory path in the workspace.

Source code in src/reach/runtime/__init__.py
def skills_dir(self, workdir: Path) -> Path:
    """Return standard skill directory path in the workspace."""
    return Path(workdir) / self.skills_subpath

AntigravityOptions

Bases: VertexOptions

Configure common options for Antigravity-ecosystem agent runtimes.

Source code in src/reach/runtime/__init__.py
class AntigravityOptions(VertexOptions):
    """Configure common options for Antigravity-ecosystem agent runtimes."""

    use_symlinks: bool = False

    @property
    def effective_vertex(self) -> bool:
        """Return True if Vertex AI / Enterprise ADC mode is active.

        When vertex is not explicitly set and no Vertex toggle env var is active,
        ambient GEMINI_API_KEY / GOOGLE_API_KEY takes precedence over implicit
        GOOGLE_CLOUD_PROJECT detection.
        """
        if self.vertex is not None:
            return self.vertex
        if has_agy_vertex_env(os.environ):
            return True
        has_api_key = bool(
            self.api_key or resolve_env_secret(os.environ, "GEMINI_API_KEY", "GOOGLE_API_KEY")
        )
        return not has_api_key and bool(self.project or resolve_registry_project(self.project))

    @property
    def effective_project(self) -> str | None:
        """Return resolved Google Cloud project ID when Vertex/ADC is active.

        When api_key is explicitly set alongside Vertex (Express Mode), omit
        ambient/registry project fallback because VertexEndpoint forbids combining
        api_key with regional project/location parameters.
        """
        if not self.effective_vertex:
            return None
        if self.api_key:
            return self.project
        return resolve_registry_project(self.project)

    @property
    def effective_location(self) -> str | None:
        """Return resolved Google Cloud location when Vertex/ADC is active.

        When api_key is explicitly set alongside Vertex (Express Mode), omit
        ambient/registry location fallback because VertexEndpoint forbids combining
        api_key with regional project/location parameters.
        """
        if not self.effective_vertex:
            return None
        if self.api_key:
            return self.location
        return resolve_registry_location(self.location)

    @property
    def effective_api_key(self) -> str | None:
        """Return configured API key or fallback to environment variables."""
        if self.api_key:
            return self.api_key
        if self.effective_vertex:
            return None
        return resolve_env_secret(os.environ, "GEMINI_API_KEY", "GOOGLE_API_KEY")

    def resolve_model_provider(self, model: str = "") -> str | None:
        """Resolve model provider unless Vertex/ADC mode is active without explicit provider."""
        if self.effective_vertex and not self.provider:
            return None
        return detect_model_provider(
            model or self.model,
            self.provider,
            api_key=self.api_key,
        )

    def resolve_schema_dict(
        self,
        schema: str | Mapping[str, Any] | None = None,
    ) -> dict[str, Any] | None:
        """Parse and validate explicit or configured JSON schema into a dictionary."""
        if isinstance(schema, Mapping):
            return dict(schema)
        raw_schema = schema if isinstance(schema, str) else self.json_schema
        if not raw_schema:
            return None
        try:
            parsed = json.loads(raw_schema)
        except json.JSONDecodeError as exc:
            msg = f"Invalid JSON schema: {exc}"
            raise ValueError(msg) from exc
        if not isinstance(parsed, dict):
            msg = f"Expected JSON schema object, got {type(parsed).__name__}"
            raise ValueError(msg)
        return parsed

effective_api_key property

effective_api_key: str | None

Return configured API key or fallback to environment variables.

effective_location property

effective_location: str | None

Return resolved Google Cloud location when Vertex/ADC is active.

When api_key is explicitly set alongside Vertex (Express Mode), omit ambient/registry location fallback because VertexEndpoint forbids combining api_key with regional project/location parameters.

effective_project property

effective_project: str | None

Return resolved Google Cloud project ID when Vertex/ADC is active.

When api_key is explicitly set alongside Vertex (Express Mode), omit ambient/registry project fallback because VertexEndpoint forbids combining api_key with regional project/location parameters.

effective_vertex property

effective_vertex: bool

Return True if Vertex AI / Enterprise ADC mode is active.

When vertex is not explicitly set and no Vertex toggle env var is active, ambient GEMINI_API_KEY / GOOGLE_API_KEY takes precedence over implicit GOOGLE_CLOUD_PROJECT detection.

resolve_model_provider

resolve_model_provider(model: str = '') -> str | None

Resolve model provider unless Vertex/ADC mode is active without explicit provider.

Source code in src/reach/runtime/__init__.py
def resolve_model_provider(self, model: str = "") -> str | None:
    """Resolve model provider unless Vertex/ADC mode is active without explicit provider."""
    if self.effective_vertex and not self.provider:
        return None
    return detect_model_provider(
        model or self.model,
        self.provider,
        api_key=self.api_key,
    )

resolve_schema_dict

resolve_schema_dict(
    schema: str | Mapping[str, Any] | None = None,
) -> dict[str, Any] | None

Parse and validate explicit or configured JSON schema into a dictionary.

Source code in src/reach/runtime/__init__.py
def resolve_schema_dict(
    self,
    schema: str | Mapping[str, Any] | None = None,
) -> dict[str, Any] | None:
    """Parse and validate explicit or configured JSON schema into a dictionary."""
    if isinstance(schema, Mapping):
        return dict(schema)
    raw_schema = schema if isinstance(schema, str) else self.json_schema
    if not raw_schema:
        return None
    try:
        parsed = json.loads(raw_schema)
    except json.JSONDecodeError as exc:
        msg = f"Invalid JSON schema: {exc}"
        raise ValueError(msg) from exc
    if not isinstance(parsed, dict):
        msg = f"Expected JSON schema object, got {type(parsed).__name__}"
        raise ValueError(msg)
    return parsed

CatalogFit

Bases: BaseModel

Report catalog residency limits and potential description truncation metrics.

Source code in src/reach/runtime/__init__.py
class CatalogFit(BaseModel):
    """Report catalog residency limits and potential description truncation metrics."""

    model_config = ConfigDict(frozen=True)

    allowed: int = Field(default=0, ge=0)
    asked: int = Field(default=0, ge=0)
    unit: str = ""
    truncated: int = Field(default=0, ge=0)
    remedy: str = ""
    elided_skills: tuple[str, ...] = ()

    @property
    def rations(self) -> bool:
        """Return True if the runtime enforces space limitations on catalog listings."""
        return self.allowed > 0

    @property
    def whole(self) -> bool:
        """Return True if all skills are presented without description truncation."""
        return not self.truncated

rations property

rations: bool

Return True if the runtime enforces space limitations on catalog listings.

whole property

whole: bool

Return True if all skills are presented without description truncation.

CliOptions

Bases: AgentOptions

Hold common configuration options for CLI subprocess-driven agent runtimes.

Source code in src/reach/runtime/__init__.py
class CliOptions(AgentOptions):
    """Hold common configuration options for CLI subprocess-driven agent runtimes."""

    executable: str = ""
    extra_args: tuple[str, ...] = ()

    def effort_args(self, flag: str = "--effort") -> list[str]:
        """Format CLI argument pair for non-empty effort setting."""
        return [flag, self.effort] if self.effort else []

    def provider_args(self, flag: str = "--provider") -> list[str]:
        """Format CLI argument pair for non-empty provider setting."""
        return [flag, self.provider] if self.provider else []

    def max_turns_args(self, flag: str = "--max-turns") -> list[str]:
        """Format CLI argument pair for non-None max_turns setting."""
        return [flag, str(self.max_turns)] if self.max_turns is not None else []

    def api_key_args(self, flag: str = "--api-key") -> list[str]:
        """Format CLI argument pair for non-empty api_key setting."""
        return [flag, self.api_key] if self.api_key else []

api_key_args

api_key_args(flag: str = '--api-key') -> list[str]

Format CLI argument pair for non-empty api_key setting.

Source code in src/reach/runtime/__init__.py
def api_key_args(self, flag: str = "--api-key") -> list[str]:
    """Format CLI argument pair for non-empty api_key setting."""
    return [flag, self.api_key] if self.api_key else []

effort_args

effort_args(flag: str = '--effort') -> list[str]

Format CLI argument pair for non-empty effort setting.

Source code in src/reach/runtime/__init__.py
def effort_args(self, flag: str = "--effort") -> list[str]:
    """Format CLI argument pair for non-empty effort setting."""
    return [flag, self.effort] if self.effort else []

max_turns_args

max_turns_args(flag: str = '--max-turns') -> list[str]

Format CLI argument pair for non-None max_turns setting.

Source code in src/reach/runtime/__init__.py
def max_turns_args(self, flag: str = "--max-turns") -> list[str]:
    """Format CLI argument pair for non-None max_turns setting."""
    return [flag, str(self.max_turns)] if self.max_turns is not None else []

provider_args

provider_args(flag: str = '--provider') -> list[str]

Format CLI argument pair for non-empty provider setting.

Source code in src/reach/runtime/__init__.py
def provider_args(self, flag: str = "--provider") -> list[str]:
    """Format CLI argument pair for non-empty provider setting."""
    return [flag, self.provider] if self.provider else []

SelectionOutcome

Bases: _ProbeTelemetry

Represent the observable result of probing an agent runtime with a query.

Source code in src/reach/runtime/__init__.py
class SelectionOutcome(_ProbeTelemetry):
    """Represent the observable result of probing an agent runtime with a query."""

    @model_validator(mode="before")
    @classmethod
    def _enforce_early_exit_invariants(cls, data: Any) -> Any:  # noqa: ANN401
        """Ensure process cancellation artifacts are never reported as probe errors."""
        if isinstance(data, dict):
            early = data.get("early_exit", False)
            err = data.get("error")
            if early and err and not str(err).startswith(("tool leak", "residency leak")):
                data = dict(data)
                data["error"] = None
        return data

SessionStatus

Bases: StrEnum

Enumerate canonical terminal execution statuses of an agent session.

Source code in src/reach/runtime/__init__.py
class SessionStatus(StrEnum):
    """Enumerate canonical terminal execution statuses of an agent session."""

    CANCELLED = "CANCELLED"
    ERROR = "ERROR"
    SUCCESS = "SUCCESS"
    TIMEOUT = "TIMEOUT"

SessionSummary

Bases: _ProbeTelemetry

Hold parsed session outcomes and telemetry across CLI runtime logs.

Source code in src/reach/runtime/__init__.py
class SessionSummary(_ProbeTelemetry):
    """Hold parsed session outcomes and telemetry across CLI runtime logs."""

    tool_calls: tuple[ToolCallInfo, ...] = ()
    status: SessionStatus | str | None = None
    retries: int = 0

    @field_validator("status", mode="before")
    @classmethod
    def _normalize_status(cls, value: object) -> SessionStatus | str | None:
        """Coerce known status variants to canonical SessionStatus enum members."""
        if value is None or isinstance(value, SessionStatus):
            return value
        if isinstance(value, str):
            normalized = value.strip()
            upper = normalized.upper()
            try:
                return SessionStatus(upper)
            except ValueError:
                return normalized
        return str(value)

    @property
    def saw_result(self) -> bool:
        """Return True if stream contained a terminal result event or early exit."""
        return self.status is not None or self.early_exit

    @model_validator(mode="before")
    @classmethod
    def _derive_observed_tools(cls, data: Any) -> Any:  # noqa: ANN401
        """Populate observed tools from tool calls if not explicitly provided."""
        if isinstance(data, dict):
            calls = data.get("tool_calls")
            if calls and not data.get("observed_tools"):
                names = sorted(
                    {c.name if hasattr(c, "name") else c.get("name") for c in calls if c}
                )
                data = dict(data)
                data["observed_tools"] = tuple(n for n in names if n)
        return data

    def to_outcome(
        self,
        observed_catalog: tuple[str, ...] | list[str] = (),
        fallback_model: str = "",
        early_exit: bool = False,
        turns_taken: int | None = None,
    ) -> SelectionOutcome:
        """Convert parsed session summary into a canonical SelectionOutcome."""
        effective_early_exit = early_exit or self.early_exit
        turns = turns_taken if turns_taken is not None else self.turns_taken

        catalog = tuple(observed_catalog) or self.observed_catalog
        return SelectionOutcome(
            cost_usd=self.cost_usd,
            duration_ms=self.duration_ms,
            prompt_tokens=self.prompt_tokens,
            error=self.error,
            invoked_skills=self.invoked_skills,
            early_exit=effective_early_exit,
            turns_taken=turns,
            observed_tools=self.observed_tools,
            reasoning=self.reasoning,
            resolved_model=self.resolved_model or fallback_model,
            observed_catalog=catalog,
        )

saw_result property

saw_result: bool

Return True if stream contained a terminal result event or early exit.

to_outcome

to_outcome(
    observed_catalog: tuple[str, ...] | list[str] = (),
    fallback_model: str = "",
    early_exit: bool = False,
    turns_taken: int | None = None,
) -> SelectionOutcome

Convert parsed session summary into a canonical SelectionOutcome.

Source code in src/reach/runtime/__init__.py
def to_outcome(
    self,
    observed_catalog: tuple[str, ...] | list[str] = (),
    fallback_model: str = "",
    early_exit: bool = False,
    turns_taken: int | None = None,
) -> SelectionOutcome:
    """Convert parsed session summary into a canonical SelectionOutcome."""
    effective_early_exit = early_exit or self.early_exit
    turns = turns_taken if turns_taken is not None else self.turns_taken

    catalog = tuple(observed_catalog) or self.observed_catalog
    return SelectionOutcome(
        cost_usd=self.cost_usd,
        duration_ms=self.duration_ms,
        prompt_tokens=self.prompt_tokens,
        error=self.error,
        invoked_skills=self.invoked_skills,
        early_exit=effective_early_exit,
        turns_taken=turns,
        observed_tools=self.observed_tools,
        reasoning=self.reasoning,
        resolved_model=self.resolved_model or fallback_model,
        observed_catalog=catalog,
    )

SkillRoot

Bases: BaseModel

Represent a skill discovery directory location and its resolution precedence.

Source code in src/reach/runtime/__init__.py
class SkillRoot(BaseModel):
    """Represent a skill discovery directory location and its resolution precedence."""

    model_config = ConfigDict(frozen=True)

    path: Path
    scope: str
    precedence: int = Field(default=0, ge=0)

ToolCallInfo

Bases: BaseModel

Represent an observed tool invocation and its parameters.

Source code in src/reach/runtime/__init__.py
class ToolCallInfo(BaseModel):
    """Represent an observed tool invocation and its parameters."""

    model_config = ConfigDict(frozen=True)

    name: str = ""
    parameters: dict[str, Any] = Field(default_factory=dict)

    def __init__(
        self,
        name: str = "",
        parameters: dict[str, Any] | None = None,
        path: str | None = None,
        **data: Any,  # noqa: ANN401
    ) -> None:
        """Initialize tool invocation with optional direct path argument."""
        params = dict(parameters or data.pop("parameters", None) or {})
        if path is not None and "path" not in params and "AbsolutePath" not in params:
            params["path"] = str(path)
        super().__init__(name=name, parameters=params, **data)

    @model_validator(mode="before")
    @classmethod
    def _coerce_path(cls, data: Any) -> Any:  # noqa: ANN401
        """Populate parameters with path keyword argument when provided directly."""
        if isinstance(data, dict) and ("path" in data or data.get("parameters") is None):
            data = dict(data)
            params = dict(data.get("parameters") or {})
            if "path" in data:
                val = data.pop("path")
                if val is not None and "path" not in params and "AbsolutePath" not in params:
                    params["path"] = str(val)
            data["parameters"] = params
        return data

    @property
    def path(self) -> str | None:
        """Extract first non-empty filesystem path from recognized tool parameters."""
        from reach.runtime._fs import extract_tool_path

        return extract_tool_path(self.parameters)

path property

path: str | None

Extract first non-empty filesystem path from recognized tool parameters.

__init__

__init__(
    name: str = "",
    parameters: dict[str, Any] | None = None,
    path: str | None = None,
    **data: Any,
) -> None

Initialize tool invocation with optional direct path argument.

Source code in src/reach/runtime/__init__.py
def __init__(
    self,
    name: str = "",
    parameters: dict[str, Any] | None = None,
    path: str | None = None,
    **data: Any,  # noqa: ANN401
) -> None:
    """Initialize tool invocation with optional direct path argument."""
    params = dict(parameters or data.pop("parameters", None) or {})
    if path is not None and "path" not in params and "AbsolutePath" not in params:
        params["path"] = str(path)
    super().__init__(name=name, parameters=params, **data)

VertexOptions

Bases: AgentOptions

Configure Google Cloud Vertex AI and Application Default Credentials options.

Source code in src/reach/runtime/__init__.py
class VertexOptions(AgentOptions):
    """Configure Google Cloud Vertex AI and Application Default Credentials options."""

    vertex: bool | None = None
    project: str | None = None
    location: str | None = None

build_runtime

build_runtime(settings: RuntimeSettings) -> AgentRuntime

Instantiate and configure an AgentRuntime from settings.

Source code in src/reach/runtime/__init__.py
def build_runtime(settings: RuntimeSettings) -> AgentRuntime:
    """Instantiate and configure an AgentRuntime from settings."""
    if settings.agent in _AGENT_FACTORIES:
        rt = _AGENT_FACTORIES[settings.agent][0](settings)
    else:
        builtin = _load_builtin_entry(settings.agent)
        if builtin is not None:
            rt = builtin[0](settings)
        else:
            agents = ", ".join(known_agents())
            msg = f"unknown runtime agent {settings.agent!r}; expected one of {agents}"
            raise ValueError(msg)
    if getattr(rt, "settings", None) is None:
        rt.settings = settings
    return rt

known_agents

known_agents(
    config_path: Path | str | None = None,
) -> tuple[str, ...]

Return tuple of supported agent runtime names from configuration.

Source code in src/reach/runtime/__init__.py
def known_agents(config_path: Path | str | None = None) -> tuple[str, ...]:
    """Return tuple of supported agent runtime names from configuration."""
    profiles = agent_profiles(config_path)
    builtins = set(_BUILTIN_AGENTS.keys())
    if profiles:
        return tuple(sorted(set(profiles.keys()) | builtins | set(_AGENT_FACTORIES.keys())))
    return tuple(sorted(builtins | set(_AGENT_FACTORIES.keys())))

register_agent

register_agent(
    name: str,
    factory: Callable[[RuntimeSettings], AgentRuntime],
    options: type[BaseModel] | None = None,
) -> None

Register a runtime factory and optional options schema for an agent name.

Source code in src/reach/runtime/__init__.py
def register_agent(
    name: str,
    factory: Callable[[RuntimeSettings], AgentRuntime],
    options: type[BaseModel] | None = None,
) -> None:
    """Register a runtime factory and optional options schema for an agent name."""
    _AGENT_FACTORIES[name] = (factory, options)