diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/a2a.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/a2a.json index 4fb7bd58f9819..2ac1c899e37a7 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/a2a.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/a2a.json @@ -49,6 +49,12 @@ "CamelA2AListStatus": { "index": 17, "kind": "header", "displayName": "", "group": "common", "label": "common", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Comma-separated status filter for task listing", "constantName": "org.apache.camel.component.a2a.A2AConstants#LIST_STATUS" }, "CamelA2AExtensions": { "index": 18, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "java.util.List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Negotiated A2A extension URIs requested by the client", "constantName": "org.apache.camel.component.a2a.A2AConstants#EXTENSIONS" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "text" ], "byOption": [ { "option": "dataFormat", "value": "POJO", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.a2a.model.Message" } ], "description": "The message of the caller, for SendMessage and SendStreamingMessage (the component answers the task and push config requests itself): the text of its parts, one per line, a data part as JSON and a file part as its URL. With dataFormat POJO the Message, with RAW the Message as JSON" }, + "consumerReply": { "carriers": [ "text", "bytes", "stream", "file", "pojo" ], "description": "The reply of the agent: text, sent as one text part (bytes, a stream or a file as their text), or a Message sent as it is. Another body is sent as text: a Task as the text of its last message, a Map or a POJO as its toString(): marshal it first. The reply goes in a Task, completed unless the CamelA2ATaskState header says another state, or as a Message when the CamelA2AResponseType header is message" }, + "producerIn": { "carriers": [ "text", "bytes", "stream", "file", "pojo" ], "byOption": [ { "option": "operation", "value": "TASK_GET", "carriers": [ "any" ] }, { "option": "operation", "value": "TASK_LIST", "carriers": [ "any" ] }, { "option": "operation", "value": "TASK_CANCEL", "carriers": [ "any" ] }, { "option": "operation", "value": "TASK_SUBSCRIBE", "carriers": [ "any" ] }, { "option": "operation", "value": "PUSH_CONFIG_CREATE", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.a2a.model.TaskPushNotificationConfig" }, { "option": "operation", "value": "PUSH_CONFIG_GET", "carriers": [ "any" ] }, { "option": "operation", "value": "PUSH_CONFIG_LIST", "carriers": [ "any" ] }, { "option": "operation", "value": "PUSH_CONFIG_DELETE", "carriers": [ "any" ] } ], "description": "The message to send: text, sent as one text part (bytes, a stream or a file as their text), or a Message sent as it is; MESSAGE_STREAM also takes a SendMessageRequest. Another body is sent as its toString(), so a Map or a POJO needs marshalling first, and JSON text is sent as text. PUSH_CONFIG_CREATE needs a TaskPushNotificationConfig, and the other operations read headers, not the body" }, + "producerOut": { "carriers": [ "text" ], "byOption": [ { "option": "operation", "value": "MESSAGE_STREAM", "carriers": [ "iterator" ], "javaType": "org.apache.camel.component.a2a.streaming.SseEventIterator" }, { "option": "operation", "value": "TASK_GET", "carriers": [ "text" ] }, { "option": "operation", "value": "TASK_LIST", "carriers": [ "list", "null" ] }, { "option": "operation", "value": "TASK_CANCEL", "carriers": [ "text" ] }, { "option": "operation", "value": "TASK_SUBSCRIBE", "carriers": [ "iterator" ], "javaType": "org.apache.camel.component.a2a.streaming.SseEventIterator" }, { "option": "operation", "value": "PUSH_CONFIG_CREATE", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.a2a.model.TaskPushNotificationConfig" }, { "option": "operation", "value": "PUSH_CONFIG_GET", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.a2a.model.TaskPushNotificationConfig" }, { "option": "operation", "value": "PUSH_CONFIG_LIST", "carriers": [ "list", "null" ] }, { "option": "operation", "value": "PUSH_CONFIG_DELETE", "carriers": [ "map" ] }, { "option": "dataFormat", "value": "POJO", "carriers": [ "pojo" ] }, { "option": "dataFormat", "value": "RAW", "carriers": [ "text" ] } ], "description": "The reply of the agent as text: the parts of the Message, or of the last message in the history of the Task, one per line. TASK_GET and TASK_CANCEL give the text of the Task, TASK_LIST a List of Task, MESSAGE_STREAM and TASK_SUBSCRIBE an Iterator of the events as they arrive (split it), and the push config operations a TaskPushNotificationConfig, a List of them, or an empty Map for delete. With dataFormat POJO the Task or the Message, with RAW the JSON of the response as text (a stream of the events for MESSAGE_STREAM and TASK_SUBSCRIBE)" } + }, "properties": { "agentCardSource": { "index": 0, "kind": "path", "displayName": "Agent Card Source", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The agent card source (classpath:, file:, http:\/\/, https:\/\/, or plain name)" }, "agentCard": { "index": 1, "kind": "parameter", "displayName": "Agent Card", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.a2a.model.AgentCard", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.a2a.A2AConfiguration", "configurationField": "configuration", "description": "Agent card bean reference or inline configuration" }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ai-tool.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ai-tool.json index 0ce16172cd96e..deed749b292a1 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ai-tool.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ai-tool.json @@ -46,6 +46,10 @@ "CamelAiToolCallId": { "index": 0, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The tool invocation identifier supplied by the calling framework. Absent when the framework does not supply one.", "constantName": "org.apache.camel.component.ai.tool.AiToolConstants#TOOL_CALL_ID" }, "CamelAiToolConversationId": { "index": 1, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The conversation identifier supplied by the calling framework. Absent when the framework does not supply one.", "constantName": "org.apache.camel.component.ai.tool.AiToolConstants#CONVERSATION_ID" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "null" ], "description": "No body: each argument of the tool call is a header named as its parameter, a Map or a List for a nested JSON value. Undeclared arguments and names starting with camel are dropped" }, + "consumerReply": { "carriers": [ "any" ], "dependsOn": [ "outputSchema", "outputParameters" ], "description": "The tool result, as text: the body converted to a String, so a Map, a List or a POJO is sent as its toString(): marshal it to JSON first. No body gives No result. With outputSchema or outputParameter.NAME options the body must be JSON: a JSON String, a Map, a List, a number or a boolean, and bytes, a stream or another object fail the call" } + }, "properties": { "toolName": { "index": 0, "kind": "path", "displayName": "Tool Name", "group": "consumer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The tool name. This is the name the LLM sees and uses to invoke the tool." }, "argSchema": { "index": 1, "kind": "parameter", "displayName": "Arg Schema", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "supportFileReference": true, "configurationClass": "org.apache.camel.component.ai.tool.AiToolConfiguration", "configurationField": "configuration", "description": "Raw JSON Schema for tool input parameters. Supports inline JSON and resource references (classpath:, file:, resource:). Mutually exclusive with the parameter multi-value options. Use for nested objects, arrays, oneOf, and other complex schemas." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/docling.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/docling.json index 2929f7f681345..426611f97d2fd 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/docling.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/docling.json @@ -117,6 +117,11 @@ "CamelDoclingChunkingMaxTokens": { "index": 30, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Maximum tokens per chunk for hybrid chunking", "constantName": "org.apache.camel.component.docling.DoclingHeaders#CHUNKING_MAX_TOKENS" }, "CamelDoclingChunkingMergePeers": { "index": 31, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Whether to merge peer chunks in hybrid chunking", "constantName": "org.apache.camel.component.docling.DoclingHeaders#CHUNKING_MERGE_PEERS" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "text" ], "description": "The document of an async conversion that completed (SUBMIT_ASYNC_CONVERSION on the same component), as text in the outputFormat it was submitted with: markdown by default, JSON text for json. The task id is in the CamelDoclingTaskId header, and a failed conversion goes to the error handler" }, + "producerIn": { "carriers": [ "any" ], "byOption": [ { "option": "operation", "value": "BATCH_CONVERT_TO_MARKDOWN", "carriers": [ "list" ] }, { "option": "operation", "value": "BATCH_CONVERT_TO_HTML", "carriers": [ "list" ] }, { "option": "operation", "value": "BATCH_CONVERT_TO_JSON", "carriers": [ "list" ] }, { "option": "operation", "value": "BATCH_EXTRACT_TEXT", "carriers": [ "list" ] }, { "option": "operation", "value": "BATCH_EXTRACT_STRUCTURED_DATA", "carriers": [ "list" ] } ], "description": "The document: its content as text or bytes, or a File (the GenericFile of the file consumers too). A stream or a Path fails: convert it to bytes first. Text that looks like a URL or a path (it starts with http:\/\/, https:\/\/ or \/, or has a backslash) is read as one only with allowUrlSource or allowFilePathSource, and fails otherwise. With the CamelDoclingInputFilePath header the body is not read. The batch operations take a List or an array of paths or files (a directory path with allowFilePathSource), and CHECK_CONVERSION_STATUS the task id, unless the CamelDoclingTaskId header gives it" }, + "producerOut": { "carriers": [ "text" ], "byOption": [ { "option": "operation", "value": "CONVERT_TO_JSON", "carriers": [ "pojo" ], "javaType": "ai.docling.core.DoclingDocument" }, { "option": "operation", "value": "EXTRACT_STRUCTURED_DATA", "carriers": [ "pojo" ], "javaType": "ai.docling.core.DoclingDocument" }, { "option": "operation", "value": "CHECK_CONVERSION_STATUS", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.docling.ConversionStatus" }, { "option": "operation", "value": "EXTRACT_METADATA", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.docling.DocumentMetadata" }, { "option": "operation", "value": "BATCH_CONVERT_TO_MARKDOWN", "carriers": [ "pojo", "list" ] }, { "option": "operation", "value": "BATCH_CONVERT_TO_HTML", "carriers": [ "pojo", "list" ] }, { "option": "operation", "value": "BATCH_CONVERT_TO_JSON", "carriers": [ "pojo", "list" ] }, { "option": "operation", "value": "BATCH_EXTRACT_TEXT", "carriers": [ "pojo", "list" ] }, { "option": "operation", "value": "BATCH_EXTRACT_STRUCTURED_DATA", "carriers": [ "pojo", "list" ] }, { "option": "operation", "value": "CHUNK_HYBRID", "carriers": [ "pojo", "list" ] }, { "option": "operation", "value": "CHUNK_HIERARCHICAL", "carriers": [ "pojo", "list" ] } ], "description": "By the operation: text for the conversions to markdown, HTML and text, which with the docling CLI is the path of the output file unless contentInBody (useDoclingServe gives the content); the task id for SUBMIT_ASYNC_CONVERSION; a DoclingDocument for CONVERT_TO_JSON and EXTRACT_STRUCTURED_DATA; a BatchProcessingResults for the batch operations, a List of BatchConversionResult with splitBatchResults; and a ChunkDocumentResponse for the chunking, a List of Chunk with contentInBody" } + }, "properties": { "operationId": { "index": 0, "kind": "path", "displayName": "Operation Id", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation identifier" }, "contentInBody": { "index": 1, "kind": "parameter", "displayName": "Content In Body", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.docling.DoclingConfiguration", "configurationField": "configuration", "description": "Include the content of the output file in the exchange body and delete the output file" }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ibm-watson-language.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ibm-watson-language.json index ce47ac5e383e0..d0b502549cf53 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ibm-watson-language.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/ibm-watson-language.json @@ -53,6 +53,10 @@ "CamelIBMWatsonLanguageSentimentScore": { "index": 10, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Double", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The sentiment score", "constantName": "org.apache.camel.component.ibm.watson.language.WatsonLanguageConstants#SENTIMENT_SCORE" }, "CamelIBMWatsonLanguageSentimentLabel": { "index": 11, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The sentiment label (positive, negative, neutral)", "constantName": "org.apache.camel.component.ibm.watson.language.WatsonLanguageConstants#SENTIMENT_LABEL" } }, + "bodyTypes": { + "producerIn": { "carriers": [ "any" ], "description": "The text to analyze for analyzeText, or the URL of the page for analyzeUrl, read as text, unless the CamelIBMWatsonLanguageText or CamelIBMWatsonLanguageUrl header gives it. Without the header, no body or a blank one fails, and a Map or a POJO is analyzed as its toString(): marshal it first" }, + "producerOut": { "carriers": [ "pojo" ], "javaType": "com.ibm.watson.natural_language_understanding.v1.model.AnalysisResults", "description": "The results of the features enabled (sentiment, entities, keywords and so on), with the sentiment score and label and the language in headers too. Converted to text, it is the JSON of the results" } + }, "properties": { "label": { "index": 0, "kind": "path", "displayName": "Label", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Logical name" }, "serviceUrl": { "index": 1, "kind": "parameter", "displayName": "Service Url", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.ibm.watson.language.WatsonLanguageConfiguration", "configurationField": "configuration", "description": "The service endpoint URL. If not specified, the default URL will be used." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-chat.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-chat.json index 951f48a17cf57..f1aedc286dafc 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-chat.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-chat.json @@ -48,6 +48,10 @@ "CamelLangChain4jChatRequestModel": { "index": 6, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The request model name.", "constantName": "org.apache.camel.component.langchain4j.chat.LangChain4jChatHeaders#REQUEST_MODEL" }, "CamelLangChain4jChatResponseModel": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The response model name.", "constantName": "org.apache.camel.component.langchain4j.chat.LangChain4jChatHeaders#RESPONSE_MODEL" } }, + "bodyTypes": { + "producerIn": { "carriers": [ "any" ], "byOption": [ { "option": "chatOperation", "value": "CHAT_SINGLE_MESSAGE_WITH_PROMPT", "carriers": [ "map" ] }, { "option": "chatOperation", "value": "CHAT_MULTIPLE_MESSAGES", "carriers": [ "list" ] } ], "description": "The prompt as text, or a ChatMessage; another body is sent as its toString(), and no body fails. CHAT_SINGLE_MESSAGE_WITH_PROMPT takes the variables of the template in the CamelLangChain4jChatPromptTemplate header as a Map, and CHAT_MULTIPLE_MESSAGES a List of ChatMessage" }, + "producerOut": { "carriers": [ "text" ], "description": "The answer of the model as text, also when it is asked for JSON: unmarshal it to read its fields" } + }, "properties": { "chatId": { "index": 0, "kind": "path", "displayName": "Chat Id", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The id" }, "chatOperation": { "index": 1, "kind": "parameter", "displayName": "Chat Operation", "group": "producer", "label": "", "required": true, "type": "enum", "javaType": "org.apache.camel.component.langchain4j.chat.LangChain4jChatOperations", "enum": [ "CHAT_SINGLE_MESSAGE", "CHAT_SINGLE_MESSAGE_WITH_PROMPT", "CHAT_MULTIPLE_MESSAGES" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "CHAT_SINGLE_MESSAGE", "configurationClass": "org.apache.camel.component.langchain4j.chat.LangChain4jChatConfiguration", "configurationField": "configuration", "description": "Operation in case of Endpoint of type CHAT. The value is one of the values of org.apache.camel.component.langchain4j.chat.LangChain4jChatOperations" }, 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 a2451cbd1b69b..6870d839b3a6f 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 @@ -146,6 +146,12 @@ "CamelOpenAIImageOutputTokens": { "index": 107, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The number of output tokens billed for the image request. Only reported by GPT image models", "constantName": "org.apache.camel.component.openai.OpenAIConstants#IMAGE_OUTPUT_TOKENS" }, "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" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "pojo" ], "javaType": "com.openai.models.webhooks.UnwrapWebhookEvent", "description": "The event of the webhook operation, verified with webhookSecret, such as a batch or a background response that completed. The event type and the id of the object it is about are in headers" }, + "consumerReply": { "carriers": [ "any" ], "description": "The body at the end of the route is not sent: OpenAI gets 200 without a body, or 500 when the route fails, and then sends the event again" }, + "producerIn": { "carriers": [ "any" ], "byOption": [ { "option": "operation", "value": "decisions", "carriers": [ "pojo" ], "javaType": "com.openai.models.decisions.DecisionCreateParams" }, { "option": "operation", "value": "batch", "carriers": [ "map", "list", "text", "bytes", "stream", "file" ] }, { "option": "operation", "value": "audio-transcription", "carriers": [ "file", "bytes", "stream" ] }, { "option": "operation", "value": "audio-translation", "carriers": [ "file", "bytes", "stream" ] }, { "option": "operation", "value": "image-edit", "carriers": [ "file", "bytes", "stream", "list" ] } ], "description": "The prompt of chat-completion and responses: text, or a file, bytes or a stream with an image or a PDF (chat-completion also audio), which userMessage then describes. Another body is sent as its toString(), and userMessage or the CamelOpenAIUserMessage header replaces a text body. embeddings and moderation take text or a List of texts (moderation also an image), audio-speech the text to speak, and image-generation the prompt unless imagePrompt is set. batch takes the requests as a Map keyed by custom_id, a List, or JSONL; audio takes the audio and image-edit the image, or a List of images. The operations that read a stored response, a batch or the tool calls of the last answer do not use the body" }, + "producerOut": { "carriers": [ "text" ], "byOption": [ { "option": "streaming", "value": "true", "carriers": [ "iterator" ] }, { "option": "autoToolExecution", "value": "false", "carriers": [ "text", "pojo", "list" ] }, { "option": "operation", "value": "decisions", "carriers": [ "pojo" ], "javaType": "com.openai.models.decisions.Decision" }, { "option": "operation", "value": "responses", "carriers": [ "text" ] }, { "option": "operation", "value": "responses-retrieve", "carriers": [ "text" ] }, { "option": "operation", "value": "responses-cancel", "carriers": [ "text" ] }, { "option": "operation", "value": "batch", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "batch-retrieve", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "batch-cancel", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "batch-results", "carriers": [ "iterator" ] }, { "option": "operation", "value": "embeddings", "carriers": [ "list" ] }, { "option": "operation", "value": "tool-execution", "carriers": [ "null", "unchanged" ] }, { "option": "operation", "value": "audio-transcription", "carriers": [ "text" ] }, { "option": "operation", "value": "audio-translation", "carriers": [ "text" ] }, { "option": "operation", "value": "audio-speech", "carriers": [ "bytes" ], "javaType": "byte[]" }, { "option": "operation", "value": "moderation", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "image-generation", "carriers": [ "bytes", "text", "list" ] }, { "option": "operation", "value": "image-edit", "carriers": [ "bytes", "text", "list" ] } ], "description": "The answer of chat-completion as text, also with outputClass or jsonSchema, where it is JSON text: unmarshal it to read its fields. With streaming, an Iterator of the chunks (text when MCP tools run in a loop). With autoToolExecution=false, the tool calls the model asks for: an Optional of the List of tool calls, or a List of the function calls for responses. embeddings gives a vector (a List of Float), or a List of vectors for a List of texts; image-generation and image-edit the image as bytes or its URL as text, a List for several; batch-results an Iterator of the result lines as Maps. batch and moderation keep the body and set headers, and tool-execution clears it when it runs tool calls" } + }, "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", "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" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "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', 'image-edit', or 'webhook' (a consumer)" }, "additionalBodyProperty": { "index": 1, "kind": "parameter", "displayName": "Additional Body Property", "group": "common", "label": "", "required": false, "type": "object", "javaType": "java.util.Map", "prefix": "additionalBodyProperty.", "multiValue": true, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Additional JSON properties to include in the request body (e.g. additionalBodyProperty.traceId=123). This is a multi-value option with prefix: additionalBodyProperty." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/milvus.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/milvus.json index 401fd632d4ccb..c2c82cb38cd3e 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/milvus.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/milvus.json @@ -42,6 +42,10 @@ "CamelMilvusKeyName": { "index": 6, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Key Name for Insert\/Upsert operation", "constantName": "org.apache.camel.component.milvus.MilvusHeaders#KEY_NAME" }, "CamelMilvusKeyValue": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Key Value for Insert\/Upsert operation", "constantName": "org.apache.camel.component.milvus.MilvusHeaders#KEY_VALUE" } }, + "bodyTypes": { + "producerIn": { "carriers": [ "pojo" ], "description": "The request of the Milvus SDK for the action in the CamelMilvusAction header: a CreateCollectionParam, CreateIndexParam, InsertParam, UpsertParam, SearchSimpleParam, QueryParam or DeleteParam. Another body fails, a vector as a List too: the milvus:embeddings data type transformer builds the InsertParam or UpsertParam from the output of langchain4j-embeddings" }, + "producerOut": { "carriers": [ "pojo" ], "description": "The result of the Milvus SDK for the action: an RpcStatus for CREATE_COLLECTION and CREATE_INDEX, a MutationResult for INSERT, UPSERT and DELETE, a SearchResponse for SEARCH and a QueryResults for QUERY" } + }, "properties": { "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection Name" }, "host": { "index": 1, "kind": "parameter", "displayName": "Host", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "localhost", "configurationClass": "org.apache.camel.component.milvus.MilvusConfiguration", "configurationField": "configuration", "description": "The host to connect to." }, 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 d212b19e520cd..4d569fa9d9439 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 @@ -146,6 +146,12 @@ "CamelOpenAIImageOutputTokens": { "index": 107, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The number of output tokens billed for the image request. Only reported by GPT image models", "constantName": "org.apache.camel.component.openai.OpenAIConstants#IMAGE_OUTPUT_TOKENS" }, "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" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "pojo" ], "javaType": "com.openai.models.webhooks.UnwrapWebhookEvent", "description": "The event of the webhook operation, verified with webhookSecret, such as a batch or a background response that completed. The event type and the id of the object it is about are in headers" }, + "consumerReply": { "carriers": [ "any" ], "description": "The body at the end of the route is not sent: OpenAI gets 200 without a body, or 500 when the route fails, and then sends the event again" }, + "producerIn": { "carriers": [ "any" ], "byOption": [ { "option": "operation", "value": "decisions", "carriers": [ "pojo" ], "javaType": "com.openai.models.decisions.DecisionCreateParams" }, { "option": "operation", "value": "batch", "carriers": [ "map", "list", "text", "bytes", "stream", "file" ] }, { "option": "operation", "value": "audio-transcription", "carriers": [ "file", "bytes", "stream" ] }, { "option": "operation", "value": "audio-translation", "carriers": [ "file", "bytes", "stream" ] }, { "option": "operation", "value": "image-edit", "carriers": [ "file", "bytes", "stream", "list" ] } ], "description": "The prompt of chat-completion and responses: text, or a file, bytes or a stream with an image or a PDF (chat-completion also audio), which userMessage then describes. Another body is sent as its toString(), and userMessage or the CamelOpenAIUserMessage header replaces a text body. embeddings and moderation take text or a List of texts (moderation also an image), audio-speech the text to speak, and image-generation the prompt unless imagePrompt is set. batch takes the requests as a Map keyed by custom_id, a List, or JSONL; audio takes the audio and image-edit the image, or a List of images. The operations that read a stored response, a batch or the tool calls of the last answer do not use the body" }, + "producerOut": { "carriers": [ "text" ], "byOption": [ { "option": "streaming", "value": "true", "carriers": [ "iterator" ] }, { "option": "autoToolExecution", "value": "false", "carriers": [ "text", "pojo", "list" ] }, { "option": "operation", "value": "decisions", "carriers": [ "pojo" ], "javaType": "com.openai.models.decisions.Decision" }, { "option": "operation", "value": "responses", "carriers": [ "text" ] }, { "option": "operation", "value": "responses-retrieve", "carriers": [ "text" ] }, { "option": "operation", "value": "responses-cancel", "carriers": [ "text" ] }, { "option": "operation", "value": "batch", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "batch-retrieve", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "batch-cancel", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "batch-results", "carriers": [ "iterator" ] }, { "option": "operation", "value": "embeddings", "carriers": [ "list" ] }, { "option": "operation", "value": "tool-execution", "carriers": [ "null", "unchanged" ] }, { "option": "operation", "value": "audio-transcription", "carriers": [ "text" ] }, { "option": "operation", "value": "audio-translation", "carriers": [ "text" ] }, { "option": "operation", "value": "audio-speech", "carriers": [ "bytes" ], "javaType": "byte[]" }, { "option": "operation", "value": "moderation", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "image-generation", "carriers": [ "bytes", "text", "list" ] }, { "option": "operation", "value": "image-edit", "carriers": [ "bytes", "text", "list" ] } ], "description": "The answer of chat-completion as text, also with outputClass or jsonSchema, where it is JSON text: unmarshal it to read its fields. With streaming, an Iterator of the chunks (text when MCP tools run in a loop). With autoToolExecution=false, the tool calls the model asks for: an Optional of the List of tool calls, or a List of the function calls for responses. embeddings gives a vector (a List of Float), or a List of vectors for a List of texts; image-generation and image-edit the image as bytes or its URL as text, a List for several; batch-results an Iterator of the result lines as Maps. batch and moderation keep the body and set headers, and tool-execution clears it when it runs tool calls" } + }, "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", "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" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "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', 'image-edit', or 'webhook' (a consumer)" }, "additionalBodyProperty": { "index": 1, "kind": "parameter", "displayName": "Additional Body Property", "group": "common", "label": "", "required": false, "type": "object", "javaType": "java.util.Map", "prefix": "additionalBodyProperty.", "multiValue": true, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Additional JSON properties to include in the request body (e.g. additionalBodyProperty.traceId=123). This is a multi-value option with prefix: additionalBodyProperty." }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/qdrant.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/qdrant.json index 283a45b213cb8..4370a6d815738 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/qdrant.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/qdrant.json @@ -48,6 +48,10 @@ "CamelQdrantPointId": { "index": 9, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The point id to use for operation.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#POINT_ID" }, "CamelQdrantMaxResults": { "index": 10, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The maximum number of results to return from a similarity search.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#MAX_RESULTS" } }, + "bodyTypes": { + "producerIn": { "carriers": [ "pojo", "list", "null" ], "description": "By the action in the CamelQdrantAction header: a VectorParams for CREATE_COLLECTION, a PointStruct or a List of them for UPSERT, a PointId or a List of them for RETRIEVE, a PointsSelector, PointId, Filter or Condition for DELETE, and the query vector as a List of Float, a float array or a PointStruct for SIMILARITY_SEARCH. DELETE_COLLECTION and COLLECTION_INFO do not read the body. Another body fails, such as a number as the id (use PointIdFactory.id) or a List of Double. The qdrant:embeddings data type transformer builds the PointStruct from the output of langchain4j-embeddings" }, + "producerOut": { "carriers": [ "list", "pojo", "unchanged" ], "description": "By the action: a List of RetrievedPoint for RETRIEVE, a List of ScoredPoint for SIMILARITY_SEARCH and a CollectionInfo for COLLECTION_INFO. The other actions keep the body, UPSERT and DELETE with the operation id and status in headers" } + }, "properties": { "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection Name" }, "host": { "index": 1, "kind": "parameter", "displayName": "Host", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "localhost", "configurationClass": "org.apache.camel.component.qdrant.QdrantConfiguration", "configurationField": "configuration", "description": "The host to connect to." }, diff --git a/components/camel-ai/camel-a2a/src/generated/resources/META-INF/org/apache/camel/component/a2a/a2a.json b/components/camel-ai/camel-a2a/src/generated/resources/META-INF/org/apache/camel/component/a2a/a2a.json index 4fb7bd58f9819..2ac1c899e37a7 100644 --- a/components/camel-ai/camel-a2a/src/generated/resources/META-INF/org/apache/camel/component/a2a/a2a.json +++ b/components/camel-ai/camel-a2a/src/generated/resources/META-INF/org/apache/camel/component/a2a/a2a.json @@ -49,6 +49,12 @@ "CamelA2AListStatus": { "index": 17, "kind": "header", "displayName": "", "group": "common", "label": "common", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Comma-separated status filter for task listing", "constantName": "org.apache.camel.component.a2a.A2AConstants#LIST_STATUS" }, "CamelA2AExtensions": { "index": 18, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "java.util.List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Negotiated A2A extension URIs requested by the client", "constantName": "org.apache.camel.component.a2a.A2AConstants#EXTENSIONS" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "text" ], "byOption": [ { "option": "dataFormat", "value": "POJO", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.a2a.model.Message" } ], "description": "The message of the caller, for SendMessage and SendStreamingMessage (the component answers the task and push config requests itself): the text of its parts, one per line, a data part as JSON and a file part as its URL. With dataFormat POJO the Message, with RAW the Message as JSON" }, + "consumerReply": { "carriers": [ "text", "bytes", "stream", "file", "pojo" ], "description": "The reply of the agent: text, sent as one text part (bytes, a stream or a file as their text), or a Message sent as it is. Another body is sent as text: a Task as the text of its last message, a Map or a POJO as its toString(): marshal it first. The reply goes in a Task, completed unless the CamelA2ATaskState header says another state, or as a Message when the CamelA2AResponseType header is message" }, + "producerIn": { "carriers": [ "text", "bytes", "stream", "file", "pojo" ], "byOption": [ { "option": "operation", "value": "TASK_GET", "carriers": [ "any" ] }, { "option": "operation", "value": "TASK_LIST", "carriers": [ "any" ] }, { "option": "operation", "value": "TASK_CANCEL", "carriers": [ "any" ] }, { "option": "operation", "value": "TASK_SUBSCRIBE", "carriers": [ "any" ] }, { "option": "operation", "value": "PUSH_CONFIG_CREATE", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.a2a.model.TaskPushNotificationConfig" }, { "option": "operation", "value": "PUSH_CONFIG_GET", "carriers": [ "any" ] }, { "option": "operation", "value": "PUSH_CONFIG_LIST", "carriers": [ "any" ] }, { "option": "operation", "value": "PUSH_CONFIG_DELETE", "carriers": [ "any" ] } ], "description": "The message to send: text, sent as one text part (bytes, a stream or a file as their text), or a Message sent as it is; MESSAGE_STREAM also takes a SendMessageRequest. Another body is sent as its toString(), so a Map or a POJO needs marshalling first, and JSON text is sent as text. PUSH_CONFIG_CREATE needs a TaskPushNotificationConfig, and the other operations read headers, not the body" }, + "producerOut": { "carriers": [ "text" ], "byOption": [ { "option": "operation", "value": "MESSAGE_STREAM", "carriers": [ "iterator" ], "javaType": "org.apache.camel.component.a2a.streaming.SseEventIterator" }, { "option": "operation", "value": "TASK_GET", "carriers": [ "text" ] }, { "option": "operation", "value": "TASK_LIST", "carriers": [ "list", "null" ] }, { "option": "operation", "value": "TASK_CANCEL", "carriers": [ "text" ] }, { "option": "operation", "value": "TASK_SUBSCRIBE", "carriers": [ "iterator" ], "javaType": "org.apache.camel.component.a2a.streaming.SseEventIterator" }, { "option": "operation", "value": "PUSH_CONFIG_CREATE", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.a2a.model.TaskPushNotificationConfig" }, { "option": "operation", "value": "PUSH_CONFIG_GET", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.a2a.model.TaskPushNotificationConfig" }, { "option": "operation", "value": "PUSH_CONFIG_LIST", "carriers": [ "list", "null" ] }, { "option": "operation", "value": "PUSH_CONFIG_DELETE", "carriers": [ "map" ] }, { "option": "dataFormat", "value": "POJO", "carriers": [ "pojo" ] }, { "option": "dataFormat", "value": "RAW", "carriers": [ "text" ] } ], "description": "The reply of the agent as text: the parts of the Message, or of the last message in the history of the Task, one per line. TASK_GET and TASK_CANCEL give the text of the Task, TASK_LIST a List of Task, MESSAGE_STREAM and TASK_SUBSCRIBE an Iterator of the events as they arrive (split it), and the push config operations a TaskPushNotificationConfig, a List of them, or an empty Map for delete. With dataFormat POJO the Task or the Message, with RAW the JSON of the response as text (a stream of the events for MESSAGE_STREAM and TASK_SUBSCRIBE)" } + }, "properties": { "agentCardSource": { "index": 0, "kind": "path", "displayName": "Agent Card Source", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The agent card source (classpath:, file:, http:\/\/, https:\/\/, or plain name)" }, "agentCard": { "index": 1, "kind": "parameter", "displayName": "Agent Card", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.a2a.model.AgentCard", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.a2a.A2AConfiguration", "configurationField": "configuration", "description": "Agent card bean reference or inline configuration" }, diff --git a/components/camel-ai/camel-a2a/src/main/java/org/apache/camel/component/a2a/A2AEndpoint.java b/components/camel-ai/camel-a2a/src/main/java/org/apache/camel/component/a2a/A2AEndpoint.java index c9868f484217c..0f3a5649244da 100644 --- a/components/camel-ai/camel-a2a/src/main/java/org/apache/camel/component/a2a/A2AEndpoint.java +++ b/components/camel-ai/camel-a2a/src/main/java/org/apache/camel/component/a2a/A2AEndpoint.java @@ -47,6 +47,9 @@ import org.apache.camel.component.a2a.state.A2ATaskStore; import org.apache.camel.component.a2a.state.GuardedTaskStore; import org.apache.camel.component.a2a.state.InMemoryTaskStore; +import org.apache.camel.spi.BodyType; +import org.apache.camel.spi.BodyType.Carrier; +import org.apache.camel.spi.BodyTypes; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; @@ -70,6 +73,75 @@ syntax = "a2a:agentCardSource", category = { Category.AI }, headersClass = A2AConstants.class) +@BodyTypes(consumerOut = @BodyType(value = Carrier.TEXT, + byOption = @BodyType.When(option = "dataFormat", value = "POJO", carriers = Carrier.POJO, + javaType = "org.apache.camel.component.a2a.model.Message"), + description = "The message of the caller, for SendMessage and SendStreamingMessage (the" + + " component answers the task and push config requests itself): the text" + + " of its parts, one per line, a data part as JSON and a file part as its" + + " URL. With dataFormat POJO the Message, with RAW the Message as JSON"), + consumerReply = @BodyType(value = { Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE, Carrier.POJO }, + description = "The reply of the agent: text, sent as one text part (bytes, a stream or a" + + " file as their text), or a Message sent as it is. Another body is sent" + + " as text: a Task as the text of its last message, a Map or a POJO as its" + + " toString(): marshal it first. The reply goes in a Task, completed" + + " unless the CamelA2ATaskState header says another state, or as a Message" + + " when the CamelA2AResponseType header is message"), + producerIn = @BodyType(value = { Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE, Carrier.POJO }, + byOption = { + @BodyType.When(option = "operation", value = "TASK_GET", carriers = Carrier.ANY), + @BodyType.When(option = "operation", value = "TASK_LIST", carriers = Carrier.ANY), + @BodyType.When(option = "operation", value = "TASK_CANCEL", carriers = Carrier.ANY), + @BodyType.When(option = "operation", value = "TASK_SUBSCRIBE", + carriers = Carrier.ANY), + @BodyType.When(option = "operation", value = "PUSH_CONFIG_CREATE", + carriers = Carrier.POJO, + javaType = "org.apache.camel.component.a2a.model.TaskPushNotificationConfig"), + @BodyType.When(option = "operation", value = "PUSH_CONFIG_GET", + carriers = Carrier.ANY), + @BodyType.When(option = "operation", value = "PUSH_CONFIG_LIST", + carriers = Carrier.ANY), + @BodyType.When(option = "operation", value = "PUSH_CONFIG_DELETE", + carriers = Carrier.ANY) }, + description = "The message to send: text, sent as one text part (bytes, a stream or a" + + " file as their text), or a Message sent as it is; MESSAGE_STREAM also" + + " takes a SendMessageRequest. Another body is sent as its toString(), so a" + + " Map or a POJO needs marshalling first, and JSON text is sent as text." + + " PUSH_CONFIG_CREATE needs a TaskPushNotificationConfig, and the other" + + " operations read headers, not the body"), + producerOut = @BodyType(value = Carrier.TEXT, + byOption = { + @BodyType.When(option = "operation", value = "MESSAGE_STREAM", + carriers = Carrier.ITERATOR, + javaType = "org.apache.camel.component.a2a.streaming.SseEventIterator"), + @BodyType.When(option = "operation", value = "TASK_GET", carriers = Carrier.TEXT), + @BodyType.When(option = "operation", value = "TASK_LIST", + carriers = { Carrier.LIST, Carrier.NULL }), + @BodyType.When(option = "operation", value = "TASK_CANCEL", carriers = Carrier.TEXT), + @BodyType.When(option = "operation", value = "TASK_SUBSCRIBE", + carriers = Carrier.ITERATOR, + javaType = "org.apache.camel.component.a2a.streaming.SseEventIterator"), + @BodyType.When(option = "operation", value = "PUSH_CONFIG_CREATE", + carriers = Carrier.POJO, + javaType = "org.apache.camel.component.a2a.model.TaskPushNotificationConfig"), + @BodyType.When(option = "operation", value = "PUSH_CONFIG_GET", + carriers = Carrier.POJO, + javaType = "org.apache.camel.component.a2a.model.TaskPushNotificationConfig"), + @BodyType.When(option = "operation", value = "PUSH_CONFIG_LIST", + carriers = { Carrier.LIST, Carrier.NULL }), + @BodyType.When(option = "operation", value = "PUSH_CONFIG_DELETE", + carriers = Carrier.MAP), + @BodyType.When(option = "dataFormat", value = "POJO", carriers = Carrier.POJO), + @BodyType.When(option = "dataFormat", value = "RAW", carriers = Carrier.TEXT) }, + description = "The reply of the agent as text: the parts of the Message, or of the last" + + " message in the history of the Task, one per line. TASK_GET and" + + " TASK_CANCEL give the text of the Task, TASK_LIST a List of Task," + + " MESSAGE_STREAM and TASK_SUBSCRIBE an Iterator of the events as they" + + " arrive (split it), and the push config operations a" + + " TaskPushNotificationConfig, a List of them, or an empty Map for delete." + + " With dataFormat POJO the Task or the Message, with RAW the JSON of the" + + " response as text (a stream of the events for MESSAGE_STREAM and" + + " TASK_SUBSCRIBE)")) public class A2AEndpoint extends DefaultEndpoint { private static final Logger LOG = LoggerFactory.getLogger(A2AEndpoint.class); diff --git a/components/camel-ai/camel-ai-tool/src/generated/resources/META-INF/org/apache/camel/component/ai/tool/ai-tool.json b/components/camel-ai/camel-ai-tool/src/generated/resources/META-INF/org/apache/camel/component/ai/tool/ai-tool.json index 0ce16172cd96e..deed749b292a1 100644 --- a/components/camel-ai/camel-ai-tool/src/generated/resources/META-INF/org/apache/camel/component/ai/tool/ai-tool.json +++ b/components/camel-ai/camel-ai-tool/src/generated/resources/META-INF/org/apache/camel/component/ai/tool/ai-tool.json @@ -46,6 +46,10 @@ "CamelAiToolCallId": { "index": 0, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The tool invocation identifier supplied by the calling framework. Absent when the framework does not supply one.", "constantName": "org.apache.camel.component.ai.tool.AiToolConstants#TOOL_CALL_ID" }, "CamelAiToolConversationId": { "index": 1, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The conversation identifier supplied by the calling framework. Absent when the framework does not supply one.", "constantName": "org.apache.camel.component.ai.tool.AiToolConstants#CONVERSATION_ID" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "null" ], "description": "No body: each argument of the tool call is a header named as its parameter, a Map or a List for a nested JSON value. Undeclared arguments and names starting with camel are dropped" }, + "consumerReply": { "carriers": [ "any" ], "dependsOn": [ "outputSchema", "outputParameters" ], "description": "The tool result, as text: the body converted to a String, so a Map, a List or a POJO is sent as its toString(): marshal it to JSON first. No body gives No result. With outputSchema or outputParameter.NAME options the body must be JSON: a JSON String, a Map, a List, a number or a boolean, and bytes, a stream or another object fail the call" } + }, "properties": { "toolName": { "index": 0, "kind": "path", "displayName": "Tool Name", "group": "consumer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The tool name. This is the name the LLM sees and uses to invoke the tool." }, "argSchema": { "index": 1, "kind": "parameter", "displayName": "Arg Schema", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "supportFileReference": true, "configurationClass": "org.apache.camel.component.ai.tool.AiToolConfiguration", "configurationField": "configuration", "description": "Raw JSON Schema for tool input parameters. Supports inline JSON and resource references (classpath:, file:, resource:). Mutually exclusive with the parameter multi-value options. Use for nested objects, arrays, oneOf, and other complex schemas." }, diff --git a/components/camel-ai/camel-ai-tool/src/main/java/org/apache/camel/component/ai/tool/AiToolEndpoint.java b/components/camel-ai/camel-ai-tool/src/main/java/org/apache/camel/component/ai/tool/AiToolEndpoint.java index c6edab87148ff..f85439260633d 100644 --- a/components/camel-ai/camel-ai-tool/src/main/java/org/apache/camel/component/ai/tool/AiToolEndpoint.java +++ b/components/camel-ai/camel-ai-tool/src/main/java/org/apache/camel/component/ai/tool/AiToolEndpoint.java @@ -20,6 +20,9 @@ import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; +import org.apache.camel.spi.BodyType; +import org.apache.camel.spi.BodyType.Carrier; +import org.apache.camel.spi.BodyTypes; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; @@ -43,6 +46,16 @@ remote = false, headersClass = AiToolConstants.class, category = { Category.AI }) +@BodyTypes(consumerOut = @BodyType(value = Carrier.NULL, + description = "No body: each argument of the tool call is a header named as its" + + " parameter, a Map or a List for a nested JSON value. Undeclared" + + " arguments and names starting with camel are dropped"), + consumerReply = @BodyType(value = Carrier.ANY, dependsOn = { "outputSchema", "outputParameters" }, + description = "The tool result, as text: the body converted to a String, so a Map, a" + + " List or a POJO is sent as its toString(): marshal it to JSON first. No" + + " body gives No result. With outputSchema or outputParameter.NAME" + + " options the body must be JSON: a JSON String, a Map, a List, a number" + + " or a boolean, and bytes, a stream or another object fail the call")) public class AiToolEndpoint extends DefaultEndpoint { @Metadata(required = true) diff --git a/components/camel-ai/camel-docling/src/generated/resources/META-INF/org/apache/camel/component/docling/docling.json b/components/camel-ai/camel-docling/src/generated/resources/META-INF/org/apache/camel/component/docling/docling.json index 2929f7f681345..426611f97d2fd 100644 --- a/components/camel-ai/camel-docling/src/generated/resources/META-INF/org/apache/camel/component/docling/docling.json +++ b/components/camel-ai/camel-docling/src/generated/resources/META-INF/org/apache/camel/component/docling/docling.json @@ -117,6 +117,11 @@ "CamelDoclingChunkingMaxTokens": { "index": 30, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Maximum tokens per chunk for hybrid chunking", "constantName": "org.apache.camel.component.docling.DoclingHeaders#CHUNKING_MAX_TOKENS" }, "CamelDoclingChunkingMergePeers": { "index": 31, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Whether to merge peer chunks in hybrid chunking", "constantName": "org.apache.camel.component.docling.DoclingHeaders#CHUNKING_MERGE_PEERS" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "text" ], "description": "The document of an async conversion that completed (SUBMIT_ASYNC_CONVERSION on the same component), as text in the outputFormat it was submitted with: markdown by default, JSON text for json. The task id is in the CamelDoclingTaskId header, and a failed conversion goes to the error handler" }, + "producerIn": { "carriers": [ "any" ], "byOption": [ { "option": "operation", "value": "BATCH_CONVERT_TO_MARKDOWN", "carriers": [ "list" ] }, { "option": "operation", "value": "BATCH_CONVERT_TO_HTML", "carriers": [ "list" ] }, { "option": "operation", "value": "BATCH_CONVERT_TO_JSON", "carriers": [ "list" ] }, { "option": "operation", "value": "BATCH_EXTRACT_TEXT", "carriers": [ "list" ] }, { "option": "operation", "value": "BATCH_EXTRACT_STRUCTURED_DATA", "carriers": [ "list" ] } ], "description": "The document: its content as text or bytes, or a File (the GenericFile of the file consumers too). A stream or a Path fails: convert it to bytes first. Text that looks like a URL or a path (it starts with http:\/\/, https:\/\/ or \/, or has a backslash) is read as one only with allowUrlSource or allowFilePathSource, and fails otherwise. With the CamelDoclingInputFilePath header the body is not read. The batch operations take a List or an array of paths or files (a directory path with allowFilePathSource), and CHECK_CONVERSION_STATUS the task id, unless the CamelDoclingTaskId header gives it" }, + "producerOut": { "carriers": [ "text" ], "byOption": [ { "option": "operation", "value": "CONVERT_TO_JSON", "carriers": [ "pojo" ], "javaType": "ai.docling.core.DoclingDocument" }, { "option": "operation", "value": "EXTRACT_STRUCTURED_DATA", "carriers": [ "pojo" ], "javaType": "ai.docling.core.DoclingDocument" }, { "option": "operation", "value": "CHECK_CONVERSION_STATUS", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.docling.ConversionStatus" }, { "option": "operation", "value": "EXTRACT_METADATA", "carriers": [ "pojo" ], "javaType": "org.apache.camel.component.docling.DocumentMetadata" }, { "option": "operation", "value": "BATCH_CONVERT_TO_MARKDOWN", "carriers": [ "pojo", "list" ] }, { "option": "operation", "value": "BATCH_CONVERT_TO_HTML", "carriers": [ "pojo", "list" ] }, { "option": "operation", "value": "BATCH_CONVERT_TO_JSON", "carriers": [ "pojo", "list" ] }, { "option": "operation", "value": "BATCH_EXTRACT_TEXT", "carriers": [ "pojo", "list" ] }, { "option": "operation", "value": "BATCH_EXTRACT_STRUCTURED_DATA", "carriers": [ "pojo", "list" ] }, { "option": "operation", "value": "CHUNK_HYBRID", "carriers": [ "pojo", "list" ] }, { "option": "operation", "value": "CHUNK_HIERARCHICAL", "carriers": [ "pojo", "list" ] } ], "description": "By the operation: text for the conversions to markdown, HTML and text, which with the docling CLI is the path of the output file unless contentInBody (useDoclingServe gives the content); the task id for SUBMIT_ASYNC_CONVERSION; a DoclingDocument for CONVERT_TO_JSON and EXTRACT_STRUCTURED_DATA; a BatchProcessingResults for the batch operations, a List of BatchConversionResult with splitBatchResults; and a ChunkDocumentResponse for the chunking, a List of Chunk with contentInBody" } + }, "properties": { "operationId": { "index": 0, "kind": "path", "displayName": "Operation Id", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation identifier" }, "contentInBody": { "index": 1, "kind": "parameter", "displayName": "Content In Body", "group": "common", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.docling.DoclingConfiguration", "configurationField": "configuration", "description": "Include the content of the output file in the exchange body and delete the output file" }, diff --git a/components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingEndpoint.java b/components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingEndpoint.java index d7e152bfa55f3..35fbad76dff3e 100644 --- a/components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingEndpoint.java +++ b/components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingEndpoint.java @@ -20,6 +20,9 @@ import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; +import org.apache.camel.spi.BodyType; +import org.apache.camel.spi.BodyType.Carrier; +import org.apache.camel.spi.BodyTypes; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; @@ -33,6 +36,69 @@ title = "Docling", syntax = "docling:operationId", category = { Category.TRANSFORMATION, Category.AI }, headersClass = DoclingHeaders.class) +@BodyTypes(consumerOut = @BodyType(value = Carrier.TEXT, + description = "The document of an async conversion that completed" + + " (SUBMIT_ASYNC_CONVERSION on the same component), as text in the" + + " outputFormat it was submitted with: markdown by default, JSON text for" + + " json. The task id is in the CamelDoclingTaskId header, and a failed" + + " conversion goes to the error handler"), + producerIn = @BodyType(value = Carrier.ANY, + byOption = { + @BodyType.When(option = "operation", value = "BATCH_CONVERT_TO_MARKDOWN", + carriers = Carrier.LIST), + @BodyType.When(option = "operation", value = "BATCH_CONVERT_TO_HTML", + carriers = Carrier.LIST), + @BodyType.When(option = "operation", value = "BATCH_CONVERT_TO_JSON", + carriers = Carrier.LIST), + @BodyType.When(option = "operation", value = "BATCH_EXTRACT_TEXT", + carriers = Carrier.LIST), + @BodyType.When(option = "operation", value = "BATCH_EXTRACT_STRUCTURED_DATA", + carriers = Carrier.LIST) }, + description = "The document: its content as text or bytes, or a File (the GenericFile of" + + " the file consumers too). A stream or a Path fails: convert it to bytes" + + " first. Text that looks like a URL or a path (it starts with http://," + + " https:// or /, or has a backslash) is read as one only with" + + " allowUrlSource or allowFilePathSource, and fails otherwise. With the" + + " CamelDoclingInputFilePath header the body is not read. The batch" + + " operations take a List or an array of paths or files (a directory path" + + " with allowFilePathSource), and CHECK_CONVERSION_STATUS the task id, unless" + + " the CamelDoclingTaskId header gives it"), + producerOut = @BodyType(value = Carrier.TEXT, + byOption = { + @BodyType.When(option = "operation", value = "CONVERT_TO_JSON", + carriers = Carrier.POJO, + javaType = "ai.docling.core.DoclingDocument"), + @BodyType.When(option = "operation", value = "EXTRACT_STRUCTURED_DATA", + carriers = Carrier.POJO, + javaType = "ai.docling.core.DoclingDocument"), + @BodyType.When(option = "operation", value = "CHECK_CONVERSION_STATUS", + carriers = Carrier.POJO, + javaType = "org.apache.camel.component.docling.ConversionStatus"), + @BodyType.When(option = "operation", value = "EXTRACT_METADATA", + carriers = Carrier.POJO, + javaType = "org.apache.camel.component.docling.DocumentMetadata"), + @BodyType.When(option = "operation", value = "BATCH_CONVERT_TO_MARKDOWN", + carriers = { Carrier.POJO, Carrier.LIST }), + @BodyType.When(option = "operation", value = "BATCH_CONVERT_TO_HTML", + carriers = { Carrier.POJO, Carrier.LIST }), + @BodyType.When(option = "operation", value = "BATCH_CONVERT_TO_JSON", + carriers = { Carrier.POJO, Carrier.LIST }), + @BodyType.When(option = "operation", value = "BATCH_EXTRACT_TEXT", + carriers = { Carrier.POJO, Carrier.LIST }), + @BodyType.When(option = "operation", value = "BATCH_EXTRACT_STRUCTURED_DATA", + carriers = { Carrier.POJO, Carrier.LIST }), + @BodyType.When(option = "operation", value = "CHUNK_HYBRID", + carriers = { Carrier.POJO, Carrier.LIST }), + @BodyType.When(option = "operation", value = "CHUNK_HIERARCHICAL", + carriers = { Carrier.POJO, Carrier.LIST }) }, + description = "By the operation: text for the conversions to markdown, HTML and text," + + " which with the docling CLI is the path of the output file unless" + + " contentInBody (useDoclingServe gives the content); the task id for" + + " SUBMIT_ASYNC_CONVERSION; a DoclingDocument for CONVERT_TO_JSON and" + + " EXTRACT_STRUCTURED_DATA; a BatchProcessingResults for the batch" + + " operations, a List of BatchConversionResult with splitBatchResults; and a" + + " ChunkDocumentResponse for the chunking, a List of Chunk with" + + " contentInBody")) public class DoclingEndpoint extends ScheduledPollEndpoint { @Metadata(required = true) diff --git a/components/camel-ai/camel-langchain4j-chat/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/chat/langchain4j-chat.json b/components/camel-ai/camel-langchain4j-chat/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/chat/langchain4j-chat.json index 951f48a17cf57..f1aedc286dafc 100644 --- a/components/camel-ai/camel-langchain4j-chat/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/chat/langchain4j-chat.json +++ b/components/camel-ai/camel-langchain4j-chat/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/chat/langchain4j-chat.json @@ -48,6 +48,10 @@ "CamelLangChain4jChatRequestModel": { "index": 6, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The request model name.", "constantName": "org.apache.camel.component.langchain4j.chat.LangChain4jChatHeaders#REQUEST_MODEL" }, "CamelLangChain4jChatResponseModel": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The response model name.", "constantName": "org.apache.camel.component.langchain4j.chat.LangChain4jChatHeaders#RESPONSE_MODEL" } }, + "bodyTypes": { + "producerIn": { "carriers": [ "any" ], "byOption": [ { "option": "chatOperation", "value": "CHAT_SINGLE_MESSAGE_WITH_PROMPT", "carriers": [ "map" ] }, { "option": "chatOperation", "value": "CHAT_MULTIPLE_MESSAGES", "carriers": [ "list" ] } ], "description": "The prompt as text, or a ChatMessage; another body is sent as its toString(), and no body fails. CHAT_SINGLE_MESSAGE_WITH_PROMPT takes the variables of the template in the CamelLangChain4jChatPromptTemplate header as a Map, and CHAT_MULTIPLE_MESSAGES a List of ChatMessage" }, + "producerOut": { "carriers": [ "text" ], "description": "The answer of the model as text, also when it is asked for JSON: unmarshal it to read its fields" } + }, "properties": { "chatId": { "index": 0, "kind": "path", "displayName": "Chat Id", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The id" }, "chatOperation": { "index": 1, "kind": "parameter", "displayName": "Chat Operation", "group": "producer", "label": "", "required": true, "type": "enum", "javaType": "org.apache.camel.component.langchain4j.chat.LangChain4jChatOperations", "enum": [ "CHAT_SINGLE_MESSAGE", "CHAT_SINGLE_MESSAGE_WITH_PROMPT", "CHAT_MULTIPLE_MESSAGES" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "CHAT_SINGLE_MESSAGE", "configurationClass": "org.apache.camel.component.langchain4j.chat.LangChain4jChatConfiguration", "configurationField": "configuration", "description": "Operation in case of Endpoint of type CHAT. The value is one of the values of org.apache.camel.component.langchain4j.chat.LangChain4jChatOperations" }, diff --git a/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatEndpoint.java b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatEndpoint.java index d333487bb13ea..e70f27fa5e799 100644 --- a/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatEndpoint.java +++ b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatEndpoint.java @@ -20,6 +20,9 @@ import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; +import org.apache.camel.spi.BodyType; +import org.apache.camel.spi.BodyType.Carrier; +import org.apache.camel.spi.BodyTypes; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; @@ -33,6 +36,19 @@ syntax = "langchain4j-chat:chatId", producerOnly = true, category = { Category.AI }, headersClass = LangChain4jChatHeaders.class) +@BodyTypes(producerIn = @BodyType(value = Carrier.ANY, + byOption = { + @BodyType.When(option = "chatOperation", value = "CHAT_SINGLE_MESSAGE_WITH_PROMPT", + carriers = Carrier.MAP), + @BodyType.When(option = "chatOperation", value = "CHAT_MULTIPLE_MESSAGES", + carriers = Carrier.LIST) }, + description = "The prompt as text, or a ChatMessage; another body is sent as its" + + " toString(), and no body fails. CHAT_SINGLE_MESSAGE_WITH_PROMPT takes the" + + " variables of the template in the CamelLangChain4jChatPromptTemplate" + + " header as a Map, and CHAT_MULTIPLE_MESSAGES a List of ChatMessage"), + producerOut = @BodyType(value = Carrier.TEXT, + description = "The answer of the model as text, also when it is asked for JSON: unmarshal" + + " it to read its fields")) public class LangChain4jChatEndpoint extends DefaultEndpoint { @Metadata(required = true) diff --git a/components/camel-ai/camel-milvus/src/generated/resources/META-INF/org/apache/camel/component/milvus/milvus.json b/components/camel-ai/camel-milvus/src/generated/resources/META-INF/org/apache/camel/component/milvus/milvus.json index 401fd632d4ccb..c2c82cb38cd3e 100644 --- a/components/camel-ai/camel-milvus/src/generated/resources/META-INF/org/apache/camel/component/milvus/milvus.json +++ b/components/camel-ai/camel-milvus/src/generated/resources/META-INF/org/apache/camel/component/milvus/milvus.json @@ -42,6 +42,10 @@ "CamelMilvusKeyName": { "index": 6, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Key Name for Insert\/Upsert operation", "constantName": "org.apache.camel.component.milvus.MilvusHeaders#KEY_NAME" }, "CamelMilvusKeyValue": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Key Value for Insert\/Upsert operation", "constantName": "org.apache.camel.component.milvus.MilvusHeaders#KEY_VALUE" } }, + "bodyTypes": { + "producerIn": { "carriers": [ "pojo" ], "description": "The request of the Milvus SDK for the action in the CamelMilvusAction header: a CreateCollectionParam, CreateIndexParam, InsertParam, UpsertParam, SearchSimpleParam, QueryParam or DeleteParam. Another body fails, a vector as a List too: the milvus:embeddings data type transformer builds the InsertParam or UpsertParam from the output of langchain4j-embeddings" }, + "producerOut": { "carriers": [ "pojo" ], "description": "The result of the Milvus SDK for the action: an RpcStatus for CREATE_COLLECTION and CREATE_INDEX, a MutationResult for INSERT, UPSERT and DELETE, a SearchResponse for SEARCH and a QueryResults for QUERY" } + }, "properties": { "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection Name" }, "host": { "index": 1, "kind": "parameter", "displayName": "Host", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "localhost", "configurationClass": "org.apache.camel.component.milvus.MilvusConfiguration", "configurationField": "configuration", "description": "The host to connect to." }, diff --git a/components/camel-ai/camel-milvus/src/main/java/org/apache/camel/component/milvus/MilvusEndpoint.java b/components/camel-ai/camel-milvus/src/main/java/org/apache/camel/component/milvus/MilvusEndpoint.java index c803a3b4bfdcb..bc647b2b11ea0 100644 --- a/components/camel-ai/camel-milvus/src/main/java/org/apache/camel/component/milvus/MilvusEndpoint.java +++ b/components/camel-ai/camel-milvus/src/main/java/org/apache/camel/component/milvus/MilvusEndpoint.java @@ -26,6 +26,9 @@ import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; +import org.apache.camel.spi.BodyType; +import org.apache.camel.spi.BodyType.Carrier; +import org.apache.camel.spi.BodyTypes; import org.apache.camel.spi.EndpointServiceLocation; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriEndpoint; @@ -47,6 +50,17 @@ Category.AI }, headersClass = MilvusHeaders.class) +@BodyTypes(producerIn = @BodyType(value = Carrier.POJO, + description = "The request of the Milvus SDK for the action in the CamelMilvusAction" + + " header: a CreateCollectionParam, CreateIndexParam, InsertParam," + + " UpsertParam, SearchSimpleParam, QueryParam or DeleteParam. Another body" + + " fails, a vector as a List too: the milvus:embeddings data type" + + " transformer builds the InsertParam or UpsertParam from the output of" + + " langchain4j-embeddings"), + producerOut = @BodyType(value = Carrier.POJO, + description = "The result of the Milvus SDK for the action: an RpcStatus for" + + " CREATE_COLLECTION and CREATE_INDEX, a MutationResult for INSERT, UPSERT" + + " and DELETE, a SearchResponse for SEARCH and a QueryResults for QUERY")) public class MilvusEndpoint extends DefaultEndpoint implements EndpointServiceLocation { @Metadata(required = true) 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 a2451cbd1b69b..6870d839b3a6f 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 @@ -146,6 +146,12 @@ "CamelOpenAIImageOutputTokens": { "index": 107, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The number of output tokens billed for the image request. Only reported by GPT image models", "constantName": "org.apache.camel.component.openai.OpenAIConstants#IMAGE_OUTPUT_TOKENS" }, "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" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "pojo" ], "javaType": "com.openai.models.webhooks.UnwrapWebhookEvent", "description": "The event of the webhook operation, verified with webhookSecret, such as a batch or a background response that completed. The event type and the id of the object it is about are in headers" }, + "consumerReply": { "carriers": [ "any" ], "description": "The body at the end of the route is not sent: OpenAI gets 200 without a body, or 500 when the route fails, and then sends the event again" }, + "producerIn": { "carriers": [ "any" ], "byOption": [ { "option": "operation", "value": "decisions", "carriers": [ "pojo" ], "javaType": "com.openai.models.decisions.DecisionCreateParams" }, { "option": "operation", "value": "batch", "carriers": [ "map", "list", "text", "bytes", "stream", "file" ] }, { "option": "operation", "value": "audio-transcription", "carriers": [ "file", "bytes", "stream" ] }, { "option": "operation", "value": "audio-translation", "carriers": [ "file", "bytes", "stream" ] }, { "option": "operation", "value": "image-edit", "carriers": [ "file", "bytes", "stream", "list" ] } ], "description": "The prompt of chat-completion and responses: text, or a file, bytes or a stream with an image or a PDF (chat-completion also audio), which userMessage then describes. Another body is sent as its toString(), and userMessage or the CamelOpenAIUserMessage header replaces a text body. embeddings and moderation take text or a List of texts (moderation also an image), audio-speech the text to speak, and image-generation the prompt unless imagePrompt is set. batch takes the requests as a Map keyed by custom_id, a List, or JSONL; audio takes the audio and image-edit the image, or a List of images. The operations that read a stored response, a batch or the tool calls of the last answer do not use the body" }, + "producerOut": { "carriers": [ "text" ], "byOption": [ { "option": "streaming", "value": "true", "carriers": [ "iterator" ] }, { "option": "autoToolExecution", "value": "false", "carriers": [ "text", "pojo", "list" ] }, { "option": "operation", "value": "decisions", "carriers": [ "pojo" ], "javaType": "com.openai.models.decisions.Decision" }, { "option": "operation", "value": "responses", "carriers": [ "text" ] }, { "option": "operation", "value": "responses-retrieve", "carriers": [ "text" ] }, { "option": "operation", "value": "responses-cancel", "carriers": [ "text" ] }, { "option": "operation", "value": "batch", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "batch-retrieve", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "batch-cancel", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "batch-results", "carriers": [ "iterator" ] }, { "option": "operation", "value": "embeddings", "carriers": [ "list" ] }, { "option": "operation", "value": "tool-execution", "carriers": [ "null", "unchanged" ] }, { "option": "operation", "value": "audio-transcription", "carriers": [ "text" ] }, { "option": "operation", "value": "audio-translation", "carriers": [ "text" ] }, { "option": "operation", "value": "audio-speech", "carriers": [ "bytes" ], "javaType": "byte[]" }, { "option": "operation", "value": "moderation", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "image-generation", "carriers": [ "bytes", "text", "list" ] }, { "option": "operation", "value": "image-edit", "carriers": [ "bytes", "text", "list" ] } ], "description": "The answer of chat-completion as text, also with outputClass or jsonSchema, where it is JSON text: unmarshal it to read its fields. With streaming, an Iterator of the chunks (text when MCP tools run in a loop). With autoToolExecution=false, the tool calls the model asks for: an Optional of the List of tool calls, or a List of the function calls for responses. embeddings gives a vector (a List of Float), or a List of vectors for a List of texts; image-generation and image-edit the image as bytes or its URL as text, a List for several; batch-results an Iterator of the result lines as Maps. batch and moderation keep the body and set headers, and tool-execution clears it when it runs tool calls" } + }, "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", "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" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "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', 'image-edit', or 'webhook' (a consumer)" }, "additionalBodyProperty": { "index": 1, "kind": "parameter", "displayName": "Additional Body Property", "group": "common", "label": "", "required": false, "type": "object", "javaType": "java.util.Map", "prefix": "additionalBodyProperty.", "multiValue": true, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Additional JSON properties to include in the request body (e.g. additionalBodyProperty.traceId=123). This is a multi-value option with prefix: additionalBodyProperty." }, 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 d212b19e520cd..4d569fa9d9439 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 @@ -146,6 +146,12 @@ "CamelOpenAIImageOutputTokens": { "index": 107, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The number of output tokens billed for the image request. Only reported by GPT image models", "constantName": "org.apache.camel.component.openai.OpenAIConstants#IMAGE_OUTPUT_TOKENS" }, "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" } }, + "bodyTypes": { + "consumerOut": { "carriers": [ "pojo" ], "javaType": "com.openai.models.webhooks.UnwrapWebhookEvent", "description": "The event of the webhook operation, verified with webhookSecret, such as a batch or a background response that completed. The event type and the id of the object it is about are in headers" }, + "consumerReply": { "carriers": [ "any" ], "description": "The body at the end of the route is not sent: OpenAI gets 200 without a body, or 500 when the route fails, and then sends the event again" }, + "producerIn": { "carriers": [ "any" ], "byOption": [ { "option": "operation", "value": "decisions", "carriers": [ "pojo" ], "javaType": "com.openai.models.decisions.DecisionCreateParams" }, { "option": "operation", "value": "batch", "carriers": [ "map", "list", "text", "bytes", "stream", "file" ] }, { "option": "operation", "value": "audio-transcription", "carriers": [ "file", "bytes", "stream" ] }, { "option": "operation", "value": "audio-translation", "carriers": [ "file", "bytes", "stream" ] }, { "option": "operation", "value": "image-edit", "carriers": [ "file", "bytes", "stream", "list" ] } ], "description": "The prompt of chat-completion and responses: text, or a file, bytes or a stream with an image or a PDF (chat-completion also audio), which userMessage then describes. Another body is sent as its toString(), and userMessage or the CamelOpenAIUserMessage header replaces a text body. embeddings and moderation take text or a List of texts (moderation also an image), audio-speech the text to speak, and image-generation the prompt unless imagePrompt is set. batch takes the requests as a Map keyed by custom_id, a List, or JSONL; audio takes the audio and image-edit the image, or a List of images. The operations that read a stored response, a batch or the tool calls of the last answer do not use the body" }, + "producerOut": { "carriers": [ "text" ], "byOption": [ { "option": "streaming", "value": "true", "carriers": [ "iterator" ] }, { "option": "autoToolExecution", "value": "false", "carriers": [ "text", "pojo", "list" ] }, { "option": "operation", "value": "decisions", "carriers": [ "pojo" ], "javaType": "com.openai.models.decisions.Decision" }, { "option": "operation", "value": "responses", "carriers": [ "text" ] }, { "option": "operation", "value": "responses-retrieve", "carriers": [ "text" ] }, { "option": "operation", "value": "responses-cancel", "carriers": [ "text" ] }, { "option": "operation", "value": "batch", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "batch-retrieve", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "batch-cancel", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "batch-results", "carriers": [ "iterator" ] }, { "option": "operation", "value": "embeddings", "carriers": [ "list" ] }, { "option": "operation", "value": "tool-execution", "carriers": [ "null", "unchanged" ] }, { "option": "operation", "value": "audio-transcription", "carriers": [ "text" ] }, { "option": "operation", "value": "audio-translation", "carriers": [ "text" ] }, { "option": "operation", "value": "audio-speech", "carriers": [ "bytes" ], "javaType": "byte[]" }, { "option": "operation", "value": "moderation", "carriers": [ "unchanged" ] }, { "option": "operation", "value": "image-generation", "carriers": [ "bytes", "text", "list" ] }, { "option": "operation", "value": "image-edit", "carriers": [ "bytes", "text", "list" ] } ], "description": "The answer of chat-completion as text, also with outputClass or jsonSchema, where it is JSON text: unmarshal it to read its fields. With streaming, an Iterator of the chunks (text when MCP tools run in a loop). With autoToolExecution=false, the tool calls the model asks for: an Optional of the List of tool calls, or a List of the function calls for responses. embeddings gives a vector (a List of Float), or a List of vectors for a List of texts; image-generation and image-edit the image as bytes or its URL as text, a List for several; batch-results an Iterator of the result lines as Maps. batch and moderation keep the body and set headers, and tool-execution clears it when it runs tool calls" } + }, "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", "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" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "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', 'image-edit', or 'webhook' (a consumer)" }, "additionalBodyProperty": { "index": 1, "kind": "parameter", "displayName": "Additional Body Property", "group": "common", "label": "", "required": false, "type": "object", "javaType": "java.util.Map", "prefix": "additionalBodyProperty.", "multiValue": true, "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Additional JSON properties to include in the request body (e.g. additionalBodyProperty.traceId=123). This is a multi-value option with prefix: additionalBodyProperty." }, 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 1b65e239cb5be..4fbad0d31b780 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 @@ -63,6 +63,9 @@ import org.apache.camel.component.ai.tool.AiToolRegistry; import org.apache.camel.component.ai.tool.AiToolRegistryListener; import org.apache.camel.component.ai.tool.AiToolSpec; +import org.apache.camel.spi.BodyType; +import org.apache.camel.spi.BodyType.Carrier; +import org.apache.camel.spi.BodyTypes; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; @@ -85,6 +88,86 @@ syntax = "openai:operation", category = { Category.AI }, headersClass = OpenAIConstants.class) +@BodyTypes(consumerOut = @BodyType(value = Carrier.POJO, javaType = "com.openai.models.webhooks.UnwrapWebhookEvent", + description = "The event of the webhook operation, verified with webhookSecret, such as" + + " a batch or a background response that completed. The event type and" + + " the id of the object it is about are in headers"), + consumerReply = @BodyType(value = Carrier.ANY, + description = "The body at the end of the route is not sent: OpenAI gets 200 without a" + + " body, or 500 when the route fails, and then sends the event again"), + producerIn = @BodyType(value = Carrier.ANY, + byOption = { + @BodyType.When(option = "operation", value = "decisions", carriers = Carrier.POJO, + javaType = "com.openai.models.decisions.DecisionCreateParams"), + @BodyType.When(option = "operation", value = "batch", + carriers = { + Carrier.MAP, Carrier.LIST, Carrier.TEXT, Carrier.BYTES, + Carrier.STREAM, Carrier.FILE }), + @BodyType.When(option = "operation", value = "audio-transcription", + carriers = { Carrier.FILE, Carrier.BYTES, Carrier.STREAM }), + @BodyType.When(option = "operation", value = "audio-translation", + carriers = { Carrier.FILE, Carrier.BYTES, Carrier.STREAM }), + @BodyType.When(option = "operation", value = "image-edit", + carriers = { + Carrier.FILE, Carrier.BYTES, Carrier.STREAM, + Carrier.LIST }) }, + description = "The prompt of chat-completion and responses: text, or a file, bytes or a" + + " stream with an image or a PDF (chat-completion also audio), which" + + " userMessage then describes. Another body is sent as its toString()," + + " and userMessage or the CamelOpenAIUserMessage header replaces a text" + + " body. embeddings and moderation take text or a List of texts" + + " (moderation also an image), audio-speech the text to speak, and" + + " image-generation the prompt unless imagePrompt is set. batch takes the" + + " requests as a Map keyed by custom_id, a List, or JSONL; audio takes the" + + " audio and image-edit the image, or a List of images. The operations" + + " that read a stored response, a batch or the tool calls of the last" + + " answer do not use the body"), + producerOut = @BodyType(value = Carrier.TEXT, + byOption = { + @BodyType.When(option = "streaming", value = "true", carriers = Carrier.ITERATOR), + @BodyType.When(option = "autoToolExecution", value = "false", + carriers = { Carrier.TEXT, Carrier.POJO, Carrier.LIST }), + @BodyType.When(option = "operation", value = "decisions", carriers = Carrier.POJO, + javaType = "com.openai.models.decisions.Decision"), + @BodyType.When(option = "operation", value = "responses", carriers = Carrier.TEXT), + @BodyType.When(option = "operation", value = "responses-retrieve", + carriers = Carrier.TEXT), + @BodyType.When(option = "operation", value = "responses-cancel", + carriers = Carrier.TEXT), + @BodyType.When(option = "operation", value = "batch", carriers = Carrier.UNCHANGED), + @BodyType.When(option = "operation", value = "batch-retrieve", + carriers = Carrier.UNCHANGED), + @BodyType.When(option = "operation", value = "batch-cancel", + carriers = Carrier.UNCHANGED), + @BodyType.When(option = "operation", value = "batch-results", + carriers = Carrier.ITERATOR), + @BodyType.When(option = "operation", value = "embeddings", carriers = Carrier.LIST), + @BodyType.When(option = "operation", value = "tool-execution", + carriers = { Carrier.NULL, Carrier.UNCHANGED }), + @BodyType.When(option = "operation", value = "audio-transcription", + carriers = Carrier.TEXT), + @BodyType.When(option = "operation", value = "audio-translation", + carriers = Carrier.TEXT), + @BodyType.When(option = "operation", value = "audio-speech", + carriers = Carrier.BYTES, + javaType = "byte[]"), + @BodyType.When(option = "operation", value = "moderation", + carriers = Carrier.UNCHANGED), + @BodyType.When(option = "operation", value = "image-generation", + carriers = { Carrier.BYTES, Carrier.TEXT, Carrier.LIST }), + @BodyType.When(option = "operation", value = "image-edit", + carriers = { Carrier.BYTES, Carrier.TEXT, Carrier.LIST }) }, + description = "The answer of chat-completion as text, also with outputClass or" + + " jsonSchema, where it is JSON text: unmarshal it to read its fields." + + " With streaming, an Iterator of the chunks (text when MCP tools run in" + + " a loop). With autoToolExecution=false, the tool calls the model asks" + + " for: an Optional of the List of tool calls, or a List of the function" + + " calls for responses. embeddings gives a vector (a List of Float), or a" + + " List of vectors for a List of texts; image-generation and image-edit" + + " the image as bytes or its URL as text, a List for several; batch-results" + + " an Iterator of the result lines as Maps. batch and moderation keep the" + + " body and set headers, and tool-execution clears it when it runs tool" + + " calls")) public class OpenAIEndpoint extends DefaultEndpoint { private static final Logger LOG = LoggerFactory.getLogger(OpenAIEndpoint.class); diff --git a/components/camel-ai/camel-qdrant/src/generated/resources/META-INF/org/apache/camel/component/qdrant/qdrant.json b/components/camel-ai/camel-qdrant/src/generated/resources/META-INF/org/apache/camel/component/qdrant/qdrant.json index 283a45b213cb8..4370a6d815738 100644 --- a/components/camel-ai/camel-qdrant/src/generated/resources/META-INF/org/apache/camel/component/qdrant/qdrant.json +++ b/components/camel-ai/camel-qdrant/src/generated/resources/META-INF/org/apache/camel/component/qdrant/qdrant.json @@ -48,6 +48,10 @@ "CamelQdrantPointId": { "index": 9, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The point id to use for operation.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#POINT_ID" }, "CamelQdrantMaxResults": { "index": 10, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The maximum number of results to return from a similarity search.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#MAX_RESULTS" } }, + "bodyTypes": { + "producerIn": { "carriers": [ "pojo", "list", "null" ], "description": "By the action in the CamelQdrantAction header: a VectorParams for CREATE_COLLECTION, a PointStruct or a List of them for UPSERT, a PointId or a List of them for RETRIEVE, a PointsSelector, PointId, Filter or Condition for DELETE, and the query vector as a List of Float, a float array or a PointStruct for SIMILARITY_SEARCH. DELETE_COLLECTION and COLLECTION_INFO do not read the body. Another body fails, such as a number as the id (use PointIdFactory.id) or a List of Double. The qdrant:embeddings data type transformer builds the PointStruct from the output of langchain4j-embeddings" }, + "producerOut": { "carriers": [ "list", "pojo", "unchanged" ], "description": "By the action: a List of RetrievedPoint for RETRIEVE, a List of ScoredPoint for SIMILARITY_SEARCH and a CollectionInfo for COLLECTION_INFO. The other actions keep the body, UPSERT and DELETE with the operation id and status in headers" } + }, "properties": { "collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection Name" }, "host": { "index": 1, "kind": "parameter", "displayName": "Host", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "localhost", "configurationClass": "org.apache.camel.component.qdrant.QdrantConfiguration", "configurationField": "configuration", "description": "The host to connect to." }, diff --git a/components/camel-ai/camel-qdrant/src/main/java/org/apache/camel/component/qdrant/QdrantEndpoint.java b/components/camel-ai/camel-qdrant/src/main/java/org/apache/camel/component/qdrant/QdrantEndpoint.java index 3b7a1b8455400..8dbb2ba6b4878 100644 --- a/components/camel-ai/camel-qdrant/src/main/java/org/apache/camel/component/qdrant/QdrantEndpoint.java +++ b/components/camel-ai/camel-qdrant/src/main/java/org/apache/camel/component/qdrant/QdrantEndpoint.java @@ -25,6 +25,9 @@ import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; +import org.apache.camel.spi.BodyType; +import org.apache.camel.spi.BodyType.Carrier; +import org.apache.camel.spi.BodyTypes; import org.apache.camel.spi.EndpointServiceLocation; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriEndpoint; @@ -46,6 +49,21 @@ Category.AI }, headersClass = QdrantHeaders.class) +@BodyTypes(producerIn = @BodyType(value = { Carrier.POJO, Carrier.LIST, Carrier.NULL }, + description = "By the action in the CamelQdrantAction header: a VectorParams for" + + " CREATE_COLLECTION, a PointStruct or a List of them for UPSERT, a PointId" + + " or a List of them for RETRIEVE, a PointsSelector, PointId, Filter or" + + " Condition for DELETE, and the query vector as a List of Float, a float" + + " array or a PointStruct for SIMILARITY_SEARCH. DELETE_COLLECTION and" + + " COLLECTION_INFO do not read the body. Another body fails, such as a" + + " number as the id (use PointIdFactory.id) or a List of Double. The" + + " qdrant:embeddings data type transformer builds the PointStruct from the" + + " output of langchain4j-embeddings"), + producerOut = @BodyType(value = { Carrier.LIST, Carrier.POJO, Carrier.UNCHANGED }, + description = "By the action: a List of RetrievedPoint for RETRIEVE, a List of" + + " ScoredPoint for SIMILARITY_SEARCH and a CollectionInfo for" + + " COLLECTION_INFO. The other actions keep the body, UPSERT and DELETE with" + + " the operation id and status in headers")) public class QdrantEndpoint extends DefaultEndpoint implements EndpointServiceLocation { @Metadata(required = true) diff --git a/components/camel-ibm/camel-ibm-watson-language/src/generated/resources/META-INF/org/apache/camel/component/ibm/watson/language/ibm-watson-language.json b/components/camel-ibm/camel-ibm-watson-language/src/generated/resources/META-INF/org/apache/camel/component/ibm/watson/language/ibm-watson-language.json index ce47ac5e383e0..d0b502549cf53 100644 --- a/components/camel-ibm/camel-ibm-watson-language/src/generated/resources/META-INF/org/apache/camel/component/ibm/watson/language/ibm-watson-language.json +++ b/components/camel-ibm/camel-ibm-watson-language/src/generated/resources/META-INF/org/apache/camel/component/ibm/watson/language/ibm-watson-language.json @@ -53,6 +53,10 @@ "CamelIBMWatsonLanguageSentimentScore": { "index": 10, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Double", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The sentiment score", "constantName": "org.apache.camel.component.ibm.watson.language.WatsonLanguageConstants#SENTIMENT_SCORE" }, "CamelIBMWatsonLanguageSentimentLabel": { "index": 11, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The sentiment label (positive, negative, neutral)", "constantName": "org.apache.camel.component.ibm.watson.language.WatsonLanguageConstants#SENTIMENT_LABEL" } }, + "bodyTypes": { + "producerIn": { "carriers": [ "any" ], "description": "The text to analyze for analyzeText, or the URL of the page for analyzeUrl, read as text, unless the CamelIBMWatsonLanguageText or CamelIBMWatsonLanguageUrl header gives it. Without the header, no body or a blank one fails, and a Map or a POJO is analyzed as its toString(): marshal it first" }, + "producerOut": { "carriers": [ "pojo" ], "javaType": "com.ibm.watson.natural_language_understanding.v1.model.AnalysisResults", "description": "The results of the features enabled (sentiment, entities, keywords and so on), with the sentiment score and label and the language in headers too. Converted to text, it is the JSON of the results" } + }, "properties": { "label": { "index": 0, "kind": "path", "displayName": "Label", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Logical name" }, "serviceUrl": { "index": 1, "kind": "parameter", "displayName": "Service Url", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.ibm.watson.language.WatsonLanguageConfiguration", "configurationField": "configuration", "description": "The service endpoint URL. If not specified, the default URL will be used." }, diff --git a/components/camel-ibm/camel-ibm-watson-language/src/main/java/org/apache/camel/component/ibm/watson/language/WatsonLanguageEndpoint.java b/components/camel-ibm/camel-ibm-watson-language/src/main/java/org/apache/camel/component/ibm/watson/language/WatsonLanguageEndpoint.java index 801c07756df8d..f8ff4572ffdbb 100644 --- a/components/camel-ibm/camel-ibm-watson-language/src/main/java/org/apache/camel/component/ibm/watson/language/WatsonLanguageEndpoint.java +++ b/components/camel-ibm/camel-ibm-watson-language/src/main/java/org/apache/camel/component/ibm/watson/language/WatsonLanguageEndpoint.java @@ -22,6 +22,9 @@ import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; +import org.apache.camel.spi.BodyType; +import org.apache.camel.spi.BodyType.Carrier; +import org.apache.camel.spi.BodyTypes; import org.apache.camel.spi.EndpointServiceLocation; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriEndpoint; @@ -35,6 +38,17 @@ @UriEndpoint(firstVersion = "4.16.0", scheme = "ibm-watson-language", title = "IBM Watson Language", syntax = "ibm-watson-language:label", producerOnly = true, category = { Category.AI, Category.CLOUD }, headersClass = WatsonLanguageConstants.class) +@BodyTypes(producerIn = @BodyType(value = Carrier.ANY, + description = "The text to analyze for analyzeText, or the URL of the page for" + + " analyzeUrl, read as text, unless the CamelIBMWatsonLanguageText or" + + " CamelIBMWatsonLanguageUrl header gives it. Without the header, no body or" + + " a blank one fails, and a Map or a POJO is analyzed as its toString():" + + " marshal it first"), + producerOut = @BodyType(value = Carrier.POJO, + javaType = "com.ibm.watson.natural_language_understanding.v1.model.AnalysisResults", + description = "The results of the features enabled (sentiment, entities, keywords and so" + + " on), with the sentiment score and label and the language in headers too." + + " Converted to text, it is the JSON of the results")) public class WatsonLanguageEndpoint extends DefaultEndpoint implements EndpointServiceLocation { @UriPath(description = "Logical name") diff --git a/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc b/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc index 573ada4c6125d..454c8930fb640 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc @@ -188,7 +188,8 @@ public class FileEndpoint extends GenericFileEndpoint { ---- The build checks that each side belongs to the kind (a consumer-only component has no producer sides), that the -options a side names exist, that `unchanged` is only on the body after a step and `any` only on what a step needs. +options a side names exist, that a value of an option is one the option can have (such as `chat-completion` for the +`operation` of openai), and that `unchanged` is only on the body after a step and `any` only on what a step needs. The values are read from the code that sets the body, and checked against the body types the message history records when the routes run. diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-validation.adoc b/docs/user-manual/modules/ROOT/pages/camel-jbang-validation.adoc index 26c18f3af01cd..54c39089b8054 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-jbang-validation.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-validation.adoc @@ -77,8 +77,9 @@ The YAML validator follows the message body through the steps of each route, and it: a field read such as `+${body.qty}+` on text that was never unmarshalled, or a Map that a `to: file` cannot write. What a component or a data format does with the body comes from the xref:camel-catalog.adoc#_body_types_in_the_catalog[body types in the catalog]: the file consumer gives the file it -read, the `http` producer leaves the response as bytes or a stream, and `unmarshal: json` makes a Map or a List. -Where they do not tell what the body is, the validator says nothing: after a `platform-http` consumer the body +read, the `http` producer leaves the response as bytes or a stream, and `unmarshal: json` makes a Map or a List. The +answer of `openai:chat-completion` is text, also when it is asked for JSON with `jsonSchema`, so a field read on it +needs `unmarshal: json` first. Where they do not tell what the body is, the validator says nothing: after a `platform-http` consumer the body depends on the request, and the deserializer of a `kafka` consumer can be set on the component, which the route file does not show. diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java index 3259582da25f3..897532a0a271d 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java @@ -191,9 +191,44 @@ private Answer componentSide(String uri, JsonNode node, String side) { String text = node != null && node.isTextual() ? node.asText() : node != null && node.isObject() && node.has("uri") ? node.get("uri").asText() : null; set.putAll(query(text)); + readPath(uri, model, set, configurable); return answer(model.getBodyType(side), set, configurable); } + /** + * Adds the options in the path of an endpoint uri, as the syntax of its component names them: the operation of + * openai:embeddings. A path the catalog cannot read says nothing about them, as an option the component may set. + */ + private void readPath(String uri, ComponentModel model, Map set, Set configurable) { + if (uri == null || model.getEndpointPathOptions().isEmpty()) { + return; + } + // the query is read on its own, and may hold what the parser of the catalog does not take, such as a space + int q = uri.indexOf('?'); + String path = q < 0 ? uri : uri.substring(0, q); + Optional> properties = endpointProperties(catalog, path); + if (properties.isEmpty() && fallback != null) { + properties = endpointProperties(fallback, path); + } + for (BaseOptionModel option : model.getEndpointPathOptions()) { + String name = option.getName(); + if (properties.isEmpty()) { + configurable.add(name); + } else if (properties.get().containsKey(name)) { + set.putIfAbsent(name, properties.get().get(name)); + } + } + } + + private static Optional> endpointProperties(CamelCatalog catalog, String uri) { + try { + return Optional.ofNullable(catalog.endpointProperties(uri)); + } catch (Exception e) { + // not an endpoint the catalog can read, such as one of a component it does not have + return Optional.empty(); + } + } + /** * What a side says for the options a step sets: the body for an option value it names, or its body when the options * it depends on keep their defaults; null when it is not known for the step. diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java index 5c0085afe5a80..0c2af877367d5 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java @@ -1037,6 +1037,50 @@ public void testWhatTheComponentMayConfigureSaysNothing() { assertThat(lines(yaml)).isEmpty(); } + @Test + public void testTheOptionsInThePathOfTheEndpoint() { + // the operation of openai is in the path: the answer of chat-completion is text, also when it is asked for as + // JSON, embeddings gives a List, and an operation only known when the route runs says nothing + String yaml = """ + - route: + id: city + from: + uri: timer:tick + steps: + - setBody: + constant: Name a city in Denmark + - to: openai:chat-completion?jsonSchema=resource:classpath:city.json + - setHeader: + name: city + simple: ${body[name]} + - route: + id: vector + from: + uri: timer:tick + steps: + - setBody: + constant: Apache Camel + - to: llm:embeddings + - setHeader: + name: first + simple: ${body[0]} + - route: + id: dynamic + from: + uri: timer:tick + steps: + - setBody: + constant: Apache Camel + - toD: openai:${header.operation} + - setHeader: + name: first + simple: ${body[0]} + """; + assertThat(lines(yaml)).singleElement().satisfies(m -> assertThat(m) + .contains("route city: simple reads a field of the body (${body[name]})") + .contains("to: openai:chat-completion returns it as text: unmarshal it first")); + } + @Test public void testOneReportForAStepThatFails() { // the first write fails at runtime, so the second does not run with this body diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/BodyTypesHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/BodyTypesHelper.java index fcb3789aa78a5..8ce467e34661f 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/BodyTypesHelper.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/BodyTypesHelper.java @@ -18,7 +18,7 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -28,6 +28,7 @@ import org.apache.camel.spi.BodyType.Carrier; import org.apache.camel.spi.BodyTypes; import org.apache.camel.tooling.model.BaseModel; +import org.apache.camel.tooling.model.BaseOptionModel; import org.apache.camel.tooling.model.BodyTypeModel; import org.apache.camel.tooling.model.ComponentModel; @@ -50,8 +51,8 @@ private BodyTypesHelper() { * @param bodyTypes the annotation, null when the class has none * @param owner the class with the annotation, for the error message * @throws IllegalArgumentException when a side does not fit the model: a data format side on a component, a - * producer side on a consumer-only component, unchanged on what a step needs or - * any on what it leaves + * producer side on a consumer-only component, unchanged on what a step needs, any + * on what it leaves, or a value an option cannot have */ static void addBodyTypes(BaseModel model, BodyTypes bodyTypes, Class owner) { if (bodyTypes == null) { @@ -70,7 +71,7 @@ static void addBodyTypes(BaseModel model, BodyTypes bodyTypes, Class owner sides.put(BodyTypeModel.EXPRESSION_OUT, bodyTypes.expressionOut()); Set allowed = allowedSides(model); - Set options = optionNames(model); + Map options = options(model); for (Map.Entry entry : sides.entrySet()) { String side = entry.getKey(); BodyType bodyType = entry.getValue(); @@ -93,6 +94,7 @@ static void addBodyTypes(BaseModel model, BodyTypes bodyTypes, Class owner } for (BodyType.When when : bodyType.byOption()) { checkOption(owner, side, when.option(), options); + checkValue(owner, side, when, options.get(when.option())); check(owner, side + " " + when.option() + "=" + when.value(), when.carriers()); } model.getBodyTypes().put(side, asModel(bodyType)); @@ -118,24 +120,39 @@ private static Set allowedSides(BaseModel model) { }; } - /** The options of the model, which the body types can depend on. */ - private static Set optionNames(BaseModel model) { - Set names = new HashSet<>(); - model.getOptions().forEach(o -> names.add(o.getName())); + /** The options of the model by name, which the body types can depend on. */ + private static Map options(BaseModel model) { + Map answer = new HashMap<>(); + model.getOptions().forEach(o -> answer.put(o.getName(), o)); if (model instanceof ComponentModel component) { - component.getComponentOptions().forEach(o -> names.add(o.getName())); - component.getEndpointOptions().forEach(o -> names.add(o.getName())); + component.getComponentOptions().forEach(o -> answer.put(o.getName(), o)); + component.getEndpointOptions().forEach(o -> answer.put(o.getName(), o)); } - return names; + return answer; } - private static void checkOption(Class owner, String side, String option, Set options) { - if (!options.contains(option)) { + private static void checkOption(Class owner, String side, String option, Map options) { + if (!options.containsKey(option)) { throw new IllegalArgumentException( owner.getName() + ": the @BodyTypes " + side + " depends on " + option + ", which is not an option"); } } + /** + * A body for a value the option cannot have would never hold: the value is one of an enum, or true or false for a + * boolean, in any case, as tooling compares it with what the endpoint sets. + */ + private static void checkValue(Class owner, String side, BodyType.When when, BaseOptionModel option) { + List values = option.getEnums() != null && !option.getEnums().isEmpty() + ? option.getEnums() + : "boolean".equals(option.getType()) ? List.of("true", "false") : List.of(); + if (!values.isEmpty() && values.stream().noneMatch(v -> v.equalsIgnoreCase(when.value()))) { + throw new IllegalArgumentException( + owner.getName() + ": the @BodyTypes " + side + " has " + when.option() + "=" + when.value() + + ", which is not a value of the option: " + String.join(", ", values)); + } + } + /** * A body has a carrier: an option value without one would say nothing. UNCHANGED is for the body after a step, such * as a sql query that leaves it unchanged unless it is a select. ANY is for the bodies a step needs. ANY and diff --git a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java index 5fa2fe71426d0..24d5b3d86b84e 100644 --- a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java +++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/EndpointSchemaGeneratorMojoTest.java @@ -233,7 +233,8 @@ void testEndpointWithHeadersOnSelfAndSuperclass() { @Test void testEndpointWithBodyTypes() throws Exception { // CAMEL-24961: the body a step needs and the body it leaves, in the order of the annotation - addEndpointOptions("resultHandlerFactory", "output"); + addEndpointOptions("resultHandlerFactory"); + addEnumOption("output", "string", "bytes"); mojo.addBodyTypes(model, SomeEndpointWithBodyTypes.class); assertEquals(List.of(BodyTypeModel.CONSUMER_OUT, BodyTypeModel.PRODUCER_IN, BodyTypeModel.PRODUCER_OUT), List.copyOf(model.getBodyTypes().keySet())); @@ -278,9 +279,10 @@ void testEndpointWithoutBodyTypes() throws Exception { SomeEndpointWithBadBodyTypes.DataFormatSide.class, SomeEndpointWithBadBodyTypes.ProducerSideOfConsumer.class, SomeEndpointWithBadBodyTypes.UnchangedInput.class, SomeEndpointWithBadBodyTypes.AnyOutput.class, SomeEndpointWithBadBodyTypes.UnknownWithOthers.class, SomeEndpointWithBadBodyTypes.NoCarriers.class, - SomeEndpointWithBadBodyTypes.UnknownOption.class, SomeEndpointWithBadBodyTypes.OptionValueWithoutCarriers.class }) + SomeEndpointWithBadBodyTypes.UnknownOption.class, SomeEndpointWithBadBodyTypes.OptionValueWithoutCarriers.class, + SomeEndpointWithBadBodyTypes.ValueTheOptionDoesNotHave.class }) void testEndpointWithBadBodyTypes(Class clazz) { - addEndpointOptions("output"); + addEnumOption("output", "string", "bytes"); model.setConsumerOnly(clazz.getAnnotation(UriEndpoint.class).consumerOnly()); MojoExecutionException e = assertThrows(MojoExecutionException.class, () -> mojo.addBodyTypes(model, clazz)); assertTrue(e.getMessage().startsWith(clazz.getName() + ": the @BodyTypes "), e.getMessage()); @@ -294,4 +296,12 @@ private void addEndpointOptions(String... names) { model.addEndpointOption(option); } } + + private void addEnumOption(String name, String... values) { + ComponentModel.EndpointOptionModel option = new ComponentModel.EndpointOptionModel(); + option.setName(name); + option.setType("enum"); + option.setEnums(List.of(values)); + model.addEndpointOption(option); + } } diff --git a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithBadBodyTypes.java b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithBadBodyTypes.java index cccd18faa7155..8c0f53728d6a6 100644 --- a/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithBadBodyTypes.java +++ b/tooling/maven/camel-package-maven-plugin/src/test/java/org/apache/camel/maven/packaging/endpoint/SomeEndpointWithBadBodyTypes.java @@ -69,4 +69,10 @@ public static class UnknownOption { byOption = @BodyType.When(option = "output", value = "bytes", carriers = {}))) public static class OptionValueWithoutCarriers { } + + @UriEndpoint(scheme = "some", syntax = "some", title = "some") + @BodyTypes(producerOut = @BodyType(value = Carrier.TEXT, + byOption = @BodyType.When(option = "output", value = "DOM", carriers = Carrier.POJO))) + public static class ValueTheOptionDoesNotHave { + } }