You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2026/01/11 09:56:49 UTC
(camel) branch main updated: camel-openai: remove temperature default and add extra request params (#20735)
This is an automated email from the ASF dual-hosted git repository.
davsclaus 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 274f656b69a7 camel-openai: remove temperature default and add extra request params (#20735)
274f656b69a7 is described below
commit 274f656b69a7afea51346775cd62e35360a58daf
Author: loop9x <ib...@email.cz>
AuthorDate: Sun Jan 11 10:56:42 2026 +0100
camel-openai: remove temperature default and add extra request params (#20735)
Co-authored-by: Ivo Bek <be...@gmail.com>
---
.../component/openai/OpenAIEndpointConfigurer.java | 15 ++++++++++
.../component/openai/OpenAIEndpointUriFactory.java | 7 +++--
.../org/apache/camel/component/openai/openai.json | 33 +++++++++++-----------
.../component/openai/OpenAIConfiguration.java | 22 ++++++++++++---
.../camel/component/openai/OpenAIProducer.java | 30 ++++++++++++++++++++
.../component/openai/OpenAIProducerMockTest.java | 26 +++++++++++++++++
6 files changed, 111 insertions(+), 22 deletions(-)
diff --git a/components/camel-ai/camel-openai/src/generated/java/org/apache/camel/component/openai/OpenAIEndpointConfigurer.java b/components/camel-ai/camel-openai/src/generated/java/org/apache/camel/component/openai/OpenAIEndpointConfigurer.java
index 810e34fa7413..fafbf343f9ec 100644
--- a/components/camel-ai/camel-openai/src/generated/java/org/apache/camel/component/openai/OpenAIEndpointConfigurer.java
+++ b/components/camel-ai/camel-openai/src/generated/java/org/apache/camel/component/openai/OpenAIEndpointConfigurer.java
@@ -23,6 +23,8 @@ public class OpenAIEndpointConfigurer extends PropertyConfigurerSupport implemen
public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
OpenAIEndpoint target = (OpenAIEndpoint) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "additionalbodyproperty":
+ case "additionalBodyProperty": target.getConfiguration().setAdditionalBodyProperty(property(camelContext, java.util.Map.class, value)); return true;
case "apikey":
case "apiKey": target.getConfiguration().setApiKey(property(camelContext, java.lang.String.class, value)); return true;
case "baseurl":
@@ -59,6 +61,8 @@ public class OpenAIEndpointConfigurer extends PropertyConfigurerSupport implemen
@Override
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "additionalbodyproperty":
+ case "additionalBodyProperty": return java.util.Map.class;
case "apikey":
case "apiKey": return java.lang.String.class;
case "baseurl":
@@ -96,6 +100,8 @@ public class OpenAIEndpointConfigurer extends PropertyConfigurerSupport implemen
public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
OpenAIEndpoint target = (OpenAIEndpoint) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "additionalbodyproperty":
+ case "additionalBodyProperty": return target.getConfiguration().getAdditionalBodyProperty();
case "apikey":
case "apiKey": return target.getConfiguration().getApiKey();
case "baseurl":
@@ -128,5 +134,14 @@ public class OpenAIEndpointConfigurer extends PropertyConfigurerSupport implemen
default: return null;
}
}
+
+ @Override
+ public Object getCollectionValueType(Object target, String name, boolean ignoreCase) {
+ switch (ignoreCase ? name.toLowerCase() : name) {
+ case "additionalbodyproperty":
+ case "additionalBodyProperty": return java.lang.Object.class;
+ default: return null;
+ }
+ }
}
diff --git a/components/camel-ai/camel-openai/src/generated/java/org/apache/camel/component/openai/OpenAIEndpointUriFactory.java b/components/camel-ai/camel-openai/src/generated/java/org/apache/camel/component/openai/OpenAIEndpointUriFactory.java
index 43a2de620e74..bf1692e86f54 100644
--- a/components/camel-ai/camel-openai/src/generated/java/org/apache/camel/component/openai/OpenAIEndpointUriFactory.java
+++ b/components/camel-ai/camel-openai/src/generated/java/org/apache/camel/component/openai/OpenAIEndpointUriFactory.java
@@ -23,7 +23,8 @@ public class OpenAIEndpointUriFactory extends org.apache.camel.support.component
private static final Set<String> SECRET_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(17);
+ Set<String> props = new HashSet<>(18);
+ props.add("additionalBodyProperty");
props.add("apiKey");
props.add("baseUrl");
props.add("conversationHistoryProperty");
@@ -45,7 +46,9 @@ public class OpenAIEndpointUriFactory extends org.apache.camel.support.component
Set<String> secretProps = new HashSet<>(1);
secretProps.add("apiKey");
SECRET_PROPERTY_NAMES = Collections.unmodifiableSet(secretProps);
- MULTI_VALUE_PREFIXES = Collections.emptyMap();
+ Map<String, String> prefixes = new HashMap<>(1);
+ prefixes.put("additionalBodyProperty", "additionalBodyProperty.");
+ MULTI_VALUE_PREFIXES = Collections.unmodifiableMap(prefixes);
}
@Override
diff --git a/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/openai.json b/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/openai.json
index d018ffaa223a..a091fe5a9b02 100644
--- a/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/openai.json
+++ b/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/openai.json
@@ -32,21 +32,22 @@
},
"properties": {
"operation": { "index": 0, "kind": "path", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation to perform (currently only chat-completion is supported)" },
- "apiKey": { "index": 1, "kind": "parameter", "displayName": "Api Key", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "OpenAI API key. Can also be set via OPENAI_API_KEY environment variable." },
- "baseUrl": { "index": 2, "kind": "parameter", "displayName": "Base Url", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Base URL for OpenAI API. Defaults to OpenAI's official endpoint. Can be used for local or third-p [...]
- "conversationHistoryProperty": { "index": 3, "kind": "parameter", "displayName": "Conversation History Property", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "CamelOpenAIConversationHistory", "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Exchan [...]
- "conversationMemory": { "index": 4, "kind": "parameter", "displayName": "Conversation Memory", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Enable conversation memory per Exchange" },
- "developerMessage": { "index": 5, "kind": "parameter", "displayName": "Developer Message", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Developer message to prepend before user messages" },
- "jsonSchema": { "index": 6, "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.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "JSON schema for structured output validation" },
- "maxTokens": { "index": 7, "kind": "parameter", "displayName": "Max Tokens", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Maximum number of tokens to generate" },
- "model": { "index": 8, "kind": "parameter", "displayName": "Model", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "gpt-5", "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "The model to use for chat completion" },
- "outputClass": { "index": 9, "kind": "parameter", "displayName": "Output Class", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Fully qualified class name for structured output using response format" },
- "storeFullResponse": { "index": 10, "kind": "parameter", "displayName": "Store Full Response", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Store the full response in the exchange property 'CamelOpenA [...]
- "streaming": { "index": 11, "kind": "parameter", "displayName": "Streaming", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Enable streaming responses" },
- "systemMessage": { "index": 12, "kind": "parameter", "displayName": "System Message", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "System message to prepend. When set and conversationMemory is enabled, the conversat [...]
- "temperature": { "index": 13, "kind": "parameter", "displayName": "Temperature", "group": "producer", "label": "", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "1.0", "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Temperature for response generation (0.0 to 2.0)" },
- "topP": { "index": 14, "kind": "parameter", "displayName": "Top P", "group": "producer", "label": "", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Top P for response generation (0.0 to 1.0)" },
- "userMessage": { "index": 15, "kind": "parameter", "displayName": "User Message", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Default user message text to use when no prompt is provided" },
- "lazyStartProducer": { "index": 16, "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 produ [...]
+ "additionalBodyProperty": { "index": 1, "kind": "parameter", "displayName": "Additional Body Property", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", "prefix": "additionalBodyProperty.", "multiValue": true, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configur [...]
+ "apiKey": { "index": 2, "kind": "parameter", "displayName": "Api Key", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "OpenAI API key. Can also be set via OPENAI_API_KEY environment variable." },
+ "baseUrl": { "index": 3, "kind": "parameter", "displayName": "Base Url", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Base URL for OpenAI API. Defaults to OpenAI's official endpoint. Can be used for local or third-p [...]
+ "conversationHistoryProperty": { "index": 4, "kind": "parameter", "displayName": "Conversation History Property", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "CamelOpenAIConversationHistory", "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Exchan [...]
+ "conversationMemory": { "index": 5, "kind": "parameter", "displayName": "Conversation Memory", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Enable conversation memory per Exchange" },
+ "developerMessage": { "index": 6, "kind": "parameter", "displayName": "Developer Message", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Developer message to prepend before user messages" },
+ "jsonSchema": { "index": 7, "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.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "JSON schema for structured output validation" },
+ "maxTokens": { "index": 8, "kind": "parameter", "displayName": "Max Tokens", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Maximum number of tokens to generate" },
+ "model": { "index": 9, "kind": "parameter", "displayName": "Model", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "The model to use for chat completion" },
+ "outputClass": { "index": 10, "kind": "parameter", "displayName": "Output Class", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Fully qualified class name for structured output using response format" },
+ "storeFullResponse": { "index": 11, "kind": "parameter", "displayName": "Store Full Response", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Store the full response in the exchange property 'CamelOpenA [...]
+ "streaming": { "index": 12, "kind": "parameter", "displayName": "Streaming", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Enable streaming responses" },
+ "systemMessage": { "index": 13, "kind": "parameter", "displayName": "System Message", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "System message to prepend. When set and conversationMemory is enabled, the conversat [...]
+ "temperature": { "index": 14, "kind": "parameter", "displayName": "Temperature", "group": "producer", "label": "", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Temperature for response generation (0.0 to 2.0)" },
+ "topP": { "index": 15, "kind": "parameter", "displayName": "Top P", "group": "producer", "label": "", "required": false, "type": "number", "javaType": "java.lang.Double", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Top P for response generation (0.0 to 1.0)" },
+ "userMessage": { "index": 16, "kind": "parameter", "displayName": "User Message", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Default user message text to use when no prompt is provided" },
+ "lazyStartProducer": { "index": 17, "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 produ [...]
}
}
diff --git a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIConfiguration.java b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIConfiguration.java
index e09948a9616e..6e076149a944 100644
--- a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIConfiguration.java
+++ b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIConfiguration.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.component.openai;
+import java.util.Map;
+
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriParams;
@@ -34,13 +36,13 @@ public class OpenAIConfiguration implements Cloneable {
@Metadata(description = "Base URL for OpenAI API. Defaults to OpenAI's official endpoint. Can be used for local or third-party providers.")
private String baseUrl;
- @UriParam(defaultValue = "gpt-5")
+ @UriParam
@Metadata(description = "The model to use for chat completion")
- private String model = "gpt-5";
+ private String model;
- @UriParam(defaultValue = "1.0")
+ @UriParam
@Metadata(description = "Temperature for response generation (0.0 to 2.0)")
- private Double temperature = 1.0;
+ private Double temperature;
@UriParam
@Metadata(description = "Top P for response generation (0.0 to 1.0)")
@@ -88,6 +90,10 @@ public class OpenAIConfiguration implements Cloneable {
@Metadata(description = "Store the full response in the exchange property 'CamelOpenAIResponse' in non-streaming mode")
private boolean storeFullResponse = false;
+ @UriParam(prefix = "additionalBodyProperty.", multiValue = true)
+ @Metadata(description = "Additional JSON properties to include in the request body (e.g. additionalBodyProperty.traceId=123)")
+ private Map<String, Object> additionalBodyProperty;
+
public String getApiKey() {
return apiKey;
}
@@ -208,6 +214,14 @@ public class OpenAIConfiguration implements Cloneable {
this.storeFullResponse = storeFullResponse;
}
+ public Map<String, Object> getAdditionalBodyProperty() {
+ return additionalBodyProperty;
+ }
+
+ public void setAdditionalBodyProperty(Map<String, Object> additionalBodyProperty) {
+ this.additionalBodyProperty = additionalBodyProperty;
+ }
+
public OpenAIConfiguration copy() {
try {
return (OpenAIConfiguration) clone();
diff --git a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIProducer.java b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIProducer.java
index 5cbe1350bbbc..3aa022c5b295 100644
--- a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIProducer.java
+++ b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIProducer.java
@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Base64;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.openai.core.JsonValue;
@@ -165,6 +166,8 @@ public class OpenAIProducer extends DefaultAsyncProducer {
}
}
+ applyAdditionalBodyProperties(paramsBuilder, config);
+
ChatCompletionCreateParams params = paramsBuilder.build();
if (Boolean.TRUE.equals(streaming)) {
@@ -448,6 +451,33 @@ public class OpenAIProducer extends DefaultAsyncProducer {
return sb.build();
}
+ private void applyAdditionalBodyProperties(ChatCompletionCreateParams.Builder paramsBuilder, OpenAIConfiguration config) {
+ Map<String, Object> additional = config.getAdditionalBodyProperty();
+ if (additional == null || additional.isEmpty()) {
+ return;
+ }
+
+ for (Map.Entry<String, Object> e : additional.entrySet()) {
+ String key = e.getKey();
+ Object rawValue = e.getValue();
+ Object valueToUse = rawValue;
+ if (rawValue instanceof String s) {
+ valueToUse = parseJsonOrString(s);
+ }
+
+ paramsBuilder.putAdditionalBodyProperty(key, JsonValue.from((Object) valueToUse));
+ }
+ }
+
+ private Object parseJsonOrString(String value) {
+ try {
+ return OBJECT_MAPPER.readValue(value, Object.class);
+ } catch (Exception e) {
+ // treat as literal string
+ return value;
+ }
+ }
+
private <T> T resolveParameter(Message message, String headerName, T defaultValue, Class<T> type) {
T headerValue = message.getHeader(headerName, type);
return ObjectHelper.isNotEmpty(headerValue) ? headerValue : defaultValue;
diff --git a/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/OpenAIProducerMockTest.java b/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/OpenAIProducerMockTest.java
index 2054c6ebb6c7..3dc7822c3376 100644
--- a/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/OpenAIProducerMockTest.java
+++ b/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/OpenAIProducerMockTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.component.openai;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.test.infra.openai.mock.OpenAIMock;
@@ -29,11 +31,25 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class OpenAIProducerMockTest extends CamelTestSupport {
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
@RegisterExtension
public OpenAIMock openAIMock = new OpenAIMock().builder()
.when("hello")
.replyWith("Hi from mock")
.end()
+ .when("hello-extra")
+ .assertRequest(request -> {
+ try {
+ JsonNode root = OBJECT_MAPPER.readTree(request);
+ assertTrue(root.has("traceId"), "Expected traceId in request body");
+ assertEquals(123, root.get("traceId").asInt());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .replyWith("Hi from mock")
+ .end()
.when("json please")
.replyWith("{\"ok\":true}")
.end()
@@ -49,6 +65,10 @@ public class OpenAIProducerMockTest extends CamelTestSupport {
.to("openai:chat-completion?model=gpt-5&apiKey=dummy&baseUrl=" + openAIMock.getBaseUrl()
+ "/v1");
+ from("direct:chat-extra")
+ .to("openai:chat-completion?model=gpt-5&apiKey=dummy&baseUrl=" + openAIMock.getBaseUrl()
+ + "/v1&additionalBodyProperty.traceId=123");
+
// Streaming chat route using the mock server
from("direct:chat-stream")
.to("openai:chat-completion?model=gpt-5&apiKey=dummy&streaming=true&baseUrl="
@@ -86,4 +106,10 @@ public class OpenAIProducerMockTest extends CamelTestSupport {
assertTrue(body instanceof java.util.Iterator);
}
+ @Test
+ void additionalBodyPropertyIsIncludedInRequestBody() {
+ Exchange result = template.request("direct:chat-extra", e -> e.getIn().setBody("hello-extra"));
+ assertEquals("Hi from mock", result.getMessage().getBody(String.class));
+ }
+
}