Federico Mariani created CAMEL-23945:
----------------------------------------

             Summary: camel-langchain4j-agent: producer race on shared agent 
field in agentFactory mode (fix needed on camel-4.18.x)
                 Key: CAMEL-23945
                 URL: https://issues.apache.org/jira/browse/CAMEL-23945
             Project: Camel
          Issue Type: Bug
          Components: camel-langchain4j-agent
    Affects Versions: 4.18.0, 4.15.0, 4.20.0
            Reporter: Federico Mariani
         Attachments: LangChain4jAgentFactoryConcurrencyTest.java

On 4.15.0 through 4.20.x (and the current {{camel-4.18.x}} branch), 
{{LangChain4jAgentProducer.process()}} writes the agent resolved by the 
{{AgentFactory}} to a *shared instance field* on every exchange and then 
re-reads that field twice:

{code:java}
if (agentFactory != null) {
    agent = agentFactory.createAgent(exchange);   // field write per exchange
}
AiAgentBody<?> aiAgentBody = agent.processBody(messagePayload, exchange);  // 
field re-read
...
String response = agent.chat(aiAgentBody, toolProvider);                  // 
field re-read again
{code}

A producer is a singleton per endpoint and {{process()}} must be thread-safe. 
With two concurrent exchanges selecting different agents (e.g. a multi-agent 
{{AgentFactory}} dispatching by header), one thread's write can land between 
another thread's write and reads: the message is processed by the *wrong agent* 
(wrong model, system prompt, guardrails and chat memory — the conversation turn 
is persisted into the wrong agent's memory store). Because there are two 
independent field reads, a single exchange can even {{processBody}} with one 
agent and {{chat}} with another. The window is tiny so it does not reproduce in 
demos, but under sustained concurrent load it is statistically inevitable.

*Status on main*: fixed incidentally by CAMEL-23697 (commit {{03d8361bbb74}}, 
4.21.0), which replaced the pattern with a local read: {{Agent agent = 
agentFactory != null ? agentFactory.createAgent(exchange) : this.agent;}} — so 
4.21.0+ is not affected.

*Requested fix*: backport the local-variable pattern (one line) to the 
{{camel-4.18.x}} LTS branch. Introduced by CAMEL-22397 (commit 
{{91ad52d80fb0}}, first released in 4.15.0).

Attached reproducer {{LangChain4jAgentFactoryConcurrencyTest}} compiles against 
*camel-4.18.x* (not main, where the API changed with the fix): it makes the 
race deterministic by blocking agent A inside {{processBody()}} — between the 
producer's field write and its {{chat()}} field re-read — while a second 
exchange selects agent B. The exchange that asked for agent A is answered by 
agent B.

_This issue was drafted by Claude Code on behalf of Federico Mariani._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to