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 <[email protected]>
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 <[email protected]>
---
.../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));
+ }
+
}