diff --git a/CMakeLists.txt b/CMakeLists.txt
index d51512f..9fa4f36 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -151,7 +151,8 @@ add_qtc_plugin(QodeAssist
tools/BuildProjectTool.hpp tools/BuildProjectTool.cpp
tools/ExecuteTerminalCommandTool.hpp tools/ExecuteTerminalCommandTool.cpp
tools/ProjectSearchTool.hpp tools/ProjectSearchTool.cpp
- tools/FindAndReadFileTool.hpp tools/FindAndReadFileTool.cpp
+ tools/FindFileTool.hpp tools/FindFileTool.cpp
+ tools/ReadFileTool.hpp tools/ReadFileTool.cpp
tools/FileSearchUtils.hpp tools/FileSearchUtils.cpp
tools/TodoTool.hpp tools/TodoTool.cpp
)
diff --git a/settings/SettingsConstants.hpp b/settings/SettingsConstants.hpp
index 1ca2242..270105b 100644
--- a/settings/SettingsConstants.hpp
+++ b/settings/SettingsConstants.hpp
@@ -99,14 +99,17 @@ const char CA_ENABLE_CHAT_IN_BOTTOM_TOOLBAR[] = "QodeAssist.caEnableChatInBottom
const char CA_ENABLE_CHAT_IN_NAVIGATION_PANEL[] = "QodeAssist.caEnableChatInNavigationPanel";
const char CA_ENABLE_CHAT_TOOLS[] = "QodeAssist.caEnableChatTools";
const char CA_USE_TOOLS[] = "QodeAssist.caUseTools";
-const char CA_ALLOW_FILE_SYSTEM_READ[] = "QodeAssist.caAllowFileSystemRead";
-const char CA_ALLOW_FILE_SYSTEM_WRITE[] = "QodeAssist.caAllowFileSystemWrite";
-const char CA_ALLOW_NETWORK_ACCESS[] = "QodeAssist.caAllowNetworkAccess";
const char CA_ALLOW_ACCESS_OUTSIDE_PROJECT[] = "QodeAssist.caAllowAccessOutsideProject";
-const char CA_ENABLE_EDIT_FILE_TOOL[] = "QodeAssist.caEnableEditFileTool";
-const char CA_ENABLE_BUILD_PROJECT_TOOL[] = "QodeAssist.caEnableBuildProjectTool";
-const char CA_ENABLE_TERMINAL_COMMAND_TOOL[] = "QodeAssist.caEnableTerminalCommandTool";
-const char CA_ENABLE_TODO_TOOL[] = "QodeAssist.caEnableTodoTool";
+const char CA_ENABLE_LIST_PROJECT_FILES_TOOL[] = "QodeAssist.caEnableListProjectFilesTool";
+const char CA_ENABLE_FIND_FILE_TOOL[] = "QodeAssist.caEnableFindFileTool";
+const char CA_ENABLE_READ_FILE_TOOL[] = "QodeAssist.caEnableReadFileTool";
+const char CA_ENABLE_PROJECT_SEARCH_TOOL[] = "QodeAssist.caEnableProjectSearchTool";
+const char CA_ENABLE_CREATE_NEW_FILE_TOOL[] = "QodeAssist.caEnableCreateNewFileTool";
+const char CA_ENABLE_GET_ISSUES_LIST_TOOL[] = "QodeAssist.caEnableGetIssuesListTool";
+const char CA_ENABLE_EDIT_FILE_TOOL[] = "QodeAssist.caEnableEditFileToolV2";
+const char CA_ENABLE_BUILD_PROJECT_TOOL[] = "QodeAssist.caEnableBuildProjectToolV2";
+const char CA_ENABLE_TERMINAL_COMMAND_TOOL[] = "QodeAssist.caEnableTerminalCommandToolV2";
+const char CA_ENABLE_TODO_TOOL[] = "QodeAssist.caEnableTodoToolV2";
const char CA_ALLOWED_TERMINAL_COMMANDS[] = "QodeAssist.caAllowedTerminalCommands";
const char CA_ALLOWED_TERMINAL_COMMANDS_LINUX[] = "QodeAssist.caAllowedTerminalCommandsLinux";
const char CA_ALLOWED_TERMINAL_COMMANDS_MACOS[] = "QodeAssist.caAllowedTerminalCommandsMacOS";
diff --git a/settings/ToolsSettings.cpp b/settings/ToolsSettings.cpp
index eb5923a..c0261f7 100644
--- a/settings/ToolsSettings.cpp
+++ b/settings/ToolsSettings.cpp
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2024-2025 Petr Mironychev
*
* This file is part of QodeAssist.
@@ -42,66 +42,80 @@ ToolsSettings::ToolsSettings()
setDisplayName(Tr::tr("Tools"));
- allowFileSystemRead.setSettingsKey(Constants::CA_ALLOW_FILE_SYSTEM_READ);
- allowFileSystemRead.setLabelText(Tr::tr("Allow File System Read Access for tools"));
- allowFileSystemRead.setToolTip(
- Tr::tr("Allow tools to read files from disk (project files, open editors)"));
- allowFileSystemRead.setDefaultValue(true);
-
- allowFileSystemWrite.setSettingsKey(Constants::CA_ALLOW_FILE_SYSTEM_WRITE);
- allowFileSystemWrite.setLabelText(Tr::tr("Allow File System Write Access for tools"));
- allowFileSystemWrite.setToolTip(
- Tr::tr("Allow tools to write and modify files on disk (WARNING: Use with caution!)"));
- allowFileSystemWrite.setDefaultValue(false);
-
- allowNetworkAccess.setSettingsKey(Constants::CA_ALLOW_NETWORK_ACCESS);
- allowNetworkAccess.setLabelText(Tr::tr("Allow Network Access for tools"));
- allowNetworkAccess.setToolTip(
- Tr::tr("Allow tools to make network requests (e.g., execute commands like git, curl, wget). "
- "Required for ExecuteTerminalCommandTool with network-capable commands."));
- allowNetworkAccess.setDefaultValue(false);
-
allowAccessOutsideProject.setSettingsKey(Constants::CA_ALLOW_ACCESS_OUTSIDE_PROJECT);
allowAccessOutsideProject.setLabelText(Tr::tr("Allow file access outside project"));
allowAccessOutsideProject.setToolTip(
- Tr::tr("Allow tools to access (read/write) files outside the project scope (system "
- "headers, Qt files, external libraries)"));
- allowAccessOutsideProject.setDefaultValue(true);
+ Tr::tr("Allow tools to read, write, and create files outside the project scope "
+ "(system headers, Qt files, external libraries)."));
+ allowAccessOutsideProject.setDefaultValue(false);
autoApplyFileEdits.setSettingsKey(Constants::CA_AUTO_APPLY_FILE_EDITS);
autoApplyFileEdits.setLabelText(Tr::tr("Automatically apply file edits"));
autoApplyFileEdits.setToolTip(
- Tr::tr("When enabled, file edits suggested by AI will be applied automatically. "
- "When disabled, you will need to manually approve each edit."));
+ Tr::tr("When enabled, file edits suggested by AI are applied immediately. "
+ "When disabled, each edit is staged for manual approval."));
autoApplyFileEdits.setDefaultValue(false);
+ enableListProjectFilesTool.setSettingsKey(Constants::CA_ENABLE_LIST_PROJECT_FILES_TOOL);
+ enableListProjectFilesTool.setLabelText(Tr::tr("List Project Files"));
+ enableListProjectFilesTool.setToolTip(
+ Tr::tr("Lists every source file tracked by the active Qt Creator project(s)."));
+ enableListProjectFilesTool.setDefaultValue(true);
+
+ enableFindFileTool.setSettingsKey(Constants::CA_ENABLE_FIND_FILE_TOOL);
+ enableFindFileTool.setLabelText(Tr::tr("Find File"));
+ enableFindFileTool.setToolTip(
+ Tr::tr("Locates a file in the project by name or partial path. Returns paths only, "
+ "without file content."));
+ enableFindFileTool.setDefaultValue(true);
+
+ enableReadFileTool.setSettingsKey(Constants::CA_ENABLE_READ_FILE_TOOL);
+ enableReadFileTool.setLabelText(Tr::tr("Read File"));
+ enableReadFileTool.setToolTip(
+ Tr::tr("Reads the content of a file by absolute path or path relative to the project root."));
+ enableReadFileTool.setDefaultValue(true);
+
+ enableProjectSearchTool.setSettingsKey(Constants::CA_ENABLE_PROJECT_SEARCH_TOOL);
+ enableProjectSearchTool.setLabelText(Tr::tr("Search in Project"));
+ enableProjectSearchTool.setToolTip(
+ Tr::tr("Searches project files for text occurrences or C++ symbol definitions."));
+ enableProjectSearchTool.setDefaultValue(true);
+
+ enableCreateNewFileTool.setSettingsKey(Constants::CA_ENABLE_CREATE_NEW_FILE_TOOL);
+ enableCreateNewFileTool.setLabelText(Tr::tr("Create New File"));
+ enableCreateNewFileTool.setToolTip(
+ Tr::tr("Creates a new empty file at the given absolute path, making missing directories."));
+ enableCreateNewFileTool.setDefaultValue(true);
+
enableEditFileTool.setSettingsKey(Constants::CA_ENABLE_EDIT_FILE_TOOL);
- enableEditFileTool.setLabelText(Tr::tr("Enable Edit File Tool (Experimental)"));
+ enableEditFileTool.setLabelText(Tr::tr("Edit File"));
enableEditFileTool.setToolTip(
- Tr::tr("Enable the experimental edit_file tool that allows AI to directly modify files. "
- "This feature is under testing and may have unexpected behavior."));
- enableEditFileTool.setDefaultValue(false);
+ Tr::tr("Applies find-and-replace edits to files. See \"Automatically apply file edits\" "
+ "to control whether edits apply immediately or wait for review."));
+ enableEditFileTool.setDefaultValue(true);
enableBuildProjectTool.setSettingsKey(Constants::CA_ENABLE_BUILD_PROJECT_TOOL);
- enableBuildProjectTool.setLabelText(Tr::tr("Enable Build Project Tool (Experimental)"));
+ enableBuildProjectTool.setLabelText(Tr::tr("Build Project"));
enableBuildProjectTool.setToolTip(
- Tr::tr("Enable the experimental build_project tool that allows AI to build the current "
- "project. This feature is under testing and may have unexpected behavior."));
- enableBuildProjectTool.setDefaultValue(false);
+ Tr::tr("Triggers a build of the active Qt Creator project and reports the result."));
+ enableBuildProjectTool.setDefaultValue(true);
+
+ enableGetIssuesListTool.setSettingsKey(Constants::CA_ENABLE_GET_ISSUES_LIST_TOOL);
+ enableGetIssuesListTool.setLabelText(Tr::tr("Get Issues List"));
+ enableGetIssuesListTool.setToolTip(
+ Tr::tr("Reads compiler/clang diagnostics from Qt Creator's Issues panel."));
+ enableGetIssuesListTool.setDefaultValue(true);
enableTerminalCommandTool.setSettingsKey(Constants::CA_ENABLE_TERMINAL_COMMAND_TOOL);
- enableTerminalCommandTool.setLabelText(Tr::tr("Enable Terminal Command Tool (Experimental)"));
+ enableTerminalCommandTool.setLabelText(Tr::tr("Execute Terminal Command"));
enableTerminalCommandTool.setToolTip(
- Tr::tr("Enable the experimental execute_terminal_command tool that allows AI to execute "
- "terminal commands from the allowed list. This feature is under testing and may have "
- "unexpected behavior."));
- enableTerminalCommandTool.setDefaultValue(false);
+ Tr::tr("Runs a command from the OS-specific allowed list below, in the project directory."));
+ enableTerminalCommandTool.setDefaultValue(true);
enableTodoTool.setSettingsKey(Constants::CA_ENABLE_TODO_TOOL);
- enableTodoTool.setLabelText(Tr::tr("Enable Todo Tool"));
+ enableTodoTool.setLabelText(Tr::tr("Todo"));
enableTodoTool.setToolTip(
- Tr::tr("Enable the todo_tool that helps AI track and organize multi-step tasks. "
- "Useful for complex refactoring, debugging, and feature implementation workflows."));
+ Tr::tr("Lets the AI maintain a session-scoped todo list for multi-step workflows."));
enableTodoTool.setDefaultValue(true);
allowedTerminalCommandsLinux.setSettingsKey(Constants::CA_ALLOWED_TERMINAL_COMMANDS_LINUX);
@@ -159,24 +173,30 @@ ToolsSettings::ToolsSettings()
Row{Stretch{1}, resetToDefaults},
Space{8},
Group{
- title(Tr::tr("Tool Settings")),
- Column{
- allowFileSystemRead,
- allowFileSystemWrite,
- allowNetworkAccess,
- allowAccessOutsideProject
- }},
- Space{8},
- Group{
- title(Tr::tr("Experimental Features")),
+ title(Tr::tr("Tools")),
Column{
+ enableListProjectFilesTool,
+ enableFindFileTool,
+ enableReadFileTool,
+ enableProjectSearchTool,
+ enableCreateNewFileTool,
enableEditFileTool,
enableBuildProjectTool,
+ enableGetIssuesListTool,
enableTerminalCommandTool,
- enableTodoTool,
- currentOsCommands,
- terminalCommandTimeout,
- autoApplyFileEdits}},
+ enableTodoTool}},
+ Space{8},
+ Group{
+ title(Tr::tr("Tool Settings")),
+ Column{
+ allowAccessOutsideProject,
+ Space{4},
+ Group{
+ title(Tr::tr("Edit File")),
+ Column{autoApplyFileEdits}},
+ Group{
+ title(Tr::tr("Execute Terminal Command")),
+ Column{currentOsCommands, terminalCommandTimeout}}}},
Stretch{1}};
});
}
@@ -200,13 +220,16 @@ void ToolsSettings::resetSettingsToDefaults()
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
- resetAspect(allowFileSystemRead);
- resetAspect(allowFileSystemWrite);
- resetAspect(allowNetworkAccess);
resetAspect(allowAccessOutsideProject);
resetAspect(autoApplyFileEdits);
+ resetAspect(enableListProjectFilesTool);
+ resetAspect(enableFindFileTool);
+ resetAspect(enableReadFileTool);
+ resetAspect(enableProjectSearchTool);
+ resetAspect(enableCreateNewFileTool);
resetAspect(enableEditFileTool);
resetAspect(enableBuildProjectTool);
+ resetAspect(enableGetIssuesListTool);
resetAspect(enableTerminalCommandTool);
resetAspect(enableTodoTool);
resetAspect(allowedTerminalCommandsLinux);
diff --git a/settings/ToolsSettings.hpp b/settings/ToolsSettings.hpp
index a447a64..356ac0f 100644
--- a/settings/ToolsSettings.hpp
+++ b/settings/ToolsSettings.hpp
@@ -32,21 +32,24 @@ public:
ButtonAspect resetToDefaults{this};
- Utils::BoolAspect allowFileSystemRead{this};
- Utils::BoolAspect allowFileSystemWrite{this};
- Utils::BoolAspect allowNetworkAccess{this};
Utils::BoolAspect allowAccessOutsideProject{this};
+ Utils::BoolAspect autoApplyFileEdits{this};
- // Experimental features
+ Utils::BoolAspect enableListProjectFilesTool{this};
+ Utils::BoolAspect enableFindFileTool{this};
+ Utils::BoolAspect enableReadFileTool{this};
+ Utils::BoolAspect enableProjectSearchTool{this};
+ Utils::BoolAspect enableCreateNewFileTool{this};
Utils::BoolAspect enableEditFileTool{this};
Utils::BoolAspect enableBuildProjectTool{this};
+ Utils::BoolAspect enableGetIssuesListTool{this};
Utils::BoolAspect enableTerminalCommandTool{this};
Utils::BoolAspect enableTodoTool{this};
+
Utils::StringAspect allowedTerminalCommandsLinux{this};
Utils::StringAspect allowedTerminalCommandsMacOS{this};
Utils::StringAspect allowedTerminalCommandsWindows{this};
Utils::IntegerAspect terminalCommandTimeout{this};
- Utils::BoolAspect autoApplyFileEdits{this};
private:
void setupConnections();
diff --git a/tools/BuildProjectTool.cpp b/tools/BuildProjectTool.cpp
index ede39bb..d709b5e 100644
--- a/tools/BuildProjectTool.cpp
+++ b/tools/BuildProjectTool.cpp
@@ -71,13 +71,10 @@ QString BuildProjectTool::displayName() const
QString BuildProjectTool::description() const
{
- return "Build the current project in Qt Creator and wait for completion. "
- "Optionally run the project after successful build. "
- "Returns build status (success/failure) and any compilation errors/warnings after "
- "the build finishes. "
- "Optional 'rebuild' parameter: set to true to force a clean rebuild (default: false). "
- "Optional 'run_after_build' parameter: set to true to run the project after successful build (default: false). "
- "Note: This operation may take some time depending on project size.";
+ return "Build the active Qt Creator project using its current build configuration and block "
+ "until the build finishes. Returns success/failure along with the full compiler output "
+ "(stdout + stderr). Use `get_issues_list` afterwards to get structured diagnostics. "
+ "This call is blocking and may take a long time for large projects.";
}
QJsonObject BuildProjectTool::parametersSchema() const
diff --git a/tools/CreateNewFileTool.cpp b/tools/CreateNewFileTool.cpp
index 35b1eba..6013c3f 100644
--- a/tools/CreateNewFileTool.cpp
+++ b/tools/CreateNewFileTool.cpp
@@ -49,10 +49,10 @@ QString CreateNewFileTool::displayName() const
QString CreateNewFileTool::description() const
{
- return "Create a new empty file at the specified path. "
- "If the directory path does not exist, it will be created automatically. "
- "Provide absolute file path. After creating files, add the file "
- "to the project file";
+ return "Create a new empty file at the given absolute path. Any missing parent directories "
+ "are created automatically. The file is written to disk only — it is NOT added to the "
+ "project's build system automatically; the user must register it in CMakeLists.txt or "
+ "the equivalent project file. Use `edit_file` afterwards to populate its content.";
}
QJsonObject CreateNewFileTool::parametersSchema() const
@@ -61,7 +61,9 @@ QJsonObject CreateNewFileTool::parametersSchema() const
QJsonObject filepathProperty;
filepathProperty["type"] = "string";
- filepathProperty["description"] = "The absolute path where the new file should be created";
+ filepathProperty["description"]
+ = "Absolute path where the new file should be created. Parent directories are made if "
+ "missing. Relative paths are rejected.";
properties["filepath"] = filepathProperty;
QJsonObject definition;
diff --git a/tools/EditFileTool.cpp b/tools/EditFileTool.cpp
index 3dec3c8..b278889 100644
--- a/tools/EditFileTool.cpp
+++ b/tools/EditFileTool.cpp
@@ -57,7 +57,7 @@ QString EditFileTool::description() const
"and new_content to replace it with. Changes are applied immediately if auto-apply "
"is enabled in settings. The user can undo or reapply changes at any time. "
"\n\nIMPORTANT:"
- "\n- ALWAYS read the current file content before editing to ensure accuracy."
+ "\n- ALWAYS use read_file to get current file content before editing to ensure accuracy."
"\n- Path can be absolute (e.g., /path/to/file.cpp) or relative to project root (e.g., src/main.cpp)."
"\n- For EMPTY files: use empty old_content (empty string or omit parameter)."
"\n- To append at the END of file: use empty old_content."
diff --git a/tools/FindAndReadFileTool.cpp b/tools/FindAndReadFileTool.cpp
deleted file mode 100644
index 7377684..0000000
--- a/tools/FindAndReadFileTool.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2025 Petr Mironychev
- *
- * This file is part of QodeAssist.
- *
- * QodeAssist is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * QodeAssist is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with QodeAssist. If not, see .
- */
-
-#include "FindAndReadFileTool.hpp"
-
-#include
-
-#include
-#include
-#include
-#include
-
-namespace QodeAssist::Tools {
-
-FindAndReadFileTool::FindAndReadFileTool(QObject *parent)
- : BaseTool(parent)
- , m_ignoreManager(new Context::IgnoreManager(this))
-{}
-
-QString FindAndReadFileTool::id() const
-{
- return "find_and_read_file";
-}
-
-QString FindAndReadFileTool::displayName() const
-{
- return "Finding and reading file";
-}
-
-QString FindAndReadFileTool::description() const
-{
- return "Search for a file by name/path and optionally read its content. "
- "Returns the best matching file and its content.";
-}
-
-QJsonObject FindAndReadFileTool::parametersSchema() const
-{
- QJsonObject properties;
-
- properties["query"] = QJsonObject{
- {"type", "string"},
- {"description", "Filename, partial name, or path to search for (case-insensitive)"}};
-
- properties["file_pattern"] = QJsonObject{
- {"type", "string"}, {"description", "File pattern filter (e.g., '*.cpp', '*.h', '*.qml')"}};
-
- properties["read_content"] = QJsonObject{
- {"type", "boolean"},
- {"description", "Read file content in addition to finding path (default: true)"}};
-
- QJsonObject definition;
- definition["type"] = "object";
- definition["properties"] = properties;
- definition["required"] = QJsonArray{"query"};
-
- return definition;
-}
-
-QFuture FindAndReadFileTool::executeAsync(const QJsonObject &input)
-{
- return QtConcurrent::run([this, input]() -> LLMQore::ToolResult {
- QString query = input["query"].toString().trimmed();
- if (query.isEmpty()) {
- throw LLMQore::ToolInvalidArgument("Query parameter is required");
- }
-
- QString filePattern = input["file_pattern"].toString();
- bool readContent = input["read_content"].toBool(true);
-
- LOG_MESSAGE(QString("FindAndReadFileTool: Searching for '%1' (pattern: %2, read: %3)")
- .arg(query, filePattern.isEmpty() ? "none" : filePattern)
- .arg(readContent));
-
- FileSearchUtils::FileMatch bestMatch = FileSearchUtils::findBestMatch(
- query, filePattern, 10, m_ignoreManager);
-
- if (bestMatch.absolutePath.isEmpty()) {
- return LLMQore::ToolResult::text(QString("No file found matching '%1'").arg(query));
- }
-
- if (readContent) {
- bestMatch.content = FileSearchUtils::readFileContent(bestMatch.absolutePath);
- if (bestMatch.content.isNull()) {
- bestMatch.error = "Could not read file";
- }
- }
-
- return LLMQore::ToolResult::text(formatResult(bestMatch, readContent));
- });
-}
-
-QString FindAndReadFileTool::formatResult(const FileSearchUtils::FileMatch &match,
- bool readContent) const
-{
- QString result
- = QString("Found file: %1\nAbsolute path: %2").arg(match.relativePath, match.absolutePath);
-
- if (readContent) {
- if (!match.error.isEmpty()) {
- result += QString("\nError: %1").arg(match.error);
- } else {
- result += QString("\n\n=== Content ===\n%1").arg(match.content);
- }
- }
-
- return result;
-}
-
-} // namespace QodeAssist::Tools
diff --git a/tools/FindFileTool.cpp b/tools/FindFileTool.cpp
new file mode 100644
index 0000000..1c8d2f1
--- /dev/null
+++ b/tools/FindFileTool.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2026 Petr Mironychev
+ *
+ * This file is part of QodeAssist.
+ *
+ * QodeAssist is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QodeAssist is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with QodeAssist. If not, see .
+ */
+
+#include "FindFileTool.hpp"
+
+#include "FileSearchUtils.hpp"
+
+#include
+
+#include
+#include
+#include
+#include
+
+namespace QodeAssist::Tools {
+
+FindFileTool::FindFileTool(QObject *parent)
+ : BaseTool(parent)
+ , m_ignoreManager(new Context::IgnoreManager(this))
+{}
+
+QString FindFileTool::id() const
+{
+ return "find_file";
+}
+
+QString FindFileTool::displayName() const
+{
+ return "Finding file";
+}
+
+QString FindFileTool::description() const
+{
+ return "Find a file in the current project(s) by name or partial path. "
+ "Returns the absolute path, project-relative path, and the name of the project "
+ "that contains the match. Does NOT read file content — use `read_file` separately "
+ "when you need the content. Use this when you know part of the filename but not "
+ "the exact location.";
+}
+
+QJsonObject FindFileTool::parametersSchema() const
+{
+ QJsonObject properties;
+
+ properties["query"] = QJsonObject{
+ {"type", "string"},
+ {"description",
+ "Filename, partial filename, or partial path to look for. Case-insensitive. "
+ "Exact filename matches rank highest, then path matches, then partial name matches."}};
+
+ properties["file_pattern"] = QJsonObject{
+ {"type", "string"},
+ {"description",
+ "Optional wildcard filter applied to the filename. Examples: '*.cpp', '*.h', '*.qml'. "
+ "Leave empty to match any extension."}};
+
+ QJsonObject definition;
+ definition["type"] = "object";
+ definition["properties"] = properties;
+ definition["required"] = QJsonArray{"query"};
+
+ return definition;
+}
+
+QFuture FindFileTool::executeAsync(const QJsonObject &input)
+{
+ return QtConcurrent::run([this, input]() -> LLMQore::ToolResult {
+ QString query = input["query"].toString().trimmed();
+ if (query.isEmpty()) {
+ throw LLMQore::ToolInvalidArgument("'query' parameter is required and cannot be empty");
+ }
+
+ QString filePattern = input["file_pattern"].toString();
+
+ LOG_MESSAGE(QString("FindFileTool: Searching for '%1' (pattern: %2)")
+ .arg(query, filePattern.isEmpty() ? "none" : filePattern));
+
+ FileSearchUtils::FileMatch match
+ = FileSearchUtils::findBestMatch(query, filePattern, 10, m_ignoreManager);
+
+ if (match.absolutePath.isEmpty()) {
+ return LLMQore::ToolResult::text(QString("No file found matching '%1'").arg(query));
+ }
+
+ QString result = QString("Found file: %1\nAbsolute path: %2\nProject: %3")
+ .arg(match.relativePath, match.absolutePath, match.projectName);
+
+ return LLMQore::ToolResult::text(result);
+ });
+}
+
+} // namespace QodeAssist::Tools
diff --git a/tools/FindAndReadFileTool.hpp b/tools/FindFileTool.hpp
similarity index 83%
rename from tools/FindAndReadFileTool.hpp
rename to tools/FindFileTool.hpp
index f58d92e..2fe5ffe 100644
--- a/tools/FindAndReadFileTool.hpp
+++ b/tools/FindFileTool.hpp
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2025 Petr Mironychev
*
* This file is part of QodeAssist.
@@ -19,8 +19,6 @@
#pragma once
-#include "FileSearchUtils.hpp"
-
#include
#include
#include
@@ -29,12 +27,12 @@
namespace QodeAssist::Tools {
-class FindAndReadFileTool : public ::LLMQore::BaseTool
+class FindFileTool : public ::LLMQore::BaseTool
{
Q_OBJECT
public:
- explicit FindAndReadFileTool(QObject *parent = nullptr);
+ explicit FindFileTool(QObject *parent = nullptr);
QString id() const override;
QString displayName() const override;
@@ -43,8 +41,6 @@ public:
QFuture executeAsync(const QJsonObject &input) override;
private:
- QString formatResult(const FileSearchUtils::FileMatch &match, bool readContent) const;
-
Context::IgnoreManager *m_ignoreManager;
};
diff --git a/tools/GetIssuesListTool.cpp b/tools/GetIssuesListTool.cpp
index 30506f6..b86c797 100644
--- a/tools/GetIssuesListTool.cpp
+++ b/tools/GetIssuesListTool.cpp
@@ -133,9 +133,10 @@ QString GetIssuesListTool::displayName() const
QString GetIssuesListTool::description() const
{
- return "Get compilation errors, warnings, and diagnostics from Qt Creator's Issues panel. "
- "Returns issue descriptions with file paths and line numbers. "
- "Optional severity filter: 'error', 'warning', or 'all' (default).";
+ return "Read diagnostics from Qt Creator's Issues panel, including the latest build output and "
+ "live clang-codemodel warnings/errors for open files. Each issue includes file path, "
+ "line number, severity, and message. Run `build_project` first if you need fresh build "
+ "diagnostics.";
}
QJsonObject GetIssuesListTool::parametersSchema() const
diff --git a/tools/ListProjectFilesTool.cpp b/tools/ListProjectFilesTool.cpp
index a7722b7..3d6ddc7 100644
--- a/tools/ListProjectFilesTool.cpp
+++ b/tools/ListProjectFilesTool.cpp
@@ -50,8 +50,10 @@ QString ListProjectFilesTool::displayName() const
QString ListProjectFilesTool::description() const
{
- return "Get a list of all source files in the current project with absolute and relative paths. "
- "Useful for understanding project structure. No parameters required.";
+ return "List every source file tracked by the active Qt Creator project(s), filtered by "
+ ".qodeassistignore. Returns absolute and project-relative paths grouped by project. "
+ "Useful for discovering the project layout before running focused searches or reads. "
+ "Takes no parameters.";
}
QJsonObject ListProjectFilesTool::parametersSchema() const
diff --git a/tools/ProjectSearchTool.cpp b/tools/ProjectSearchTool.cpp
index f7187f7..39313f4 100644
--- a/tools/ProjectSearchTool.cpp
+++ b/tools/ProjectSearchTool.cpp
@@ -56,39 +56,50 @@ QString ProjectSearchTool::displayName() const
QString ProjectSearchTool::description() const
{
- return "Search project for text content or C++ symbols. "
- "Text mode: finds text patterns in files. "
- "Symbol mode: finds C++ definitions (classes, functions, etc).";
+ return "Search across all open Qt Creator project(s) for text occurrences or C++ symbol "
+ "definitions. 'text' mode scans source files line-by-line for literal text or regex. "
+ "'symbol' mode uses Qt Creator's C++ code model and works only for C++ "
+ "(not QML, Python, or plain text). Respects .qodeassistignore. "
+ "Use `find_file` for locating files by name, not this tool.";
}
QJsonObject ProjectSearchTool::parametersSchema() const
{
QJsonObject properties;
- properties["query"]
- = QJsonObject{{"type", "string"}, {"description", "Text or symbol name to search for"}};
+ properties["query"] = QJsonObject{
+ {"type", "string"},
+ {"description", "Text string or symbol name to search for. In text mode with "
+ "use_regex=true, this is a regular expression."}};
properties["search_type"] = QJsonObject{
{"type", "string"},
{"enum", QJsonArray{"text", "symbol"}},
- {"description", "Search mode: 'text' for content, 'symbol' for C++ definitions"}};
+ {"description", "Search mode: 'text' scans file contents, 'symbol' looks up C++ "
+ "declarations via the code model."}};
properties["symbol_type"] = QJsonObject{
{"type", "string"},
{"enum", QJsonArray{"all", "class", "function", "enum", "variable", "namespace"}},
- {"description", "Symbol type filter (symbol mode only)"}};
+ {"description", "Filter for symbol mode. Default: 'all'. Ignored in text mode."}};
- properties["case_sensitive"]
- = QJsonObject{{"type", "boolean"}, {"description", "Case-sensitive search"}};
+ properties["case_sensitive"] = QJsonObject{
+ {"type", "boolean"},
+ {"description", "Case-sensitive matching. Default: false."}};
- properties["use_regex"]
- = QJsonObject{{"type", "boolean"}, {"description", "Use regex patterns"}};
+ properties["use_regex"] = QJsonObject{
+ {"type", "boolean"},
+ {"description", "Treat the query as a regular expression. Default: false."}};
- properties["whole_words"]
- = QJsonObject{{"type", "boolean"}, {"description", "Match whole words only (text mode)"}};
+ properties["whole_words"] = QJsonObject{
+ {"type", "boolean"},
+ {"description", "Match whole words only. Text mode only; ignored in symbol mode. "
+ "Default: false."}};
properties["file_pattern"] = QJsonObject{
- {"type", "string"}, {"description", "File filter pattern (e.g., '*.cpp', '*.h')"}};
+ {"type", "string"},
+ {"description", "Wildcard to restrict which files are searched in text mode, e.g. "
+ "'*.cpp' or '*.h'. Default: all files."}};
QJsonObject definition;
definition["type"] = "object";
diff --git a/tools/ReadFileTool.cpp b/tools/ReadFileTool.cpp
new file mode 100644
index 0000000..c47da84
--- /dev/null
+++ b/tools/ReadFileTool.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2026 Petr Mironychev
+ *
+ * This file is part of QodeAssist.
+ *
+ * QodeAssist is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QodeAssist is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with QodeAssist. If not, see .
+ */
+
+#include "ReadFileTool.hpp"
+
+#include "FileSearchUtils.hpp"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace QodeAssist::Tools {
+
+ReadFileTool::ReadFileTool(QObject *parent)
+ : BaseTool(parent)
+{}
+
+QString ReadFileTool::id() const
+{
+ return "read_file";
+}
+
+QString ReadFileTool::displayName() const
+{
+ return "Reading file";
+}
+
+QString ReadFileTool::description() const
+{
+ return "Read the text content of a file. Accepts either an absolute path or a path "
+ "relative to the project root. Reading files outside the active project requires "
+ "the 'Allow file access outside project' option in settings. Use `find_file` first "
+ "if you only know a partial filename.";
+}
+
+QJsonObject ReadFileTool::parametersSchema() const
+{
+ QJsonObject properties;
+
+ properties["file_path"] = QJsonObject{
+ {"type", "string"},
+ {"description",
+ "Absolute path (e.g. /path/to/file.cpp) or project-relative path (e.g. src/main.cpp). "
+ "Relative paths are resolved against the root of the active project."}};
+
+ QJsonObject definition;
+ definition["type"] = "object";
+ definition["properties"] = properties;
+ definition["required"] = QJsonArray{"file_path"};
+
+ return definition;
+}
+
+QFuture ReadFileTool::executeAsync(const QJsonObject &input)
+{
+ return QtConcurrent::run([input]() -> LLMQore::ToolResult {
+ QString rawPath = input["file_path"].toString().trimmed();
+ if (rawPath.isEmpty()) {
+ throw LLMQore::ToolInvalidArgument(
+ "'file_path' parameter is required and cannot be empty");
+ }
+
+ QFileInfo pathInfo(rawPath);
+ QString absolutePath;
+ if (pathInfo.isAbsolute()) {
+ absolutePath = rawPath;
+ } else {
+ QString projectRoot = Context::ProjectUtils::getProjectRoot();
+ if (projectRoot.isEmpty()) {
+ throw LLMQore::ToolRuntimeError(
+ QString("Cannot resolve relative path '%1': no project is open. "
+ "Provide an absolute path or open a project.")
+ .arg(rawPath));
+ }
+ absolutePath = QDir(projectRoot).absoluteFilePath(rawPath);
+ LOG_MESSAGE(QString("ReadFileTool: Resolved relative path '%1' to '%2'")
+ .arg(rawPath, absolutePath));
+ }
+
+ QFileInfo finalInfo(absolutePath);
+ if (!finalInfo.exists() || !finalInfo.isFile()) {
+ throw LLMQore::ToolRuntimeError(QString("File does not exist: %1").arg(absolutePath));
+ }
+
+ QString content = FileSearchUtils::readFileContent(absolutePath);
+ if (content.isNull()) {
+ throw LLMQore::ToolRuntimeError(
+ QString("Cannot read file '%1'. It may be outside the project scope "
+ "(enable 'Allow file access outside project' in settings), unreadable, "
+ "or use an unsupported encoding.")
+ .arg(absolutePath));
+ }
+
+ QString result = QString("File: %1\n\n%2").arg(absolutePath, content);
+ return LLMQore::ToolResult::text(result);
+ });
+}
+
+} // namespace QodeAssist::Tools
diff --git a/tools/ReadFileTool.hpp b/tools/ReadFileTool.hpp
new file mode 100644
index 0000000..a25a015
--- /dev/null
+++ b/tools/ReadFileTool.hpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2025 Petr Mironychev
+ *
+ * This file is part of QodeAssist.
+ *
+ * QodeAssist is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QodeAssist is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with QodeAssist. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+namespace QodeAssist::Tools {
+
+class ReadFileTool : public ::LLMQore::BaseTool
+{
+ Q_OBJECT
+
+public:
+ explicit ReadFileTool(QObject *parent = nullptr);
+
+ QString id() const override;
+ QString displayName() const override;
+ QString description() const override;
+ QJsonObject parametersSchema() const override;
+ QFuture executeAsync(const QJsonObject &input) override;
+};
+
+} // namespace QodeAssist::Tools
diff --git a/tools/ToolsRegistration.cpp b/tools/ToolsRegistration.cpp
index 91922a9..305023a 100644
--- a/tools/ToolsRegistration.cpp
+++ b/tools/ToolsRegistration.cpp
@@ -21,29 +21,62 @@
#include
+#include
+#include
+
#include "BuildProjectTool.hpp"
#include "CreateNewFileTool.hpp"
#include "EditFileTool.hpp"
#include "ExecuteTerminalCommandTool.hpp"
-#include "FindAndReadFileTool.hpp"
+#include "FindFileTool.hpp"
#include "GetIssuesListTool.hpp"
#include "ListProjectFilesTool.hpp"
#include "ProjectSearchTool.hpp"
+#include "ReadFileTool.hpp"
#include "TodoTool.hpp"
namespace QodeAssist::Tools {
+namespace {
+
+template
+void wireTool(::LLMQore::ToolsManager *manager,
+ Utils::BoolAspect &aspect,
+ const QString &toolId)
+{
+ auto sync = [manager, toolId, &aspect]() {
+ const bool wanted = aspect.volatileValue();
+ const bool present = manager->tool(toolId) != nullptr;
+ if (wanted && !present) {
+ manager->addTool(new ToolT(manager));
+ } else if (!wanted && present) {
+ manager->removeTool(toolId);
+ }
+ };
+
+ sync();
+
+ QObject::connect(&aspect, &Utils::BoolAspect::volatileValueChanged, manager, sync);
+ QObject::connect(&aspect, &Utils::BaseAspect::changed, manager, sync);
+}
+
+} // namespace
+
void registerQodeAssistTools(::LLMQore::ToolsManager *manager)
{
- manager->addTool(new ListProjectFilesTool(manager));
- manager->addTool(new GetIssuesListTool(manager));
- manager->addTool(new CreateNewFileTool(manager));
- manager->addTool(new EditFileTool(manager));
- manager->addTool(new BuildProjectTool(manager));
- manager->addTool(new ExecuteTerminalCommandTool(manager));
- manager->addTool(new ProjectSearchTool(manager));
- manager->addTool(new FindAndReadFileTool(manager));
- manager->addTool(new TodoTool(manager));
+ auto &s = Settings::toolsSettings();
+
+ wireTool(manager, s.enableListProjectFilesTool, "list_project_files");
+ wireTool(manager, s.enableFindFileTool, "find_file");
+ wireTool(manager, s.enableReadFileTool, "read_file");
+ wireTool(manager, s.enableProjectSearchTool, "search_project");
+ wireTool(manager, s.enableCreateNewFileTool, "create_new_file");
+ wireTool(manager, s.enableEditFileTool, "edit_file");
+ wireTool(manager, s.enableBuildProjectTool, "build_project");
+ wireTool(manager, s.enableGetIssuesListTool, "get_issues_list");
+ wireTool(
+ manager, s.enableTerminalCommandTool, "execute_terminal_command");
+ wireTool(manager, s.enableTodoTool, "todo_tool");
}
} // namespace QodeAssist::Tools