jamesnetherton opened a new issue, #8836:
URL: https://github.com/apache/camel-quarkus/issues/8836
## Description
When Quarkus LangChain4j (QL4J) is on the classpath and a default
`ChatModel` is configured via `quarkus.langchain4j.*` properties, QL4J's
`ChatMemoryProvider` silently leaks into Camel's `AgentWithoutMemory`, making
it stateful despite the user's explicit intent for stateless behavior.
## Root Cause
QL4J replaces `AiServices.builder()` via SPI (`AiServicesFactory`) in JVM
mode and via GraalVM `@Substitute` in native mode. When Camel calls
`AiServices.builder(AiAgentWithoutMemoryService.class)`:
1. QL4J's `AiServicesProcessor.determinedImpliedRegisterAiService()`
discovers `AiAgentWithoutMemoryService` because it has `@UserMessage` and
`@SystemMessage` annotations. The `AGENTIC_PACKAGE_PREFIX` exclusion
(`dev.langchain4j.agentic.*`) does not match Camel's package
(`org.apache.camel.component.langchain4j.agent.api`).
2. QL4J creates a synthetic `QuarkusAiServiceContext` CDI bean for this
interface. Since no explicit `chatMemoryProviderSupplier` is set on the implied
registration, it defaults to `BEAN_CHAT_MEMORY_PROVIDER_SUPPLIER` — meaning
"inject `ChatMemoryProvider` from CDI."
3. `ChatMemoryProcessor` always creates a default `@ApplicationScoped`
`ChatMemoryProvider` (`MessageWindowChatMemory`). This gets injected into the
synthetic context.
4. `QuarkusAiServiceContextFactory.create()` returns this pre-configured
context (with `ChatMemoryProvider` already set) to Camel's builder.
5. Camel's `AgentWithoutMemory.createAiAgentService()` only calls
`.chatModel(config.getChatModel())` — it never resets `chatMemoryProvider`. The
QL4J-injected `ChatMemoryProvider` survives into the built proxy.
## Impact
Since `AiAgentWithoutMemoryService` has no `@MemoryId` parameter, the memory
ID falls back to either a request-scope hash (HTTP routes) or the literal
string `"default"` (non-HTTP routes like timer, file, kafka). This causes:
- **Non-HTTP routes**: All `AgentWithoutMemory` instances across the
application share a single global chat memory. Messages from unrelated
conversations contaminate each other.
- **HTTP routes**: Per-request isolation, but `InMemoryChatMemoryStore`
entries are never evicted (memory leak).
- **All routes**: Each call sends up to 9 prior unrelated messages to the
LLM (default window size = 10), increasing token cost, latency, and producing
incorrect responses.
No error or warning is logged. The agent silently behaves differently than
its name and contract imply.
## Steps to Reproduce
1. Add `quarkus-langchain4j-ollama` (or another QL4J model provider) as a
dependency
2. Configure a default model:
```properties
quarkus.langchain4j.ollama.base-url=http://localhost:11434
quarkus.langchain4j.ollama.chat-model.model-id=llama3.2
```
3. Create an `AgentWithoutMemory` with a Camel-managed `ChatModel`:
```java
new AgentWithoutMemory(new AgentConfiguration().withChatModel(chatModel))
```
4. Send multiple unrelated messages through the agent
5. Observe that responses reference content from previous, unrelated messages
## Expected Behavior
`AgentWithoutMemory` should be stateless — each call processed independently
with no conversation history, regardless of whether QL4J is on the classpath.
## Why Current Tests Don't Catch This
The `langchain4j-agent-ql4j` integration test uses `@Identifier`-qualified
`ChatModel` beans and does not configure a default QL4J model via properties.
Without a default `ChatModel`, the CDI context bean creation fails and
`QuarkusAiServiceContextFactory` falls back to a clean empty context. The
`ChatMemoryProvider` doesn't leak — but only by accident, not by design.
## Additional Context
The `langchain4j-agent-ql4j` test README acknowledges related interference:
`RetrievalAugmentor` had to be disabled
(`cq-test.retrieval.augmentor.disabled=true`) because "Testing with
quarkus-langchain4j does not work when the RetrievalAugmentor bean is present
with scope <default>."
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]