oscerd commented on code in PR #27422:
URL: https://github.com/apache/camel/pull/27422#discussion_r4193615221


##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringTools.java:
##########
@@ -160,6 +160,10 @@ static void register(Consumer<ToolDescriptor> registry) {
                 .param("content", "string", "The source to validate", false)
                 .param("camelVersion", "string", VERSION_DESC, false)
                 .core(true)
+                // the same content gets the same answer: a model that 
validates it again and again is stuck (CAMEL-25371)
+                .deterministicWhen("content")

Review Comment:
   **With `directory`, validating the same content is not deterministic**
   
   When `directory` is passed with `content`, the answer depends on other 
files: `SourceValidator.validate` then runs `BeanDeclarations.scan`, 
`validateResourceRefs`, `OpenApiVerbs.bodylessEndpoints` and 
`EndpointConsumerChecks.validateYamlConsumers`, which read the sibling files. 
`ToolDescriptor#deterministic` itself says that "a tool that reads ... the 
files ... is not" deterministic.
   
   A concrete case on `camel tui --mcp`:
   1. Validate `orders.camel.yaml` content with `to: direct:audit`, with 
`directory`. The answer says no route consumes `direct:audit`.
   2. Validate it again: the full answer again.
   3. Do what the error says: write `audit.camel.yaml` with `from: 
direct:audit` (the write path allows the missing consumer, CAMEL-24955).
   4. Validate the unchanged `orders` content again. `repeatOf` answers with 
the note before the tool runs ("Its answer does not change ... change the line 
the error names"), although the real answer is now `valid: true`, and the line 
it points at is correct.
   
   The same applies after declaring a missing bean in a sibling file or writing 
a referenced resource. Possible fixes: treat the call as deterministic only 
when `content` is given and `directory` is not, forget the counts when a 
non-read-only tool runs, or put a fingerprint of the directory into the key. A 
test along the lines of steps 1-4 would pin it down.



##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/RepeatedToolCalls.java:
##########
@@ -51,7 +51,7 @@ public final class RepeatedToolCalls {
      * identical calls.
      */
     public synchronized JsonObject repeatOf(ToolDescriptor tool, Map<String, 
?> args) {
-        if (tool == null || !tool.isDeterministic()) {
+        if (tool == null || !tool.isDeterministic(args)) {

Review Comment:
   **The repeat key trims `content`, so a whitespace-only fix counts as the 
same call**
   
   `key()` trims every value. That suits short catalog arguments, but now it 
also applies to `content`, where leading/trailing whitespace can decide the 
result: XML with a newline before `<?xml ...?>` is rejected by 
`XmlChecks.validateXml` ("The processing instruction target matching 
"[xX][mM][lL]" is not allowed"), while the same text without the newline is 
valid. Once the first form has been validated twice, the fix (removing the 
newline) gets the repeat note instead of a validation, because both trim to the 
same key. The key also now holds the whole source text, for up to `MAX_TRACKED` 
entries per session. Keying `content` on a digest of the exact text would fix 
both and still match the byte-identical repeats the benchmark found.



##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/AuthoringTools.java:
##########
@@ -174,8 +178,16 @@ static void register(Consumer<ToolDescriptor> registry) {
                             throw new ToolExecutionException("No such file in 
the directory: " + file);
                         }
                         content = read(path);
+                        return validate(ctx, dir, file, content).toJson();
                     }
-                    return validate(ctx, dir, file, content).toJson();
+                    JsonObject result = validate(ctx, dir, file, content);
+                    if (sameAsOnDisk(ctx, directory, file, content)) {
+                        // a model that meant to change the file validates the 
old version: say so (CAMEL-25371)
+                        result.put("sameAsFile", true);
+                        result.put("note", "This content is the same as " + 
file + " on disk: an edit you meant to make"

Review Comment:
   **The `sameAsFile` note states a missing edit as fact**
   
   The note states a missing edit as a fact, which misleads in two common 
flows: after `camel_write_file` answers with `existingProblems` and the model 
validates the same content to look at them, and when the model reads the file 
with `camel_get_files` and passes that text as `content` to explain a reload 
error. A small model may then believe its write failed and write again. A 
conditional wording keeps the hint for the stuck case, e.g. "This content is 
the same as <file> on disk: if you meant to change the file, that change is not 
in this content." 



##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/ToolDescriptor.java:
##########
@@ -128,6 +145,21 @@ public boolean isDeterministic() {
         return deterministic;
     }
 
+    /**
+     * Whether this call gives the same answer each time: the tool is 
deterministic, or the argument that makes it so.
+     */
+    public boolean isDeterministic(java.util.Map<String, ?> args) {

Review Comment:
   **FQCN where the import already exists**
   
   Minor: `java.util.Map` is already imported in this file, and CLAUDE.md asks 
for imports instead of fully qualified names (the same applies to 
`@org.junit.jupiter.api.io.TempDir java.nio.file.Path` / 
`java.nio.file.Files.writeString` in the new `AuthoringToolsTest` case, where 
those types are already imported).
   
   ```suggestion
       public boolean isDeterministic(Map<String, ?> args) {
   ```



-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to