From ed9b2d2b0ba59fd976ce6b0656c5312692b872b4 Mon Sep 17 00:00:00 2001 From: Christian Tzolov Date: Tue, 30 Sep 2025 11:41:15 +0200 Subject: [PATCH] feat(anthropic): add new Claude models and update naming conventions - Add CLAUDE_SONNET_4_5 and CLAUDE_OPUS_4_1 model constants - Rename CLAUDE_OPUS_4 to CLAUDE_OPUS_4_0 and CLAUDE_SONNET_4 to CLAUDE_SONNET_4_0 for consistency - Remove deprecated legacy models CLAUDE_2_1 and CLAUDE_2 - Update test references to use renamed CLAUDE_SONNET_4_0 constant Signed-off-by: Christian Tzolov --- .../ai/anthropic/api/AnthropicApi.java | 27 +++++++++---------- .../anthropic/AnthropicPromptCachingIT.java | 22 +++++++-------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/api/AnthropicApi.java b/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/api/AnthropicApi.java index d9687a57c2a..eae45fb6e78 100644 --- a/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/api/AnthropicApi.java +++ b/models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/api/AnthropicApi.java @@ -275,15 +275,25 @@ private void addDefaultHeadersIfMissing(HttpHeaders headers) { public enum ChatModel implements ChatModelDescription { // @formatter:off + /** + * The claude-sonnet-4-5 model. + */ + CLAUDE_SONNET_4_5("claude-sonnet-4-5"), + + /** + * The claude-opus-4-1 model. + */ + CLAUDE_OPUS_4_1("claude-opus-4-1"), + /** * The claude-opus-4-0 model. */ - CLAUDE_OPUS_4("claude-opus-4-0"), + CLAUDE_OPUS_4_0("claude-opus-4-0"), /** * The claude-sonnet-4-0 model. */ - CLAUDE_SONNET_4("claude-sonnet-4-0"), + CLAUDE_SONNET_4_0("claude-sonnet-4-0"), /** * The claude-3-7-sonnet-latest model. @@ -313,18 +323,7 @@ public enum ChatModel implements ChatModelDescription { /** * The CLAUDE_3_HAIKU */ - CLAUDE_3_HAIKU("claude-3-haiku-20240307"), - - // Legacy models - /** - * The CLAUDE_2_1 (Deprecated. To be removed on July 21, 2025) - */ - CLAUDE_2_1("claude-2.1"), - - /** - * The CLAUDE_2_0 (Deprecated. To be removed on July 21, 2025) - */ - CLAUDE_2("claude-2.0"); + CLAUDE_3_HAIKU("claude-3-haiku-20240307"); // @formatter:on diff --git a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicPromptCachingIT.java b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicPromptCachingIT.java index 22459ca2937..3ed96e5a17d 100644 --- a/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicPromptCachingIT.java +++ b/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicPromptCachingIT.java @@ -101,7 +101,7 @@ void shouldCacheSystemMessageOnly() { String systemPrompt = loadPrompt("system-only-cache-prompt.txt"); AnthropicChatOptions options = AnthropicChatOptions.builder() - .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4.getValue()) + .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_0.getValue()) .cacheOptions(AnthropicCacheOptions.builder().strategy(AnthropicCacheStrategy.SYSTEM_ONLY).build()) .maxTokens(150) .temperature(0.3) @@ -142,7 +142,7 @@ void shouldCacheSystemAndTools() { MockWeatherService weatherService = new MockWeatherService(); AnthropicChatOptions options = AnthropicChatOptions.builder() - .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4.getValue()) + .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_0.getValue()) .cacheOptions(AnthropicCacheOptions.builder().strategy(AnthropicCacheStrategy.SYSTEM_AND_TOOLS).build()) .maxTokens(200) .temperature(0.3) @@ -233,7 +233,7 @@ void shouldCacheConversationHistory() { String response = chatClient.prompt() .user("What career advice would you give me based on our conversation?") .options(AnthropicChatOptions.builder() - .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4.getValue()) + .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_0.getValue()) .cacheOptions( AnthropicCacheOptions.builder().strategy(AnthropicCacheStrategy.CONVERSATION_HISTORY).build()) .maxTokens(200) @@ -258,7 +258,7 @@ void shouldRespectMinLengthForSystemCaching() { String systemPrompt = loadPrompt("system-only-cache-prompt.txt"); AnthropicChatOptions options = AnthropicChatOptions.builder() - .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4.getValue()) + .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_0.getValue()) .cacheOptions(AnthropicCacheOptions.builder() .strategy(AnthropicCacheStrategy.SYSTEM_ONLY) // Set min length above actual system prompt length to prevent caching @@ -287,7 +287,7 @@ void shouldRespectMinLengthForUserHistoryCaching() { // Set USER min length high so caching should not apply AnthropicChatOptions noCacheOptions = AnthropicChatOptions.builder() - .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4.getValue()) + .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_0.getValue()) .cacheOptions(AnthropicCacheOptions.builder() .strategy(AnthropicCacheStrategy.CONVERSATION_HISTORY) .messageTypeMinContentLength(MessageType.USER, userMessage.length() + 1) @@ -305,7 +305,7 @@ void shouldRespectMinLengthForUserHistoryCaching() { // Now allow caching by lowering the USER min length AnthropicChatOptions cacheOptions = AnthropicChatOptions.builder() - .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4.getValue()) + .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_0.getValue()) .cacheOptions(AnthropicCacheOptions.builder() .strategy(AnthropicCacheStrategy.CONVERSATION_HISTORY) .messageTypeMinContentLength(MessageType.USER, userMessage.length() - 1) @@ -334,7 +334,7 @@ void shouldRespectAllButLastUserMessageForUserHistoryCaching() { // The combined length of the first two USER messages exceeds the min length, // so caching should apply AnthropicChatOptions cacheOptions = AnthropicChatOptions.builder() - .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4.getValue()) + .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_0.getValue()) .cacheOptions(AnthropicCacheOptions.builder() .strategy(AnthropicCacheStrategy.CONVERSATION_HISTORY) .messageTypeMinContentLength(MessageType.USER, userMessage.length()) @@ -357,7 +357,7 @@ void shouldHandleExtendedTtlCaching() { String systemPrompt = loadPrompt("extended-ttl-cache-prompt.txt"); AnthropicChatOptions options = AnthropicChatOptions.builder() - .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4.getValue()) + .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_0.getValue()) .cacheOptions(AnthropicCacheOptions.builder() .strategy(AnthropicCacheStrategy.SYSTEM_ONLY) .messageTypeTtl(MessageType.SYSTEM, AnthropicCacheTtl.ONE_HOUR) @@ -398,7 +398,7 @@ void shouldNotCacheWithNoneStrategy() { String systemPrompt = "You are a helpful assistant."; AnthropicChatOptions options = AnthropicChatOptions.builder() - .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4.getValue()) + .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_0.getValue()) .cacheOptions(AnthropicCacheOptions.builder().strategy(AnthropicCacheStrategy.NONE).build()) .maxTokens(50) .temperature(0.3) @@ -428,7 +428,7 @@ void shouldHandleMultipleCacheStrategiesInSession() { responses.add(this.chatModel.call(new Prompt( List.of(new SystemMessage("You are a math tutor."), new UserMessage("What is calculus?")), AnthropicChatOptions.builder() - .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4.getValue()) + .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_0.getValue()) .cacheOptions(AnthropicCacheOptions.builder().strategy(AnthropicCacheStrategy.SYSTEM_ONLY).build()) .maxTokens(100) .build()))); @@ -436,7 +436,7 @@ void shouldHandleMultipleCacheStrategiesInSession() { // Second: No caching responses.add(this.chatModel.call(new Prompt(List.of(new UserMessage("What's 5+5?")), AnthropicChatOptions.builder() - .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4.getValue()) + .model(AnthropicApi.ChatModel.CLAUDE_SONNET_4_0.getValue()) .cacheOptions(AnthropicCacheOptions.builder().strategy(AnthropicCacheStrategy.NONE).build()) .maxTokens(50) .build())));