Progresses #3916.
## Change
Adds `AnthropicBatchChatModel`, an implementation of the core
`BatchChatModel` interface
(`submit` / `retrieve` / `cancel` / `list`) for the [Anthropic Message
Batches
API](https://docs.anthropic.com/en/docs/build-with-claude/batch-processing),
which processes many chat requests asynchronously at 50% of the standard
per-token price.
Each request is built through the same `createAnthropicRequest` path as
`AnthropicChatModel`, so per-request
parameters (tools, thinking, caching, etc.) behave identically in a
batch and in a single call. Results come
back in arbitrary order and are re-sorted to submission order by
generated `custom_id`s. Anthropic reports
only `in_progress` / `canceling` / `ended` at the batch level, so
`ended` maps to `BatchState.SUCCEEDED` and
the per-request `succeeded` / `errored` / `canceled` / `expired`
outcomes are surfaced as `BatchItemResult`s.
The batch endpoints are added to the existing hand-rolled
`AnthropicClient` as default methods that throw
`UnsupportedFeatureException`, so existing `AnthropicClient`
implementations keep compiling. No new
dependency. Chat requests only.
Covered by unit tests against a mock HTTP server (custom-id ordering,
success/error/canceled mapping, the
in-progress case that fetches no results until the batch ends, and
pagination). The integration test
`AnthropicBatchChatModelIT` (key-gated on `ANTHROPIC_API_KEY`) was also
run against the live Batches API and
passes, exercising submit / retrieve / list / cancel.
## 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
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#5867
## Change
`AnthropicMapper` only applied `cache_control=ephemeral` to
`TextContent` when a
`UserMessage` was marked for caching, silently dropping it when the last
content
item was `ImageContent` or `PdfFileContent`. This contradicts the
surrounding
code comment ("apply the cache_control to the last content item") and
the
documented behavior in `anthropic.md`.
- Add `cacheControl`-accepting constructors and `from*` overloads to
`AnthropicImageContent` and `AnthropicPdfContent` (mirrors
`AnthropicTextContent`)
- In `AnthropicMapper`, pass `cacheControl` to Image/Pdf content when
`applyCache`
- Include `cacheControl` in `AnthropicPdfContent.toString()` (already
present on
`AnthropicImageContent` and `AnthropicTextContent`)
Only the user turn is affected, matching Anthropic's prompt caching
restriction.
Nested blocks inside `tool_result` are unchanged — sub-content blocks
cannot be
cached directly. Backward compatible: additive overloads; `cacheControl`
is null
when absent.
## 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)
Co-authored-by: tianyu.zhao <mrzgetbetter820@users.noreply.github.com>
## Issue
Closes#5727
## Change
`AnthropicMapper` already honored a `cache_control: "ephemeral"`
attribute on `UserMessage` (#4487). In an agentic tool loop,
`AiServices` resends the growing conversation tail (`AiMessage` +
`ToolExecutionResultMessage`) on every call, but neither of those
message types could be marked for caching, so every accumulated tool
result was rebilled at full price on each turn.
This extends the same `cache_control` handling to `AiMessage` and
`ToolExecutionResultMessage`, mirroring the existing `UserMessage`
behavior:
```java
AiMessage aiMessage = someAiMessage.toBuilder()
.attributes(Map.of("cache_control", "ephemeral"))
.build();
```
The cache marker is applied to the last content block of the message
(for `ToolExecutionResultMessage`, the `tool_result` block itself).
`AnthropicToolResultContent` and `AnthropicToolUseContent` gained
`cacheControl`-aware constructor/builder overloads so the marker is set
at construction time, consistent with how `AnthropicTextContent` already
does it for `UserMessage`.
## 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
- [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
Closes#5658
## Change
Adds opt-in support for Anthropic's `cache-diagnosis-2026-04-07` beta
feature, which reports why a prompt-cache hit was missed instead of only
showing `usage.cacheReadInputTokens` drop to zero.
- `AnthropicChatRequestParameters`: new `returnCacheDiagnostics` +
`previousMessageId` (per-request, mirrors `userId`)
- `AnthropicChatResponseMetadata#cacheDiagnostics()` exposes the result
(sync and streaming) as a new `AnthropicCacheDiagnostics` type
- Request/response shape wired through new internal API POJOs
(`AnthropicDiagnosticsParameters`, `AnthropicDiagnostics`,
`AnthropicCacheMissReason`) and the mapper
- No behavior change when the feature isn't enabled (no extra request
field, no allocation)
## 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
- [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>
## Summary
Closes#5530 (Phase 1).
Adds a typed, ergonomic way to enable Anthropic [Agent
Skills](https://docs.anthropic.com/en/docs/agents-and-tools/agent-skills/overview)
on `AnthropicChatModel` and `AnthropicStreamingChatModel`, so Claude can
generate real downloadable documents (`.xlsx`, `.pptx`, `.docx`, `.pdf`)
instead of only describing them:
```java
AnthropicChatModel model = AnthropicChatModel.builder()
.apiKey(System.getenv("ANTHROPIC_API_KEY"))
.modelName("claude-opus-4-8")
.maxTokens(4096)
.skills(AnthropicSkill.XLSX, AnthropicSkill.PPTX) // up to 8
.returnServerToolResults(true)
.build();
```
Today this requires hand-assembling a `container.skills` block via
`customParameters(...)`, manually adding the `code_execution` server
tool, and remembering three beta headers — undocumented and easy to get
wrong.
### What `skills(...)` does
When skills are configured it automatically:
- adds the `container.skills` array
(`{"type":"anthropic","skill_id":"xlsx","version":"latest"}`),
- adds the `code_execution` server tool, unless one is already
configured via `serverTools(...)` (no duplicates),
- merges the required `anthropic-beta` tokens
(`code-execution-2025-08-25`, `skills-2025-10-02`,
`files-api-2025-04-14`) with any user-supplied `beta(...)` value,
without duplicates.
The produced request matches the reference body from the issue:
```json
{
"model": "claude-opus-4-8",
"max_tokens": 4096,
"container": { "skills": [{ "type": "anthropic", "skill_id": "pptx", "version": "latest" }] },
"messages": [ ... ],
"tools": [{ "type": "code_execution_20250825", "name": "code_execution" }]
}
```
Generated file ids remain surfacable via `returnServerToolResults(true)`
under the `AiMessage` `"server_tool_results"` attribute. Both the
blocking and streaming models are covered.
## Scope / follow-up
This is the self-contained Phase 1 from the issue. The Anthropic **Files
API client** (upload / list / delete, and the genuinely missing
**download** primitive) is intentionally left out so its surface can be
agreed first — @RyanHowell30 explicitly suggested landing Phase 1 first
and aligning on the Files-client shape before implementing Phase 2.
Happy to follow up with it once there's direction on the desired API.
Advanced cases not covered by the `.skills(...)` sugar (per-skill
version pinning, custom workspace skills, reusing a `container.id`)
remain reachable through the existing `customParameters(...)` escape
hatch; typed support for those can be layered on later if wanted.
## Test plan
- [x] New `AnthropicSkillsTest` (8 unit tests, no network): container
block contents, auto-added `code_execution` tool, no duplication when
the tool is already configured, no container/tool when no skills,
serialized request shape, and beta-header merging/de-duplication.
- [x] `mvn -pl langchain4j-anthropic test` — all unit tests pass.
- [x] `mvn -pl langchain4j-anthropic spotless:check` — clean.
- Public API change is additive (new `AnthropicSkill` enum,
`skills(...)` builder methods, and a `container` field on the internal
`AnthropicCreateMessageRequest` mirroring the existing `outputConfig`
field) — binary compatible.
---------
Co-authored-by: Benamira05 <145583236+Benamira05@users.noreply.github.com>
Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>
## Issue
Closes#5603
## Change
Right now the Anthropic integration folds every `SystemMessage` into the
top-level `system` field, so there's no way to use Claude Opus 4.8's
[mid-conversation system
messages](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages).
This adds an opt-in `midConversationSystemMessages` option (default off)
that sends a `SystemMessage` appearing after the conversation has
started as a `role:"system"` entry in the `messages` array. Leading
system messages still go to the top-level `system` field, and with the
option off behaviour is unchanged.
The library doesn't enforce or reorder placement: it sends the
`SystemMessage` at whatever position the caller put it in, and Anthropic
rejects invalid placements with a 400 (an inline system message has to
follow a user turn, can't be first, and can't sit between a `tool_use`
and its `tool_result`). Those rules are noted on the option's Javadoc.
I've opened this as a draft to get a read on the approach. I don't mind
changing how it's exposed if you'd rather it worked differently.
## 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
and main modules, and they are all green
- [ ] 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)
Fixes a bug where replaying historical malformed tool arguments would
throw a \JsonParseException\, breaking the error feedback loop with the
Anthropic API.
As suggested by the maintainers in #5227, this avoids parsing
\ToolExecutionRequest.arguments()\ to a \Map\ during request
construction. Instead, it uses \@JsonRawValue\ on the
\AnthropicToolUseContent.input\ field to pass the raw JSON string
directly to Jackson for serialization.
This eliminates the wasteful string -> map -> string serialization
roundtrip, prevents subtle normalizations of JSON formatting, and
preserves invalid JSON strings so that the subsequent tool execution
error result can be successfully reported back to the model.
Resolves#5227
---------
Co-authored-by: Dmytro Liubarskyi <ljubarskij@gmail.com>
Closes#5384
## Summary
When an OpenAI-compatible proxy in front of Claude (e.g. LiteLLM,
OpenRouter, or a custom Anthropic->OpenAI bridge) emits a trailing
`data: [DONE]` sentinel, a comment line, or a frame with an unknown
event name, `DefaultAnthropicClient.createMessage(...)` was
deserializing the payload into `AnthropicStreamingData` and throwing
`MismatchedInputException`. The exception was swallowed by
`ServerSentEventListenerUtils.ignoringExceptions`, but it pollutes logs
and aborts trailing event processing.
This PR adds a small `isSkippableSseFrame(...)` guard in the streaming
`onEvent` callback. The guard bails out early on:
- `eventName == null` (heartbeat / keep-alive)
- `data == null` or empty (after trim)
- the OpenAI-style `"[DONE]"` sentinel
- payloads that are not JSON objects (arrays, bare scalars, raw numbers)
The raw `ServerSentEvent` is still added to `rawServerSentEvents` for
observability; the return only skips the `AnthropicStreamingData` parse
and the downstream handler dispatch.
## Why this location (not `DefaultServerSentEventParser`)
The shared `DefaultServerSentEventParser` is intentionally kept
protocol-agnostic and untouched. The same convention is already used by
`OpenAiStreamingResponseBuilder#onEvent` (OpenAI client) and
`MistralAiServerSentEventListener#onEvent` (Mistral client), which both
drop `[DONE]` at the client-listener layer. Putting the guard there
keeps the SSE parser general and matches the established pattern in the
codebase.
## Changes
-
`langchain4j-anthropic/src/main/java/dev/langchain4j/model/anthropic/internal/client/DefaultAnthropicClient.java`
- Extract `event.event()` / `event.data()` into locals.
- Add `isSkippableSseFrame(eventName, eventData)` guard before the
`fromJson` call.
- Add the raw event to `rawServerSentEvents` even when skipping, for
parity with the existing observability behavior.
-
`langchain4j-anthropic/src/test/java/dev/langchain4j/model/anthropic/internal/client/DefaultAnthropicClientTest.java`
- New `StreamingTest#shouldIgnoreDoneSentinelAndUnknownEventFrames`:
feeds a canonical 6-event Anthropic stream followed by `[DONE]` and a
`"ping"` frame, asserts the assembled `AiMessage` is returned, the
partial-response text contains the expected tokens, and no error is
raised. The test is verified to fail (with the exact
`MismatchedInputException: ... from Array value (token
JsonToken.START_ARRAY)` from the issue) on the unfixed code and pass on
the fixed code.
## Test plan
```bash
mvn -pl langchain4j-anthropic -am test
```
All 98 unit tests in the `langchain4j-anthropic` module pass, including
the new `shouldIgnoreDoneSentinelAndUnknownEventFrames` regression test.
## Backward compatibility
No public API change. The new behavior is strictly more permissive:
previously crashing payloads (`[DONE]`, non-object JSON, `eventName ==
null`) are now silently skipped. No legitimate Anthropic streaming event
types are affected — all eight documented event types (`message_start`,
`content_block_start`, `content_block_delta`, `content_block_stop`,
`message_delta`, `message_stop`, `error`, `ping`) have a non-null,
non-empty, JSON-object `data` payload and pass the guard.
---
Reference: #5384
Co-authored-by: ENG <eng@redos.local>
Co-authored-by: Claude <noreply@anthropic.com>
## Issue
<!-- Update with the real issue number once filed. -->
Closes#5498
## Change
`AnthropicMapper.toAnthropicTool()` did not serialize a tool parameter's
top-level `$defs` into the tool `input_schema`. Because the referenced
definitions in `JsonObjectSchema.definitions()` were dropped, a
parameter using a `$ref` (`JsonReferenceSchema`) reached Anthropic as a
dangling reference.
This is the missed sibling of PR #5131 (Closes#5133), which added
`$defs` to the structured-output path (`toAnthropicSchema`) only. The
OpenAI mapper already preserves `$defs` for the same input, so this also
restores cross-provider parity.
Changes:
- `AnthropicToolSchema`: add a `defs` field mapped to `$defs` via
`@JsonProperty("$defs")` (needed because the class uses
`SnakeCaseStrategy`), with builder support and
`equals`/`hashCode`/`toString`. The deprecated 3-arg constructor is
untouched.
- `AnthropicMapper.toAnthropicTool()`: populate `defs` from
`parameters.definitions()` when non-empty, reusing `mapDefs` and
mirroring `toAnthropicSchema`.
Backward compatible: `@JsonInclude(NON_NULL)` applies, so tools without
definitions produce identical output.
Tests (`AnthropicMapperTest`): a positive test asserts `$defs` is
present, contains the referenced key, and serializes as `"$defs"`
(regression guard for the `@JsonProperty`); a negative test asserts no
`$defs` is emitted without definitions.
## 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 <!-- core/main untouched -->
- [ ] I have added/updated the
[documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs)
<!-- N/A, add after approval -->
- [ ] 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" checklists omitted: not
applicable, this is a bug fix in an existing module. -->
## Issue
Closes#5301
## Change
This PR introduces the provider-specific
`AnthropicChatRequestParameters` class to support per-invocation
overrides of all Anthropic-specific options, rather than baking them
into the model instance at build time.
### Key Changes:
- **Implemented `AnthropicChatRequestParameters`**: Subclasses
`DefaultChatRequestParameters` and exposes Anthropic-specific
parameters: `cacheSystemMessages`, `cacheTools`, `thinkingType`,
`thinkingBudgetTokens`, `sendThinking`, `returnThinking`,
`toolChoiceName`, `disableParallelToolUse`, and `userId`.
- **Integrated Per-Call Merging**: Updated `AnthropicChatModel` and
`AnthropicStreamingChatModel` to extract, merge, and apply parameters
dynamically on each `doChat(...)` call.
- **Narrowed Return Type**: Changed `defaultRequestParameters()` to
return the narrower `AnthropicChatRequestParameters` (with corresponding
compatibility exemptions in `revapi.json`).
- **Comprehensive Tests**: Added unit tests for merge behavior
(`overrideWith`, `defaultedBy`) and WireMock integration tests to verify
the serialized JSON payload.
### How it is Helpful (Benefits):
- **Avoids Duplicate Model Instances**: Prevents the need to instantiate
multiple model instances just to toggle features like prompt caching
(e.g. enabling caching for long agent loops, but disabling it for cheap
one-shot completions on the same model).
- **Dynamic Feature Control**: Allows applications to dynamically adjust
Extended Thinking budgets, tool choices, and parallel tool flags on a
call-by-call basis.
- **Consistent Architecture**: Aligns the Anthropic provider with other
major integrations (like OpenAI and Ollama) which already support
provider-specific request parameter overrides.
## 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
---------
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 #
## Change
<!-- Please describe the changes you made. -->
## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [x] There are no breaking changes (API, behaviour)
- [ ] 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. -->
- [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>
…atalog builder methods
All public builder methods in both classes were missing documentation.
This adds @param and @return Javadoc to each method, following the style
established across the rest of the langchain4j-anthropic module.
<!--
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 #
## Change
<!-- Please describe the changes you made. -->
## General checklist
<!-- Please double-check the following points and mark them like this:
[X] -->
- [x] There are no breaking changes (API, behaviour)
- [ ] 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. -->
- [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
Closes#5128
## Summary
- Adds a `Boolean strict` field to `ToolSpecification` enabling per-tool
strict schema enforcement
- When `null` (default), defers to the model-level `strictTools` setting
— fully backward compatible
- When `true`/`false`, overrides the model-level default for that
specific tool
- Updates `AnthropicMapper` and `OpenAiUtils` to resolve per-tool strict
before falling back to the model default
- Includes JSON serialization/deserialization support and tests for all
three modules
## Motivation
Anthropic limits strict tools to **20 per request**. Agentic
architectures that send 20+ tools in a single request cannot use
`strictTools(true)` on the model without hitting this limit. Per-tool
strict allows selectively enforcing strict on high-value tools while
leaving others non-strict.
## Usage
```java
ToolSpecification.builder()
.name("runSql")
.description("Execute a SQL query")
.parameters(schema)
.strict(true) // enforce strict for this tool
.build();
```
## Test plan
- [x] `ToolSpecificationJsonTest` — round-trip for `strict` true, false,
null; rejection of non-boolean
- [x] `AnthropicMapperTest` — per-tool true overrides model null,
per-tool false overrides model true, per-tool null falls back to model
- [x] `OpenAiUtilsTest` — same three override/fallback scenarios
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Issue
Closes#5133
## Change
`AnthropicMapper.toAnthropicSchema(...)` no longer mapped
`JsonObjectSchema.definitions()` to a `$defs` entry on the produced
Anthropic schema. As a result, any tool or response-format schema
containing a `JsonReferenceSchema` (e.g. recursive types, or polymorphic
AI Service return types lowered to `anyOf` of `$ref`) was serialized
with `$ref: "#/$defs/<id>"` entries and no matching `$defs` block, and
Anthropic rejected the request:
```
400 Bad Request: invalid_request_error
output_config.format.schema: Invalid schema:
Reference to non-existent definition: #/$defs/15d2a4f5-f977-330a-9c2b-b4d343c805c7
```
This is a regression introduced by #5060 (commit
[`205cb5ada`](205cb5adae),
"AI Services: support polymorphic return types and tool parameters") —
that refactor added a `JsonAnyOfSchema` branch but accidentally removed:
```java
if (!objectSchema.definitions().isEmpty()) {
map.put("$defs", mapDefs(objectSchema.definitions()));
}
```
The pre-existing `mapDefs(...)` helper has remained in the file but
became unused.
This PR:
- Re-inserts the `definitions() -> $defs` mapping inside the
`JsonObjectSchema` branch of `toAnthropicSchema`. The existing `mapDefs`
helper is reused as-is.
- Adds `test_toAnthropicSchema_with_definitions` in
`AnthropicMapperTest`, which builds a root `JsonObjectSchema` with a
`definitions()` entry referenced via `JsonReferenceSchema` and asserts
the produced map contains a matching `$defs` block. Verified failing on
`main` and passing with the fix.
Verification:
```
mvn -pl langchain4j-anthropic -Dtest=AnthropicMapperTest test
```
All 24 tests pass.
## 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)
## Problem
`AnthropicChatModel` and `AnthropicStreamingChatModel` had no way to
attach custom HTTP headers to API requests. This is needed for use cases
like:
- Routing/tracing headers required by API gateways or proxies
- Short-lived auth tokens (OAuth, STS) that must be rotated per-request
- Tenant or correlation IDs
The feature was already available for OpenAI, Mistral, Ollama, Voyage,
and other integrations (see #4403), but was missing for Anthropic.
Closes#5100
## Solution
Added two `customHeaders` overloads to both model builders, matching the
pattern established in #4403:
```java
// Static map — headers are fixed for the lifetime of the model
AnthropicChatModel.builder()
.customHeaders(Map.of("X-Tenant-Id", "acme"))
...
// Dynamic supplier — evaluated on every request, allows credential rotation
AnthropicChatModel.builder()
.customHeaders(() -> Map.of("Authorization", tokenService.currentToken()))
...
```
The same API is available on `AnthropicStreamingChatModel`.
## Changes
| File | Change |
|------|--------|
| `AnthropicClient.Builder` | Added `customHeadersSupplier` field + two
`customHeaders()` builder methods |
| `DefaultAnthropicClient` | Stores the supplier; calls
`customHeadersSupplier.get()` inside `toHttpRequest()` via
`HttpRequest.Builder#addHeaders()` |
| `AnthropicChatModel.AnthropicChatModelBuilder` | Exposes
`customHeaders(Map)` and `customHeaders(Supplier<Map>)` |
| `AnthropicStreamingChatModel.AnthropicStreamingChatModelBuilder` |
Same as above |
## Tests
`AnthropicCustomHeadersTest` uses an embedded JDK `HttpServer` (no extra
dependencies) to verify headers at the HTTP level:
- Custom headers from a static `Map` reach the server
- Supplier is evaluated per-request (dynamic rotation verified across
two calls)
- Standard headers (`x-api-key`, `anthropic-version`) are not affected
- `AnthropicStreamingChatModel` sends custom headers correctly
A `null` return from the supplier is safe because
`HttpRequest.Builder#addHeaders` delegates to `isNullOrEmpty` before
iterating.
---------
Co-authored-by: Benamira05 <145583236+Benamira05@users.noreply.github.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!
-->
## Change
Adds a new `thinkingDisplay` builder option to `AnthropicChatModel` and
`AnthropicStreamingChatModel`, plumbed through to the `thinking.display`
field on `AnthropicThinking`. This lets callers request `"summarized"`
thinking content on Claude Opus 4.7 (where the server default is
`"omitted"`), while leaving behavior unchanged on earlier Opus/Sonnet
models that already default to `"summarized"`.
## General checklist
(I've updated the doc before PR given how small the change is)
<!-- Please double-check the following points and mark them like this:
[X] -->
- [X] There are no breaking changes (API, behaviour)
- [ ] 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. -->
- [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>