Support Mistral API endpoints
I tried to configure a custom provider to connect to the Mistral API like so:
{
"providers": {
"mistral": {
"name": "Mistral",
"base_url": "https://api.mistral.ai/v1/",
"type": "openai",
"api_key": "...",
"models": [
{
"name": "Devstral Medium",
"id": "devstral-medium-latest",
"context_window": 128000,
"default_max_tokens": 20000
}
]
}
}
}
However, when I end up with a 422 when the request is being made. Digging into the logs, here's an example request:
{"time":"2025-08-08T16:21:40.041695+02:00","level":"DEBUG","source":{"function":"github.com/charmbracelet/crush/internal/log.(*HTTPRoundTripLogger).RoundTrip","file":"/home/runner/work/crush/crush/internal/log/http.go","line":46},"msg":"HTTP Request","method":"POST","url":{"Scheme":"https","Opaque":"","User":null,"Host":"api.mistral.ai","Path":"/v1/chat/completions","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"","Fragment":"","RawFragment":""},"body":"{\"messages\":[{\"content\":\"you will generate a short title based on the first message a user begins a conversation with\\n\\n- ensure it is not more than 50 characters long\\n- the title should be a summary of the user's message\\n- it should be one line long\\n- do not use quotes or colons\\n- the entire text you return will be used as the title\\n- never return anything that is more than one sentence (one line) long\\n\",\"role\":\"system\"},{\"content\":\"Generate a concise title for the following content:\\n\\n`Please analyze this codebase and create a **CRUSH.md** file containing:\\n\\n- Build/lint/test commands - especially for running a single test\\n- Code style guidelines including imports, formatting, types, naming conventions, error handling, etc.\\n\\nThe file you create will be given to agentic coding agents (such as yourself) that operate in this repository. Make it about 20-30 lines long.\\nIf there's already a **CRUSH.md**, improve it.\\n\\nIf there are Cursor rules (in `.cursor/rules/` or `.cursorrules`) or Copilot rules (in `.github/copilot-instructions.md`), make sure to include them.\\nAdd the `.crush` directory to the `.gitignore` file if it's not already there.\\n\",\"role\":\"user\"}],\"model\":\"devstral-medium-latest\",\"max_tokens\":20000,\"stream_options\":{\"include_usage\":true},\"stream\":true}"}
And this is the error I get:
{"time":"2025-08-08T16:21:40.195155+02:00","level":"DEBUG","source":{"function":"github.com/charmbracelet/crush/internal/log.(*HTTPRoundTripLogger).RoundTrip","file":"/home/runner/work/crush/crush/internal/log/http.go","line":68},"msg":"HTTP Response","status_code":422,"status":"422 Unprocessable Entity","headers":{"Access-Control-Allow-Origin":["*"],"Alt-Svc":["h3=\":443\"; ma=86400"],"Cf-Cache-Status":["DYNAMIC"],"Cf-Ray":["96bfa9559e31085c-FRA"],"Content-Length":["224"],"Content-Type":["application/json"],"Date":["Fri, 08 Aug 2025 14:21:40 GMT"],"Mistral-Correlation-Id":["01988a0f-119a-7eac-80cb-e608f2264854"],"Server":["cloudflare"],"Set-Cookie":["__cf_bm=922.okTGThgZn6EE11Oj4g05wI9GrzTpyOpfRB3nfO0-1754662900-1.0.1.1-WaDFfZ2lp0TCq88WIMAc6rE.wr_khUR5TWZ4kY4JifiZ_LMzqS1gsD_g3pd48TOicDSiNALfawnHN1kM6bITSTG.K3CCtr14DONF_smUxl8; path=/; expires=Fri, 08-Aug-25 14:51:40 GMT; domain=.mistral.ai; HttpOnly; Secure; SameSite=None","_cfuvid=ZG5l0SQAontyjfB84i6fCi2v6C.CyFH3n_6aKiRCrB4-1754662900182-0.0.1.1-604800000; path=/; domain=.mistral.ai; HttpOnly; Secure; SameSite=None"],"Strict-Transport-Security":["max-age=15552000; includeSubDomains"],"X-Envoy-Upstream-Service-Time":["28"],"X-Kong-Proxy-Latency":["7"],"X-Kong-Request-Id":["01988a0f-119a-7eac-80cb-e608f2264854"],"X-Kong-Upstream-Latency":["29"]},"body":"{\"object\":\"error\",\"message\":{\"detail\":[{\"type\":\"extra_forbidden\",\"loc\":[\"body\",\"stream_options\",\"include_usage\"],\"msg\":\"Extra inputs are not permitted\",\"input\":true}]},\"type\":\"invalid_request_error\",\"param\":null,\"code\":null}","content_length":224,"duration_ms":153,"error":null}
It seems to me that the stream_options part of the request is not accepted.
Is there a way for me to test this some more apart from actually doing this in the code or am I maybe doing something wrong in some other place?
The API docs also don't include stream_options, so it seems to make sense.
Yeah, thatβs the only thing holding me back from giving this tool a try. Kinda disappointing.
Hey all, I was just able to successfully use this with my own API Key today:
β Hi!
Hello! How can I assist you today?
β Devstral Medium 3s βββββββββββββ
Could you give it another try? (I'm running on HEAD of main for what its worth)
It didn't work for me on Crush v0.13.7.
I just tried Crush v0.18.1, and it seems to work now.
@ujh: Have you tried the latest stable Crush with your setting?
If it works now, then this issue is no longer relevant and can be closed.
tested with crush 0.18.6, it works, but somewhat buggy.
Often after prompting there is no response. Then can prompt a few more times, with different words, or different questions, and it comes back with answer for all the previous promts too.
Switching back from 0.18.6 to 0.18.1, I'm seeing the same behavior as @ckjoris . I'm going to see if I have any time over the holiday weekend (like 50/50 chance) and see if I can figure something out.