Your first agent

A tool, an agent, a reply — in about ten lines.

A tool is a decorated async function. An agent is a prompt, a model and a list of tools. There is no third concept.

from agentino import Agent, tool

@tool
async def get_weather(city: str) -> str:
    """Look up current weather for a city."""
    return f"It's 22°C in {city}."

agent = Agent(instructions="You're a helpful assistant.", tools=[get_weather])
print(await agent.run("What's the weather in Lisbon?"))
# → "It's 22°C in Lisbon. Want a forecast?"

That is the whole API. The framework handles the model round-trip, tool dispatch, retries and pulling the final text out of the response.

What the decorator reads

@tool builds the schema the model sees from the function itself — nothing is declared twice:

  • the function name becomes the tool name
  • the docstring becomes the description, and its Args: section describes each parameter
  • the type hints become the JSON schema

So the function above is offered to the model as get_weather(city: string) with the description "Look up current weather for a city." Rename the function and the tool renames itself.

What happens on .run()

  1. Your instructions and the user's message go to the model along with the tool schemas.
  2. If the model asks for a tool, the runtime calls it, appends the result, and goes back to the model.
  3. That repeats until the model answers in prose or max_turns is reached.
  4. You get the final text.

Failures inside a tool come back to the model as an error result rather than raising, so one broken lookup does not end the turn.

Synchronous callers

The core is async all the way down, and there is deliberately no sync wrapper — one would either block an event loop that is already running or hide the fact that a turn takes seconds. From synchronous code, drive it yourself:

import asyncio

print(asyncio.run(agent.run("What's the weather in Lisbon?")))

Runner is the higher-level entry point when you are working from a config file rather than an Agent you built in Python:

from agentino import Runner, load_config

runner = Runner(load_config("agents.yml"))
print(await runner.one_shot("Review PR #42"))

load_agents is the same loader when you want the agents themselves rather than a runner around them.