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

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


The following commit(s) were added to refs/heads/main by this push:
     new 81ef9b3dfc36 CAMEL-26216: camel-pinecone - QUERY defaults to 10 
matches, UPSERT generates a missing id, the vector takes any numbers, the 
pinecone:rag transformer reads the query response, and test-infra binds the 
index ports (#29063)
81ef9b3dfc36 is described below

commit 81ef9b3dfc362b56b51db171f16f0bf70a811cdb
Author: Andrea Cosentino <[email protected]>
AuthorDate: Wed Nov 4 10:36:45 2026 +0100

    CAMEL-26216: camel-pinecone - QUERY defaults to 10 matches, UPSERT 
generates a missing id, the vector takes any numbers, the pinecone:rag 
transformer reads the query response, and test-infra binds the index ports 
(#29063)
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../apache/camel/catalog/components/pinecone.json  |  10 +-
 .../camel/catalog/docs/pinecone-component.adoc     |   4 +-
 .../camel/catalog/transformers/pinecone-rag.json   |   3 +-
 .../apache/camel/component/pinecone/pinecone.json  |  10 +-
 .../org/apache/camel/transformer/pinecone-rag.json |   3 +-
 .../src/main/docs/pinecone-component.adoc          |   4 +-
 .../pinecone/PineconeVectorDbEndpoint.java         |  13 +-
 .../pinecone/PineconeVectorDbHeaders.java          |  10 +-
 .../pinecone/PineconeVectorDbProducer.java         |  47 +++-
 ...neconeReverseEmbeddingsDataTypeTransformer.java |  20 +-
 .../pinecone/PineconeVectorDbProducerTest.java     | 291 +++++++++++++++++++++
 ...neReverseEmbeddingsDataTypeTransformerTest.java |  17 +-
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |   8 +
 .../PineconeVectorDbEndpointBuilderFactory.java    |  10 +-
 .../PineconeLocalContainerInfraService.java        |  19 +-
 15 files changed, 422 insertions(+), 47 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pinecone.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pinecone.json
index 5645fa59db76..fe55acd56013 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pinecone.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pinecone.json
@@ -51,15 +51,15 @@
     "CamelPineconeCollectionDimension": { "index": 8, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Collection Dimension", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#COLLECTION_DIMENSION"
 },
     "CamelPineconeCollectionCloud": { "index": 9, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "enum": [ "aws", "gcp", "azure" ], "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Collection Cloud Vendor", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#COLLECTION_CLOUD" 
},
     "CamelPineconeCollectionCloudRegion": { "index": 10, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "enum": [ "aws", "gcp", "azure" ], "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Collection Cloud Vendor Region", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#COLLECTION_CLOUD_REGION"
 },
-    "CamelPineconeIndexId": { "index": 11, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Index Upsert Id", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#INDEX_ID" },
-    "CamelPineconeQueryTopK": { "index": 12, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "Integer", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Query Top K", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_TOP_K" },
+    "CamelPineconeIndexId": { "index": 11, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The id of the vector for UPSERT, UPDATE and QUERY_BY_ID. 
Without it, UPSERT generates a random UUID and sets this header to it", 
"constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#INDEX_ID" },
+    "CamelPineconeQueryTopK": { "index": 12, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "Integer", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "defaultValue": "10", "description": "The number of matches QUERY and 
QUERY_BY_ID return", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_TOP_K" },
     "CamelPineconeNamespace": { "index": 13, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Namespace for actions (query\/upsert\/etc)", 
"constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#NAMESPACE" },
-    "CamelPineconeQueryFilter": { "index": 14, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Query Filter", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_FILTER" },
+    "CamelPineconeQueryFilter": { "index": 14, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "com.google.protobuf.Struct", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Query Filter", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_FILTER" },
     "CamelPineconeQueryIncludeValues": { "index": 15, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Query Include Values", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_INCLUDE_VALUES"
 },
-    "CamelPineconeQueryIncludeMetadata": { "index": 16, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "com.google.protobuf.Struct", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Query Include Metadata", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_INCLUDE_METADATA"
 }
+    "CamelPineconeQueryIncludeMetadata": { "index": 16, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Query Include Metadata", 
"constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_INCLUDE_METADATA"
 }
   },
   "bodyTypes": {
-    "producerIn": { "carriers": [ "list", "null" ], "byOption": [ { "option": 
"action", "value": "UPSERT", "carriers": [ "list" ] }, { "option": "action", 
"value": "UPDATE", "carriers": [ "list" ] }, { "option": "action", "value": 
"QUERY", "carriers": [ "list" ] }, { "option": "action", "value": "FETCH", 
"carriers": [ "list" ] }, { "option": "action", "value": "DELETE_BY_ID", 
"carriers": [ "list" ] }, { "option": "action", "value": "QUERY_BY_ID", 
"carriers": [ "any" ] }, { "option": "act [...]
+    "producerIn": { "carriers": [ "list", "null" ], "byOption": [ { "option": 
"action", "value": "UPSERT", "carriers": [ "list" ] }, { "option": "action", 
"value": "UPDATE", "carriers": [ "list" ] }, { "option": "action", "value": 
"QUERY", "carriers": [ "list" ] }, { "option": "action", "value": "FETCH", 
"carriers": [ "list" ] }, { "option": "action", "value": "DELETE_BY_ID", 
"carriers": [ "list" ] }, { "option": "action", "value": "QUERY_BY_ID", 
"carriers": [ "any" ] }, { "option": "act [...]
     "producerOut": { "carriers": [ "pojo", "unchanged" ], "byOption": [ { 
"option": "action", "value": "UPSERT", "carriers": [ "pojo" ], "javaType": 
"io.pinecone.proto.UpsertResponse" }, { "option": "action", "value": "UPDATE", 
"carriers": [ "pojo" ], "javaType": "io.pinecone.proto.UpdateResponse" }, { 
"option": "action", "value": "QUERY", "carriers": [ "pojo" ], "javaType": 
"io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices" }, { 
"option": "action", "value": "QUERY_BY_ [...]
   },
   "properties": {
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pinecone-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pinecone-component.adoc
index 2c46492fd874..35a185854b8a 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pinecone-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pinecone-component.adoc
@@ -33,7 +33,7 @@ include::partial$component-endpoint-headers.adoc[]
 
 == Usage
 
-The `action` option, or the `CamelPineconeAction` header, selects the 
operation. The first route below creates a serverless index. The second route 
queries the index with a vector, and the `CamelPineconeQueryTopK` header sets 
how many matches it returns:
+The `action` option, or the `CamelPineconeAction` header, selects the 
operation. The first route below creates a serverless index. The second route 
queries the index with a vector, and the `CamelPineconeQueryTopK` header sets 
how many matches it returns (10 without it):
 
 [source,yaml]
 ----
@@ -74,4 +74,6 @@ The `action` option, or the `CamelPineconeAction` header, 
selects the operation.
             message: "${body}"
 ----
 
+The vector of UPSERT, UPDATE and QUERY is the message body: a List of numbers, 
such as the List of Double a JSON array unmarshals to, or a `float[]` or a 
`double[]`; each number is converted to a float. Another body fails, and so 
does a List with an element that is not a number. UPSERT stores the vector 
under the id in the `CamelPineconeIndexId` header; without the header, it 
generates a random UUID and sets the header to it.
 
+The `pinecone:rag` data type transformer turns the result of a QUERY or 
QUERY_BY_ID into the List of the texts of its matches, read from their 
`text_segment` metadata, which the query returns when the 
`CamelPineconeQueryIncludeMetadata` header is `true`.
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/pinecone-rag.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/pinecone-rag.json
index a5c574cdd5e9..44dd4755b35d 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/pinecone-rag.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/pinecone-rag.json
@@ -13,10 +13,11 @@
   "bodyTypes": {
     "transformerIn": {
       "carriers": [
+        "pojo",
         "list",
         "null"
       ],
-      "description": "The List of ScoredVectorWithUnsignedIndices of a QUERY, 
the matchesList of its QueryResponseWithUnsignedIndices, with the text in the 
text_segment metadata. A null body, or the QueryResponseWithUnsignedIndices 
itself, gives an empty List"
+      "description": "The QueryResponseWithUnsignedIndices of a QUERY or 
QUERY_BY_ID, or the List of ScoredVectorWithUnsignedIndices of its matches, 
with the text in the text_segment metadata, which the query returns with the 
CamelPineconeQueryIncludeMetadata header set to true. A match without the text 
gives an empty String, and a null body an empty List"
     },
     "transformerOut": {
       "carriers": [
diff --git 
a/components/camel-ai/camel-pinecone/src/generated/resources/META-INF/org/apache/camel/component/pinecone/pinecone.json
 
b/components/camel-ai/camel-pinecone/src/generated/resources/META-INF/org/apache/camel/component/pinecone/pinecone.json
index 5645fa59db76..fe55acd56013 100644
--- 
a/components/camel-ai/camel-pinecone/src/generated/resources/META-INF/org/apache/camel/component/pinecone/pinecone.json
+++ 
b/components/camel-ai/camel-pinecone/src/generated/resources/META-INF/org/apache/camel/component/pinecone/pinecone.json
@@ -51,15 +51,15 @@
     "CamelPineconeCollectionDimension": { "index": 8, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Collection Dimension", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#COLLECTION_DIMENSION"
 },
     "CamelPineconeCollectionCloud": { "index": 9, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "enum": [ "aws", "gcp", "azure" ], "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Collection Cloud Vendor", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#COLLECTION_CLOUD" 
},
     "CamelPineconeCollectionCloudRegion": { "index": 10, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "enum": [ "aws", "gcp", "azure" ], "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Collection Cloud Vendor Region", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#COLLECTION_CLOUD_REGION"
 },
-    "CamelPineconeIndexId": { "index": 11, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Index Upsert Id", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#INDEX_ID" },
-    "CamelPineconeQueryTopK": { "index": 12, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "Integer", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Query Top K", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_TOP_K" },
+    "CamelPineconeIndexId": { "index": 11, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The id of the vector for UPSERT, UPDATE and QUERY_BY_ID. 
Without it, UPSERT generates a random UUID and sets this header to it", 
"constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#INDEX_ID" },
+    "CamelPineconeQueryTopK": { "index": 12, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "Integer", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "defaultValue": "10", "description": "The number of matches QUERY and 
QUERY_BY_ID return", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_TOP_K" },
     "CamelPineconeNamespace": { "index": 13, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Namespace for actions (query\/upsert\/etc)", 
"constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#NAMESPACE" },
-    "CamelPineconeQueryFilter": { "index": 14, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Query Filter", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_FILTER" },
+    "CamelPineconeQueryFilter": { "index": 14, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "com.google.protobuf.Struct", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Query Filter", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_FILTER" },
     "CamelPineconeQueryIncludeValues": { "index": 15, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Query Include Values", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_INCLUDE_VALUES"
 },
-    "CamelPineconeQueryIncludeMetadata": { "index": 16, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "com.google.protobuf.Struct", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Query Include Metadata", "constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_INCLUDE_METADATA"
 }
+    "CamelPineconeQueryIncludeMetadata": { "index": 16, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Query Include Metadata", 
"constantName": 
"org.apache.camel.component.pinecone.PineconeVectorDbHeaders#QUERY_INCLUDE_METADATA"
 }
   },
   "bodyTypes": {
-    "producerIn": { "carriers": [ "list", "null" ], "byOption": [ { "option": 
"action", "value": "UPSERT", "carriers": [ "list" ] }, { "option": "action", 
"value": "UPDATE", "carriers": [ "list" ] }, { "option": "action", "value": 
"QUERY", "carriers": [ "list" ] }, { "option": "action", "value": "FETCH", 
"carriers": [ "list" ] }, { "option": "action", "value": "DELETE_BY_ID", 
"carriers": [ "list" ] }, { "option": "action", "value": "QUERY_BY_ID", 
"carriers": [ "any" ] }, { "option": "act [...]
+    "producerIn": { "carriers": [ "list", "null" ], "byOption": [ { "option": 
"action", "value": "UPSERT", "carriers": [ "list" ] }, { "option": "action", 
"value": "UPDATE", "carriers": [ "list" ] }, { "option": "action", "value": 
"QUERY", "carriers": [ "list" ] }, { "option": "action", "value": "FETCH", 
"carriers": [ "list" ] }, { "option": "action", "value": "DELETE_BY_ID", 
"carriers": [ "list" ] }, { "option": "action", "value": "QUERY_BY_ID", 
"carriers": [ "any" ] }, { "option": "act [...]
     "producerOut": { "carriers": [ "pojo", "unchanged" ], "byOption": [ { 
"option": "action", "value": "UPSERT", "carriers": [ "pojo" ], "javaType": 
"io.pinecone.proto.UpsertResponse" }, { "option": "action", "value": "UPDATE", 
"carriers": [ "pojo" ], "javaType": "io.pinecone.proto.UpdateResponse" }, { 
"option": "action", "value": "QUERY", "carriers": [ "pojo" ], "javaType": 
"io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices" }, { 
"option": "action", "value": "QUERY_BY_ [...]
   },
   "properties": {
diff --git 
a/components/camel-ai/camel-pinecone/src/generated/resources/META-INF/services/org/apache/camel/transformer/pinecone-rag.json
 
b/components/camel-ai/camel-pinecone/src/generated/resources/META-INF/services/org/apache/camel/transformer/pinecone-rag.json
index a5c574cdd5e9..44dd4755b35d 100644
--- 
a/components/camel-ai/camel-pinecone/src/generated/resources/META-INF/services/org/apache/camel/transformer/pinecone-rag.json
+++ 
b/components/camel-ai/camel-pinecone/src/generated/resources/META-INF/services/org/apache/camel/transformer/pinecone-rag.json
@@ -13,10 +13,11 @@
   "bodyTypes": {
     "transformerIn": {
       "carriers": [
+        "pojo",
         "list",
         "null"
       ],
-      "description": "The List of ScoredVectorWithUnsignedIndices of a QUERY, 
the matchesList of its QueryResponseWithUnsignedIndices, with the text in the 
text_segment metadata. A null body, or the QueryResponseWithUnsignedIndices 
itself, gives an empty List"
+      "description": "The QueryResponseWithUnsignedIndices of a QUERY or 
QUERY_BY_ID, or the List of ScoredVectorWithUnsignedIndices of its matches, 
with the text in the text_segment metadata, which the query returns with the 
CamelPineconeQueryIncludeMetadata header set to true. A match without the text 
gives an empty String, and a null body an empty List"
     },
     "transformerOut": {
       "carriers": [
diff --git 
a/components/camel-ai/camel-pinecone/src/main/docs/pinecone-component.adoc 
b/components/camel-ai/camel-pinecone/src/main/docs/pinecone-component.adoc
index 2c46492fd874..35a185854b8a 100644
--- a/components/camel-ai/camel-pinecone/src/main/docs/pinecone-component.adoc
+++ b/components/camel-ai/camel-pinecone/src/main/docs/pinecone-component.adoc
@@ -33,7 +33,7 @@ include::partial$component-endpoint-headers.adoc[]
 
 == Usage
 
-The `action` option, or the `CamelPineconeAction` header, selects the 
operation. The first route below creates a serverless index. The second route 
queries the index with a vector, and the `CamelPineconeQueryTopK` header sets 
how many matches it returns:
+The `action` option, or the `CamelPineconeAction` header, selects the 
operation. The first route below creates a serverless index. The second route 
queries the index with a vector, and the `CamelPineconeQueryTopK` header sets 
how many matches it returns (10 without it):
 
 [source,yaml]
 ----
@@ -74,4 +74,6 @@ The `action` option, or the `CamelPineconeAction` header, 
selects the operation.
             message: "${body}"
 ----
 
+The vector of UPSERT, UPDATE and QUERY is the message body: a List of numbers, 
such as the List of Double a JSON array unmarshals to, or a `float[]` or a 
`double[]`; each number is converted to a float. Another body fails, and so 
does a List with an element that is not a number. UPSERT stores the vector 
under the id in the `CamelPineconeIndexId` header; without the header, it 
generates a random UUID and sets the header to it.
 
+The `pinecone:rag` data type transformer turns the result of a QUERY or 
QUERY_BY_ID into the List of the texts of its matches, read from their 
`text_segment` metadata, which the query returns when the 
`CamelPineconeQueryIncludeMetadata` header is `true`.
diff --git 
a/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/PineconeVectorDbEndpoint.java
 
b/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/PineconeVectorDbEndpoint.java
index 654f6bbccbb0..fa93992e9abf 100644
--- 
a/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/PineconeVectorDbEndpoint.java
+++ 
b/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/PineconeVectorDbEndpoint.java
@@ -62,12 +62,13 @@ import org.apache.camel.support.DefaultEndpoint;
                                           @BodyType.When(option = "action", 
value = "DELETE_COLLECTION",
                                                          carriers = 
Carrier.ANY) },
                                   description = "By the action in the action 
option or the CamelPineconeAction header: the"
-                                                + " vector as a List of Float 
or a float array for UPSERT, UPDATE and QUERY,"
-                                                + " with the id in the 
CamelPineconeIndexId header, and the ids as a List"
-                                                + " of String for FETCH and 
DELETE_BY_ID. The other actions do not read the"
-                                                + " body. Another body fails, 
a List of Double too: the pinecone:embeddings"
-                                                + " data type transformer 
builds the vector from the output of"
-                                                + " langchain4j-embeddings"),
+                                                + " vector as a List of 
numbers, such as the List of Double a JSON array"
+                                                + " unmarshals to, or a float 
or double array for UPSERT, UPDATE and QUERY,"
+                                                + " with the id in the 
CamelPineconeIndexId header (UPSERT generates one"
+                                                + " without it), and the ids 
as a List of String for FETCH and DELETE_BY_ID."
+                                                + " The other actions do not 
read the body. Another body fails: the"
+                                                + " pinecone:embeddings data 
type transformer builds the vector from the"
+                                                + " output of 
langchain4j-embeddings"),
            producerOut = @BodyType(value = { Carrier.POJO, Carrier.UNCHANGED },
                                    byOption = {
                                            @BodyType.When(option = "action", 
value = "UPSERT", carriers = Carrier.POJO,
diff --git 
a/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/PineconeVectorDbHeaders.java
 
b/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/PineconeVectorDbHeaders.java
index ebd4c162fb67..222d31fe84dc 100644
--- 
a/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/PineconeVectorDbHeaders.java
+++ 
b/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/PineconeVectorDbHeaders.java
@@ -53,22 +53,24 @@ public class PineconeVectorDbHeaders {
     @Metadata(description = "Collection Cloud Vendor Region", javaType = 
"String", enums = "aws,gcp,azure")
     public static final String COLLECTION_CLOUD_REGION = 
"CamelPineconeCollectionCloudRegion";
 
-    @Metadata(description = "Index Upsert Id", javaType = "String")
+    @Metadata(description = "The id of the vector for UPSERT, UPDATE and 
QUERY_BY_ID. Without it, UPSERT generates a random UUID"
+                            + " and sets this header to it",
+              javaType = "String")
     public static final String INDEX_ID = "CamelPineconeIndexId";
 
-    @Metadata(description = "Query Top K", javaType = "Integer")
+    @Metadata(description = "The number of matches QUERY and QUERY_BY_ID 
return", javaType = "Integer", defaultValue = "10")
     public static final String QUERY_TOP_K = "CamelPineconeQueryTopK";
 
     @Metadata(description = "Namespace for actions (query/upsert/etc)", 
javaType = "String")
     public static final String NAMESPACE = "CamelPineconeNamespace";
 
-    @Metadata(description = "Query Filter", javaType = "String")
+    @Metadata(description = "Query Filter", javaType = 
"com.google.protobuf.Struct")
     public static final String QUERY_FILTER = "CamelPineconeQueryFilter";
 
     @Metadata(description = "Query Include Values", javaType = "boolean")
     public static final String QUERY_INCLUDE_VALUES = 
"CamelPineconeQueryIncludeValues";
 
-    @Metadata(description = "Query Include Metadata", javaType = 
"com.google.protobuf.Struct")
+    @Metadata(description = "Query Include Metadata", javaType = "boolean")
     public static final String QUERY_INCLUDE_METADATA = 
"CamelPineconeQueryIncludeMetadata";
 
 }
diff --git 
a/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/PineconeVectorDbProducer.java
 
b/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/PineconeVectorDbProducer.java
index 24b54ad7133f..4ea721b30af8 100644
--- 
a/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/PineconeVectorDbProducer.java
+++ 
b/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/PineconeVectorDbProducer.java
@@ -16,7 +16,9 @@
  */
 package org.apache.camel.component.pinecone;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
 import java.util.concurrent.ExecutorService;
 
 import com.google.protobuf.Struct;
@@ -29,6 +31,7 @@ import io.pinecone.proto.UpsertResponse;
 import io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices;
 import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.Message;
 import org.apache.camel.NoSuchHeaderException;
 import org.apache.camel.support.DefaultProducer;
@@ -37,6 +40,10 @@ import 
org.openapitools.db_control.client.model.DeletionProtection;
 import org.openapitools.db_control.client.model.IndexModel;
 
 public class PineconeVectorDbProducer extends DefaultProducer {
+    // the number of matches of QUERY and QUERY_BY_ID without the 
CamelPineconeQueryTopK header, as camel-weaviate
+    private static final int DEFAULT_QUERY_TOP_K = 10;
+    private static final String VECTOR_TYPES = "a List of numbers, such as 
Float or Double, a float[] or a double[]";
+
     private Pinecone client;
     private ExecutorService executor;
 
@@ -205,12 +212,17 @@ public class PineconeVectorDbProducer extends 
DefaultProducer {
 
     private void upsert(Exchange exchange) throws Exception {
         final Message in = exchange.getMessage();
-        List elements = in.getMandatoryBody(List.class);
+        List<Float> elements = toVector(exchange);
         String indexName = getEndpoint().getConfiguration().getIndexName();
         if (in.getHeader(PineconeVectorDbHeaders.INDEX_NAME, String.class) != 
null) {
             indexName = in.getHeader(PineconeVectorDbHeaders.INDEX_NAME, 
String.class);
         }
         String indexId = in.getHeader(PineconeVectorDbHeaders.INDEX_ID, 
String.class);
+        if (indexId == null) {
+            // a random id, as the pinecone:embeddings transformer gives, in 
the header so the caller knows it
+            indexId = UUID.randomUUID().toString();
+            in.setHeader(PineconeVectorDbHeaders.INDEX_ID, indexId);
+        }
         String namespace = in.getHeader(PineconeVectorDbHeaders.NAMESPACE, 
String.class);
 
         Index index = this.client.getIndexConnection(indexName);
@@ -223,7 +235,7 @@ public class PineconeVectorDbProducer extends 
DefaultProducer {
 
     private void update(Exchange exchange) throws Exception {
         final Message in = exchange.getMessage();
-        List elements = in.getMandatoryBody(List.class);
+        List<Float> elements = toVector(exchange);
         String indexName = getEndpoint().getConfiguration().getIndexName();
 
         if (in.getHeader(PineconeVectorDbHeaders.INDEX_NAME, String.class) != 
null) {
@@ -292,14 +304,14 @@ public class PineconeVectorDbProducer extends 
DefaultProducer {
 
     private void query(Exchange exchange) throws Exception {
         final Message in = exchange.getMessage();
-        List elements = in.getMandatoryBody(List.class);
+        List<Float> elements = toVector(exchange);
         String indexName = getEndpoint().getConfiguration().getIndexName();
 
         if (in.getHeader(PineconeVectorDbHeaders.INDEX_NAME, String.class) != 
null) {
             indexName = in.getHeader(PineconeVectorDbHeaders.INDEX_NAME, 
String.class);
         }
 
-        int topK = in.getHeader(PineconeVectorDbHeaders.QUERY_TOP_K, 
Integer.class);
+        int topK = in.getHeader(PineconeVectorDbHeaders.QUERY_TOP_K, 
DEFAULT_QUERY_TOP_K, Integer.class);
         Index index = this.client.getIndexConnection(indexName);
 
         // Optional arguments, can be null
@@ -326,7 +338,7 @@ public class PineconeVectorDbProducer extends 
DefaultProducer {
             indexName = in.getHeader(PineconeVectorDbHeaders.INDEX_NAME, 
String.class);
         }
 
-        int topK = in.getHeader(PineconeVectorDbHeaders.QUERY_TOP_K, 
Integer.class);
+        int topK = in.getHeader(PineconeVectorDbHeaders.QUERY_TOP_K, 
DEFAULT_QUERY_TOP_K, Integer.class);
         Index index = this.client.getIndexConnection(indexName);
 
         String indexId = in.getHeader(PineconeVectorDbHeaders.INDEX_ID, 
String.class);
@@ -355,6 +367,31 @@ public class PineconeVectorDbProducer extends 
DefaultProducer {
         return getEndpoint().getCamelContext();
     }
 
+    /**
+     * The vector in the body of UPSERT, UPDATE and QUERY: a List of numbers, 
such as the List of Double a JSON array
+     * unmarshals to, or another body Camel converts to a List, such as a 
float[] or a double[]. The Pinecone SDK takes
+     * a List of Float.
+     */
+    private static List<Float> toVector(Exchange exchange) throws 
InvalidPayloadException {
+        final Message in = exchange.getMessage();
+        List<?> elements = in.getBody(List.class);
+        if (elements == null) {
+            throw new InvalidPayloadException(exchange, List.class, in, "the 
vector must be " + VECTOR_TYPES);
+        }
+        List<Float> vector = new ArrayList<>(elements.size());
+        for (Object element : elements) {
+            if (!(element instanceof Number number)) {
+                // the type only, not the value, which comes from the message
+                throw new IllegalArgumentException(
+                        "Vector element at index " + vector.size() + " is "
+                                                   + (element == null ? "null" 
: "a " + element.getClass().getName())
+                                                   + ": the vector must be " + 
VECTOR_TYPES);
+            }
+            vector.add(number.floatValue());
+        }
+        return vector;
+    }
+
     private void populateCollectionResponse(CollectionModel r, Exchange 
exchange) {
         Message out = exchange.getMessage();
         out.setBody(r);
diff --git 
a/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/transform/PineconeReverseEmbeddingsDataTypeTransformer.java
 
b/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/transform/PineconeReverseEmbeddingsDataTypeTransformer.java
index cbd6486a5804..78cd3308408c 100644
--- 
a/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/transform/PineconeReverseEmbeddingsDataTypeTransformer.java
+++ 
b/components/camel-ai/camel-pinecone/src/main/java/org/apache/camel/component/pinecone/transform/PineconeReverseEmbeddingsDataTypeTransformer.java
@@ -21,6 +21,7 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 import com.google.protobuf.Value;
+import io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices;
 import io.pinecone.unsigned_indices_model.ScoredVectorWithUnsignedIndices;
 import org.apache.camel.Message;
 import org.apache.camel.spi.BodyType;
@@ -35,16 +36,23 @@ import org.apache.camel.spi.Transformer;
  */
 @DataTypeTransformer(name = "pinecone:rag",
                      description = "Maps a List of retrieved LangChain4j 
Embeddings with similarity search to a List of String for LangChain4j RAG")
-@BodyTypes(transformerIn = @BodyType(value = { Carrier.LIST, Carrier.NULL },
-                                     description = "The List of 
ScoredVectorWithUnsignedIndices of a QUERY, the matchesList of"
-                                                   + " its 
QueryResponseWithUnsignedIndices, with the text in the text_segment"
-                                                   + " metadata. A null body, 
or the QueryResponseWithUnsignedIndices"
-                                                   + " itself, gives an empty 
List"),
+@BodyTypes(transformerIn = @BodyType(value = { Carrier.POJO, Carrier.LIST, 
Carrier.NULL },
+                                     description = "The 
QueryResponseWithUnsignedIndices of a QUERY or QUERY_BY_ID, or the List"
+                                                   + " of 
ScoredVectorWithUnsignedIndices of its matches, with the text in the"
+                                                   + " text_segment metadata, 
which the query returns with the"
+                                                   + " 
CamelPineconeQueryIncludeMetadata header set to true. A match without"
+                                                   + " the text gives an empty 
String, and a null body an empty List"),
            transformerOut = @BodyType(value = Carrier.LIST, javaType = 
"java.util.List<java.lang.String>"))
 public class PineconeReverseEmbeddingsDataTypeTransformer extends Transformer {
     @Override
     public void transform(Message message, DataType fromType, DataType toType) 
throws Exception {
-        List<ScoredVectorWithUnsignedIndices> embeddings = 
message.getBody(List.class);
+        List<ScoredVectorWithUnsignedIndices> embeddings;
+        if (message.getBody() instanceof QueryResponseWithUnsignedIndices 
response) {
+            // the body a QUERY or QUERY_BY_ID leaves
+            embeddings = response.getMatchesList();
+        } else {
+            embeddings = message.getBody(List.class);
+        }
 
         if (embeddings == null || embeddings.isEmpty()) {
             message.setBody(Collections.emptyList());
diff --git 
a/components/camel-ai/camel-pinecone/src/test/java/org/apache/camel/component/pinecone/PineconeVectorDbProducerTest.java
 
b/components/camel-ai/camel-pinecone/src/test/java/org/apache/camel/component/pinecone/PineconeVectorDbProducerTest.java
new file mode 100644
index 000000000000..9fa7f5f6ab5d
--- /dev/null
+++ 
b/components/camel-ai/camel-pinecone/src/test/java/org/apache/camel/component/pinecone/PineconeVectorDbProducerTest.java
@@ -0,0 +1,291 @@
+/*
+ * 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.pinecone;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.stream.Stream;
+
+import com.google.protobuf.Struct;
+import com.google.protobuf.Value;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpServer;
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+import io.grpc.stub.StreamObserver;
+import io.pinecone.proto.QueryRequest;
+import io.pinecone.proto.QueryResponse;
+import io.pinecone.proto.ScoredVector;
+import io.pinecone.proto.UpdateRequest;
+import io.pinecone.proto.UpdateResponse;
+import io.pinecone.proto.UpsertRequest;
+import io.pinecone.proto.UpsertResponse;
+import io.pinecone.proto.VectorServiceGrpc;
+import io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Named;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * CAMEL-26216: UPSERT, UPDATE and QUERY take the vector as a List of numbers, 
such as the List of Double a JSON array
+ * unmarshals to, or a float or double array, QUERY and QUERY_BY_ID return 10 
matches without the CamelPineconeQueryTopK
+ * header, UPSERT without the CamelPineconeIndexId header stores the vector 
under a random id, and the pinecone:rag data
+ * type transformer reads the matches of a QUERY. A fake Pinecone, its control 
plane on a JDK HttpServer and the data
+ * plane of the index on a gRPC server, records the requests of the client, so 
no Pinecone is needed.
+ */
+class PineconeVectorDbProducerTest extends CamelTestSupport {
+
+    private static final List<Float> VECTOR = List.of(0.1f, 0.2f, 0.3f);
+
+    // the client keeps a connection per index name for the JVM, so each test 
has its own index
+    private final String indexName = "camel-" + UUID.randomUUID();
+    private final List<Object> requests = new CopyOnWriteArrayList<>();
+    private HttpServer controlPlane;
+    private Server dataPlane;
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        dataPlane = ServerBuilder.forPort(0).addService(new 
VectorServiceGrpc.VectorServiceImplBase() {
+            @Override
+            public void upsert(UpsertRequest request, 
StreamObserver<UpsertResponse> reply) {
+                requests.add(request);
+                
reply.onNext(UpsertResponse.newBuilder().setUpsertedCount(request.getVectorsCount()).build());
+                reply.onCompleted();
+            }
+
+            @Override
+            public void update(UpdateRequest request, 
StreamObserver<UpdateResponse> reply) {
+                requests.add(request);
+                reply.onNext(UpdateResponse.getDefaultInstance());
+                reply.onCompleted();
+            }
+
+            @Override
+            public void query(QueryRequest request, 
StreamObserver<QueryResponse> reply) {
+                requests.add(request);
+                Struct metadata = Struct.newBuilder()
+                        .putFields("text_segment", 
Value.newBuilder().setStringValue("hello").build())
+                        .build();
+                reply.onNext(QueryResponse.newBuilder()
+                        
.addMatches(ScoredVector.newBuilder().setId("vector-1").setScore(0.9f).setMetadata(metadata))
+                        .build());
+                reply.onCompleted();
+            }
+        }).build().start();
+        controlPlane = HttpServer.create(new InetSocketAddress("localhost", 
0), 0);
+        controlPlane.createContext("/indexes/", this::describeIndex);
+        controlPlane.start();
+
+        CamelContext context = super.createCamelContext();
+        PineconeVectorDbConfiguration configuration
+                = context.getComponent(PineconeVectorDb.SCHEME, 
PineconeVectorDbComponent.class).getConfiguration();
+        configuration.setToken("test");
+        configuration.setHost("http://localhost:"; + 
controlPlane.getAddress().getPort());
+        configuration.setTls(false);
+        configuration.setIndexName(indexName);
+        return context;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:rag")
+                        .to("pinecone:rag?action=QUERY")
+                        .transformDataType(new DataType("pinecone:rag"));
+            }
+        };
+    }
+
+    @AfterEach
+    void stopFakePinecone() {
+        controlPlane.stop(0);
+        dataPlane.shutdownNow();
+    }
+
+    static Stream<Named<Object>> vectorBodies() {
+        return Stream.of(
+                Named.of("List of Float", List.of(0.1f, 0.2f, 0.3f)),
+                Named.of("List of Double", List.of(0.1d, 0.2d, 0.3d)),
+                Named.of("List of BigDecimal", List.of(new BigDecimal("0.1"), 
new BigDecimal("0.2"), new BigDecimal("0.3"))),
+                Named.of("float[]", new float[] { 0.1f, 0.2f, 0.3f }),
+                Named.of("double[]", new double[] { 0.1d, 0.2d, 0.3d }),
+                Named.of("Double[]", new Double[] { 0.1d, 0.2d, 0.3d }));
+    }
+
+    @ParameterizedTest
+    @MethodSource("vectorBodies")
+    void upsertTakesTheVector(Object body) {
+        Exchange result = fluentTemplate.to("pinecone:test?action=UPSERT")
+                .withHeader(PineconeVectorDbHeaders.INDEX_ID, "vector-1")
+                .withBody(body)
+                .request(Exchange.class);
+
+        assertNull(result.getException());
+        UpsertRequest upsert = assertInstanceOf(UpsertRequest.class, 
singleRequest());
+        assertEquals("vector-1", upsert.getVectors(0).getId());
+        assertEquals(VECTOR, upsert.getVectors(0).getValuesList());
+    }
+
+    @ParameterizedTest
+    @MethodSource("vectorBodies")
+    void updateTakesTheVector(Object body) {
+        Exchange result = fluentTemplate.to("pinecone:test?action=UPDATE")
+                .withHeader(PineconeVectorDbHeaders.INDEX_ID, "vector-1")
+                .withBody(body)
+                .request(Exchange.class);
+
+        assertNull(result.getException());
+        UpdateRequest update = assertInstanceOf(UpdateRequest.class, 
singleRequest());
+        assertEquals("vector-1", update.getId());
+        assertEquals(VECTOR, update.getValuesList());
+    }
+
+    @ParameterizedTest
+    @MethodSource("vectorBodies")
+    void queryTakesTheVector(Object body) {
+        Exchange result = fluentTemplate.to("pinecone:test?action=QUERY")
+                .withHeader(PineconeVectorDbHeaders.QUERY_TOP_K, 3)
+                .withBody(body)
+                .request(Exchange.class);
+
+        assertNull(result.getException());
+        QueryRequest query = assertInstanceOf(QueryRequest.class, 
singleRequest());
+        assertEquals(VECTOR, query.getVectorList());
+        assertEquals(3, query.getTopK());
+    }
+
+    @Test
+    void queryWithoutTheTopKHeaderReturnsTenMatches() {
+        Exchange result = fluentTemplate.to("pinecone:test?action=QUERY")
+                .withBody(VECTOR)
+                .request(Exchange.class);
+
+        assertNull(result.getException());
+        assertInstanceOf(QueryResponseWithUnsignedIndices.class, 
result.getMessage().getBody());
+        assertEquals(10, assertInstanceOf(QueryRequest.class, 
singleRequest()).getTopK());
+    }
+
+    @Test
+    void queryByIdWithoutTheTopKHeaderReturnsTenMatches() {
+        Exchange result = fluentTemplate.to("pinecone:test?action=QUERY_BY_ID")
+                .withHeader(PineconeVectorDbHeaders.INDEX_ID, "vector-1")
+                .request(Exchange.class);
+
+        assertNull(result.getException());
+        QueryRequest query = assertInstanceOf(QueryRequest.class, 
singleRequest());
+        assertEquals("vector-1", query.getId());
+        assertEquals(10, query.getTopK());
+    }
+
+    @Test
+    void upsertWithoutTheIdHeaderGeneratesOne() {
+        Exchange result = fluentTemplate.to("pinecone:test?action=UPSERT")
+                .withBody(VECTOR)
+                .request(Exchange.class);
+
+        assertNull(result.getException());
+        String id = 
result.getMessage().getHeader(PineconeVectorDbHeaders.INDEX_ID, String.class);
+        assertNotNull(id);
+        assertEquals(id, UUID.fromString(id).toString());
+        UpsertRequest upsert = assertInstanceOf(UpsertRequest.class, 
singleRequest());
+        assertEquals(id, upsert.getVectors(0).getId());
+        assertEquals(VECTOR, upsert.getVectors(0).getValuesList());
+    }
+
+    @Test
+    void theRagTransformerReadsTheMatchesOfAQuery() {
+        Object texts = fluentTemplate.to("direct:rag")
+                .withHeader(PineconeVectorDbHeaders.QUERY_TOP_K, 3)
+                .withHeader(PineconeVectorDbHeaders.QUERY_INCLUDE_METADATA, 
true)
+                .withBody(VECTOR)
+                .request();
+
+        assertEquals(List.of("hello"), texts);
+    }
+
+    @Test
+    void aBodyThatIsNotAVectorFails() {
+        Exchange text = fluentTemplate.to("pinecone:test?action=UPSERT")
+                .withHeader(PineconeVectorDbHeaders.INDEX_ID, "vector-1")
+                .withBody("0.1, 0.2, 0.3")
+                .request(Exchange.class);
+        InvalidPayloadException invalidPayload = 
assertInstanceOf(InvalidPayloadException.class, text.getException());
+        assertEquals(List.class, invalidPayload.getType());
+        assertTrue(invalidPayload.getMessage()
+                .contains("the vector must be a List of numbers, such as Float 
or Double, a float[] or a double[]"),
+                invalidPayload.getMessage());
+
+        // the message names the type of the element, not its value
+        Exchange listOfText = fluentTemplate.to("pinecone:test?action=QUERY")
+                .withBody(List.of("secret-0.1", "0.2"))
+                .request(Exchange.class);
+        IllegalArgumentException notANumber = 
assertInstanceOf(IllegalArgumentException.class, listOfText.getException());
+        assertTrue(notANumber.getMessage().startsWith("Vector element at index 
0 is a java.lang.String"),
+                notANumber.getMessage());
+        assertFalse(notANumber.getMessage().contains("secret"), 
notANumber.getMessage());
+
+        Exchange nullElement = fluentTemplate.to("pinecone:test?action=UPDATE")
+                .withHeader(PineconeVectorDbHeaders.INDEX_ID, "vector-1")
+                .withBody(Arrays.asList(0.1d, null, 0.3d))
+                .request(Exchange.class);
+        IllegalArgumentException isNull = 
assertInstanceOf(IllegalArgumentException.class, nullElement.getException());
+        assertTrue(isNull.getMessage().startsWith("Vector element at index 1 
is null"), isNull.getMessage());
+
+        assertEquals(List.of(), requests);
+    }
+
+    private Object singleRequest() {
+        assertEquals(1, requests.size(), requests::toString);
+        return requests.get(0);
+    }
+
+    private void describeIndex(HttpExchange http) throws IOException {
+        // the index, which the data plane of the fake serves
+        String json = "{\"name\":\"" + indexName + 
"\",\"dimension\":3,\"metric\":\"cosine\","
+                      + "\"host\":\"localhost:" + dataPlane.getPort() + "\","
+                      + 
"\"spec\":{\"serverless\":{\"cloud\":\"aws\",\"region\":\"us-east-1\"}},"
+                      + "\"status\":{\"ready\":true,\"state\":\"Ready\"}}";
+        byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
+        http.getResponseHeaders().add("Content-Type", "application/json");
+        http.sendResponseHeaders(200, bytes.length);
+        http.getResponseBody().write(bytes);
+        http.close();
+    }
+}
diff --git 
a/components/camel-ai/camel-pinecone/src/test/java/org/apache/camel/component/pinecone/transform/PineconeReverseEmbeddingsDataTypeTransformerTest.java
 
b/components/camel-ai/camel-pinecone/src/test/java/org/apache/camel/component/pinecone/transform/PineconeReverseEmbeddingsDataTypeTransformerTest.java
index d97516e489cb..e4b5dd850174 100644
--- 
a/components/camel-ai/camel-pinecone/src/test/java/org/apache/camel/component/pinecone/transform/PineconeReverseEmbeddingsDataTypeTransformerTest.java
+++ 
b/components/camel-ai/camel-pinecone/src/test/java/org/apache/camel/component/pinecone/transform/PineconeReverseEmbeddingsDataTypeTransformerTest.java
@@ -43,9 +43,10 @@ class PineconeReverseEmbeddingsDataTypeTransformerTest {
 
     @Test
     void theBodyTypesSayTheBody() throws Exception {
-        // CAMEL-25928: the matches of a query, or null, as transformerIn 
says, and the List of String transformerOut says
+        // CAMEL-25928: the response of a query or its matches, or null, as 
transformerIn says, and the List of String
+        // transformerOut says
         BodyTypes bodyTypes = 
PineconeReverseEmbeddingsDataTypeTransformer.class.getAnnotation(BodyTypes.class);
-        assertArrayEquals(new Carrier[] { Carrier.LIST, Carrier.NULL }, 
bodyTypes.transformerIn().value());
+        assertArrayEquals(new Carrier[] { Carrier.POJO, Carrier.LIST, 
Carrier.NULL }, bodyTypes.transformerIn().value());
         assertArrayEquals(new Carrier[] { Carrier.LIST }, 
bodyTypes.transformerOut().value());
         assertEquals("java.util.List<java.lang.String>", 
bodyTypes.transformerOut().javaType());
 
@@ -55,12 +56,14 @@ class PineconeReverseEmbeddingsDataTypeTransformerTest {
         // a null body gives an empty List
         assertEquals(List.of(), transform(null));
 
-        // the QueryResponseWithUnsignedIndices a QUERY leaves is not a List: 
the transformer gives an empty List
+        // CAMEL-26216: the QueryResponseWithUnsignedIndices a QUERY or 
QUERY_BY_ID leaves gives the texts of its matches,
+        // as its matches do
         QueryResponseWithUnsignedIndices response = new 
QueryResponseWithUnsignedIndices(
-                QueryResponse.newBuilder().addMatches(scoredVector("1", 
"hello")).build());
-        assertEquals(List.of(), transform(response));
-        // its matches are the body the transformer needs
-        assertEquals(List.of("hello"), transform(response.getMatchesList()));
+                QueryResponse.newBuilder().addMatches(scoredVector("1", 
"hello")).addMatches(scoredVector("2", null)).build());
+        assertEquals(List.of("hello", ""), transform(response));
+        assertEquals(List.of("hello", ""), 
transform(response.getMatchesList()));
+        // a response without matches gives an empty List
+        assertEquals(List.of(), transform(new 
QueryResponseWithUnsignedIndices(QueryResponse.getDefaultInstance())));
     }
 
     private Object transform(Object body) throws Exception {
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index f23049e8871e..f7bfdc3326ae 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -5582,6 +5582,14 @@ other operations do. Previously they failed without the 
headers.
 * A `java.util.Date` in the `CamelAwsCwMetricTimestamp` header is now used. 
Previously it was ignored. The catalog
   lists the header as an `Instant`.
 
+=== camel-pinecone - default topK, generated UPSERT id and the pinecone:rag 
transformer
+
+QUERY and QUERY_BY_ID without the `CamelPineconeQueryTopK` header now return 
10 matches, as camel-weaviate does. Before, they failed with a 
`NullPointerException`.
+
+UPSERT without the `CamelPineconeIndexId` header now stores the vector under a 
random UUID, as the `pinecone:embeddings` data type transformer does, and sets 
the `CamelPineconeIndexId` header to that id. Before, it failed with a 
`PineconeValidationException`.
+
+The `pinecone:rag` data type transformer now reads the 
`QueryResponseWithUnsignedIndices` body that a QUERY or QUERY_BY_ID leaves, and 
returns the texts of its matches. Before, it returned an empty List for that 
body. A route that passes the `matchesList` of the response to the transformer 
gets the same result as before.
+
 === camel-aws2-lambda - the code of createFunction and updateFunction, and the 
payload of invokeFunction
 
 * createFunction and updateFunction: the `CamelAwsLambdaZipFile` header, or 
the S3 location of the
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PineconeVectorDbEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PineconeVectorDbEndpointBuilderFactory.java
index 09af9ee571a1..4c64d5d39b6f 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PineconeVectorDbEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PineconeVectorDbEndpointBuilderFactory.java
@@ -525,7 +525,8 @@ public interface PineconeVectorDbEndpointBuilderFactory {
             return "CamelPineconeCollectionCloudRegion";
         }
         /**
-         * Index Upsert Id.
+         * The id of the vector for UPSERT, UPDATE and QUERY_BY_ID. Without it,
+         * UPSERT generates a random UUID and sets this header to it.
          * 
          * The option is a: {@code String} type.
          * 
@@ -537,10 +538,11 @@ public interface PineconeVectorDbEndpointBuilderFactory {
             return "CamelPineconeIndexId";
         }
         /**
-         * Query Top K.
+         * The number of matches QUERY and QUERY_BY_ID return.
          * 
          * The option is a: {@code Integer} type.
          * 
+         * Default: 10
          * Group: producer
          * 
          * @return the name of the header {@code PineconeQueryTopK}.
@@ -563,7 +565,7 @@ public interface PineconeVectorDbEndpointBuilderFactory {
         /**
          * Query Filter.
          * 
-         * The option is a: {@code String} type.
+         * The option is a: {@code com.google.protobuf.Struct} type.
          * 
          * Group: producer
          * 
@@ -587,7 +589,7 @@ public interface PineconeVectorDbEndpointBuilderFactory {
         /**
          * Query Include Metadata.
          * 
-         * The option is a: {@code com.google.protobuf.Struct} type.
+         * The option is a: {@code boolean} type.
          * 
          * Group: producer
          * 
diff --git 
a/test-infra/camel-test-infra-pinecone/src/main/java/org/apache/camel/test/infra/pinecone/services/PineconeLocalContainerInfraService.java
 
b/test-infra/camel-test-infra-pinecone/src/main/java/org/apache/camel/test/infra/pinecone/services/PineconeLocalContainerInfraService.java
index de2e9b20c4ef..fb449f35c606 100644
--- 
a/test-infra/camel-test-infra-pinecone/src/main/java/org/apache/camel/test/infra/pinecone/services/PineconeLocalContainerInfraService.java
+++ 
b/test-infra/camel-test-infra-pinecone/src/main/java/org/apache/camel/test/infra/pinecone/services/PineconeLocalContainerInfraService.java
@@ -28,6 +28,7 @@ import 
org.apache.camel.test.infra.common.services.ContainerService;
 import org.apache.camel.test.infra.pinecone.common.PineconeProperties;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.wait.strategy.Wait;
 import org.testcontainers.pinecone.PineconeLocalContainer;
 import org.testcontainers.utility.DockerImageName;
 
@@ -38,6 +39,13 @@ public class PineconeLocalContainerInfraService implements 
PineconeInfraService,
 
     private static final Logger LOG = 
LoggerFactory.getLogger(PineconeLocalContainerInfraService.class);
 
+    // the control plane, and the ports pinecone-local serves the indexes it 
creates on, one port each. They are bound
+    // to the same host ports, as pinecone-local gives each index host as 
localhost:<port>, so a container serves at
+    // most five indexes: a test that creates more needs a wider range
+    private static final int CONTROL_PLANE_PORT = 5080;
+    private static final int FIRST_INDEX_PORT = 5081;
+    private static final int LAST_INDEX_PORT = 5085;
+
     private final PineconeLocalContainer container;
 
     public PineconeLocalContainerInfraService() {
@@ -59,9 +67,18 @@ public class PineconeLocalContainerInfraService implements 
PineconeInfraService,
                 super(DockerImageName.parse(imageName)
                         
.asCompatibleSubstituteFor("pinecone-io/pinecone-local"));
 
+                // wait for the control plane only, not for the index ports 
bound below
+                waitingFor(Wait.forListeningPorts(CONTROL_PLANE_PORT));
                 withStartupTimeout(Duration.ofMinutes(3L));
 
-                ContainerEnvironmentUtil.configurePort(this, fixedPort, 5080);
+                ContainerEnvironmentUtil.configurePort(this, fixedPort, 
CONTROL_PLANE_PORT);
+
+                // the control plane gives each index as localhost:<port>, 
which the Pinecone client connects to for
+                // the data plane (upsert, query, fetch), so the index ports 
are bound to the same ports of the host
+                withEnv("PINECONE_HOST", "localhost");
+                for (int port = FIRST_INDEX_PORT; port <= LAST_INDEX_PORT; 
port++) {
+                    addFixedExposedPort(port, port);
+                }
             }
         }
 

Reply via email to