agentix.executors¶
executors ¶
Tool execution — the boundary where tool calls actually run.
The executor is deliberately separate from the model and from tool definitions:
the registry says what tools exist, the executor says how (and under what
limits) they run. Keeping execution here is what lets you drop in a sandboxed
executor later without touching the loop. The loop passes the policy's
network_allowlist and timeout_s so those limits can't be influenced by
the model.
ToolExecutor ¶
Bases: Protocol
Executes a single tool call under policy-enforced limits.
LocalToolExecutor ¶
Runs tools in-process by dispatching to a mapping of name -> callable.
Callables may be sync or async and are invoked with the tool-call args as
keyword arguments. Each call is bounded by timeout_s. This executor does
NOT sandbox the network or filesystem and cannot honour network_allowlist
(an in-process call can open any socket) — it's the default for trusted,
in-process tools. For untrusted tools or model-generated code, use
:class:~agentix.sandbox.SubprocessExecutor, which runs each call in an
isolated subprocess and enforces the network/resource limits.
Concurrency: synchronous tool functions are run in a worker thread
(via :func:asyncio.to_thread) so a blocking tool can't stall the event
loop and starve other concurrently-running agents — and so timeout_s
can actually return control (a blocking sync call cannot be timed out while
it holds the loop). Note: a timed-out sync tool's thread keeps running in
the background until it returns — Python can't forcibly kill a thread — and
sync tools draw from the default thread-pool, so size that pool for your
concurrency (loop.set_default_executor(...)). Async tools run inline.