## Issue
`MistralAiChatModel.doChat()` accesses
`mistralAiResponse.getChoices().get(0)` without checking whether
`choices` is null or empty. When the Mistral AI API (or an
OpenAI-compatible server fronted by it, e.g. vLLM/llama.cpp/Ollama in
OpenAI mode) returns a response with no choices — content filtering,
quota or rate-limit errors, malformed responses — this throws a cryptic
`IndexOutOfBoundsException` (empty list) or `NullPointerException`
(null) instead of a clear failure.
This is the same class of issue reported for `OpenAiChatModel` in #4810,
and complements the `content: null` null-guard recently added to
`MistralAiMapper.aiMessageFrom` in #5123. That guard covers *non-empty*
choices whose `message.content` is null; this PR covers the orthogonal
case of *empty/null* choices themselves. No existing issue covers the
empty-choices case for the MistralAI integration.
## Change
`MistralAiChatModel.doChat()` now checks
`isNullOrEmpty(mistralAiResponse.getChoices())` before the choices are
consumed and throws a descriptive `IllegalArgumentException`, mirroring
the guard already applied in `OpenAiChatModel` (see #4810):
```java
if (isNullOrEmpty(mistralAiResponse.getChoices())) {
throw new IllegalArgumentException("Mistral AI response has no choices");
}
```
`isNullOrEmpty` is the same helper already imported across the codebase.
No public API or behaviour change for well-formed responses; only the
previously-crashing path now throws a clear exception instead.
## Tests
Added `MistralAiChatModelEmptyChoicesTest`, mirroring the existing
`MistralAiChatModelToolCallsTest` /
`MistralAiChatModelReturnThinkingTest` style (uses `MockHttpClient`, no
API key required). Covers:
1.
`should_throw_IllegalArgumentException_when_response_has_empty_choices`
— empty `choices: []` list → `IllegalArgumentException` (previously
`IndexOutOfBoundsException`).
2.
`should_throw_IllegalArgumentException_when_response_has_null_choices` —
`choices` absent (deserializes to `null`) → `IllegalArgumentException`
(previously `NullPointerException`).
3. `should_return_chat_response_when_response_has_choices` — regression
guard: a well-formed single-choice response is still parsed correctly.
## General checklist
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
`mvn -pl langchain4j-mistral-ai -am test
-Dtest=MistralAiChatModelEmptyChoicesTest
-Dsurefire.failIfNoSpecifiedTests=false` → `Tests run: 3, Failures: 0,
Errors: 0, Skipped: 0`, BUILD SUCCESS.
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
Mistral returns the failure detail of a batch result line either as a JSON
object or as a bare JSON string. The latter made Jackson fail with
MismatchedInputException while parsing the output/error file, so a single
failed item broke the whole retrieve() call. The error is now normalized
into a map on deserialization, keeping the field type unchanged.
## Issue
Closes#5851
## Change
Mistral's provider-specific options (`safePrompt`, `randomSeed`,
`sendThinking`, `returnThinking`) were settable only at build time and
could not be varied per request. This adds
`MistralAiChatRequestParameters extends DefaultChatRequestParameters` so
they can be overridden per `ChatRequest`, on both `MistralAiChatModel`
and `MistralAiStreamingChatModel`.
```java
model.chat(ChatRequest.builder()
.messages(UserMessage.from("What is the best French cheese?"))
.parameters(MistralAiChatRequestParameters.builder()
.safePrompt(true)
.randomSeed(42)
.build())
.build());
```
- Backward compatible: the model builder options keep working and now
populate the default parameters.
- `strictJsonSchema` remains a model-level setting.
- `defaultRequestParameters()` return type is narrowed to
`MistralAiChatRequestParameters` (source- and binary-compatible; two
`revapi.json` entries added).
Tests: `MistralAiChatRequestParametersTest` (build, `EMPTY`,
`overrideWith`/`defaultedBy`, `toBuilder`, `equals`/`hashCode` incl.
cross-type) and `MistralAiChatModelParametersTest` /
`MistralAiStreamingChatModelParametersTest` (per-request options reach
the request body and override the model defaults, for both models). Docs
updated in `docs/docs/integrations/language-models/mistral-ai.md`.
## General checklist
- [x] There are no breaking changes (API, behaviour)
- [x] I have added unit and/or integration tests for my change
- [x] The tests cover both positive and negative cases
- [x] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [x] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
- [x] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
## Issue
Progresses #3916
## Change
Adds `MistralAiBatchChatModel`, an implementation of the core
`BatchChatModel` interface for the
[Mistral Batch API](https://docs.mistral.ai/capabilities/batch/), which
processes many chat requests
asynchronously at 50% of the standard per-token price. It follows the
existing
`GoogleAiGeminiBatchChatModel`, so both providers expose the same
`submit` / `retrieve` / `cancel` /
`list` surface.
Each `ChatRequest` is built through the same path `MistralAiChatModel`
uses (`createMistralAiRequest`),
so per-request parameters (temperature, tools, response format, etc.)
behave identically in a batch and
in a single call. Requests are submitted inline, so no separate file
upload is needed; once a job
completes, its results are downloaded from the `output_file` /
`error_file` and re-sorted back to
submission order using generated `custom_id`s. Mistral's job statuses
map onto the core `BatchState`:
| Mistral status | `BatchState` |
|---|---|
| `QUEUED` | `PENDING` |
| `RUNNING`, `CANCELLATION_REQUESTED` | `RUNNING` |
| `SUCCESS` | `SUCCEEDED` |
| `FAILED` | `FAILED` |
| `TIMEOUT_EXCEEDED` | `EXPIRED` |
| `CANCELLED` | `CANCELLED` |
The batch operations (create / retrieve / cancel / list jobs, and
downloading a result file) are added
to the existing hand-rolled `MistralAiClient`. They are non-abstract
methods that throw
`UnsupportedFeatureException` by default, so existing `MistralAiClient`
implementations keep compiling
and are unaffected. No new dependency is introduced.
Scope:
- Chat requests only.
- One model per job (a Mistral constraint): the model configured on the
batch model applies to every
request in the batch.
- Inline submission (the documented path for batches under 10,000
requests); the file-upload submission
path is not included.
Verified with unit tests against a mock HTTP server custom-id ordering,
success/error mapping,
`output_file` + `error_file` merge, the running-state short-circuit (no
results fetched until the job
produces them), status-code failures, and pagination and with a
key-gated integration test
(`MistralAiBatchChatModelIT`) run end-to-end against the live Batch API
(submit → poll to completion →
read results, plus cancel and list).
## General checklist
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the core
and main modules, and they are all green
- [X] I have added/updated the documentation
- [ ] I have added an example in the examples repo (only for "big"
features)
- [ ] I have added/updated Spring Boot starter(s) (if applicable)
---------
Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>
## Issue
Closes#5116
## Change
Adds a new **`onUnmappedRawEvent`** streaming callback that gives
advanced users access to provider streaming events that LangChain4j does
**not** map to one of its typed callbacks — e.g. OpenAI server-tool
lifecycle events (`response.web_search_call.in_progress` / `searching` /
`completed`). This is an escape hatch so power users don't have to fall
back to a provider's native SDK for events we don't model yet.
**API** (both `@Experimental`, `@since 1.17.0`, `default` so nothing
breaks):
- `StreamingChatResponseHandler.onUnmappedRawEvent(Object rawEvent)` —
low-level API
- `TokenStream.onUnmappedRawEvent(Consumer<Object> rawEventHandler)` —
AI Services API
**Semantics — no duplication.** The callback fires **only** for events
that were *not* already delivered via a typed callback
(`onPartialResponse`, `onPartialThinking`, `onPartialToolCall`,
`onCompleteToolCall`, `onCompleteResponse`). So you can consume the
typed callbacks and the raw stream together without seeing the same
event twice. This is enforced by a small internal
`MappingTrackingStreamingChatResponseHandler` that records whether an
event was mapped to a typed callback (`wasMapped()`), and providers emit
the raw event only when it wasn't.
> Naming note: it's called `onUnmappedRawEvent` (not `onRawEvent`) to
leave room for a planned follow-up that also exposes the raw event
behind *mapped* callbacks (e.g. `PartialToolCall.rawEvent()`), giving a
clean mapped/unmapped split.
**The concrete `rawEvent` type is provider-specific:**
| Provider | Raw event type |
|---|---|
| OpenAI, Anthropic, Google AI Gemini, Mistral, Ollama |
`dev.langchain4j.http.client.sse.ServerSentEvent` |
| OpenAI (official) – Responses API |
`com.openai.models.responses.ResponseStreamEvent` |
| OpenAI (official) – Chat Completions API |
`com.openai.models.chat.completions.ChatCompletionChunk` |
| Amazon Bedrock |
`software.amazon.awssdk.services.bedrockruntime.model.ConverseStreamOutput`
|
| Google GenAI | `com.google.genai.types.GenerateContentResponse` |
**Providers wired:** OpenAI (Chat Completions + Responses),
OpenAI-official (Chat Completions + Responses), Anthropic, Google AI
Gemini, Google GenAI, Amazon Bedrock, Mistral, Ollama.
**Docs:** added a "Unmapped Raw Events" section to
`response-streaming.md` and the callback to the `TokenStream` example in
`ai-services.md`.
## General checklist
- [x] There are no breaking changes (API, behaviour) — all additions are
`default` and `@Experimental`
- [x] I have added unit and/or integration tests for my change
- [x] The tests cover both positive and negative cases — i.e. unmapped
events are forwarded *and* typed (text/tool) events are **not** repeated
as raw events
- [x] I have manually run all the unit and integration tests in the
module(s) I have added/changed, and they are all green
- [x] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
- [x] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
## Issue
Closes#5582
## Change
`MistralAiStreamingChatModel.doChat()` passed the literal `false` for
the `strict` flag and the builder had no setter, so strict JSON schema
was always disabled for the streaming model, unlike the synchronous
`MistralAiChatModel`. This is an incomplete fix from PR #4603, which
wired the option into the synchronous model only.
This mirrors the synchronous model: a `strictJsonSchema` field
initialized via `getOrDefault(builder.strictJsonSchema, false)`, a
builder field and setter, and the field passed to
`createMistralAiRequest` instead of the hardcoded `false`.
```java
MistralAiChatCompletionRequest request =
createMistralAiRequest(chatRequest, safePrompt, randomSeed, true, sendThinking, strictJsonSchema);
```
The default stays `false`, so existing callers are unaffected.
Added `MistralAiStreamingChatModelStrictJsonSchemaTest`
(`MockHttpClient`, no API key): a positive test asserts the request body
contains `"strict":true` when `strictJsonSchema(true)` is set, and a
regression test asserts `"strict":false` when it is not.
## General checklist
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
Spotless: jgit ratchet fails inside the worktree ("Cannot find git
repository"), so the two changed files were copied to the main checkout
and `spotless:check -pl langchain4j-mistral-ai` was run there (0 files
needed changes, both already clean); the temporary copies were then
reverted.
## Issue
Closes#5580
## Change
`MistralAiFimServerSentEventListener.onEvent()` iterated the content
delta with an enhanced-for loop and no null check. Mistral streams
normal SSE deltas with no `content` field (for example the
`finish_reason` / metadata-only chunk), so
`choice.getDelta().getContent()` is `null` and the loop throws
`NullPointerException`.
This wraps the loop in `if (isNotNullOrEmpty(chunks))`, mirroring the
existing guard in the chat streaming listener
`MistralAiServerSentEventListener` (line 107). `isNotNullOrEmpty` was
already statically imported, so there are no new imports or
dependencies.
Added `MistralAiStreamingFimModelTest` using `MockHttpClient` to inject
SSE without an API key: a negative case feeds a content-less
`finish_reason` delta (NPE before the fix, passes after) and a positive
case asserts text is streamed and concatenated.
This completes PR #5123, which fixed the chat paths but left the FIM
streaming path unguarded.
## General checklist
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [X] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
<!--
Thank you so much for your contribution!
Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.
Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->
## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes#5121.
## Change
<!-- Please describe the changes you made. -->
Minimal, behavior-preserving null-guard in
`MistralAiMapper.aiMessageFrom`. OpenAI-compatible servers (vLLM,
llama.cpp, …) return `content: null` on assistant messages that carry
only `tool_calls`. The current mapper unconditionally calls `.stream()`
on `aiMistralMessage.getContent()`, which NPEs on this spec-compliant
payload.
The fix treats null content as an empty list — both the `text` and
`thinking` extraction streams now operate on the local reference:
```java
List<MistralAiMessageContent> contents = aiMistralMessage.getContent();
if (contents == null) {
contents = List.of();
}
```
No public API or behaviour change for callers: `text` is still `""` when
there is no text content, `thinking` stays `null` when no thinking
content. No new dependencies. Spotless applied.
Adds `MistralAiChatModelToolCallsTest` mirroring
`MistralAiChatModelReturnThinkingTest` (uses `MockHttpClient`), with
three scenarios:
1. `should_handle_response_with_only_tool_calls_and_null_content` — the
regression case (vLLM-style payload, captured byte-for-byte from a real
production response).
2. `should_handle_response_with_both_text_content_and_tool_calls` —
sanity, both fields present.
3. `should_handle_response_with_text_only_and_no_tool_calls` — ensures
the null-guard doesn't disturb the existing text-only path.
## General checklist
- [x] There are no breaking changes (API, behaviour)
- [x] I have added unit and/or integration tests for my change
- [x] The tests cover both positive and negative cases
- [x] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Doc/example checkboxes left unchecked: a 3-line internal-mapper
null-guard does not require docs or example updates. Happy to add either
if a maintainer disagrees. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
### Note on the test runs
Ran `mvn -fae clean test` from the repo root and a follow-up `mvn -fae
clean test -pl '!embeddings/langchain4j-embeddings'`. Combined: **59
modules pass cleanly, 2 modules fail, 46 modules auto-skip** as
transitive dependents of the failures.
**Both failures share a single root cause unrelated to this change**:
`ai.djl.engine.EngineException: Failed to load Huggingface native
library` (`Unexpected flavor:
cpu` — DJL HuggingFace native binaries do not load on aarch64 / Apple
Silicon). Affects:
- `langchain4j-embeddings` directly
- `langchain4j` main module (15 test classes touching
`AllMiniLmL6V2QuantizedEmbeddingModel` static init)
- `langchain4j-azure-ai-search` (`AzureAiSearchContentRetrieverTest`
setup uses the same embedding model)
The module touched by this PR — `langchain4j-mistral-ai` — was tested
independently: **21/21 unit tests green** (3 new + 18 pre-existing). CI
will validate the rest.
## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`
## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`
## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j
---------
Co-authored-by: madaram <6826292+madaram@users.noreply.github.com>
Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>
<!--
Thank you so much for your contribution!
Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.
Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->
## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes#5013
## Change
<!-- Please describe the changes you made. -->
Added support for `PdfFileContent` for the Mistral AI integration, very
similar to https://github.com/langchain4j/langchain4j/pull/4978
- Modified `MistralAiMapper.toMistralAiMessageContents()` so it now
supports mapping `PdfFileContent` to Mistral's API format
(`DocumentURLChunk`).
- Added `MistralAiDocumentUrlContent` and
`MistralAiDocumentBase46Content` classes for modeling
`DocumentUrlChunk`. The API supports both using URLs and base64 strings
for representing the `document_url` field in `DocumentUrlChunk`.
- Added the two classes as well to keep consistency with how image
chunks are handled in the module (`MistralAiImageBase64Content`,
`MistralAiImageUrlContent`, and the audio chunk representations as
well).
- For testing, the URL pdf file is from [Wikimedia
Commons](https://commons.wikimedia.org/wiki/Main_Page) to avoid
copyright issues, and the local one is just one I made up (it only
contains `Bonjour!`).
## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [X] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
---------
Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>
<!--
Thank you so much for your contribution!
Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.
Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->
## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes#4977
## Change
<!-- Please describe the changes you made. -->
Added support for `AudioContent` for the Mistral AI integration.
- Modified `MistralAiMapper.toMistralAiMessageContents()`' so it
supports mapping `AudioContent` to Mistral's API format (`AudioChunk`).
- Added `MistralAiAudioBase64Content` and `MistralAiAudioUrlContent`
classes for modeling `AudioChunk`. The API supports both using URLs and
base64 strings for representing the content of an audio chunk
- Added the two classes as well to keep consistency with how image
chunks are handled in the module (`MistralAiImageBase64Content` and `
MistralAiImageUrlContent`).
- Added two more values for `MistralAiChatModelName` for easy access to
Voxtral latest models.
- Tests cover `AudioContent` instances generated from base64 data and
URL.
- Audio files are from [Wikipedia
Commons](https://commons.wikimedia.org/wiki/Main_Page) to avoid
copyright issues :).
## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [X] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`
## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`
## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j
## Issue
Closes https://github.com/langchain4j/langchain4j/issues/4652
## Change
- Add support for `@Tool`-annotated methods to return multimodal content
(images) to the LLM, not just text. Tools can now return `Image`,
`ImageContent`, `Content`, `List<Content>`, `Content[]`, etc.
- Refactor `ToolExecutionResultMessage` to store `List<Content>`
internally instead of a plain `String`, with backward-compatible
`text()` accessor and new `contents()` / `hasSingleText()`
methods.
- Refactor `ToolExecutionResult` to support
`resultContents(List<Content>)` as an alternative to
`resultText(String)` and `resultTextSupplier(Supplier)`.
- Implement multimodal tool result mapping for providers that support
it: Anthropic, Amazon Bedrock, and Google AI Gemini.
- Add `UnsupportedFeatureException` guards in providers that do not
support non-text tool results: Azure OpenAI, GitHub Models, Jlama,
Mistral AI, Ollama, OpenAI (Chat Completions
& Responses), Vertex AI (Anthropic & Gemini), Watsonx, and Workers AI.
- Update `ToolExecutedEvent` / `DefaultToolExecutedEvent` to carry
`resultContents` alongside the existing `resultText` accessor.
- Add comprehensive unit and integration tests
(`should_execute_tool_returning_Image`,
`should_execute_tool_returning_ImageContent`,
`should_execute_tool_returning_ContentList`,
`should_fail_when_tool_returns_image_and_provider_does_not_support_it`).
- Update tools documentation with new "Returning Images and Multimodal
Content" and "Multimodal Tool Results" sections.
## General checklist
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [X] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
- [X] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
Refactor `OpenAiModerationModel` and `MistralAiModerationModel `to make
them more readable and facilitate the addition of new features.
Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>
## Issue
This PR adds observability support for `ModerationModel`
implementations, following the same patterns established for `ChatModel`
listeners. It introduces a new request/response API for moderation
operations and provides listener callbacks for monitoring moderation
requests, responses, and errors.
## Change
Commits:
1)
[f025c0f61](https://github.com/jeanbisutti/langchain4j/commit/f025c0f61)
- **Add ModerationRequest/ModerationResponse API to ModerationModel**
- Introduce `ModerationRequest` with builder pattern supporting both
text and messages
- Introduce `ModerationResponse` with metadata (model name, token usage,
finish reason)
- Add `moderate(ModerationRequest)` method to `ModerationModel`
interface
- Update all implementations (OpenAI, MistralAI, Watsonx) to support the
new API
- Add unit tests for request/response classes
2)
[aed77bf60](https://github.com/jeanbisutti/langchain4j/commit/aed77bf60)
- **Add moderation model listener support**
- Add `ModerationModelListener` interface with `onRequest`,
`onResponse`, `onError` callbacks
- Add context classes: `ModerationModelRequestContext`,
`ModerationModelResponseContext`, `ModerationModelErrorContext`
- Add `ModerationModelListenerUtils` for consistent listener invocation
across implementations
- Implement listener support in OpenAI, MistralAI, and Watsonx
moderation models
- Add `AbstractModerationModelListenerIT` base test class for consistent
testing
- Add documentation in observability tutorial
3)
[2c600cd90](https://github.com/jeanbisutti/langchain4j/commit/2c600cd90)
- **Refactoring - Add toInputs and toText utility methods to
ModerationModel**
- Extract common `toInputs()` and `toText()` utility methods to
`ModerationModel` interface
- Remove duplicate code from OpenAI, MistralAI, and Watsonx
implementations
**Backward Compatibility:** The existing `moderate(String text)` and
`moderate(ChatMessage... messages)` methods remain unchanged. The new
`moderate(ModerationRequest)` API is additive. Listener support is
opt-in via builder configuration.
## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [X] The tests cover both positive and negative cases
- [X] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [X] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [X] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
---------
Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>
## Issue
Closes#4602
## Change
This adds a builder method to the `MistralAiChatModelBuilder` to
configure strict JSON schema for response format, as is done in the
OpenAI implementation.
## General checklist
- [x] There are no breaking changes (API, behaviour)
- [x] I have added unit and/or integration tests for my change
- [x] The tests cover both positive and negative cases
- [x] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [x] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [x] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`
## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`
## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j
Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>
<!--
Thank you so much for your contribution!
Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.
Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->
## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes#4568
## Change
Added the possibility to have a custom headers, I did as it was done for
Ollama
## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [x] There are no breaking changes (API, behaviour)
- [x] I have added unit and/or integration tests for my change
- [x] The tests cover both positive and negative cases
- [x] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
<img width="575" height="280" alt="image"
src="https://github.com/user-attachments/assets/563f2f58-0fef-493d-9d1a-9d71f09e5ad9"
/>
- [x] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
### Once reviewed & approved
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
<!--
Thank you so much for your contribution!
Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.
Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->
## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes#4476
## Change
<!-- Please describe the changes you made. -->
Add support for Mistral AI's Magistral reasoning models.
- Add `MAGISTRAL_SMALL_LATEST` and `MAGISTRAL_MEDIUM_LATEST` model names
- Add `returnThinking` parameter to parse thinking content from API
responses into `AiMessage.thinking()`
- Add `sendThinking` parameter to include thinking content in follow-up
requests for multi-turn conversations
- Support streaming of thinking content via `onPartialThinking` callback
### Response format handling
The Mistral API can return content in two formats. As a simple string:
```json
{
"message": {
"role": "assistant",
"content": "The answer is 42."
}
}
```
Or as an array of structured blocks when thinking is included:
```json
{
"message": {
"role": "assistant",
"content": [
{"type": "thinking", "thinking": [{"type": "text", "text": "Let me reason..."}]},
{"type": "text", "text": "The answer is 42."}
]
}
}
```
I added a custom deserializer handles both formats.
### Testing notes
Tests for `returnThinking` use mocked HTTP responses rather than real
API calls. I was not able to reliably trigger Magistral models to return
thinking content, which would make real API tests flaky.
## References
- [Mistral AI Chat Completions
API](https://docs.mistral.ai/api/#tag/chat/operation/chat_completion_v1_chat_completions_post)
- [Mistral AI Reasoning
doc](https://docs.mistral.ai/capabilities/reasoning)
## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [x] There are no breaking changes (API, behaviour)
- [x] I have added unit and/or integration tests for my change
- [x] The tests cover both positive and negative cases
- [x] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [x] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
## Checklist for adding new maven module
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added my new module in the root `pom.xml` and
`langchain4j-bom/pom.xml`
## Checklist for adding new embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreIT` that extends
from either `EmbeddingStoreIT` or `EmbeddingStoreWithFilteringIT`
- [ ] I have added a `{NameOfIntegration}EmbeddingStoreRemovalIT` that
extends from `EmbeddingStoreWithRemovalIT`
## Checklist for changing existing embedding store integration
<!-- Please double-check the following points and mark them like this:
[X] -->
- [ ] I have manually verified that the
`{NameOfIntegration}EmbeddingStore` works correctly with the data
persisted using the latest released version of LangChain4j
---------
Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>
## Issue
Closes#4222
## Change
Similiar to #4225: Exposes raw HTTP Header via
`MistralAiChatResponseMetadata` for MistralAiChatModel by passing
through the data from HTTP client.
## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [x] There are no breaking changes (API, behaviour)
- [x] I have added unit and/or integration tests for my change
- [ ] The tests cover both positive and negative cases
- [x] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
<!--
Thank you so much for your contribution!
Please fill in all the sections below.
Please open the PR as a draft initially. Once it is reviewed and
approved, we will ask you to add documentation and examples.
Please note that PRs with breaking changes or without tests will be
rejected.
Please note that PRs will be reviewed based on the priority of the
issues they address.
We ask for your patience. We are doing our best to review your PR as
quickly as possible.
Please refrain from pinging and asking when it will be reviewed. Thank
you for understanding!
-->
## Issue
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes#3437
## Change
<!-- Please describe the changes you made. -->
Allow customers to discover available models and their capabilities
programmatically without visiting provider websites.
Core Infrastructure (langchain4j-core):
- Added ModelDiscovery interface for unified model discovery API
- Added ModelDescription class for standardized model metadata
- Added ModelType enum (CHAT, EMBEDDING, IMAGE_GENERATION, etc.)
- Added ModelDiscoveryFilter for filtering models by type, capabilities,
context window, etc.
- Added ModelPricing class for model pricing information
- Created comprehensive unit tests for all core classes
- Created AbstractModelDiscoveryIT base class for provider integration
tests
OpenAI Implementation (langchain4j-open-ai):
- Extended OpenAiClient with listModels() method for GET /v1/models
endpoint
- Added ModelsListResponse and OpenAiModelInfo API response classes
- Implemented OpenAiModelDiscovery with client-side filtering support
- Follows existing OpenAI builder pattern and conventions
Anthropic Implementation (langchain4j-anthropic):
- Implemented AnthropicModelDiscovery with static model registry
- Includes Claude 3.5 Sonnet, Haiku, Opus and Claude 3 models
- Provides complete pricing and capability metadata
- Supports client-side filtering
Key Features:
- Unified API across all providers
- Flexible filtering by type, capabilities, context window, name pattern
- Builder pattern consistent with existing LangChain4j conventions
- Immutable data structures for thread safety
- No breaking changes to existing APIs
- Comprehensive test coverage
## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [X] There are no breaking changes (API, behaviour)
- [X] I have added unit and/or integration tests for my change
- [ ] The tests cover both positive and negative cases
- [ ] I have manually run all the unit and integration tests in the
module I have added/changed, and they are all green
- [ ] I have manually run all the unit and integration tests in the
[core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core)
and
[main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j)
modules, and they are all green
<!-- Before adding documentation and example(s) (below), please wait
until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features)
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>