Augments LabsAugments ADK

Sandbox Cost and Billing

The sandbox module models cost at three levels: a static rate card per backend (SandboxCostDescriptor), a per-command computed estimate accumulated into SandboxUsage, and an optional provider-reported session total (billed_cost_usd) retrieved when live billing is enabled.

SandboxCostDescriptor

Each backend client declares a cost class attribute of type SandboxCostDescriptor. The descriptor is the backend's static rate card.

FieldTypeDefaultMeaning
usd_per_minutefloat0.0Dollar cost per wall-clock minute of session life
usd_per_cpu_secondfloat | NoneNoneOptional CPU-second rate (live-billing reconciliation)
usd_per_gb_secondfloat | NoneNoneOptional GiB-second memory rate (live-billing reconciliation)
freeboolFalseWhen True the backend costs nothing (self-hosted / local)

Two methods:

  • rate_key() -> float β€” scalar used to rank backends cheapest-first. Returns 0.0 when free=True, otherwise returns usd_per_minute.
  • cost_for_ms(duration_ms: int) -> float β€” computed dollar cost for a command of duration_ms wall-clock milliseconds. Returns 0.0 when free=True, otherwise usd_per_minute * (duration_ms / 60000.0).

Per-backend rate table

Rates are approximate starting points. Every backend exposes cost as a class attribute, so you can subclass a client and override cost to reflect your actual contracted rate.

BackendClassusd_per_minutefreenetworkpersistent
Local subprocessLocalSubprocessSandboxClientβ€”TrueTrueFalse
Docker containerDockerSandboxClientβ€”TrueTrueTrue
Kubernetes podK8sPodSandboxClientβ€”TrueTrueTrue
E2BE2bSandboxClient0.06FalseTrueTrue
CloudflareCloudflareSandboxClient0.05FalseTrueFalse
DaytonaDaytonaSandboxClient0.08FalseTrueTrue
BlaxelBlaxelSandboxClient0.09FalseTrueTrue
ModalModalSandboxClient0.10FalseTrueTrue
RunloopRunloopSandboxClient0.10FalseTrueTrue
VercelVercelSandboxClient0.12FalseTrueFalse

All priced rates are in USD per minute. Check each provider's pricing page for the current contracted rate; these values are used to rank backends cheapest-first and to compute per-command estimates.

SandboxBackendCapabilities

Each backend client declares a capabilities class attribute of type SandboxBackendCapabilities. The selector matches these against a run's SandboxRequirements.

FieldTypeDefaultMeaning
networkboolFalseBackend grants outbound network access
persistentboolFalseBackend offers a persistent (non-ephemeral) workspace
max_cpuint | NoneNoneMaximum CPU count available (None = unknown)
max_memory_mbint | NoneNoneMaximum memory in MiB (None = unknown)
regionstuple[str, ...]()Regions the backend can run in

capabilities.satisfies(requirements) returns True when the backend meets every field the SandboxRequirements states.

SandboxUsage cost fields

SandboxUsage accumulates resource counters for one or more sandbox sessions. Two cost fields live on the accumulator (a third, cost_usd, is the per-command figure on SandboxSingleExecUsage):

FieldTypeDefaultMeaning
computed_cost_usdfloat0.0Sum of per-command cost_usd values (rate-card estimate)
billed_cost_usdfloat | NoneNoneProvider-reported session cost; set only when live billing ran

computed_cost_usd grows with every command: after each run_command call the framework computes cost.cost_for_ms(duration_ms) and folds the result into the accumulator. A free backend (free=True) yields cost_for_ms == 0.0, so its per-command cost_usd is 0.0 and computed_cost_usd stays 0.0. A per-command cost_usd is None only when client.cost is None β€” a custom backend that declares no rate card (every shipped backend declares one); a None per-command cost is skipped in the fold, so computed_cost_usd stays 0.0.

billed_cost_usd is None until live billing is enabled and fetch_billing returns a SandboxBillingRecord. If both values are set, computed_cost_usd is the rate-card estimate and billed_cost_usd is the provider-reported figure; treat them as complementary signals.

SandboxUsage is exposed on RunResult.sandbox_usage after the run completes. Access it to log cost, enforce per-run budgets, or route usage records to a billing system.

result = await Runner.arun(agent, prompt, run_config=run_config)
if result.sandbox_usage is not None:
    usage = result.sandbox_usage
    print(f"commands run: {usage.exec_count}")
    print(f"rate-card estimate: ${usage.computed_cost_usd:.6f}")
    if usage.billed_cost_usd is not None:
        print(f"provider-reported: ${usage.billed_cost_usd:.6f}")

The sandbox session is bracketed once per Runner.arun: a single SandboxUsage accumulates every command for the run (handoffs between SandboxAgents execute inside that one bracket) and is attached directly to RunResult.sandbox_usage β€” there is no cross-session merge step. SandboxUsage also supports __add__ for explicitly aggregating usage across separate runs: counters sum elementwise, memory_peak_mb takes the max, executions are concatenated, and billed_cost_usd sums only when at least one operand has a non-None value.

Live billing (opt-in)

Setting SandboxRunConfig(capture_live_cost=True) tells the Runner to call client.fetch_billing(session) during teardown, after the session stops. The result, if non-None, is stored in SandboxUsage.billed_cost_usd.

capture_live_cost defaults to False. This is the cost-conservative default: the billing API call is a network round-trip that the developer must explicitly opt into.

fetch_billing is best-effort: any exception from the provider call is suppressed (and logged at DEBUG) so a billing-endpoint failure never fails the run. A None return means no provider-reported figure is available for this session β€” computed_cost_usd is the estimate to use. The DEBUG log is what distinguishes a thrown billing error from a backend that simply reports no per-sandbox cost.

E2B

E2B meters compute usage at the account level, not per sandbox. The E2bSandboxClient.fetch_billing override therefore returns None by design. computed_cost_usd (the rate-card estimate) is the per-run cost approximation for E2B runs.

Other backends

BaseSandboxClient.fetch_billing returns None by default. Hosted-bridge subclasses can override it to call the provider's billing API and return a SandboxBillingRecord(cost_usd=..., currency="USD", unit=..., raw=...).

SandboxBillingRecord

SandboxBillingRecord is a Pydantic BaseModel (received + validated):

FieldTypeDefaultMeaning
cost_usdfloatβ€”Dollar cost the provider reported for the session
currencystr"USD"ISO currency code
unitstr | NoneNoneProvider billing unit label (e.g. "compute-seconds")
rawdict | NoneNoneUntouched provider payload for audit / debugging

See selection.md for how the rate card feeds backend selection. See observability.md for how usage is accumulated and surfaced via hooks.