Skip to content

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

TapeClient(url: str = DEFAULT_URL, *, auth: bool = True, audience: str = '', id_token: str = '')

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

list_effects_to_dispatch(*, now_ms=0, connector='', limit=200)

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

claim_effect_dispatch(*, run_id, idempotency_key, claimer, lease_ttl_ms=60000)

Atomic CAS lease on the dispatch slot. Returns a ClaimEffectDispatchResponse with acquired and the current effect row.

record_dispatch_attempt

record_dispatch_attempt(*, run_id, idempotency_key, error, next_dispatch_at_ms)

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

list_obligations(*, run_id, only_unresolved=True, status_filter=0)

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

claim_obligation(*, run_id, obligation_seq, claimer, lease_ttl_ms=60000)

Atomic CAS lease. Returns a ClaimObligationResponse with acquired and the current obligation row (whether or not the claim was won).

record_obligation_attempt

record_obligation_attempt(*, run_id, obligation_seq, error, next_attempt_at_ms)

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

subscribe_by_subject(*, subject_pattern, predicate_cel='', from_global_seq=0, timeout=None)

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.

DEFAULT_URL module-attribute

DEFAULT_URL = get('TAPE_URL', 'tape://localhost:7878')

RUN_STATUS_RUNNABLE module-attribute

RUN_STATUS_RUNNABLE = RUN_STATUS_RUNNABLE

RUN_STATUS_RUNNING module-attribute

RUN_STATUS_RUNNING = RUN_STATUS_RUNNING

RUN_STATUS_WAITING module-attribute

RUN_STATUS_WAITING = RUN_STATUS_WAITING

RUN_STATUS_TERMINAL module-attribute

RUN_STATUS_TERMINAL = RUN_STATUS_TERMINAL

RUN_STATUS_FAILED module-attribute

RUN_STATUS_FAILED = RUN_STATUS_FAILED

RUN_STATUS_STUCK module-attribute

RUN_STATUS_STUCK = RUN_STATUS_STUCK

RUN_STATUS_CANCELLED module-attribute

RUN_STATUS_CANCELLED = RUN_STATUS_CANCELLED

EFFECT_STATUS_PENDING module-attribute

EFFECT_STATUS_PENDING = EFFECT_STATUS_PENDING

EFFECT_STATUS_CONFIRMED module-attribute

EFFECT_STATUS_CONFIRMED = EFFECT_STATUS_CONFIRMED

EFFECT_STATUS_FAILED module-attribute

EFFECT_STATUS_FAILED = EFFECT_STATUS_FAILED

EFFECT_STATUS_UNKNOWN module-attribute

EFFECT_STATUS_UNKNOWN = EFFECT_STATUS_UNKNOWN

EFFECT_SEMANTICS_IDEMPOTENT module-attribute

EFFECT_SEMANTICS_IDEMPOTENT = EFFECT_SEMANTICS_IDEMPOTENT

EFFECT_SEMANTICS_NON_IDEMPOTENT module-attribute

EFFECT_SEMANTICS_NON_IDEMPOTENT = EFFECT_SEMANTICS_NON_IDEMPOTENT

EFFECT_SEMANTICS_OBSERVE_ONLY module-attribute

EFFECT_SEMANTICS_OBSERVE_ONLY = EFFECT_SEMANTICS_OBSERVE_ONLY

EFFECT_DISPATCH_MODE_INLINE module-attribute

EFFECT_DISPATCH_MODE_INLINE = EFFECT_DISPATCH_MODE_INLINE

EFFECT_DISPATCH_MODE_OUTBOX module-attribute

EFFECT_DISPATCH_MODE_OUTBOX = EFFECT_DISPATCH_MODE_OUTBOX

EFFECT_RESOLUTION_CONFIRMED module-attribute

EFFECT_RESOLUTION_CONFIRMED = EFFECT_RESOLUTION_CONFIRMED

EFFECT_RESOLUTION_FAILED module-attribute

EFFECT_RESOLUTION_FAILED = EFFECT_RESOLUTION_FAILED

EFFECT_RESOLUTION_ABSENT module-attribute

EFFECT_RESOLUTION_ABSENT = EFFECT_RESOLUTION_ABSENT

EFFECT_RESOLUTION_DUPLICATE module-attribute

EFFECT_RESOLUTION_DUPLICATE = EFFECT_RESOLUTION_DUPLICATE

EFFECT_RESOLUTION_STUCK module-attribute

EFFECT_RESOLUTION_STUCK = EFFECT_RESOLUTION_STUCK