feat: Add sharing opened files with code completion requests (#156)

This commit is contained in:
Petr Mironychev 2025-04-04 10:38:06 +02:00 committed by GitHub
parent ffaf6bd61b
commit 9d2d70fc63
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 92 additions and 4 deletions

View File

@ -230,6 +230,19 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
if (updatedContext.fileContext.has_value())
systemPrompt.append(updatedContext.fileContext.value());
if (m_completeSettings.useOpenFilesContext()) {
if (provider->providerID() == LLMCore::ProviderID::LlamaCpp) {
for (const auto openedFilePath : m_contextManager->openedFiles({filePath})) {
if (!updatedContext.filesMetadata) {
updatedContext.filesMetadata = QList<LLMCore::FileMetadata>();
}
updatedContext.filesMetadata->append({openedFilePath.first, openedFilePath.second});
}
} else {
systemPrompt.append(m_contextManager->openedFilesContext({filePath}));
}
}
updatedContext.systemPrompt = systemPrompt;
if (promptTemplate->type() == LLMCore::TemplateType::Chat) {
@ -330,6 +343,4 @@ void LLMClientInterface::sendCompletionToClient(
emit messageReceived(LanguageServerProtocol::JsonRpcMessage(response));
}
void LLMClientInterface::parseCurrentMessage() {}
} // namespace QodeAssist

View File

@ -64,7 +64,6 @@ public:
protected:
void startImpl() override;
void parseCurrentMessage() override;
private:
void handleInitialize(const QJsonObject &request);

View File

@ -25,8 +25,10 @@
#include <QTextStream>
#include "settings/GeneralSettings.hpp"
#include <coreplugin/editormanager/editormanager.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectnodes.h>
#include <texteditor/textdocument.h>
#include "Logger.hpp"
@ -107,4 +109,48 @@ bool ContextManager::isSpecifyCompletion(const DocumentInfo &documentInfo) const
return generalSettings.specifyPreset1() && documentLanguage == preset1Language;
}
QList<QPair<QString, QString>> ContextManager::openedFiles(const QStringList excludeFiles) const
{
auto documents = Core::DocumentModel::openedDocuments();
QList<QPair<QString, QString>> files;
for (const auto *document : std::as_const(documents)) {
auto textDocument = qobject_cast<const TextEditor::TextDocument *>(document);
if (!textDocument)
continue;
auto filePath = textDocument->filePath().toUrlishString();
if (!excludeFiles.contains(filePath)) {
files.append({filePath, textDocument->plainText()});
}
}
return files;
}
QString ContextManager::openedFilesContext(const QStringList excludeFiles)
{
QString context = "User files context:\n";
auto documents = Core::DocumentModel::openedDocuments();
for (const auto *document : documents) {
auto textDocument = qobject_cast<const TextEditor::TextDocument *>(document);
if (!textDocument)
continue;
auto filePath = textDocument->filePath().toUrlishString();
if (excludeFiles.contains(filePath))
continue;
context += QString("File: %1\n").arg(filePath);
context += textDocument->plainText();
context += "\n";
}
return context;
}
} // namespace QodeAssist::Context

View File

@ -47,6 +47,8 @@ public:
ProgrammingLanguage getDocumentLanguage(const DocumentInfo &documentInfo) const override;
bool isSpecifyCompletion(const DocumentInfo &documentInfo) const override;
QList<QPair<QString, QString>> openedFiles(const QStringList excludeFiles = QStringList{}) const;
QString openedFilesContext(const QStringList excludeFiles = QStringList{});
};
} // namespace QodeAssist::Context

View File

@ -34,6 +34,13 @@ struct Message
// clang-format on
};
struct FileMetadata
{
QString filePath;
QString content;
bool operator==(const FileMetadata &) const = default;
};
struct ContextData
{
std::optional<QString> systemPrompt;
@ -41,6 +48,7 @@ struct ContextData
std::optional<QString> suffix;
std::optional<QString> fileContext;
std::optional<QVector<Message>> history;
std::optional<QList<FileMetadata>> filesMetadata;
bool operator==(const ContextData &) const = default;
};

View File

@ -206,6 +206,10 @@ CodeCompletionSettings::CodeCompletionSettings()
showProgressWidget.setLabelText(Tr::tr("Show progress indicator during code completion"));
showProgressWidget.setDefaultValue(true);
useOpenFilesContext.setSettingsKey(Constants::CC_USE_OPEN_FILES_CONTEXT);
useOpenFilesContext.setLabelText(Tr::tr("Include context from open files"));
useOpenFilesContext.setDefaultValue(false);
useProjectChangesCache.setSettingsKey(Constants::CC_USE_PROJECT_CHANGES_CACHE);
useProjectChangesCache.setDefaultValue(true);
useProjectChangesCache.setLabelText(Tr::tr("Max Changes Cache Size:"));
@ -286,7 +290,8 @@ CodeCompletionSettings::CodeCompletionSettings()
autoCompletionTypingInterval,
startSuggestionTimer,
Stretch{1}},
showProgressWidget}},
showProgressWidget,
useOpenFilesContext}},
Space{8},
Group{
title(Tr::tr("General Parameters")),
@ -364,6 +369,8 @@ void CodeCompletionSettings::resetSettingsToDefaults()
resetAspect(userMessageTemplateForCC);
resetAspect(systemPromptForNonFimModels);
resetAspect(customLanguages);
resetAspect(showProgressWidget);
resetAspect(useOpenFilesContext);
}
}

View File

@ -45,6 +45,7 @@ public:
Utils::StringListAspect customLanguages{this};
Utils::BoolAspect showProgressWidget{this};
Utils::BoolAspect useOpenFilesContext{this};
// General Parameters Settings
Utils::DoubleAspect temperature{this};

View File

@ -56,6 +56,7 @@ const char CC_PRESET1_URL_HISTORY[] = "QodeAssist.ccPreset1UrlHistory";
const char ENABLE_QODE_ASSIST[] = "QodeAssist.enableQodeAssist";
const char CC_AUTO_COMPLETION[] = "QodeAssist.ccAutoCompletion";
const char CC_SHOW_PROGRESS_WIDGET[] = "QodeAssist.ccShowProgressWidget";
const char CC_USE_OPEN_FILES_CONTEXT[] = "QodeAssist.ccUseOpenFilesContext";
const char ENABLE_LOGGING[] = "QodeAssist.enableLogging";
const char ENABLE_CHECK_UPDATE[] = "QodeAssist.enableCheckUpdate";
const char ENABLE_CHAT[] = "QodeAssist.enableChat";

View File

@ -19,6 +19,8 @@
#pragma once
#include <QJsonArray>
#include "llmcore/PromptTemplate.hpp"
namespace QodeAssist::Templates {
@ -34,6 +36,17 @@ public:
{
request["input_prefix"] = context.prefix.value_or("");
request["input_suffix"] = context.suffix.value_or("");
if (context.filesMetadata && !context.filesMetadata->isEmpty()) {
QJsonArray filesArray;
for (const auto &file : *context.filesMetadata) {
QJsonObject fileObj;
fileObj["filename"] = file.filePath;
fileObj["text"] = file.content;
filesArray.append(fileObj);
}
request["input_extra"] = filesArray;
}
}
QString description() const override