From bf3c0b3aa058e0cd8b009f4b75a675ef9bbc0f37 Mon Sep 17 00:00:00 2001 From: Petr Mironychev <9195189+Palm1r@users.noreply.github.com> Date: Fri, 24 Jan 2025 00:22:44 +0100 Subject: [PATCH] feat: Add auto sync open files with model context --- ChatView/ChatRootView.cpp | 75 +++++++++++++++++++++++++----- ChatView/ChatRootView.hpp | 18 ++++--- ChatView/ClientInterface.cpp | 9 +--- ChatView/ClientInterface.hpp | 3 +- ChatView/qml/RootItem.qml | 8 ++-- ChatView/qml/parts/BottomBar.qml | 6 +-- settings/ChatAssistantSettings.cpp | 11 +++-- settings/ChatAssistantSettings.hpp | 2 +- settings/SettingsConstants.hpp | 2 +- 9 files changed, 93 insertions(+), 41 deletions(-) diff --git a/ChatView/ChatRootView.cpp b/ChatView/ChatRootView.cpp index f18902f..f6e58de 100644 --- a/ChatView/ChatRootView.cpp +++ b/ChatView/ChatRootView.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "ChatAssistantSettings.hpp" #include "ChatSerializer.hpp" @@ -45,6 +46,13 @@ ChatRootView::ChatRootView(QQuickItem *parent) , m_chatModel(new ChatModel(this)) , m_clientInterface(new ClientInterface(m_chatModel, this)) { + m_isSyncOpenFiles = Settings::chatAssistantSettings().linkOpenFiles(); + connect(&Settings::chatAssistantSettings().linkOpenFiles, &Utils::BaseAspect::changed, + this, + [this](){ + setIsSyncOpenFiles(Settings::chatAssistantSettings().linkOpenFiles()); + }); + auto &settings = Settings::generalSettings(); connect(&settings.caModel, @@ -52,11 +60,6 @@ ChatRootView::ChatRootView(QQuickItem *parent) this, &ChatRootView::currentTemplateChanged); - connect(&Settings::chatAssistantSettings().sharingCurrentFile, - &Utils::BaseAspect::changed, - this, - &ChatRootView::isSharingCurrentFileChanged); - connect( m_clientInterface, &ClientInterface::messageReceivedCompletely, @@ -76,6 +79,13 @@ ChatRootView::ChatRootView(QQuickItem *parent) this, &ChatRootView::updateInputTokensCount); connect(&Settings::chatAssistantSettings().systemPrompt, &Utils::BaseAspect::changed, this, &ChatRootView::updateInputTokensCount); + + auto editors = Core::EditorManager::instance(); + + connect(editors, &Core::EditorManager::editorOpened, this, &ChatRootView::onEditorOpened); + connect(editors, &Core::EditorManager::editorAboutToClose, this, &ChatRootView::onEditorAboutToClose); + connect(editors, &Core::EditorManager::editorsClosed, this, &ChatRootView::onEditorsClosed); + updateInputTokensCount(); } @@ -84,7 +94,7 @@ ChatModel *ChatRootView::chatModel() const return m_chatModel; } -void ChatRootView::sendMessage(const QString &message, bool sharingCurrentFile) +void ChatRootView::sendMessage(const QString &message) { if (m_inputTokensCount > m_chatModel->tokensThreshold()) { QMessageBox::StandardButton reply = QMessageBox::question( @@ -102,7 +112,7 @@ void ChatRootView::sendMessage(const QString &message, bool sharingCurrentFile) } } - m_clientInterface->sendMessage(message, m_attachmentFiles, m_linkedFiles, sharingCurrentFile); + m_clientInterface->sendMessage(message, m_attachmentFiles, m_linkedFiles); clearAttachmentFiles(); } @@ -158,11 +168,6 @@ QString ChatRootView::currentTemplate() const return settings.caModel(); } -bool ChatRootView::isSharingCurrentFile() const -{ - return Settings::chatAssistantSettings().sharingCurrentFile(); -} - void ChatRootView::saveHistory(const QString &filePath) { auto result = ChatSerializer::saveToFile(m_chatModel, filePath); @@ -362,6 +367,14 @@ void ChatRootView::calculateMessageTokensCount(const QString &message) updateInputTokensCount(); } +void ChatRootView::setIsSyncOpenFiles(bool state) +{ + if (m_isSyncOpenFiles != state) { + m_isSyncOpenFiles = state; + emit isSyncOpenFilesChanged(); + } +} + void ChatRootView::updateInputTokensCount() { int inputTokens = m_messageTokensCount; @@ -396,4 +409,42 @@ int ChatRootView::inputTokensCount() const return m_inputTokensCount; } +bool ChatRootView::isSyncOpenFiles() const +{ + return m_isSyncOpenFiles; +} + +void ChatRootView::onEditorOpened(Core::IEditor *editor) +{ + if (auto document = editor->document(); document && isSyncOpenFiles()) { + QString filePath = document->filePath().toString(); + if (!m_linkedFiles.contains(filePath)) { + m_linkedFiles.append(filePath); + emit linkedFilesChanged(); + } + } +} + +void ChatRootView::onEditorAboutToClose(Core::IEditor *editor) +{ + if (auto document = editor->document(); document && isSyncOpenFiles()) { + QString filePath = document->filePath().toString(); + m_linkedFiles.removeOne(filePath); + emit linkedFilesChanged(); + } +} + +void ChatRootView::onEditorsClosed(QList editors) +{ + if (isSyncOpenFiles()) { + for (Core::IEditor *editor : editors) { + if (auto document = editor->document()) { + QString filePath = document->filePath().toString(); + m_linkedFiles.removeOne(filePath); + } + } + emit linkedFilesChanged(); + } +} + } // namespace QodeAssist::Chat diff --git a/ChatView/ChatRootView.hpp b/ChatView/ChatRootView.hpp index 1a17d4d..0eecaaf 100644 --- a/ChatView/ChatRootView.hpp +++ b/ChatView/ChatRootView.hpp @@ -23,6 +23,7 @@ #include "ChatModel.hpp" #include "ClientInterface.hpp" +#include namespace QodeAssist::Chat { @@ -31,8 +32,7 @@ class ChatRootView : public QQuickItem Q_OBJECT Q_PROPERTY(QodeAssist::Chat::ChatModel *chatModel READ chatModel NOTIFY chatModelChanged FINAL) Q_PROPERTY(QString currentTemplate READ currentTemplate NOTIFY currentTemplateChanged FINAL) - Q_PROPERTY(bool isSharingCurrentFile READ isSharingCurrentFile NOTIFY - isSharingCurrentFileChanged FINAL) + Q_PROPERTY(bool isSyncOpenFiles READ isSyncOpenFiles NOTIFY isSyncOpenFilesChanged FINAL) Q_PROPERTY(QStringList attachmentFiles READ attachmentFiles NOTIFY attachmentFilesChanged FINAL) Q_PROPERTY(QStringList linkedFiles READ linkedFiles NOTIFY linkedFilesChanged FINAL) Q_PROPERTY(int inputTokensCount READ inputTokensCount NOTIFY inputTokensCountChanged FINAL) @@ -45,8 +45,6 @@ public: ChatModel *chatModel() const; QString currentTemplate() const; - bool isSharingCurrentFile() const; - void saveHistory(const QString &filePath); void loadHistory(const QString &filePath); @@ -64,12 +62,19 @@ public: Q_INVOKABLE void showLinkFilesDialog(); Q_INVOKABLE void removeFileFromLinkList(int index); Q_INVOKABLE void calculateMessageTokensCount(const QString &message); + Q_INVOKABLE void setIsSyncOpenFiles(bool state); void updateInputTokensCount(); int inputTokensCount() const; + bool isSyncOpenFiles() const; + + void onEditorOpened(Core::IEditor *editor); + void onEditorAboutToClose(Core::IEditor *editor); + void onEditorsClosed(QList editors); + public slots: - void sendMessage(const QString &message, bool sharingCurrentFile = false); + void sendMessage(const QString &message); void copyToClipboard(const QString &text); void cancelRequest(); void clearAttachmentFiles(); @@ -78,10 +83,10 @@ public slots: signals: void chatModelChanged(); void currentTemplateChanged(); - void isSharingCurrentFileChanged(); void attachmentFilesChanged(); void linkedFilesChanged(); void inputTokensCountChanged(); + void isSyncOpenFilesChanged(); private: QString getChatsHistoryDir() const; @@ -95,6 +100,7 @@ private: QStringList m_linkedFiles; int m_messageTokensCount{0}; int m_inputTokensCount{0}; + bool m_isSyncOpenFiles; }; } // namespace QodeAssist::Chat diff --git a/ChatView/ClientInterface.cpp b/ChatView/ClientInterface.cpp index 939e1e6..8de7186 100644 --- a/ChatView/ClientInterface.cpp +++ b/ChatView/ClientInterface.cpp @@ -66,7 +66,7 @@ ClientInterface::ClientInterface(ChatModel *chatModel, QObject *parent) ClientInterface::~ClientInterface() = default; void ClientInterface::sendMessage( - const QString &message, const QList &attachments, const QList &linkedFiles, bool includeCurrentFile) + const QString &message, const QList &attachments, const QList &linkedFiles) { cancelRequest(); @@ -100,13 +100,6 @@ void ClientInterface::sendMessage( if (chatAssistantSettings.useSystemPrompt()) systemPrompt = chatAssistantSettings.systemPrompt(); - if (includeCurrentFile) { - QString fileContext = getCurrentFileContext(); - if (!fileContext.isEmpty()) { - systemPrompt = systemPrompt.append(fileContext); - } - } - if (!linkedFiles.isEmpty()) { systemPrompt = getSystemPromptWithLinkedFiles(systemPrompt, linkedFiles); } diff --git a/ChatView/ClientInterface.hpp b/ChatView/ClientInterface.hpp index aff781d..8dec2d2 100644 --- a/ChatView/ClientInterface.hpp +++ b/ChatView/ClientInterface.hpp @@ -39,8 +39,7 @@ public: void sendMessage( const QString &message, const QList &attachments = {}, - const QList &linkedFiles = {}, - bool includeCurrentFile = false); + const QList &linkedFiles = {}); void clearMessages(); void cancelRequest(); diff --git a/ChatView/qml/RootItem.qml b/ChatView/qml/RootItem.qml index 84bd7b2..1be7325 100644 --- a/ChatView/qml/RootItem.qml +++ b/ChatView/qml/RootItem.qml @@ -188,7 +188,10 @@ ChatRootView { sendButton.onClicked: root.sendChatMessage() stopButton.onClicked: root.cancelRequest() - sharingCurrentFile.checked: root.isSharingCurrentFile + syncOpenFiles { + checked: root.isSyncOpenFiles + onCheckedChanged: root.setIsSyncOpenFiles(bottomBar.syncOpenFiles.checked) + } attachFiles.onClicked: root.showAttachFilesDialog() linkFiles.onClicked: root.showLinkFilesDialog() } @@ -197,7 +200,6 @@ ChatRootView { function clearChat() { root.chatModel.clear() root.clearAttachmentFiles() - root.clearLinkedFiles() } function scrollToBottom() { @@ -205,7 +207,7 @@ ChatRootView { } function sendChatMessage() { - root.sendMessage(messageInput.text, bottomBar.sharingCurrentFile.checked) + root.sendMessage(messageInput.text) messageInput.text = "" scrollToBottom() } diff --git a/ChatView/qml/parts/BottomBar.qml b/ChatView/qml/parts/BottomBar.qml index ffdd939..1040d80 100644 --- a/ChatView/qml/parts/BottomBar.qml +++ b/ChatView/qml/parts/BottomBar.qml @@ -27,7 +27,7 @@ Rectangle { property alias sendButton: sendButtonId property alias stopButton: stopButtonId - property alias sharingCurrentFile: sharingCurrentFileId + property alias syncOpenFiles: syncOpenFilesId property alias attachFiles: attachFilesId property alias linkFiles: linkFilesId @@ -61,9 +61,9 @@ Rectangle { } CheckBox { - id: sharingCurrentFileId + id: syncOpenFilesId - text: qsTr("Share current file with models") + text: qsTr("Sync open files with model context") } QoAButton { diff --git a/settings/ChatAssistantSettings.cpp b/settings/ChatAssistantSettings.cpp index 14fb9cf..c05900a 100644 --- a/settings/ChatAssistantSettings.cpp +++ b/settings/ChatAssistantSettings.cpp @@ -44,15 +44,15 @@ ChatAssistantSettings::ChatAssistantSettings() // Chat Settings chatTokensThreshold.setSettingsKey(Constants::CA_TOKENS_THRESHOLD); - chatTokensThreshold.setLabelText(Tr::tr("Chat History Token Limit:")); + chatTokensThreshold.setLabelText(Tr::tr("Chat history token limit:")); chatTokensThreshold.setToolTip(Tr::tr("Maximum number of tokens in chat history. When " "exceeded, oldest messages will be removed.")); chatTokensThreshold.setRange(1, 900000); chatTokensThreshold.setDefaultValue(8000); - sharingCurrentFile.setSettingsKey(Constants::CA_SHARING_CURRENT_FILE); - sharingCurrentFile.setLabelText(Tr::tr("Share Current File With Assistant by Default")); - sharingCurrentFile.setDefaultValue(true); + linkOpenFiles.setSettingsKey(Constants::CA_LINK_OPEN_FILES); + linkOpenFiles.setLabelText(Tr::tr("Sync open files with assistant by default")); + linkOpenFiles.setDefaultValue(false); stream.setSettingsKey(Constants::CA_STREAM); stream.setDefaultValue(true); @@ -171,7 +171,7 @@ ChatAssistantSettings::ChatAssistantSettings() Space{8}, Group{ title(Tr::tr("Chat Settings")), - Column{Row{chatTokensThreshold, Stretch{1}}, sharingCurrentFile, stream, autosave}}, + Column{Row{chatTokensThreshold, Stretch{1}}, linkOpenFiles, stream, autosave}}, Space{8}, Group{ title(Tr::tr("General Parameters")), @@ -227,6 +227,7 @@ void ChatAssistantSettings::resetSettingsToDefaults() resetAspect(systemPrompt); resetAspect(ollamaLivetime); resetAspect(contextWindow); + resetAspect(linkOpenFiles); } } diff --git a/settings/ChatAssistantSettings.hpp b/settings/ChatAssistantSettings.hpp index 8bf9f84..70bae71 100644 --- a/settings/ChatAssistantSettings.hpp +++ b/settings/ChatAssistantSettings.hpp @@ -34,7 +34,7 @@ public: // Chat settings Utils::IntegerAspect chatTokensThreshold{this}; - Utils::BoolAspect sharingCurrentFile{this}; + Utils::BoolAspect linkOpenFiles{this}; Utils::BoolAspect stream{this}; Utils::BoolAspect autosave{this}; diff --git a/settings/SettingsConstants.hpp b/settings/SettingsConstants.hpp index 71ed0c0..018519b 100644 --- a/settings/SettingsConstants.hpp +++ b/settings/SettingsConstants.hpp @@ -62,7 +62,7 @@ const char CC_STREAM[] = "QodeAssist.ccStream"; const char CC_SMART_PROCESS_INSTRUCT_TEXT[] = "QodeAssist.ccSmartProcessInstructText"; const char CUSTOM_JSON_TEMPLATE[] = "QodeAssist.customJsonTemplate"; const char CA_TOKENS_THRESHOLD[] = "QodeAssist.caTokensThreshold"; -const char CA_SHARING_CURRENT_FILE[] = "QodeAssist.caSharingCurrentFile"; +const char CA_LINK_OPEN_FILES[] = "QodeAssist.caLinkOpenFiles"; const char CA_STREAM[] = "QodeAssist.caStream"; const char CA_AUTOSAVE[] = "QodeAssist.caAutosave";