This is an automated email from the ASF dual-hosted git repository.

luigidemasi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 2cca8a20db65520cddaf4a668659d954c19a690a
Author: Luigi De Masi <[email protected]>
AuthorDate: Wed Oct 14 22:22:43 2026 +0200

    CAMEL-25669: Add native OpenAI Decisions support
    
    Use native Decisions request and response types with validated text/image 
input and dedicated refusal, response, and service exceptions. Upgrade the SDK 
and cover the integration with local HTTP tests and opt-in API smoke tests.
    
    Co-authored-by: OpenAI Codex <[email protected]>
    Signed-off-by: Luigi De Masi <[email protected]>
---
 .../org/apache/camel/catalog/components/llm.json   |   4 +-
 .../apache/camel/catalog/components/openai.json    |   4 +-
 .../camel/catalog/docs/openai-component.adoc       |  34 +++
 .../org/apache/camel/component/openai/llm.json     |   4 +-
 .../org/apache/camel/component/openai/openai.json  |   4 +-
 .../src/main/docs/openai-component.adoc            |  34 +++
 .../component/openai/OpenAIConfiguration.java      |   2 +-
 .../openai/OpenAIDecisionRefusalException.java     |  30 +++
 .../openai/OpenAIDecisionResponseException.java    |  30 +++
 .../openai/OpenAIDecisionServiceException.java     |  30 +++
 .../component/openai/OpenAIDecisionsProducer.java  |  36 +++
 .../component/openai/OpenAIDecisionsSupport.java   | 276 +++++++++++++++++++++
 .../camel/component/openai/OpenAIEndpoint.java     |  34 ++-
 .../camel/component/openai/OpenAIOperations.java   |   3 +-
 .../component/openai/OpenAIDecisionsHttpTest.java  | 139 +++++++++++
 .../component/openai/OpenAIDecisionsTest.java      | 138 +++++++++++
 .../OpenAIDecisionsExternalServiceIT.java          |  98 ++++++++
 .../builder/endpoint/StaticEndpointBuilders.java   |  24 +-
 .../endpoint/dsl/OpenAIEndpointBuilderFactory.java |  54 ++--
 parent/pom.xml                                     |   2 +-
 20 files changed, 926 insertions(+), 54 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/llm.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/llm.json
index c052860fbcf8..c6e238e99c9e 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/llm.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/llm.json
@@ -147,7 +147,7 @@
     "CamelOpenAIImageTotalTokens": { "index": 108, "kind": "header", 
"displayName": "", "group": "common", "label": "", "required": false, 
"javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The total number of tokens billed for 
the image request. Only reported by GPT image models", "constantName": 
"org.apache.camel.component.openai.OpenAIConstants#IMAGE_TOTAL_TOKENS" }
   },
   "properties": {
-    "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "common", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.openai.OpenAIOperations", "enum": [ 
"chat-completion", "responses", "responses-retrieve", "responses-cancel", 
"batch", "batch-retrieve", "batch-cancel", "batch-results", "embeddings", 
"tool-execution", "audio-transcription", "audio-translation", "audio-speech", 
"moderation", "image-generation", "image-edit", " [...]
+    "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "common", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.openai.OpenAIOperations", "enum": [ 
"chat-completion", "decisions", "responses", "responses-retrieve", 
"responses-cancel", "batch", "batch-retrieve", "batch-cancel", "batch-results", 
"embeddings", "tool-execution", "audio-transcription", "audio-translation", 
"audio-speech", "moderation", "image-generation", "i [...]
     "additionalBodyProperty": { "index": 1, "kind": "parameter", 
"displayName": "Additional Body Property", "group": "common", "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": "configurat [...]
     "additionalHeader": { "index": 2, "kind": "parameter", "displayName": 
"Additional Header", "group": "common", "label": "", "required": false, "type": 
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", 
"prefix": "additionalHeader.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": true, "security": 
"secret", "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configur [...]
     "additionalResponseHeader": { "index": 3, "kind": "parameter", 
"displayName": "Additional Response Header", "group": "common", "label": "", 
"required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"additionalResponseHeader.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "conf [...]
@@ -206,7 +206,7 @@
     "mcpServer": { "index": 56, "kind": "parameter", "displayName": "Mcp 
Server", "group": "common", "label": "", "required": false, "type": "object", 
"javaType": "java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"mcpServer.", "multiValue": true, "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "MCP (Model Contex [...]
     "mcpTimeout": { "index": 57, "kind": "parameter", "displayName": "Mcp 
Timeout", "group": "common", "label": "", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "defaultValue": 20, "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "Timeout in seconds for MCP tool call requests. 
Applies to all MCP operations includi [...]
     "mcpToolRefresh": { "index": 58, "kind": "parameter", "displayName": "Mcp 
Tool Refresh", "group": "common", "label": "", "required": false, "type": 
"boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "defaultValue": true, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "configuration", "description": "Refresh the advertised 
tool list when an MCP server notifies that its [...]
-    "model": { "index": 59, "kind": "parameter", "displayName": "Model", 
"group": "common", "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" },
+    "model": { "index": 59, "kind": "parameter", "displayName": "Model", 
"group": "common", "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 the selected operation" },
     "moderationModel": { "index": 60, "kind": "parameter", "displayName": 
"Moderation Model", "group": "common", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
"omni-moderation-latest", "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "The model to use for moderation" },
     "outputClass": { "index": 61, "kind": "parameter", "displayName": "Output 
Class", "group": "common", "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" },
     "parallelToolExecution": { "index": 62, "kind": "parameter", 
"displayName": "Parallel Tool Execution", "group": "common", "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": "Execute the tool calls returned by the model 
in a sing [...]
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openai.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openai.json
index 09982cd59edd..071be79b4cac 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openai.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openai.json
@@ -147,7 +147,7 @@
     "CamelOpenAIImageTotalTokens": { "index": 108, "kind": "header", 
"displayName": "", "group": "common", "label": "", "required": false, 
"javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The total number of tokens billed for 
the image request. Only reported by GPT image models", "constantName": 
"org.apache.camel.component.openai.OpenAIConstants#IMAGE_TOTAL_TOKENS" }
   },
   "properties": {
-    "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "common", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.openai.OpenAIOperations", "enum": [ 
"chat-completion", "responses", "responses-retrieve", "responses-cancel", 
"batch", "batch-retrieve", "batch-cancel", "batch-results", "embeddings", 
"tool-execution", "audio-transcription", "audio-translation", "audio-speech", 
"moderation", "image-generation", "image-edit", " [...]
+    "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "common", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.openai.OpenAIOperations", "enum": [ 
"chat-completion", "decisions", "responses", "responses-retrieve", 
"responses-cancel", "batch", "batch-retrieve", "batch-cancel", "batch-results", 
"embeddings", "tool-execution", "audio-transcription", "audio-translation", 
"audio-speech", "moderation", "image-generation", "i [...]
     "additionalBodyProperty": { "index": 1, "kind": "parameter", 
"displayName": "Additional Body Property", "group": "common", "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": "configurat [...]
     "additionalHeader": { "index": 2, "kind": "parameter", "displayName": 
"Additional Header", "group": "common", "label": "", "required": false, "type": 
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", 
"prefix": "additionalHeader.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": true, "security": 
"secret", "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configur [...]
     "additionalResponseHeader": { "index": 3, "kind": "parameter", 
"displayName": "Additional Response Header", "group": "common", "label": "", 
"required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"additionalResponseHeader.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "conf [...]
@@ -206,7 +206,7 @@
     "mcpServer": { "index": 56, "kind": "parameter", "displayName": "Mcp 
Server", "group": "common", "label": "", "required": false, "type": "object", 
"javaType": "java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"mcpServer.", "multiValue": true, "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "MCP (Model Contex [...]
     "mcpTimeout": { "index": 57, "kind": "parameter", "displayName": "Mcp 
Timeout", "group": "common", "label": "", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "defaultValue": 20, "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "Timeout in seconds for MCP tool call requests. 
Applies to all MCP operations includi [...]
     "mcpToolRefresh": { "index": 58, "kind": "parameter", "displayName": "Mcp 
Tool Refresh", "group": "common", "label": "", "required": false, "type": 
"boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "defaultValue": true, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "configuration", "description": "Refresh the advertised 
tool list when an MCP server notifies that its [...]
-    "model": { "index": 59, "kind": "parameter", "displayName": "Model", 
"group": "common", "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" },
+    "model": { "index": 59, "kind": "parameter", "displayName": "Model", 
"group": "common", "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 the selected operation" },
     "moderationModel": { "index": 60, "kind": "parameter", "displayName": 
"Moderation Model", "group": "common", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
"omni-moderation-latest", "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "The model to use for moderation" },
     "outputClass": { "index": 61, "kind": "parameter", "displayName": "Output 
Class", "group": "common", "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" },
     "parallelToolExecution": { "index": 62, "kind": "parameter", 
"displayName": "Parallel Tool Execution", "group": "common", "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": "Execute the tool calls returned by the model 
in a sing [...]
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openai-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openai-component.adoc
index 002f1aebb2dd..24dcf60ca7c0 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openai-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openai-component.adoc
@@ -30,6 +30,39 @@ Maven users will need to add the following dependency to 
their `pom.xml` for thi
 </dependency>
 ----
 
+== Decisions
+
+`openai:decisions` (also `llm:decisions`) accepts a native
+`com.openai.models.decisions.DecisionCreateParams` body and returns a
+`com.openai.models.decisions.Decision` body. It uses the endpoint's managed 
OpenAI client,
+including credentials, base URL, TLS, proxy, timeout and retry settings.
+Decisions does not initialize configured MCP servers or route tools.
+
+[source,java]
+----
+var request = DecisionCreateParams.builder()
+    .model("gpt-6-luna")
+    .input("The service is unavailable for every customer")
+    .addQuestion(DecisionCreateParams.Question.Predicate.builder()
+        .name("urgent").instructions("Does this require immediate 
attention?").build())
+    .build();
+var response = template.requestBody("openai:decisions", request, 
Decision.class);
+double probability = response.answers().get(0).asPredicate().probability();
+----
+
+Use a model and API endpoint that implement Decisions. Inputs are text or 
native ordered
+text/image messages; images use inline PNG, JPEG, GIF or WebP base64 data 
URLs. Other input
+modalities and hosted image URLs are rejected by this integration. Requests 
contain 1–200
+questions and at most 128 images. Responses are validated against the complete 
request before
+returning any result. OpenAI predicate probabilities have no built-in Boolean 
threshold.
+
+Refusal raises `OpenAIDecisionRefusalException`, invalid provider output raises
+`OpenAIDecisionResponseException`, and transport/API/client-start failures 
raise
+`OpenAIDecisionServiceException`. No failure is converted into a decision 
value.
+
+See the
+https://developers.openai.com/api/docs/guides/decisions[Decisions guide] for 
the provider contract.
+
 == URI Format
 
 [source]
@@ -44,6 +77,7 @@ TIP: Prefer `llm:` in new routes for discoverability. 
Examples below use `openai
 Supported operations:
 
 * `chat-completion` - Generate chat completions using language models
+* `decisions` - Native typed predicate, choice and rubric assessments of text 
and images
 * `responses` - Call the OpenAI Responses API (hosted tools, server-side 
conversation state; non-streaming)
 * `responses-retrieve` - Retrieve a stored Responses API response, such as one 
started in background mode
 * `responses-cancel` - Cancel a Responses API response still running in 
background mode
diff --git 
a/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/llm.json
 
b/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/llm.json
index c052860fbcf8..c6e238e99c9e 100644
--- 
a/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/llm.json
+++ 
b/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/llm.json
@@ -147,7 +147,7 @@
     "CamelOpenAIImageTotalTokens": { "index": 108, "kind": "header", 
"displayName": "", "group": "common", "label": "", "required": false, 
"javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The total number of tokens billed for 
the image request. Only reported by GPT image models", "constantName": 
"org.apache.camel.component.openai.OpenAIConstants#IMAGE_TOTAL_TOKENS" }
   },
   "properties": {
-    "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "common", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.openai.OpenAIOperations", "enum": [ 
"chat-completion", "responses", "responses-retrieve", "responses-cancel", 
"batch", "batch-retrieve", "batch-cancel", "batch-results", "embeddings", 
"tool-execution", "audio-transcription", "audio-translation", "audio-speech", 
"moderation", "image-generation", "image-edit", " [...]
+    "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "common", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.openai.OpenAIOperations", "enum": [ 
"chat-completion", "decisions", "responses", "responses-retrieve", 
"responses-cancel", "batch", "batch-retrieve", "batch-cancel", "batch-results", 
"embeddings", "tool-execution", "audio-transcription", "audio-translation", 
"audio-speech", "moderation", "image-generation", "i [...]
     "additionalBodyProperty": { "index": 1, "kind": "parameter", 
"displayName": "Additional Body Property", "group": "common", "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": "configurat [...]
     "additionalHeader": { "index": 2, "kind": "parameter", "displayName": 
"Additional Header", "group": "common", "label": "", "required": false, "type": 
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", 
"prefix": "additionalHeader.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": true, "security": 
"secret", "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configur [...]
     "additionalResponseHeader": { "index": 3, "kind": "parameter", 
"displayName": "Additional Response Header", "group": "common", "label": "", 
"required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"additionalResponseHeader.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "conf [...]
@@ -206,7 +206,7 @@
     "mcpServer": { "index": 56, "kind": "parameter", "displayName": "Mcp 
Server", "group": "common", "label": "", "required": false, "type": "object", 
"javaType": "java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"mcpServer.", "multiValue": true, "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "MCP (Model Contex [...]
     "mcpTimeout": { "index": 57, "kind": "parameter", "displayName": "Mcp 
Timeout", "group": "common", "label": "", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "defaultValue": 20, "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "Timeout in seconds for MCP tool call requests. 
Applies to all MCP operations includi [...]
     "mcpToolRefresh": { "index": 58, "kind": "parameter", "displayName": "Mcp 
Tool Refresh", "group": "common", "label": "", "required": false, "type": 
"boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "defaultValue": true, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "configuration", "description": "Refresh the advertised 
tool list when an MCP server notifies that its [...]
-    "model": { "index": 59, "kind": "parameter", "displayName": "Model", 
"group": "common", "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" },
+    "model": { "index": 59, "kind": "parameter", "displayName": "Model", 
"group": "common", "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 the selected operation" },
     "moderationModel": { "index": 60, "kind": "parameter", "displayName": 
"Moderation Model", "group": "common", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
"omni-moderation-latest", "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "The model to use for moderation" },
     "outputClass": { "index": 61, "kind": "parameter", "displayName": "Output 
Class", "group": "common", "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" },
     "parallelToolExecution": { "index": 62, "kind": "parameter", 
"displayName": "Parallel Tool Execution", "group": "common", "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": "Execute the tool calls returned by the model 
in a sing [...]
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 09982cd59edd..071be79b4cac 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
@@ -147,7 +147,7 @@
     "CamelOpenAIImageTotalTokens": { "index": 108, "kind": "header", 
"displayName": "", "group": "common", "label": "", "required": false, 
"javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The total number of tokens billed for 
the image request. Only reported by GPT image models", "constantName": 
"org.apache.camel.component.openai.OpenAIConstants#IMAGE_TOTAL_TOKENS" }
   },
   "properties": {
-    "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "common", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.openai.OpenAIOperations", "enum": [ 
"chat-completion", "responses", "responses-retrieve", "responses-cancel", 
"batch", "batch-retrieve", "batch-cancel", "batch-results", "embeddings", 
"tool-execution", "audio-transcription", "audio-translation", "audio-speech", 
"moderation", "image-generation", "image-edit", " [...]
+    "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "common", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.openai.OpenAIOperations", "enum": [ 
"chat-completion", "decisions", "responses", "responses-retrieve", 
"responses-cancel", "batch", "batch-retrieve", "batch-cancel", "batch-results", 
"embeddings", "tool-execution", "audio-transcription", "audio-translation", 
"audio-speech", "moderation", "image-generation", "i [...]
     "additionalBodyProperty": { "index": 1, "kind": "parameter", 
"displayName": "Additional Body Property", "group": "common", "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": "configurat [...]
     "additionalHeader": { "index": 2, "kind": "parameter", "displayName": 
"Additional Header", "group": "common", "label": "", "required": false, "type": 
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", 
"prefix": "additionalHeader.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": true, "security": 
"secret", "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configur [...]
     "additionalResponseHeader": { "index": 3, "kind": "parameter", 
"displayName": "Additional Response Header", "group": "common", "label": "", 
"required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"additionalResponseHeader.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "conf [...]
@@ -206,7 +206,7 @@
     "mcpServer": { "index": 56, "kind": "parameter", "displayName": "Mcp 
Server", "group": "common", "label": "", "required": false, "type": "object", 
"javaType": "java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"mcpServer.", "multiValue": true, "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "MCP (Model Contex [...]
     "mcpTimeout": { "index": 57, "kind": "parameter", "displayName": "Mcp 
Timeout", "group": "common", "label": "", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "defaultValue": 20, "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "Timeout in seconds for MCP tool call requests. 
Applies to all MCP operations includi [...]
     "mcpToolRefresh": { "index": 58, "kind": "parameter", "displayName": "Mcp 
Tool Refresh", "group": "common", "label": "", "required": false, "type": 
"boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "defaultValue": true, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "configuration", "description": "Refresh the advertised 
tool list when an MCP server notifies that its [...]
-    "model": { "index": 59, "kind": "parameter", "displayName": "Model", 
"group": "common", "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" },
+    "model": { "index": 59, "kind": "parameter", "displayName": "Model", 
"group": "common", "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 the selected operation" },
     "moderationModel": { "index": 60, "kind": "parameter", "displayName": 
"Moderation Model", "group": "common", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 
"omni-moderation-latest", "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "The model to use for moderation" },
     "outputClass": { "index": 61, "kind": "parameter", "displayName": "Output 
Class", "group": "common", "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" },
     "parallelToolExecution": { "index": 62, "kind": "parameter", 
"displayName": "Parallel Tool Execution", "group": "common", "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": "Execute the tool calls returned by the model 
in a sing [...]
diff --git 
a/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc 
b/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc
index 002f1aebb2dd..24dcf60ca7c0 100644
--- a/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc
+++ b/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc
@@ -30,6 +30,39 @@ Maven users will need to add the following dependency to 
their `pom.xml` for thi
 </dependency>
 ----
 
+== Decisions
+
+`openai:decisions` (also `llm:decisions`) accepts a native
+`com.openai.models.decisions.DecisionCreateParams` body and returns a
+`com.openai.models.decisions.Decision` body. It uses the endpoint's managed 
OpenAI client,
+including credentials, base URL, TLS, proxy, timeout and retry settings.
+Decisions does not initialize configured MCP servers or route tools.
+
+[source,java]
+----
+var request = DecisionCreateParams.builder()
+    .model("gpt-6-luna")
+    .input("The service is unavailable for every customer")
+    .addQuestion(DecisionCreateParams.Question.Predicate.builder()
+        .name("urgent").instructions("Does this require immediate 
attention?").build())
+    .build();
+var response = template.requestBody("openai:decisions", request, 
Decision.class);
+double probability = response.answers().get(0).asPredicate().probability();
+----
+
+Use a model and API endpoint that implement Decisions. Inputs are text or 
native ordered
+text/image messages; images use inline PNG, JPEG, GIF or WebP base64 data 
URLs. Other input
+modalities and hosted image URLs are rejected by this integration. Requests 
contain 1–200
+questions and at most 128 images. Responses are validated against the complete 
request before
+returning any result. OpenAI predicate probabilities have no built-in Boolean 
threshold.
+
+Refusal raises `OpenAIDecisionRefusalException`, invalid provider output raises
+`OpenAIDecisionResponseException`, and transport/API/client-start failures 
raise
+`OpenAIDecisionServiceException`. No failure is converted into a decision 
value.
+
+See the
+https://developers.openai.com/api/docs/guides/decisions[Decisions guide] for 
the provider contract.
+
 == URI Format
 
 [source]
@@ -44,6 +77,7 @@ TIP: Prefer `llm:` in new routes for discoverability. 
Examples below use `openai
 Supported operations:
 
 * `chat-completion` - Generate chat completions using language models
+* `decisions` - Native typed predicate, choice and rubric assessments of text 
and images
 * `responses` - Call the OpenAI Responses API (hosted tools, server-side 
conversation state; non-streaming)
 * `responses-retrieve` - Retrieve a stored Responses API response, such as one 
started in background mode
 * `responses-cancel` - Cancel a Responses API response still running in 
background mode
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 b19ef617531d..bec600217483 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
@@ -104,7 +104,7 @@ public class OpenAIConfiguration implements Cloneable {
     private Map<String, Object> additionalHeader;
 
     @UriParam
-    @Metadata(description = "The model to use for chat completion")
+    @Metadata(description = "The model to use for the selected operation")
     private String model;
 
     @UriParam
diff --git 
a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionRefusalException.java
 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionRefusalException.java
new file mode 100644
index 000000000000..04c8d1f263f8
--- /dev/null
+++ 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionRefusalException.java
@@ -0,0 +1,30 @@
+/*
+ * 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.openai;
+
+import org.apache.camel.RuntimeCamelException;
+
+/** The provider declined to answer at least one question. */
+public class OpenAIDecisionRefusalException extends RuntimeCamelException {
+    public OpenAIDecisionRefusalException(String message) {
+        super(message);
+    }
+
+    public OpenAIDecisionRefusalException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git 
a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionResponseException.java
 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionResponseException.java
new file mode 100644
index 000000000000..651488e4f4c8
--- /dev/null
+++ 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionResponseException.java
@@ -0,0 +1,30 @@
+/*
+ * 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.openai;
+
+import org.apache.camel.RuntimeCamelException;
+
+/** The provider returned an invalid or incomplete answer. */
+public class OpenAIDecisionResponseException extends RuntimeCamelException {
+    public OpenAIDecisionResponseException(String message) {
+        super(message);
+    }
+
+    public OpenAIDecisionResponseException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git 
a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionServiceException.java
 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionServiceException.java
new file mode 100644
index 000000000000..18297cb243f5
--- /dev/null
+++ 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionServiceException.java
@@ -0,0 +1,30 @@
+/*
+ * 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.openai;
+
+import org.apache.camel.RuntimeCamelException;
+
+/** A transport or service failure prevented the assessment. */
+public class OpenAIDecisionServiceException extends RuntimeCamelException {
+    public OpenAIDecisionServiceException(String message) {
+        super(message);
+    }
+
+    public OpenAIDecisionServiceException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git 
a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionsProducer.java
 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionsProducer.java
new file mode 100644
index 000000000000..b616fd8cd878
--- /dev/null
+++ 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionsProducer.java
@@ -0,0 +1,36 @@
+/*
+ * 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.openai;
+
+import com.openai.models.decisions.DecisionCreateParams;
+import org.apache.camel.Exchange;
+import org.apache.camel.support.DefaultProducer;
+
+/** Sends native Decisions requests without executing tools or applying 
decision policy. */
+public class OpenAIDecisionsProducer extends DefaultProducer {
+    public OpenAIDecisionsProducer(OpenAIEndpoint endpoint) {
+        super(endpoint);
+    }
+
+    @Override
+    public void process(Exchange exchange) throws Exception {
+        if (!(exchange.getMessage().getBody() instanceof DecisionCreateParams 
request)) {
+            throw new IllegalArgumentException("Decisions requires a 
DecisionCreateParams body");
+        }
+        exchange.getMessage().setBody(((OpenAIEndpoint) 
getEndpoint()).decide(request));
+    }
+}
diff --git 
a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionsSupport.java
 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionsSupport.java
new file mode 100644
index 000000000000..751e54bc0f59
--- /dev/null
+++ 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIDecisionsSupport.java
@@ -0,0 +1,276 @@
+/*
+ * 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.openai;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+import com.openai.client.OpenAIClient;
+import com.openai.errors.OpenAIException;
+import com.openai.errors.OpenAIInvalidDataException;
+import com.openai.models.decisions.Decision;
+import com.openai.models.decisions.DecisionCreateParams;
+import com.openai.models.decisions.DecisionInputImage;
+
+/** Native Decisions validation shared by component callers and provider 
adapters. */
+public final class OpenAIDecisionsSupport {
+    private OpenAIDecisionsSupport() {
+    }
+
+    public static void validateRequest(DecisionCreateParams request) {
+        try {
+            if (request == null || request.questions().isEmpty() || 
request.questions().size() > 200) {
+                throw new IllegalArgumentException("Decisions requires between 
1 and 200 questions");
+            }
+            request._body().validate();
+            if (!request._additionalBodyProperties().isEmpty()) {
+                throw new IllegalArgumentException("Unsupported Decisions 
request fields");
+            }
+            Set<String> names = new HashSet<>();
+            for (var question : request.questions()) {
+                Optional<String> name = name(question);
+                if (name.isPresent() && !names.add(name.get())) {
+                    throw new IllegalArgumentException("Decisions question 
names must be unique");
+                }
+                if (question.isChoice()) {
+                    var choices = question.asChoice().choices();
+                    Set<Object> values = new HashSet<>();
+                    if (choices.size() < 2 || choices.size() > 255
+                            || choices.stream().anyMatch(
+                                    c -> !values.add(c.value().isString() ? 
c.value().asString() : c.value().asBool()))) {
+                        throw new IllegalArgumentException("Decisions choice 
requires 2 to 255 distinct values");
+                    }
+                } else if (question.isScore()) {
+                    var levels = question.asScore().levels();
+                    Set<String> labels = new HashSet<>();
+                    if (levels.isEmpty() || levels.stream().anyMatch(l -> 
!labels.add(l.label()))) {
+                        throw new IllegalArgumentException("Decisions score 
requires distinct ordered levels");
+                    }
+                }
+            }
+            validateInput(request.input());
+        } catch (OpenAIInvalidDataException e) {
+            throw new IllegalArgumentException("Invalid Decisions request 
structure");
+        }
+    }
+
+    public static void validateInput(DecisionCreateParams.Input input) {
+        if (input == null) {
+            throw new IllegalArgumentException("Decisions input is required");
+        }
+        try {
+            input.validate();
+            validateContent(input);
+        } catch (OpenAIInvalidDataException e) {
+            throw new IllegalArgumentException("Invalid Decisions input 
structure");
+        }
+    }
+
+    private static void validateContent(DecisionCreateParams.Input input) {
+        if (input.isString()) {
+            validateText(input.asString());
+            return;
+        }
+        var messages = input.asDecisionInputMessages();
+        if (messages.isEmpty()) {
+            throw new IllegalArgumentException("Decisions input messages must 
not be empty");
+        }
+        int images = 0;
+        for (var message : messages) {
+            var content = message.content();
+            if (!message._additionalProperties().isEmpty()) {
+                throw new IllegalArgumentException("Unsupported Decisions 
input message fields");
+            }
+            if (content.isString()) {
+                validateText(content.asString());
+            } else {
+                if (content.asParts().isEmpty()) {
+                    throw new IllegalArgumentException("Decisions input parts 
must not be empty");
+                }
+                for (var part : content.asParts()) {
+                    if (part.isInputText()) {
+                        if 
(!part.asInputText()._additionalProperties().isEmpty()) {
+                            throw new IllegalArgumentException("Unsupported 
Decisions text fields");
+                        }
+                        validateText(part.asInputText().text());
+                    } else if (part.isInputImage()) {
+                        if (++images > 128) {
+                            throw new IllegalArgumentException("Decisions 
accepts at most 128 images per request");
+                        }
+                        validateImage(part.asInputImage());
+                    } else {
+                        throw new IllegalArgumentException("Decisions accepts 
only text and image input parts");
+                    }
+                }
+            }
+        }
+    }
+
+    private static void validateText(String text) {
+        if (text.length() > 10_485_760) {
+            throw new IllegalArgumentException("Decisions text exceeds the 
provider input limit");
+        }
+    }
+
+    private static void validateImage(DecisionInputImage image) {
+        String data = image.imageUrl();
+        int start = data.indexOf(";base64,");
+        if (!image._additionalProperties().isEmpty() || start < 0
+                || !Set.of("data:image/png", "data:image/jpeg", 
"data:image/webp", "data:image/gif")
+                        .contains(data.substring(0, start))
+                || data.length() > 1_073_741_824) {
+            throw new IllegalArgumentException("Decisions requires inline PNG, 
JPEG, WebP or GIF base64 image data URLs");
+        }
+        start += 8;
+        int length = data.length() - start;
+        if (length == 0 || length % 4 != 0) {
+            throw new IllegalArgumentException("Invalid image base64 
encoding");
+        }
+        // Scan without decoding to avoid allocating another copy of image 
data up to 1 GiB.
+        int padding = 0;
+        for (int i = start; i < data.length(); i++) {
+            char c = data.charAt(i);
+            if (c == '=' && i >= data.length() - 2) {
+                padding++;
+            } else if (padding != 0 || !(c >= 'A' && c <= 'Z' || c >= 'a' && c 
<= 'z'
+                    || c >= '0' && c <= '9' || c == '+' || c == '/')) {
+                throw new IllegalArgumentException("Invalid image base64 
encoding");
+            }
+        }
+    }
+
+    static Decision execute(OpenAIClient client, DecisionCreateParams request) 
throws InterruptedException {
+        try {
+            Decision response = client.decisions().create(request);
+            if (Thread.currentThread().isInterrupted()) {
+                throw new InterruptedException("OpenAI decision interrupted");
+            }
+            validateResponse(request, response);
+            return response;
+        } catch (OpenAIInvalidDataException e) {
+            throw new OpenAIDecisionResponseException("Invalid OpenAI decision 
response", e);
+        } catch (OpenAIException e) {
+            throw new OpenAIDecisionServiceException("OpenAI decision request 
failed", e);
+        }
+    }
+
+    private static Optional<String> name(DecisionCreateParams.Question 
question) {
+        if (question.isPredicate()) {
+            return question.asPredicate().name();
+        } else if (question.isChoice()) {
+            return question.asChoice().name();
+        }
+        return question.asScore().name();
+    }
+
+    private static void validateResponse(DecisionCreateParams request, 
Decision response) {
+        if (response == null || response.answers().size() != 
request.questions().size()) {
+            throw invalid("Decisions returned an unexpected answer count");
+        }
+        if (response.model().isBlank()) {
+            throw invalid("Decisions response is missing its model");
+        }
+        if (!response._usage().isMissing() && !response._usage().isNull()) {
+            var usage = response.usage();
+            if (usage.inputTokens() < 0 || usage.outputTokens() < 0 || 
usage.totalTokens() < 0) {
+                throw invalid("Decisions response contains invalid token 
usage");
+            }
+        }
+        for (int i = 0; i < request.questions().size(); i++) {
+            var question = request.questions().get(i);
+            var answer = response.answers().get(i);
+            Optional<String> answerName;
+            if (answer.isRefusal()) {
+                throw new OpenAIDecisionRefusalException("OpenAI declined to 
answer a decision question");
+            } else if (question.isPredicate() && answer.isPredicate()) {
+                probability(answer.asPredicate().probability());
+                answerName = answer.asPredicate().name();
+            } else if (question.isChoice() && answer.isChoice()) {
+                choice(question.asChoice(), answer.asChoice());
+                answerName = answer.asChoice().name();
+            } else if (question.isScore() && answer.isScore()) {
+                score(question.asScore(), answer.asScore());
+                answerName = answer.asScore().name();
+            } else {
+                throw invalid("Decisions answer type does not match its 
question");
+            }
+            if (!Objects.equals(name(question), answerName)) {
+                throw invalid("Decisions answer name does not match its 
question");
+            }
+        }
+    }
+
+    private static void choice(DecisionCreateParams.Question.Choice question, 
Decision.Answer.Choice answer) {
+        Set<Object> expected = new HashSet<>();
+        question.choices().forEach(c -> expected.add(c.value().isString() ? 
c.value().asString() : c.value().asBool()));
+        if (!expected.contains(answer.choice().isString() ? 
answer.choice().asString() : answer.choice().asBool())) {
+            throw invalid("Decisions choice is outside the declared domain");
+        }
+        if (!answer._confidence().isMissing() && 
!answer._confidence().isNull()) {
+            probability(answer.confidence());
+        }
+        if (!answer._probabilities().isMissing() && 
!answer._probabilities().isNull()) {
+            Set<Object> actual = new HashSet<>();
+            for (var p : answer.probabilities()) {
+                probability(p.probability());
+                if (!actual.add(p.value().isString() ? p.value().asString() : 
p.value().asBool())) {
+                    throw invalid("Duplicate Decisions choice probability");
+                }
+            }
+            if (!actual.equals(expected)) {
+                throw invalid("Decisions probabilities do not cover the 
declared choices");
+            }
+        }
+    }
+
+    private static void score(DecisionCreateParams.Question.Score question, 
Decision.Answer.Score answer) {
+        List<DecisionCreateParams.Question.Score.Level> levels = 
question.levels();
+        double score = answer.score();
+        if (!Double.isFinite(score) || score < 0 || score > levels.size() - 1) 
{
+            throw invalid("Decisions score is outside the ordered rubric");
+        }
+        if (!answer._confidence().isMissing() && 
!answer._confidence().isNull()) {
+            probability(answer.confidence());
+        }
+        if (!answer._probabilities().isMissing() && 
!answer._probabilities().isNull()) {
+            Set<Long> actual = new HashSet<>();
+            for (var p : answer.probabilities()) {
+                probability(p.probability());
+                if (p.value() < 0 || p.value() >= levels.size() || 
!actual.add(p.value())
+                        || !levels.get((int) 
p.value()).label().equals(p.label())) {
+                    throw invalid("Decisions probability does not match the 
ordered rubric");
+                }
+            }
+            if (actual.size() != levels.size()) {
+                throw invalid("Decisions probabilities do not cover the 
ordered rubric");
+            }
+        }
+    }
+
+    private static void probability(double value) {
+        if (!Double.isFinite(value) || value < 0 || value > 1) {
+            throw invalid("Decisions probability or confidence is outside 
[0,1]");
+        }
+    }
+
+    private static OpenAIDecisionResponseException invalid(String message) {
+        return new OpenAIDecisionResponseException(message);
+    }
+}
diff --git 
a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIEndpoint.java
 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIEndpoint.java
index 9076e97bca27..1b65e239cb5b 100644
--- 
a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIEndpoint.java
+++ 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIEndpoint.java
@@ -43,6 +43,8 @@ import com.openai.client.OpenAIClient;
 import com.openai.client.okhttp.OpenAIOkHttpClient;
 import com.openai.core.Timeout;
 import com.openai.models.chat.completions.ChatCompletionFunctionTool;
+import com.openai.models.decisions.Decision;
+import com.openai.models.decisions.DecisionCreateParams;
 import io.modelcontextprotocol.client.McpClient;
 import io.modelcontextprotocol.client.McpSyncClient;
 import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport;
@@ -68,6 +70,7 @@ import org.apache.camel.spi.UriPath;
 import org.apache.camel.support.DefaultEndpoint;
 import org.apache.camel.support.OAuthHelper;
 import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -88,7 +91,7 @@ public class OpenAIEndpoint extends DefaultEndpoint {
 
     @UriPath
     @Metadata(required = true,
-              description = "The operation to perform: 'chat-completion', 
'responses', 'responses-retrieve', "
+              description = "The operation to perform: 'chat-completion', 
'decisions', 'responses', 'responses-retrieve', "
                             + "'responses-cancel', 'batch', 'batch-retrieve', 
'batch-cancel', 'batch-results', "
                             + "'embeddings', 'tool-execution', 
'audio-transcription', "
                             + "'audio-translation', 'audio-speech', 
'moderation', 'image-generation', "
@@ -128,6 +131,7 @@ public class OpenAIEndpoint extends DefaultEndpoint {
     public Producer createProducer() throws Exception {
         return switch (operation) {
             case chatCompletion -> new OpenAIProducer(this);
+            case decisions -> new OpenAIDecisionsProducer(this);
             case responses -> new OpenAIResponsesProducer(this);
             case responsesRetrieve -> new OpenAIResponsesStoredProducer(this, 
false);
             case responsesCancel -> new OpenAIResponsesStoredProducer(this, 
true);
@@ -180,9 +184,11 @@ public class OpenAIEndpoint extends DefaultEndpoint {
             // the webhook consumer verifies signatures with a client of its 
own and needs no API key
             client = createClient();
         }
-        registerRouteToolRegistryListener();
-        initializeMcpServers();
-        refreshRouteTools();
+        if (operation != OpenAIOperations.decisions) {
+            registerRouteToolRegistryListener();
+            initializeMcpServers();
+            refreshRouteTools();
+        }
     }
 
     @Override
@@ -960,6 +966,26 @@ public class OpenAIEndpoint extends DefaultEndpoint {
         return configuration;
     }
 
+    /** Executes a Decisions request using this endpoint's managed client and 
configuration. */
+    public Decision decide(DecisionCreateParams request) throws Exception {
+        if (operation != OpenAIOperations.decisions) {
+            throw new IllegalStateException("Decisions requires an 
openai:decisions endpoint");
+        }
+        OpenAIDecisionsSupport.validateRequest(request);
+        if (Thread.currentThread().isInterrupted()) {
+            throw new InterruptedException("OpenAI decision interrupted");
+        }
+        if (getCamelContext().isStopping() || getCamelContext().isStopped()) {
+            throw new OpenAIDecisionServiceException("OpenAI Decisions 
requires a running CamelContext");
+        }
+        try {
+            ServiceHelper.startService(this);
+        } catch (Exception e) {
+            throw new OpenAIDecisionServiceException("Unable to start the 
OpenAI Decisions client", e);
+        }
+        return OpenAIDecisionsSupport.execute(client, request);
+    }
+
     public OpenAIClient getClient() {
         return client;
     }
diff --git 
a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIOperations.java
 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIOperations.java
index 5772c7a9c2da..a1e29a6ec5e6 100644
--- 
a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIOperations.java
+++ 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIOperations.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.openai;
 public enum OpenAIOperations {
 
     chatCompletion("chat-completion"),
+    decisions("decisions"),
     responses("responses"),
     responsesRetrieve("responses-retrieve"),
     responsesCancel("responses-cancel"),
@@ -50,7 +51,7 @@ public enum OpenAIOperations {
         }
         throw new IllegalArgumentException(
                 "Unknown operation: " + value
-                                           + ". Supported: chat-completion, 
responses, responses-retrieve, "
+                                           + ". Supported: chat-completion, 
decisions, responses, responses-retrieve, "
                                            + "responses-cancel, batch, 
batch-retrieve, batch-cancel, batch-results, "
                                            + "embeddings, tool-execution, "
                                            + "audio-transcription, 
audio-translation, audio-speech, moderation, "
diff --git 
a/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/OpenAIDecisionsHttpTest.java
 
b/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/OpenAIDecisionsHttpTest.java
new file mode 100644
index 000000000000..50ca4aed1a39
--- /dev/null
+++ 
b/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/OpenAIDecisionsHttpTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.openai;
+
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import com.openai.models.decisions.DecisionChoiceOption;
+import com.openai.models.decisions.DecisionCreateParams;
+import com.openai.models.decisions.DecisionInputImage;
+import com.openai.models.decisions.DecisionInputMessage;
+import com.openai.models.decisions.DecisionInputPart;
+import com.sun.net.httpserver.HttpServer;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class OpenAIDecisionsHttpTest {
+    private HttpServer server;
+    private DefaultCamelContext context;
+    private OpenAIEndpoint endpoint;
+    private final AtomicReference<String> received = new AtomicReference<>();
+    private final AtomicReference<String> method = new AtomicReference<>();
+    private volatile String response;
+    private volatile int status = 200;
+
+    @BeforeEach
+    void start() throws Exception {
+        server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
+        server.createContext("/v1/decisions", exchange -> {
+            method.set(exchange.getRequestMethod());
+            received.set(new String(exchange.getRequestBody().readAllBytes(), 
StandardCharsets.UTF_8));
+            byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
+            exchange.getResponseHeaders().add("Content-Type", 
"application/json");
+            exchange.sendResponseHeaders(status, bytes.length);
+            try (var body = exchange.getResponseBody()) {
+                body.write(bytes);
+            }
+        });
+        server.start();
+        context = new DefaultCamelContext();
+        endpoint = 
context.getEndpoint("openai:decisions?apiKey=test&maxRetries=0&baseUrl=http://127.0.0.1:";
+                                       + server.getAddress().getPort() + "/v1",
+                OpenAIEndpoint.class);
+        context.start();
+    }
+
+    @AfterEach
+    void stop() throws Exception {
+        try {
+            if (context != null) {
+                context.close();
+            }
+        } finally {
+            if (server != null) {
+                server.stop(0);
+            }
+        }
+    }
+
+    @Test
+    void serializesNativeImageAndDeserializesPredicate() throws Exception {
+        response = """
+                
{"model":"gpt-6-luna","answers":[{"type":"predicate","name":"test","probability":0.96}]}
+                """;
+        var image = DecisionInputPart.ofInputImage(DecisionInputImage.builder()
+                .imageUrl("data:image/png;base64,AA==").build());
+        var request = 
request().toBuilder().inputOfDecisionInputMessages(List.of(
+                
DecisionInputMessage.builder().contentOfParts(List.of(image)).build())).build();
+        
assertThat(endpoint.decide(request).answers().get(0).asPredicate().probability()).isEqualTo(0.96);
+        assertThat(method.get()).isEqualTo("POST");
+        assertThat(received.get()).contains("input_image", 
"data:image/png;base64,AA==", "predicate");
+    }
+
+    @Test
+    void absentOptionalChoiceUncertaintyRemainsAbsent() throws Exception {
+        response = """
+                
{"model":"gpt-6-luna","answers":[{"type":"choice","name":"test","choice":"a"}]}
+                """;
+        var request = 
DecisionCreateParams.builder().model("gpt-6-luna").input("Evidence")
+                
.addQuestion(DecisionCreateParams.Question.Choice.builder().name("test").instructions("Choose")
+                        
.addChoice(DecisionChoiceOption.builder().value("a").build())
+                        
.addChoice(DecisionChoiceOption.builder().value("b").build()).build())
+                .build();
+        var answer = endpoint.decide(request).answers().get(0).asChoice();
+        assertThat(answer._confidence().isMissing()).isTrue();
+        assertThat(answer._probabilities().isMissing()).isTrue();
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "probability", "model", "usage" })
+    void malformedResponsesHaveDedicatedException(String field) {
+        response = """
+                
{"model":"gpt-6-luna","answers":[{"type":"predicate","name":"test","probability":0.9}]}
+                """;
+        response = switch (field) {
+            case "probability" -> response.replace("0.9", "\"invalid\"");
+            case "model" -> response.replace("\"model\":\"gpt-6-luna\",", "");
+            default -> response.replace("}]}", 
"}],\"usage\":{\"input_tokens\":\"invalid\"}}");
+        };
+        assertThatThrownBy(() -> 
endpoint.decide(request())).isInstanceOf(OpenAIDecisionResponseException.class);
+    }
+
+    @Test
+    void serviceFailuresHaveDedicatedException() {
+        status = 503;
+        response = "{\"error\":{\"message\":\"unavailable\"}}";
+        assertThatThrownBy(() -> 
endpoint.decide(request())).isInstanceOf(OpenAIDecisionServiceException.class);
+    }
+
+    private static DecisionCreateParams request() {
+        return 
DecisionCreateParams.builder().model("gpt-6-luna").input("Evidence")
+                .addQuestion(DecisionCreateParams.Question.Predicate.builder()
+                        .name("test").instructions("Is it relevant?").build())
+                .build();
+    }
+}
diff --git 
a/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/OpenAIDecisionsTest.java
 
b/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/OpenAIDecisionsTest.java
new file mode 100644
index 000000000000..ee976ee25529
--- /dev/null
+++ 
b/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/OpenAIDecisionsTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.openai;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import com.openai.client.OpenAIClient;
+import com.openai.models.decisions.Decision;
+import com.openai.models.decisions.DecisionCreateParams;
+import com.openai.models.decisions.DecisionInputImage;
+import com.openai.models.decisions.DecisionInputMessage;
+import com.openai.models.decisions.DecisionInputPart;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class OpenAIDecisionsTest {
+    @Test
+    void usesManagedClientWithoutStartingConfiguredMcp() throws Exception {
+        OpenAIClient client = mock(OpenAIClient.class, RETURNS_DEEP_STUBS);
+        DecisionCreateParams request = request();
+        Decision answer = Decision.builder().model("gpt-6-luna")
+                
.addAnswer(Decision.Answer.Predicate.builder().name("test").probability(0.91).build())
+                .usage(usage()).build();
+        when(client.decisions().create(request)).thenReturn(answer);
+        try (DefaultCamelContext context = new DefaultCamelContext()) {
+            context.start();
+            OpenAIComponent component = new OpenAIComponent();
+            component.setCamelContext(context);
+            OpenAIConfiguration configuration = new OpenAIConfiguration();
+            configuration.setMcpServer(Map.of("unused.transportType", 
"invalid"));
+            OpenAIEndpoint endpoint = new OpenAIEndpoint("openai:decisions", 
component, configuration) {
+                @Override
+                protected OpenAIClient createClient() {
+                    return client;
+                }
+            };
+            endpoint.setOperation(OpenAIOperations.decisions);
+            try {
+                assertThat(endpoint.decide(request)).isSameAs(answer);
+            } finally {
+                endpoint.stop();
+            }
+        }
+        verify(client).close();
+    }
+
+    @Test
+    void refusesWholeRequest() {
+        OpenAIClient client = mock(OpenAIClient.class, RETURNS_DEEP_STUBS);
+        DecisionCreateParams request = request();
+        
when(client.decisions().create(request)).thenReturn(Decision.builder().model("gpt-6-luna")
+                
.addAnswer(Decision.Answer.Refusal.builder().name("test").build()).usage(usage()).build());
+        assertThatThrownBy(() -> OpenAIDecisionsSupport.execute(client, 
request))
+                .isInstanceOf(OpenAIDecisionRefusalException.class);
+    }
+
+    @Test
+    void validatesNativeImageFormsAndCount() {
+        var image = DecisionInputPart.ofInputImage(DecisionInputImage.builder()
+                
.imageUrl("data:image/png;base64,AA==").detail(DecisionInputImage.Detail.HIGH).build());
+        var valid = request().toBuilder().inputOfDecisionInputMessages(List.of(
+                
DecisionInputMessage.builder().contentOfParts(List.of(image)).build())).build();
+        OpenAIDecisionsSupport.validateRequest(valid);
+        for (String data : List.of("https://example.com/image.png";, 
"data:audio/wav;base64,AA==",
+                "data:image/png;base64,invalid!")) {
+            var invalid = 
valid.toBuilder().inputOfDecisionInputMessages(List.of(DecisionInputMessage.builder()
+                    .contentOfParts(
+                            
List.of(DecisionInputPart.ofInputImage(DecisionInputImage.builder().imageUrl(data).build())))
+                    .build())).build();
+            assertThatThrownBy(() -> 
OpenAIDecisionsSupport.validateRequest(invalid))
+                    .isInstanceOf(IllegalArgumentException.class)
+                    .hasMessageNotContaining(data);
+        }
+        var excessive = 
valid.toBuilder().inputOfDecisionInputMessages(List.of(DecisionInputMessage.builder()
+                .contentOfParts(Collections.nCopies(129, 
image)).build())).build();
+        assertThatThrownBy(() -> 
OpenAIDecisionsSupport.validateRequest(excessive)).hasMessageContaining("128 
images");
+    }
+
+    @Test
+    void rejectsInvalidResponseBeforeReturningAnyAnswer() {
+        var request = request();
+        for (Decision response : List.of(
+                
Decision.builder().model("gpt-6-luna").answers(List.of()).usage(usage()).build(),
+                
Decision.builder().model("gpt-6-luna").usage(usage()).addAnswer(Decision.Answer.Predicate.builder()
+                        .name("wrong").probability(0.9).build()).build(),
+                
Decision.builder().model("gpt-6-luna").usage(usage()).addAnswer(Decision.Answer.Predicate.builder()
+                        
.name("test").probability(Double.NaN).build()).build())) {
+            OpenAIClient client = mock(OpenAIClient.class, RETURNS_DEEP_STUBS);
+            when(client.decisions().create(request)).thenReturn(response);
+            assertThatThrownBy(() -> OpenAIDecisionsSupport.execute(client, 
request))
+                    .isInstanceOf(OpenAIDecisionResponseException.class);
+        }
+    }
+
+    @Test
+    void duplicateQuestionNamesAndOversizedBatchesAreRejected() {
+        assertThatThrownBy(() -> 
OpenAIDecisionsSupport.validateRequest(request().toBuilder()
+                
.addQuestion(request().questions().get(0)).build())).hasMessageContaining("unique");
+        assertThatThrownBy(() -> 
OpenAIDecisionsSupport.validateRequest(request().toBuilder()
+                .questions(Collections.nCopies(201, 
request().questions().get(0))).build())).hasMessageContaining("200");
+    }
+
+    private static DecisionCreateParams request() {
+        return 
DecisionCreateParams.builder().model("gpt-6-luna").input("Evidence")
+                .addQuestion(DecisionCreateParams.Question.Predicate.builder()
+                        .name("test").instructions("Is it relevant?").build())
+                .build();
+    }
+
+    private static Decision.Usage usage() {
+        return 
Decision.Usage.builder().inputTokens(1).outputTokens(0).totalTokens(1)
+                
.inputTokensDetails(Decision.Usage.InputTokensDetails.builder().cachedTokens(0).cacheWriteTokens(0).build())
+                
.outputTokensDetails(Decision.Usage.OutputTokensDetails.builder().reasoningTokens(0).build()).build();
+    }
+}
diff --git 
a/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/integration/OpenAIDecisionsExternalServiceIT.java
 
b/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/integration/OpenAIDecisionsExternalServiceIT.java
new file mode 100644
index 000000000000..39dafa2bc658
--- /dev/null
+++ 
b/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/integration/OpenAIDecisionsExternalServiceIT.java
@@ -0,0 +1,98 @@
+/*
+ * 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.openai.integration;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.util.Base64;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+import com.openai.models.decisions.Decision;
+import com.openai.models.decisions.DecisionChoiceOption;
+import com.openai.models.decisions.DecisionCreateParams;
+import com.openai.models.decisions.DecisionInputImage;
+import com.openai.models.decisions.DecisionInputMessage;
+import com.openai.models.decisions.DecisionInputPart;
+import com.openai.models.decisions.DecisionInputText;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@EnabledIfSystemProperty(named = 
OpenAIExternalServiceTestSupport.ENABLE_LIVE_TESTS, matches = "true",
+                         disabledReason = "Set -Dopenai.live.tests=true and 
configure a Decisions API service and model")
+public class OpenAIDecisionsExternalServiceIT extends 
OpenAIExternalServiceTestSupport {
+    private static final String DECISIONS_MODEL = 
"openai.live.decisions.model";
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                
from("direct:decisions").to("openai:decisions?requestTimeout=60000&maxRetries=0");
+            }
+        };
+    }
+
+    @Test
+    void textBatchReturnsNativePredicateChoiceAndScore() {
+        var request = 
DecisionCreateParams.builder().model(requiredProperty(DECISIONS_MODEL))
+                .input("My invoice contains a duplicate charge. Please help.")
+                .addQuestion(DecisionCreateParams.Question.Predicate.builder()
+                        .name("request").instructions("Does the message ask 
for assistance?").build())
+                
.addQuestion(DecisionCreateParams.Question.Choice.builder().name("category")
+                        .instructions("Which team should assess this message?")
+                        
.addChoice(DecisionChoiceOption.builder().value("billing").description("Invoices
 and charges").build())
+                        
.addChoice(DecisionChoiceOption.builder().value("technical").description("Product
 defects").build())
+                        .build())
+                
.addQuestion(DecisionCreateParams.Question.Score.builder().name("urgency")
+                        .instructions("How urgent is the request?")
+                        
.addLevel(DecisionCreateParams.Question.Score.Level.builder().label("routine").build())
+                        
.addLevel(DecisionCreateParams.Question.Score.Level.builder().label("urgent").build()).build())
+                .build();
+        Decision response = template.requestBody("direct:decisions", request, 
Decision.class);
+        assertThat(response.model()).isNotBlank();
+        assertThat(response.answers()).hasSize(3);
+        
assertThat(response.answers().get(0).asPredicate().probability()).isBetween(0.0,
 1.0);
+        
assertThat(response.answers().get(1).asChoice().choice().asString()).isIn("billing",
 "technical");
+        assertThat(response.answers().get(2).asScore().score()).isBetween(0.0, 
1.0);
+    }
+
+    @Test
+    void mixedTextAndInlineImageAreAcceptedWithoutTranscodingServices() throws 
Exception {
+        var image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_RGB);
+        var bytes = new ByteArrayOutputStream();
+        ImageIO.write(image, "png", bytes);
+        var request = 
DecisionCreateParams.builder().model(requiredProperty(DECISIONS_MODEL))
+                
.inputOfDecisionInputMessages(List.of(DecisionInputMessage.builder().contentOfParts(List.of(
+                        
DecisionInputPart.ofInputText(DecisionInputText.builder().text("Inspect this 
image.").build()),
+                        
DecisionInputPart.ofInputImage(DecisionInputImage.builder()
+                                .imageUrl("data:image/png;base64," + 
Base64.getEncoder().encodeToString(bytes.toByteArray()))
+                                .build())))
+                        .build()))
+                .addQuestion(DecisionCreateParams.Question.Predicate.builder()
+                        .name("dark").instructions("Is the image predominantly 
dark?").build())
+                .build();
+        Decision response = template.requestBody("direct:decisions", request, 
Decision.class);
+        assertThat(response.model()).isNotBlank();
+        assertThat(response.answers()).hasSize(1);
+        
assertThat(response.answers().get(0).asPredicate().probability()).isBetween(0.0,
 1.0);
+    }
+}
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
index a39ba3501a4d..85d6a1c5b689 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
@@ -11289,14 +11289,14 @@ public class StaticEndpointBuilders {
      * Syntax: <code>llm:operation</code>
      * 
      * Path parameter: operation (required)
-     * The operation to perform: 'chat-completion', 'responses',
+     * The operation to perform: 'chat-completion', 'decisions', 'responses',
      * 'responses-retrieve', 'responses-cancel', 'batch', 'batch-retrieve',
      * 'batch-cancel', 'batch-results', 'embeddings', 'tool-execution',
      * 'audio-transcription', 'audio-translation', 'audio-speech', 
'moderation',
      * 'image-generation', 'image-edit', or 'webhook' (a consumer)
-     * There are 17 enums and the value can be one of: chat-completion,
-     * responses, responses-retrieve, responses-cancel, batch, batch-retrieve,
-     * batch-cancel, batch-results, embeddings, tool-execution,
+     * There are 18 enums and the value can be one of: chat-completion,
+     * decisions, responses, responses-retrieve, responses-cancel, batch,
+     * batch-retrieve, batch-cancel, batch-results, embeddings, tool-execution,
      * audio-transcription, audio-translation, audio-speech, moderation,
      * image-generation, image-edit, webhook
      * 
@@ -12853,14 +12853,14 @@ public class StaticEndpointBuilders {
      * Syntax: <code>openai:operation</code>
      * 
      * Path parameter: operation (required)
-     * The operation to perform: 'chat-completion', 'responses',
+     * The operation to perform: 'chat-completion', 'decisions', 'responses',
      * 'responses-retrieve', 'responses-cancel', 'batch', 'batch-retrieve',
      * 'batch-cancel', 'batch-results', 'embeddings', 'tool-execution',
      * 'audio-transcription', 'audio-translation', 'audio-speech', 
'moderation',
      * 'image-generation', 'image-edit', or 'webhook' (a consumer)
-     * There are 17 enums and the value can be one of: chat-completion,
-     * responses, responses-retrieve, responses-cancel, batch, batch-retrieve,
-     * batch-cancel, batch-results, embeddings, tool-execution,
+     * There are 18 enums and the value can be one of: chat-completion,
+     * decisions, responses, responses-retrieve, responses-cancel, batch,
+     * batch-retrieve, batch-cancel, batch-results, embeddings, tool-execution,
      * audio-transcription, audio-translation, audio-speech, moderation,
      * image-generation, image-edit, webhook
      * 
@@ -12883,14 +12883,14 @@ public class StaticEndpointBuilders {
      * Syntax: <code>openai:operation</code>
      * 
      * Path parameter: operation (required)
-     * The operation to perform: 'chat-completion', 'responses',
+     * The operation to perform: 'chat-completion', 'decisions', 'responses',
      * 'responses-retrieve', 'responses-cancel', 'batch', 'batch-retrieve',
      * 'batch-cancel', 'batch-results', 'embeddings', 'tool-execution',
      * 'audio-transcription', 'audio-translation', 'audio-speech', 
'moderation',
      * 'image-generation', 'image-edit', or 'webhook' (a consumer)
-     * There are 17 enums and the value can be one of: chat-completion,
-     * responses, responses-retrieve, responses-cancel, batch, batch-retrieve,
-     * batch-cancel, batch-results, embeddings, tool-execution,
+     * There are 18 enums and the value can be one of: chat-completion,
+     * decisions, responses, responses-retrieve, responses-cancel, batch,
+     * batch-retrieve, batch-cancel, batch-results, embeddings, tool-execution,
      * audio-transcription, audio-translation, audio-speech, moderation,
      * image-generation, image-edit, webhook
      * 
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenAIEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenAIEndpointBuilderFactory.java
index a5007e168214..b2d36c953b41 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenAIEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenAIEndpointBuilderFactory.java
@@ -1443,7 +1443,7 @@ public interface OpenAIEndpointBuilderFactory {
             return this;
         }
         /**
-         * The model to use for chat completion.
+         * The model to use for the selected operation.
          * 
          * The option is a: <code>java.lang.String</code> type.
          * 
@@ -3875,7 +3875,7 @@ public interface OpenAIEndpointBuilderFactory {
             return this;
         }
         /**
-         * The model to use for chat completion.
+         * The model to use for the selected operation.
          * 
          * The option is a: <code>java.lang.String</code> type.
          * 
@@ -6156,7 +6156,7 @@ public interface OpenAIEndpointBuilderFactory {
             return this;
         }
         /**
-         * The model to use for chat completion.
+         * The model to use for the selected operation.
          * 
          * The option is a: <code>java.lang.String</code> type.
          * 
@@ -7014,14 +7014,14 @@ public interface OpenAIEndpointBuilderFactory {
          * Syntax: <code>openai:operation</code>
          * 
          * Path parameter: operation (required)
-         * The operation to perform: 'chat-completion', 'responses',
-         * 'responses-retrieve', 'responses-cancel', 'batch', 'batch-retrieve',
-         * 'batch-cancel', 'batch-results', 'embeddings', 'tool-execution',
-         * 'audio-transcription', 'audio-translation', 'audio-speech',
-         * 'moderation', 'image-generation', 'image-edit', or 'webhook' (a
-         * consumer)
-         * There are 17 enums and the value can be one of: chat-completion,
-         * responses, responses-retrieve, responses-cancel, batch,
+         * The operation to perform: 'chat-completion', 'decisions',
+         * 'responses', 'responses-retrieve', 'responses-cancel', 'batch',
+         * 'batch-retrieve', 'batch-cancel', 'batch-results', 'embeddings',
+         * 'tool-execution', 'audio-transcription', 'audio-translation',
+         * 'audio-speech', 'moderation', 'image-generation', 'image-edit', or
+         * 'webhook' (a consumer)
+         * There are 18 enums and the value can be one of: chat-completion,
+         * decisions, responses, responses-retrieve, responses-cancel, batch,
          * batch-retrieve, batch-cancel, batch-results, embeddings,
          * tool-execution, audio-transcription, audio-translation, 
audio-speech,
          * moderation, image-generation, image-edit, webhook
@@ -7045,14 +7045,14 @@ public interface OpenAIEndpointBuilderFactory {
          * Syntax: <code>openai:operation</code>
          * 
          * Path parameter: operation (required)
-         * The operation to perform: 'chat-completion', 'responses',
-         * 'responses-retrieve', 'responses-cancel', 'batch', 'batch-retrieve',
-         * 'batch-cancel', 'batch-results', 'embeddings', 'tool-execution',
-         * 'audio-transcription', 'audio-translation', 'audio-speech',
-         * 'moderation', 'image-generation', 'image-edit', or 'webhook' (a
-         * consumer)
-         * There are 17 enums and the value can be one of: chat-completion,
-         * responses, responses-retrieve, responses-cancel, batch,
+         * The operation to perform: 'chat-completion', 'decisions',
+         * 'responses', 'responses-retrieve', 'responses-cancel', 'batch',
+         * 'batch-retrieve', 'batch-cancel', 'batch-results', 'embeddings',
+         * 'tool-execution', 'audio-transcription', 'audio-translation',
+         * 'audio-speech', 'moderation', 'image-generation', 'image-edit', or
+         * 'webhook' (a consumer)
+         * There are 18 enums and the value can be one of: chat-completion,
+         * decisions, responses, responses-retrieve, responses-cancel, batch,
          * batch-retrieve, batch-cancel, batch-results, embeddings,
          * tool-execution, audio-transcription, audio-translation, 
audio-speech,
          * moderation, image-generation, image-edit, webhook
@@ -7078,14 +7078,14 @@ public interface OpenAIEndpointBuilderFactory {
          * Syntax: <code>llm:operation</code>
          * 
          * Path parameter: operation (required)
-         * The operation to perform: 'chat-completion', 'responses',
-         * 'responses-retrieve', 'responses-cancel', 'batch', 'batch-retrieve',
-         * 'batch-cancel', 'batch-results', 'embeddings', 'tool-execution',
-         * 'audio-transcription', 'audio-translation', 'audio-speech',
-         * 'moderation', 'image-generation', 'image-edit', or 'webhook' (a
-         * consumer)
-         * There are 17 enums and the value can be one of: chat-completion,
-         * responses, responses-retrieve, responses-cancel, batch,
+         * The operation to perform: 'chat-completion', 'decisions',
+         * 'responses', 'responses-retrieve', 'responses-cancel', 'batch',
+         * 'batch-retrieve', 'batch-cancel', 'batch-results', 'embeddings',
+         * 'tool-execution', 'audio-transcription', 'audio-translation',
+         * 'audio-speech', 'moderation', 'image-generation', 'image-edit', or
+         * 'webhook' (a consumer)
+         * There are 18 enums and the value can be one of: chat-completion,
+         * decisions, responses, responses-retrieve, responses-cancel, batch,
          * batch-retrieve, batch-cancel, batch-results, embeddings,
          * tool-execution, audio-transcription, audio-translation, 
audio-speech,
          * moderation, image-generation, image-edit, webhook
diff --git a/parent/pom.xml b/parent/pom.xml
index 2ede68d3e2b4..73ac4037d8c7 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -424,7 +424,7 @@
         <mcp-java-sdk-version>2.0.1</mcp-java-sdk-version>
         <mssql-jdbc-version>12.10.0.jre11</mssql-jdbc-version>
         <ojdbc-version>23.8.0.25.04</ojdbc-version>
-        <openai-java-version>4.76.0</openai-java-version>
+        <openai-java-version>4.78.0</openai-java-version>
         <openapi-generator-version>7.25.0</openapi-generator-version>
         <openjpa-version>4.1.1</openjpa-version>
         <opensearch-rest-client-version>3.9.0</opensearch-rest-client-version>

Reply via email to