You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by "Croway (via GitHub)" <gi...@apache.org> on 2026/09/15 11:35:28 UTC

[PR] Add Camel 4.22.1 migration recipe for camel-openai storeFullResponse property (CAMEL-24539) [camel-upgrade-recipes]

Croway opened a new pull request, #130:
URL: https://github.com/apache/camel-upgrade-recipes/pull/130

   ## Summary
   
   - Camel 4.22.1 (LTS patch) backports CAMEL-24539: with `storeFullResponse=true`, the camel-openai `embeddings`, `audio-transcription` and `audio-translation` operations now store their full SDK response under an operation-specific exchange property (`CamelOpenAIEmbeddingsResponse` / `CamelOpenAIAudioTranscriptionResponse` / `CamelOpenAIAudioTranslationResponse`) instead of the shared `CamelOpenAIResponse` property still used by `chat-completion`.
   - Adds a route-scoped recipe (Java, XML and YAML DSL) that renames `CamelOpenAIResponse` (and the matching `OpenAIConstants` field) only in a route whose single openai operation is one of the three eligible ones. Routes with several openai operations, `chat-completion`/`responses`/`tool-execution`/`audio-speech`, or processors/beans defined outside the route are left unchanged. Gated on the `camel-openai` dependency.
   - Everything else backported into 4.22.1 is a secure-default/runtime behaviour change or a deprecation with no replacement yet, so it's manual-only and documented in `release_notes.adoc` rather than automated.
   - Wires the new `camel422_1.CamelMigrationRecipe` into `latest.yaml` (core) and `4.22.yaml` (Spring Boot), following the patch-recipe convention in `RECIPE-CONVENTIONS.md`.
   - Does **not** add a `4.22LTS.yaml` aggregate recipe — tracked separately in #129 pending a decision on when to introduce it.
   
   ## Test plan
   
   - [x] `mvn test -pl camel-upgrade-recipes -Dtest=CamelUpdate422_1Test` — 5/5 passing
   - [x] `mvn clean install` (core `camel-upgrade-recipes` module) — 890/890 passing
   - [x] `mvn clean install` (Spring Boot module) — all passing except 3 pre-existing failures in `CamelSpringBoot422Test` unrelated to this change (confirmed to fail identically on `main`, caused by a stray locally-cached `camel-ai-tool-starter:4.23.0-SNAPSHOT` artifact resolving ahead of the pinned `4.22.0` version on this machine)
   
   _Claude Code on behalf of croway_


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Camel 4.22.1 migration recipe for camel-openai storeFullResponse property (CAMEL-24539) [camel-upgrade-recipes]

Posted by "JiriOndrusek (via GitHub)" <gi...@apache.org>.
JiriOndrusek commented on code in PR #130:
URL: https://github.com/apache/camel-upgrade-recipes/pull/130#discussion_r4023520067


##########
camel-upgrade-recipes/src/main/java/org/apache/camel/upgrade/camel422_1/FlagOpenAIFullResponsePropertyInXmlDsl.java:
##########
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.upgrade.camel422_1;
+
+import org.apache.camel.upgrade.AbstractCamelXmlVisitor;
+import org.apache.camel.upgrade.RecipesUtil;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Preconditions;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.xml.tree.Xml;
+
+import java.util.regex.Pattern;
+
+import static org.apache.camel.upgrade.camel422_1.FlagOpenAIFullResponsePropertyInJavaDsl.WARNING_COMMENT;
+
+/**
+ * Flags camel-openai {@code CamelOpenAIResponse} usages in XML DSL for manual review (CAMEL-24539).
+ * See {@link FlagOpenAIFullResponsePropertyInJavaDsl} for why this marks instead of rewriting.
+ */
+public class FlagOpenAIFullResponsePropertyInXmlDsl extends Recipe {
+
+    // A short, unique substring of WARNING_COMMENT used to detect an already-added comment
+    private static final String MARKER = "CAMEL-24539";
+
+    private static final String OLD_PROPERTY_NAME = "CamelOpenAIResponse";
+
+    private static final Pattern SIMPLE_EXCHANGE_PROPERTY = Pattern.compile(
+            "\\$\\{exchangeProperty(?:\\.CamelOpenAIResponse[.}]|\\[CamelOpenAIResponse]}|(?:As)?\\(CamelOpenAIResponse[,)])");
+
+    @Override
+    public String getDisplayName() {
+        return "Flag camel-openai CamelOpenAIResponse property in XML DSL";
+    }
+
+    @Override
+    public String getDescription() {
+        return "Adds a review comment wherever CamelOpenAIResponse is used, since whether it should become " +
+               "CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse " +
+               "or stay CamelOpenAIResponse cannot be decided statically.";
+    }
+
+    @Override
+    public TreeVisitor<?, ExecutionContext> getVisitor() {
+        return Preconditions.check(RecipesUtil.camelXmlDslPrecondition(), new FlagVisitor());
+    }
+
+    private static class FlagVisitor extends AbstractCamelXmlVisitor {
+
+        @Override
+        public Xml.Tag doVisitTag(Xml.Tag tag, ExecutionContext ctx) {
+            Xml.Tag t = super.doVisitTag(tag, ctx);
+
+            String tagName = t.getName();
+            boolean propertyTag = "setProperty".equals(tagName) || "removeProperty".equals(tagName);
+
+            boolean flagTag = false;
+            for (Xml.Attribute attr : t.getAttributes()) {
+                String value = attr.getValueAsString();
+                if (value == null) {
+                    continue;
+                }
+                if (propertyTag && "name".equals(attr.getKeyAsString()) && OLD_PROPERTY_NAME.equals(value)) {
+                    flagTag = true;
+                }
+                if (SIMPLE_EXCHANGE_PROPERTY.matcher(value).find()) {
+                    flagTag = true;
+                }
+            }
+            if (t.getChildren().isEmpty()) {
+                String value = t.getValue().orElse(null);
+                if (value != null && SIMPLE_EXCHANGE_PROPERTY.matcher(value).find()) {
+                    flagTag = true;
+                }
+            }
+
+            if (flagTag && !t.getPrefix().contains(MARKER)) {

Review Comment:
   **Blocking: not idempotent across runs.** The comment is written into the tag *prefix*, but on the next parse OpenRewrite turns `<!--…-->` into a separate `Xml.Comment` node (`XmlParserVisitor.visitMisc`/`visitContent`), so `getPrefix().contains(MARKER)` is false and **every rerun duplicates every comment**. Reproduced by feeding this PR's own "after" XML back as input — both comments double. Users run `mvn rewrite:run` iteratively, so this will happen in practice.
   
   Suggest inserting a real `Xml.Comment` into the parent's content (`RecipesUtil.createXmlComment` exists, currently unused) and treating a preceding sibling comment containing `CAMEL-24539` as already flagged.



##########
camel-upgrade-recipes/src/test/java/org/apache/camel/upgrade/CamelUpdate422_1Test.java:
##########
@@ -0,0 +1,249 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.upgrade;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+import org.openrewrite.test.TypeValidation;
+
+import static org.openrewrite.java.Assertions.java;
+import static org.openrewrite.java.Assertions.mavenProject;
+import static org.openrewrite.xml.Assertions.xml;
+import static org.openrewrite.yaml.Assertions.yaml;
+
+/**
+ * Tests for migrating from Camel 4.22.0 to 4.22.1 (CAMEL-24539, camel-openai).
+ * <p>
+ * Whether a given CamelOpenAIResponse occurrence should become the embeddings/audio-transcription/
+ * audio-translation property, or stay CamelOpenAIResponse (chat-completion), is not mechanically
+ * decidable in general -- see {@code org.apache.camel.upgrade.camel422_1.FlagOpenAIFullResponsePropertyInJavaDsl}
+ * for why. So the recipe flags every occurrence with a review comment instead of rewriting it.
+ */
+public class CamelUpdate422_1Test implements RewriteTest {
+
+    @Override
+    public void defaults(RecipeSpec spec) {
+        CamelTestUtil.recipe(spec, CamelTestUtil.CamelVersion.v4_22_1)
+                .parser(CamelTestUtil.parserFromClasspath(CamelTestUtil.CamelVersion.v4_22, "camel-api",
+                        "camel-core-model", "camel-support", "camel-openai"))
+                .typeValidationOptions(TypeValidation.none());
+    }
+
+    @Test
+    @DisabledIfSystemProperty(named = CamelTestUtil.PROPERTY_USE_RECIPE, matches = ".+")
+    void javaDslFlagsOccurrencesAndLeavesLookalikesAndUnrelatedConstantAlone() {
+        //language=java
+        rewriteRun(
+                mavenProject("test-openai",
+                        CamelTestUtil.pomXmlSpec("camel-openai", CamelTestUtil.CamelVersion.v4_22),
+                        java(
+                        """
+                        import org.apache.camel.builder.RouteBuilder;
+                        import org.apache.camel.component.openai.OpenAIConstants;
+
+                        class Test extends RouteBuilder {
+                            public void configure() {
+                                from("direct:openai")
+                                    .setProperty("CamelOpenAIResponseModel", constant("keep-model"))
+                                    .process(exchange -> {
+                                        Object response = exchange.getProperty("CamelOpenAIResponse", Object.class);
+                                        exchange.setProperty("CamelOpenAIResponse", response);
+                                    })
+                                    .setProperty(OpenAIConstants.RESPONSE, exchangeProperty("CamelOpenAIResponse"))
+                                    .setBody(simple("${exchangeProperty.CamelOpenAIResponse.data}"))
+                                    .removeProperty("CamelOpenAIResponseId")
+                                    .removeProperty("CamelOpenAIResponse");
+                            }
+                        }
+                        """,
+                        """
+                        import org.apache.camel.builder.RouteBuilder;
+                        import org.apache.camel.component.openai.OpenAIConstants;
+
+                        class Test extends RouteBuilder {
+                            public void configure() {
+                                from("direct:openai")
+                                    .setProperty("CamelOpenAIResponseModel", constant("keep-model"))
+                                    .process(exchange -> {
+                                        Object response = exchange.getProperty(/* CAMEL-24539 (Camel 4.22.1): with storeFullResponse=true, embeddings/audio-transcription/audio-translation now use CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which operation this refers to and update the property name manually if needed.*/"CamelOpenAIResponse", Object.class);
+                                        exchange.setProperty(/* CAMEL-24539 (Camel 4.22.1): with storeFullResponse=true, embeddings/audio-transcription/audio-translation now use CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which operation this refers to and update the property name manually if needed.*/"CamelOpenAIResponse", response);
+                                    })
+                                    .setProperty(/* CAMEL-24539 (Camel 4.22.1): with storeFullResponse=true, embeddings/audio-transcription/audio-translation now use CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which operation this refers to and update the property name manually if needed.*/OpenAIConstants.RESPONSE, exchangeProperty(/* CAMEL-24539 (Camel 4.22.1): with storeFullResponse=true, embeddings/audio-transcription/audio-translation now use CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which operation this refers to and update the property name manually if needed.*/"CamelOpenAIResponse"))
+                                    .setBody(simple(/* CAMEL-24539 (Camel 4.22.1): with storeFullResponse=true, embeddings/audio-transcription/audio-translation now use CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which operation this refers to and update the property name manually if needed.*/"${exchangeProperty.CamelOpenAIResponse.data}"))
+                                    .removeProperty("CamelOpenAIResponseId")
+                                    .removeProperty(/* CAMEL-24539 (Camel 4.22.1): with storeFullResponse=true, embeddings/audio-transcription/audio-translation now use CamelOpenAIEmbeddingsResponse/CamelOpenAIAudioTranscriptionResponse/CamelOpenAIAudioTranslationResponse instead of CamelOpenAIResponse; chat-completion is unchanged. Verify which operation this refers to and update the property name manually if needed.*/"CamelOpenAIResponse");
+                            }
+                        }
+                        """
+                        ),
+                        // A user's own unrelated OpenAIConstants (no camel-openai import) must never be flagged.
+                        java(
+                        """
+                        package com.example;
+
+                        public final class OpenAIConstants {
+                            public static final String RESPONSE = "SomeUnrelatedConstant";
+                        }
+                        """
+                        ),
+                        java(
+                        """
+                        package com.example;
+
+                        import org.apache.camel.builder.RouteBuilder;
+
+                        class UnrelatedRoute extends RouteBuilder {
+                            public void configure() {
+                                from("direct:other")
+                                    .setProperty(OpenAIConstants.RESPONSE, constant("x"));
+                            }
+                        }
+                        """
+                        )
+                )
+        );
+    }
+
+    @Test
+    @DisabledIfSystemProperty(named = CamelTestUtil.PROPERTY_USE_RECIPE, matches = ".+")
+    void javaDslWithoutCamelOpenAIDependencyIsUnchanged() {
+        //language=java
+        rewriteRun(
+                mavenProject("test-no-openai",
+                        CamelTestUtil.pomXmlSpec("camel-core", CamelTestUtil.CamelVersion.v4_22),
+                        java(
+                        """
+                        import org.apache.camel.builder.RouteBuilder;
+
+                        class Test extends RouteBuilder {
+                            public void configure() {
+                                from("direct:openai")
+                                    .setProperty("CamelOpenAIResponse", exchangeProperty("CamelOpenAIResponse"));
+                            }
+                        }
+                        """
+                )
+                )
+        );
+    }
+
+    @Test
+    @DisabledIfSystemProperty(named = CamelTestUtil.PROPERTY_USE_RECIPE, matches = ".+")
+    void javaDslIsIdempotent() {

Review Comment:
   Please add the analogous cross-run idempotency tests for XML and YAML — i.e. feed the flagged output back as *input* and expect no change. YAML passes today (rewrite-yaml keeps comments in prefixes) and is worth locking in; XML currently fails (see the comment on the XML recipe).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Camel 4.22.1 migration recipe for camel-openai storeFullResponse property (CAMEL-24539) [camel-upgrade-recipes]

Posted by "Croway (via GitHub)" <gi...@apache.org>.
Croway commented on PR #130:
URL: https://github.com/apache/camel-upgrade-recipes/pull/130#issuecomment-5680604148

   Thanks for the thorough review — pushed a redesign addressing all three points.
   
   **1. Wiring**: Reverted the `latest.yaml` / Spring Boot `4.22.yaml` additions. `camel422_1.CamelMigrationRecipe` isn't chained anywhere for now; it belongs in the future `4.23.yaml` and/or the 4.22 LTS aggregate (#129). Runnable directly in the meantime with `-Drewrite.activeRecipes=org.apache.camel.upgrade.camel422_1.CamelMigrationRecipe`.
   
   **2 & 3. Rewrite → flag**: Replaced the route-scoped rewrite with a flag-only recipe that adds a review comment at every `CamelOpenAIResponse` / `OpenAIConstants.RESPONSE` occurrence (Java, XML, YAML), following the existing mark-don't-rewrite pattern in `camel42/CamelSagaRecipe`, `camel43/CamelThrottleEIPRecipe` and `camel44/CamelCoreRecipe`. This drops all route/operation-detection logic entirely, since it's no longer trying to pick a specific replacement property — so examples A–C (error handlers, hidden operations behind constants, `wireTap`) no longer apply: there's nothing left to misclassify. Also fixed the `OpenAIConstants.RESPONSE` match to verify the import (or resolved type) instead of the bare identifier, so a user's own unrelated `OpenAIConstants` class is no longer touched.
   
   ~90 lines per DSL now (down from the original design), all three DSL recipes tested, `release_notes.adoc` updated to describe the flagged-for-review coverage. Full test suite green except the pre-existing, unrelated `CamelSpringBoot422Test` flake (verified to fail identically on `main`).
   
   _Claude Code on behalf of croway_


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Camel 4.22.1 migration recipe for camel-openai storeFullResponse property (CAMEL-24539) [camel-upgrade-recipes]

Posted by "Croway (via GitHub)" <gi...@apache.org>.
Croway merged PR #130:
URL: https://github.com/apache/camel-upgrade-recipes/pull/130


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] Add Camel 4.22.1 migration recipe for camel-openai storeFullResponse property (CAMEL-24539) [camel-upgrade-recipes]

Posted by "Croway (via GitHub)" <gi...@apache.org>.
Croway commented on PR #130:
URL: https://github.com/apache/camel-upgrade-recipes/pull/130#issuecomment-5693774524

   Both fixed, pushed in \`89dd5c9\`.
   
   **XML idempotency**: root-caused as you described — the recipe now inserts a real \`Xml.Comment\` into the parent's content list via \`RecipesUtil.createXmlComment\` (previously unused, now wired up) instead of gluing \`<!--...-->\` text into the tag's prefix, and checks for a preceding sibling comment containing the marker instead of checking the prefix string. Added cross-run idempotency tests for both XML and YAML (feed the flagged output back as input, expect no change) — confirmed the new XML test fails against the old implementation and passes against the fix; YAML passes as expected on both.
   
   **4.23 tracking**: not opening a separate issue — croway is already working on #132 (Camel 4.23 recipes), which is the natural place to chain \`camel422_1.CamelMigrationRecipe\` in once it lands.
   
   _Claude Code on behalf of croway_


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org