Mistral Agents API Research
Give a Mistral agent a research tool. You declare research_report as a function tool in the Agents API, beside Mistral's own web_search. When the model calls it, your code starts a SpecStream research report and returns the written answer from the live web, with a numbered list of the pages it cites and when each was read. A report has one fixed price: $0.10, $0.30 or $1.00 by depth.
What you need
- A Mistral API key, and Python with the Mistral SDK and requests (
pip install mistralai requests). The code uses the SDK's V2 imports,from mistralai.client import .... On V1 of the SDK, import the same names frommistralai. - A SpecStream key. Get your key on the Search API screen of your SpecStream workspace. New accounts start with $10 of credit, no card.
- 1
1. Set both keys
Create a key in your SpecStream workspace, then set it and your Mistral key on the machine that runs your code. Neither key goes into a file.
Terminal - 2
2. Write the research function
Save this as
specstream_research.py.research_reporttakes the question and a depth:quick,standardordeep. It starts the report withPOST /v1/research, then readsGET /v1/research/{id}every 5 seconds for up to 7 minutes. A quick report takes about a minute, a standard report about four and a deep report about five, so the report usually comes back in the same call: the text with[1]markers, then a Sources list with each cited page's title, URL and read time.If the report needs longer, the function returns the report ID, which starts with
rr_.read_research_reportreads a report by that ID and costs nothing.Mistral runs a function tool in your environment, so the SpecStream key stays in your process and never reaches the model.
specstream_research.py - 3
3. Create the agent with the function tool
Save this as
agent.pyand run it once.client.beta.agents.createtakes the tools list:{"type": "web_search"}is Mistral's built in search, and each{"type": "function", ...}entry is a JSON schema for one of your functions. The description carries the three prices, and the instructions make the agent name the price and wait for a yes before it starts a report.The script prints the agent ID, which starts with
ag_. Keep it for the next step.agent.py - 4
4. Answer each function call
Save this as
chat.py. It starts a conversation withclient.beta.conversations.startand continues it withclient.beta.conversations.append. When an output has the typefunction.call, the script runs the function named in it and sends the result back as aFunctionResultEntrywith the sametool_call_id. It answers every call in the reply, so two calls in one turn both get their result.Mistral runs
web_searchon its own servers. Only your two functions reach this loop.chat.py - 5
5. Ask for a report
Run the chat with the agent ID from
agent.py. Ask your question. The agent names the price, and after your yes it callsresearch_report. The terminal waits about a minute for a quick report, then prints the report with its sources. SpecStream takes the $0.10 from your balance when the report is delivered.Terminal
Beside Mistral's web_search
The two tools do different jobs, and the agent's instructions tell the model which to pick. web_search answers one fact inside the turn, on Mistral's servers. research_report plans the question, searches the live web, reads the pages and writes an answer of several paragraphs, where each cited sentence carries a [1] marker and the Sources list gives that page's title, its URL and the time it was read in this run.
web_search works with the Conversations API and the Agents API, and Mistral's docs say it is not supported in Chat Completions. A function tool works in all three. For Chat Completions, declare the same two schemas in the tools field and answer each tool call with a tool message. The Mistral API guide has that loop for web search.
On the Agents SDK
Mistral's docs now carry this notice: the Agents API v1 is about to be deprecated, and new agents are built with the Agents SDK (mistralai-agents, in public preview). The function from step 2 moves over as it is. Decorate a wrapper with @agents.tool and pass it in tools=. The SDK takes the tool's name from the function's name, its description from the docstring and its input schema from the typed parameters, so there is no JSON schema to write.
The wrappers are plain def functions, since they wait for the report. Mistral's docs say a blocking tool written as a plain def runs in its own thread. Save the file as main.py beside specstream_research.py, add the dependency with uv add requests, and run uv run --env-file .env agents chat. Put SPECSTREAM_API_KEY in the same .env as your Mistral key. To make the price approval a rule of the harness and not only an instruction, see Mistral's Approvals (opens in a new tab) page.
What the agent gets back
The function returns the report as text, which is what a model reads best: the answer with [1] markers, then the Sources list. In your own code, GET /v1/research/{id} returns more. report.citations holds each cited sentence with its page, read time and passage, and report.sources lists every page read, cited or not.
Send "output": {"type": "json", "schema": {...}} to get JSON in the shape of your schema in place of text, length to choose short, standard or long, and include_domains or exclude_domains to choose the sites. The research docs list every field.
How spending stays under control
- One report has one fixed price for its depth. No report costs more than $1.00.
- The user approves the price. The agent's instructions make it name the price and wait for a yes before
research_report. - A repeated call buys nothing new. The function sends an
Idempotency-Keybuilt from the question, the depth and the hour, so the same question in the same hour returns the report it already started. - The charge comes at delivery. A report that fails or is cancelled costs nothing.
- The SpecStream key stays in your process. The model sees the function's name, its schema and its result, never the key.
- To keep deep reports out, remove
"deep"from theenuminagent.pyand from the depth check inspecstream_research.py.
If something doesn't work
| What you see | What to do |
|---|---|
The report is still in work | The report needs more than the 7 minutes one call waits. Ask the agent for it again in a minute. It calls read_research_report with the report ID. |
SpecStream answered 401 | The key is unknown, expired or revoked. Create a new key in your SpecStream workspace and set SPECSTREAM_API_KEY again. |
SpecStream answered 402, or the balance cannot pay for it | The balance does not hold the report's price. Add balance in your SpecStream workspace. A report that was already written is delivered on the next read. |
SpecStream answered 422 | A field is wrong, and the reply names it. The question holds up to 15,000 characters. |
SpecStream answered 429 | The account used its calls for the minute. Wait and ask again. Nothing is charged. |
KeyError: 'SPECSTREAM_API_KEY' | The key is not set in the shell that runs chat.py. Export it there, or pass --env-file .env to uv run on the Agents SDK. |
ImportError on mistralai.client | Your SDK is V1. Import Mistral and FunctionResultEntry from mistralai. |
| The agent starts a report without asking | The instructions were changed or left out. Create the agent again with the instructions from agent.py. |
Cost
A report costs $0.10 at quick, $0.30 at standard and $1.00 at deep, taken from your SpecStream balance once, when the report is delivered. Reading a report costs nothing. Mistral bills the model's tokens as it bills any conversation, and the report text counts as input tokens when your code returns it. The rates are on pricing.
Web search and page reading too
For one fact or the text of a page as a function tool, the Mistral API guide declares a search function on the same key. The Search API is $5 per 1,000 searches of up to 10 results and the Extract API $0.80 per 1,000 pages. Mistral also registers MCP servers as Connectors: the SpecStream server is at https://api.specstream.ai/mcp, and the MCP docs list its tools, research_price, start_research and get_research among them. The REST API reference lists every call on this page.
Remove
Delete the agent in Mistral, remove the three files, and revoke the key in your SpecStream workspace. Reports already delivered stay in your account. Questions: [email protected].
More
SpecStream for Mistral Agents API Research covers what it does in Mistral Agents API Research on one page. Every other tool has its guide in Connect your tools. You see the most a request can cost before it starts, and the matches are paid from your balance. Billing has the details. For help, email [email protected].