Initial Support for the Anthropic Java SDK#5366
Initial Support for the Anthropic Java SDK#5366sobychacko wants to merge 1 commit intospring-projects:mainfrom
Conversation
ericbottard
left a comment
There was a problem hiding this comment.
Added some comments related to JSpecify and builder.
This does not constitue a thorough review of the anthropic aspects.
| /** | ||
| * Maximum number of tokens to generate in the response. | ||
| */ | ||
| @Nullable private Integer maxTokens; |
There was a problem hiding this comment.
All of those JSpecify annotations are out of place.
Should be
| @Nullable private Integer maxTokens; | |
| private @Nullable Integer maxTokens; |
| */ | ||
| public static final class Builder { | ||
|
|
||
| private final AnthropicSdkChatOptions options = new AnthropicSdkChatOptions(); |
There was a problem hiding this comment.
Builders should be re-usable. Hence, they should not act on an pre-created instance of options, otherwise if you call build(), then mutate the builder, then build() again, you actually get the same instance and the result of the first call is mutated while the user may not realise.
| @NullMarked | ||
| package org.springframework.ai.anthropicsdk.metadata; | ||
|
|
||
| import org.jspecify.annotations.NullMarked; |
| */ | ||
| private Map<String, String> customHeaders = new HashMap<>(); | ||
|
|
||
| @Nullable public String getBaseUrl() { |
There was a problem hiding this comment.
Similarly, all the method annotations are out of place.
Should be
| @Nullable public String getBaseUrl() { | |
| public @Nullable String getBaseUrl() { |
| /** | ||
| * Creates a new AnthropicSdkChatModel with default options. | ||
| */ | ||
| public AnthropicSdkChatModel() { |
There was a problem hiding this comment.
There should be only ONE constructor, which should be private.
Users construct instance via the builder.
|
@ericbottard Thanks for the review. The initial focus was to get the basic functionality done and have feature parity with the regular anthropic module for sync and async calls. I will go through this review and address them soon. Thanks again! |
|
@ericbottard Addressed most of the comments and issues you raised. Could you take a look again? Thanks! |
|
@sobychacko How should we proceed for this PR versus #5282 ? I guess we should decide which one is merged first. Edit: #5282 has been merged so please let me know if you need my inputs for the rebase. |
|
@sdeleuze I used jackson2 in this PR. I think I will make it jackson 3 based. |
|
@sdeleuze I think it might be better to wait for the jackson 3 changes with the broader upgrade in the framework. What do you think? |
6f7950e to
c7ee377
Compare
40cb8ca to
f729e83
Compare
fa7601c to
a81f788
Compare
a81f788 to
32c2346
Compare
| * @author Yanming Zhou | ||
| * @since 1.0.0 | ||
| */ | ||
| @AutoConfiguration(after = { RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, |
There was a problem hiding this comment.
This configuration only defines 2 beans, one of type AnthropicApi and one of type AnthropicChatModel (ChatModel).
None of those are defined in the configurations cited in after, so that attribute should be removed
| ToolCallingAutoConfiguration.class, SpringAiRetryAutoConfiguration.class }) | ||
| @EnableConfigurationProperties({ AnthropicChatProperties.class, AnthropicConnectionProperties.class }) | ||
| @ConditionalOnClass(AnthropicApi.class) | ||
| @AutoConfiguration(after = { ToolCallingAutoConfiguration.class }) |
There was a problem hiding this comment.
See my comment above about after
There was a problem hiding this comment.
The anthropicChatModel bean directly injects ToolCallingManager, which is provided by ToolCallingAutoConfiguration. Removing the after attribute breaks various auto-config tests since SpringAiTestAutoConfigurations.of() rely on it to include dependency configs in the test context. OpenAiSdkChatAutoConfiguration also follows the same pattern. Therefore I am keeping the after as is, unless you see further issues with that.
There was a problem hiding this comment.
This is not correct. SpringAiTestAutoConfigurations is wrong too (it adding any config that is in after to the list of configs to load is wrong and does not reflect what happens at runtime). Please remove the afters from this PR and I'll also create a PR to get rid of SpringAiTestAutoConfigurations for M3
There was a problem hiding this comment.
@ericbottard Based on our discussion on this matter, we are good here, right?
| @@ -0,0 +1,108 @@ | |||
| /* | |||
There was a problem hiding this comment.
What's with that "legacy" module?
| /** | ||
| * Builder for creating {@link AnthropicChatOptions} instances. | ||
| */ | ||
| public static final class Builder { |
| */ | ||
| class AnthropicChatOptionsTests<B extends AnthropicChatOptions.Builder<B>> | ||
| extends AbstractChatOptionsTests<AnthropicChatOptions, B> { | ||
| class AnthropicChatOptionsTests { |
32dc776 to
8462ca6
Compare
Rewrite the Anthropic integration from the ground up on the official
Anthropic Java SDK (v2.16.1), replacing the hand-rolled RestClient
implementation.
Core capabilities:
- Sync and streaming chat with typed SDK response objects
- Tool calling with JsonValue visitor pattern for schema conversion
- Streaming tool calling with partial JSON accumulation and recursive
multi-turn execution
- Multi-modal inputs (base64 images, HTTPS URLs, PDF documents)
- Extended thinking (ThinkingBlock, RedactedThinkingBlock) with
budget control and adaptive mode
- Citations across plain text, PDF, and custom content documents
with three location types (char, page, content block)
- Citation consistency validation on build to reject mixed settings
- Prompt caching with 5 strategies, configurable TTL, content length
thresholds, and multi-block system message support
- Structured output via OutputConfig with JSON schema enforcement
and effort control (LOW/MEDIUM/HIGH/MAX)
- Per-request HTTP headers for beta features and request tracking
- Claude Skills (XLSX, PPTX, DOCX, PDF) with Files API for
downloading generated documents
- disableParallelToolUse wiring into ToolChoice subtypes
- Expose underlying SDK clients via getAnthropicClient() and
getAnthropicClientAsync() for direct access to SDK features
Infrastructure:
- Builder aligned with DefaultToolCallingChatOptions.Builder using
self-type generics, mutate()/combineWith() pattern
- SDK-native retry (no Spring RetryTemplate), matching spring-ai-openai-sdk
- Raw SDK Message stored in metadata under "anthropic-response" key
- Observation/tracing support with Micrometer for both sync and
streaming paths
- Default model: claude-haiku-4-5, default max tokens: 4096
- Auto-configuration and starter modules
- Comprehensive unit tests (55+) and integration tests (35+)
- Reference documentation with configuration properties
Signed-off-by: Soby Chacko <soby.chacko@broadcom.com>
8d429ed to
8952059
Compare
|
Great contribution. Thanks @sobychacko |
Initial support for the Anthropic Java SDK. Current support in the PR includes both sync and async chat model interactions with tool calling support in both cases.