refactor: Replace singletone for context manager

This commit is contained in:
Petr Mironychev 2025-03-29 12:46:19 +01:00
parent 7e6e526ac8
commit 9c7723df56
9 changed files with 114 additions and 37 deletions

View File

@ -464,12 +464,12 @@ void ChatRootView::updateInputTokensCount()
} }
if (!m_attachmentFiles.isEmpty()) { if (!m_attachmentFiles.isEmpty()) {
auto attachFiles = Context::ContextManager::instance().getContentFiles(m_attachmentFiles); auto attachFiles = m_clientInterface->contextManager()->getContentFiles(m_attachmentFiles);
inputTokens += Context::TokenUtils::estimateFilesTokens(attachFiles); inputTokens += Context::TokenUtils::estimateFilesTokens(attachFiles);
} }
if (!m_linkedFiles.isEmpty()) { if (!m_linkedFiles.isEmpty()) {
auto linkFiles = Context::ContextManager::instance().getContentFiles(m_linkedFiles); auto linkFiles = m_clientInterface->contextManager()->getContentFiles(m_linkedFiles);
inputTokens += Context::TokenUtils::estimateFilesTokens(linkFiles); inputTokens += Context::TokenUtils::estimateFilesTokens(linkFiles);
} }

View File

@ -33,7 +33,6 @@
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
#include "ChatAssistantSettings.hpp" #include "ChatAssistantSettings.hpp"
#include "ContextManager.hpp"
#include "GeneralSettings.hpp" #include "GeneralSettings.hpp"
#include "Logger.hpp" #include "Logger.hpp"
#include "ProvidersManager.hpp" #include "ProvidersManager.hpp"
@ -46,6 +45,7 @@ ClientInterface::ClientInterface(
, m_requestHandler(new LLMCore::RequestHandler(this)) , m_requestHandler(new LLMCore::RequestHandler(this))
, m_chatModel(chatModel) , m_chatModel(chatModel)
, m_promptProvider(promptProvider) , m_promptProvider(promptProvider)
, m_contextManager(new Context::ContextManager(this))
{ {
connect( connect(
m_requestHandler, m_requestHandler,
@ -73,7 +73,7 @@ void ClientInterface::sendMessage(
{ {
cancelRequest(); cancelRequest();
auto attachFiles = Context::ContextManager::instance().getContentFiles(attachments); auto attachFiles = m_contextManager->getContentFiles(attachments);
m_chatModel->addMessage(message, ChatModel::ChatRole::User, "", attachFiles); m_chatModel->addMessage(message, ChatModel::ChatRole::User, "", attachFiles);
auto &chatAssistantSettings = Settings::chatAssistantSettings(); auto &chatAssistantSettings = Settings::chatAssistantSettings();
@ -200,7 +200,7 @@ QString ClientInterface::getSystemPromptWithLinkedFiles(
if (!linkedFiles.isEmpty()) { if (!linkedFiles.isEmpty()) {
updatedPrompt += "\n\nLinked files for reference:\n"; updatedPrompt += "\n\nLinked files for reference:\n";
auto contentFiles = Context::ContextManager::instance().getContentFiles(linkedFiles); auto contentFiles = m_contextManager->getContentFiles(linkedFiles);
for (const auto &file : contentFiles) { for (const auto &file : contentFiles) {
updatedPrompt += QString("\nFile: %1\nContent:\n%2\n").arg(file.filename, file.content); updatedPrompt += QString("\nFile: %1\nContent:\n%2\n").arg(file.filename, file.content);
} }
@ -209,4 +209,9 @@ QString ClientInterface::getSystemPromptWithLinkedFiles(
return updatedPrompt; return updatedPrompt;
} }
Context::ContextManager *ClientInterface::contextManager() const
{
return m_contextManager;
}
} // namespace QodeAssist::Chat } // namespace QodeAssist::Chat

View File

@ -26,6 +26,7 @@
#include "ChatModel.hpp" #include "ChatModel.hpp"
#include "RequestHandler.hpp" #include "RequestHandler.hpp"
#include "llmcore/IPromptProvider.hpp" #include "llmcore/IPromptProvider.hpp"
#include <context/ContextManager.hpp>
namespace QodeAssist::Chat { namespace QodeAssist::Chat {
@ -45,6 +46,8 @@ public:
void clearMessages(); void clearMessages();
void cancelRequest(); void cancelRequest();
Context::ContextManager *contextManager() const;
signals: signals:
void errorOccurred(const QString &error); void errorOccurred(const QString &error);
void messageReceivedCompletely(); void messageReceivedCompletely();
@ -58,6 +61,7 @@ private:
LLMCore::IPromptProvider *m_promptProvider = nullptr; LLMCore::IPromptProvider *m_promptProvider = nullptr;
ChatModel *m_chatModel; ChatModel *m_chatModel;
LLMCore::RequestHandler *m_requestHandler; LLMCore::RequestHandler *m_requestHandler;
Context::ContextManager *m_contextManager;
}; };
} // namespace QodeAssist::Chat } // namespace QodeAssist::Chat

View File

@ -24,7 +24,6 @@
#include <QNetworkReply> #include <QNetworkReply>
#include "CodeHandler.hpp" #include "CodeHandler.hpp"
#include "context/ContextManager.hpp"
#include "context/DocumentContextReader.hpp" #include "context/DocumentContextReader.hpp"
#include "context/Utils.hpp" #include "context/Utils.hpp"
#include "llmcore/PromptTemplateManager.hpp" #include "llmcore/PromptTemplateManager.hpp"
@ -51,6 +50,7 @@ LLMClientInterface::LLMClientInterface(
, m_requestHandler(requestHandler) , m_requestHandler(requestHandler)
, m_documentReader(documentReader) , m_documentReader(documentReader)
, m_performanceLogger(performanceLogger) , m_performanceLogger(performanceLogger)
, m_contextManager(new Context::ContextManager(this))
{ {
connect( connect(
&m_requestHandler, &m_requestHandler,
@ -170,8 +170,7 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
auto updatedContext = prepareContext(request, documentInfo); auto updatedContext = prepareContext(request, documentInfo);
bool isPreset1Active bool isPreset1Active = m_contextManager->isSpecifyCompletion(documentInfo);
= Context::ContextManager::isSpecifyCompletion(documentInfo, m_generalSettings);
const auto providerName = !isPreset1Active ? m_generalSettings.ccProvider() const auto providerName = !isPreset1Active ? m_generalSettings.ccProvider()
: m_generalSettings.ccPreset1Provider(); : m_generalSettings.ccPreset1Provider();
@ -282,8 +281,7 @@ void LLMClientInterface::sendCompletionToClient(
{ {
auto filePath = Context::extractFilePathFromRequest(request); auto filePath = Context::extractFilePathFromRequest(request);
auto documentInfo = m_documentReader.readDocument(filePath); auto documentInfo = m_documentReader.readDocument(filePath);
bool isPreset1Active bool isPreset1Active = m_contextManager->isSpecifyCompletion(documentInfo);
= Context::ContextManager::isSpecifyCompletion(documentInfo, m_generalSettings);
auto templateName = !isPreset1Active ? m_generalSettings.ccTemplate() auto templateName = !isPreset1Active ? m_generalSettings.ccTemplate()
: m_generalSettings.ccPreset1Template(); : m_generalSettings.ccPreset1Template();

View File

@ -22,6 +22,7 @@
#include <languageclient/languageclientinterface.h> #include <languageclient/languageclientinterface.h>
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
#include <context/ContextManager.hpp>
#include <context/IDocumentReader.hpp> #include <context/IDocumentReader.hpp>
#include <context/ProgrammingLanguage.hpp> #include <context/ProgrammingLanguage.hpp>
#include <llmcore/ContextData.hpp> #include <llmcore/ContextData.hpp>
@ -84,6 +85,7 @@ private:
Context::IDocumentReader &m_documentReader; Context::IDocumentReader &m_documentReader;
IRequestPerformanceLogger &m_performanceLogger; IRequestPerformanceLogger &m_performanceLogger;
QElapsedTimer m_completionTimer; QElapsedTimer m_completionTimer;
Context::ContextManager *m_contextManager;
}; };
} // namespace QodeAssist } // namespace QodeAssist

View File

@ -7,6 +7,7 @@ add_library(Context STATIC
IDocumentReader.hpp IDocumentReader.hpp
TokenUtils.hpp TokenUtils.cpp TokenUtils.hpp TokenUtils.cpp
ProgrammingLanguage.hpp ProgrammingLanguage.cpp ProgrammingLanguage.hpp ProgrammingLanguage.cpp
IContextManager.hpp
) )
target_link_libraries(Context target_link_libraries(Context

View File

@ -24,17 +24,14 @@
#include <QJsonObject> #include <QJsonObject>
#include <QTextStream> #include <QTextStream>
#include "GeneralSettings.hpp" #include "settings/GeneralSettings.hpp"
#include <projectexplorer/project.h>
#include <projectexplorer/projectnodes.h>
#include "Logger.hpp" #include "Logger.hpp"
namespace QodeAssist::Context { namespace QodeAssist::Context {
ContextManager &ContextManager::instance()
{
static ContextManager manager;
return manager;
}
ContextManager::ContextManager(QObject *parent) ContextManager::ContextManager(QObject *parent)
: QObject(parent) : QObject(parent)
{} {}
@ -59,6 +56,27 @@ QList<ContentFile> ContextManager::getContentFiles(const QStringList &filePaths)
return files; return files;
} }
QStringList ContextManager::getProjectSourceFiles(ProjectExplorer::Project *project) const
{
QStringList sourceFiles;
if (!project)
return sourceFiles;
auto projectNode = project->rootProjectNode();
if (!projectNode)
return sourceFiles;
projectNode->forEachNode(
[&sourceFiles, this](ProjectExplorer::FileNode *fileNode) {
if (fileNode /*&& shouldProcessFile(fileNode->filePath().toString())*/) {
sourceFiles.append(fileNode->filePath().toUrlishString());
}
},
nullptr);
return sourceFiles;
}
ContentFile ContextManager::createContentFile(const QString &filePath) const ContentFile ContextManager::createContentFile(const QString &filePath) const
{ {
ContentFile contentFile; ContentFile contentFile;
@ -68,7 +86,7 @@ ContentFile ContextManager::createContentFile(const QString &filePath) const
return contentFile; return contentFile;
} }
ProgrammingLanguage ContextManager::getDocumentLanguage(const DocumentInfo &documentInfo) ProgrammingLanguage ContextManager::getDocumentLanguage(const DocumentInfo &documentInfo) const
{ {
if (!documentInfo.document) { if (!documentInfo.document) {
LOG_MESSAGE("Error: Document is not available for" + documentInfo.filePath); LOG_MESSAGE("Error: Document is not available for" + documentInfo.filePath);
@ -78,9 +96,10 @@ ProgrammingLanguage ContextManager::getDocumentLanguage(const DocumentInfo &docu
return Context::ProgrammingLanguageUtils::fromMimeType(documentInfo.mimeType); return Context::ProgrammingLanguageUtils::fromMimeType(documentInfo.mimeType);
} }
bool ContextManager::isSpecifyCompletion( bool ContextManager::isSpecifyCompletion(const DocumentInfo &documentInfo) const
const DocumentInfo &documentInfo, const Settings::GeneralSettings &generalSettings)
{ {
const auto &generalSettings = Settings::generalSettings();
Context::ProgrammingLanguage documentLanguage = getDocumentLanguage(documentInfo); Context::ProgrammingLanguage documentLanguage = getDocumentLanguage(documentInfo);
Context::ProgrammingLanguage preset1Language = Context::ProgrammingLanguageUtils::fromString( Context::ProgrammingLanguage preset1Language = Context::ProgrammingLanguageUtils::fromString(
generalSettings.preset1Language.displayForIndex(generalSettings.preset1Language())); generalSettings.preset1Language.displayForIndex(generalSettings.preset1Language()));

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2024 Petr Mironychev * Copyright (C) 2025 Petr Mironychev
* *
* This file is part of QodeAssist. * This file is part of QodeAssist.
* *
@ -23,31 +23,30 @@
#include <QString> #include <QString>
#include "ContentFile.hpp" #include "ContentFile.hpp"
#include "IDocumentReader.hpp" #include "IContextManager.hpp"
#include "ProgrammingLanguage.hpp" #include "ProgrammingLanguage.hpp"
#include "settings/GeneralSettings.hpp"
namespace ProjectExplorer {
class Project;
}
namespace QodeAssist::Context { namespace QodeAssist::Context {
class ContextManager : public QObject class ContextManager : public QObject, public IContextManager
{ {
Q_OBJECT Q_OBJECT
public: public:
static ContextManager &instance();
QString readFile(const QString &filePath) const;
QList<ContentFile> getContentFiles(const QStringList &filePaths) const;
static ProgrammingLanguage getDocumentLanguage(const DocumentInfo &documentInfo);
static bool isSpecifyCompletion(
const DocumentInfo &documentInfo, const Settings::GeneralSettings &generalSettings);
private:
explicit ContextManager(QObject *parent = nullptr); explicit ContextManager(QObject *parent = nullptr);
~ContextManager() = default; ~ContextManager() override = default;
ContextManager(const ContextManager &) = delete;
ContextManager &operator=(const ContextManager &) = delete; QString readFile(const QString &filePath) const override;
ContentFile createContentFile(const QString &filePath) const; QList<ContentFile> getContentFiles(const QStringList &filePaths) const override;
QStringList getProjectSourceFiles(ProjectExplorer::Project *project) const override;
ContentFile createContentFile(const QString &filePath) const override;
ProgrammingLanguage getDocumentLanguage(const DocumentInfo &documentInfo) const override;
bool isSpecifyCompletion(const DocumentInfo &documentInfo) const override;
}; };
} // namespace QodeAssist::Context } // namespace QodeAssist::Context

View File

@ -0,0 +1,49 @@
/*
* 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 <QObject>
#include <QString>
#include "ContentFile.hpp"
#include "IDocumentReader.hpp"
#include "ProgrammingLanguage.hpp"
namespace ProjectExplorer {
class Project;
}
namespace QodeAssist::Context {
class IContextManager
{
public:
virtual ~IContextManager() = default;
virtual QString readFile(const QString &filePath) const = 0;
virtual QList<ContentFile> getContentFiles(const QStringList &filePaths) const = 0;
virtual QStringList getProjectSourceFiles(ProjectExplorer::Project *project) const = 0;
virtual ContentFile createContentFile(const QString &filePath) const = 0;
virtual ProgrammingLanguage getDocumentLanguage(const DocumentInfo &documentInfo) const = 0;
virtual bool isSpecifyCompletion(const DocumentInfo &documentInfo) const = 0;
};
} // namespace QodeAssist::Context