Top level¶
The everyday names, imported from agent_adapter. Each loads on first use, so import agent_adapter stays cheap. Concepts: Tools, Registry, Executor.
Four names have no docstring of their own, so here is what they are:
| Name | What it is |
|---|---|
default_registry |
The process-wide Registry, created on first access, then reused |
tool, wrap |
default_registry.tool and default_registry.wrap: register a function on it |
Decision |
An alias of ApprovalDecision |
__version__ |
The installed version string |
Agent Adapter: framework-independent tools, parallel execution and flows for LLM agents.
Names load on first use (PEP 562), so import agent_adapter stays cheap. Every other
public name lives in its home subpackage: errors in agent_adapter.errors, the rest in
agent_adapter.exec, .approval, .hooks, .cost, .cache, .flow and so on.
Decision = ApprovalDecision
module-attribute
¶
__version__ = '1.1.0'
module-attribute
¶
default_registry = Registry()
module-attribute
¶
tool = default_registry.tool
module-attribute
¶
wrap = default_registry.wrap
module-attribute
¶
AdapterError
¶
Bases: Exception
Base class for every error raised by Agent Adapter.
ApprovalDecision
¶
Bases: BaseModel
A reviewer's decision; edited_args replaces the arguments when set.
ApprovalDenied
¶
ApprovalPending
¶
ApprovalRequest
¶
Bases: BaseModel
A call (or flow node) waiting for a human decision.
AutoApprove
¶
ApprovalPort that approves every request.
AutoDeny
¶
ApprovalPort that denies every request.
BudgetHook
¶
Bases: Hook
Caps spend per run, thread, user, team or everything, optionally per UTC day or month.
Raises:
| Type | Description |
|---|---|
ConfigError
|
invalid limits, scope, window, store or estimate; |
on_llm_end(inv, billed)
async
¶
Settle the hold with what the call billed (as the ledger prices it), or release it.
scope_of(ctx)
¶
The effective scope and the id spend is counted under for ctx.
Raises:
| Type | Description |
|---|---|
ConfigError
|
|
status(ctx, *, scope_id=None)
async
¶
The budget of ctx's scope, or of scope_id when given (an approver's view).
Raises:
| Type | Description |
|---|---|
ConfigError
|
as |
with_config(config)
¶
A new hook with config merged over this one's (store and keys carried over).
Raises:
| Type | Description |
|---|---|
ConfigError
|
unknown keys or invalid values. |
CallableModel
¶
Wraps fn(request); it returns an LLMResponse, the reply text, or a response mapping.
fn may be async or sync; a sync fn runs in a worker thread (context variables are
copied), so a blocking local model or HTTP client never stalls the event loop. A mapping
holds LLMResponse fields, including usage (a Usage or its field names), which the
ledger prices; provider, model and message are filled in when missing. Exceptions
raised by fn propagate unchanged.
cache_key_fields()
¶
LLM-cache key material: which host function answers.
generate(request)
async
¶
Call the host function (or drain stream_fn when request.stream is set).
Raises:
| Type | Description |
|---|---|
ModelOutputInvalid
|
the result does not form a valid response. |
ToolUsageError
|
|
ConfigError
|
|
stream(request)
async
¶
stream_fn's events, or the generated reply replayed as deltas.
With output_schema, text deltas are followed by PartialOutput unless stream_fn
sends its own.
Raises:
| Type | Description |
|---|---|
ModelOutputInvalid
|
|
ConfigError
|
|
CallbackApproval
¶
ApprovalPort over a sync or async function returning a decision or a bool.
request(request)
async
¶
Ask fn; a bool becomes a decision by "callback".
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
|
ApprovalPending
|
|
DeferredApproval
¶
ApprovalPort for out-of-band review (HTTP server, queues); emits no events itself.
consume(record, request)
async
¶
Use the stored decision of record once; the record and request are not trusted.
The record is read again from the store; never looks the call up by call_id.
Raises:
| Type | Description |
|---|---|
ApprovalPending
|
the stored record is not decided (nothing is consumed). |
ApprovalDenied
|
the stored decision differs from |
ToolUsageError
|
|
ApprovalNotFound
|
the store has no such record. |
prepare(request)
async
¶
The record for (run_id, call_id), created pending when new; never consumes it.
Advisory: batch callers (approval.batch.ask_each) prepare every call first and act
only on what consume returns for these records.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
non-JSON arguments, the call id has a record for another tool or other arguments, or the HTTP tool server parked the record. |
request(request)
async
¶
Return the decision for (run_id, call_id) once decided, consuming it.
A record only answers the request it was made for: same kind, tool and original
arguments (args_digest). The decision's edited_args are what then runs.
Raises:
| Type | Description |
|---|---|
ApprovalPending
|
no decision yet; the first request creates the record. |
ApprovalDenied
|
a concurrent request consumed the same decision (fails closed). |
ToolUsageError
|
the call id has a record for another tool or other arguments. |
sqlite(path, *, max_records=10000, timeout=5.0)
classmethod
¶
A port on a SQLiteApprovalStore file, shared by every process on this host.
Raises:
| Type | Description |
|---|---|
ConfigError
|
a bad path, |
Executor
¶
Bases: Batches, SyncTwins
Runs tools with run guards, hooks, approval, cache, retries, ledger and events.
With no registry it uses the default one (@tool). Sync code uses the SyncTwins
methods. Run state (guards, run locks) is shared with every executor made by replace.
hooks
property
¶
The executor's own hooks; a policy's hooks run before them and are not listed.
policy
property
¶
The policy every call's spec passes through (Policy.apply sets it), or None.
sink
property
¶
The executor's stable sink: the constructor's sink, then every added one.
__reduce__()
¶
Refuse pickling with a clear error (it holds locks and loop-bound state).
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
always. |
add_sink(sink)
¶
Also send events to sink, beside the existing ones; contexts made earlier get it too.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
|
context(*, run_id=None, thread_id='', user_id='', state=None, extras=None)
¶
A context for a new (or given) run, carrying this executor's ledger, cache and sink.
end_run(run_id)
¶
Forget a run's guard counters and locks.
model(model, *, cache_ttl=None)
¶
model with this executor's hooks, response cache, ledger and sink around it.
remove_sink(sink)
¶
Stop sending events to a sink add_sink added; False when it was not added.
replace(**changes)
¶
A new Executor with some constructor arguments replaced; self is unchanged.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
an unknown argument name. |
resume(approval_id, decision=None, ctx=None, *, decided_by='', reason='')
async
¶
Run a parked call once: decide it first if pending (decision and decided_by
are then required), else apply the decision already in the store.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
no approval store, a flow-node or HTTP-server approval, a pending
record without |
ApprovalNotFound
|
unknown or expired id (an expiry also sends |
ApprovalAlreadyDecided
|
already used, or decided otherwise in the store. |
run(tool, args=None, ctx=None, *, call_id=None)
async
¶
Run a tool (its name, spec or function) and return its value; failures raise.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
|
run_call(call, ctx=None, *, registry=None)
async
¶
Run one call; every failure is a ToolResult, only control flow raises.
run_scope(**context_kwargs)
¶
async with ex.run_scope() as ctx: emits run.started/run.finished, then ends the run.
run_spec(spec, args=None, ctx=None, *, call_id=None)
async
¶
Run spec (registered or not) and return its value; failures raise.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
|
FallbackModel
¶
An LLMPort over models: the next one answers after a fall_on error.
Each port keeps its SDK retries, so a hop happens after those are spent; pass
client_kwargs={"max_retries": 0} to the provider ports for fast failover. Ports after the
first get the request with model=None, so each uses its own configured model. With
metadata["call_id"], every hop (hop 0 and a single port too) gets {call_id}:hop{i}.
Hops emit llm.fallback to sink, else to the current context's sink.
Raises:
| Type | Description |
|---|---|
ConfigError
|
no models, or a |
cache_key_fields()
¶
LLM-cache key material: every port in order.
generate(request)
async
¶
The first successful reply in order; the last error when every port fails.
Raises:
| Type | Description |
|---|---|
ModelError
|
a non- |
stream(request)
async
¶
The first port's stream that starts; a port that fails after its first event is final.
Raises:
| Type | Description |
|---|---|
ModelError
|
as |
Flow
¶
Bases: Generic[S]
A portable graph flow over a pydantic state model; every builder method returns self.
edge(src, dst)
¶
Add static edges; several destinations run as parallel branches in the next superstep.
end(*names)
¶
Mark end nodes: they have no exit, and the flow is done once nothing else is pending.
graph()
¶
The validated graph as JSON-able nodes and edges (fan-out, fan-in, routes, loops, gates).
Raises:
| Type | Description |
|---|---|
FlowDefinitionError
|
the flow is invalid. |
node(name, action, *, concurrency=None, timeout=None, retries=0, pause=False, prompt=None, cache=None)
¶
Add a node: fn(state) / fn(state, ctx), or a Call, Map, Join or SubFlow.
prompts()
¶
The prompt of every node that has one, by node name.
route(src, route, *, max_loops=None, on_exhausted=None)
¶
Add a conditional exit from src; max_loops caps how often it may revisit nodes.
start(name)
¶
Set the start node (default: the first node added).
to_mermaid()
¶
The validated graph as a mermaid flowchart.
Raises:
| Type | Description |
|---|---|
FlowDefinitionError
|
the flow is invalid. |
validate()
¶
Check the definition and return its graph.
Raises:
| Type | Description |
|---|---|
FlowDefinitionError
|
every problem found, listed together (a sub-flow cycle alone). |
with_prompts(prompts)
¶
A copy whose named nodes carry the given prompts; this flow is unchanged.
Raises:
| Type | Description |
|---|---|
FlowDefinitionError
|
a name is not a node of this flow. |
FlowRunner
¶
Runs a Flow locally: nodes on the executor, supersteps, merges, routes and pauses.
__init__(executor, *, approval=None, hooks=(), sink=None, max_steps=100, concurrency=None, model=None, checkpoint_key=None, seal_encoder=None, seal_decoder=None, trace_state=False, checkpoints=None)
¶
trace_state=True puts each node's updated values on node.finished (updates).
With checkpoints, every superstep ends with a sealed checkpoint in the store and
each tool call is logged, so recover continues a crashed run without re-running a
finished call.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
a bad |
ConfigError
|
|
dump_checkpoint(checkpoint)
¶
The checkpoint as sealed JSON text, for storage outside this process.
Raises:
| Type | Description |
|---|---|
FlowError
|
the checkpoint is not sealed by this runner ( |
inspect(flow, run_id, ctx=None)
async
¶
A durable run's stored status and checkpoint, checked, without saving anything.
Raises:
| Type | Description |
|---|---|
FlowError
|
no |
(CheckpointNotFound, CheckpointConflict, CheckpointStoreCorrupt)
|
as |
ToolUsageError
|
|
load_checkpoint(flow, data)
¶
A checkpoint from dump_checkpoint text; its MAC is checked before anything is built.
Raises:
| Type | Description |
|---|---|
FlowError
|
not a checkpoint, a wrong MAC ( |
recover(flow, run_id, ctx=None, *, rerun_in_doubt=False)
async
¶
Continue a crashed run from its last checkpoint; finished tool calls replay.
A call that started but logged no result runs again only if its tool is
idempotent=True, or with rerun_in_doubt=True after you checked it. A run that
was paused comes back paused (resume it as usual).
Raises:
| Type | Description |
|---|---|
FlowError
|
no |
CheckpointNotFound
|
nothing is stored for |
CheckpointConflict
|
another worker took the run first, it already ended, or the checkpoint is for another flow. |
CheckpointStoreCorrupt
|
the stored checkpoint or its signature does not check out. |
RecoveryNeedsDecision
|
a call may have run and its tool is not idempotent. |
recover_all(flow, *, rerun_in_doubt=False, limit=100)
async
¶
Recover every unfinished run of flow (a worker on startup), one at a time.
Each run id maps to its result, or to the error that stopped its recovery (another worker took it, a call needs a decision, a node failed); the other runs still go on.
Raises:
| Type | Description |
|---|---|
FlowError
|
no |
resume(flow, checkpoint, decision, ctx=None)
async
¶
Continue a paused run; decision answers checkpoint.pending (the port is not asked).
Only the paused node(s) of the paused superstep run again. A denied tool decision
raises ApprovalDenied inside the node (a FlowError, or a skipped Map item).
Raises:
| Type | Description |
|---|---|
FlowError
|
the checkpoint is from another flow or graph, has nothing pending, holds
another state model, or is not sealed by this runner's key
( |
ApprovalAlreadyDecided
|
the checkpoint was already resumed. |
run(flow, state, ctx=None)
async
¶
Run flow from its start node until it is done, paused or denied.
Raises:
| Type | Description |
|---|---|
FlowDefinitionError
|
the flow is invalid. |
FlowError
|
a node, route or merge failed ( |
FlowLoopExceeded
|
a route without |
FlowError
|
|
GuardrailHook
¶
Bases: Hook
check(stage, payload): True passes; False or a reason string raises GuardrailBlocked.
Payloads: args the validated arguments, result the value of an ok result (failed
results are not checked), llm_request the LLMRequest, llm_response the LLMResponse.
Hook
¶
Override any phase; the defaults do nothing (return None).
before_llm(inv)
async
¶
A ShortCircuit's value must be an LLMResponse.
before_node(inv)
async
¶
A ShortCircuit's value must be the node's state update mapping.
config()
¶
Tunable settings (read by the optimiser); empty when the hook has none.
config_schema()
classmethod
¶
JSON schema of config(), or None when the hook is not tunable.
on_llm_end(inv, billed)
async
¶
Runs once when the call ends, however it ends; billed is its ledger entry or None.
with_config(config)
¶
LLMRequest
¶
Bases: BaseModel
One provider-neutral model call.
LLMResponse
¶
Bases: BaseModel
A model reply, normalised across providers.
parse(model)
¶
Validate the structured output (parsed, else text as JSON) into model.
Raises:
| Type | Description |
|---|---|
ModelContentFiltered
|
the provider withheld the output. |
ModelOutputInvalid
|
the output does not validate against |
Ledger
¶
A LedgerPort: idempotent on (run_id, entry_id); keeps the max_runs latest runs.
max_runs
property
¶
How many runs the in-memory index keeps.
prices
property
¶
The price table used for entries recorded without a cost.
sinks
property
¶
Sinks every recorded entry is forwarded to, in order.
__reduce__()
¶
Refuse pickling with a clear error (it holds locks and loop-bound state).
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
always. |
clear(run_id=None)
¶
Forget one run's entries, or everything (sinks are not touched).
entries(run_id=None, *, thread_id=None)
¶
Entries by run, least recently recorded run first; first-record order within a run.
record(entry)
¶
Price entry if its cost is unknown, store it (replacing a same-id entry), fan out.
summary(run_id=None)
¶
Cost, cache and parallelism summary for one run, or for every run kept.
total_usd(run_id=None, *, thread_id=None)
¶
Sum of known costs; unknown costs count as 0.
LedgerEntry
¶
Bases: BaseModel
One billable call; idempotent on (run_id, entry_id).
from_usage(usage, **fields)
classmethod
¶
An entry whose token counts come from usage; fields sets the rest.
LoggingHook
¶
Bases: Hook
Logs <subject>.start|finish|error lines; errors log at WARNING or above.
Each record carries aa_event and aa_fields attributes for structured handlers, and
a "<event> <json>" message. Arguments are redacted; those of confirm tools, message
content and result values are never logged.
MemoryApprovalStore
¶
In-process ApprovalStore; one threading.Lock makes it safe across event loops.
Every operation is synchronous under the lock (no awaits inside), so loops in several
threads (run_sync) can share one store. Past max_records it evicts the earliest
consumed record, else the oldest decided one, else the oldest pending one (WARNING for
both: a decided record is lost before use); each eviction is O(1).
consume(approval_id)
async
¶
Mark a decided record used; True only for the caller that flipped it.
A pending record is never consumed (False): only a decision can be used up.
Raises:
| Type | Description |
|---|---|
ApprovalNotFound
|
unknown id. |
create(request)
async
¶
Store a pending record (empty id / created_at filled in), or return the open one.
Atomic per (run_id, call_id): while the call has an unconsumed record, that record
is returned unchanged and nothing is stored.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
another call's record already has this approval id. |
decide(approval_id, decision)
async
¶
Record the decision; only the first decide of a record succeeds.
Raises:
| Type | Description |
|---|---|
ApprovalNotFound
|
unknown id. |
ApprovalAlreadyDecided
|
the record is no longer pending. |
ToolUsageError
|
|
list(*, run_id=None, status=None, limit=100)
async
¶
Records newest first, filtered by run and status.
Raises:
| Type | Description |
|---|---|
ConfigError
|
unknown |
MemoryCache
¶
Message
¶
Bases: BaseModel
One chat message.
MissingDependency
¶
Prices
¶
An immutable price table; build one with default(), load() or merged().
version
property
¶
The table version recorded on priced ledger entries.
caps(model)
¶
Capability flags for model; defaults for an unknown model.
cost(model, usage, *, at=None, seconds=0.0, attempts=1)
¶
USD for one call of attempts provider requests lasting seconds; None if unpriced.
Raises:
| Type | Description |
|---|---|
ConfigError
|
a per-second model got a negative or non-finite |
default()
classmethod
¶
The packaged table (cost/prices_default.json), loaded once per process.
empty(version='empty')
classmethod
¶
A table with no models, for pricing only your own with merged().
Raises:
| Type | Description |
|---|---|
ConfigError
|
|
load(source)
classmethod
¶
A table from a mapping or a JSON file path.
Raises:
| Type | Description |
|---|---|
ConfigError
|
the file cannot be read, is not JSON, or the table is invalid. |
merged(overrides)
¶
A new table where each model, alias and unit in overrides replaces this one's.
Raises:
| Type | Description |
|---|---|
ConfigError
|
the overrides are invalid. |
price(model, *, at=None, prompt_tokens=0)
¶
Prices for model on at (default today, UTC) at this prompt size; None if unpriced.
resolve(model)
¶
The table key for model: exact name, alias, then longest match; None if unknown.
A row key matches when the rest is a snapshot suffix (-2025-04-14, -20250514,
-0613, -001, -latest); a caps-only key ending in - matches its family; a
key ending in * matches any id starting with what precedes it ("*": any id).
The longest matched prefix wins; on a tie, row, then pattern, then family. caps()
reads this key; price() skips caps-only entries (ResolvedPrice.model is its key).
unit_cost(item, units, *, at=None)
¶
USD for units of item ("provider:model", or "provider:model:cache_storage").
item is looked up exactly, then by the longest * pattern in units. A storage
item uses its model's cache_storage_per_hour first (0 for a free model).
RateLimitHook
¶
Bases: Hook
Delays tool calls by spec.kind and model calls by "llm"; unlisted kinds never wait.
One bucket per kind is shared by every event loop and thread: its state sits under a
threading.Lock, and each caller books a slot there (GCRA) and then sleeps in its own
loop, so no asyncio primitive is shared between loops. A cancelled wait returns its slot
only when it was the latest booking, so a slot is never handed out twice.
RedisApprovalStore
¶
ApprovalStore on Redis (agent-adapter[redis]), shared by every worker and host.
client_factory() returns a redis.asyncio.Redis (one per event loop), e.g.
lambda: Redis.from_url(url) (keep decode_responses=False). create and every
status change are Lua scripts; decide and consume compare-and-set the stored record,
so each decision is consumed once. Each record expires ttl_s seconds after it was
created (None: never; then run Redis with maxmemory-policy noeviction). Backend
errors propagate (fail closed). On Redis Cluster put a hash tag in prefix
("{approvals}:"): the scripts address record keys built from it.
Raises:
| Type | Description |
|---|---|
ConfigError
|
|
aclose()
async
¶
Close the running loop's client.
consume(approval_id)
async
¶
Mark a decided record used; True only for the caller that flipped it.
Raises:
| Type | Description |
|---|---|
ApprovalNotFound
|
unknown or expired id. |
create(request)
async
¶
Store a pending record (empty id / created_at filled in), or return the open one.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
another call's record already has this approval id, or the record holds a value JSON cannot carry. |
decide(approval_id, decision)
async
¶
Record the decision; only the first decide of a record succeeds.
Raises:
| Type | Description |
|---|---|
ApprovalNotFound
|
unknown or expired id. |
ApprovalAlreadyDecided
|
the record is no longer pending. |
ToolUsageError
|
|
find(run_id, call_id)
async
¶
The unconsumed record of the call, or None.
get(approval_id)
async
¶
The record. Raises: ApprovalNotFound.
list(*, run_id=None, status=None, limit=100)
async
¶
Records newest first, filtered by run and status (expired ones are skipped).
Raises:
| Type | Description |
|---|---|
ConfigError
|
unknown |
Registry
¶
Holds ToolSpecs by name; executors and exports read from here.
__reduce__()
¶
Refuse pickling with a clear error (it holds locks and loop-bound state).
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
always. |
add(spec)
¶
Register a spec after checking its name and schema portability.
Raises:
| Type | Description |
|---|---|
DuplicateTool
|
the name is taken. |
SchemaNotPortable
|
the schema would fail on some provider. |
add_many(specs)
¶
Register several specs, all or nothing.
Raises:
| Type | Description |
|---|---|
DuplicateTool
|
a name is taken or repeated; nothing is registered. |
SchemaNotPortable
|
a schema would fail on some provider; nothing is registered. |
catalogue()
¶
Markdown tool list for planner prompts, generated so it never drifts from code.
for_target(target)
¶
A new registry with the tools exported to target (targets None or listing it).
get(name)
¶
names()
¶
Tool names in registration order.
remove(name)
¶
subset(*, names=None, tags=None, kinds=None)
¶
A new registry holding only tools that match every given filter.
Raises:
| Type | Description |
|---|---|
ToolNotFound
|
a requested name is not registered. |
tool(func=None, /, **options)
¶
Decorator: register a function as a tool and return it unchanged.
wrap(func, **options)
¶
Register existing code as a tool without editing it.
RunLimits
dataclass
¶
Per-run limits; per_kind caps concurrent calls of one tool kind within a run.
SQLiteApprovalStore
¶
ApprovalStore in a SQLite file (WAL), safe across threads, loops and processes.
Every call runs in a worker thread (asyncio.to_thread) on its own connection.
create, decide and consume hold BEGIN IMMEDIATE, so writers on every process
are serialised; timeout is how long one waits for the file lock (seconds). Past
max_records it evicts like MemoryApprovalStore: the earliest consumed record,
else the oldest decided, else the oldest pending (WARNING).
Raises:
| Type | Description |
|---|---|
ConfigError
|
a bad |
consume(approval_id)
async
¶
Mark a decided record used; True only for the caller that flipped it.
Raises:
| Type | Description |
|---|---|
ApprovalNotFound
|
unknown id. |
create(request)
async
¶
Store a pending record (empty id / created_at filled in), or return the open one.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
another call's record already has this approval id, or the record holds a value JSON cannot carry. |
decide(approval_id, decision)
async
¶
Record the decision; only the first decide of a record succeeds.
Raises:
| Type | Description |
|---|---|
ApprovalNotFound
|
unknown id. |
ApprovalAlreadyDecided
|
the record is no longer pending. |
ToolUsageError
|
|
find(run_id, call_id)
async
¶
The unconsumed record of the call, or None.
get(approval_id)
async
¶
The record. Raises: ApprovalNotFound.
list(*, run_id=None, status=None, limit=100)
async
¶
Records newest first, filtered by run and status.
Raises:
| Type | Description |
|---|---|
ConfigError
|
unknown |
Step
dataclass
¶
One tool call of a plan; callable args receive the results of depends_on.
ToolCall
¶
Bases: BaseModel
One tool call requested by a model or a host.
ToolContext
dataclass
¶
ToolDef
¶
Bases: BaseModel
A tool as model ports receive it.
ToolError
¶
ToolResult
dataclass
¶
ToolSpec
dataclass
¶
A registered tool: callable, argument model and execution policy.
Equality and hashing are by identity: two specs built from the same function are
different tools (they may differ in fixed, rename or policy).
call(validated, ctx=None)
async
¶
Call the function with already-validated args (sync ones in a worker thread).
A direct call is no executor attempt: current_attempt() is None inside it.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
|
invoke(args=None, ctx=None)
async
¶
Validate args, call the function, apply result.
Raises:
| Type | Description |
|---|---|
ToolArgsInvalid
|
arguments are missing, unknown or the wrong type. |
json_schema()
¶
Neutral JSON schema of the LLM-supplied arguments (input_schema if set); a copy.
result_schema()
¶
output_schema, else the return annotation's schema; None if absent or result set.
tool_def(*, strict=True)
¶
The tool as model ports take it (see strict_downgraded).
validate_args(args)
¶
Validate LLM-supplied arguments against the tool's model.
Raises:
| Type | Description |
|---|---|
ToolArgsInvalid
|
arguments are missing, unknown or the wrong type. |
Usage
¶
Bases: BaseModel
Normalised token usage of one or more LLM calls.
prompt_tokens
property
¶
Every input token: billable, cached and cache-write.
acall(tool, /, **args)
async
¶
Run tool (a function, spec or name) on the default executor and return its value.
attach(target_or_name, registry=None, *, executor=None, **opts)
¶
The framework's native tools for registry (default: default_registry).
target_or_name is an integration name ("langgraph", "openai-agents") or an
object, class or module from that framework. executor runs every call (default: the
process-wide default executor). Approval stays on the executor: an option such as
approval=True is refused. Other opts go to an integration's own attach method.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
an approval option, a bad registry or executor, or options the integration does not take. |
IntegrationError
|
no installed integration matches; the message lists them. |
MissingDependency
|
the integration's extra is not installed. |
build_spec(func, *, name=None, description=None, fixed=None, hide=(), rename=None, result=None, args_model=None, **policy)
¶
Build a ToolSpec from a function's signature and docstring.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hide
|
Iterable[str] | str
|
Parameter names (or one name) hidden from the LLM; their defaults apply. |
()
|
rename
|
Mapping[str, str] | None
|
Python parameter name -> name the LLM sees. |
None
|
args_model
|
type[BaseModel] | None
|
Use this model as the argument schema instead of the signature's types; its field names must equal the LLM-facing parameter names. |
None
|
**policy
|
Any
|
Execution options such as |
{}
|
Raises:
| Type | Description |
|---|---|
ToolDefinitionError
|
the function cannot be exposed as a tool. |
call(tool, /, **args)
¶
acall from sync code, on the process's shared loop; raises like Executor.run.
configure(registry=None, **options)
¶
Make Executor(registry, **options) the default (call, integrations) and return it.
Raises:
| Type | Description |
|---|---|
TypeError
|
an unknown option name. |
ToolUsageError
|
a bad option value (see |
run_sync(work, *, timeout=None)
¶
Run work to completion on a fresh event loop and return its result.
Without a running loop in this thread it uses asyncio.run. Inside a running loop
(Jupyter, an async framework) it runs that loop in a one-shot worker thread with a copy
of the current contextvars and blocks this thread until done. Loop-local values
(LoopLocal) are closed before the loop ends.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
work
|
Awaitable[T] | Callable[[], Awaitable[T]]
|
An awaitable, or a zero-argument callable returning one (called inside the loop). |
required |
timeout
|
float | None
|
Seconds before the work is cancelled. In the worker-thread case the caller
also stops waiting |
None
|
Raises:
| Type | Description |
|---|---|
TimeoutError
|
the work ran past |
ToolUsageError
|
|
run_tool_loop(model, registry, messages, *, max_steps=8, executor=None, ctx=None, output_schema=None, tool_choice='auto', concurrency=None, stage='tool_loop', request_options=None, compression=None, on_text=None, on_event=None, run_id=None, checkpoints=None, checkpoint_key=None)
async
¶
Call the model, run its tool calls, feed the results back, until it answers.
messages ending in an assistant turn whose tool calls lack results (a loop that stopped
on pending or max_steps) resumes by running those calls first; pass the same ctx
(or one with the same run_id) so approvals and run guards carry over.
With compression, the history is compressed before each model call and the loop goes
on with the shorter history (also in the result); a context overflow runs the policy's
if_still_too_long once and retries the call once.
With on_text, each model call streams through the port's stream() and every text
chunk is passed to on_text (sync or async) as it arrives. on_event (also streaming)
gets every other stream event: ToolCallDelta, PartialOutput, and the StreamDone
that ends each model call.
With checkpoints (and a run_id, or a ctx with one), the history is saved signed
after each step and every tool call is logged; recover_tool_loop continues the run
after a crash without re-running a finished call. A paused run resumes here.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
|
ConfigError
|
|
CheckpointConflict
|
|
ModelError
|
the model call failed. |
set_default_executor(executor)
¶
Make executor the default for every integration that is not given one.
Raises:
| Type | Description |
|---|---|
ToolUsageError
|
|
spec_from_schema(name, description, input_schema, func, *, output_schema=None, portable=None, context_param=None, **policy)
¶
A tool whose arguments are described by input_schema instead of a signature.
func receives the set arguments as keywords named exactly as the schema properties
(plus context_param=ctx when set); unset optional arguments are not sent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
portable
|
bool | None
|
None checks the schema and records the result; True makes |
None
|
**policy
|
Any
|
Execution options as for |
{}
|
Raises:
| Type | Description |
|---|---|
ToolDefinitionError
|
bad name, empty description, non-object schema or bad option. |