OpenAI-compatible file inputs
mistral.rs supports OpenAI-compatible user file inputs on the server API and local SDKs:
POST /v1/filesmultipart uploads withpurpose="user_data".POST /v1/responsesinput_filecontent parts withfile_id,file_data, orfile_url.POST /v1/chat/completionsfilecontent parts withfile_idorfile_data.- Rust SDK
InputFileonRequestBuilder::with_input_file(...). - Python SDK
InputFileonChatCompletionRequest.input_files.
Use this when a request needs to analyze or transform user-provided files, or when a Responses shell/Skill workflow should see request files in the session working directory.
For field-level compatibility notes, see OpenAI compatibility. For wire schema and lifetime rules, see HTTP API file semantics.
File handling
Section titled “File handling”file_data is decoded before it reaches the model. Base64 is never placed in prompt context.
Uploaded, inline, URL-fetched, and SDK-provided files are visible through the server file endpoints:
Text-like UTF-8 files get:
- metadata in prompt context,
- a decoded preview of up to 4096 chars per file,
- a total preview budget of 32768 chars per request,
- access to additional text during agentic tool runs when the preview is not enough.
Binary or non-UTF-8 files get metadata only in prompt context. They are still stored, downloadable from GET /v1/files/{id}/content, and mounted into shell/code workdirs when those tools are active.
Extraction support is intentionally simple:
| File kind | Behavior |
|---|---|
| Text-like UTF-8 files | Text, CSV, JSON, XML, Markdown, YAML, TOML, HTML, source files, and other valid UTF-8 payloads are readable as text. |
| Binary or structured documents | PDFs, images, archives, spreadsheets, and other binary formats are stored and mounted, but mistral.rs does not extract OCR, PDF text, or spreadsheet summaries yet. |
Responses file_url fetches only http and https URLs, with a timeout, redirect cap, decoded-size cap, and basic local/private host rejection. Chat Completions does not support file URLs; upload the file first or use inline file_data.
Start a server:
mistralrs serve --agent -m <model>--agent is useful when you want file pagination, Python code execution, shell execution, or OpenAI-compatible Skills. Plain requests still receive text previews even without tool execution.
Related setup guides:
- Build an agent for the
--agentpreset. - Code execution and shell execution for workdir mounting behavior.
- OpenAI-compatible Skills for using request files alongside uploaded Skills.
- Agentic runtime for streaming progress, sessions, and file events.
Examples
Section titled “Examples”from openai import OpenAI
client = OpenAI(base_url="http://localhost:1234/v1", api_key="not-used")
with open("data.csv", "rb") as file: uploaded = client.files.create(file=file, purpose="user_data")
response = client.responses.create( model="default", input=[ { "role": "user", "content": [ {"type": "input_file", "file_id": uploaded.id}, {"type": "input_text", "text": "Summarize this CSV."}, ], } ],)
print(response.output_text)from mistralrs import Architecture, ChatCompletionRequest, InputFile, Runner, Which
runner = Runner( which=Which.Plain( model_id="Qwen/Qwen3-4B", arch=Architecture.Qwen3, ),)
sales = InputFile.from_text( "sales.csv", "region,revenue\nnorth,120\nsouth,95\nwest,180\n", "text/csv",)request = ChatCompletionRequest( messages=[ { "role": "user", "content": "Which region has the highest revenue? Use the attached CSV.", } ], model="default", input_files=[sales],)
response = runner.send_chat_completion_request(request)print(response.choices[0].message.content)use anyhow::Result;use mistralrs::{ InputFile, IsqBits, ModelBuilder, RequestBuilder, TextMessageRole, TextMessages,};
#[tokio::main]async fn main() -> Result<()> { let model = ModelBuilder::new("Qwen/Qwen3-4B") .with_auto_isq(IsqBits::Four) .build() .await?;
let sales = InputFile::from_text_with_mime( "sales.csv", "text/csv", "region,revenue\nnorth,120\nsouth,95\nwest,180\n", ); let messages = TextMessages::new().add_message( TextMessageRole::User, "Which region has the highest revenue? Use the attached CSV.", ); let request = RequestBuilder::from(messages).with_input_file(sales);
let response = model.send_chat_request(request).await?; println!( "{}", response.choices[0].message.content.as_deref().unwrap_or("") );
Ok(())}Full examples:
Other server shapes
Section titled “Other server shapes”Use inline Responses input_file when you do not want a separate upload:
import base64from openai import OpenAI
client = OpenAI(base_url="http://localhost:1234/v1", api_key="not-used")
with open("notes.md", "rb") as file: data = base64.b64encode(file.read()).decode("utf-8")
response = client.responses.create( model="default", input=[ { "role": "user", "content": [ { "type": "input_file", "filename": "notes.md", "file_data": f"data:text/markdown;base64,{data}", }, {"type": "input_text", "text": "Extract the action items."}, ], } ],)
print(response.output_text)Chat Completions uses type: "file" content parts:
import base64from openai import OpenAI
client = OpenAI(base_url="http://localhost:1234/v1", api_key="not-used")
with open("report.json", "rb") as file: data = base64.b64encode(file.read()).decode("utf-8")
completion = client.chat.completions.create( model="default", messages=[ { "role": "user", "content": [ { "type": "file", "file": { "filename": "report.json", "file_data": f"data:application/json;base64,{data}", }, }, {"type": "text", "text": "What are the main anomalies?"}, ], } ],)
print(completion.choices[0].message.content)