feat: add native Mistral AI provider support#541
feat: add native Mistral AI provider support#541edouard-claude wants to merge 2 commits intosipeed:mainfrom
Conversation
@edouard-claude Can you add logs that were generated during that chat in the description just to be sure? |
|
@edouard-claude does tool calling work with the HTTP provider? Following @harshbansal7 comment. Would like to see that or create a test ensuring tool calling work. |
|
Thanks @harshbansal7 @lukemilby for the great feedback! Your comments actually led me to discover a tool calling compatibility issue — Mistral's API is stricter than OpenAI's and rejects extra fields ( Here are the E2E logs with tool calling working: Simple chat: Tool call — read_file: Tool call — list_dir: Tool call — exec (shell): All 3 tool types (read_file, list_dir, exec) work correctly with |
96b1b63 to
5d7a85a
Compare
| Name string `json:"name,omitempty"` | ||
| Arguments map[string]any `json:"arguments,omitempty"` | ||
| Name string `json:"-"` | ||
| Arguments map[string]any `json:"-"` |
There was a problem hiding this comment.
This change hides Name and Arguments from JSON serialization, which could be a breaking change for downstream consumers. Could you share the reasoning behind this decision and whether it’s been tested with other setups outside Mistral?
There was a problem hiding this comment.
Good question! These two fields (Name and Arguments) are duplicates of Function.Name and Function.Arguments — they were populated internally after JSON parsing (see the deserialization logic in the provider code) but were never meant to be serialized back to the API.
The OpenAI spec only expects tool_calls[].function.name and tool_calls[].function.arguments — the top-level name/arguments fields don't exist in the spec. OpenAI silently ignores them, but Mistral's stricter validation returns a 422 error.
Since the data already lives in Function.Name/Function.Arguments (which remain serialized normally), removing the duplicates from JSON output doesn't change any behavior — it just stops sending fields that shouldn't be there.
Tested with: Mistral (mistral-small-latest) including tool calling (read_file, list_dir, exec). Other OpenAI-compatible providers are unaffected since they already ignore these extra fields.
|
Looks great, I was testing with new model_list and have 422 too on |
There was a problem hiding this comment.
This fix is already in main, perhaps we can keep the commits clean by rebasing?
There was a problem hiding this comment.
Done! Rebased on main and dropped the shell_test.go commit since it's already in main. Clean 2-commit history now.
Add Mistral as a first-class provider alongside the 17 existing ones. Mistral uses the OpenAI-compatible API at https://api.mistral.ai/v1 with provider-specific model prefix stripping (mistral/model → model). Changes: - Add Mistral to ProvidersConfig, IsEmpty(), HasProvidersConfig() - Add mistral entry in default model_list (defaults.go) - Add mistral protocol in factory_provider.go and getDefaultAPIBase() - Add mistral prefix stripping in openai_compat normalizeModel() - Add mistral case in legacy factory.go resolveProviderSelection() - Add mistral migration entry in ConvertProvidersToModelList() - Add mistral to supported providers in migrate/config.go - Add mistral section in config.example.json - Update AllProviders test (17 → 18 providers) Tested end-to-end with mistral-small-latest model.
Mistral's API strictly validates tool_calls in assistant messages and rejects non-standard fields. The ToolCall struct had Name and Arguments as top-level JSON fields, duplicating data already in Function.Name and Function.Arguments. OpenAI silently ignored these extras but Mistral returns 422. Change json tags to "-" so these internal fields are no longer serialized to API payloads while remaining available in Go code.
5d7a85a to
34a8ce5
Compare
|
This addresses the feature request in #246 (Add Mistral AI provider support). Linking for tracking. |
sipeed#541) This is a cleaner implementation than the previous attempt, adding Mistral as a first-class provider. Changes from PR sipeed#541: - Add Mistral to ProvidersConfig, IsEmpty(), HasProvidersConfig() - Add mistral entry in default model_list (defaults.go) - Add mistral protocol in factory_provider.go and getDefaultAPIBase() - Add mistral prefix stripping in openai_compat normalizeModel() - Add mistral case in legacy factory.go resolveProviderSelection() - Add mistral migration entry in ConvertProvidersToModelList() - Add mistral to supported providers in migrate/config.go - Add mistral section in config.example.json - Fix: remove extra fields from ToolCall JSON serialization (Mistral strict validation) Previously attempted changes (b42039f, 3555fbc) reverted in favor of this implementation.
…stream PR sipeed#198) Implements file and image support for chat channels, following pattern from nanobot implementation. Images are downloaded to local temp files, base64-encoded, and sent as multipart content to LLMs with vision capabilities. Changes: - Modified Message.Content from string to interface{} to support multipart content - Added buildUserContent() method for base64 encoding images - Updated all providers to handle multipart content - Added IsImageFile() and improved GetMimeType() utilities - Implemented image download in Discord, LINE, and Slack channels - Fixed critical bug where media paths weren't reaching LLM - Consolidated duplicate contentToString* functions - Proper file cleanup after base64 encoding Conflicts resolved to preserve: - Mistral provider support (PR sipeed#541) - ContextWindow/MaxTokens separation Note: PR sipeed#198 was made on an older upstream commit and required manual conflict resolution.
Summary
https://api.mistral.ai/v1with provider-specific model prefix strippingmodel_listformat and legacyprovidersconfig migrationname/argumentsfields fromtool_callsJSON serialization that Mistral's strict API rejects (OpenAI silently ignores them)Changes
pkg/config/config.go: AddMistral ProviderConfigtoProvidersConfig,IsEmpty(),HasProvidersConfig()pkg/config/defaults.go: Addmistral-smallentry in defaultmodel_listpkg/config/migration.go: Add mistral migration entry forConvertProvidersToModelList()pkg/config/migration_test.go: UpdateAllProviderstest (17 → 18)pkg/providers/factory_provider.go: Add"mistral"to OpenAI-compat protocol list +getDefaultAPIBase()pkg/providers/factory.go: Add"mistral"case in legacyresolveProviderSelection()pkg/providers/openai_compat/provider.go: Add"mistral"to prefix strip listpkg/providers/protocoltypes/types.go: FixToolCall.NameandToolCall.Argumentsserialization (json:"-") — these internal fields were incorrectly included in API payloads, causing 422 errors on strict APIs like Mistralpkg/migrate/config.go: Add"mistral"tosupportedProvidersconfig/config.example.json: Add mistral config sectionConfiguration
{ "model_list": [ { "model_name": "mistral-small", "model": "mistral/mistral-small-latest", "api_key": "YOUR_API_KEY", "api_base": "https://api.mistral.ai/v1" } ] }E2E Test Logs
Simple chat (model=mistral-small-latest):
Tool call — read_file:
Tool call — list_dir:
Tool call — exec (shell):
Test plan
go test ./...— 0 failures)gofmt,go vetcleanmistral-small-latest