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

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


The following commit(s) were added to refs/heads/main by this push:
     new 1d9d9a5b1516 CAMEL-24223: camel-jbang-mcp - Locale.ROOT cost 
formatting and model-specific disclaimer (follow-up) (#25167)
1d9d9a5b1516 is described below

commit 1d9d9a5b1516a87250856225ab057adb90aa5bb8
Author: Andrea Cosentino <[email protected]>
AuthorDate: Tue Jul 28 09:25:56 2026 +0200

    CAMEL-24223: camel-jbang-mcp - Locale.ROOT cost formatting and 
model-specific disclaimer (follow-up) (#25167)
    
    CAMEL-24223: Locale.ROOT cost formatting, model-specific disclaimer, 
tighter tests
    
    Addresses the remaining review points:
    
    - formatCost now uses Locale.ROOT so the decimal separator is always '.'
      (a comma separator under e.g. a French locale would break MCP clients that
      parse the returned strings).
    - The top-level disclaimer now states explicitly that token-based (LLM)
      components are priced as a specific model, not a provider-wide figure, and
      that Nova Lite / Haiku / local models (Ollama) cost far less, often ~zero 
—
      making clear these are specific-model estimates.
    - shouldExtractSchemesCorrectly now uses containsExactlyInAnyOrder(file,
      docling, aws-bedrock, aws2-s3), catching both a false "uri" capture and a
      dropped "file" scheme; shouldEstimateCostForAiPipeline pins the breakdown 
to
      exactly 3 priced components and asserts the computed aws-bedrock 
per-execution
      cost rather than only the count.
    
    Signed-off-by: Andrea Cosentino <[email protected]>
    Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
---
 .../jbang/core/commands/mcp/RouteCostEstimateTools.java   | 13 +++++++++----
 .../core/commands/mcp/RouteCostEstimateToolsTest.java     | 15 ++++++++++++---
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteCostEstimateTools.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteCostEstimateTools.java
index a1aa84fb5eca..57e5fd519e3a 100644
--- 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteCostEstimateTools.java
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteCostEstimateTools.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -134,8 +135,10 @@ public class RouteCostEstimateTools {
                 breakdown.isEmpty() ? null : breakdown,
                 projection, summary,
                 optimizationTips.isEmpty() ? null : optimizationTips,
-                "Cost estimates are approximate based on published AWS pricing 
(us-east-1). "
-                                                                      + 
"Actual costs vary by region, volume tier, and model.",
+                "Cost estimates are approximate based on published AWS pricing 
(us-east-1). Token-based (LLM) "
+                                                                      + 
"components are priced as a specific model — see each component's pricingNote — 
and are NOT a "
+                                                                      + 
"provider-wide figure: a route on Nova Lite, Haiku or a local/self-hosted model 
(Ollama) will cost "
+                                                                      + "far 
less, often ~zero. Actual costs vary by region, volume tier, and model.",
                 "2025-Q2");
     }
 
@@ -179,10 +182,12 @@ public class RouteCostEstimateTools {
     }
 
     private static String formatCost(double cost) {
+        // Locale.ROOT so the decimal separator is always '.' regardless of 
the server locale — MCP clients
+        // parse these strings and a comma separator (e.g. "$0,003000" under a 
French locale) would break them.
         if (cost < 0.01) {
-            return String.format("$%.6f", cost);
+            return String.format(Locale.ROOT, "$%.6f", cost);
         }
-        return String.format("$%.4f", cost);
+        return String.format(Locale.ROOT, "$%.4f", cost);
     }
 
     private static Map<String, ComponentCostProfile> buildCostProfiles() {
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteCostEstimateToolsTest.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteCostEstimateToolsTest.java
index f66289e24488..889bd6ee5cbb 100644
--- 
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteCostEstimateToolsTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/RouteCostEstimateToolsTest.java
@@ -76,10 +76,18 @@ class RouteCostEstimateToolsTest {
 
         assertThat(result).isNotNull();
         assertThat(result.costBreakdown()).isNotNull();
-        assertThat(result.costBreakdown()).hasSizeGreaterThanOrEqualTo(2);
+        // docling, aws-bedrock and aws2-s3 have cost profiles; the file: 
scheme does not, so exactly 3 are priced.
+        assertThat(result.costBreakdown()).hasSize(3);
         
assertThat(result.summary().mostExpensiveComponent()).isEqualTo("aws-bedrock");
         assertThat(result.projection().messagesPerHour()).isEqualTo(100);
         assertThat(result.disclaimer()).isNotBlank();
+
+        // aws-bedrock is estimated at Claude Sonnet 4 pricing: 1000 in * 
$3/MTok + 500 out * $15/MTok.
+        double expectedBedrock = 1000 * 3.0 / 1_000_000 + 500 * 15.0 / 
1_000_000;
+        assertThat(result.costBreakdown())
+                .filteredOn(c -> "aws-bedrock".equals(c.scheme()))
+                .singleElement()
+                .satisfies(c -> 
assertThat(c.estimatedCostPerExecution()).isEqualTo(expectedBedrock));
     }
 
     @Test
@@ -132,8 +140,9 @@ class RouteCostEstimateToolsTest {
     void shouldExtractSchemesCorrectly() {
         List<String> schemes = tools.extractSchemes(AI_PIPELINE_ROUTE);
 
-        assertThat(schemes).contains("docling", "aws-bedrock", "aws2-s3");
-        assertThat(schemes).doesNotContain("uri");
+        // Exact set: the from: uri is file, then the three to: schemes. This 
catches both a false "uri" capture
+        // (from the multi-line from:\n  uri: form) and a dropped "file" 
scheme.
+        assertThat(schemes).containsExactlyInAnyOrder("file", "docling", 
"aws-bedrock", "aws2-s3");
     }
 
     @Test

Reply via email to