Feature highlights
Each card shows one feature in a few lines of Python, with the output of a real run.
To run the examples, install the SDK and paste each one into main() of the file below. Its tools return fixed text.
main.py
import asyncio
from pydantic import BaseModel
from mistralai import agents
@agents.tool(annotations=agents.ToolAnnotations(read_only_hint=True))
async def get_order(order_id: str) -> str:
"""Get the status of an order."""
return f"Order {order_id}: delivered, 49 EUR"
@agents.tool(annotations=agents.ToolAnnotations(read_only_hint=True))
async def list_orders(country: str) -> list[str]:
"""List this week's orders for a country, or for every country with 'any'."""
return [f"order {number} ({country})" for number in range(1040, 1045)]
@agents.tool
async def refund_order(order_id: str) -> str:
"""Refund an order."""
return f"Order {order_id}: refunded"
agent = agents.Agent(
model="mistral-large-4",
name="support-agent",
instructions="Answer questions about orders in one plain sentence.",
tools=[get_order, list_orders, refund_order],
)
async def main() -> None:
... # paste an example's code here
if __name__ == "__main__":
asyncio.run(main())Approve tool calls
With permission_mode="ask", every tool call needs an approval. Your code can give it, or leave the call for a person to approve.
def policy(
ctx: agents.ApprovalCallbackContext, request: agents.ApprovalRequest
) -> agents.AllowApproval | agents.KeepCallbackOpen:
if request.tool.annotations.read_only_hint:
return agents.AllowApproval()
return agents.KeepCallbackOpen() # anything else waits for a person
careful = agents.Agent(
model="mistral-large-4",
tools=[get_order, refund_order],
permission_mode="ask",
)
session = await careful.start_session(on_approval=policy)
state = await session.run("Check the status of order 1042, then refund it.")
while isinstance(state, agents.Blocked): # refund_order waits
turn = session.turn(state.turn_id)
for callback in state.callbacks:
await turn.answer(callback.id, agents.AllowApproval()) # a person allows
state = await turn.result(after=state)
if isinstance(state, agents.Completed):
print(state.text)
await session.cancel()The loop runs until the turn ends: turn.result(after=state) waits for the turn again, from where it stopped. See Approvals and Step through a session.
Steer a turn while it runs
Send a message to the agent while it works, to change what it does. on_event= shows the turn's events as they come.
def show(event: agents.Event) -> None:
match event:
case agents.EntryCompleted(entry=agents.MessageEntry(role="user") as message):
print("user:", message.text)
case agents.EntryCompleted(entry=agents.ToolCallEntry(name, arguments)):
print("calling", name, arguments)
case agents.TextDelta(text=text):
print(text, end="", flush=True) # the reply, while the model writes it
session = await agent.start_session()
turn = await session.send_message("List this week's orders, then count them.")
await turn.steer("Only the orders from France.")
state = await turn.result(on_event=show)
print()
await session.cancel()The steer joins the running turn. Here it arrives before the first tool call, so the agent lists only the orders from France. See Build a session app and Follow a turn while you wait.
Get a typed result in one call
run sends one message and waits for the answer. Pass a Pydantic model as output_type to get the answer as an object of that model.
class Order(BaseModel):
order_id: str
delivered: bool
price_eur: int
typed = agents.Agent(model="mistral-medium-latest", tools=[get_order])
state = await typed.run("What is the status of order 1042?", output_type=Order)
if isinstance(state, agents.Completed):
print(state.output)See One call and Structured output.
Interact with an agent
A session keeps everything the agent has done, so each message builds on the work before it. It can hold a quick exchange, work that runs for hours, or a follow-up the next day.
# payment-reviewer and review_policy come from the suspicious payment review example
agent = agents.Agent.load_from(agent_name="payment-reviewer")
session = await agent.start_session(on_approval=review_policy)
await session.run("Summarise alert 4711: who paid whom, and why it was flagged.")
stored_id = session.id # keep it, in your database
# The next day, in a new process: the same session, by its id
agent = agents.Agent.load_from(agent_name="payment-reviewer")
session = agent.session(stored_id, on_approval=review_policy)
state = await session.run("Compare it with the customer's payments of the last 12 months.")
if isinstance(state, agents.Completed):
print(state.text)See Sessions.
Deploy to Mistral
In a project made by agents init, with the main.py above (its agent is support-agent): chat with the agent in your terminal, then push and deploy it. The deploy builds the commit you pushed to GitHub, in the repository that Deploy your agent sets up:
uv run --env-file .env agents chat
git add --all && git commit -m "Support agent"
git push
uv run --env-file .env agents deployThe figure adds environment=agents.MistralSandbox() to the agent in main.py: then each session gets its own container on Mistral, deleted when the session closes. Without it, the agent has no sandbox (NoSandbox, the default).
Your app loads the deployed agent by its name, then runs it like a local one:
agent = agents.Agent.load_from(agent_name="support-agent")
state = await agent.run("Has order 1042 shipped?")
if isinstance(state, agents.Completed):
print(state.text)See Deploy your agent and Deploy.
Run in the background
Once you deploy with Studio, self-hosted or Mistral-managed, execution is durable and runs in the background. Your app can exit and get the result later. This example uses the agent from Deploy to Mistral. The figure shows the same calls with the coding agent of Private repository cleanup agent, which works for minutes in its own sandbox.
agent = agents.Agent.load_from(agent_name="support-agent")
session = await agent.start_session()
turn = await session.send_message("List this week's orders, then count them.")
session_id, turn_id = session.id, turn.id # store them, then exit
# Later, after your app restarts:
agent = agents.Agent.load_from(agent_name="support-agent")
session = agent.session(session_id)
state = await session.turn(turn_id).result()
if isinstance(state, agents.Completed):
print(state.text)
await session.cancel()Next steps
- Quickstart: install the SDK, then build and chat with a first agent, step by step.
- Deploy your agent: run it on Mistral and call it from your app.