Skip to content

feat(dotAI): Dot AI LangChain4J - Amazon Bedrock#35242

Draft
ihoffmann-dot wants to merge 9 commits intodot-ai-langchain-azure-openaifrom
dot-ai-langchain-amazon-bedrock
Draft

feat(dotAI): Dot AI LangChain4J - Amazon Bedrock#35242
ihoffmann-dot wants to merge 9 commits intodot-ai-langchain-azure-openaifrom
dot-ai-langchain-amazon-bedrock

Conversation

@ihoffmann-dot
Copy link
Copy Markdown
Member

Summary

Adds AWS Bedrock as a supported provider. Bedrock is a managed platform that
proxies multiple model families (Anthropic, Amazon Titan, Cohere, Meta, etc.)
via a unified Converse API — a single integration covers all of them.

  • Add langchain4j-bedrock dependency
  • Add bedrock case to LangChain4jModelFactory switch
  • Implement buildBedrockChatModel using BedrockRuntimeClient with explicit or IAM role credentials
  • Implement buildBedrockEmbeddingModel with automatic Titan/Cohere dispatch by model ID prefix
  • Add embeddingInputType field to ProviderConfig (Cohere-specific; default: search_document)
  • buildBedrockImageModel throws UnsupportedOperationException (no LangChain4J support)
  • Add 4 unit tests in LangChain4jModelFactoryTest

Configuration

{
  "chat": {
    "provider": "bedrock",
    "region": "us-east-1",
    "accessKeyId": "...",
    "secretAccessKey": "...",
    "model": "anthropic.claude-3-5-sonnet-20241022-v2:0",
    "maxTokens": 16384,
    "temperature": 1.0
  },
  "embeddings": {
    "provider": "bedrock",
    "region": "us-east-1",
    "accessKeyId": "...",
    "secretAccessKey": "...",
    "model": "amazon.titan-embed-text-v2:0"
  }
}

Notes

  • If accessKeyId / secretAccessKey are omitted, credentials resolve via DefaultCredentialsProvider (IAM role, environment, ~/.aws/credentials).
  • Embedding dispatch: model IDs starting with cohere. → BedrockCohereEmbeddingModel; all others → BedrockTitanEmbeddingModel.
  • embeddingInputType is Cohere-only. Use search_document when indexing content, search_query when embedding a search query. Titan silently ignores this field.
  • Image generation via Bedrock is not available through LangChain4J. Attempting it throws UnsupportedOperationException.

Related Issue

This PR fixes #35183
EPIC: dotAI Multi-Provider Support #33970

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

❌ Issue Linking Required

This PR could not be linked to an issue. All PRs must be linked to an issue for tracking purposes.

How to fix this:

Option 1: Add keyword to PR body (Recommended - auto-removes this comment)
Edit this PR description and add one of these lines:

  • This PR fixes #123 or Fixes: #123

  • This PR closes #123 or Closes: #123

  • This PR resolves #123 or Resolves: #123

  • Other supported keywords: fix, fixed, close, closed, resolve, resolved
    Option 2: Link via GitHub UI (Note: won't clear the failed check)

  1. Go to the PR → Development section (right sidebar)

  2. Click "Link issue" and select an existing issue

  3. Push a new commit or re-run the workflow to clear the failed check
    Option 3: Use branch naming
    Create a new branch with one of these patterns:

  • 123-feature-description (number at start)

  • issue-123-feature-description (issue-number at start)

  • feature-issue-123 (issue-number anywhere)

Why is this required?

Issue linking ensures proper tracking, documentation, and helps maintain project history. It connects your code changes to the problem they solve.---

This comment was automatically generated by the issue linking workflow

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Apr 7, 2026

Claude finished @ihoffmann-dot's task in 1m 51s —— View job


PR Review: feat(dotAI) - Amazon Bedrock

  • Read changed files and diff
  • Review LangChain4jModelFactory.java (main implementation)
  • Review ProviderConfig.java
  • Review LangChain4jModelFactoryTest.java
  • Review dotCMS/pom.xml
  • Post review findings

Issues Found

1. Silent credential fallback on partial credentials — LangChain4jModelFactory.java:264

if (config.accessKeyId() != null && config.secretAccessKey() != null) {
    return StaticCredentialsProvider.create(...);
}
return DefaultCredentialsProvider.create();   // ← silent fallback

If a user sets accessKeyId but forgets secretAccessKey (or vice versa), the code silently falls back to DefaultCredentialsProvider instead of failing with a useful error. This is a misconfiguration that will be invisible until IAM role resolution fails at runtime, likely with a confusing AWS error. The check should be: if either key is non-null, require both.

Fix this →


2. Blank-string credentials bypass the null check — LangChain4jModelFactory.java:264

bedrockCredentials() guards with != null but AwsBasicCredentials.create("", "") would be called if the config values are empty strings, resulting in a cryptic AWS SDK failure rather than a clear validation error. Use the existing requireNonBlank pattern or an isBlank() check.

Fix this →


3. buildBedrockStreamingChatModel silently drops temperature and maxTokens — LangChain4jModelFactory.java:299-304

private static StreamingChatModel buildBedrockStreamingChatModel(final ProviderConfig config) {
    return BedrockStreamingChatModel.builder()
            .modelId(config.model())
            .client(bedrockAsyncClient(config))
            .build();   // temperature and maxTokens never applied
}

buildBedrockChatModel applies both temperature and maxTokens via BedrockChatRequestParameters. The streaming variant applies neither. If BedrockStreamingChatModel.builder() supports request parameters, they should be applied for consistency. If it doesn't, that limitation should be documented (a // BedrockStreamingChatModel does not support per-request parameters comment would suffice).


4. Resource leak: AWS clients are created on every call — LangChain4jModelFactory.java:271-283

bedrockClient() and bedrockAsyncClient() each call .build() on the AWS SDK builder, which allocates thread pools and HTTP connection pools. These are created fresh every time buildBedrockChatModel() / buildBedrockStreamingChatModel() is called and are never closed. In a long-running server this is a resource leak. The clients should be cached (e.g., keyed on region+credentials), or the caller should be responsible for lifecycle — but the current design makes that impossible since the clients are internal.


5. Redundant .region() in buildBedrockChatModelLangChain4jModelFactory.java:287-289

BedrockChatModel.builder()
    .modelId(config.model())
    .region(Region.of(config.region()))   // ← region already set in the client
    .client(bedrockClient(config));

bedrockClient(config) already configures the client with the same region. Setting .region() on the builder too is redundant and could cause confusion if the SDK uses one and ignores the other (or if they diverge during a future refactor). BedrockStreamingChatModel doesn't have a separate .region() setter, which makes this asymmetry visible.


6. Dead null-check in buildBedrockEmbeddingModelLangChain4jModelFactory.java:310

if (model != null && model.startsWith("cohere.")) {

By the time this line is reached, requireNonBlank(config.model(), ...) has already run and thrown if model is null/blank. The != null guard is unreachable dead code.


7. No test for buildStreamingChatModel with Bedrock

The test class covers chat, embedding, and image for all three providers, but buildStreamingChatModel with the bedrock provider has no test. Given that it's the one builder that silently drops parameters (issue 3), a test that at least confirms it constructs without throwing would be helpful.


pom.xml: langchain4j-bedrock has no explicit version because it's managed via the langchain4j-bom import in bom/application/pom.xml. That's correct per repo conventions.

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Apr 7, 2026

Claude finished @ihoffmann-dot's task in 54s —— View job


I'll analyze this and get back to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant