diff --git a/dotCMS/pom.xml b/dotCMS/pom.xml index 76a37ab49658..1d39b69cdeac 100644 --- a/dotCMS/pom.xml +++ b/dotCMS/pom.xml @@ -514,6 +514,11 @@ dev.langchain4j langchain4j-open-ai-official + + + dev.langchain4j + langchain4j-anthropic + dev.langchain4j diff --git a/dotCMS/src/main/java/com/dotcms/ai/client/langchain4j/AnthropicModelProviderStrategy.java b/dotCMS/src/main/java/com/dotcms/ai/client/langchain4j/AnthropicModelProviderStrategy.java new file mode 100644 index 000000000000..b471c4891543 --- /dev/null +++ b/dotCMS/src/main/java/com/dotcms/ai/client/langchain4j/AnthropicModelProviderStrategy.java @@ -0,0 +1,82 @@ +package com.dotcms.ai.client.langchain4j; + +import com.dotmarketing.util.Logger; +import dev.langchain4j.model.anthropic.AnthropicChatModel; +import dev.langchain4j.model.anthropic.AnthropicStreamingChatModel; +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.chat.StreamingChatModel; +import dev.langchain4j.model.embedding.EmbeddingModel; +import dev.langchain4j.model.image.ImageModel; + +import java.time.Duration; + +/** + * {@link ModelProviderStrategy} implementation for Anthropic (Claude). + * + *

Talks directly to the Anthropic Messages API with an API key — distinct from + * accessing Claude models through AWS Bedrock. The {@code endpoint} config field + * overrides the default base URL if set (useful for proxies/gateways). + * + *

Model IDs use the Anthropic form, e.g. {@code claude-sonnet-4-6}, + * {@code claude-opus-4-8}, {@code claude-haiku-4-5}. + * + *

Supports chat (streaming and non-streaming) only. Anthropic does not offer + * embeddings or image-generation APIs. + */ +class AnthropicModelProviderStrategy implements ModelProviderStrategy { + + @Override + public String providerName() { + return "anthropic"; + } + + @Override + public ChatModel buildChatModel(final ProviderConfig config, final String modelType) { + validate(config, modelType); + final AnthropicChatModel.AnthropicChatModelBuilder builder = AnthropicChatModel.builder() + .apiKey(config.apiKey()) + .modelName(config.model()); + if (config.endpoint() != null) builder.baseUrl(config.endpoint()); + if (config.temperature() != null) builder.temperature(config.temperature()); + if (config.maxTokens() != null) builder.maxTokens(config.maxTokens()); + if (config.maxRetries() != null) builder.maxRetries(config.maxRetries()); + if (config.timeout() != null) builder.timeout(Duration.ofSeconds(config.timeout())); + return builder.build(); + } + + @Override + public StreamingChatModel buildStreamingChatModel(final ProviderConfig config, final String modelType) { + validate(config, modelType); + final AnthropicStreamingChatModel.AnthropicStreamingChatModelBuilder builder = + AnthropicStreamingChatModel.builder() + .apiKey(config.apiKey()) + .modelName(config.model()); + if (config.maxRetries() != null) { + Logger.warn(AnthropicModelProviderStrategy.class, + "maxRetries is not supported by the Anthropic streaming chat model and will be ignored"); + } + if (config.endpoint() != null) builder.baseUrl(config.endpoint()); + if (config.temperature() != null) builder.temperature(config.temperature()); + if (config.maxTokens() != null) builder.maxTokens(config.maxTokens()); + if (config.timeout() != null) builder.timeout(Duration.ofSeconds(config.timeout())); + return builder.build(); + } + + @Override + public EmbeddingModel buildEmbeddingModel(final ProviderConfig config, final String modelType) { + throw new UnsupportedOperationException( + "Embeddings are not supported by Anthropic (no embeddings API)"); + } + + @Override + public ImageModel buildImageModel(final ProviderConfig config, final String modelType) { + throw new UnsupportedOperationException( + "Image generation is not supported by Anthropic (no image API)"); + } + + private void validate(final ProviderConfig config, final String modelType) { + ModelProviderStrategy.requireNonBlank(config.model(), "model", modelType); + ModelProviderStrategy.requireNonBlank(config.apiKey(), "apiKey", modelType); + } + +} diff --git a/dotCMS/src/main/java/com/dotcms/ai/client/langchain4j/LangChain4jModelFactory.java b/dotCMS/src/main/java/com/dotcms/ai/client/langchain4j/LangChain4jModelFactory.java index 2ee704514bc8..8175f09c0ba8 100644 --- a/dotCMS/src/main/java/com/dotcms/ai/client/langchain4j/LangChain4jModelFactory.java +++ b/dotCMS/src/main/java/com/dotcms/ai/client/langchain4j/LangChain4jModelFactory.java @@ -14,15 +14,16 @@ * To add a new provider, create a class that implements {@link ModelProviderStrategy} * and add an instance to {@link #STRATEGIES}. No other class needs to change. * - *

Supported providers: {@code openai}, {@code azure_openai}, {@code vertex_ai} - *

Note: {@code vertex_ai} supports chat only; embeddings and image are not available via LangChain4J. + *

Supported providers: {@code openai}, {@code azure_openai}, {@code vertex_ai}, {@code anthropic} + *

Note: {@code vertex_ai} and {@code anthropic} support chat only; embeddings and image are not available via LangChain4J. */ public class LangChain4jModelFactory { static final List STRATEGIES = List.of( new OpenAiModelProviderStrategy(), new AzureOpenAiModelProviderStrategy(), - new VertexAiModelProviderStrategy() + new VertexAiModelProviderStrategy(), + new AnthropicModelProviderStrategy() ); private LangChain4jModelFactory() {} diff --git a/dotCMS/src/main/java/com/dotcms/ai/client/langchain4j/ProviderConfig.java b/dotCMS/src/main/java/com/dotcms/ai/client/langchain4j/ProviderConfig.java index ee9b416a686e..cf91277f6f09 100644 --- a/dotCMS/src/main/java/com/dotcms/ai/client/langchain4j/ProviderConfig.java +++ b/dotCMS/src/main/java/com/dotcms/ai/client/langchain4j/ProviderConfig.java @@ -18,7 +18,7 @@ * *

Common fields (all providers): *

* + *

Anthropic (chat only — Anthropic has no embeddings or image APIs): + *

+ * *

Google Vertex AI (chat only — embeddings and image not supported by this integration): *