Durable Agents: LLM Agents on Mistral Workflows
Durable Agents allow you to run LLM agents within your Mistral workflows.
Installation
To use Durable Agents, install the Mistral plugin:
uv add 'mistralai-workflows[mistralai]'What is a Durable Agent?
A Durable Agent is an LLM agent that executes within a workflow, benefiting from:
- Durability: Agent state is preserved across failures and restarts
- Tool Integration: Use activities as agent tools
- Multi-Agent Handoffs: Agents can delegate tasks to specialized agents
- MCP Support: Connect to external tools via Model Context Protocol (stdio / SSE)
Architecture Overview
flowchart TB
subgraph Runner["Runner"]
direction TB
R[Runner.run]
end
subgraph Session["Session"]
S[RemoteSession / LocalSession]
end
subgraph Coordinator["Coordinator Agent"]
CA[deal-coordinator]
end
subgraph Specialists["Specialist Agents"]
RA[risk-agent]
CompA[compliance-agent]
end
subgraph Activities["Activities"]
A1[parse_deal_document]
A2[calculate_risk_score]
A3[check_compliance]
end
subgraph BuiltIn["Built-in Tools"]
T1[WebSearchTool]
end
subgraph External["External"]
MCP[MCP Server]
end
R -->|manages| S
S -->|runs| CA
CA -->|handoff| RA
CA -->|handoff| CompA
CA -->|uses| A1
RA -->|uses| A2
RA -->|connects| MCP
CompA -->|uses| A3
CompA -->|uses| T1The Runner orchestrates agent execution through a Session. Agents can hand off tasks to specialized agents and each agent can use activities, built-in Mistral tools or MCP servers as tools.
Core Components
Agent
The Agent class defines an LLM agent with its model, instructions, tools and handoffs:
import mistralai.workflows as workflows
import mistralai.workflows.plugins.mistralai as workflows_mistralai
agent = workflows_mistralai.Agent(
model="mistral-medium-latest",
name="my-agent",
description="Agent that performs specific tasks",
instructions="Use tools to complete the user's request.",
tools=[my_activity], # Workflows activities as tools
handoffs=[other_agent], # Agents to delegate to
)Runner
The Runner executes an agent with user inputs and manages the conversation loop. It calls the model, processes tool calls, and repeats until the agent produces a final response or reaches max_turns. If max_turns is reached, the runner returns whatever outputs have been collected so far.
import mistralai.workflows as workflows
import mistralai.workflows.plugins.mistralai as workflows_mistralai
outputs = await workflows_mistralai.Runner.run(
agent=agent,
inputs="What is the interest rate for 2024?",
session=session,
max_turns=10, # Maximum model call iterations before stopping
)The returned outputs is a list of output items produced by the agent during the run (text responses, tool results, handoff results).
Sessions
Sessions manage agent state and API communication. Two session types are available:
| Session | Use Case | Backend |
|---|---|---|
RemoteSession | Production (recommended) | Mistral Agents SDK |
LocalSession | Experimental / On-premises | Direct completion API |
Basic example
Here's a simple agent workflow that uses an activity as a tool:
import mistralai.workflows as workflows
import mistralai.workflows.plugins.mistralai as workflows_mistralai
from mistralai.client.models import TextChunk
@workflows.activity()
async def get_interest_rate(year: int) -> dict:
"""Get the interest rate for a given year.
Args:
year: The year to get the interest rate for
"""
# Your implementation here
return {"interest_rate": 1.62}
@workflows.workflow.define(name="finance_agent_workflow")
class FinanceAgentWorkflow:
@workflows.workflow.entrypoint
async def entrypoint(self, question: str) -> dict:
session = workflows_mistralai.RemoteSession()
agent = workflows_mistralai.Agent(
model="mistral-medium-latest",
name="finance-agent",
description="Agent for financial queries",
instructions="Use tools to answer financial questions.",
tools=[get_interest_rate],
)
outputs = await workflows_mistralai.Runner.run(
agent=agent,
inputs=question,
session=session,
)
answer = "\n".join([
output.text for output in outputs
if isinstance(output, TextChunk)
])
return {"answer": answer}Multi-Agent Handoffs
Agents can delegate tasks to specialized agents using handoffs. The system automatically manages the handoff conversation:
import mistralai.workflows as workflows
import mistralai.workflows.plugins.mistralai as workflows_mistralai
# Create a specialized agent for interest rate queries
interest_rate_agent = workflows_mistralai.Agent(
model="mistral-medium-latest",
name="ecb-interest-rate-agent",
description="Agent for European Central Bank interest rate research",
instructions="Use tools to get the interest rate for a given year.",
tools=[get_interest_rate],
)
# Main agent that can hand off to the specialist
finance_agent = workflows_mistralai.Agent(
model="mistral-medium-latest",
name="finance-agent",
description="Agent for financial queries",
handoffs=[interest_rate_agent], # Can delegate to interest_rate_agent
)
outputs = await workflows_mistralai.Runner.run(
agent=finance_agent,
inputs="What was the ECB interest rate in 2023?",
session=workflows_mistralai.RemoteSession(),
)When the finance agent receives a query about ECB interest rates, it can automatically hand off to the specialized interest_rate_agent.
MCP Integration
Connect to external tool servers using the Model Context Protocol. Two transport types are supported:
Stdio MCP Server
For local command-line MCP servers:
from mistralai.workflows.plugins.mistralai import MCPStdioConfig
mcp_config = MCPStdioConfig(
command="npx",
args=["-y", "@modelcontextprotocol/server-everything"],
name="server-everything",
)
agent = Agent(
model="mistral-medium-latest",
name="mcp-agent",
description="Agent with access to MCP tools",
mcp_clients=[mcp_config],
)SSE MCP Server
For remote MCP servers over Server-Sent Events:
from mistralai.workflows.plugins.mistralai import MCPSSEConfig
mcp_config = MCPSSEConfig(
url="https://your-mcp-server.com/sse",
timeout=60,
name="remote-tools",
headers={"Authorization": "Bearer your-token"}, # Optional
)
agent = workflows_mistralai.Agent(
model="mistral-medium-latest",
name="sse-mcp-agent",
description="Agent with access to remote MCP tools",
mcp_clients=[mcp_config],
)Built-in Tools
Use Mistral's built-in tools alongside activities:
import mistralai.workflows as workflows
import mistralai.workflows.plugins.mistralai as workflows_mistralai
from mistralai.client.models import WebSearchTool
agent = workflows_mistralai.Agent(
model="mistral-medium-latest",
name="web-search-agent",
description="Agent with web search capability",
instructions="Use web search to answer user questions",
tools=[WebSearchTool()],
)Available built-in tools:
| Tool | Description |
|---|---|
WebSearchTool() | Search the web and return results to the model |
CodeInterpreterTool() | Execute Python code in a sandboxed environment |
ImageGenerationTool() | Generate images from text descriptions |
DocumentLibraryTool() | Analyze and extract information from uploaded documents |
These tools are executed server-side by the Mistral platform — they do not run in your worker process. Pass them in the tools list alongside any activity-based tools.
Session Types
RemoteSession (Recommended)
Uses the Mistral Agents SDK for production workloads:
import mistralai.workflows as workflows
import mistralai.workflows.plugins.mistralai as workflows_mistralai
session = workflows_mistralai.RemoteSession()
outputs = await workflows_mistralai.Runner.run(
agent=agent,
inputs="Your question here",
session=session,
)Features:
- Full Agents SDK integration
- Automatic agent creation and updates
- Managed conversation state
- Production-ready
LocalSession (Experimental)
Runs agents locally using the completion endpoint:
import mistralai.workflows as workflows
import mistralai.workflows.plugins.mistralai as workflows_mistralai
session = workflows_mistralai.LocalSession()
outputs = await workflows_mistralai.Runner.run(
agent=agent,
inputs="Your question here",
session=session,
)Use cases:
- On-premises deployments that doesn't have access to Agents (Bora)
- Development and testing
- Full context control
LocalSession is experimental and may be removed in future versions. Use RemoteSession for production workloads.
Complete Workflow Example
A full example combining activities, handoffs and workflow orchestration:
import asyncio
import mistralai.workflows as workflows
import mistralai.workflows.plugins.mistralai as workflows_mistralai
from mistralai.client.models import TextChunk
@workflows.activity()
async def calculate_risk_score(deal_type: str, amount: float) -> dict:
"""Calculate financial risk score for a deal.
Args:
deal_type: The type of deal being analyzed
amount: The monetary amount of the deal
"""
risk_score = min(100.0, amount / 10000.0)
risk_factors = []
if amount > 100000:
risk_factors.append("High value transaction")
return {"risk_score": risk_score, "risk_factors": risk_factors}
@workflows.workflow.define(name="deal_analysis_workflow")
class DealAnalysisWorkflow:
@workflows.workflow.entrypoint
async def entrypoint(self, deal_request: str) -> dict:
"""Analyze a deal request.
Args:
deal_request: The deal request to analyze
"""
session = workflows_mistralai.RemoteSession()
# Risk assessment agent
risk_agent = workflows_mistralai.Agent(
model="mistral-medium-latest",
name="risk-agent",
description="Analyzes financial risk of deals",
instructions="Use the risk calculation tool to assess deal risk.",
tools=[calculate_risk_score],
)
# Main coordinator agent
coordinator = workflows_mistralai.Agent(
model="mistral-medium-latest",
name="deal-coordinator",
description="Coordinates deal analysis",
instructions="Analyze the deal request and hand off to specialists.",
handoffs=[risk_agent],
)
outputs = await workflows_mistralai.Runner.run(
agent=coordinator,
inputs=deal_request,
session=session,
)
analysis = "\n".join([
output.text for output in outputs
if isinstance(output, TextChunk)
])
return {"analysis": analysis}
if __name__ == "__main__":
asyncio.run(workflows.run_worker([DealAnalysisWorkflow]))Best practices
- Use RemoteSession for production - It provides better reliability and Agents SDK integration
- Keep activities granular - Small, focused activities work better as agent tools
- Provide clear instructions - Agent performance depends on clear instructions
- Use handoffs for specialization - Create specialized agents for specific domains and improve context management by delegating tasks
- Handle tool errors gracefully - Activities used as tools should return meaningful error messages