Skip to content

smolagents

Available · Tool subclass per spec · pip install "agent-adapter[smolagents]"

smolagents tools are synchronous. Each exported tool's forward runs the executor through run_sync, so the full async pipeline applies.

Functions

Function (agent_adapter.integrations.smolagents) Returns
smolagents_tool(spec, *, executor=None) one smolagents.Tool for spec
smolagents_tools(registry, *, executor=None) a tool for every registry tool whose targets include smolagents
INTEGRATION the integration object (get_integration("smolagents"))

executor=None uses the default executor at call time (set_default_executor).

Use

executor = Executor(registry)  # hooks, approval, cache, ledger apply to every call
tools = smolagents_tools(registry, executor=executor)
rate = tools[0]
print(rate.name, rate.output_type, rate(region="us"))  # sync: forward uses run_sync
print(rate(region="mars"))  # ToolError comes back as a model-visible error

In a ToolCallingAgent:

agent = ToolCallingAgent(tools=tools, model=OfflineModel(), verbosity_level=0)
print("answer:", agent.run("Shipping rate to the US?"))
sequenceDiagram
  participant A as Agent (sync)
  participant T as Tool.forward
  participant RS as run_sync
  participant E as Executor
  A->>T: tool(**arguments)
  T->>RS: run_sync(run_spec(...))
  Note over RS: no loop in this thread: asyncio.run<br/>loop running: a worker thread with its own loop
  RS->>E: run_spec(spec, args, ctx)
  E-->>RS: value, or raises
  RS-->>T: value
  T-->>A: observation (value, or the error payload)

What smolagents sees

Tool attribute From
name, description spec.name, spec.description; a Python keyword as name raises IntegrationError
inputs each property of the plain schema, with description (default "") and nullable: True for optional or nullable arguments
inputs[...]["type"] the JSON type; Optional[X] becomes X (nested schema kept); other unions a type list; anything else "any"
output_type the result schema's JSON type, else "any"

Behaviour

Topic Rule
Validation The tool's own args model, in the executor. smolagents' agent check runs first in agents, with the same types
Errors ToolArgsInvalid, ToolError, ApprovalDenied, GuardrailBlocked, RunLimitExceeded come back as {"error": {"kind", "message"}} (its JSON text when output_type is "string"); anything else raises
Positional args tool("tea") maps to inputs in order, as agents call one-input tools
Call id forward gets only arguments, so each call gets a fresh call_... id. ctx.extras["smolagents"] is the tool
Approval smolagents has no per-tool gate: confirm tools ask the executor's ApprovalPort. Edited arguments from the port are validated again and applied. Use a port that blocks until it decides (CallbackApproval, a console or UI prompt): a DeferredApproval raises ApprovalPending, which the agent (it catches Exception) reports to the model as a tool error instead of pausing the run
Serialisation Tool.save, push_to_hub, to_dict and remote executors (E2B, Docker, Modal) are not supported: the tool closes over the spec and the executor, which cannot be written out as source
Cancellation forward blocks a thread. Cancelling the awaiter of asyncio.to_thread(tool, ...) does not stop that thread; the tool's own timeout does. CancelledError raised inside the tool propagates