Codestral API in Python
On this page
Calling Codestral from Python
This lesson moves from theory to executable code. You will use the Mistral AI Python SDK to query Codestral on its two endpoints, tune the advanced parameters that separate a useful suggestion from a verbose one, and implement the patterns found in most real-world integrations.
Installation and configuration
Install the SDK with a single command:
pip install mistralai
Retrieve your API key from console.mistral.ai and read it from the environment rather than hard-coding it into your file:
import os
from mistralai.client import Mistral
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
Two platforms serve Codestral, and you choose between them when creating your key. api.mistral.ai operates on a pay-per-use basis with usage-based billing: this is the standard path when Codestral is one component among many in an application. codestral.mistral.ai is a dedicated endpoint, accessible for free or via subscription, designed for direct use by a developer within their editor.
Complete FIM call
Here is a detailed FIM call with all the important parameters:
from mistralai.client import Mistral
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
response = client.fim.complete(
model="codestral-latest",
prompt="def calculate_vat(price_excl: float, rate: float = 0.20) -> float:",
suffix="price = float(input('Price excl. VAT: '))\nprint(f'Price incl. VAT: {calculate_vat(price):.2f} EUR')",
temperature=0,
max_tokens=150,
stop=["\n\n"],
)
completion = response.choices[0].message.content
print(completion)
Breaking down the response
The returned object contains more than just the generated text. In production, you should systematically check three pieces of information: the completion itself, the token consumption that determines your bill, and the stop reason, which tells you whether the model finished naturally or hit your limit.
# Access the generated completion
text = response.choices[0].message.content
# Check the number of tokens used
tokens_prompt = response.usage.prompt_tokens
tokens_completion = response.usage.completion_tokens
tokens_total = response.usage.total_tokens
# Check the stop reason
reason = response.choices[0].finish_reason # "stop", "length", etc.
A finish_reason of "length" on half your calls is a clear signal: your max_tokens is too low, and you are delivering truncated code to your users.
Chat call for code generation
Whenever there is no cursor in the middle of a file—such as for full generation, explanation, or refactoring—the chat endpoint takes over. The system message then frames the output format, which avoids the need to clean up the response afterward:
response = client.chat.complete(
model="codestral-latest",
messages=[
{
"role": "system",
"content": "You are an expert Python development assistant. Respond with code only, no explanations."
},
{
"role": "user",
"content": "Write a Python function that validates an email address using regex."
}
],
temperature=0.2,
max_tokens=500,
)
code = response.choices[0].message.content
print(code)
Advanced parameters
The min_tokens / max_tokens pair frames the output length. The floor is useful when generating a block that you know cannot be shorter than a certain volume, such as a function with its error handling.
# min_tokens: forces a minimum output length
# max_tokens: limits the maximum length
response = client.fim.complete(
model="codestral-latest",
prompt=prompt,
suffix=suffix,
min_tokens=20,
max_tokens=300,
)
Stop tokens play a different role: they halt generation on a specific pattern, keeping the completion within the scope of the current function instead of letting the model chain into the next one.
# Stop generation on specific patterns
response = client.fim.complete(
model="codestral-latest",
prompt=prompt,
suffix=suffix,
stop=["\n\n", "\nclass ", "\ndef "], # Stop before a new function/class
)
Finally, temperature governs variability. At 0, the same input always yields the same output, which auto-completion requires. Around 0.3, the model proposes variants, which is interesting when displaying multiple suggestions. At 0.7, you are in code brainstorming mode, useful for exploring an approach but unsuited for an editing flow.
# temperature=0: deterministic (auto-completion)
# temperature=0.3: slightly creative (multiple suggestions)
# temperature=0.7: creative (code brainstorming)
response = client.fim.complete(
model="codestral-latest",
prompt=prompt,
suffix=suffix,
temperature=0.3,
top_p=0.95,
)
Two patterns to copy-paste
The first reproduces IDE behavior: you split the file content at the cursor position, and the two halves become the prompt and suffix.
def autocomplete_ide(file_content: str, cursor_position: int) -> str:
"""Simulates IDE auto-completion with Codestral FIM."""
prompt = file_content[:cursor_position]
suffix = file_content[cursor_position:]
response = client.fim.complete(
model="codestral-latest",
prompt=prompt,
suffix=suffix,
temperature=0,
max_tokens=100,
stop=["\n\n", "\ndef ", "\nclass "],
)
return response.choices[0].message.content
The second automates documentation for an existing project: you pass in a function, retrieve its docstring, and the system instruction enforces a single format so the result inserts without further editing.
def generate_docstring(function_code: str) -> str:
"""Generates a docstring for a Python function."""
response = client.chat.complete(
model="codestral-latest",
messages=[
{
"role": "system",
"content": "Generate a Google-style docstring for the following function. Return ONLY the docstring between triple quotes."
},
{
"role": "user",
"content": function_code
}
],
temperature=0,
max_tokens=300,
)
return response.choices[0].message.content
Error handling
A network call will fail sooner or later, and an editor extension that crashes on a validation error is worse than an extension with no completion. Therefore, always wrap your calls:
from mistralai.client import Mistral
from mistralai.client.errors import HTTPValidationError
try:
response = client.fim.complete(
model="codestral-latest",
prompt=prompt,
suffix=suffix,
)
except HTTPValidationError as e:
print(f"Validation error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
Key takeaways
- The
mistralaiSDK exposesclient.fim.complete()for FIM andclient.chat.complete()for chat - The
promptandsuffixparameters are specific to the FIM endpoint - Use
temperature=0for auto-completion,0.2-0.7for creative generation stoplimits generation to a coherent code blockmin_tokensandmax_tokenscontrol output length- Always handle HTTP errors in production code