Repository navigation
feat(models): add Mistral AI as a native LLM provider - #2406
Conversation
c5a96c8 to
75c7a22
Compare
|
First off, thanks so much for the PR :) If the wire protocol is the same as OpenAI I'm wondering if we really need a whole new API block for this? Typically we allow usage of chat completions compatible APIs via BaseURL. I definitely see value in adding a mistral block to the UI and website, so it's clearer there that Mistral is supported, but I'm not sure it's worth adding the block to the API. What do you think? |
Hi. Yes it's just a proposition. Yes Mistral is openai compatible so it does the job like that (I already did a video to show Mistral Inference with kagent). We can close the PR no worries. |
So actually, after some more thought we realized that it's valuable to have more options in the API, so we'd love to have your contribution. |
Adds Mistral AI as a first-class provider across the v1alpha3 CRD, the v2 translator, the Go and Python ADK runtimes, the UI, and Helm. Mistral speaks the OpenAI-compatible wire protocol, so the runtime reuses the OpenAI SDK client internally with a Mistral base URL and MISTRAL_API_KEY env var — no new HTTP transport, no new SDK dependency. New surfaces: - v1alpha3 CRD: Mistral enum + MistralConfig (baseUrl, temperature, topP, maxTokens, timeout) + CEL rule + default endpoint https://api.mistral.ai/v1 - v2 translator (go/core/v2/translator/kagent/model.go): injects MISTRAL_API_KEY from Secret and translates MistralConfig → adk.Mistral - Go ADK: adk.Mistral type + models.MistralModel (wraps OpenAIModel) - Python ADK: KAgentMistralLlm subclassing BaseOpenAI + ModelUnion entry + branch in _create_llm_from_model_config - Env vars: MISTRAL_API_KEY, MISTRAL_API_BASE - Model catalog (service/model/discovery.go): 10 Mistral models (mistral/magistral/codestral/ministral/pixtral/nemo latest tags) - UI: Mistral entry in providerInfo.ts + inline SVG icon in ProviderIcon.tsx - Helm values: providers.mistral entry (default provider unchanged) - Docs: helm/README.md install example - Tests: Go unit tests (CreateLLM_Mistral, mistral_test.go), CEL admission tests (4 cases in v1alpha3), Python unit tests (10 cases in test_mistral.py), discovery/grpc tests updated for 11-provider count Rebased onto current main after upstream refactors: - PR kagent-dev#2565 removed the legacy controller/translator stack, so translator changes now live in the v2 translator (go/core/v2/translator/kagent/model.go) rather than the deleted go/core/internal/controller/translator. - PR kagent-dev#2569 rewrote the UI on Vite; provider icon + metadata wiring now lives in ui/src/components/model-form/ rather than the deleted lib/providers.ts and combobox files. - All work targets v1alpha3 (current storage version) rather than v1alpha2 (legacy served version) per AGENTS.md. Signed-off-by: Xavier Pestel <xavier.pestel@mistral.ai>
04b8231 to
afdff3e
Compare
|
Rebased onto current What movedTwo upstream refactors landed between the original PR and today, so the rebase is not a small merge — most of the touched files on
What was dropped, with reason
Also added on top of the original PR
Verification
Not in this PRSame as before — embeddings and a native streaming e2e are still separate follow-ups. |
There was a problem hiding this comment.
Can we backout this file? I'm not against adding support for this, but I've never heard of this specific project and I'd rather discuss that separately so we can get this in
|
This pull request has been marked as stale because of no activity in the last 15 days. It will be closed in the next 5 days unless it is tagged "no stalebot" or other activity occurs. |
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
|
This pull request has been closed after 15 days of inactivity and an additional 5 days after being marked as stale. |
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
…3008) kagent-dev#2406 added mistral to the modelconfig enum and the adk renderer, but the v1alpha3 resolver still rejects it as an unsupported provider. so any agent that uses a mistral model fails to compile. this pr lets the resolver accept mistral, sends `MISTRAL_API_KEY` as a bearer token to `api.mistral.ai` (or to the baseUrl if set), and allows that host in agent egress. each of the three parts has a new test that fails without this change. Signed-off-by: moezdil <mesudozdil@gmail.com> Signed-off-by: mesutoezdil <mesudozdil@gmail.com>
## Summary Adds Mistral AI as a first-class LLM provider across the Go controller, Go ADK runtime, Python ADK runtime, and UI. Mistral speaks the OpenAI-compatible wire protocol (POST `/chat/completions` with a Bearer token at `https://api.mistral.ai/v1`), so both runtimes reuse the OpenAI SDK client internally — no new HTTP transport, no new SDK dependency. ## Changes **CRD (v1alpha2)** - New `Mistral` provider enum value + `MistralConfig` struct (`baseUrl`, `temperature`, `topP`, `maxTokens`, `timeout`) - CEL rule enforcing `mistral` is nil for non-Mistral providers - Default endpoint `https://api.mistral.ai/v1` - Regenerated `zz_generated.deepcopy.go` and CRD manifests in both `go/api/config/crd/bases/` and `helm/kagent-crds/templates/` **Controller translator** - New `Mistral` case in `translateModel()` — injects `MISTRAL_API_KEY` from Secret into the agent pod **Go ADK runtime** - New `adk.Mistral` type + `models.MistralModel` (wraps `OpenAIModel` internally) - Wired into `CreateLLM()` in `go/adk/pkg/agent/agent.go` **Python ADK runtime** - New `KAgentMistralLlm` class subclassing `BaseOpenAI` (hardcodes Mistral base URL + `MISTRAL_API_KEY` env fallback) - Registered in the `ModelUnion` Pydantic discriminator **Env vars, telemetry, catalog** - `MISTRAL_API_KEY`, `MISTRAL_API_BASE` - OpenTelemetry GenAI semconv: `gen_ai.provider.name=mistral_ai` - 10 Mistral models in the HTTP model catalog: `mistral-large-latest`, `mistral-medium-latest`, `mistral-small-latest`, `magistral-medium-latest`, `magistral-small-latest`, `codestral-latest`, `ministral-8b-latest`, `ministral-3b-latest`, `pixtral-large-latest`, `open-mistral-nemo` (all with function calling) **UI** - `Mistral` added to `BackendModelProviderType`, `modelProviders`, `PROVIDERS_INFO` - New Mistral SVG icon (`ui/src/components/icons/Mistral.tsx`) - Icon wired into both `ModelProviderCombobox` and `ProviderCombobox` icon maps **Helm** - `providers.mistral` entry in `values.yaml`. Default provider unchanged. **Docs** - New Mistral section in `.claude/skills/kagent/references/providers.md` (Helm keys, env vars, CLI examples, ModelConfig YAML) ## Example ModelConfig ```yaml apiVersion: kagent.dev/v1alpha2 kind: ModelConfig metadata: name: mistral-large namespace: kagent spec: provider: Mistral model: mistral-large-latest apiKeySecret: kagent-mistral apiKeySecretKey: MISTRAL_API_KEY mistral: temperature: "0.3" maxTokens: 4096 # baseUrl: https://api.mistral.ai/v1 # optional ``` Set `MISTRAL_API_BASE` to point at a self-hosted or regional Mistral endpoint. ## Testing All test suites green (evidence): | Suite | Result | |---|---| | `go/api` unit tests | **121 passed** — includes 4 new CEL admission cases for Mistral | | `go/adk` unit tests | **539 passed** — includes new `TestNewMistralModelWithLogger` (7 cases) + `TestMistralModel_NamePropagatesModelNotProvider` | | `go/core` unit tests (non-e2e) | **1504 passed** — includes new `TestGoldenAdkTranslator/mistral_agent` golden test | | `TestCreateLLMConfig_Mistral` (agent_test.go) | ✅ passes | | Python `test_mistral.py` | **10 passed** | | Python `test_mistral.py` + `test_openai.py` + `test_anthropic.py` | **47 passed** | | E2E `TestE2EInvokeWithMistralAgent` | Compiles + skips cleanly when `MISTRAL_API_KEY` unset (verified). Modeled on `foundry_test.go`, uses a mock OpenAI-compatible server — never contacts the real Mistral API | | `make -C go generate` + `make -C go manifests` + `make controller-manifests` | ✅ regenerated CRDs | | UI `npx tsc --noEmit` | ✅ no new TypeScript errors (fixed 2 real "Property 'Mistral' is missing" errors caught in the combobox icon maps by wiring the new icon) | | `go vet ./...` | ✅ clean across the workspace | | Local secret scan (gitleaks) | ✅ clean, both staged + branch diff | ## Pre-existing issues observed (not fixed here) - `golangci-lint` fails to load `bin/kube-api-linter.so` due to a Go runtime version drift in the vendored plugin. Unrelated to this PR (`go vet` is clean). - 9 Python `test_tls_e2e.py` failures exist on `main` (verified via `git stash` + rerun). Unrelated to Mistral. ## Not in this PR - **Embeddings**: The Python `EmbeddingConfig` type does not discriminate on provider the same way `Model` does. Mistral embeddings (`mistral-embed`) is a straightforward follow-up but is not scoped here. - **Mistral-specific streaming e2e**: Streaming works because the inner OpenAI client handles it; a real streaming e2e against Mistral can be added when a stable mock harness lands. Type: `feat` (Conventional Commits). Signed-off-by: Xavier Pestel <xavier.pestel@mistral.ai> Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io> Co-authored-by: Eitan Yarmush <eitan.yarmush@solo.io>
…3008) kagent-dev#2406 added mistral to the modelconfig enum and the adk renderer, but the v1alpha3 resolver still rejects it as an unsupported provider. so any agent that uses a mistral model fails to compile. this pr lets the resolver accept mistral, sends `MISTRAL_API_KEY` as a bearer token to `api.mistral.ai` (or to the baseUrl if set), and allows that host in agent egress. each of the three parts has a new test that fails without this change. Signed-off-by: moezdil <mesudozdil@gmail.com> Signed-off-by: mesutoezdil <mesudozdil@gmail.com>
Summary
Adds Mistral AI as a first-class LLM provider across the Go controller, Go ADK runtime, Python ADK runtime, and UI. Mistral speaks the OpenAI-compatible wire protocol (POST
/chat/completionswith a Bearer token athttps://api.mistral.ai/v1), so both runtimes reuse the OpenAI SDK client internally — no new HTTP transport, no new SDK dependency.Changes
CRD (v1alpha2)
Mistralprovider enum value +MistralConfigstruct (baseUrl,temperature,topP,maxTokens,timeout)mistralis nil for non-Mistral providershttps://api.mistral.ai/v1zz_generated.deepcopy.goand CRD manifests in bothgo/api/config/crd/bases/andhelm/kagent-crds/templates/Controller translator
Mistralcase intranslateModel()— injectsMISTRAL_API_KEYfrom Secret into the agent podGo ADK runtime
adk.Mistraltype +models.MistralModel(wrapsOpenAIModelinternally)CreateLLM()ingo/adk/pkg/agent/agent.goPython ADK runtime
KAgentMistralLlmclass subclassingBaseOpenAI(hardcodes Mistral base URL +MISTRAL_API_KEYenv fallback)ModelUnionPydantic discriminatorEnv vars, telemetry, catalog
MISTRAL_API_KEY,MISTRAL_API_BASEgen_ai.provider.name=mistral_aimistral-large-latest,mistral-medium-latest,mistral-small-latest,magistral-medium-latest,magistral-small-latest,codestral-latest,ministral-8b-latest,ministral-3b-latest,pixtral-large-latest,open-mistral-nemo(all with function calling)UI
Mistraladded toBackendModelProviderType,modelProviders,PROVIDERS_INFOui/src/components/icons/Mistral.tsx)ModelProviderComboboxandProviderComboboxicon mapsHelm
providers.mistralentry invalues.yaml. Default provider unchanged.Docs
.claude/skills/kagent/references/providers.md(Helm keys, env vars, CLI examples, ModelConfig YAML)Example ModelConfig
Set
MISTRAL_API_BASEto point at a self-hosted or regional Mistral endpoint.Testing
All test suites green (evidence):
go/apiunit testsgo/adkunit testsTestNewMistralModelWithLogger(7 cases) +TestMistralModel_NamePropagatesModelNotProvidergo/coreunit tests (non-e2e)TestGoldenAdkTranslator/mistral_agentgolden testTestCreateLLMConfig_Mistral(agent_test.go)test_mistral.pytest_mistral.py+test_openai.py+test_anthropic.pyTestE2EInvokeWithMistralAgentMISTRAL_API_KEYunset (verified). Modeled onfoundry_test.go, uses a mock OpenAI-compatible server — never contacts the real Mistral APImake -C go generate+make -C go manifests+make controller-manifestsnpx tsc --noEmitgo vet ./...Pre-existing issues observed (not fixed here)
golangci-lintfails to loadbin/kube-api-linter.sodue to a Go runtime version drift in the vendored plugin. Unrelated to this PR (go vetis clean).test_tls_e2e.pyfailures exist onmain(verified viagit stash+ rerun). Unrelated to Mistral.Not in this PR
EmbeddingConfigtype does not discriminate on provider the same wayModeldoes. Mistral embeddings (mistral-embed) is a straightforward follow-up but is not scoped here.Type:
feat(Conventional Commits).