This is an automated email from the ASF dual-hosted git repository.
zbendhiba pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 03d8361bbb74 CAMEL-23697: Add outputClass parameter for structured
output in lang… (#23996)
03d8361bbb74 is described below
commit 03d8361bbb749e56986270f8d33f326b7cf6184d
Author: Zineb BENDHIBA <[email protected]>
AuthorDate: Wed Jun 17 15:57:55 2026 +0200
CAMEL-23697: Add outputClass parameter for structured output in lang…
(#23996)
* CAMEL-23697: Add outputClass parameter for structured output in
langchain4j-agent
Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]>
---
.../catalog/components/langchain4j-agent.json | 22 +--
.../langchain4j/agent/api/AbstractAgent.java | 2 +-
.../agent/LangChain4jAgentComponentConfigurer.java | 8 ++
.../LangChain4jAgentConfigurationConfigurer.java | 6 +
.../agent/LangChain4jAgentEndpointConfigurer.java | 8 ++
.../agent/LangChain4jAgentEndpointUriFactory.java | 3 +-
.../langchain4j/agent/langchain4j-agent.json | 22 +--
.../src/main/docs/langchain4j-agent-component.adoc | 68 +++++++++
.../agent/LangChain4jAgentConfiguration.java | 24 +++-
.../agent/LangChain4jAgentProducer.java | 96 +++++++++----
.../integration/LangChain4jAgentOutputClassIT.java | 152 +++++++++++++++++++++
.../LangChain4jAgentStructuredOutputTest.java | 146 ++++++++++++++++++++
.../agent/pojos/CarRentalRecommendation.java | 126 +++++++++++++++++
.../Langchain4jAgentComponentBuilderFactory.java | 29 +++-
.../LangChain4jAgentEndpointBuilderFactory.java | 48 ++++++-
15 files changed, 705 insertions(+), 55 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-agent.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-agent.json
index d9d41b08123e..7573c35232aa 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-agent.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-agent.json
@@ -28,12 +28,13 @@
"agentConfiguration": { "index": 1, "kind": "property", "displayName":
"Agent Configuration", "group": "producer", "label": "", "required": false,
"type": "object", "javaType":
"org.apache.camel.component.langchain4j.agent.api.AgentConfiguration",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Agent [...]
"agentFactory": { "index": 2, "kind": "property", "displayName": "Agent
Factory", "group": "producer", "label": "", "required": false, "type":
"object", "javaType":
"org.apache.camel.component.langchain4j.agent.api.AgentFactory", "deprecated":
false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "The agent factory to us
[...]
"configuration": { "index": 3, "kind": "property", "displayName":
"Configuration", "group": "producer", "label": "", "required": false, "type":
"object", "javaType":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"deprecated": false, "autowired": false, "secret": false, "description": "The
configuration" },
- "jsonSchema": { "index": 4, "kind": "property", "displayName": "Json
Schema", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "supportFileReference": true,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "JSON schema for
structured output validat [...]
+ "jsonSchema": { "index": 4, "kind": "property", "displayName": "Json
Schema", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "supportFileReference": true,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "JSON schema for
structured output validat [...]
"lazyStartProducer": { "index": 5, "kind": "property", "displayName":
"Lazy Start Producer", "group": "producer", "label": "producer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether the producer should be started lazy (on the first message). By
starting lazy you can use this to allow CamelContext and routes to startup in
situations where a producer may otherwise fail [...]
- "tags": { "index": 6, "kind": "property", "displayName": "Tags", "group":
"producer", "label": "", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Tags for discovering and
calling Camel route tools" },
- "autowiredEnabled": { "index": 7, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching t [...]
- "mcpClients": { "index": 8, "kind": "property", "displayName": "Mcp
Clients", "group": "advanced", "label": "advanced", "required": false, "type":
"array", "javaType": "java.util.List<dev.langchain4j.mcp.client.McpClient>",
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Pre-built MCP (Model
Context Protocol) client insta [...]
- "mcpServer": { "index": 9, "kind": "property", "displayName": "Mcp
Server", "group": "advanced", "label": "advanced", "required": false, "type":
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>",
"prefix": "mcpServer.", "multiValue": true, "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "MCP server [...]
+ "outputClass": { "index": 6, "kind": "property", "displayName": "Output
Class", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.Class<java.lang.Object>", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Java class to use for
structured output. Camel deriv [...]
+ "tags": { "index": 7, "kind": "property", "displayName": "Tags", "group":
"producer", "label": "", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Tags for discovering and
calling Camel route tools" },
+ "autowiredEnabled": { "index": 8, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching t [...]
+ "mcpClients": { "index": 9, "kind": "property", "displayName": "Mcp
Clients", "group": "advanced", "label": "advanced", "required": false, "type":
"array", "javaType": "java.util.List<dev.langchain4j.mcp.client.McpClient>",
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Pre-built MCP (Model
Context Protocol) client insta [...]
+ "mcpServer": { "index": 10, "kind": "property", "displayName": "Mcp
Server", "group": "advanced", "label": "advanced", "required": false, "type":
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>",
"prefix": "mcpServer.", "multiValue": true, "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "MCP server [...]
},
"headers": {
"CamelLangChain4jAgentSystemMessage": { "index": 0, "kind": "header",
"displayName": "", "group": "producer", "label": "", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The system prompt.", "constantName":
"org.apache.camel.component.langchain4j.agent.api.Headers#SYSTEM_MESSAGE" },
@@ -48,10 +49,11 @@
"agent": { "index": 1, "kind": "parameter", "displayName": "Agent",
"group": "producer", "label": "", "required": false, "type": "object",
"javaType": "org.apache.camel.component.langchain4j.agent.api.Agent",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "The agent to use for the
component" },
"agentConfiguration": { "index": 2, "kind": "parameter", "displayName":
"Agent Configuration", "group": "producer", "label": "", "required": false,
"type": "object", "javaType":
"org.apache.camel.component.langchain4j.agent.api.AgentConfiguration",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Agen [...]
"agentFactory": { "index": 3, "kind": "parameter", "displayName": "Agent
Factory", "group": "producer", "label": "", "required": false, "type":
"object", "javaType":
"org.apache.camel.component.langchain4j.agent.api.AgentFactory", "deprecated":
false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "The agent factory to u
[...]
- "jsonSchema": { "index": 4, "kind": "parameter", "displayName": "Json
Schema", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "supportFileReference": true,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "JSON schema for
structured output valida [...]
- "tags": { "index": 5, "kind": "parameter", "displayName": "Tags", "group":
"producer", "label": "", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Tags for discovering and
calling Camel route tools" },
- "lazyStartProducer": { "index": 6, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produc [...]
- "mcpClients": { "index": 7, "kind": "parameter", "displayName": "Mcp
Clients", "group": "advanced", "label": "advanced", "required": false, "type":
"array", "javaType": "java.util.List<dev.langchain4j.mcp.client.McpClient>",
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Pre-built MCP (Model
Context Protocol) client inst [...]
- "mcpServer": { "index": 8, "kind": "parameter", "displayName": "Mcp
Server", "group": "advanced", "label": "advanced", "required": false, "type":
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>",
"prefix": "mcpServer.", "multiValue": true, "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "MCP server [...]
+ "jsonSchema": { "index": 4, "kind": "parameter", "displayName": "Json
Schema", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "supportFileReference": true,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "JSON schema for
structured output valida [...]
+ "outputClass": { "index": 5, "kind": "parameter", "displayName": "Output
Class", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.Class<java.lang.Object>", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Java class to use for
structured output. Camel deri [...]
+ "tags": { "index": 6, "kind": "parameter", "displayName": "Tags", "group":
"producer", "label": "", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Tags for discovering and
calling Camel route tools" },
+ "lazyStartProducer": { "index": 7, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produc [...]
+ "mcpClients": { "index": 8, "kind": "parameter", "displayName": "Mcp
Clients", "group": "advanced", "label": "advanced", "required": false, "type":
"array", "javaType": "java.util.List<dev.langchain4j.mcp.client.McpClient>",
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Pre-built MCP (Model
Context Protocol) client inst [...]
+ "mcpServer": { "index": 9, "kind": "parameter", "displayName": "Mcp
Server", "group": "advanced", "label": "advanced", "required": false, "type":
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>",
"prefix": "mcpServer.", "multiValue": true, "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "MCP server [...]
}
}
diff --git
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AbstractAgent.java
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AbstractAgent.java
index 24ddd3c51887..0cccc29792b8 100644
---
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AbstractAgent.java
+++
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AbstractAgent.java
@@ -146,7 +146,7 @@ public abstract class AbstractAgent<S> implements Agent {
builder.outputGuardrailClasses((List)
configuration.getOutputGuardrailClasses());
}
- // Response Format (structured output / JSON schema)
+ // Response Format (structured output): set once at startup via
setResponseFormat(), used here per request
if (responseFormat != null) {
builder.chatRequestTransformer(chatRequest ->
chatRequest.toBuilder().responseFormat(responseFormat).build());
}
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentComponentConfigurer.java
b/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentComponentConfigurer.java
index 690c48c1d780..3cee6170962e 100644
---
a/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentComponentConfigurer.java
+++
b/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentComponentConfigurer.java
@@ -46,6 +46,8 @@ public class LangChain4jAgentComponentConfigurer extends
PropertyConfigurerSuppo
case "mcpClients":
getOrCreateConfiguration(target).setMcpClients(property(camelContext,
java.util.List.class, value)); return true;
case "mcpserver":
case "mcpServer":
getOrCreateConfiguration(target).setMcpServer(property(camelContext,
java.util.Map.class, value)); return true;
+ case "outputclass":
+ case "outputClass":
getOrCreateConfiguration(target).setOutputClass(property(camelContext,
java.lang.Class.class, value)); return true;
case "tags":
getOrCreateConfiguration(target).setTags(property(camelContext,
java.lang.String.class, value)); return true;
default: return false;
}
@@ -75,6 +77,8 @@ public class LangChain4jAgentComponentConfigurer extends
PropertyConfigurerSuppo
case "mcpClients": return java.util.List.class;
case "mcpserver":
case "mcpServer": return java.util.Map.class;
+ case "outputclass":
+ case "outputClass": return java.lang.Class.class;
case "tags": return java.lang.String.class;
default: return null;
}
@@ -100,6 +104,8 @@ public class LangChain4jAgentComponentConfigurer extends
PropertyConfigurerSuppo
case "mcpClients": return
getOrCreateConfiguration(target).getMcpClients();
case "mcpserver":
case "mcpServer": return
getOrCreateConfiguration(target).getMcpServer();
+ case "outputclass":
+ case "outputClass": return
getOrCreateConfiguration(target).getOutputClass();
case "tags": return getOrCreateConfiguration(target).getTags();
default: return null;
}
@@ -112,6 +118,8 @@ public class LangChain4jAgentComponentConfigurer extends
PropertyConfigurerSuppo
case "mcpClients": return dev.langchain4j.mcp.client.McpClient.class;
case "mcpserver":
case "mcpServer": return java.lang.Object.class;
+ case "outputclass":
+ case "outputClass": return java.lang.Object.class;
default: return null;
}
}
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConfigurationConfigurer.java
b/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConfigurationConfigurer.java
index 406f70ada266..240f9fdd9fe1 100644
---
a/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConfigurationConfigurer.java
+++
b/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConfigurationConfigurer.java
@@ -34,6 +34,8 @@ public class LangChain4jAgentConfigurationConfigurer extends
org.apache.camel.su
case "mcpClients": target.setMcpClients(property(camelContext,
java.util.List.class, value)); return true;
case "mcpserver":
case "mcpServer": target.setMcpServer(property(camelContext,
java.util.Map.class, value)); return true;
+ case "outputclass":
+ case "outputClass": target.setOutputClass(property(camelContext,
java.lang.Class.class, value)); return true;
case "tags": target.setTags(property(camelContext,
java.lang.String.class, value)); return true;
default: return false;
}
@@ -53,6 +55,8 @@ public class LangChain4jAgentConfigurationConfigurer extends
org.apache.camel.su
case "mcpClients": return java.util.List.class;
case "mcpserver":
case "mcpServer": return java.util.Map.class;
+ case "outputclass":
+ case "outputClass": return java.lang.Class.class;
case "tags": return java.lang.String.class;
default: return null;
}
@@ -73,6 +77,8 @@ public class LangChain4jAgentConfigurationConfigurer extends
org.apache.camel.su
case "mcpClients": return target.getMcpClients();
case "mcpserver":
case "mcpServer": return target.getMcpServer();
+ case "outputclass":
+ case "outputClass": return target.getOutputClass();
case "tags": return target.getTags();
default: return null;
}
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentEndpointConfigurer.java
b/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentEndpointConfigurer.java
index 9b7382db9773..00a641d41cea 100644
---
a/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentEndpointConfigurer.java
+++
b/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentEndpointConfigurer.java
@@ -36,6 +36,8 @@ public class LangChain4jAgentEndpointConfigurer extends
PropertyConfigurerSuppor
case "mcpClients":
target.getConfiguration().setMcpClients(property(camelContext,
java.util.List.class, value)); return true;
case "mcpserver":
case "mcpServer":
target.getConfiguration().setMcpServer(property(camelContext,
java.util.Map.class, value)); return true;
+ case "outputclass":
+ case "outputClass":
target.getConfiguration().setOutputClass(property(camelContext,
java.lang.Class.class, value)); return true;
case "tags": target.getConfiguration().setTags(property(camelContext,
java.lang.String.class, value)); return true;
default: return false;
}
@@ -62,6 +64,8 @@ public class LangChain4jAgentEndpointConfigurer extends
PropertyConfigurerSuppor
case "mcpClients": return java.util.List.class;
case "mcpserver":
case "mcpServer": return java.util.Map.class;
+ case "outputclass":
+ case "outputClass": return java.lang.Class.class;
case "tags": return java.lang.String.class;
default: return null;
}
@@ -84,6 +88,8 @@ public class LangChain4jAgentEndpointConfigurer extends
PropertyConfigurerSuppor
case "mcpClients": return target.getConfiguration().getMcpClients();
case "mcpserver":
case "mcpServer": return target.getConfiguration().getMcpServer();
+ case "outputclass":
+ case "outputClass": return target.getConfiguration().getOutputClass();
case "tags": return target.getConfiguration().getTags();
default: return null;
}
@@ -96,6 +102,8 @@ public class LangChain4jAgentEndpointConfigurer extends
PropertyConfigurerSuppor
case "mcpClients": return dev.langchain4j.mcp.client.McpClient.class;
case "mcpserver":
case "mcpServer": return java.lang.Object.class;
+ case "outputclass":
+ case "outputClass": return java.lang.Object.class;
default: return null;
}
}
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentEndpointUriFactory.java
b/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentEndpointUriFactory.java
index 40ee98ce66db..d145280ea180 100644
---
a/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentEndpointUriFactory.java
+++
b/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentEndpointUriFactory.java
@@ -24,7 +24,7 @@ public class LangChain4jAgentEndpointUriFactory extends
org.apache.camel.support
private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(9);
+ Set<String> props = new HashSet<>(10);
props.add("agent");
props.add("agentConfiguration");
props.add("agentFactory");
@@ -33,6 +33,7 @@ public class LangChain4jAgentEndpointUriFactory extends
org.apache.camel.support
props.add("lazyStartProducer");
props.add("mcpClients");
props.add("mcpServer");
+ props.add("outputClass");
props.add("tags");
PROPERTY_NAMES = Collections.unmodifiableSet(props);
SECRET_PROPERTY_NAMES = Collections.emptySet();
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/agent/langchain4j-agent.json
b/components/camel-ai/camel-langchain4j-agent/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/agent/langchain4j-agent.json
index d9d41b08123e..7573c35232aa 100644
---
a/components/camel-ai/camel-langchain4j-agent/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/agent/langchain4j-agent.json
+++
b/components/camel-ai/camel-langchain4j-agent/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/agent/langchain4j-agent.json
@@ -28,12 +28,13 @@
"agentConfiguration": { "index": 1, "kind": "property", "displayName":
"Agent Configuration", "group": "producer", "label": "", "required": false,
"type": "object", "javaType":
"org.apache.camel.component.langchain4j.agent.api.AgentConfiguration",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Agent [...]
"agentFactory": { "index": 2, "kind": "property", "displayName": "Agent
Factory", "group": "producer", "label": "", "required": false, "type":
"object", "javaType":
"org.apache.camel.component.langchain4j.agent.api.AgentFactory", "deprecated":
false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "The agent factory to us
[...]
"configuration": { "index": 3, "kind": "property", "displayName":
"Configuration", "group": "producer", "label": "", "required": false, "type":
"object", "javaType":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"deprecated": false, "autowired": false, "secret": false, "description": "The
configuration" },
- "jsonSchema": { "index": 4, "kind": "property", "displayName": "Json
Schema", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "supportFileReference": true,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "JSON schema for
structured output validat [...]
+ "jsonSchema": { "index": 4, "kind": "property", "displayName": "Json
Schema", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "supportFileReference": true,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "JSON schema for
structured output validat [...]
"lazyStartProducer": { "index": 5, "kind": "property", "displayName":
"Lazy Start Producer", "group": "producer", "label": "producer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether the producer should be started lazy (on the first message). By
starting lazy you can use this to allow CamelContext and routes to startup in
situations where a producer may otherwise fail [...]
- "tags": { "index": 6, "kind": "property", "displayName": "Tags", "group":
"producer", "label": "", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Tags for discovering and
calling Camel route tools" },
- "autowiredEnabled": { "index": 7, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching t [...]
- "mcpClients": { "index": 8, "kind": "property", "displayName": "Mcp
Clients", "group": "advanced", "label": "advanced", "required": false, "type":
"array", "javaType": "java.util.List<dev.langchain4j.mcp.client.McpClient>",
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Pre-built MCP (Model
Context Protocol) client insta [...]
- "mcpServer": { "index": 9, "kind": "property", "displayName": "Mcp
Server", "group": "advanced", "label": "advanced", "required": false, "type":
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>",
"prefix": "mcpServer.", "multiValue": true, "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "MCP server [...]
+ "outputClass": { "index": 6, "kind": "property", "displayName": "Output
Class", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.Class<java.lang.Object>", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Java class to use for
structured output. Camel deriv [...]
+ "tags": { "index": 7, "kind": "property", "displayName": "Tags", "group":
"producer", "label": "", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Tags for discovering and
calling Camel route tools" },
+ "autowiredEnabled": { "index": 8, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching t [...]
+ "mcpClients": { "index": 9, "kind": "property", "displayName": "Mcp
Clients", "group": "advanced", "label": "advanced", "required": false, "type":
"array", "javaType": "java.util.List<dev.langchain4j.mcp.client.McpClient>",
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Pre-built MCP (Model
Context Protocol) client insta [...]
+ "mcpServer": { "index": 10, "kind": "property", "displayName": "Mcp
Server", "group": "advanced", "label": "advanced", "required": false, "type":
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>",
"prefix": "mcpServer.", "multiValue": true, "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "MCP server [...]
},
"headers": {
"CamelLangChain4jAgentSystemMessage": { "index": 0, "kind": "header",
"displayName": "", "group": "producer", "label": "", "required": false,
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The system prompt.", "constantName":
"org.apache.camel.component.langchain4j.agent.api.Headers#SYSTEM_MESSAGE" },
@@ -48,10 +49,11 @@
"agent": { "index": 1, "kind": "parameter", "displayName": "Agent",
"group": "producer", "label": "", "required": false, "type": "object",
"javaType": "org.apache.camel.component.langchain4j.agent.api.Agent",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "The agent to use for the
component" },
"agentConfiguration": { "index": 2, "kind": "parameter", "displayName":
"Agent Configuration", "group": "producer", "label": "", "required": false,
"type": "object", "javaType":
"org.apache.camel.component.langchain4j.agent.api.AgentConfiguration",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Agen [...]
"agentFactory": { "index": 3, "kind": "parameter", "displayName": "Agent
Factory", "group": "producer", "label": "", "required": false, "type":
"object", "javaType":
"org.apache.camel.component.langchain4j.agent.api.AgentFactory", "deprecated":
false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "The agent factory to u
[...]
- "jsonSchema": { "index": 4, "kind": "parameter", "displayName": "Json
Schema", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "supportFileReference": true,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "JSON schema for
structured output valida [...]
- "tags": { "index": 5, "kind": "parameter", "displayName": "Tags", "group":
"producer", "label": "", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Tags for discovering and
calling Camel route tools" },
- "lazyStartProducer": { "index": 6, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produc [...]
- "mcpClients": { "index": 7, "kind": "parameter", "displayName": "Mcp
Clients", "group": "advanced", "label": "advanced", "required": false, "type":
"array", "javaType": "java.util.List<dev.langchain4j.mcp.client.McpClient>",
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Pre-built MCP (Model
Context Protocol) client inst [...]
- "mcpServer": { "index": 8, "kind": "parameter", "displayName": "Mcp
Server", "group": "advanced", "label": "advanced", "required": false, "type":
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>",
"prefix": "mcpServer.", "multiValue": true, "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "MCP server [...]
+ "jsonSchema": { "index": 4, "kind": "parameter", "displayName": "Json
Schema", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "supportFileReference": true,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "JSON schema for
structured output valida [...]
+ "outputClass": { "index": 5, "kind": "parameter", "displayName": "Output
Class", "group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.Class<java.lang.Object>", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Java class to use for
structured output. Camel deri [...]
+ "tags": { "index": 6, "kind": "parameter", "displayName": "Tags", "group":
"producer", "label": "", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Tags for discovering and
calling Camel route tools" },
+ "lazyStartProducer": { "index": 7, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produc [...]
+ "mcpClients": { "index": 8, "kind": "parameter", "displayName": "Mcp
Clients", "group": "advanced", "label": "advanced", "required": false, "type":
"array", "javaType": "java.util.List<dev.langchain4j.mcp.client.McpClient>",
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "Pre-built MCP (Model
Context Protocol) client inst [...]
+ "mcpServer": { "index": 9, "kind": "parameter", "displayName": "Mcp
Server", "group": "advanced", "label": "advanced", "required": false, "type":
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>",
"prefix": "mcpServer.", "multiValue": true, "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration",
"configurationField": "configuration", "description": "MCP server [...]
}
}
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc
b/components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc
index f50192fba300..f98183b9daf4 100644
---
a/components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc
+++
b/components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc
@@ -1393,6 +1393,74 @@ The `jsonSchema` option accepts:
* Inline JSON:
`jsonSchema={"type":"object","properties":{"name":{"type":"string"}}}`
* Property placeholders: `jsonSchema=resource:classpath:${schema.location}`
+
+
+==== Using the outputClass endpoint option (Java Class-based Schema)
+
+As an alternative to providing a JSON schema directly, you can use the
`outputClass` endpoint option to specify a Java class. The Camel LangChain4j
agent will automatically:
+
+1. Derive the JSON schema from the class structure
+2. Configure the AI model to return JSON matching that schema
+
+The response body is left as a raw JSON string, consistent with the
`camel-openai` component. Use Camel's `.unmarshal().json()` in your route to
convert it to a POJO.
+
+This approach is mutually exclusive with `jsonSchema` — you can use one or the
other, but not both.
+
+===== Example with Java POJO
+
+First, define your response class. Annotate required fields with
`@JsonProperty(required = true)` so they appear in the `required` array of the
generated JSON schema, ensuring the model always populates them. Use
`@Description` to add semantic hints:
+
+[source,java]
+----
+import com.fasterxml.jackson.annotation.JsonProperty;
+import dev.langchain4j.model.output.structured.Description;
+
+public class PersonInfo {
+ @JsonProperty(required = true)
+ @Description("The person's full name")
+ private String name;
+
+ @JsonProperty(required = true)
+ @Description("The person's age in years")
+ private int age;
+
+ @JsonProperty(required = true)
+ @Description("The person's job or profession")
+ private String occupation;
+
+ // Getters and setters...
+}
+----
+
+Then configure the endpoint to use this class. Use the fully qualified class
name (FQCN) directly — no registry binding needed. Add `.unmarshal().json()` to
convert the raw JSON response to a POJO:
+
+[source,java]
+----
+AgentConfiguration agentConfiguration = new AgentConfiguration()
+ .withChatModel(chatModel);
+
+context.getRegistry().bind("myAgentConfig", agentConfiguration);
+
+from("direct:extract-person-info")
+ .setBody(constant("Extract information about John Smith, a 35-year-old
software engineer"))
+ .to("langchain4j-agent:structured?agentConfiguration=#myAgentConfig"
+ + "&outputClass=com.example.PersonInfo")
+ .unmarshal().json(PersonInfo.class)
+ .process(exchange -> {
+ PersonInfo person = exchange.getIn().getBody(PersonInfo.class);
+ log.info("Name: {}, Age: {}, Occupation: {}",
+ person.getName(), person.getAge(), person.getOccupation());
+ });
+----
+
+[NOTE]
+====
+* Both `jsonSchema` and `outputClass` only work when using
`agentConfiguration` (inline agent creation mode), without `agent` or
`agentFactory` configured
+* You cannot use both options simultaneously — they are mutually exclusive
+* The AI model must support structured outputs (e.g., OpenAI GPT-4o,
GPT-4o-mini, or Ollama models with JSON mode)
+* Complex nested objects and collections are fully supported with `outputClass`
+====
+
==== Alternative: configuring ResponseFormat on the ChatModel
You can also define the `ResponseFormat` at the `ChatModel` level. See the
https://docs.langchain4j.dev/tutorials/structured-outputs#using-json-schema-with-chatmodel[LangChain4j
Structured Outputs documentation] for details.
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConfiguration.java
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConfiguration.java
index f9c9004d2279..107d513d21c8 100644
---
a/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConfiguration.java
+++
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConfiguration.java
@@ -58,10 +58,19 @@ public class LangChain4jAgentConfiguration implements
Cloneable {
@UriParam
@Metadata(description = "JSON schema for structured output validation. "
- + "This option works only when using
agentConfiguration (inline agent creation mode).",
+ + "Only supported in inline agent creation mode:
agentConfiguration must be set and neither agent nor agentFactory may be
configured. "
+ + "Mutually exclusive with outputClass.",
supportFileReference = true, largeInput = true, inputLanguage =
"json")
private String jsonSchema;
+ @UriParam
+ @Metadata(description = "Java class to use for structured output. "
+ + "Camel derives the JSON schema from the class
and instructs the model to produce matching JSON; the response body is left as
a raw JSON string. "
+ + "Only supported in inline agent creation mode:
agentConfiguration must be set and neither agent nor agentFactory may be
configured. "
+ + "The class must be a POJO with public fields or
getters; simple types, enums, and collections are not supported. "
+ + "Mutually exclusive with jsonSchema.")
+ private Class<?> outputClass;
+
@UriParam(description = "MCP server definitions in the form of
mcpServer.<name>.<property>=<value>."
+ " Supported properties: transportType (stdio,
http, streamableHttp, or sse, default: stdio),"
+ " command (comma-separated, for stdio), url (for
http/sse),"
@@ -180,4 +189,17 @@ public class LangChain4jAgentConfiguration implements
Cloneable {
public void setJsonSchema(String jsonSchema) {
this.jsonSchema = jsonSchema;
}
+
+ /**
+ * Java class to use for structured output
+ *
+ * @return the output class
+ */
+ public Class<?> getOutputClass() {
+ return outputClass;
+ }
+
+ public void setOutputClass(Class<?> outputClass) {
+ this.outputClass = outputClass;
+ }
}
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentProducer.java
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentProducer.java
index 027c6f82c885..4e0eefac6418 100644
---
a/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentProducer.java
+++
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentProducer.java
@@ -32,6 +32,7 @@ import dev.langchain4j.model.chat.request.ResponseFormatType;
import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
import dev.langchain4j.model.chat.request.json.JsonRawSchema;
import dev.langchain4j.model.chat.request.json.JsonSchema;
+import dev.langchain4j.service.output.JsonSchemas;
import dev.langchain4j.service.tool.ToolExecutor;
import dev.langchain4j.service.tool.ToolProvider;
import dev.langchain4j.service.tool.ToolProviderRequest;
@@ -72,6 +73,31 @@ public class LangChain4jAgentProducer extends
DefaultProducer {
protected void doInit() throws Exception {
super.doInit();
+ boolean hasStructuredOutput =
endpoint.getConfiguration().getOutputClass() != null
+ ||
ObjectHelper.isNotEmpty(endpoint.getConfiguration().getJsonSchema());
+ if (hasStructuredOutput) {
+ if (endpoint.getConfiguration().getAgentConfiguration() == null) {
+ throw new IllegalArgumentException(
+ "outputClass and jsonSchema require agentConfiguration
to be set "
+ + "(inline agent creation
mode). They cannot be used with a user-provided agent bean or agentFactory.");
+ }
+ if (endpoint.getConfiguration().getAgent() != null) {
+ throw new IllegalArgumentException(
+ "outputClass and jsonSchema cannot be combined with a
user-provided agent bean. "
+ + "They only work in inline
agent creation mode (agentConfiguration without agent or agentFactory).");
+ }
+ if (endpoint.getConfiguration().getAgentFactory() != null) {
+ throw new IllegalArgumentException(
+ "outputClass and jsonSchema cannot be combined with
agentFactory. "
+ + "They only work in inline
agent creation mode (agentConfiguration without agent or agentFactory).");
+ }
+ if
(ObjectHelper.isNotEmpty(endpoint.getConfiguration().getJsonSchema())
+ && endpoint.getConfiguration().getOutputClass() != null) {
+ throw new IllegalArgumentException(
+ "jsonSchema and outputClass are mutually exclusive.
Please specify only one.");
+ }
+ }
+
if (endpoint.getConfiguration().getAgent() != null) {
agent = endpoint.getConfiguration().getAgent();
} else if (endpoint.getConfiguration().getAgentConfiguration() !=
null) {
@@ -79,8 +105,7 @@ public class LangChain4jAgentProducer extends
DefaultProducer {
agent = agentConfiguration.getChatMemoryProvider() != null
? new AgentWithMemory(agentConfiguration)
: new AgentWithoutMemory(agentConfiguration);
- // Apply jsonSchema only when Camel creates the agent internally —
we cannot modify user-provided agents
- resolveAndApplyJsonSchema();
+ resolveAndApplyStructuredOutput();
} else {
agent =
endpoint.getCamelContext().getRegistry().lookupByNameAndType(endpoint.getAgentId(),
Agent.class);
}
@@ -94,9 +119,7 @@ public class LangChain4jAgentProducer extends
DefaultProducer {
// tags for Camel Routes as Tools
String tags = endpoint.getConfiguration().getTags();
- if (agentFactory != null) {
- agent = agentFactory.createAgent(exchange);
- }
+ Agent agent = agentFactory != null ?
agentFactory.createAgent(exchange) : this.agent;
AiAgentBody<?> aiAgentBody =
exchange.getMessage().getMandatoryBody(AiAgentBody.class);
@@ -305,40 +328,57 @@ public class LangChain4jAgentProducer extends
DefaultProducer {
}
/**
- * Resolves the jsonSchema endpoint property: loads from
classpath/filesystem if it is a resource URI, otherwise
- * treats it as inline JSON. Converts the raw JSON string into a
langchain4j ResponseFormat and sets it on the
- * agent. Only called when the agent is created internally from
agentConfiguration.
+ * Resolves and applies structured output configuration (jsonSchema or
outputClass) to the agent. Only called when
+ * the agent is created internally from agentConfiguration.
*/
- private void resolveAndApplyJsonSchema() throws Exception {
+ private void resolveAndApplyStructuredOutput() throws Exception {
String jsonSchema = endpoint.getConfiguration().getJsonSchema();
- if (ObjectHelper.isEmpty(jsonSchema)) {
+ Class<?> outputClass = endpoint.getConfiguration().getOutputClass();
+
+ if (ObjectHelper.isEmpty(jsonSchema) && outputClass == null) {
return;
}
- String resolved =
endpoint.getCamelContext().resolvePropertyPlaceholders(jsonSchema);
+ JsonSchema schema;
+ if (outputClass != null) {
+ // JsonSchemas.jsonSchemaFrom() uses rawClass.getSimpleName() as
schema name; rename to camel_schema
+ // for consistency with the jsonSchema branch and cross-component
portability with camel-openai.
+ JsonSchema derived = JsonSchemas.jsonSchemaFrom(outputClass)
+ .orElseThrow(() -> new IllegalArgumentException(
+ "Cannot derive JSON schema from outputClass: " +
outputClass.getName()
+ + ".
outputClass must be a POJO class with public fields or getters."
+ + " Simple
types, enums, and collections are not supported."));
+ schema = JsonSchema.builder()
+ .name("camel_schema")
+ .rootElement(derived.rootElement())
+ .build();
+ LOG.debug("Configured structured output with output class: {}",
outputClass.getName());
+ } else {
+ String resolved =
endpoint.getCamelContext().resolvePropertyPlaceholders(jsonSchema);
- String content = resolveResourceContent(resolved);
- if (content != null) {
- resolved = content;
- }
+ String content = resolveResourceContent(resolved);
+ if (content != null) {
+ resolved = content;
+ }
- // Validates that resolved is valid JSON (whether loaded from a
resource or used as inline content)
- try {
- objectMapper.readTree(resolved);
- } catch (Exception e) {
- throw new IllegalArgumentException(
- "jsonSchema endpoint property does not contain valid JSON.
Provided value: " + jsonSchema, e);
+ // Validates that resolved is valid JSON (whether loaded from a
resource or used as inline content)
+ try {
+ objectMapper.readTree(resolved);
+ } catch (Exception e) {
+ throw new IllegalArgumentException(
+ "jsonSchema endpoint property does not contain valid
JSON. Provided value: " + jsonSchema, e);
+ }
+ // Use a fixed name consistent with camel-openai for
cross-component portability
+ schema = JsonSchema.builder()
+ .name("camel_schema")
+ .rootElement(JsonRawSchema.from(resolved))
+ .build();
}
- JsonRawSchema jsonRawSchema = JsonRawSchema.from(resolved);
- // Use a fixed name consistent with camel-openai for cross-component
portability
+
ResponseFormat responseFormat = ResponseFormat.builder()
.type(ResponseFormatType.JSON)
- .jsonSchema(JsonSchema.builder()
- .name("camel_schema")
- .rootElement(jsonRawSchema)
- .build())
+ .jsonSchema(schema)
.build();
-
((AbstractAgent<?>) agent).setResponseFormat(responseFormat);
}
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentOutputClassIT.java
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentOutputClassIT.java
new file mode 100644
index 000000000000..74c58f39a362
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentOutputClassIT.java
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.langchain4j.agent.integration;
+
+import dev.langchain4j.memory.chat.ChatMemoryProvider;
+import dev.langchain4j.memory.chat.MessageWindowChatMemory;
+import dev.langchain4j.model.chat.ChatModel;
+import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.langchain4j.agent.api.AgentConfiguration;
+import
org.apache.camel.component.langchain4j.agent.pojos.CarRentalRecommendation;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.infra.ollama.services.OllamaService;
+import org.apache.camel.test.infra.ollama.services.OllamaServiceFactory;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration test for outputClass parameter with the langchain4j-agent
component.
+ */
+@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*",
disabledReason = "Requires too much network resources")
+public class LangChain4jAgentOutputClassIT extends CamelTestSupport {
+
+ protected ChatModel chatModel;
+ protected ChatMemoryProvider chatMemoryProvider;
+
+ @RegisterExtension
+ static OllamaService OLLAMA =
OllamaServiceFactory.createSingletonService();
+
+ @Override
+ protected void setupResources() throws Exception {
+ super.setupResources();
+ chatModel = ModelHelper.loadChatModel(OLLAMA);
+ }
+
+ @Test
+ void testOutputClassWithoutMemory() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedMessageCount(1);
+
+ CarRentalRecommendation response =
template.requestBody("direct:outputClass",
+ "Recommend a car for a family of 4 traveling to the
mountains", CarRentalRecommendation.class);
+
+ mock.assertIsSatisfied();
+
+ assertThat(response).isNotNull();
+ assertThat(response.getVehicleType()).isNotNull();
+ assertThat(response.getVehicleModel()).isNotNull();
+ assertThat(response.getDailyRate()).isPositive();
+ assertThat(response.getFeatures()).isNotNull().isNotEmpty();
+ assertThat(response.getReasoning()).isNotNull();
+ }
+
+ @Test
+ void testOutputClassWithMemory() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:resultWithMemory");
+ mock.expectedMessageCount(2);
+
+ // First request
+ CarRentalRecommendation response1 =
template.requestBodyAndHeader("direct:outputClassWithMemory",
+ "Recommend an economy car", "CamelLangChain4jAgentMemoryId",
"user123", CarRentalRecommendation.class);
+
+ // Second request - should remember context
+ CarRentalRecommendation response2 =
template.requestBodyAndHeader("direct:outputClassWithMemory",
+ "Now recommend a luxury version",
"CamelLangChain4jAgentMemoryId", "user123", CarRentalRecommendation.class);
+
+ mock.assertIsSatisfied();
+
+ // Verify both responses are well-structured (fields populated)
+ assertThat(response1.getVehicleType()).isNotNull();
+ assertThat(response1.getVehicleModel()).isNotNull();
+ assertThat(response1.getFeatures()).isNotNull().isNotEmpty();
+
+ assertThat(response2.getVehicleType()).isNotNull();
+ assertThat(response2.getVehicleModel()).isNotNull();
+ assertThat(response2.getFeatures()).isNotNull().isNotEmpty();
+
+ // Verify memory works: second response references prior context
+ // (the conversation evolved - responses need not have specific price
differences)
+ }
+
+ @Test
+ void testOutputClassWithNestedObjects() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedMessageCount(1);
+
+ CarRentalRecommendation response =
template.requestBody("direct:outputClass",
+ "Recommend an SUV with at least 5 features",
CarRentalRecommendation.class);
+
+ mock.assertIsSatisfied();
+
+ // Verify the nested collection (List<String> features) is populated
+ assertThat(response.getFeatures()).isNotNull().isNotEmpty();
+ assertThat(response.getFeatures().size()).isGreaterThanOrEqualTo(3);
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ // Create agent configurations
+ AgentConfiguration agentConfig = new
AgentConfiguration().withChatModel(chatModel);
+ context.getRegistry().bind("agentConfig", agentConfig);
+
+ // Create agent configuration with memory
+ InMemoryChatMemoryStore chatMemoryStore = new
InMemoryChatMemoryStore();
+ chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder()
+ .id(memoryId)
+ .maxMessages(10)
+ .chatMemoryStore(chatMemoryStore)
+ .build();
+ AgentConfiguration agentConfigWithMemory
+ = new
AgentConfiguration().withChatModel(chatModel).withChatMemoryProvider(chatMemoryProvider);
+ context.getRegistry().bind("agentConfigWithMemory",
agentConfigWithMemory);
+
+ String outputClassFqcn = CarRentalRecommendation.class.getName();
+
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ // Route with outputClass (stateless): unmarshal the raw JSON
response to a POJO
+ from("direct:outputClass")
+
.to("langchain4j-agent:test1?agentConfiguration=#agentConfig&outputClass=" +
outputClassFqcn)
+ .unmarshal().json(CarRentalRecommendation.class)
+ .to("mock:result");
+
+ // Route with outputClass (stateful, with memory): unmarshal
the raw JSON response to a POJO
+ from("direct:outputClassWithMemory")
+
.to("langchain4j-agent:test2?agentConfiguration=#agentConfigWithMemory&outputClass="
+ + outputClassFqcn)
+ .unmarshal().json(CarRentalRecommendation.class)
+ .to("mock:resultWithMemory");
+ }
+ };
+ }
+}
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentStructuredOutputTest.java
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentStructuredOutputTest.java
index fb30f0678dd4..5ede51a2051a 100644
---
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentStructuredOutputTest.java
+++
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentStructuredOutputTest.java
@@ -18,8 +18,13 @@ package
org.apache.camel.component.langchain4j.agent.integration;
import java.io.FileNotFoundException;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.langchain4j.agent.api.Agent;
import org.apache.camel.component.langchain4j.agent.api.AgentConfiguration;
+import org.apache.camel.component.langchain4j.agent.api.AgentFactory;
+import
org.apache.camel.component.langchain4j.agent.pojos.CarRentalRecommendation;
import org.apache.camel.impl.DefaultCamelContext;
import org.junit.jupiter.api.Test;
@@ -101,4 +106,145 @@ public class LangChain4jAgentStructuredOutputTest {
}
}
+ @Test
+ void
testJsonSchemaAndOutputClassMutuallyExclusiveThrowsIllegalArgumentException()
throws Exception {
+ try (DefaultCamelContext context = new DefaultCamelContext()) {
+ AgentConfiguration config = new AgentConfiguration();
+ context.getRegistry().bind("myConfig", config);
+
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:test")
+
.to("langchain4j-agent:test?agentConfiguration=#myConfig"
+ + "&jsonSchema=RAW({\"type\":\"object\"})"
+ + "&outputClass=" +
CarRentalRecommendation.class.getName());
+ }
+ });
+
+ // FailedToStartRouteException -> RuntimeCamelException ->
IllegalArgumentException
+ Exception ex = assertThrows(Exception.class, context::start);
+ assertInstanceOf(IllegalArgumentException.class,
ex.getCause().getCause());
+ }
+ }
+
+ @Test
+ void
testOutputClassWithoutAgentConfigurationThrowsIllegalArgumentException() throws
Exception {
+ try (DefaultCamelContext context = new DefaultCamelContext()) {
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ // outputClass without agentConfiguration — should fail at
startup
+ from("direct:test")
+ .to("langchain4j-agent:myAgent?outputClass=" +
CarRentalRecommendation.class.getName());
+ }
+ });
+
+ // FailedToStartRouteException -> RuntimeCamelException ->
IllegalArgumentException
+ Exception ex = assertThrows(Exception.class, context::start);
+ assertInstanceOf(IllegalArgumentException.class,
ex.getCause().getCause());
+ }
+ }
+
+ @Test
+ void testNonExistentOutputClassThrowsException() throws Exception {
+ try (DefaultCamelContext context = new DefaultCamelContext()) {
+ AgentConfiguration config = new AgentConfiguration();
+ context.getRegistry().bind("myConfig", config);
+
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:test")
+
.to("langchain4j-agent:test?agentConfiguration=#myConfig"
+ + "&outputClass=com.nonexistent.DoesNotExist");
+ }
+ });
+
+ assertThrows(Exception.class, context::start);
+ }
+ }
+
+ @Test
+ void testNonPojoOutputClassThrowsIllegalArgumentException() throws
Exception {
+ try (DefaultCamelContext context = new DefaultCamelContext()) {
+ AgentConfiguration config = new AgentConfiguration();
+ context.getRegistry().bind("myConfig", config);
+
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:test")
+
.to("langchain4j-agent:test?agentConfiguration=#myConfig"
+ + "&outputClass=java.lang.String");
+ }
+ });
+
+ // JsonSchemas.jsonSchemaFrom(String.class) returns empty ->
orElseThrow fires
+ Exception ex = assertThrows(Exception.class, context::start);
+ assertInstanceOf(IllegalArgumentException.class,
ex.getCause().getCause());
+ }
+ }
+
+ @Test
+ void testOutputClassWithUserProvidedAgentThrowsIllegalArgumentException()
throws Exception {
+ try (DefaultCamelContext context = new DefaultCamelContext()) {
+ AgentConfiguration config = new AgentConfiguration();
+ Agent stubAgent = (aiAgentBody, toolProvider) -> "stub";
+ context.getRegistry().bind("myConfig", config);
+ context.getRegistry().bind("myAgent", stubAgent);
+
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:test")
+
.to("langchain4j-agent:test?agentConfiguration=#myConfig"
+ + "&agent=#myAgent"
+ + "&outputClass=" +
CarRentalRecommendation.class.getName());
+ }
+ });
+
+ Exception ex = assertThrows(Exception.class, context::start);
+ assertInstanceOf(IllegalArgumentException.class,
ex.getCause().getCause());
+ }
+ }
+
+ @Test
+ void testOutputClassWithAgentFactoryThrowsIllegalArgumentException()
throws Exception {
+ try (DefaultCamelContext context = new DefaultCamelContext()) {
+ AgentConfiguration config = new AgentConfiguration();
+ Agent stubAgent = (aiAgentBody, toolProvider) -> "stub";
+ AgentFactory stubFactory = new AgentFactory() {
+ @Override
+ public Agent createAgent(Exchange exchange) {
+ return stubAgent;
+ }
+
+ @Override
+ public void setCamelContext(CamelContext camelContext) {
+ }
+
+ @Override
+ public CamelContext getCamelContext() {
+ return null;
+ }
+ };
+ context.getRegistry().bind("myConfig", config);
+ context.getRegistry().bind("myFactory", stubFactory);
+
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:test")
+
.to("langchain4j-agent:test?agentConfiguration=#myConfig"
+ + "&agentFactory=#myFactory"
+ + "&outputClass=" +
CarRentalRecommendation.class.getName());
+ }
+ });
+
+ Exception ex = assertThrows(Exception.class, context::start);
+ assertInstanceOf(IllegalArgumentException.class,
ex.getCause().getCause());
+ }
+ }
+
}
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/pojos/CarRentalRecommendation.java
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/pojos/CarRentalRecommendation.java
new file mode 100644
index 000000000000..2be379d5a084
--- /dev/null
+++
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/pojos/CarRentalRecommendation.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.langchain4j.agent.pojos;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import dev.langchain4j.model.output.structured.Description;
+
+/**
+ * Test POJO for structured output testing with responseType parameter.
Represents a car rental recommendation with
+ * vehicle details and reasoning.
+ */
+public class CarRentalRecommendation {
+
+ @JsonProperty(required = true)
+ @Description("The category of vehicle (e.g., Economy, SUV, Luxury,
Minivan, Sedan)")
+ private String vehicleType;
+
+ @JsonProperty(required = true)
+ @Description("The make and model of the vehicle (e.g., Toyota Camry, Ford
Explorer)")
+ private String vehicleModel;
+
+ @JsonProperty(required = true)
+ @Description("The estimated daily rental rate in USD (e.g., 45.0, 89.99,
150.0)")
+ private double dailyRate;
+
+ @JsonProperty(required = true)
+ @Description("List of key features or benefits of this vehicle")
+ private List<String> features;
+
+ @JsonProperty(required = true)
+ @Description("The reasoning behind recommending this vehicle")
+ private String reasoning;
+
+ @Description("Whether insurance is recommended for this rental")
+ private boolean insuranceRecommended;
+
+ public CarRentalRecommendation() {
+ }
+
+ public CarRentalRecommendation(
+ String vehicleType, String vehicleModel,
double dailyRate,
+ List<String> features, String reasoning,
boolean insuranceRecommended) {
+ this.vehicleType = vehicleType;
+ this.vehicleModel = vehicleModel;
+ this.dailyRate = dailyRate;
+ this.features = features;
+ this.reasoning = reasoning;
+ this.insuranceRecommended = insuranceRecommended;
+ }
+
+ public String getVehicleType() {
+ return vehicleType;
+ }
+
+ public void setVehicleType(String vehicleType) {
+ this.vehicleType = vehicleType;
+ }
+
+ public String getVehicleModel() {
+ return vehicleModel;
+ }
+
+ public void setVehicleModel(String vehicleModel) {
+ this.vehicleModel = vehicleModel;
+ }
+
+ public double getDailyRate() {
+ return dailyRate;
+ }
+
+ public void setDailyRate(double dailyRate) {
+ this.dailyRate = dailyRate;
+ }
+
+ public List<String> getFeatures() {
+ return features;
+ }
+
+ public void setFeatures(List<String> features) {
+ this.features = features;
+ }
+
+ public String getReasoning() {
+ return reasoning;
+ }
+
+ public void setReasoning(String reasoning) {
+ this.reasoning = reasoning;
+ }
+
+ public boolean isInsuranceRecommended() {
+ return insuranceRecommended;
+ }
+
+ public void setInsuranceRecommended(boolean insuranceRecommended) {
+ this.insuranceRecommended = insuranceRecommended;
+ }
+
+ @Override
+ public String toString() {
+ return "CarRentalRecommendation{" +
+ "vehicleType='" + vehicleType + '\'' +
+ ", vehicleModel='" + vehicleModel + '\'' +
+ ", dailyRate=" + dailyRate +
+ ", features=" + features +
+ ", reasoning='" + reasoning + '\'' +
+ ", insuranceRecommended=" + insuranceRecommended +
+ '}';
+ }
+}
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/Langchain4jAgentComponentBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/Langchain4jAgentComponentBuilderFactory.java
index a6d6fa9f43e6..5521d8788833 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/Langchain4jAgentComponentBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/Langchain4jAgentComponentBuilderFactory.java
@@ -118,8 +118,10 @@ public interface Langchain4jAgentComponentBuilderFactory {
}
/**
- * JSON schema for structured output validation. This option works only
- * when using agentConfiguration (inline agent creation mode).
+ * JSON schema for structured output validation. Only supported in
+ * inline agent creation mode: agentConfiguration must be set and
+ * neither agent nor agentFactory may be configured. Mutually exclusive
+ * with outputClass.
*
* This option can also be loaded from an existing file, by prefixing
* with file: or classpath: followed by the location of the file.
@@ -161,6 +163,28 @@ public interface Langchain4jAgentComponentBuilderFactory {
return this;
}
+ /**
+ * Java class to use for structured output. Camel derives the JSON
+ * schema from the class and instructs the model to produce matching
+ * JSON; the response body is left as a raw JSON string. Only supported
+ * in inline agent creation mode: agentConfiguration must be set and
+ * neither agent nor agentFactory may be configured. The class must be
a
+ * POJO with public fields or getters; simple types, enums, and
+ * collections are not supported. Mutually exclusive with jsonSchema.
+ *
+ * The option is a:
+ *
<code>java.lang.Class&lt;java.lang.Object&gt;</code> type.
+ *
+ * Group: producer
+ *
+ * @param outputClass the value to set
+ * @return the dsl builder
+ */
+ default Langchain4jAgentComponentBuilder
outputClass(java.lang.Class<java.lang.Object> outputClass) {
+ doSetProperty("outputClass", outputClass);
+ return this;
+ }
+
/**
* Tags for discovering and calling Camel route tools.
*
@@ -264,6 +288,7 @@ public interface Langchain4jAgentComponentBuilderFactory {
case "configuration": ((LangChain4jAgentComponent)
component).setConfiguration((org.apache.camel.component.langchain4j.agent.LangChain4jAgentConfiguration)
value); return true;
case "jsonSchema":
getOrCreateConfiguration((LangChain4jAgentComponent)
component).setJsonSchema((java.lang.String) value); return true;
case "lazyStartProducer": ((LangChain4jAgentComponent)
component).setLazyStartProducer((boolean) value); return true;
+ case "outputClass":
getOrCreateConfiguration((LangChain4jAgentComponent)
component).setOutputClass((java.lang.Class) value); return true;
case "tags": getOrCreateConfiguration((LangChain4jAgentComponent)
component).setTags((java.lang.String) value); return true;
case "autowiredEnabled": ((LangChain4jAgentComponent)
component).setAutowiredEnabled((boolean) value); return true;
case "mcpClients":
getOrCreateConfiguration((LangChain4jAgentComponent)
component).setMcpClients((java.util.List) value); return true;
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jAgentEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jAgentEndpointBuilderFactory.java
index bbdf10af20b8..45cf87615fa8 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jAgentEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jAgentEndpointBuilderFactory.java
@@ -143,8 +143,10 @@ public interface LangChain4jAgentEndpointBuilderFactory {
return this;
}
/**
- * JSON schema for structured output validation. This option works only
- * when using agentConfiguration (inline agent creation mode).
+ * JSON schema for structured output validation. Only supported in
+ * inline agent creation mode: agentConfiguration must be set and
+ * neither agent nor agentFactory may be configured. Mutually exclusive
+ * with outputClass.
*
* This option can also be loaded from an existing file, by prefixing
* with file: or classpath: followed by the location of the file.
@@ -160,6 +162,48 @@ public interface LangChain4jAgentEndpointBuilderFactory {
doSetProperty("jsonSchema", jsonSchema);
return this;
}
+ /**
+ * Java class to use for structured output. Camel derives the JSON
+ * schema from the class and instructs the model to produce matching
+ * JSON; the response body is left as a raw JSON string. Only supported
+ * in inline agent creation mode: agentConfiguration must be set and
+ * neither agent nor agentFactory may be configured. The class must be
a
+ * POJO with public fields or getters; simple types, enums, and
+ * collections are not supported. Mutually exclusive with jsonSchema.
+ *
+ * The option is a:
<code>java.lang.Class<java.lang.Object></code>
+ * type.
+ *
+ * Group: producer
+ *
+ * @param outputClass the value to set
+ * @return the dsl builder
+ */
+ default LangChain4jAgentEndpointBuilder
outputClass(Class<java.lang.Object> outputClass) {
+ doSetProperty("outputClass", outputClass);
+ return this;
+ }
+ /**
+ * Java class to use for structured output. Camel derives the JSON
+ * schema from the class and instructs the model to produce matching
+ * JSON; the response body is left as a raw JSON string. Only supported
+ * in inline agent creation mode: agentConfiguration must be set and
+ * neither agent nor agentFactory may be configured. The class must be
a
+ * POJO with public fields or getters; simple types, enums, and
+ * collections are not supported. Mutually exclusive with jsonSchema.
+ *
+ * The option will be converted to a
+ * <code>java.lang.Class<java.lang.Object></code> type.
+ *
+ * Group: producer
+ *
+ * @param outputClass the value to set
+ * @return the dsl builder
+ */
+ default LangChain4jAgentEndpointBuilder outputClass(String
outputClass) {
+ doSetProperty("outputClass", outputClass);
+ return this;
+ }
/**
* Tags for discovering and calling Camel route tools.
*