refactor: Move QuickRefactor to Session way

This commit is contained in:
Petr Mironychev
2026-06-11 14:18:44 +02:00
parent 7bfe9d6f0e
commit e65ac23e66
7 changed files with 83 additions and 87 deletions

View File

@@ -18,9 +18,16 @@
#include <AgentFactory.hpp> #include <AgentFactory.hpp>
#include <AgentRouter.hpp> #include <AgentRouter.hpp>
#include <ConversationHistory.hpp> #include <ConversationHistory.hpp>
#include <PluginBlocks.hpp>
#include <Session.hpp> #include <Session.hpp>
#include <SystemPromptBuilder.hpp>
#include "sources/common/ContextData.hpp" #include "sources/common/ContextData.hpp"
#include <LLMQore/ContentBlocks.hpp>
#include <memory>
#include <vector>
#include "CodeHandler.hpp" #include "CodeHandler.hpp"
#include "context/DocumentContextReader.hpp" #include "context/DocumentContextReader.hpp"
#include "context/Utils.hpp" #include "context/Utils.hpp"
@@ -271,7 +278,7 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
editorContext.append(m_contextManager->openedFilesContext({filePath})); editorContext.append(m_contextManager->openedFilesContext({filePath}));
if (!editorContext.isEmpty()) if (!editorContext.isEmpty())
context.systemPrompt = editorContext; session->systemPrompt()->setLayer(QStringLiteral("completion.context"), editorContext);
connect(session, &Session::finished, this, [this, session](const LLMQore::RequestID &, const QString &) { connect(session, &Session::finished, this, [this, session](const LLMQore::RequestID &, const QString &) {
onCompletionFinished(requestIdForSession(session)); onCompletionFinished(requestIdForSession(session));
@@ -284,7 +291,10 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
client->setTransferTimeout( client->setTransferTimeout(
static_cast<int>(m_generalSettings.requestTimeout() * 1000)); static_cast<int>(m_generalSettings.requestTimeout() * 1000));
const LLMQore::RequestID requestId = session->sendCompletion(std::move(context)); std::vector<std::unique_ptr<LLMQore::ContentBlock>> blocks;
blocks.push_back(std::make_unique<CompletionContent>(
context.prefix.value_or(QString()), context.suffix.value_or(QString())));
const LLMQore::RequestID requestId = session->send(std::move(blocks), /*toolsOverride=*/false);
if (requestId.isEmpty()) { if (requestId.isEmpty()) {
QString error = QString("Failed to start completion request for agent '%1': %2") QString error = QString("Failed to start completion request for agent '%1': %2")
.arg(agentName, session->lastError().message); .arg(agentName, session->lastError().message);

View File

@@ -30,6 +30,7 @@
#include <AgentFactory.hpp> #include <AgentFactory.hpp>
#include <AgentRouter.hpp> #include <AgentRouter.hpp>
#include <ConversationHistory.hpp>
#include <Session.hpp> #include <Session.hpp>
#include <SessionManager.hpp> #include <SessionManager.hpp>
#include <SystemPromptBuilder.hpp> #include <SystemPromptBuilder.hpp>
@@ -184,14 +185,13 @@ void QuickRefactorHandler::prepareAndSendRequest(
m_isRefactoringInProgress = true; m_isRefactoringInProgress = true;
connect( connect(
client, &::LLMQore::BaseClient::requestCompleted, session, &Session::finished, this,
this, &QuickRefactorHandler::handleFullResponse, Qt::UniqueConnection); [this](const LLMQore::RequestID &id, const QString &) { onRefactorFinished(id); });
connect( connect(
client, &::LLMQore::BaseClient::requestFinalized, session, &Session::failed, this,
this, &QuickRefactorHandler::handleRequestFinalized, Qt::UniqueConnection); [this](const LLMQore::RequestID &id, const QodeAssist::ErrorInfo &error) {
connect( onRefactorFailed(id, error);
client, &::LLMQore::BaseClient::requestFailed, });
this, &QuickRefactorHandler::handleRequestFailed, Qt::UniqueConnection);
std::vector<std::unique_ptr<LLMQore::ContentBlock>> blocks; std::vector<std::unique_ptr<LLMQore::ContentBlock>> blocks;
const QString userMessage = instructions.isEmpty() const QString userMessage = instructions.isEmpty()
@@ -371,32 +371,6 @@ QString QuickRefactorHandler::buildSystemPrompt(
return systemPrompt; return systemPrompt;
} }
void QuickRefactorHandler::handleLLMResponse(
const QString &response, const QJsonObject &request, bool isComplete)
{
if (request["id"].toString() != m_lastRequestId) {
return;
}
if (isComplete) {
m_isRefactoringInProgress = false;
QString cleanedResponse = ResponseCleaner::clean(response);
RefactorResult result;
result.newText = cleanedResponse;
result.insertRange = m_currentRange;
result.success = true;
result.editor = m_currentEditor;
LOG_MESSAGE("Refactoring completed successfully. New code to insert: ");
LOG_MESSAGE("---------- BEGIN REFACTORED CODE ----------");
LOG_MESSAGE(cleanedResponse);
LOG_MESSAGE("----------- END REFACTORED CODE -----------");
emit refactoringCompleted(result);
}
}
void QuickRefactorHandler::cancelRequest() void QuickRefactorHandler::cancelRequest()
{ {
if (!m_isRefactoringInProgress) if (!m_isRefactoringInProgress)
@@ -410,12 +384,8 @@ void QuickRefactorHandler::cancelRequest()
if (it != m_activeRequests.end()) { if (it != m_activeRequests.end()) {
Session *session = it.value().session; Session *session = it.value().session;
m_activeRequests.erase(it); m_activeRequests.erase(it);
if (session) { if (session && m_sessionManager)
if (auto *client = session->client()) m_sessionManager->removeSession(session);
disconnect(client, nullptr, this, nullptr);
if (m_sessionManager)
m_sessionManager->removeSession(session);
}
} }
RefactorResult result; RefactorResult result;
@@ -424,7 +394,7 @@ void QuickRefactorHandler::cancelRequest()
emit refactoringCompleted(result); emit refactoringCompleted(result);
} }
void QuickRefactorHandler::handleFullResponse(const QString &requestId, const QString &fullText) void QuickRefactorHandler::onRefactorFinished(const QString &requestId)
{ {
if (requestId != m_lastRequestId) if (requestId != m_lastRequestId)
return; return;
@@ -434,30 +404,36 @@ void QuickRefactorHandler::handleFullResponse(const QString &requestId, const QS
if (it != m_activeRequests.end()) if (it != m_activeRequests.end())
m_activeRequests.erase(it); m_activeRequests.erase(it);
QJsonObject request{{"id", requestId}}; QString fullText;
handleLLMResponse(fullText, request, true); if (session) {
if (auto *history = session->history(); history && !history->isEmpty())
fullText = history->messages().back().text();
}
m_isRefactoringInProgress = false;
m_lastRequestId.clear();
const QString cleanedResponse = ResponseCleaner::clean(fullText);
RefactorResult result;
result.newText = cleanedResponse;
result.insertRange = m_currentRange;
result.success = true;
result.editor = m_currentEditor;
LOG_MESSAGE("Refactoring completed successfully. New code to insert: ");
LOG_MESSAGE("---------- BEGIN REFACTORED CODE ----------");
LOG_MESSAGE(cleanedResponse);
LOG_MESSAGE("----------- END REFACTORED CODE -----------");
emit refactoringCompleted(result);
if (session && m_sessionManager) if (session && m_sessionManager)
m_sessionManager->removeSession(session); m_sessionManager->removeSession(session);
} }
void QuickRefactorHandler::handleRequestFinalized( void QuickRefactorHandler::onRefactorFailed(
const ::LLMQore::RequestID &requestId, const ::LLMQore::CompletionInfo &info) const QString &requestId, const QodeAssist::ErrorInfo &error)
{
if (requestId != m_lastRequestId || !info.usage)
return;
const auto &u = *info.usage;
LOG_MESSAGE(
QString("Quick refactor usage [%1]: prompt=%2 completion=%3 cached=%4 reasoning=%5")
.arg(requestId)
.arg(u.promptTokens)
.arg(u.completionTokens)
.arg(u.cachedPromptTokens)
.arg(u.reasoningTokens));
}
void QuickRefactorHandler::handleRequestFailed(const QString &requestId, const QString &error)
{ {
if (requestId != m_lastRequestId) if (requestId != m_lastRequestId)
return; return;
@@ -468,9 +444,11 @@ void QuickRefactorHandler::handleRequestFailed(const QString &requestId, const Q
m_activeRequests.erase(it); m_activeRequests.erase(it);
m_isRefactoringInProgress = false; m_isRefactoringInProgress = false;
m_lastRequestId.clear();
RefactorResult result; RefactorResult result;
result.success = false; result.success = false;
result.errorMessage = error; result.errorMessage = error.message;
result.editor = m_currentEditor; result.editor = m_currentEditor;
emit refactoringCompleted(result); emit refactoringCompleted(result);

View File

@@ -12,6 +12,7 @@
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
#include <utils/textutils.h> #include <utils/textutils.h>
#include <ErrorInfo.hpp>
#include <context/ContextManager.hpp> #include <context/ContextManager.hpp>
#include <context/IDocumentReader.hpp> #include <context/IDocumentReader.hpp>
@@ -49,19 +50,14 @@ public:
signals: signals:
void refactoringCompleted(const QodeAssist::RefactorResult &result); void refactoringCompleted(const QodeAssist::RefactorResult &result);
private slots:
void handleFullResponse(const QString &requestId, const QString &fullText);
void handleRequestFinalized(
const ::LLMQore::RequestID &requestId, const ::LLMQore::CompletionInfo &info);
void handleRequestFailed(const QString &requestId, const QString &error);
private: private:
void prepareAndSendRequest( void prepareAndSendRequest(
TextEditor::TextEditorWidget *editor, TextEditor::TextEditorWidget *editor,
const QString &instructions, const QString &instructions,
const Utils::Text::Range &range); const Utils::Text::Range &range);
void handleLLMResponse(const QString &response, const QJsonObject &request, bool isComplete); void onRefactorFinished(const QString &requestId);
void onRefactorFailed(const QString &requestId, const QodeAssist::ErrorInfo &error);
QString buildSystemPrompt( QString buildSystemPrompt(
TextEditor::TextEditorWidget *editor, const Utils::Text::Range &range); TextEditor::TextEditorWidget *editor, const Utils::Text::Range &range);
QString pickRefactorAgent(const QString &filePath) const; QString pickRefactorAgent(const QString &filePath) const;

View File

@@ -31,6 +31,7 @@
#include <AgentFactory.hpp> #include <AgentFactory.hpp>
#include <ContextData.hpp> #include <ContextData.hpp>
#include <ContextRenderer.hpp> #include <ContextRenderer.hpp>
#include <PluginBlocks.hpp>
#include <GenericProvider.hpp> #include <GenericProvider.hpp>
#include <Provider.hpp> #include <Provider.hpp>
#include <ProviderInstance.hpp> #include <ProviderInstance.hpp>
@@ -532,11 +533,11 @@ int main(int argc, char *argv[])
auto dispatch = [&] { auto dispatch = [&] {
if (fimMode) { if (fimMode) {
Templates::ContextData ctx; const QString prefix = turns.value(0);
ctx.prefix = turns.value(0); const QString suffix = parser.isSet(suffixOpt) ? parser.value(suffixOpt) : QString();
if (parser.isSet(suffixOpt)) std::vector<std::unique_ptr<LLMQore::ContentBlock>> blocks;
ctx.suffix = parser.value(suffixOpt); blocks.push_back(std::make_unique<QodeAssist::CompletionContent>(prefix, suffix));
if (session->sendCompletion(std::move(ctx)).isEmpty()) { if (session->send(std::move(blocks), /*toolsOverride=*/false).isEmpty()) {
err() << "Failed to dispatch FIM request: " << session->lastError().message << "\n"; err() << "Failed to dispatch FIM request: " << session->lastError().message << "\n";
exitCode = 1; exitCode = 1;
QCoreApplication::quit(); QCoreApplication::quit();

View File

@@ -31,6 +31,24 @@ private:
QString m_mediaType; QString m_mediaType;
}; };
class CompletionContent : public LLMQore::ContentBlock
{
public:
CompletionContent(QString prefix, QString suffix)
: m_prefix(std::move(prefix))
, m_suffix(std::move(suffix))
{}
QString type() const override { return QStringLiteral("completion"); }
QString prefix() const { return m_prefix; }
QString suffix() const { return m_suffix; }
private:
QString m_prefix;
QString m_suffix;
};
class StoredAttachmentContent : public LLMQore::ContentBlock class StoredAttachmentContent : public LLMQore::ContentBlock
{ {
public: public:

View File

@@ -134,17 +134,6 @@ LLMQore::RequestID Session::sendText(const QString &text)
return send(std::move(blocks)); return send(std::move(blocks));
} }
LLMQore::RequestID Session::sendCompletion(Templates::ContextData ctx)
{
if (!isValid()) {
m_lastError = makeError(ErrorCategory::Config, invalidReason());
return {};
}
if (isInFlight())
cancel();
return dispatchContext(std::move(ctx), /*tools=*/false);
}
LLMQore::RequestID Session::send( LLMQore::RequestID Session::send(
std::vector<std::unique_ptr<LLMQore::ContentBlock>> userBlocks, std::vector<std::unique_ptr<LLMQore::ContentBlock>> userBlocks,
std::optional<bool> toolsOverride) std::optional<bool> toolsOverride)
@@ -290,6 +279,12 @@ Templates::ContextData Session::buildLegacyContext(
if (m.role() == Message::Role::System) if (m.role() == Message::Role::System)
continue; continue;
if (auto *cc = m.lastBlockOfType<CompletionContent>()) {
ctx.prefix = cc->prefix();
ctx.suffix = cc->suffix();
continue;
}
QVector<ContentBlockEntry> blockEntries; QVector<ContentBlockEntry> blockEntries;
for (const auto &blockPtr : m.blocks()) { for (const auto &blockPtr : m.blocks()) {

View File

@@ -66,8 +66,6 @@ public:
LLMQore::RequestID sendText(const QString &text); LLMQore::RequestID sendText(const QString &text);
LLMQore::RequestID sendCompletion(Templates::ContextData ctx);
void cancel(); void cancel();
signals: signals: