## Change
Several providers did not map their native errors to the specific
`dev.langchain4j.exception.*` types (`RateLimitException`,
`AuthenticationException`, `ModelNotFoundException`,
`InvalidRequestException`,
`TimeoutException`, `InternalServerException`), so retry/error-handling
logic keyed on these exception types (as already works for OpenAI,
Anthropic, Ollama, Mistral, Bedrock, watsonx.ai, etc.) silently did
not work for them. This PR closes that gap:
- **`langchain4j-google-genai`**: added `GoogleGenAiExceptionMapper`
(maps `com.google.genai.errors.ApiException` by its HTTP status code,
same pattern as `BedrockExceptionMapper`/`WatsonxExceptionMapper`).
The module already used `withRetryMappingExceptions(...)`, but with the
default mapper, which only understands lc4j's `HttpException` — the
GenAI SDK exceptions fell through unmapped. The mapper is now passed
to all call sites (chat, streaming, embedding, image, batch models,
token count estimator), the streaming `onError` path, and the
`GoogleGenAiFiles` API calls (which previously threw raw SDK
exceptions).
- **`langchain4j-vertex-ai-gemini`**: added
`VertexAiGeminiExceptionMapper` (maps gax `ApiException` via its HTTP
status code equivalent; `DEADLINE_EXCEEDED` maps to `TimeoutException`).
Same "default mapper
cannot map SDK exceptions" issue as above. Also fixed a double-wrap: the
sync path re-wrapped the already-mapped exception in `new
RuntimeException(e)`, destroying the mapped type. The streaming path now
maps
the error before invoking `handler.onError(...)` and the listener error
context.
- **`langchain4j-vertex-ai-anthropic`**: added
`VertexAiAnthropicExceptionMapper` (gax-based, like the Gemini one, but
walks the whole cause chain because the internal client wraps gax
exceptions into
`IOException`). Replaces `new RuntimeException("Failed to generate
response", e)` in the sync path and maps both streaming error paths.
- **`langchain4j-workers-ai`**: `HttpException` from the HTTP client
passed through unmapped; all requests go through the single
`WorkersAiClient.execute(...)`, which now wraps the call in
`ExceptionMapper.mappingException(...)`.
- **`langchain4j-cohere`**: `CohereEmbeddingModel` called
`client.embed(...)` / `v2Client.embedV2(...)` without mapping (unlike
`CohereScoringModel`, which already uses `withRetryMappingExceptions`).
Both call
sites are now wrapped in `ExceptionMapper.mappingException(...)`
(mapping only, no retry added, to preserve existing behavior).
Behavior note: exceptions thrown by these modules on provider errors
change from raw `RuntimeException`/SDK exceptions to the specific
`dev.langchain4j.exception.*` types. All of them extend
`RuntimeException`
and carry the original exception as the cause, so existing code catching
`RuntimeException` keeps working; this aligns these providers with the
behavior of the already-migrated ones.
## General checklist
- [X] There are no breaking changes (API, behaviour): thrown exception
types become more specific (see behavior note above), matching the
established behavior of the other providers
- [ ] 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 (unit tests: green;
integration tests requiring provider credentials were not run)
- [ ] 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)
## Issue
Closes#5614
## Change
`langchain4j-vertex-ai-gemini` `FinishReasonMapper.map` only mapped
`STOP`, `MAX_TOKENS` and `SAFETY`. The Vertex SDK content-policy reasons
`RECITATION`, `BLOCKLIST`, `PROHIBITED_CONTENT` and `SPII` fell through
to the default and were returned as `FinishReason.OTHER`, hiding the
fact that the response was blocked by a content policy.
This adds four `case` labels so those reasons return
`FinishReason.CONTENT_FILTER`, matching `SAFETY` and the sibling
`langchain4j-google-ai-gemini` mapper. The existing three cases and the
default `OTHER` are unchanged; `MALFORMED_FUNCTION_CALL` and
`FINISH_REASON_UNSPECIFIED` still map to `OTHER`.
```java
case SAFETY:
case RECITATION:
case BLOCKLIST:
case PROHIBITED_CONTENT:
case SPII:
return FinishReason.CONTENT_FILTER;
```
Added `FinishReasonMapperTest` (new file) covering the four fixed
reasons plus regression cases. The four positive assertions fail before
this change and pass after.
## 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 <!-- N/A — change is isolated to
langchain4j-vertex-ai-gemini -->
<!-- Below items wait until the PR is reviewed and approved. -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
<!-- N/A — no doc change for an internal mapper fix -->
- [ ] I have added an example in the [examples
repo](https://github.com/langchain4j/langchain4j-examples) (only for
"big" features) <!-- N/A -->
- [ ] I have added/updated [Spring Boot
starter(s)](https://github.com/langchain4j/langchain4j-spring) (if
applicable) <!-- N/A -->
<!-- "new maven module" and "embedding store" checklist sections omitted
— not applicable to this fix. -->
## Issue
Closes#5136
## Change
Adds a `labels(Map<String, String>)` builder method on both
`VertexAiGeminiChatModel` and `VertexAiGeminiStreamingChatModel`. When
set, the labels are placed on every `GenerateContentRequest` issued by
the model via `GenerateContentRequest.Builder.putAllLabels(...)`.
Vertex AI's `generateContent` request body has a top-level `labels` map
intended for billing and reporting, per the [REST
spec](https://cloud.google.com/vertex-ai/generative-ai/docs/reference/rest/v1/projects.locations.endpoints/generateContent#request-body).
Until now there was no path through the langchain4j Vertex AI Gemini
chat model to set this field — the underlying Google `GenerativeModel`
is `final` and builds the request privately.
### Implementation outline
When `labels` is empty (the default), the existing
`GenerativeModel.generateContent(...)` / `generateContentStream(...)`
SDK calls are used unchanged. When `labels` is non-empty, the model
builds a `GenerateContentRequest` manually — mirroring the SDK's private
`buildGenerateContentRequest` envelope and reading
`getGenerationConfig`/`getSafetySettings`/`getTools`/`getToolConfig`/`getSystemInstruction`
from the (already configured) `GenerativeModel` — and dispatches it
through the SDK's public
`PredictionServiceClient.generateContentCallable()` /
`streamGenerateContentCallable()`. The fully-qualified resource name is
reconstructed from the configured project/location/modelName, matching
the SDK's private `getResourceName` rules.
This is the same wire shape that Google's official [`@google/genai`
TypeScript
SDK](4383badd5b/src/converters/_models_converters.ts (L1882-L1885))
produces — TS lifts `config.labels` to the top of the request envelope;
this PR does the equivalent in Java.
### Verified end-to-end
- 88 unit tests pass in `langchain4j-vertex-ai-gemini` (12 in
`VertexAiGeminiChatModelBuilderTest`, 6 in
`VertexAiGeminiStreamingChatModelBuilderTest`, including new tests
covering: builder storage, default-empty behaviour, request-payload
label injection, no-labels-when-empty, and the four `buildResourceName`
branches).
- 1309 tests pass in `langchain4j-core` and `langchain4j` modules (no
regressions).
- Real-world integration confirmed: a downstream consumer using this
snapshot issued labelled `GenerateContent` and `StreamGenerateContent`
requests against `aiplatform.googleapis.com`; the labels surfaced in
**Cloud Billing → Reports → Group by → Labels** for the calling project.
### Backward compatibility
The new builder method is opt-in. All existing constructors and the
deprecated constructor initialise `labels` to `Collections.emptyMap()`,
so the new code path is never entered for callers that don't opt in.
## 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)
## Issue
Closes#5109
## Change
Added `customHeaders(Map<String, String>)` builder method to
`VertexAiGeminiChatModel`, mirroring the existing support already
present on `VertexAiGeminiStreamingChatModel`.
The merge logic is identical to the streaming counterpart: user-supplied
headers are merged with the default `user-agent: LangChain4j` header
using `putIfAbsent`, so a custom `user-agent` takes precedence.
Note: only a `Map` overload is provided (no `Supplier`) because the
VertexAI SDK sets headers at client construction time, not per-request —
dynamic per-request headers are not applicable here.
## 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
## 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)
## Summary
This fixes `SchemaHelper.from(JsonSchemaElement)` in the Vertex AI
Gemini integration to handle schema variants that are already supported
in Google AI Gemini mapping but currently fail in Vertex AI mapping.
Fixes#4617
## What changed
- Added handling for `JsonAnyOfSchema` in `SchemaHelper.from(...)` by
mapping nested variants into Vertex AI `Schema.anyOf`.
- Added handling for `JsonNullSchema` in `SchemaHelper.from(...)` by
mapping it to `Schema.nullable=true`.
- Added regression tests in `SchemaHelperTest` covering:
- `anyOf` + `null` composition
- direct `null` schema mapping
- `anyOf` without description
- object path after null-check branch
## Why this is safe
- Change is scoped to schema conversion for Vertex AI Gemini
tool/response schema mapping.
- Existing behavior for other schema types is unchanged.
## Local verification
- `./mvnw -pl langchain4j-vertex-ai-gemini spotless:check
-Dtest=SchemaHelperTest -Dsurefire.failIfNoSpecifiedTests=false test
jacoco:report`
- `Tests run: 8, Failures: 0, Errors: 0`
Coverage note:
- The newly added anyOf/null conversion paths are exercised by dedicated
regression tests.
## AI usage disclosure
AI assistance was limited to unit test drafting, code review support,
and formatting/check command validation.
<!--
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#4230
## Change
This PR refactors and improves the `PartsMapper` class in the
`langchain4j-vertex-ai-gemini` module.
Most importantly, it fixes the issue with parsing of escaped quotes in
the tool response.
Extracted the logic for parsing function response text into a new helper
method `parseFunctionResponseToStruct`, which tries multiple strategies
to convert the response to a `Struct`.
## 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
## Issue
Closes#4020
## Change
I exposed the vertex ApiEndpoint in the builder for Vertex AI Gemini
chat models, allowing users to specify a custom API endpoint.
This enhancement applies to both the synchronous and streaming chat
model implementations
## 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
- [ ] 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)
## Issue
Closes https://github.com/langchain4j/langchain4j/issues/1146
## Change
Implemented streaming cancellation for the following APIs:
- `StreamingChatModel` + `StreamingChatResponseHandler`
- `TokenStream`
Implemented streaming cancellation for the following modules:
- Anthropic
- Azure OpenAI
- Bedrock
- Google AI Gemini
- Mistral
- Ollama
- OpenAI
- OpenAI Official
- Vertex AI Gemini
## Examples
### `StreamingChatModel` + `StreamingChatResponseHandler` APIs
If you wish to cancel the streaming, you can do so from one of the
following `StreamingChatResponseHandler` methods:
- `onPartialResponse(PartialResponse, PartialResponseContext)`
- `onPartialThinking(PartialThinking, PartialThinkingContext)`
- `onPartialToolCall(PartialToolCall, PartialToolCallContext)`
The context object contains the `StreamingHandle`, which can be used to
cancel the streaming:
```java
model.chat(userMessage, new StreamingChatResponseHandler() {
@Override
public void onPartialResponse(PartialResponse partialResponse, PartialResponseContext context) {
process(partialResponse);
if (shouldCancel()) {
context.streamingHandle().cancel();
}
}
@Override
public void onCompleteResponse(ChatResponse completeResponse) {
System.out.println("onCompleteResponse: " + completeResponse);
}
@Override
public void onError(Throwable error) {
error.printStackTrace();
}
});
```
### `TokenStream` API
If you wish to cancel the streaming, you can do so from one of the
following callbacks:
- `onPartialResponseWithContext(BiConsumer<PartialResponse,
PartialResponseContext>)`
- `onPartialThinkingWithContext(BiConsumer<PartialThinking,
PartialThinkingContext>)`
For example:
```java
tokenStream
.onPartialResponseWithContext((PartialResponse partialResponse, PartialResponseContext context) -> {
process(partialResponse);
if (shouldCancel()) {
context.streamingHandle().cancel();
}
})
.onCompleteResponse((ChatResponse response) -> futureResponse.complete(response))
.onError((Throwable error) -> futureResponse.completeExceptionally(error))
.start();
```
When `StreamingHandle.cancel()` is called, LangChain4j will close the
connection and stop the streaming.
Once `StreamingHandle.cancel()` has been called, `TokenStream` will not
receive any further callbacks.
## 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)
<!--
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!
-->
Unlike OpenAI, whose tool call responses already contain a unique
[tool_call_id](f60698986d/langchain4j-open-ai/src/main/java/dev/langchain4j/model/openai/internal/OpenAiUtils.java (L335)),
the Gemini API does not provide such identifiers. Instead, according to
the [[Gemini function calling
documentation]](https://ai.google.dev/gemini-api/docs/function-calling?example=meeting#parallel_function_calling),
the API relies on the index order of function calls to match requests
with responses.
This PR updates the Gemini integration in langchain4j to embed a request
ID based on the function call index whenever a ToolExecutionRequest is
created. This ensures consistent and reliable mapping between Gemini
function calls and their corresponding tool execution results.
One use case is that in front end, we can know when the tool execution
is invoked and finished by leveraging two callback handlers
(`beforeToolExecution` and `onToolExecuted`) in TokenStream
<!-- Please specify the ID of the issue this PR is addressing. For
example: "Closes #1234" or "Fixes #1234" -->
Closes #
## Change
<!-- Please describe the changes you made. -->
1. FunctionCallHelper
2. VertexAiGeminiStreamingChatModel:
## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [x] There are no breaking changes
- [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>
## Summary
This PR enhances test coverage for the `ContentsMapper` class in the
Vertex AI Gemini integration, adding tests for various edge cases and
message type combinations.
## Changes
- Added test for empty message list handling
- Added test for single system message processing
- Added test for single user message processing
- Added test for multiple system messages handling
- Added test for consecutive user messages
- Added test for consecutive AI messages
- Added test for tool execution without preceding AI message
- Added test for single tool execution request
- Added test for tools with empty arguments
- Added test for tools with null arguments
## Test Coverage Details
The new tests cover:
- **Empty input handling**: Verifying proper behavior with empty message
lists
- **Single message types**: Testing isolation of system-only and
user-only messages
- **Multiple system messages**: Ensuring proper handling when multiple
system messages are present
- **Consecutive messages**: Testing same-type messages appearing in
sequence
- **Tool execution edge cases**: Testing tool requests and responses
with various argument configurations
- **Null/empty arguments**: Verifying handling of tools with null or
empty argument objects
## Key Scenarios Tested
- Message list boundary conditions (empty, single message)
- Message type combinations and ordering
- Tool execution flow with and without AI messages
- Argument handling in tool requests (null, empty, populated)
## Impact
- No production code changes
- Improves confidence in ContentsMapper message handling
- Documents expected behavior through comprehensive test cases
- Helps prevent regressions in Vertex AI message conversion logic
Signed-off-by: Oleksandr Klymenko <alexanderklmn@gmail.com>