Running

run.run()

Execute a RunSpec asynchronously, retrying transient failures with backoff.

Usage

Source

run.run(
    spec,
    *,
    backend=None,
)

Each attempt runs through backend.aexecute; the core’s retry_decision op classifies a Response.error (a 529, overloaded, rate-limit, or 5xx) and returns the backoff to sleep before another attempt, up to spec.max_attempts. The final Response — success or last failure — is returned without raising; every operational failure (nonzero exit, error envelope, timeout, validation) lives in resp.error.

Parameters

spec: RunSpec

The configured run to execute.

backend: LlmBackend | None = None
The backend to run on; defaults to select_backend().

Returns

Response

The resolved Response of the last attempt, carrying every retried-away

attempt in discarded_attempts.

run.run_sync()

Execute a RunSpec synchronously, retrying transient failures with backoff.

Usage

Source

run.run_sync(spec, *, backend=None)

The synchronous companion to run: each attempt runs through backend.execute, the core decides retry and backoff, and the last Response is returned without raising.

Parameters

spec: RunSpec

The configured run to execute.

backend: LlmBackend | None = None
The backend to run on; defaults to select_backend().

Returns

Response

The resolved Response of the last attempt, carrying every retried-away

attempt in discarded_attempts.

RunSpec

A single configured run, translated per backend at execution time.

Usage

Source

RunSpec(
    prompt,
    model,
    response_model=None,
    schema=None,
    agent=False,
    isolated=True,
    cwd=None,
    env=None,
    api_auth=False,
    timeout=180,
    max_attempts=5,
    provider_configs=dict()
)

Common fields are interpreted by every backend; provider_configs carries optional per-provider flag passthrough that only the matching backend reads. model is a literal provider model id (opus, sonnet, …) passed straight through with no tier mapping. isolated (default True) runs the backend against a fresh, host-free config home so a spawned CLI ignores ambient settings, MCP servers, and hooks. api_auth (default False) strips the provider’s API-key environment variables from the child process so the CLI bills the logged-in subscription; True inherits the environment untouched. Structured output comes from either a response_model (validated to a model) or a raw schema (a JSON-Schema dict or pre-serialized string, passed to the provider verbatim, with nothing to validate); setting both raises ValueError.

Parameter Attributes

prompt: str
model: str
response_model: type[BaseModel] | None = None
schema: dict[str, object] | str | None = None
agent: bool = False
isolated: bool = True
cwd: str | None = None
env: dict[str, str] | None = None
api_auth: bool = False
timeout: int = 180
max_attempts: int = 5
provider_configs: dict[ProviderName, ProviderConfig] = dict()

Example

>>> RunSpec(prompt="ping", model="opus")

Methods

Name Description
config_for() Return the first provider config that is an instance of kind, or None.
config_for()

Return the first provider config that is an instance of kind, or None.

Usage

Source

config_for(kind)

Response

A backend’s fully-resolved outcome: the spec, the raw output, and exactly one of result/error.

Usage

Source

Response(spec, output, result=None, error=None, discarded_attempts=())

A backend runs the process, reads its output wherever the provider writes it, detects failure, and validates — then hands back one Response. spec and output are always present (the raw bytes live in output.raw even on failure); exactly one of result/error is set. Every failure — a nonzero exit, an error envelope, a timeout, or a validation error — routes through error, never a raise from run. discarded_attempts carries the transient failures run retried away before this one, empty when there were none.

Parameter Attributes

spec: RunSpec
output: Output
result: Result | None = None
error: Error | None = None
discarded_attempts: tuple[DiscardedAttempt, …] = ()

Example

>>> Response(spec=spec, output=Output(raw="hi"), result=Result(raw="hi"))

Result

A successful run: the extracted final text and the optional validated model.

Usage

Source

Result(raw, parsed=None)

raw is the extracted final text; parsed is the validated model, set only when the RunSpec carried a response_model.

Parameter Attributes

raw: str
parsed: BaseModel | None = None

Example

>>> Result(raw="hello", parsed=None)

Output

The full unparsed transport stream, present on success and failure alike.

Usage

Source

Output(raw)

raw is the complete output the provider wrote — the claude --output-format json event stream, the codex -o file, or plain stdout — before any extraction.

Parameter Attributes

raw: str

Example

>>> Output(raw='[{"type": "system"}, {"type": "result", "result": "hi"}]')

Error

A failed run: a human-readable message plus the underlying exception.

Usage

Source

Error(msg, ex)

ex preserves the real exception so a caller can re-raise it unchanged — a BackendCallError for a nonzero exit or error envelope, a normalized timeout error, or a pydantic.ValidationError for a non-conforming model.

Parameter Attributes

msg: str
ex: Exception

Example

>>> Error(msg="codex exited 127: codex: not found", ex=RuntimeError("..."))

DiscardedAttempt

A transient failure the retry loop threw away, summarized for spend accounting.

Usage

Source

DiscardedAttempt(attempt, error, cost_usd, usage, raw_bytes)

run/run_sync return only the final attempt’s Response, so a caller tracking spend never sees the cost of the retries that preceded it. Each discarded attempt is summarized here: cost_usd and usage when the attempt’s output carried parseable accounting, else None; raw_bytes is always the UTF-8 byte length of the discarded output. attempt is the zero-based index and error the discarded exception’s class name.

Parameter Attributes

attempt: int
error: str
cost_usd: float | None
usage: dict[str, object] | None
raw_bytes: int

Example

>>> DiscardedAttempt(attempt=0, error="BackendCallError", cost_usd=0.02, usage=None, raw_bytes=57)

AppleConfig

Apple Foundation Models knobs applied only by the Apple backend.

Usage

Source

AppleConfig(
    use_case="general",
    guardrails="default",
    instructions=None,
    temperature=None,
    maximum_response_tokens=None,
    sampling=None,
    sampling_top=None,
    sampling_probability_threshold=None,
    sampling_seed=None
)

use_case and guardrails select the SystemLanguageModelUseCase and SystemLanguageModelGuardrails the spawnllm-apple sidecar builds its session with. The sampling knobs are flat rather than a nested mode because Apple exposes SamplingMode as a factory (greedy() / random()) that no serializable value can carry: sampling picks the factory and sampling_top, sampling_probability_threshold, and sampling_seed are the arguments random takes. None everywhere leaves the framework default.

Parameter Attributes

use_case: Literal["general", "content_tagging"] = "general"
guardrails: Literal["default", "permissive_content_transformations"] = "default"
instructions: str | None = None
temperature: float | None = None
maximum_response_tokens: int | None = None
sampling: Literal["greedy", "random"] | None = None
sampling_top: int | None = None
sampling_probability_threshold: float | None = None
sampling_seed: int | None = None

Example

>>> AppleConfig(use_case="content_tagging", sampling="random", sampling_top=20)

Raises

ValueError
When a random-only argument is set without sampling="random", a combination the framework would silently discard; when sampling_top and sampling_probability_threshold are set together, a pair the framework rejects; or when sampling_seed is negative, which the framework’s UInt64 cannot carry.

ClaudeConfig

Claude CLI flag passthrough applied only by the Claude backend.

Usage

Source

ClaudeConfig(
    permission_mode=None,
    mcp_config=None,
    strict_mcp=False,
    append_system_prompt=None,
    system_prompt=None,
    settings=None,
    disallowed_tools=(),
    max_turns=None,
    max_budget_usd=None,
    tools=None,
    disable_slash_commands=False,
    output_format=None,
    verbose=False
)

Fields map one-to-one onto claude flags: the agent/system-prompt knobs (permission_mode, mcp_config, strict_mcp, append_system_prompt, system_prompt, settings, disallowed_tools) and orthogonal extras (max_turns, max_budget_usd, tools, disable_slash_commands, output_format, verbose). tools selects the built-in toolset: None keeps the CLI default, () disables every built-in tool, and names restrict the session to those tools.

Parameter Attributes

permission_mode: str | None = None
mcp_config: str | None = None
strict_mcp: bool = False
append_system_prompt: str | None = None
system_prompt: str | None = None
settings: str | None = None
disallowed_tools: tuple[str, …] = ()
max_turns: int | None = None
max_budget_usd: float | None = None
tools: tuple[str, …] | None = None
disable_slash_commands: bool = False
output_format: str | None = None
verbose: bool = False

Example

>>> ClaudeConfig(permission_mode="bypassPermissions", strict_mcp=True)
>>> ClaudeConfig(tools=())  # bare session: no built-in tools

CodexConfig

Codex CLI knobs applied only by the Codex backend.

Usage

Source

CodexConfig(
    sandbox=None,
    enable_hooks=False,
    enable_mcp=False,
    service_tier="fast",
    developer_instructions=None
)

service_tier (default "fast") is emitted as -c service_tier=<value> on every invocation, isolated or not: isolated runs pass --ignore-user-config, which drops a service_tier pin in the user’s ~/.codex/config.toml, and the standard tier turns long prompts into multi-minute runs. Set it to None to drop the flag; an isolated run still passes --ignore-user-config, so a user-level tier pin applies only with isolated=False. developer_instructions injects the system-prompt layer via -c developer_instructions=<value>, serialized as a TOML string so any text — multi-line, or TOML-ambiguous words like true — arrives as a string.

Parameter Attributes

sandbox: str | None = None
enable_hooks: bool = False
enable_mcp: bool = False
service_tier: str | None = "fast"
developer_instructions: str | None = None

Example

>>> CodexConfig(sandbox="read-only", enable_mcp=True)

GeminiConfig

Gemini CLI knobs applied only by the Gemini and Antigravity backends.

Usage

Source

GeminiConfig(approval_mode=None, extensions=None)

Parameter Attributes

approval_mode: str | None = None
extensions: tuple[str, …] | None = None

Example

>>> GeminiConfig(approval_mode="auto", extensions=("search",))