Client⌗
The thin gRPC client over the tape.v1 service. Every mutating call is idempotent on the server,
so retrying is always safe.
from tape import TapeClient
with TapeClient("tape://localhost:7878") as c:
run = c.begin_run(app_name="treasury", user_id="cfo", session_id="s1",
invocation_id="inv-1", lease_owner="me")
tape.client.TapeClient
⌗
Synchronous gRPC client over the tape.v1 service.
URL schemes: tape://host:port (plaintext — self-hosted / k8s / local),
tapes://host (TLS on :443 — Cloud Run / any HTTPS endpoint). On a TLS
channel, if the endpoint is IAM-protected (e.g. an internal Cloud Run
service), Tape attaches a Google ID token automatically — pass auth=False
to disable, or id_token=<str> to supply your own, or audience=<url> to
override the derived one.
begin_effect
⌗
begin_effect(*, run_id, decision_index, tool_name, call_index=0, request_json='', custom_key='', semantics=0, dispatch_mode=0, business_key='', connector='')
Begin (or short-circuit) an effect. Defaults preserve the v1 contract
(idempotent + inline). Pass semantics=EFFECT_SEMANTICS_NON_IDEMPOTENT
and dispatch_mode=EFFECT_DISPATCH_MODE_OUTBOX to opt into the outbox
path; business_key + connector declare the cross-run dedupe key the
counterparty would use.
list_effects_to_dispatch
⌗
PENDING + OUTBOX effects whose next_dispatch_at_ms <= now (and whose
dispatch lease is empty or expired). Pass connector to scope the result.
claim_effect_dispatch
⌗
Atomic CAS lease on the dispatch slot. Returns a
ClaimEffectDispatchResponse with acquired and the current effect row.
record_dispatch_attempt
⌗
Report a failed dispatch attempt. next_dispatch_at_ms <= 0 →
the server transitions the effect to UNKNOWN (the reconciler resolves);
a positive value schedules a retry.
record_external_observation
⌗
record_external_observation(*, run_id, idempotency_key, resolution, external_ref='', response_json='', error_json='', compensate_on_duplicate_kind='')
Record what the counterparty said about an effect — the reconciler's
write path. resolution is one of EFFECT_RESOLUTION_*. When DUPLICATE
+ compensate_on_duplicate_kind is set, the server registers a
compensation obligation atomically.
register_compensation
⌗
register_compensation(*, run_id, effect_key, kind, payload_json='', compensator_ref='', max_attempts=0)
Register an obligation in PENDING (immediately eligible for the drainer).
Idempotent on (run_id, effect_key, kind). compensator_ref is an optional
"module:attr" path so a generic drainer process can resolve the inverse
without having imported the agent module. max_attempts defaults to 5.
list_obligations
⌗
Per-run LIFO. status_filter matches an ObligationStatus exactly (or 0
for any); only_unresolved is a shorthand that excludes COMPENSATED/STUCK.
list_unresolved_obligations
⌗
list_unresolved_obligations(*, limit=500, now_ms=0, include_pending=True, include_stuck=False, include_committed_expired=True)
Cross-run drainer feed. Defaults pick up ready-to-run PENDING plus
COMMITTED rows whose lease has expired — the drainer's normal hot set.
Pass include_stuck=True for an operator dashboard view.
claim_obligation
⌗
Atomic CAS lease. Returns a ClaimObligationResponse with acquired
and the current obligation row (whether or not the claim was won).
record_obligation_attempt
⌗
Report a failed attempt. The server bumps attempts and either reschedules
(status -> PENDING with next_attempt_at_ms) or marks STUCK (when retries are
exhausted, or when next_attempt_at_ms <= 0 means terminal-now).
subscribe_by_subject
⌗
Subject-routed, global-seq-cursored bus stream. Returns the streaming
gRPC iterator; iterate it (optionally in a thread) and .cancel() to
stop. Pass timeout= to bound the call (the iterator will surface
DEADLINE_EXCEEDED when the deadline passes — useful for tick-style
consumers like the outbox relay).
register_reaction
⌗
register_reaction(*, reaction_id='', name='', subject_pattern, predicate_cel='', handler_kind, agent_app='', publish_target='', max_concurrency=1, rate_limit_per_s=0, debounce_ms=0, retry_max=5, retry_backoff_ms=1000, dlq_after_n=5, num_shards=1)
Register a server-side reaction. Returns the persisted Reaction
(with reaction_id filled in if it was empty).
Status enums⌗
TapeClient — a thin, synchronous client over the tape.v1 gRPC service.
This is the layer the ADK adapter (and your own code, when you need it) talks to. Every mutating call is idempotent on the server, so retrying is always safe.