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

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


The following commit(s) were added to refs/heads/main by this push:
     new f14163c8a2bb CAMEL-24760: camel-jbang - the core tool set for local 
models: camel_catalog_find in, three screen tools out, prefix budgets raised, 
prompt lines for file writes and the canonical YAML shape (#26487)
f14163c8a2bb is described below

commit f14163c8a2bbe0d40d71f26c79151185f0bfded8
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Sep 16 08:41:44 2026 +0200

    CAMEL-24760: camel-jbang - the core tool set for local models: 
camel_catalog_find in, three screen tools out, prefix budgets raised, prompt 
lines for file writes and the canonical YAML shape (#26487)
    
    * CAMEL-24760: camel-jbang - camel_catalog_find in the core tool set for 
local models, prefix budgets raised, prompt lines for the canonical YAML shape 
and file writes
    
    camel_catalog_find turns a product or protocol name (postgres, mqtt, 
artemis) into a component; it was outside
    the core set for lack of room in the prefix budget (4,291 of 4,300 
estimated tokens). The budget guards against
    accidental growth, not a model limit: core 5,000, full 9,200, system prompt 
620. Two lines in the system prompt
    from the benchmark traces (CAMEL-24698): write files only with 
camel_write_file, never paste them; the canonical
    YAML DSL shape, since the shorthand a model writes from memory is 
deprecated (CAMEL-24722).
    
    Co-Authored-By: Claude Fable 5.1 <[email protected]>
    Claude-Session: https://claude.ai/code/session_01Bp3538HRBPMQkb5ta9xRaj
    
    * CAMEL-24760: camel-jbang - tui_get_diagram, tui_filter and 
tui_set_log_level leave the core tool set for local models
    
    A tool earns its place in the core set by the questions a local model gets 
asked, not by its size: the topology
    JSON answers how routes relate (the ASCII drawing is for the screen), the 
whole table comes back without a filter,
    and the root log level is a rare request. About 620 characters less in 
every request; the prompt line on the
    log level moves to the full set where the tool is.
    
    Co-Authored-By: Claude Fable 5.1 <[email protected]>
    Claude-Session: https://claude.ai/code/session_01Bp3538HRBPMQkb5ta9xRaj
    
    * CAMEL-24760: camel-jbang - the shared tool test agrees that 
camel_catalog_find is core; the prompt line of tui_set_log_level is asserted 
absent from the core set
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
    
    ---------
    
    Signed-off-by: Claus Ibsen <[email protected]>
    Co-authored-by: Claude Fable 5.1 <[email protected]>
---
 .../dsl/jbang/core/commands/ai/AuthoringTools.java |  1 +
 .../jbang/core/commands/ai/AuthoringToolsTest.java |  5 +++-
 .../camel/dsl/jbang/core/commands/tui/AiPanel.java |  7 ++++--
 .../jbang/core/commands/tui/TuiToolRegistry.java   |  7 ++++--
 .../core/commands/tui/AiPanelPromptBudgetTest.java | 29 +++++++++++++++++++---
 5 files changed, 41 insertions(+), 8 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringTools.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringTools.java
index 3a190baef33b..f63629556da2 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringTools.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringTools.java
@@ -95,6 +95,7 @@ public final class AuthoringTools {
                         false)
                 .param("limit", "integer", "Maximum matches per kind (default 
10)", false)
                 .param("camelVersion", "string", VERSION_DESC, false)
+                .core(true)
                 .executor((ctx, args) -> {
                     applyVersion(ctx, args);
                     return CatalogDocs.find(ctx.catalog(), args.get("term"), 
args.get("kind"),
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringToolsTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringToolsTest.java
index 4e0805dc9f30..5408d5b14286 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringToolsTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringToolsTest.java
@@ -90,8 +90,11 @@ class AuthoringToolsTest {
             assertTrue(ToolRegistry.findTool(reading).isReadOnly(), reading);
         }
         assertTrue(ToolRegistry.findTool("camel_control").isDestructive());
-        assertFalse(ToolRegistry.findTool("camel_catalog_find").isCore(), "not 
needed by a small model");
+        // the core subset is what a local model gets: find turns a product or 
protocol into a component, the first
+        // question of most tasks (CAMEL-24760); starting an integration is 
the TUI's own run form there
+        assertTrue(ToolRegistry.findTool("camel_catalog_find").isCore(), "a 
local model asks for mqtt, not paho-mqtt5");
         assertTrue(ToolRegistry.findTool("camel_write_file").isCore());
+        assertFalse(ToolRegistry.findTool("camel_run").isCore(), "not needed 
by a small model");
     }
 
     @Test
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java
index 1a45751f4eaa..9d5b1b6f831b 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanel.java
@@ -2898,8 +2898,11 @@ class AiPanel {
         sb.append(
                 "retry a rejected write. Invalid YAML/properties is refused 
with errors: fix them (camel_catalog_doc has the ");
         sb.append("option names)\n");
-        sb.append("- tui_set_log_level is the app's root logger, only when 
asked; 'log at WARN' in a route is the log ");
-        sb.append("step's loggingLevel in the source\n");
+        sb.append("- Write files only with camel_write_file; never paste file 
contents in the answer\n");
+        sb.append("- YAML DSL shape: a step is `- log: {message: ...}`, `- to: 
{uri: ...}`, an expression goes under ");
+        sb.append("expression: (`- setBody: {expression: {simple: ...}}`); the 
shorthand forms are deprecated\n");
+        sb.append("- 'log at WARN' in a route is the log step's loggingLevel 
in the source");
+        sb.append(useCoreTools() ? "\n" : "; tui_set_log_level is the app's 
root logger, only when asked\n");
         sb.append("- Simple: functions inside ${...}, operators between them: 
${header.a} == 'b', ");
         sb.append("${body} ?: 'none'; camel_eval_expression checks one, 
camel_catalog_doc simple lists them\n");
         if (!useCoreTools()) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
index 035a8b03a6b7..ea7f8f695cbd 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
@@ -157,10 +157,13 @@ class TuiToolRegistry {
     static final String VALIDATE_TOOL = "camel_validate_source";
 
     /** The TUI's own tools in the core subset; the shared tools add those 
flagged core in the registry. */
+    // CAMEL-24760: a tool earns its place here by the questions a local model 
gets asked, not by its size.
+    // tui_get_diagram is the ASCII drawing of what tui_get_topology returns 
as JSON, tui_filter a screen nicety
+    // (tui_get_table returns the whole table), tui_set_log_level a rare 
request the prompt guards anyway.
     private static final Set<String> CORE_TUI_TOOLS = Set.of(
-            "tui_get_state", "tui_get_options", "tui_get_table", 
"tui_get_diagram", "tui_get_topology",
+            "tui_get_state", "tui_get_options", "tui_get_table", 
"tui_get_topology",
             "tui_get_processor_detail", "tui_get_history", "tui_get_spans", 
"tui_send_message",
-            "tui_get_readme", "tui_navigate", "tui_set_log_level", 
"tui_filter", "tui_get_status", "tui_infra");
+            "tui_get_readme", "tui_navigate", "tui_get_status", "tui_infra");
 
     static final Set<String> CORE_TOOLS = Stream.concat(
             CORE_TUI_TOOLS.stream(),
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanelPromptBudgetTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanelPromptBudgetTest.java
index 1536f25b26cf..2bfd77cc224f 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanelPromptBudgetTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/AiPanelPromptBudgetTest.java
@@ -39,13 +39,16 @@ class AiPanelPromptBudgetTest {
     // and from 3900 when the authoring tools became the camel_* set shared 
with camel-jbang-mcp (CAMEL-24695):
     // their schemas carry the directory and name arguments a server without a 
selection needs, and
     // camel_error_diagnose joined the core set
-    static final int CORE_BUDGET_TOKENS = 4_300;
+    // raised to 5000 when camel_catalog_find joined the core set 
(CAMEL-24760): the budget guards against accidental
+    // growth of the prefix, a 32k context leaves ample room
+    static final int CORE_BUDGET_TOKENS = 5_000;
     /** Measured ~6.9k tokens for 47 tools. */
     // raised from 7500 with tui_write_file and tui_validate_source
     // and from 7900 with the shared camel_* set (camel_catalog_find, 
camel_run and camel_error_diagnose added)
     // and from 8500 when camel_catalog_doc gained the api kind (CAMEL-24708): 
its kind argument names the core
     // classes and script languages the API reference covers, which is what 
makes a model ask for them
-    static final int FULL_BUDGET_TOKENS = 8_700;
+    // raised with the core budget (CAMEL-24760)
+    static final int FULL_BUDGET_TOKENS = 9_200;
 
     record Prefix(String mode, int tools, long promptChars, long toolChars) {
 
@@ -122,8 +125,28 @@ class AiPanelPromptBudgetTest {
         // the tool definitions already describe every tool; repeating them in 
prose doubles the cost
         // 450 before the file editing guidance (two bullets) was added
         // 530 before the tools were split into camel_* and tui_* in the 
introduction
-        assertTrue(AiPanel.estimateTokens(prompt.length()) <= 545,
+        // 545 before the file-write and canonical YAML shape lines 
(CAMEL-24760)
+        assertTrue(AiPanel.estimateTokens(prompt.length()) <= 620,
                 "system prompt grew to ~" + 
AiPanel.estimateTokens(prompt.length()) + " tokens");
         assertTrue(!prompt.contains("- tui_get_table:"), "system prompt must 
not list the tools again");
     }
+
+    @Test
+    void thePromptOnlyMentionsTheToolsOfTheActiveSet() {
+        // tui_set_log_level left the core set (CAMEL-24760): its prompt line 
goes with it, a local model must not be
+        // told about a tool it cannot call
+        AiPanel panel = new AiPanel();
+        panel.setToolRegistryForTesting(new TuiToolRegistry(null));
+        panel.setToolModeForTesting(AiPanel.TOOL_MODE_CORE);
+        String core = panel.systemPromptForTesting();
+        panel.setToolModeForTesting(AiPanel.TOOL_MODE_FULL);
+        String full = panel.systemPromptForTesting();
+
+        assertTrue(full.contains("tui_set_log_level is the app's root 
logger"), "the full set has the tool");
+        assertTrue(!core.contains("tui_set_log_level"), "the core set has 
not");
+        // what both sets get: the file write rule and the canonical YAML shape
+        for (String prompt : List.of(core, full)) {
+            assertTrue(prompt.contains("camel_write_file"), "write files with 
the tool");
+        }
+    }
 }

Reply via email to