Skip to content

Commit 1191862

Browse files
Implementing US #276 interactive mode for models that do not support tools (#286)
* Improved DummyTool and DummyChatModel with some enhancements and needs to toolify LLMs * Added new Util tools classes with an echo tool * Updated all tools providing @p() description so that they will be provided to the LLM in the tools definition block * - Added ToolNotFoundException - Bumped langchain4j version to 1.11.0 * - Added ExecutionJSONObject.java and its test - Updated copyright on ToolNotFoundException * - finally added the full HackerWithoutTool and integrated it in JeddictBrain * Update pom.xml * Update langchain4j version to 1.11.0 * Merged main * Fixed issue with paths on windowns * Fixed issue with paths on windowns * Removed wrong DummyChatModel and fixed the new version * Fixed issue with paths on windowns * Fixed issue with paths on windowns... --------- Co-authored-by: Gaurav Gupta <gaurav.gupta@payara.fish>
1 parent e18f2e7 commit 1191862

48 files changed

Lines changed: 2354 additions & 244 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

pom.xml

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
<properties>
4646
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
4747
<maven.compiler.release>17</maven.compiler.release>
48-
<javalang4j.version>1.10.0</javalang4j.version>
48+
<langchain4j.version>1.11.0</langchain4j.version>
4949
<netbeans.version>RELEASE290</netbeans.version>
5050
</properties>
5151

@@ -287,48 +287,48 @@
287287
<dependency>
288288
<groupId>dev.langchain4j</groupId>
289289
<artifactId>langchain4j-open-ai</artifactId>
290-
<version>${javalang4j.version}</version>
290+
<version>${langchain4j.version}</version>
291291
</dependency>
292292
<dependency>
293293
<groupId>dev.langchain4j</groupId>
294294
<artifactId>langchain4j-ollama</artifactId>
295-
<version>${javalang4j.version}</version>
295+
<version>${langchain4j.version}</version>
296296
</dependency>
297297
<dependency>
298298
<groupId>dev.langchain4j</groupId>
299299
<artifactId>langchain4j-local-ai</artifactId>
300-
<version>${javalang4j.version}-beta18</version>
300+
<version>${langchain4j.version}-beta19</version>
301301
</dependency>
302302
<dependency>
303303
<groupId>dev.langchain4j</groupId>
304304
<artifactId>langchain4j-mistral-ai</artifactId>
305-
<version>${javalang4j.version}</version>
305+
<version>${langchain4j.version}</version>
306306
</dependency>
307307
<dependency>
308308
<groupId>dev.langchain4j</groupId>
309309
<artifactId>langchain4j-anthropic</artifactId>
310-
<version>${javalang4j.version}</version>
310+
<version>${langchain4j.version}</version>
311311
</dependency>
312312
<dependency>
313313
<groupId>dev.langchain4j</groupId>
314314
<artifactId>langchain4j-google-ai-gemini</artifactId>
315-
<version>${javalang4j.version}</version>
315+
<version>${langchain4j.version}</version>
316316
</dependency>
317317
<dependency>
318318
<groupId>dev.langchain4j</groupId>
319319
<artifactId>langchain4j-agentic</artifactId>
320-
<version>${javalang4j.version}-beta18</version>
320+
<version>${langchain4j.version}-beta19</version>
321321
<type>jar</type>
322322
</dependency>
323323
<dependency>
324324
<groupId>dev.langchain4j</groupId>
325325
<artifactId>langchain4j</artifactId>
326-
<version>${javalang4j.version}</version>
326+
<version>${langchain4j.version}</version>
327327
</dependency>
328328
<dependency>
329329
<groupId>dev.langchain4j</groupId>
330330
<artifactId>langchain4j-http-client-jdk</artifactId>
331-
<version>${javalang4j.version}</version>
331+
<version>${langchain4j.version}</version>
332332
</dependency>
333333
<dependency>
334334
<groupId>com.knuddels</groupId>
@@ -338,13 +338,38 @@
338338
<dependency>
339339
<groupId>org.commonmark</groupId>
340340
<artifactId>commonmark</artifactId>
341-
<version>0.27.0</version>
341+
<version>0.27.1</version>
342342
</dependency>
343343
<dependency>
344344
<groupId>org.json</groupId>
345345
<artifactId>json</artifactId>
346-
<version>20240303</version>
346+
<version>20251224</version>
347347
</dependency>
348+
<dependency>
349+
<!--
350+
TOON
351+
-->
352+
<groupId>tools.jackson.core</groupId>
353+
<artifactId>jackson-databind</artifactId>
354+
<version>3.1.0</version>
355+
</dependency>
356+
<dependency>
357+
<groupId>tools.jackson.module</groupId>
358+
<artifactId>jackson-module-afterburner</artifactId>
359+
<version>3.1.0</version>
360+
</dependency>
361+
<dependency>
362+
<groupId>com.fasterxml.jackson.core</groupId>
363+
<artifactId>jackson-annotations</artifactId>
364+
<version>2.21</version>
365+
</dependency>
366+
367+
<dependency>
368+
<groupId>dev.toonformat</groupId>
369+
<artifactId>jtoon</artifactId>
370+
<version>1.0.8</version>
371+
</dependency>
372+
<!-- -->
348373
<dependency>
349374
<groupId>org.jfree</groupId>
350375
<artifactId>jfreechart</artifactId>
@@ -691,7 +716,7 @@
691716
<dependency>
692717
<groupId>com.github.stefanofornari</groupId>
693718
<artifactId>lambda-loop</artifactId>
694-
<version>0.5.0</version>
719+
<version>0.6.1</version>
695720
</dependency>
696721
<dependency>
697722
<groupId>net.bytebuddy</groupId>

src/main/java/io/github/jeddict/ai/agent/EditorTools.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package io.github.jeddict.ai.agent;
1717

18+
import dev.langchain4j.agent.tool.P;
1819
import dev.langchain4j.agent.tool.Tool;
1920
import java.io.IOException;
2021
import java.util.regex.Pattern;
@@ -39,8 +40,14 @@ public EditorTools(final String basedir) throws IOException {
3940
* @return a status message
4041
*/
4142
@Tool("Insert a line of code at a given line number (0-based) in a file by path")
42-
public String insertLineInFile(String path, int lineNumber, String lineText)
43-
throws Exception {
43+
public String insertLineInFile(
44+
@P("the file path relative to the project")
45+
final String path,
46+
@P("the line number (0-based) where to insert the text")
47+
final int lineNumber,
48+
@P("the line to insert")
49+
final String lineText
50+
) throws Exception {
4451
progress("✏️ Inserting line at " + lineNumber + " in file: " + path);
4552

4653
return withDocument(path, doc -> {
@@ -77,8 +84,14 @@ public String insertLineInFile(String path, int lineNumber, String lineText)
7784
* @return status message
7885
*/
7986
@Tool("Insert a line of code at a given line number (0-based) in a file by path")
80-
public String insertLineAfterMethod(String path, String methodName, String lineText)
81-
throws Exception {
87+
public String insertLineAfterMethod(
88+
@P("the file path relative to the project")
89+
final String path,
90+
@P("the method or constructor name where to insert after")
91+
final String methodName,
92+
@P("the text to insert as a new line")
93+
final String lineText
94+
) throws Exception {
8295
progress("✏️ Inserting line after method '" + methodName + "' in file: " + path);
8396
String content = withDocument(path, doc -> doc.getText(0, doc.getLength()), false);
8497
if (content.startsWith("Could not")) {
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* Copyright 2026 the original author or authors from the Jeddict project (https://jeddict.github.io/).
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package io.github.jeddict.ai.agent;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
import org.json.JSONArray;
22+
import org.json.JSONObject;
23+
import static ste.lloop.Loop.on;
24+
25+
/**
26+
* Object to represent a tool execution. It basically consists of
27+
* a name and a list of arguments. Each argument can be a string or an array
28+
* of strings (for now, more types may be supported in the future).
29+
* If an error arises while converting the arguments to JSON, it falls back
30+
* to an execution of the tool "echo" with a proper error message.
31+
*/
32+
public class ExecutionJSONObject {
33+
34+
public String name;
35+
public JSONObject arguments;
36+
37+
public ExecutionJSONObject(final String name) {
38+
this(name, "");
39+
}
40+
41+
public ExecutionJSONObject(final String name, final String content) {
42+
try {
43+
this.name = name;
44+
this.arguments = new JSONObject("{" + content + "}");
45+
} catch (final Throwable t) {
46+
this.name = "echo";
47+
this.arguments = new JSONObject();
48+
arguments.put(
49+
"message",
50+
"ERR error parsing tool execution for %s, make sure it is in well formed JSON:\n%s"
51+
.formatted(name, content)
52+
);
53+
}
54+
}
55+
56+
public String name() {
57+
return name;
58+
}
59+
60+
public Object[] arguments() {
61+
final List values = new ArrayList();
62+
on(arguments.keys()).loop((key) -> {
63+
values.add(arguments.get(key));
64+
});
65+
return values.toArray();
66+
}
67+
68+
public Object[] arguments(String... args) {
69+
final Object[] values = new Object[args.length];
70+
on(args).loop((i, arg) -> {
71+
values[i] = arguments.opt(arg);
72+
if (values[i] instanceof JSONArray jarray) {
73+
values[i] = jarray.toList();
74+
} else if (values[i] == JSONObject.NULL) {
75+
values[i] = null;
76+
}
77+
});
78+
return values;
79+
}
80+
}

src/main/java/io/github/jeddict/ai/agent/ExplorationTools.java

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
package io.github.jeddict.ai.agent;
1818

19+
import dev.langchain4j.agent.tool.P;
1920
import dev.langchain4j.agent.tool.Tool;
2021
import java.util.List;
2122
import java.util.Set;
@@ -94,7 +95,7 @@ private static boolean isJavaFile(String path) {
9495
* listClassesInFile("src/main/java/com/example/MyClass.java");
9596
* // -> "Class: com.example.MyClass"
9697
* </pre>
97-
*
98+
*
9899
* <p><b>Output format:</b></p>
99100
* <pre>
100101
* Class: fully.qualified.ClassName
@@ -110,7 +111,10 @@ private static boolean isJavaFile(String path) {
110111
*/
111112
@Tool("JAVA ONLY: List all classes declared in a given Java file by path")
112113
@ToolPolicy(READONLY)
113-
public String listClassesInFile(String path) throws Exception {
114+
public String listClassesInFile(
115+
@P("the file path relative to the project")
116+
final String path
117+
) throws Exception {
114118

115119
if (!isJavaFile(path)) {
116120
return "Not a Java source file: " + path;
@@ -143,7 +147,7 @@ public String listClassesInFile(String path) throws Exception {
143147
* listMethodsInFile("src/main/java/com/example/MyClass.java");
144148
* // -> "Method: public void sayHello()"
145149
* </pre>
146-
*
150+
*
147151
* <p><b>Output format:</b></p>
148152
* <pre>
149153
* Method: methodSignature
@@ -159,7 +163,10 @@ public String listClassesInFile(String path) throws Exception {
159163
*/
160164
@Tool("JAVA ONLY: List all methods of a class in a given Java file by path")
161165
@ToolPolicy(READONLY)
162-
public String listMethodsInFile(String path) throws Exception {
166+
public String listMethodsInFile(
167+
@P("the file path relative to the project")
168+
final String path
169+
) throws Exception {
163170

164171
if (!isJavaFile(path)) {
165172
return "Not a Java source file: " + path;
@@ -206,7 +213,7 @@ public String listMethodsInFile(String path) throws Exception {
206213
* </ul>
207214
* </li>
208215
* </ol>
209-
*
216+
*
210217
* <p>
211218
* The search is performed using the symbol's <b>simple name</b> only. Fully
212219
* qualified names are not required and are not matched directly.</p>
@@ -220,15 +227,15 @@ public String listMethodsInFile(String path) throws Exception {
220227
* <li>Overloaded methods are returned by name only, without signature
221228
* differentiation.</li>
222229
* </ul>
223-
*
230+
*
224231
* <p>
225232
* <b>Examples:</b></p>
226233
* <pre>
227234
* searchSymbol("UserService"); // Class: com.example.service.UserService
228235
* searchSymbol("findUser"); // Method: com.example.service.UserService.findUser
229236
* searchSymbol("userRepository");// Field: com.example.service.UserService.userRepository
230237
* </pre>
231-
*
238+
*
232239
* <p><b>Output format:</b></p>
233240
* <pre>
234241
* Class: fully.qualified.ClassName
@@ -254,8 +261,10 @@ public String listMethodsInFile(String path) throws Exception {
254261
"If no symbol is found, returns 'No matches found.'. " +
255262
"If the project has no Java sources, returns an explanatory message.")
256263
@ToolPolicy(READONLY)
257-
public String searchSymbol(String symbolName)
258-
throws Exception {
264+
public String searchSymbol(
265+
@P("simple name of the Java class, method, or field to search for")
266+
final String symbolName
267+
) throws Exception {
259268
progress("Searching symbol " + symbolName);
260269

261270
Sources sources = lookup.lookup(Sources.class);
@@ -353,7 +362,7 @@ public String searchSymbol(String symbolName)
353362
* NetBeans {@code WhereUsedQuery}.
354363
* If no usages are found, {@code "No usages found."} is returned.
355364
* </p>
356-
*
365+
*
357366
* @param path relative path to a .java file
358367
* @param symbolName Java symbol name
359368
* @return formatted usage list
@@ -365,8 +374,12 @@ public String searchSymbol(String symbolName)
365374
+ "If no usages are found, returns 'No usages found.'."
366375
)
367376
@ToolPolicy(READONLY)
368-
public String findUsages(String path, String symbolName)
369-
throws Exception {
377+
public String findUsages(
378+
@P("path relative path to a .java file")
379+
final String path,
380+
@P("symbolName Java symbol name")
381+
final String symbolName
382+
) throws Exception {
370383
if (!isJavaFile(path)) {
371384
return "Not a Java source file: " + path;
372385
}

0 commit comments

Comments
 (0)