diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b092b4..af5863c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,7 @@ add_qtc_plugin(QodeAssist tools/EditProjectFileTool.hpp tools/EditProjectFileTool.cpp tools/FindSymbolTool.hpp tools/FindSymbolTool.cpp tools/FindFileTool.hpp tools/FindFileTool.cpp + tools/CreateNewFileTool.hpp tools/CreateNewFileTool.cpp providers/ClaudeMessage.hpp providers/ClaudeMessage.cpp providers/OpenAIMessage.hpp providers/OpenAIMessage.cpp providers/OllamaMessage.hpp providers/OllamaMessage.cpp diff --git a/tools/CreateNewFileTool.cpp b/tools/CreateNewFileTool.cpp new file mode 100644 index 0000000..7d4ab96 --- /dev/null +++ b/tools/CreateNewFileTool.cpp @@ -0,0 +1,125 @@ +/* + * 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 "CreateNewFileTool.hpp" +#include "ToolExceptions.hpp" + +#include +#include +#include +#include +#include +#include + +namespace QodeAssist::Tools { + +CreateNewFileTool::CreateNewFileTool(QObject *parent) + : BaseTool(parent) +{} + +QString CreateNewFileTool::name() const +{ + return "create_new_file"; +} + +QString CreateNewFileTool::stringName() const +{ + return {"Creating new file"}; +} + +QString CreateNewFileTool::description() const +{ + return "Create a new empty file at the specified path. " + "The directory path must exist. Provide absolute file path. After crate files add file " + "to project file (CMakeLists.txt or .cmake or .pri)"; +} + +QJsonObject CreateNewFileTool::getDefinition(LLMCore::ToolSchemaFormat format) const +{ + QJsonObject properties; + + QJsonObject filepathProperty; + filepathProperty["type"] = "string"; + filepathProperty["description"] = "The absolute path where the new file should be created"; + properties["filepath"] = filepathProperty; + + QJsonObject definition; + definition["type"] = "object"; + definition["properties"] = properties; + QJsonArray required; + required.append("filepath"); + definition["required"] = required; + + switch (format) { + case LLMCore::ToolSchemaFormat::OpenAI: + return customizeForOpenAI(definition); + case LLMCore::ToolSchemaFormat::Claude: + return customizeForClaude(definition); + case LLMCore::ToolSchemaFormat::Ollama: + return customizeForOllama(definition); + case LLMCore::ToolSchemaFormat::Google: + return customizeForGoogle(definition); + } + + return definition; +} + +LLMCore::ToolPermissions CreateNewFileTool::requiredPermissions() const +{ + return LLMCore::ToolPermission::FileSystemWrite; +} + +QFuture CreateNewFileTool::executeAsync(const QJsonObject &input) +{ + return QtConcurrent::run([this, input]() -> QString { + QString filePath = input["filepath"].toString(); + + if (filePath.isEmpty()) { + throw ToolInvalidArgument("Error: 'filepath' parameter is required"); + } + + QFileInfo fileInfo(filePath); + + if (fileInfo.exists()) { + throw ToolRuntimeError( + QString("Error: File already exists at path '%1'").arg(filePath)); + } + + QDir dir = fileInfo.absoluteDir(); + if (!dir.exists()) { + throw ToolRuntimeError(QString("Error: Directory does not exist: '%1'") + .arg(dir.absolutePath())); + } + + QFile file(filePath); + if (!file.open(QIODevice::WriteOnly)) { + throw ToolRuntimeError( + QString("Error: Could not create file '%1': %2").arg(filePath, file.errorString())); + } + + file.close(); + + LOG_MESSAGE(QString("Successfully created new file: %1").arg(filePath)); + + return QString("Successfully created new file: %1").arg(filePath); + }); +} + +} // namespace QodeAssist::Tools + diff --git a/tools/CreateNewFileTool.hpp b/tools/CreateNewFileTool.hpp new file mode 100644 index 0000000..1c16325 --- /dev/null +++ b/tools/CreateNewFileTool.hpp @@ -0,0 +1,42 @@ +/* + * 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 + +namespace QodeAssist::Tools { + +class CreateNewFileTool : public LLMCore::BaseTool +{ + Q_OBJECT +public: + explicit CreateNewFileTool(QObject *parent = nullptr); + + QString name() const override; + QString stringName() const override; + QString description() const override; + QJsonObject getDefinition(LLMCore::ToolSchemaFormat format) const override; + LLMCore::ToolPermissions requiredPermissions() const override; + + QFuture executeAsync(const QJsonObject &input = QJsonObject()) override; +}; + +} // namespace QodeAssist::Tools + diff --git a/tools/ToolsFactory.cpp b/tools/ToolsFactory.cpp index 5cb5d6f..7db04ef 100644 --- a/tools/ToolsFactory.cpp +++ b/tools/ToolsFactory.cpp @@ -24,6 +24,7 @@ #include #include +#include "CreateNewFileTool.hpp" #include "EditProjectFileTool.hpp" #include "FindFileTool.hpp" #include "FindSymbolTool.hpp" @@ -51,6 +52,7 @@ void ToolsFactory::registerTools() registerTool(new EditProjectFileTool(this)); registerTool(new FindSymbolTool(this)); registerTool(new FindFileTool(this)); + registerTool(new CreateNewFileTool(this)); LOG_MESSAGE(QString("Registered %1 tools").arg(m_tools.size())); }