Skip to content

cayu.approvals.business

Public Cayu API. Definitions are grouped by their public source module, and definitions from private implementation modules appear on their package’s page; adding a symbol does not move existing links. The import shown at each entry is a supported public namespace. Read the Python API overview and install the required extra.

from cayu.approvals import business_approval_audit

Project approval events into business approval records.

Pass the output of session_store.load_events(...) or an EventQuery filtered to the approval event types — in any order and from any number of sessions (records pair per session; requests are seeded before resolutions are applied). Parsing is lenient: approvals paused without the routing carrier project with routing=None, and unstamped resolutions (made through the raw primitive) project with outcome=None — the audit never raises on foreign approvals. The projection records what callers asserted; it does not authenticate the stamp — a caller at operator trust level resolving through the raw primitive can write any resolution metadata, including this stamp.

business_approval_audit(events: Iterable[Event]) -> list[BusinessApprovalRecord]

Release source · Runtime guarantees · Capability guides

from cayu.approvals import BUSINESS_APPROVAL_RESOLUTION_METADATA_KEY
BUSINESS_APPROVAL_RESOLUTION_METADATA_KEY = approval_support.BUSINESS_APPROVAL_RESOLUTION_METADATA_KEY

Release source · Runtime guarantees · Capability guides

from cayu.approvals import business_approval_routing

Read the routing carrier off a pending approval.

Raises BusinessApprovalRoutingMissing when the pause was created without the carrier or the carrier is malformed — the tier gate never silently degrades into an ungated resolve.

business_approval_routing(pending: PendingToolApproval | PendingToolApprovalEventView) -> BusinessApprovalRouting

Release source · Runtime guarantees · Capability guides

from cayu.approvals import business_approval_routing_metadata

Build the ToolPolicyResult.metadata carrier for a routed approval.

Merge the returned dict into the metadata of a ToolPolicyResult(decision=REQUIRE_APPROVAL, ...); the routing then persists on the pending approval and surfaces to approval UIs in the tool.call.approval_requested event under payload["approval"]["metadata"].

business_approval_routing_metadata(*, required_tier: str, chain: Sequence[str], metadata: Mapping[str, Any] | None=None) -> dict[str, Any]

Release source · Runtime guarantees · Capability guides

from cayu.approvals import BUSINESS_APPROVAL_ROUTING_METADATA_KEY
BUSINESS_APPROVAL_ROUTING_METADATA_KEY = 'cayu:business_approval_routing'

Release source · Runtime guarantees · Capability guides

from cayu.approvals import BusinessApprovalError

Base class for business-approval adapter failures.

Bases: Exception.

This type’s implementation and inherited behavior are available in the linked release source.

Release source · Runtime guarantees · Capability guides

from cayu.approvals import BusinessApprovalOutcome

Bases: StrEnum.

Defaults below are source expressions; Field(...) includes schema/validation settings and default_factory creates a fresh value. Inherited declarations are included. Constructor behavior follows the model or dataclass shown in the bases/decorators.

Name Type Default
APPROVED class attribute 'approved'
CONDITIONED class attribute 'conditioned'
DECLINED class attribute 'declined'

Release source · Runtime guarantees · Capability guides

from cayu.approvals import BusinessApprovalRecord

One business approval, projected from the session’s approval events.

resolution_state distinguishes a pending request, a binary runtime decision, and a non-authorizing recovery acknowledgement. decision is the raw Cayu decision (None while pending or safely blocked); outcome is the business outcome stamped by the adapter (None while pending, and None on unstamped resolutions made through the raw primitive). resolved_by is the typed ResolutionActor provenance the runtime stamped on the resolution event, when the resolver supplied one — the authenticated who/how next to the caller-asserted approver_id/approver_tier. expired is True when the runtime’s approval TTL closed on the attempt and coerced it to a denial: the stamped business fields then record what the approver asserted, while decision records the expiry-coerced outcome (so decision=DENY with outcome=approved reads as “approved too late”).

Decorators: @dataclass(frozen=True).

Defaults below are source expressions; Field(...) includes schema/validation settings and default_factory creates a fresh value. Inherited declarations are included. Constructor behavior follows the model or dataclass shown in the bases/decorators.

Name Type Default
approval_id str required
session_id str required
tool_call_id str required
tool_name str required
agent_name str required
routing BusinessApprovalRouting | None required
resolution_state BusinessApprovalResolutionState required
decision ToolApprovalDecision | None required
outcome BusinessApprovalOutcome | None required
condition_text str | None required
approver_id str | None required
approver_tier str | None required
resolved_by ResolutionActor | None required
reason str | None required
expired bool required
requested_at datetime | None required
resolved_at datetime | None required
BusinessApprovalRecord.pending() -> bool
BusinessApprovalRecord.resolved_via_adapter() -> bool

Release source · Runtime guarantees · Capability guides

from cayu.approvals import BusinessApprovalResolutionState

Durable lifecycle state of one business approval.

Bases: StrEnum.

Defaults below are source expressions; Field(...) includes schema/validation settings and default_factory creates a fresh value. Inherited declarations are included. Constructor behavior follows the model or dataclass shown in the bases/decorators.

Name Type Default
PENDING class attribute 'pending'
APPROVED class attribute 'approved'
DENIED class attribute 'denied'
BLOCKED class attribute 'blocked'

Release source · Runtime guarantees · Capability guides

from cayu.approvals import BusinessApprovalRouting

Product-computed routing for one business approval.

chain is ordered lowest to highest authority; required_tier is the minimum tier that may resolve. metadata carries product extras (package id, amount, cost center, …) for the approval UI and the audit trail.

Bases: BaseModel.

Defaults below are source expressions; Field(...) includes schema/validation settings and default_factory creates a fresh value. Inherited declarations are included. Constructor behavior follows the model or dataclass shown in the bases/decorators.

Name Type Default
kind str BUSINESS_APPROVAL_ROUTING_KIND
required_tier str required
chain tuple[str, ...] required
metadata dict[str, Any] Field(default_factory=dict)
BusinessApprovalRouting.validate_kind(value: str) -> str
BusinessApprovalRouting.validate_required_tier(value: str) -> str
BusinessApprovalRouting.validate_chain(value: Any) -> tuple[str, ...]
BusinessApprovalRouting.copy_metadata(value: Any) -> dict[str, Any]
BusinessApprovalRouting.validate_required_tier_in_chain() -> BusinessApprovalRouting

Release source · Runtime guarantees · Capability guides

from cayu.approvals import BusinessApprovalRoutingMissing

The pending approval carries no (valid) business-approval routing.

Raised when a pause was created without business_approval_routing_metadata (for example by a plain policy) or the carrier payload is malformed. The adapter refuses rather than resolving ungated — resolve such approvals with CayuApp.resolve_tool_approval directly.

Bases: BusinessApprovalError.

This type’s implementation and inherited behavior are available in the linked release source.

Release source · Runtime guarantees · Capability guides

from cayu.approvals import BusinessApprovalTierMismatch

The asserted approver tier may not resolve this approval.

Bases: BusinessApprovalError.

BusinessApprovalTierMismatch.__init__(*, approver_tier: str, required_tier: str, chain: tuple[str, ...]) -> None

Release source · Runtime guarantees · Capability guides

from cayu.approvals import resolve_business_approval

Resolve a routed business approval and return the resumed event stream.

Enforces the tier gate against the routing persisted on the session’s pending-approval checkpoint — never a caller-supplied value — (approver_tier must sit at or above required_tier in the ordered chain), maps the business outcome onto the binary primitive (APPROVED/CONDITIONED resume as approve — CONDITIONED requires condition_text; DECLINED resumes as deny), stamps the business outcome into the resolution metadata for the audit trail, and delegates to CayuApp.resolve_tool_approval.

This is a coroutine returning the event iterator: gate failures raise at await time, before any event is consumed — events = await resolve_business_approval(...) then iterate. The approved tool sees the stamped record via ToolContext.metadata["cayu:business_approval"]; the model does not see approve-path metadata, so a condition that must steer the model has to be surfaced by the tool’s own result. The gate is an application affordance, not a security boundary: approver_id/approver_tier are caller-asserted, and direct primitive callers bypass the adapter entirely (unstamped resolutions show outcome=None in the audit; a same-trust caller can also forge the stamp — authenticate approvers product-side and pass resolved_by (a ResolutionActor from your auth layer) so the typed provenance the runtime stamps sits next to the business assertion). The primitive independently reloads and re-validates the pending approval when the returned stream is first iterated, so a resolution race lost after this gate surfaces as the primitive’s own status-conflict error. Approval expiry composes the same way: a tier-authorized resolution whose approval window already closed is coerced by the runtime to a denial — no typed error; the stream carries tool.call.approval_expired and denial events with expired: true, and the audit record shows expired=True next to the asserted outcome.

async resolve_business_approval(app: CayuApp, *, session_id: str, task_worker_id: str | None=None, approval_id: str, approver_id: str, approver_tier: str, outcome: BusinessApprovalOutcome | str, condition_text: str | None=None, reason: str | None=None, metadata: dict[str, Any] | None=None, resolved_by: ResolutionActor | None=None, max_steps: int | None=None, limits: RunLimits | None=None, budget_limits: tuple[BudgetLimit, ...] | None=None, retry_policy: RetryPolicy | None=None, structured_output: StructuredOutputSpec | None=None, thinking: ThinkingConfig | None=None, loop_policies: tuple[LoopPolicy, ...]=()) -> AsyncIterator[Event]

Release source · Runtime guarantees · Capability guides

from cayu.approvals import TieredApprovalPolicy

Pause tool calls for business approval with a product-computed routing.

Tier computation stays product-owned: compute_routing receives the ToolPolicyRequest and returns a BusinessApprovalRouting (pause for approval at that tier) or None (allow without approval). The callback may be sync or async — a product implementation typically consults its own rules or database. It can run more than once for the same call: the runtime re-authorizes when a before_tool_call hook modifies arguments (marked with request.metadata[TOOL_POLICY_REAUTHORIZATION_METADATA_KEY]), so keep the callback deterministic and side-effect free; a REQUIRE_APPROVAL verdict on re-authorized arguments blocks the call instead of pausing again. expires_in_seconds bounds how long the resulting approval demand stays valid, exactly like AlwaysRequireApprovalToolPolicy(expires_in_seconds=...).

Bases: ToolPolicy.

TieredApprovalPolicy.execution_profile_identity() -> ExecutionProfileBehaviorIdentity | None

Return a stable application declaration, or None when non-portable.

async TieredApprovalPolicy.authorize(request: ToolPolicyRequest) -> ToolPolicyResult
TieredApprovalPolicy.__init__(*, compute_routing: Callable[[ToolPolicyRequest], BusinessApprovalRouting | None | Awaitable[BusinessApprovalRouting | None]], reason: str | None=None, expires_in_seconds: float | None=None) -> None

Release source · Runtime guarantees · Capability guides