Skip to content

aaa.tools

tool

tool(
    fn: Callable[..., Any] | None = None, **opts: Any
) -> Any

Decorator: @tool or @tool(requires_approval=True). Schema comes from type hints, description from the docstring.

Tool

Tool(
    fn: Callable[..., Any],
    *,
    name: str | None = None,
    description: str | None = None,
    requires_approval: bool = False,
    timeout_s: float = 60.0,
    pool: str = "default",
    delivery: str | None = None,
    idempotency_key: Callable[[dict[str, Any]], str]
    | None = None,
    guard: dict[str, Any] | GuardConfig | None = None,
)

delivery, idempotency_key and guard configure the stalled-worker guard for this tool (see aaa.tools.guard); anything unset inherits the ToolHandler's default.

delivery property

delivery: str | None

This tool's own delivery override (at_least_once / at_most_once), or None to inherit the ToolHandler's default.

ToolRegistry

ToolRegistry(tools: list[Tool] | None = None)

ToolHandler

ToolHandler(
    registry: ToolRegistry,
    *,
    pools: dict[str, int] | None = None,
    guard: GuardConfig | dict[str, Any] | None = None,
    result_retry: RetryPolicy | None = None,
    guards: GuardPolicy | None = None,
)

Executes aaa.tool.requested {call_id, name, arguments}.

  • Durable: the bus message stays unacknowledged until the tool finishes (defer_ack), so a worker that dies mid-call has the request redelivered to another worker.
  • Guarded (see aaa.tools.guard): an exclusive execution lease with heartbeat, numbered attempt records (the fencing token), a delivery policy (at-least-once with a cap, or at-most-once), stale-result rejection, and an idempotency key handed to the tool. All configurable globally via guard= and per tool.
  • Tools with requires_approval wait for an external aaa.approval.granted|denied {call_id} event (e.g. RunHandle.signal), enforced outside the model's control.
  • Executions run as tracked background tasks in bounded pools, so a tool that waits on a child run (delegation) can never starve the pool its child needs.
  • Failures (bad args, timeout, exception, lost attempt) become aaa.tool.failed facts the model sees.

config_for

config_for(t: Tool) -> GuardConfig

Effective guard configuration of a tool: handler default + the tool's overrides.

attach

attach(engine: Engine) -> None

One tool executor per engine: later handlers merge their tools into the first, so independent algorithms (e.g. a supervisor and its workers) share one namespace.

ToolContext dataclass

ToolContext(
    engine: Any,
    run_id: str,
    call_id: str,
    attempt: int = 1,
    fence: int = 1,
    idempotency_key: str = "",
    tenant: str | None = None,
    meta: dict[str, Any] = dict(),
)

Injected into tools that declare a ctx: ToolContext parameter.

idempotency_key is stable across every attempt and every worker for the same logical call (default <run>/<call id>, or whatever the tool's idempotency_key= function returns). Pass it to the system you are calling so a repeated attempt cannot repeat the effect. attempt/fence is the 1-based, monotonically increasing execution number of this call.

search_tool

search_tool(
    index: Index,
    *,
    name: str = "search_documents",
    k: int = 5,
    max_chars: int = 800,
) -> Tool

Expose any Index (keyword/vector/hybrid) as a retrieval tool for ToolLoop/ReAct.

Guard configuration

GuardConfig

Bases: BaseModel

enabled class-attribute instance-attribute

enabled: bool = True

False restores the minimal behavior: no lease, no attempt records (the bus still redelivers a request lost with its worker, so tools can run twice and nothing detects it).

max_attempts class-attribute instance-attribute

max_attempts: int = Field(default=3, ge=1)

Upper bound on executions of one call under AT_LEAST_ONCE. Exceeding it fails the call with ExecutionAbandoned (a poison call that keeps killing workers must not loop forever).

lease_ttl_s class-attribute instance-attribute

lease_ttl_s: float = Field(default=15.0, gt=0)

How long a silent worker keeps its exclusive claim. Lower = faster takeover, but a worker that is merely slow to heartbeat (long GC pause) loses its claim sooner.

heartbeat_s class-attribute instance-attribute

heartbeat_s: float | None = Field(default=None, gt=0)

Renewal period; default lease_ttl_s / 3.

wait_poll_s class-attribute instance-attribute

wait_poll_s: float = Field(default=0.5, gt=0)

How often a worker that found the call busy re-checks (to take over, or to see it finished).

fence_results class-attribute instance-attribute

fence_results: bool = True

Drop (and audit as aaa.tool.stale_result) a result from an attempt that a newer attempt has superseded.

merged

merged(
    overrides: dict[str, Any] | GuardConfig | None,
) -> GuardConfig

This config with a tool's explicit overrides applied (validated).

Delivery

Bases: StrEnum

AT_LEAST_ONCE class-attribute instance-attribute

AT_LEAST_ONCE = 'at_least_once'

If an attempt is lost (worker died/stalled), run it again, up to max_attempts. The tool may execute more than once: it must be idempotent, or honor ctx.idempotency_key.

AT_MOST_ONCE class-attribute instance-attribute

AT_MOST_ONCE = 'at_most_once'

Never run a call again once an attempt has started. A lost attempt becomes an OutcomeUnknown failure (the effect may or may not have happened) for the algorithm or a human to reconcile. Use for sends/payments that cannot be made idempotent.

LostLease

Bases: StrEnum

CANCEL class-attribute instance-attribute

CANCEL = 'cancel'

A worker that discovers it lost its lease cancels the running tool and records nothing.

FINISH class-attribute instance-attribute

FINISH = 'finish'

Let the tool finish anyway. Its result is still subject to fence_results.

Errors

ToolError

Bases: Exception

Raise from a tool to report a clean, model-readable failure.

ToolArgsError

Bases: ToolError