/* * 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