mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2025-10-28 06:44:32 -04:00
feat: Add project-specific rules support
This commit is contained in:
@ -28,6 +28,9 @@
|
|||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/editormanager/ieditor.h>
|
#include <coreplugin/editormanager/ieditor.h>
|
||||||
#include <coreplugin/idocument.h>
|
#include <coreplugin/idocument.h>
|
||||||
|
#include <projectexplorer/project.h>
|
||||||
|
#include <projectexplorer/projectexplorer.h>
|
||||||
|
#include <projectexplorer/projectmanager.h>
|
||||||
|
|
||||||
#include <texteditor/textdocument.h>
|
#include <texteditor/textdocument.h>
|
||||||
#include <texteditor/texteditor.h>
|
#include <texteditor/texteditor.h>
|
||||||
@ -37,6 +40,7 @@
|
|||||||
#include "Logger.hpp"
|
#include "Logger.hpp"
|
||||||
#include "ProvidersManager.hpp"
|
#include "ProvidersManager.hpp"
|
||||||
#include "RequestConfig.hpp"
|
#include "RequestConfig.hpp"
|
||||||
|
#include <RulesLoader.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Chat {
|
namespace QodeAssist::Chat {
|
||||||
|
|
||||||
@ -81,6 +85,17 @@ void ClientInterface::sendMessage(
|
|||||||
|
|
||||||
if (chatAssistantSettings.useSystemPrompt()) {
|
if (chatAssistantSettings.useSystemPrompt()) {
|
||||||
QString systemPrompt = chatAssistantSettings.systemPrompt();
|
QString systemPrompt = chatAssistantSettings.systemPrompt();
|
||||||
|
|
||||||
|
auto project = LLMCore::RulesLoader::getActiveProject();
|
||||||
|
if (project) {
|
||||||
|
QString projectRules
|
||||||
|
= LLMCore::RulesLoader::loadRulesForProject(project, LLMCore::RulesContext::Chat);
|
||||||
|
|
||||||
|
if (!projectRules.isEmpty()) {
|
||||||
|
systemPrompt += "\n\n# Project Rules\n\n" + projectRules;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!linkedFiles.isEmpty()) {
|
if (!linkedFiles.isEmpty()) {
|
||||||
systemPrompt = getSystemPromptWithLinkedFiles(systemPrompt, linkedFiles);
|
systemPrompt = getSystemPromptWithLinkedFiles(systemPrompt, linkedFiles);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
#include "settings/CodeCompletionSettings.hpp"
|
#include "settings/CodeCompletionSettings.hpp"
|
||||||
#include "settings/GeneralSettings.hpp"
|
#include "settings/GeneralSettings.hpp"
|
||||||
#include <llmcore/RequestConfig.hpp>
|
#include <llmcore/RequestConfig.hpp>
|
||||||
|
#include <llmcore/RulesLoader.hpp>
|
||||||
|
|
||||||
namespace QodeAssist {
|
namespace QodeAssist {
|
||||||
|
|
||||||
@ -242,6 +243,18 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
|
|||||||
&& promptTemplate->type() == LLMCore::TemplateType::Chat
|
&& promptTemplate->type() == LLMCore::TemplateType::Chat
|
||||||
? m_completeSettings.systemPromptForNonFimModels()
|
? m_completeSettings.systemPromptForNonFimModels()
|
||||||
: m_completeSettings.systemPrompt());
|
: m_completeSettings.systemPrompt());
|
||||||
|
|
||||||
|
auto project = LLMCore::RulesLoader::getActiveProject();
|
||||||
|
if (project) {
|
||||||
|
QString projectRules
|
||||||
|
= LLMCore::RulesLoader::loadRulesForProject(project, LLMCore::RulesContext::Completions);
|
||||||
|
|
||||||
|
if (!projectRules.isEmpty()) {
|
||||||
|
systemPrompt += "\n\n# Project Rules\n\n" + projectRules;
|
||||||
|
LOG_MESSAGE("Loaded project rules for completion");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (updatedContext.fileContext.has_value())
|
if (updatedContext.fileContext.has_value())
|
||||||
systemPrompt.append(updatedContext.fileContext.value());
|
systemPrompt.append(updatedContext.fileContext.value());
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,7 @@
|
|||||||
#include <llmcore/PromptTemplateManager.hpp>
|
#include <llmcore/PromptTemplateManager.hpp>
|
||||||
#include <llmcore/ProvidersManager.hpp>
|
#include <llmcore/ProvidersManager.hpp>
|
||||||
#include <llmcore/RequestConfig.hpp>
|
#include <llmcore/RequestConfig.hpp>
|
||||||
|
#include <llmcore/RulesLoader.hpp>
|
||||||
#include <logger/Logger.hpp>
|
#include <logger/Logger.hpp>
|
||||||
#include <settings/ChatAssistantSettings.hpp>
|
#include <settings/ChatAssistantSettings.hpp>
|
||||||
#include <settings/GeneralSettings.hpp>
|
#include <settings/GeneralSettings.hpp>
|
||||||
@ -206,6 +207,18 @@ LLMCore::ContextData QuickRefactorHandler::prepareContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString systemPrompt = Settings::codeCompletionSettings().quickRefactorSystemPrompt();
|
QString systemPrompt = Settings::codeCompletionSettings().quickRefactorSystemPrompt();
|
||||||
|
|
||||||
|
auto project = LLMCore::RulesLoader::getActiveProject();
|
||||||
|
if (project) {
|
||||||
|
QString projectRules = LLMCore::RulesLoader::loadRulesForProject(
|
||||||
|
project, LLMCore::RulesContext::QuickRefactor);
|
||||||
|
|
||||||
|
if (!projectRules.isEmpty()) {
|
||||||
|
systemPrompt += "\n\n# Project Rules\n\n" + projectRules;
|
||||||
|
LOG_MESSAGE("Loaded project rules for quick refactor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
systemPrompt += "\n\nFile information:";
|
systemPrompt += "\n\nFile information:";
|
||||||
systemPrompt += "\nLanguage: " + documentInfo.mimeType;
|
systemPrompt += "\nLanguage: " + documentInfo.mimeType;
|
||||||
systemPrompt += "\nFile path: " + documentInfo.filePath;
|
systemPrompt += "\nFile path: " + documentInfo.filePath;
|
||||||
|
|||||||
28
README.md
28
README.md
@ -218,6 +218,34 @@ You're all set! QodeAssist is now ready to use in Qt Creator.
|
|||||||
|
|
||||||
The plugin comes with default system prompts optimized for chat and instruct models, as these currently provide better results for code assistance. If you prefer using FIM (Fill-in-Middle) models, you can easily customize the system prompt in the settings.
|
The plugin comes with default system prompts optimized for chat and instruct models, as these currently provide better results for code assistance. If you prefer using FIM (Fill-in-Middle) models, you can easily customize the system prompt in the settings.
|
||||||
|
|
||||||
|
## Project Rules Configuration
|
||||||
|
|
||||||
|
QodeAssist supports project-specific rules to customize AI behavior for your codebase. Create a `.qodeassist/rules/` directory in your project root.
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
```bash
|
||||||
|
mkdir -p .qodeassist/rules/{common,completion,chat,quickrefactor}
|
||||||
|
```
|
||||||
|
```
|
||||||
|
.qodeassist/
|
||||||
|
└── rules/
|
||||||
|
├── common/ # Applied to all contexts
|
||||||
|
├── completion/ # Code completion only
|
||||||
|
├── chat/ # Chat assistant only
|
||||||
|
└── quickrefactor/ # Quick refactor only
|
||||||
|
```
|
||||||
|
All .md files in each directory are automatically loaded and added to the system prompt.
|
||||||
|
|
||||||
|
Example
|
||||||
|
Create .qodeassist/rules/common/general.md:
|
||||||
|
```markdown
|
||||||
|
# Project Guidelines
|
||||||
|
- Use snake_case for private members
|
||||||
|
- Prefix interfaces with 'I'
|
||||||
|
- Always document public APIs
|
||||||
|
- Prefer Qt containers over STL
|
||||||
|
```
|
||||||
|
|
||||||
## File Context Feature
|
## File Context Feature
|
||||||
|
|
||||||
QodeAssist provides two powerful ways to include source code files in your chat conversations: Attachments and Linked Files. Each serves a distinct purpose and helps provide better context for the AI assistant.
|
QodeAssist provides two powerful ways to include source code files in your chat conversations: Attachments and Linked Files. Each serves a distinct purpose and helps provide better context for the AI assistant.
|
||||||
|
|||||||
@ -15,9 +15,9 @@ add_library(LLMCore STATIC
|
|||||||
HttpClient.hpp HttpClient.cpp
|
HttpClient.hpp HttpClient.cpp
|
||||||
DataBuffers.hpp
|
DataBuffers.hpp
|
||||||
SSEBuffer.hpp SSEBuffer.cpp
|
SSEBuffer.hpp SSEBuffer.cpp
|
||||||
BaseTool.hpp
|
BaseTool.hpp BaseTool.cpp
|
||||||
BaseTool.cpp
|
|
||||||
ContentBlocks.hpp
|
ContentBlocks.hpp
|
||||||
|
RulesLoader.hpp RulesLoader.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(LLMCore
|
target_link_libraries(LLMCore
|
||||||
|
|||||||
112
llmcore/RulesLoader.cpp
Normal file
112
llmcore/RulesLoader.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "RulesLoader.hpp"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
|
#include <projectexplorer/project.h>
|
||||||
|
#include <projectexplorer/projectmanager.h>
|
||||||
|
|
||||||
|
namespace QodeAssist::LLMCore {
|
||||||
|
|
||||||
|
QString RulesLoader::loadRules(const QString &projectPath, RulesContext context)
|
||||||
|
{
|
||||||
|
if (projectPath.isEmpty()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString combined;
|
||||||
|
QString basePath = projectPath + "/.qodeassist/rules";
|
||||||
|
|
||||||
|
combined += loadAllMarkdownFiles(basePath + "/common");
|
||||||
|
|
||||||
|
switch (context) {
|
||||||
|
case RulesContext::Completions:
|
||||||
|
combined += loadAllMarkdownFiles(basePath + "/completions");
|
||||||
|
break;
|
||||||
|
case RulesContext::Chat:
|
||||||
|
combined += loadAllMarkdownFiles(basePath + "/chat");
|
||||||
|
break;
|
||||||
|
case RulesContext::QuickRefactor:
|
||||||
|
combined += loadAllMarkdownFiles(basePath + "/quickrefactor");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return combined;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RulesLoader::loadRulesForProject(ProjectExplorer::Project *project, RulesContext context)
|
||||||
|
{
|
||||||
|
if (!project) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString projectPath = getProjectPath(project);
|
||||||
|
return loadRules(projectPath, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectExplorer::Project *RulesLoader::getActiveProject()
|
||||||
|
{
|
||||||
|
auto currentEditor = Core::EditorManager::currentEditor();
|
||||||
|
if (currentEditor && currentEditor->document()) {
|
||||||
|
Utils::FilePath filePath = currentEditor->document()->filePath();
|
||||||
|
auto project = ProjectExplorer::ProjectManager::projectForFile(filePath);
|
||||||
|
if (project) {
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ProjectExplorer::ProjectManager::startupProject();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RulesLoader::loadAllMarkdownFiles(const QString &dirPath)
|
||||||
|
{
|
||||||
|
QString combined;
|
||||||
|
QDir dir(dirPath);
|
||||||
|
|
||||||
|
if (!dir.exists()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList mdFiles = dir.entryList({"*.md"}, QDir::Files, QDir::Name);
|
||||||
|
|
||||||
|
for (const QString &fileName : mdFiles) {
|
||||||
|
QFile file(dir.filePath(fileName));
|
||||||
|
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
combined += file.readAll();
|
||||||
|
combined += "\n\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return combined;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RulesLoader::getProjectPath(ProjectExplorer::Project *project)
|
||||||
|
{
|
||||||
|
if (!project) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return project->projectDirectory().toUrlishString();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QodeAssist::LLMCore
|
||||||
44
llmcore/RulesLoader.hpp
Normal file
44
llmcore/RulesLoader.hpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace ProjectExplorer {
|
||||||
|
class Project;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace QodeAssist::LLMCore {
|
||||||
|
|
||||||
|
enum class RulesContext { Completions, Chat, QuickRefactor };
|
||||||
|
|
||||||
|
class RulesLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static QString loadRules(const QString &projectPath, RulesContext context);
|
||||||
|
static QString loadRulesForProject(ProjectExplorer::Project *project, RulesContext context);
|
||||||
|
static ProjectExplorer::Project *getActiveProject();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static QString loadAllMarkdownFiles(const QString &dirPath);
|
||||||
|
static QString getProjectPath(ProjectExplorer::Project *project);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QodeAssist::LLMCore
|
||||||
Reference in New Issue
Block a user