Skip to content

CAMEL-23954: Add langchain4j-agent moderation support - #26174

Open
atiaomar1978-hub wants to merge 5 commits into
apache:mainfrom
atiaomar1978-hub:feature/CAMEL-23954-langchain4j-agent-moderation
Open

CAMEL-23954: Add langchain4j-agent moderation support#26174
atiaomar1978-hub wants to merge 5 commits into
apache:mainfrom
atiaomar1978-hub:feature/CAMEL-23954-langchain4j-agent-moderation

Conversation

@atiaomar1978-hub

@atiaomar1978-hub atiaomar1978-hub commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Description

Implements CAMEL-23954: content moderation support for camel-langchain4j-agent.

When AgentConfiguration.withModerationModel(ModerationModel) is configured, Camel pre-moderates the user message before invoking the chat model. Flagged input raises ModerationException before tools run or conversation memory is updated.

Changes

  • AgentConfiguration.withModerationModel(ModerationModel) — fluent configuration for a LangChain4j moderation model
  • ModerationSupport — public Camel-owned pre-check (fail-closed; uses ModerationModel.moderate(String))
  • CamelLangChain4jAgentModerationFlagged header — set to true on moderation failure (cause chain aware)
  • GenAiErrorSupport — classifies ModerationException as VALIDATION
  • Tests — API + component coverage including chat model not invoked, memory provider not accessed, null verdict fail-closed, duplicate() field copy, GenAI error category
  • Docs — pre-moderation semantics in component and guardrails pages; xref uses others: module prefix

Example

AgentConfiguration configuration = new AgentConfiguration()
    .withChatModel(chatModel)
    .withModerationModel(openAiModerationModel);

onException(ModerationException.class)
    .handled(true)
    .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(422))
    .setBody(constant("Sorry, your message violates our usage policy."));

from("platform-http:/support/chat")
    .to("langchain4j-agent:support?agentConfiguration=#supportAgentConfig");

Testing

./mvnw -pl components/camel-ai/camel-langchain4j-agent-api,components/camel-ai/camel-langchain4j-agent,components/camel-ai/camel-ai-observability-api -am test \
  -Dtest=AgentModerationTest,AgentConfigurationTest,LangChain4jAgentModerationTest,GenAiErrorSupportTest

All tests pass.

Target

  • I checked that the commit is targeting the correct branch (Camel 4 uses the main branch)

Tracking

Apache Camel coding standards and style

  • Each commit has a meaningful subject line and body
  • Code formatted; generated catalog metadata updated

AI-assisted contributions

  • Commits include Co-authored-by: Cursor <cursoragent@cursor.com> trailers

AI-generated PR description on behalf of atiaomar1978-hub

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Bugbot review

Severity: medium — Guardrails xref missing module prefix

components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc:184

The Content moderation section linked to xref:langchain4j-agent-guardrails.adoc#_content_moderation, but the guardrails page is published under the others component module; the same doc already uses xref:others:langchain4j-agent-guardrails.adoc elsewhere.

Status: Fixed in a1e29f0914f — now uses xref:others:langchain4j-agent-guardrails.adoc#_content_moderation.


AI-generated Bugbot review summary on behalf of atiaomar1978-hub

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Grok review — initial findings (REQUEST CHANGES)

The rewrite to Camel-owned pre-moderation is the correct architecture. LangChain4j @Moderate runs in parallel with the LLM and only checks after memory/tools — Camel pre-moderation gates before chat.

High severity (addressed)

  1. Fail-open on missing verdictModerationSupport previously returned when response or moderation() was null. Fixed: fail-closed with ModerationException and flagged=true; runtime failures from the model are wrapped similarly.

  2. Call moderate(...), not doModerate(...)Fixed: uses ModerationModel.moderate(String) public API (listeners + model name).

Medium severity (addressed)

  1. Stale @Moderate docsFixed: javadocs and component docs describe pre-moderation; removed @Moderate / configureBuilder claims.

  2. Package-private ModerationSupportFixed: class is now public for custom Agent implementations.

  3. Header semanticsFixed: CamelLangChain4jAgentModerationFlagged metadata clarifies failure-only boolean; producer walks cause chain; docs note ${exception.moderation} for category details.

  4. GenAiErrorSupport mappingFixed: ModerationExceptionVALIDATION; added cause-chain and apply() tests.

Test gaps (addressed)

  • Null / empty moderation response → fail-closed test added
  • Memory provider not accessed when input flagged
  • duplicate() includes moderationModel
  • @BeforeEach clears shared exchange reference in route tests

AI-generated Grok review summary on behalf of atiaomar1978-hub

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Review follow-up — fixes applied

Thanks for the reviews. Actionable findings were addressed in commits 7f5e6bf4d00 and a1e29f0914f.

Architecture

  • Removed duplicated @Moderate service interfaces (AiAgentWithMemoryModeratedService, AiAgentWithoutMemoryModeratedService)
  • Added public ModerationSupport.moderateUserMessage(...) called from AgentWithMemory / AgentWithoutMemory before AiServices chat
  • Flagged input never reaches chat model, tools, or memory

Producer / observability

  • CamelLangChain4jAgentModerationFlagged header set on failure (cause chain aware)
  • GenAiErrorSupport classifies ModerationException as VALIDATION

Tests (all passing)

./mvnw -pl components/camel-ai/camel-langchain4j-agent-api,components/camel-ai/camel-langchain4j-agent,components/camel-ai/camel-ai-observability-api -am test \
  -Dtest=AgentModerationTest,AgentConfigurationTest,LangChain4jAgentModerationTest,GenAiErrorSupportTest

Please re-review when convenient.


AI-generated comment on behalf of atiaomar1978-hub

@atiaomar1978-hub
atiaomar1978-hub marked this pull request as ready for review September 8, 2026 01:30

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this — the moderation feature itself is well-built: the pre-check semantics are the right call, the tests are thorough, and both catalog mirror copies were properly regenerated. I built the branch locally and all the new unit tests pass (AgentModerationTest 11/11, LangChain4jAgentModerationTest 4/4, GenAiErrorSupportTest 13/13, AgentConfigurationTest 31/31; the only failures were Ollama ITs failing on missing Docker infra, unrelated to this PR).

Two stray artifacts need to come out before this can go in, plus a behavioural concern about how moderation-provider outages are reported. Details inline; summary below.

Blocking

  1. csimple re-added to core/camel-core-model/.../model.properties — unrelated to moderation and partially reverts 9e8d8e4fe979 ("Removal of csimple language"). See inline comment.
  2. AbstractAgent.configureBuilder signature widened from AiServices<S> to AiServices<?> — leftover from the abandoned @Moderate approach in 563da0b, and a source-incompatible change to a protected extension point. See inline comment.

Significant

  1. Infrastructure failures of the moderation provider are labelled as content policy violations (ModerationSupport.java). See inline comment.
  2. No test for the moderation-model-throws path. AgentModerationTest covers flagged / clean / not-configured / null-verdict / empty-message, but not a ModerationModel that throws — which is exactly the branch with the behaviour questioned in (3). Per CLAUDE.md "Code Quality", new functionality needs test coverage.
  3. FQCN usage in test code — 7 occurrences across the two new test classes. CLAUDE.md "Import Style" forbids fully-qualified names and states the rule applies to test code; the OpenRewrite pass in CI rewrites them and the uncommitted-changes check then fails. See inline comments.

Minor

  1. The AgentWithMemory / AgentWithoutMemory refactor strips explanatory comments (// Multi-modal message with content, // Text-only message, the createAiAgentService javadoc) and reshapes if/else into early-return. That churn is unrelated to the feature and makes the diff harder to review — could it be dropped?
  2. FlaggingModerationModel is duplicated verbatim in both modules. Acceptable if there is no shared test-jar, but worth a note.

Questions

  1. Why not LangChain4j's native AiServices.moderationModel(...) + @Moderate? It does exist in 1.19.0, and 563da0b used it before 7f5e6bf replaced it. I believe the reason is that native moderation runs concurrently with the LLM call, so it cannot prevent tool execution or memory writes, whereas this pre-check can — which is genuinely the stronger guarantee. But that rationale is nowhere in the PR description, and every reviewer will ask. Could you state it explicitly in the description so the decision is on record?
  2. Ordering vs input guardrails: moderation now runs strictly before input guardrails (which execute inside the AiServices call). Intentional? If so, a row in the guardrails page's "Guardrail Behavior Summary" table would make the ordering explicit.

Verified as correct

  • Both mirrored catalog copies regenerated (component JSON + catalog JSON, both .adoc pairs).
  • others:langchain4j-agent-guardrails.adoc matches the existing prefix at langchain4j-agent-component.adoc:1257; the #_content_moderation fragment matches the auto-generated id for === Content Moderation, with no explicit [[anchor]] block.
  • Commit subjects follow CAMEL-XXXX: ...; AI co-authorship trailers present.
  • No upgrade-guide entry — correct, this is a new feature and the guide is migration-only.
  • @since 4.23 on the new public methods; the new dependency is test-scope only.
  • ModerationModel.moderate(String) is not deprecated in 1.19.0.

Scope note: this is a rules-and-conventions review against the project's contribution rules. It does not replace CodeRabbit, Sourcery, or SonarCloud.

Claude Code on behalf of davsclaus

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

✅ Generated files are up to date

An earlier CI run reported uncommitted generated changes; the latest run no longer does.

@davsclaus
davsclaus force-pushed the feature/CAMEL-23954-langchain4j-agent-moderation branch from e47d7cd to 9ff0631 Compare September 8, 2026 21:02
cursoragent and others added 4 commits September 9, 2026 08:06
- Add AgentConfiguration.withModerationModel(ModerationModel)
- Use moderated AiServices interfaces with @moderate when configured
- Wire moderationModel in AbstractAgent.configureBuilder()
- Surface ModerationException details on exchange headers
- Add AgentModerationTest and LangChain4jAgentModerationTest
- Document content moderation in component and guardrails docs

Co-authored-by: Cursor Agent <noreply@cursor.com>
Replace duplicated @moderate service interfaces with Camel-owned
pre-moderation via ModerationSupport so flagged input is rejected
before the chat model, tools, or memory are updated.

- Add AgentConfiguration.withModerationModel(ModerationModel)
- Set CamelLangChain4jAgentModerationFlagged header on failure
- Classify ModerationException as GenAiErrorCategory.VALIDATION
- Expand API and component moderation tests
- Document pre-moderation semantics in component and guardrails docs

Co-authored-by: Cursor <cursoragent@cursor.com>
- Fail closed when moderation returns no verdict or throws
- Use ModerationModel.moderate(String) public API with error wrapping
- Make ModerationSupport public for custom Agent implementations
- Walk cause chain when setting MODERATION_FLAGGED header
- Fix guardrails xref module prefix and refresh header metadata
- Expand tests for null verdict, memory provider skip, GenAI errors

Co-authored-by: Cursor <cursoragent@cursor.com>
- Remove stale csimple re-addition from model.properties
- Restore AbstractAgent.configureBuilder(AiServices<S>) signature
- Rethrow moderation provider failures instead of wrapping as flagged
- Fail closed on missing verdict without marking input as flagged
- Fix FQCN usage in moderation tests and add provider failure tests
- Document moderation ordering vs guardrails and fix component doc wording

Co-authored-by: Cursor <cursoragent@cursor.com>
@davsclaus
davsclaus force-pushed the feature/CAMEL-23954-langchain4j-agent-moderation branch from 9ff0631 to 490b10d Compare September 9, 2026 06:06
@github-actions github-actions Bot removed the dsl label Sep 9, 2026
@github-actions github-actions Bot added the dsl label Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • catalog/camel-catalog
  • components/camel-ai/camel-ai-observability-api
  • components/camel-ai/camel-langchain4j-agent-api
  • components/camel-ai/camel-langchain4j-agent
  • dsl/camel-endpointdsl

ℹ️ Dependent modules were not tested because the total number of affected modules exceeded the threshold (50). Use the test-dependents label to force testing all dependents.


🔬 Scalpel shadow comparison — Scalpel: 74 tested, 25 compile-only — current: 72 all tested

Maveniverse Scalpel detected 99 affected modules (current approach: 72).

⚠️ Modules only in Scalpel (27)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

Skip-tests mode would test 74 modules (5 direct + 69 downstream), skip tests for 25 (generated code, meta-modules)

Modules Scalpel would test (74)
  • camel-a2a
  • camel-ai-observability
  • camel-ai-observability-api
  • camel-as2
  • camel-catalog
  • camel-clickup
  • camel-consul
  • camel-core-all
  • camel-csv
  • camel-endpointdsl
  • camel-fhir
  • camel-groovy
  • camel-hazelcast
  • camel-hl7
  • camel-ibm-watsonx-ai
  • camel-iso8583
  • camel-java-joor-dsl
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-jetty
  • camel-jsonpath
  • camel-kamelet
  • camel-kamelet-main-support
  • camel-knative-http
  • camel-langchain4j-agent
  • camel-langchain4j-agent-api
  • camel-langchain4j-chat
  • camel-langchain4j-embeddings
  • camel-langchain4j-embeddingstore
  • camel-launcher-container
  • camel-mail
  • camel-mail-microsoft-oauth
  • camel-main
  • camel-maven-plugin
  • camel-mcp-server
  • camel-micrometer-prometheus
  • camel-microprofile-health
  • camel-netty
  • camel-netty-http
  • camel-oauth
  • camel-observability-services
  • camel-once
  • camel-openai
  • camel-openapi-validator
  • camel-platform-http-main
  • camel-platform-http-vertx
  • camel-plc4x
  • camel-pubnub
  • camel-quickfix
  • camel-rest-openapi
  • camel-restdsl-openapi-plugin
  • camel-salesforce
  • camel-salesforce-codegen
  • camel-salesforce-maven-plugin
  • camel-spring-ai-chat
  • camel-spring-main
  • camel-state-store
  • camel-syslog
  • camel-telegram
  • camel-test-main-junit5
  • camel-test-main-junit6
  • camel-vertx-websocket
  • camel-webhook
  • camel-whatsapp
  • camel-xml-io-dsl
  • camel-xml-jaxb-dsl
  • camel-xml-jaxb-dsl-test-definition
  • camel-xml-jaxb-dsl-test-spring
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin
  • camel-zookeeper
Modules with tests skipped (25)
  • apache-camel
  • camel-allcomponents
  • camel-catalog-console
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

⚠️ Some tests are disabled on GitHub Actions (@DisabledIfSystemProperty(named = "ci.env.name")) and require manual verification:

  • components/camel-ai/camel-langchain4j-agent: 16 test(s) disabled on GitHub Actions
Build reactor — dependencies compiled but only changed modules were tested (5 modules, 52.3s total)

Total reactor time: 52.3s

Module Duration Status
Camel :: AI :: LangChain4j :: Agent 15.2s SUCCESS
Camel :: Catalog :: Camel Catalog 14.8s SUCCESS
Camel :: AI :: LangChain4j :: Agent :: API 11.1s SUCCESS
Camel :: AI :: Observability API 11.0s SUCCESS
Camel :: Endpoint DSL n/a

Top 20 slowest modules:

  • Camel :: AI :: LangChain4j :: Agent (15.2s)
  • Camel :: Catalog :: Camel Catalog (14.8s)
  • Camel :: AI :: LangChain4j :: Agent :: API (11.1s)
  • Camel :: AI :: Observability API (11.0s)

⚙️ View full build and test results

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants