aaa.runtime¶
Engine ¶
Engine(
store: EventStore | None = None,
bus: EventBus | None = None,
schemas: SchemaRegistry | None = None,
default_budget: Budget | None = None,
blobs: BlobStore | None = None,
claim_threshold: int = 16384,
sweep_interval_s: float | None = None,
store_retry: RetryPolicy | None = None,
is_transient: Callable[[BaseException], bool]
| None = None,
redactor: Redactor | None = None,
require_tenant: bool = False,
retention: Sequence[RetentionPolicy] = (),
memory: Sequence[Any] = (),
)
Owns store + bus + schemas (+ optional blob store). Everything persisted is appended to the log BEFORE it is delivered, so the log is the source of truth and delivery replayable.
Cluster-ready: per-run state in _runs is only a cache of a fold of the log, rebuilt on
demand ("adopted") by whichever process the bus routes a run's events to. With a
distributed bus, several Engine processes sharing one store cooperate on the same runs.
abort
async
¶
Hard stop without draining or completing anything — what a crash looks like to the
log. Runs stay open in the store; another process (or recover()) continues them.
Sets crashed so cleanup code (lease release, ...) behaves as if the process vanished.
spawn ¶
Run background work (e.g. a long tool call) tracked for clean shutdown.
tenant ¶
A view of this engine bound to one tenant: namespaced run ids, ownership-checked lookups.
erase
async
¶
erase(
run_id: str,
*,
delete: bool = False,
reason: str = "erasure",
force: bool = False,
) -> ErasureReport
Erase a finished run: scrub its payloads (keeping the audit skeleton) or, with
delete=True, remove it. Also removes its snapshots, blobs and bus copies.
purge
async
¶
purge(
*,
older_than: timedelta,
tenant: str | None = None,
delete: bool = False,
reason: str = "retention",
) -> PurgeReport
Erase every finished run (of tenant, if given) that completed more than older_than ago.
forget_memory
async
¶
Erase everything the registered memory backends hold for scope (an aaa.memory.Scope:
a tenant, or one user of it). Backends without a forget capability are reported, not skipped silently.
apply_retention
async
¶
Evaluate the configured retention policies now (each is rate-limited by its interval_s).
handle ¶
A handle to any run by id (started here, in another process, or before a restart).
retry
async
¶
retry(
fn: Callable[[], Awaitable[Any]],
what: str = "store operation",
policy: RetryPolicy | None = None,
) -> Any
Run a store/blob operation, riding out transient outages per store_retry (or policy).
Raises StoreUnavailable if the outage outlasts the budget; other errors pass through.
hydrate
async
¶
Restore a claim-checked payload (no-op for ordinary events).
subscribe ¶
Subscribe a handler whose returned events are persisted+published by the engine.
Handlers receive hydrated events. Handler exceptions fail the run (as an event), never
the bus. A handler that fails because the STORE is unavailable (beyond store_retry) is not
a failed run: the engine raises Redeliver and the bus delivers the event again later.
Events for runs that already finished are not delivered to handlers.
group names a logical consumer. With a distributed bus, processes subscribing with the
same group compete (each event is handled by exactly one of them, in order per run);
group=None means broadcast to every process. Ignored by the in-process bus.
register ¶
Subscribe an algorithm. It only ever sees events of runs it was started for, so several algorithms (and nested child runs) coexist on one bus. With a distributed bus, algorithm names must be unique and identical across processes.
emit
async
¶
Validate -> claim-check -> append (assign seq) -> account budget -> deliver. Returns the stored event, or None if dropped (duplicate terminal event).
A store outage is ridden out per retry (default store_retry); if it outlasts that budget
StoreUnavailable is raised and NOTHING has been recorded or marked done locally.
await_event
async
¶
Wait for the first event on stream (from from_seq on) that match accepts. A dropped store
connection mid-read is ridden out like any other store call: resubscribe from the last event
seen, backing off per store_retry (the budget restarts on progress).
start
async
¶
start(
algo: Algorithm,
input: dict[str, Any],
*,
budget: Budget | None = None,
run_id: str | None = None,
parent: str | None = None,
tag: str | None = None,
tenant: str | None = None,
meta: dict[str, str | int | float | bool] | None = None,
) -> RunHandle
Start a run (idempotent for a given run_id). With parent, the child's spend rolls
up into the parent's budget, its completion is announced on the parent stream, and it is
cancelled if the parent finishes first. tenant tags the run and everything derived from it
(children inherit their parent's); see Engine.tenant() for the safe, namespaced way. meta
is trusted application data (e.g. {"user": "ann"}) stamped on the run's events and inherited
by everything derived from them; memory scopes are built from it, never from model output.
recover
async
¶
Continue every run left open in the store (single-process restart). See recovery.py.
sweep
async
¶
Stateless, idempotent cluster maintenance: expire deadlines of dead processes, cancel orphaned children, repair lost child announcements. Safe to run anywhere, any time.
run
async
¶
Facade: start and await the outcome (no event knowledge needed).
RunHandle ¶
Budget ¶
Bases: BaseModel
Hard limits for a run. None = unlimited. Enforced by the Engine, not by algorithms.
Ledger ¶
Bases: BaseModel
fold ¶
Pure fold; also usable as a Projection to rebuild spend from the log. Child-run
spend rolls up into the parent via aaa.child.completed.
Ctx ¶
Per-event context handed to algorithms. Algorithms hold no run state of their own: everything is derived from the run's event stream, so runs resume, replay and migrate between processes.
Algorithm ¶
Bases: Protocol
Tenancy and retention¶
TenantScope ¶
run_id ¶
The namespaced stream id for one of this tenant's own run ids (idempotent).
handle
async
¶
A handle to one of this tenant's runs. KeyError if it does not exist OR belongs to someone else.
purge
async
¶
Erase this tenant's finished runs older than older_than (never another tenant's).
erase_all
async
¶
Right-to-erasure for the whole tenant: every FINISHED run now, and (unless memory=False)
everything the engine's memory backends hold for the tenant. Open runs are reported in
skipped_open; cancel them first, then call again.
forget_memory
async
¶
Erase this tenant's long-term memories (or one user's / agent's) from every backend.
RetentionPolicy
dataclass
¶
RetentionPolicy(
older_than: timedelta,
delete: bool = False,
tenant: str | None = None,
interval_s: float = 3600.0,
)
Erase finished runs older than older_than. tenant=None matches runs of any tenant (and
untenanted ones). With several policies the first one whose tenant matches a run applies, so list
tenant-specific policies before a catch-all.
ErasureReport
dataclass
¶
PurgeReport
dataclass
¶
PurgeReport(
erased: list[ErasureReport] = list(),
skipped_open: int = 0,
memory: MemoryReport | None = None,
)
Redaction (aaa.privacy)¶
Redactor ¶
Bases: Protocol
redact ¶
Return the event with sensitive values replaced. Must be pure and idempotent.
PatternRedactor ¶
PatternRedactor(
patterns: Iterable[Pattern] = DEFAULT_PATTERNS,
*,
only: Iterable[str] = ("*",),
skip: Iterable[str] = (),
)
Bases: _Base
Replace matches of regular expressions inside any string value with [REDACTED:<name>].
PatternRedactor() covers e-mail addresses, payment-card numbers (Luhn-checked), US SSNs, common
API keys/tokens, JWTs and bearer tokens. Pass your own Patterns for anything else (national
ids, phone formats, account numbers): redaction is only as good as its patterns, so treat this
as a safety net and keep sensitive data out of events where you can.
KeyRedactor ¶
KeyRedactor(
keys: Iterable[str] = SECRET_KEYS,
*,
replacement: str = "[REDACTED]",
only: Iterable[str] = ("*",),
skip: Iterable[str] = (),
)
Bases: _Base
Replace the VALUE of well-known secret-bearing keys (password, api_key, authorization,
cookie...) wherever they appear, however deeply nested. Keys match whole (case- and
punctuation-insensitively), so accounting fields such as prompt_tokens are never touched.
Pattern ¶
A named regex, with an optional check that can veto a match (e.g. a Luhn check).
standard_redactor ¶
Secret-bearing keys + the default patterns: a sensible starting point.