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");
+ }
+ }
}