refactor: Remove duplicated signals

This commit is contained in:
Petr Mironychev
2026-04-01 01:07:37 +02:00
parent 666aa94e81
commit cd017ae1f2
28 changed files with 186 additions and 977 deletions

View File

@ -34,8 +34,8 @@ add_definitions(
-DQODEASSIST_QT_CREATOR_VERSION_PATCH=${QODEASSIST_QT_CREATOR_VERSION_PATCH} -DQODEASSIST_QT_CREATOR_VERSION_PATCH=${QODEASSIST_QT_CREATOR_VERSION_PATCH}
) )
add_subdirectory(pluginllmcore)
add_subdirectory(sources/external/llmcore) add_subdirectory(sources/external/llmcore)
add_subdirectory(pluginllmcore)
add_subdirectory(settings) add_subdirectory(settings)
add_subdirectory(logger) add_subdirectory(logger)
add_subdirectory(UIControls) add_subdirectory(UIControls)
@ -62,8 +62,9 @@ add_qtc_plugin(QodeAssist
QtCreator::ExtensionSystem QtCreator::ExtensionSystem
QtCreator::Utils QtCreator::Utils
QtCreator::CPlusPlus QtCreator::CPlusPlus
QodeAssistChatViewplugin
LLMCore LLMCore
PluginLLMCore
QodeAssistChatViewplugin
SOURCES SOURCES
.github/workflows/build_cmake.yml .github/workflows/build_cmake.yml
.github/workflows/README.md .github/workflows/README.md

View File

@ -18,6 +18,8 @@
*/ */
#include "ChatCompressor.hpp" #include "ChatCompressor.hpp"
#include <LLMCore/BaseClient.hpp>
#include "ChatModel.hpp" #include "ChatModel.hpp"
#include "GeneralSettings.hpp" #include "GeneralSettings.hpp"
#include "PromptTemplateManager.hpp" #include "PromptTemplateManager.hpp"
@ -76,7 +78,6 @@ void ChatCompressor::startCompression(const QString &chatFilePath, ChatModel *ch
m_chatModel = chatModel; m_chatModel = chatModel;
m_originalChatPath = chatFilePath; m_originalChatPath = chatFilePath;
m_accumulatedSummary.clear(); m_accumulatedSummary.clear();
m_currentRequestId = QUuid::createUuid().toString(QUuid::WithoutBraces);
emit compressionStarted(); emit compressionStarted();
@ -98,8 +99,8 @@ void ChatCompressor::startCompression(const QString &chatFilePath, ChatModel *ch
buildRequestPayload(payload, promptTemplate); buildRequestPayload(payload, promptTemplate);
m_currentRequestId = m_provider->sendRequest(requestUrl, payload);
LOG_MESSAGE(QString("Starting compression request: %1").arg(m_currentRequestId)); LOG_MESSAGE(QString("Starting compression request: %1").arg(m_currentRequestId));
m_provider->sendRequest(m_currentRequestId, requestUrl, payload);
} }
bool ChatCompressor::isCompressing() const bool ChatCompressor::isCompressing() const
@ -266,23 +267,25 @@ bool ChatCompressor::createCompressedChatFile(
void ChatCompressor::connectProviderSignals() void ChatCompressor::connectProviderSignals()
{ {
auto *c = m_provider->client();
m_connections.append(connect( m_connections.append(connect(
m_provider, c,
&PluginLLMCore::Provider::partialResponseReceived, &::LLMCore::BaseClient::chunkReceived,
this, this,
&ChatCompressor::onPartialResponseReceived, &ChatCompressor::onPartialResponseReceived,
Qt::UniqueConnection)); Qt::UniqueConnection));
m_connections.append(connect( m_connections.append(connect(
m_provider, c,
&PluginLLMCore::Provider::fullResponseReceived, &::LLMCore::BaseClient::requestCompleted,
this, this,
&ChatCompressor::onFullResponseReceived, &ChatCompressor::onFullResponseReceived,
Qt::UniqueConnection)); Qt::UniqueConnection));
m_connections.append(connect( m_connections.append(connect(
m_provider, c,
&PluginLLMCore::Provider::requestFailed, &::LLMCore::BaseClient::requestFailed,
this, this,
&ChatCompressor::onRequestFailed, &ChatCompressor::onRequestFailed,
Qt::UniqueConnection)); Qt::UniqueConnection));

View File

@ -19,6 +19,8 @@
#include "ClientInterface.hpp" #include "ClientInterface.hpp"
#include <LLMCore/BaseClient.hpp>
#include <projectexplorer/buildconfiguration.h> #include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <texteditor/textdocument.h> #include <texteditor/textdocument.h>
@ -274,63 +276,49 @@ void ClientInterface::sendMessage(
useTools, useTools,
useThinking); useThinking);
QString requestId = QUuid::createUuid().toString(); connect(
provider->client(),
&::LLMCore::BaseClient::chunkReceived,
this,
&ClientInterface::handlePartialResponse,
Qt::UniqueConnection);
connect(
provider->client(),
&::LLMCore::BaseClient::requestCompleted,
this,
&ClientInterface::handleFullResponse,
Qt::UniqueConnection);
connect(
provider->client(),
&::LLMCore::BaseClient::requestFailed,
this,
&ClientInterface::handleRequestFailed,
Qt::UniqueConnection);
connect(
provider->client(),
&::LLMCore::BaseClient::toolStarted,
this,
&ClientInterface::handleToolExecutionStarted,
Qt::UniqueConnection);
connect(
provider->client(),
&::LLMCore::BaseClient::toolResultReady,
this,
&ClientInterface::handleToolExecutionCompleted,
Qt::UniqueConnection);
connect(
provider->client(),
&::LLMCore::BaseClient::thinkingBlockReceived,
this,
&ClientInterface::handleThinkingBlockReceived,
Qt::UniqueConnection);
auto requestId = provider->sendRequest(config.url, config.providerRequest);
QJsonObject request{{"id", requestId}}; QJsonObject request{{"id", requestId}};
m_activeRequests[requestId] = {request, provider}; m_activeRequests[requestId] = {request, provider};
emit requestStarted(requestId); emit requestStarted(requestId);
connect(
provider,
&PluginLLMCore::Provider::partialResponseReceived,
this,
&ClientInterface::handlePartialResponse,
Qt::UniqueConnection);
connect(
provider,
&PluginLLMCore::Provider::fullResponseReceived,
this,
&ClientInterface::handleFullResponse,
Qt::UniqueConnection);
connect(
provider,
&PluginLLMCore::Provider::requestFailed,
this,
&ClientInterface::handleRequestFailed,
Qt::UniqueConnection);
connect(
provider,
&PluginLLMCore::Provider::toolExecutionStarted,
this,
&ClientInterface::handleToolExecutionStarted,
Qt::UniqueConnection);
connect(
provider,
&PluginLLMCore::Provider::toolExecutionCompleted,
this,
&ClientInterface::handleToolExecutionCompleted,
Qt::UniqueConnection);
connect(
provider,
&PluginLLMCore::Provider::continuationStarted,
this,
&ClientInterface::handleCleanAccumulatedData,
Qt::UniqueConnection);
connect(
provider,
&PluginLLMCore::Provider::thinkingBlockReceived,
this,
&ClientInterface::handleThinkingBlockReceived,
Qt::UniqueConnection);
connect(
provider,
&PluginLLMCore::Provider::redactedThinkingBlockReceived,
this,
&ClientInterface::handleRedactedThinkingBlockReceived,
Qt::UniqueConnection);
provider->sendRequest(requestId, config.url, config.providerRequest);
if (provider->capabilities().testFlag(PluginLLMCore::ProviderCapability::Tools) if (provider->capabilities().testFlag(PluginLLMCore::ProviderCapability::Tools)
&& provider->toolsManager()) { && provider->toolsManager()) {
@ -368,7 +356,7 @@ void ClientInterface::cancelRequest()
} }
for (auto *provider : providers) { for (auto *provider : providers) {
disconnect(provider, nullptr, this, nullptr); disconnect(provider->client(), nullptr, this, nullptr);
} }
for (auto it = m_activeRequests.begin(); it != m_activeRequests.end(); ++it) { for (auto it = m_activeRequests.begin(); it != m_activeRequests.end(); ++it) {
@ -380,6 +368,7 @@ void ClientInterface::cancelRequest()
m_activeRequests.clear(); m_activeRequests.clear();
m_accumulatedResponses.clear(); m_accumulatedResponses.clear();
m_awaitingContinuation.clear();
LOG_MESSAGE("All requests cancelled and state cleared"); LOG_MESSAGE("All requests cancelled and state cleared");
} }
@ -446,6 +435,12 @@ void ClientInterface::handlePartialResponse(const QString &requestId, const QStr
if (it == m_activeRequests.end()) if (it == m_activeRequests.end())
return; return;
if (m_awaitingContinuation.remove(requestId)) {
m_accumulatedResponses[requestId].clear();
LOG_MESSAGE(
QString("Cleared accumulated responses for continuation request %1").arg(requestId));
}
m_accumulatedResponses[requestId] += partialText; m_accumulatedResponses[requestId] += partialText;
const RequestContext &ctx = it.value(); const RequestContext &ctx = it.value();
@ -476,12 +471,9 @@ void ClientInterface::handleFullResponse(const QString &requestId, const QString
+ ": " + finalText); + ": " + finalText);
emit messageReceivedCompletely(); emit messageReceivedCompletely();
if (it != m_activeRequests.end()) { m_activeRequests.erase(it);
m_activeRequests.erase(it); m_accumulatedResponses.remove(requestId);
} m_awaitingContinuation.remove(requestId);
if (m_accumulatedResponses.contains(requestId)) {
m_accumulatedResponses.remove(requestId);
}
} }
void ClientInterface::handleRequestFailed(const QString &requestId, const QString &error) void ClientInterface::handleRequestFailed(const QString &requestId, const QString &error)
@ -493,18 +485,9 @@ void ClientInterface::handleRequestFailed(const QString &requestId, const QStrin
LOG_MESSAGE(QString("Chat request %1 failed: %2").arg(requestId, error)); LOG_MESSAGE(QString("Chat request %1 failed: %2").arg(requestId, error));
emit errorOccurred(error); emit errorOccurred(error);
if (it != m_activeRequests.end()) { m_activeRequests.erase(it);
m_activeRequests.erase(it); m_accumulatedResponses.remove(requestId);
} m_awaitingContinuation.remove(requestId);
if (m_accumulatedResponses.contains(requestId)) {
m_accumulatedResponses.remove(requestId);
}
}
void ClientInterface::handleCleanAccumulatedData(const QString &requestId)
{
m_accumulatedResponses[requestId].clear();
LOG_MESSAGE(QString("Cleared accumulated responses for continuation request %1").arg(requestId));
} }
void ClientInterface::handleThinkingBlockReceived( void ClientInterface::handleThinkingBlockReceived(
@ -515,19 +498,17 @@ void ClientInterface::handleThinkingBlockReceived(
return; return;
} }
m_chatModel->addThinkingBlock(requestId, thinking, signature); if (m_awaitingContinuation.remove(requestId)) {
} m_accumulatedResponses[requestId].clear();
void ClientInterface::handleRedactedThinkingBlockReceived(
const QString &requestId, const QString &signature)
{
if (!m_activeRequests.contains(requestId)) {
LOG_MESSAGE( LOG_MESSAGE(
QString("Ignoring redacted thinking block for non-chat request: %1").arg(requestId)); QString("Cleared accumulated responses for continuation request %1").arg(requestId));
return;
} }
m_chatModel->addRedactedThinkingBlock(requestId, signature); if (thinking.isEmpty()) {
m_chatModel->addRedactedThinkingBlock(requestId, signature);
} else {
m_chatModel->addThinkingBlock(requestId, thinking, signature);
}
} }
void ClientInterface::handleToolExecutionStarted( void ClientInterface::handleToolExecutionStarted(
@ -539,6 +520,7 @@ void ClientInterface::handleToolExecutionStarted(
} }
m_chatModel->addToolExecutionStatus(requestId, toolId, toolName); m_chatModel->addToolExecutionStatus(requestId, toolId, toolName);
m_awaitingContinuation.insert(requestId);
} }
void ClientInterface::handleToolExecutionCompleted( void ClientInterface::handleToolExecutionCompleted(

View File

@ -20,6 +20,7 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QSet>
#include <QString> #include <QString>
#include <QVector> #include <QVector>
@ -62,10 +63,8 @@ private slots:
void handlePartialResponse(const QString &requestId, const QString &partialText); void handlePartialResponse(const QString &requestId, const QString &partialText);
void handleFullResponse(const QString &requestId, const QString &fullText); void handleFullResponse(const QString &requestId, const QString &fullText);
void handleRequestFailed(const QString &requestId, const QString &error); void handleRequestFailed(const QString &requestId, const QString &error);
void handleCleanAccumulatedData(const QString &requestId);
void handleThinkingBlockReceived( void handleThinkingBlockReceived(
const QString &requestId, const QString &thinking, const QString &signature); const QString &requestId, const QString &thinking, const QString &signature);
void handleRedactedThinkingBlockReceived(const QString &requestId, const QString &signature);
void handleToolExecutionStarted( void handleToolExecutionStarted(
const QString &requestId, const QString &toolId, const QString &toolName); const QString &requestId, const QString &toolId, const QString &toolName);
void handleToolExecutionCompleted( void handleToolExecutionCompleted(
@ -97,6 +96,7 @@ private:
QHash<QString, RequestContext> m_activeRequests; QHash<QString, RequestContext> m_activeRequests;
QHash<QString, QString> m_accumulatedResponses; QHash<QString, QString> m_accumulatedResponses;
QSet<QString> m_awaitingContinuation;
}; };
} // namespace QodeAssist::Chat } // namespace QodeAssist::Chat

View File

@ -19,6 +19,7 @@
#include "LLMClientInterface.hpp" #include "LLMClientInterface.hpp"
#include <LLMCore/BaseClient.hpp>
#include <QJsonDocument> #include <QJsonDocument>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkReply> #include <QNetworkReply>
@ -122,8 +123,6 @@ void LLMClientInterface::sendData(const QByteArray &data)
} else if (method == "textDocument/didOpen") { } else if (method == "textDocument/didOpen") {
handleTextDocumentDidOpen(request); handleTextDocumentDidOpen(request);
} else if (method == "getCompletionsCycling") { } else if (method == "getCompletionsCycling") {
QString requestId = request["id"].toString();
m_performanceLogger.startTimeMeasurement(requestId);
handleCompletion(request); handleCompletion(request);
} else if (method == "$/cancelRequest") { } else if (method == "$/cancelRequest") {
handleCancelRequest(); handleCancelRequest();
@ -144,7 +143,7 @@ void LLMClientInterface::handleCancelRequest()
} }
for (auto *provider : providers) { for (auto *provider : providers) {
disconnect(provider, nullptr, this, nullptr); disconnect(provider->client(), nullptr, this, nullptr);
} }
for (auto it = m_activeRequests.begin(); it != m_activeRequests.end(); ++it) { for (auto it = m_activeRequests.begin(); it != m_activeRequests.end(); ++it) {
@ -360,25 +359,22 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
return; return;
} }
QString requestId = request["id"].toString();
m_performanceLogger.startTimeMeasurement(requestId);
m_activeRequests[requestId] = {request, provider};
connect( connect(
provider, provider->client(),
&PluginLLMCore::Provider::fullResponseReceived, &::LLMCore::BaseClient::requestCompleted,
this, this,
&LLMClientInterface::handleFullResponse, &LLMClientInterface::handleFullResponse,
Qt::UniqueConnection); Qt::UniqueConnection);
connect( connect(
provider, provider->client(),
&PluginLLMCore::Provider::requestFailed, &::LLMCore::BaseClient::requestFailed,
this, this,
&LLMClientInterface::handleRequestFailed, &LLMClientInterface::handleRequestFailed,
Qt::UniqueConnection); Qt::UniqueConnection);
provider->sendRequest(requestId, config.url, config.providerRequest); auto requestId = provider->sendRequest(config.url, config.providerRequest);
m_activeRequests[requestId] = {request, provider};
m_performanceLogger.startTimeMeasurement(requestId);
} }
PluginLLMCore::ContextData LLMClientInterface::prepareContext( PluginLLMCore::ContextData LLMClientInterface::prepareContext(

View File

@ -19,6 +19,7 @@
#include "QuickRefactorHandler.hpp" #include "QuickRefactorHandler.hpp"
#include <LLMCore/BaseClient.hpp>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QUuid> #include <QUuid>
@ -173,29 +174,27 @@ void QuickRefactorHandler::prepareAndSendRequest(
enableTools, enableTools,
enableThinking); enableThinking);
QString requestId = QUuid::createUuid().toString();
m_lastRequestId = requestId;
QJsonObject request{{"id", requestId}};
m_isRefactoringInProgress = true; m_isRefactoringInProgress = true;
m_activeRequests[requestId] = {request, provider};
connect( connect(
provider, provider->client(),
&PluginLLMCore::Provider::fullResponseReceived, &::LLMCore::BaseClient::requestCompleted,
this, this,
&QuickRefactorHandler::handleFullResponse, &QuickRefactorHandler::handleFullResponse,
Qt::UniqueConnection); Qt::UniqueConnection);
connect( connect(
provider, provider->client(),
&PluginLLMCore::Provider::requestFailed, &::LLMCore::BaseClient::requestFailed,
this, this,
&QuickRefactorHandler::handleRequestFailed, &QuickRefactorHandler::handleRequestFailed,
Qt::UniqueConnection); Qt::UniqueConnection);
provider->sendRequest(requestId, config.url, config.providerRequest); auto requestId = provider->sendRequest(config.url, config.providerRequest);
m_lastRequestId = requestId;
QJsonObject request{{"id", requestId}};
m_activeRequests[requestId] = {request, provider};
} }
PluginLLMCore::ContextData QuickRefactorHandler::prepareContext( PluginLLMCore::ContextData QuickRefactorHandler::prepareContext(

View File

@ -28,6 +28,7 @@ target_link_libraries(PluginLLMCore
QtCreator::Core QtCreator::Core
QtCreator::Utils QtCreator::Utils
QtCreator::ExtensionSystem QtCreator::ExtensionSystem
LLMCore
PRIVATE PRIVATE
QodeAssistLogger QodeAssistLogger
) )

View File

@ -1,9 +1,61 @@
/*
* Copyright (C) 2024-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 "Provider.hpp" #include "Provider.hpp"
#include <LLMCore/BaseClient.hpp>
#include <LLMCore/ToolsManager.hpp>
#include <Logger.hpp>
namespace QodeAssist::PluginLLMCore { namespace QodeAssist::PluginLLMCore {
Provider::Provider(QObject *parent) Provider::Provider(QObject *parent)
: QObject(parent) : QObject(parent)
{} {}
RequestID Provider::sendRequest(const QUrl &url, const QJsonObject &payload)
{
auto *c = client();
QUrl baseUrl(url);
baseUrl.setPath("");
c->setUrl(baseUrl.toString());
c->setApiKey(apiKey());
auto requestId = c->sendMessage(payload);
LOG_MESSAGE(
QString("%1: Sending request %2 to %3").arg(name(), requestId, url.toString()));
return requestId;
}
void Provider::cancelRequest(const RequestID &requestId)
{
LOG_MESSAGE(QString("%1: Cancelling request %2").arg(name(), requestId));
client()->cancelRequest(requestId);
}
::LLMCore::ToolsManager *Provider::toolsManager() const
{
return client()->tools();
}
} // namespace QodeAssist::PluginLLMCore } // namespace QodeAssist::PluginLLMCore

View File

@ -21,10 +21,10 @@
#include <QFlags> #include <QFlags>
#include <QFuture> #include <QFuture>
#include <utils/environment.h>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <utils/environment.h>
#include "ContextData.hpp" #include "ContextData.hpp"
#include "IToolsManager.hpp" #include "IToolsManager.hpp"
@ -32,6 +32,7 @@
#include "RequestType.hpp" #include "RequestType.hpp"
namespace LLMCore { namespace LLMCore {
class BaseClient;
class ToolsManager; class ToolsManager;
} }
@ -73,34 +74,13 @@ public:
virtual QString apiKey() const = 0; virtual QString apiKey() const = 0;
virtual void prepareNetworkRequest(QNetworkRequest &networkRequest) const = 0; virtual void prepareNetworkRequest(QNetworkRequest &networkRequest) const = 0;
virtual ProviderID providerID() const = 0; virtual ProviderID providerID() const = 0;
virtual void sendRequest(const RequestID &requestId, const QUrl &url, const QJsonObject &payload)
= 0;
virtual ProviderCapabilities capabilities() const { return {}; } virtual ProviderCapabilities capabilities() const { return {}; }
virtual void cancelRequest(const RequestID &requestId) = 0; virtual ::LLMCore::BaseClient *client() const = 0;
virtual ::LLMCore::ToolsManager *toolsManager() const { return nullptr; }
signals:
void partialResponseReceived(
const QodeAssist::PluginLLMCore::RequestID &requestId, const QString &partialText);
void fullResponseReceived(
const QodeAssist::PluginLLMCore::RequestID &requestId, const QString &fullText);
void requestFailed(const QodeAssist::PluginLLMCore::RequestID &requestId, const QString &error);
void toolExecutionStarted(
const QString &requestId, const QString &toolId, const QString &toolName);
void toolExecutionCompleted(
const QString &requestId,
const QString &toolId,
const QString &toolName,
const QString &result);
void continuationStarted(const QodeAssist::PluginLLMCore::RequestID &requestId);
void thinkingBlockReceived(
const QString &requestId, const QString &thinking, const QString &signature);
void redactedThinkingBlockReceived(const QString &requestId, const QString &signature);
RequestID sendRequest(const QUrl &url, const QJsonObject &payload);
void cancelRequest(const RequestID &requestId);
::LLMCore::ToolsManager *toolsManager() const;
}; };
} // namespace QodeAssist::PluginLLMCore } // namespace QodeAssist::PluginLLMCore

View File

@ -176,74 +176,6 @@ PluginLLMCore::ProviderID ClaudeProvider::providerID() const
return PluginLLMCore::ProviderID::Claude; return PluginLLMCore::ProviderID::Claude;
} }
void ClaudeProvider::sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload)
{
QUrl baseUrl(url);
baseUrl.setPath("");
m_client->setUrl(baseUrl.toString());
m_client->setApiKey(apiKey());
::LLMCore::RequestCallbacks callbacks;
callbacks.onChunk = [this, requestId](const ::LLMCore::RequestID &, const QString &chunk) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
emit partialResponseReceived(requestId, chunk);
};
callbacks.onCompleted
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &fullText) {
emit fullResponseReceived(requestId, fullText);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onFailed
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &error) {
emit requestFailed(requestId, error);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onThinkingBlock = [this, requestId](const ::LLMCore::RequestID &,
const QString &thinking,
const QString &signature) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
if (thinking.isEmpty()) {
emit redactedThinkingBlockReceived(requestId, signature);
} else {
emit thinkingBlockReceived(requestId, thinking, signature);
}
};
callbacks.onToolStarted = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName) {
emit toolExecutionStarted(requestId, toolId, toolName);
m_awaitingContinuation.insert(requestId);
};
callbacks.onToolResult = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName,
const QString &result) {
emit toolExecutionCompleted(requestId, toolId, toolName, result);
};
auto clientId = m_client->sendMessage(payload, callbacks);
m_providerToClientIds[requestId] = clientId;
m_clientToProviderIds[clientId] = requestId;
LOG_MESSAGE(QString("ClaudeProvider: Sending request %1 (client: %2) to %3")
.arg(requestId, clientId, url.toString()));
}
PluginLLMCore::ProviderCapabilities ClaudeProvider::capabilities() const PluginLLMCore::ProviderCapabilities ClaudeProvider::capabilities() const
{ {
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Thinking return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Thinking
@ -251,21 +183,9 @@ PluginLLMCore::ProviderCapabilities ClaudeProvider::capabilities() const
| PluginLLMCore::ProviderCapability::ModelListing; | PluginLLMCore::ProviderCapability::ModelListing;
} }
void ClaudeProvider::cancelRequest(const PluginLLMCore::RequestID &requestId) ::LLMCore::BaseClient *ClaudeProvider::client() const
{ {
LOG_MESSAGE(QString("ClaudeProvider: Cancelling request %1").arg(requestId)); return m_client;
if (m_providerToClientIds.contains(requestId)) {
auto clientId = m_providerToClientIds.take(requestId);
m_clientToProviderIds.remove(clientId);
m_client->cancelRequest(clientId);
}
m_awaitingContinuation.remove(requestId);
}
::LLMCore::ToolsManager *ClaudeProvider::toolsManager() const
{
return m_client->tools();
} }
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -19,8 +19,6 @@
#pragma once #pragma once
#include <QSet>
#include <pluginllmcore/Provider.hpp> #include <pluginllmcore/Provider.hpp>
#include <LLMCore/ClaudeClient.hpp> #include <LLMCore/ClaudeClient.hpp>
@ -49,20 +47,12 @@ public:
QString apiKey() const override; QString apiKey() const override;
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override; void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
PluginLLMCore::ProviderID providerID() const override; PluginLLMCore::ProviderID providerID() const override;
void sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload) override;
PluginLLMCore::ProviderCapabilities capabilities() const override; PluginLLMCore::ProviderCapabilities capabilities() const override;
void cancelRequest(const PluginLLMCore::RequestID &requestId) override;
::LLMCore::ToolsManager *toolsManager() const override; ::LLMCore::BaseClient *client() const override;
private: private:
::LLMCore::ClaudeClient *m_client; ::LLMCore::ClaudeClient *m_client;
QHash<PluginLLMCore::RequestID, ::LLMCore::RequestID> m_providerToClientIds;
QHash<::LLMCore::RequestID, PluginLLMCore::RequestID> m_clientToProviderIds;
QSet<PluginLLMCore::RequestID> m_awaitingContinuation;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -192,74 +192,6 @@ PluginLLMCore::ProviderID GoogleAIProvider::providerID() const
return PluginLLMCore::ProviderID::GoogleAI; return PluginLLMCore::ProviderID::GoogleAI;
} }
void GoogleAIProvider::sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload)
{
QUrl baseUrl(url);
baseUrl.setPath("");
m_client->setUrl(baseUrl.toString());
m_client->setApiKey(apiKey());
::LLMCore::RequestCallbacks callbacks;
callbacks.onChunk = [this, requestId](const ::LLMCore::RequestID &, const QString &chunk) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
emit partialResponseReceived(requestId, chunk);
};
callbacks.onCompleted
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &fullText) {
emit fullResponseReceived(requestId, fullText);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onFailed
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &error) {
emit requestFailed(requestId, error);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onThinkingBlock = [this, requestId](const ::LLMCore::RequestID &,
const QString &thinking,
const QString &signature) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
if (thinking.isEmpty()) {
emit redactedThinkingBlockReceived(requestId, signature);
} else {
emit thinkingBlockReceived(requestId, thinking, signature);
}
};
callbacks.onToolStarted = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName) {
emit toolExecutionStarted(requestId, toolId, toolName);
m_awaitingContinuation.insert(requestId);
};
callbacks.onToolResult = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName,
const QString &result) {
emit toolExecutionCompleted(requestId, toolId, toolName, result);
};
auto clientId = m_client->sendMessage(payload, callbacks);
m_providerToClientIds[requestId] = clientId;
m_clientToProviderIds[clientId] = requestId;
LOG_MESSAGE(QString("GoogleAIProvider: Sending request %1 (client: %2) to %3")
.arg(requestId, clientId, url.toString()));
}
PluginLLMCore::ProviderCapabilities GoogleAIProvider::capabilities() const PluginLLMCore::ProviderCapabilities GoogleAIProvider::capabilities() const
{ {
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Thinking return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Thinking
@ -267,21 +199,9 @@ PluginLLMCore::ProviderCapabilities GoogleAIProvider::capabilities() const
| PluginLLMCore::ProviderCapability::ModelListing; | PluginLLMCore::ProviderCapability::ModelListing;
} }
void GoogleAIProvider::cancelRequest(const PluginLLMCore::RequestID &requestId) ::LLMCore::BaseClient *GoogleAIProvider::client() const
{ {
LOG_MESSAGE(QString("GoogleAIProvider: Cancelling request %1").arg(requestId)); return m_client;
if (m_providerToClientIds.contains(requestId)) {
auto clientId = m_providerToClientIds.take(requestId);
m_clientToProviderIds.remove(clientId);
m_client->cancelRequest(clientId);
}
m_awaitingContinuation.remove(requestId);
}
::LLMCore::ToolsManager *GoogleAIProvider::toolsManager() const
{
return m_client->tools();
} }
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -19,8 +19,6 @@
#pragma once #pragma once
#include <QSet>
#include <pluginllmcore/Provider.hpp> #include <pluginllmcore/Provider.hpp>
#include <LLMCore/GoogleAIClient.hpp> #include <LLMCore/GoogleAIClient.hpp>
@ -49,20 +47,12 @@ public:
QString apiKey() const override; QString apiKey() const override;
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override; void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
PluginLLMCore::ProviderID providerID() const override; PluginLLMCore::ProviderID providerID() const override;
void sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload) override;
PluginLLMCore::ProviderCapabilities capabilities() const override; PluginLLMCore::ProviderCapabilities capabilities() const override;
void cancelRequest(const PluginLLMCore::RequestID &requestId) override;
::LLMCore::ToolsManager *toolsManager() const override; ::LLMCore::BaseClient *client() const override;
private: private:
::LLMCore::GoogleAIClient *m_client; ::LLMCore::GoogleAIClient *m_client;
QHash<PluginLLMCore::RequestID, ::LLMCore::RequestID> m_providerToClientIds;
QHash<::LLMCore::RequestID, PluginLLMCore::RequestID> m_clientToProviderIds;
QSet<PluginLLMCore::RequestID> m_awaitingContinuation;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -104,92 +104,12 @@ PluginLLMCore::ProviderID LMStudioProvider::providerID() const
return PluginLLMCore::ProviderID::LMStudio; return PluginLLMCore::ProviderID::LMStudio;
} }
void LMStudioProvider::sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload)
{
QUrl baseUrl(url);
baseUrl.setPath("");
m_client->setUrl(baseUrl.toString());
m_client->setApiKey(apiKey());
::LLMCore::RequestCallbacks callbacks;
callbacks.onChunk = [this, requestId](const ::LLMCore::RequestID &, const QString &chunk) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
emit partialResponseReceived(requestId, chunk);
};
callbacks.onCompleted
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &fullText) {
emit fullResponseReceived(requestId, fullText);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onFailed
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &error) {
emit requestFailed(requestId, error);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onThinkingBlock = [this, requestId](const ::LLMCore::RequestID &,
const QString &thinking,
const QString &signature) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
if (thinking.isEmpty()) {
emit redactedThinkingBlockReceived(requestId, signature);
} else {
emit thinkingBlockReceived(requestId, thinking, signature);
}
};
callbacks.onToolStarted = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName) {
emit toolExecutionStarted(requestId, toolId, toolName);
m_awaitingContinuation.insert(requestId);
};
callbacks.onToolResult = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName,
const QString &result) {
emit toolExecutionCompleted(requestId, toolId, toolName, result);
};
auto clientId = m_client->sendMessage(payload, callbacks);
m_providerToClientIds[requestId] = clientId;
m_clientToProviderIds[clientId] = requestId;
LOG_MESSAGE(QString("LMStudioProvider: Sending request %1 (client: %2) to %3")
.arg(requestId, clientId, url.toString()));
}
PluginLLMCore::ProviderCapabilities LMStudioProvider::capabilities() const PluginLLMCore::ProviderCapabilities LMStudioProvider::capabilities() const
{ {
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
| PluginLLMCore::ProviderCapability::ModelListing; | PluginLLMCore::ProviderCapability::ModelListing;
} }
void LMStudioProvider::cancelRequest(const PluginLLMCore::RequestID &requestId)
{
LOG_MESSAGE(QString("LMStudioProvider: Cancelling request %1").arg(requestId));
if (m_providerToClientIds.contains(requestId)) {
auto clientId = m_providerToClientIds.take(requestId);
m_clientToProviderIds.remove(clientId);
m_client->cancelRequest(clientId);
}
m_awaitingContinuation.remove(requestId);
}
void LMStudioProvider::prepareRequest( void LMStudioProvider::prepareRequest(
QJsonObject &request, QJsonObject &request,
PluginLLMCore::PromptTemplate *prompt, PluginLLMCore::PromptTemplate *prompt,
@ -235,9 +155,9 @@ void LMStudioProvider::prepareRequest(
} }
} }
::LLMCore::ToolsManager *LMStudioProvider::toolsManager() const ::LLMCore::BaseClient *LMStudioProvider::client() const
{ {
return m_client->tools(); return m_client;
} }
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -19,8 +19,6 @@
#pragma once #pragma once
#include <QSet>
#include <LLMCore/OpenAIClient.hpp> #include <LLMCore/OpenAIClient.hpp>
#include <pluginllmcore/Provider.hpp> #include <pluginllmcore/Provider.hpp>
@ -48,20 +46,12 @@ public:
QString apiKey() const override; QString apiKey() const override;
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override; void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
PluginLLMCore::ProviderID providerID() const override; PluginLLMCore::ProviderID providerID() const override;
void sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload) override;
PluginLLMCore::ProviderCapabilities capabilities() const override; PluginLLMCore::ProviderCapabilities capabilities() const override;
void cancelRequest(const PluginLLMCore::RequestID &requestId) override;
::LLMCore::ToolsManager *toolsManager() const override; ::LLMCore::BaseClient *client() const override;
private: private:
::LLMCore::OpenAIClient *m_client; ::LLMCore::OpenAIClient *m_client;
QHash<PluginLLMCore::RequestID, ::LLMCore::RequestID> m_providerToClientIds;
QHash<::LLMCore::RequestID, PluginLLMCore::RequestID> m_clientToProviderIds;
QSet<PluginLLMCore::RequestID> m_awaitingContinuation;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -164,94 +164,14 @@ PluginLLMCore::ProviderID LlamaCppProvider::providerID() const
return PluginLLMCore::ProviderID::LlamaCpp; return PluginLLMCore::ProviderID::LlamaCpp;
} }
void LlamaCppProvider::sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload)
{
QUrl baseUrl(url);
baseUrl.setPath("");
m_client->setUrl(baseUrl.toString());
m_client->setApiKey(apiKey());
::LLMCore::RequestCallbacks callbacks;
callbacks.onChunk = [this, requestId](const ::LLMCore::RequestID &, const QString &chunk) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
emit partialResponseReceived(requestId, chunk);
};
callbacks.onCompleted
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &fullText) {
emit fullResponseReceived(requestId, fullText);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onFailed
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &error) {
emit requestFailed(requestId, error);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onThinkingBlock = [this, requestId](const ::LLMCore::RequestID &,
const QString &thinking,
const QString &signature) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
if (thinking.isEmpty()) {
emit redactedThinkingBlockReceived(requestId, signature);
} else {
emit thinkingBlockReceived(requestId, thinking, signature);
}
};
callbacks.onToolStarted = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName) {
emit toolExecutionStarted(requestId, toolId, toolName);
m_awaitingContinuation.insert(requestId);
};
callbacks.onToolResult = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName,
const QString &result) {
emit toolExecutionCompleted(requestId, toolId, toolName, result);
};
auto clientId = m_client->sendMessage(payload, callbacks);
m_providerToClientIds[requestId] = clientId;
m_clientToProviderIds[clientId] = requestId;
LOG_MESSAGE(QString("LlamaCppProvider: Sending request %1 (client: %2) to %3")
.arg(requestId, clientId, url.toString()));
}
PluginLLMCore::ProviderCapabilities LlamaCppProvider::capabilities() const PluginLLMCore::ProviderCapabilities LlamaCppProvider::capabilities() const
{ {
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image; return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image;
} }
void LlamaCppProvider::cancelRequest(const PluginLLMCore::RequestID &requestId) ::LLMCore::BaseClient *LlamaCppProvider::client() const
{ {
LOG_MESSAGE(QString("LlamaCppProvider: Cancelling request %1").arg(requestId)); return m_client;
if (m_providerToClientIds.contains(requestId)) {
auto clientId = m_providerToClientIds.take(requestId);
m_clientToProviderIds.remove(clientId);
m_client->cancelRequest(clientId);
}
m_awaitingContinuation.remove(requestId);
}
::LLMCore::ToolsManager *LlamaCppProvider::toolsManager() const
{
return m_client->tools();
} }
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -19,8 +19,6 @@
#pragma once #pragma once
#include <QSet>
#include <pluginllmcore/Provider.hpp> #include <pluginllmcore/Provider.hpp>
#include <LLMCore/LlamaCppClient.hpp> #include <LLMCore/LlamaCppClient.hpp>
@ -49,20 +47,12 @@ public:
QString apiKey() const override; QString apiKey() const override;
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override; void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
PluginLLMCore::ProviderID providerID() const override; PluginLLMCore::ProviderID providerID() const override;
void sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload) override;
PluginLLMCore::ProviderCapabilities capabilities() const override; PluginLLMCore::ProviderCapabilities capabilities() const override;
void cancelRequest(const PluginLLMCore::RequestID &requestId) override;
::LLMCore::ToolsManager *toolsManager() const override; ::LLMCore::BaseClient *client() const override;
private: private:
::LLMCore::LlamaCppClient *m_client; ::LLMCore::LlamaCppClient *m_client;
QHash<PluginLLMCore::RequestID, ::LLMCore::RequestID> m_providerToClientIds;
QHash<::LLMCore::RequestID, PluginLLMCore::RequestID> m_clientToProviderIds;
QSet<PluginLLMCore::RequestID> m_awaitingContinuation;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -116,92 +116,12 @@ PluginLLMCore::ProviderID MistralAIProvider::providerID() const
return PluginLLMCore::ProviderID::MistralAI; return PluginLLMCore::ProviderID::MistralAI;
} }
void MistralAIProvider::sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload)
{
QUrl baseUrl(url);
baseUrl.setPath("");
m_client->setUrl(baseUrl.toString());
m_client->setApiKey(apiKey());
::LLMCore::RequestCallbacks callbacks;
callbacks.onChunk = [this, requestId](const ::LLMCore::RequestID &, const QString &chunk) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
emit partialResponseReceived(requestId, chunk);
};
callbacks.onCompleted
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &fullText) {
emit fullResponseReceived(requestId, fullText);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onFailed
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &error) {
emit requestFailed(requestId, error);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onThinkingBlock = [this, requestId](const ::LLMCore::RequestID &,
const QString &thinking,
const QString &signature) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
if (thinking.isEmpty()) {
emit redactedThinkingBlockReceived(requestId, signature);
} else {
emit thinkingBlockReceived(requestId, thinking, signature);
}
};
callbacks.onToolStarted = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName) {
emit toolExecutionStarted(requestId, toolId, toolName);
m_awaitingContinuation.insert(requestId);
};
callbacks.onToolResult = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName,
const QString &result) {
emit toolExecutionCompleted(requestId, toolId, toolName, result);
};
auto clientId = m_client->sendMessage(payload, callbacks);
m_providerToClientIds[requestId] = clientId;
m_clientToProviderIds[clientId] = requestId;
LOG_MESSAGE(QString("MistralAIProvider: Sending request %1 (client: %2) to %3")
.arg(requestId, clientId, url.toString()));
}
PluginLLMCore::ProviderCapabilities MistralAIProvider::capabilities() const PluginLLMCore::ProviderCapabilities MistralAIProvider::capabilities() const
{ {
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
| PluginLLMCore::ProviderCapability::ModelListing; | PluginLLMCore::ProviderCapability::ModelListing;
} }
void MistralAIProvider::cancelRequest(const PluginLLMCore::RequestID &requestId)
{
LOG_MESSAGE(QString("MistralAIProvider: Cancelling request %1").arg(requestId));
if (m_providerToClientIds.contains(requestId)) {
auto clientId = m_providerToClientIds.take(requestId);
m_clientToProviderIds.remove(clientId);
m_client->cancelRequest(clientId);
}
m_awaitingContinuation.remove(requestId);
}
void MistralAIProvider::prepareRequest( void MistralAIProvider::prepareRequest(
QJsonObject &request, QJsonObject &request,
PluginLLMCore::PromptTemplate *prompt, PluginLLMCore::PromptTemplate *prompt,
@ -247,9 +167,9 @@ void MistralAIProvider::prepareRequest(
} }
} }
::LLMCore::ToolsManager *MistralAIProvider::toolsManager() const ::LLMCore::BaseClient *MistralAIProvider::client() const
{ {
return m_client->tools(); return m_client;
} }
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -19,8 +19,6 @@
#pragma once #pragma once
#include <QSet>
#include <LLMCore/OpenAIClient.hpp> #include <LLMCore/OpenAIClient.hpp>
#include <pluginllmcore/Provider.hpp> #include <pluginllmcore/Provider.hpp>
@ -48,20 +46,12 @@ public:
QString apiKey() const override; QString apiKey() const override;
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override; void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
PluginLLMCore::ProviderID providerID() const override; PluginLLMCore::ProviderID providerID() const override;
void sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload) override;
PluginLLMCore::ProviderCapabilities capabilities() const override; PluginLLMCore::ProviderCapabilities capabilities() const override;
void cancelRequest(const PluginLLMCore::RequestID &requestId) override;
::LLMCore::ToolsManager *toolsManager() const override; ::LLMCore::BaseClient *client() const override;
private: private:
::LLMCore::OpenAIClient *m_client; ::LLMCore::OpenAIClient *m_client;
QHash<PluginLLMCore::RequestID, ::LLMCore::RequestID> m_providerToClientIds;
QHash<::LLMCore::RequestID, PluginLLMCore::RequestID> m_clientToProviderIds;
QSet<PluginLLMCore::RequestID> m_awaitingContinuation;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -199,74 +199,6 @@ PluginLLMCore::ProviderID OllamaProvider::providerID() const
return PluginLLMCore::ProviderID::Ollama; return PluginLLMCore::ProviderID::Ollama;
} }
void OllamaProvider::sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload)
{
QUrl baseUrl(url);
baseUrl.setPath("");
m_client->setUrl(baseUrl.toString());
m_client->setApiKey(apiKey());
::LLMCore::RequestCallbacks callbacks;
callbacks.onChunk = [this, requestId](const ::LLMCore::RequestID &, const QString &chunk) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
emit partialResponseReceived(requestId, chunk);
};
callbacks.onCompleted
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &fullText) {
emit fullResponseReceived(requestId, fullText);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onFailed
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &error) {
emit requestFailed(requestId, error);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onThinkingBlock = [this, requestId](const ::LLMCore::RequestID &,
const QString &thinking,
const QString &signature) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
if (thinking.isEmpty()) {
emit redactedThinkingBlockReceived(requestId, signature);
} else {
emit thinkingBlockReceived(requestId, thinking, signature);
}
};
callbacks.onToolStarted = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName) {
emit toolExecutionStarted(requestId, toolId, toolName);
m_awaitingContinuation.insert(requestId);
};
callbacks.onToolResult = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName,
const QString &result) {
emit toolExecutionCompleted(requestId, toolId, toolName, result);
};
auto clientId = m_client->sendMessage(payload, callbacks);
m_providerToClientIds[requestId] = clientId;
m_clientToProviderIds[clientId] = requestId;
LOG_MESSAGE(QString("OllamaProvider: Sending request %1 (client: %2) to %3")
.arg(requestId, clientId, url.toString()));
}
PluginLLMCore::ProviderCapabilities OllamaProvider::capabilities() const PluginLLMCore::ProviderCapabilities OllamaProvider::capabilities() const
{ {
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Thinking return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Thinking
@ -274,21 +206,9 @@ PluginLLMCore::ProviderCapabilities OllamaProvider::capabilities() const
| PluginLLMCore::ProviderCapability::ModelListing; | PluginLLMCore::ProviderCapability::ModelListing;
} }
void OllamaProvider::cancelRequest(const PluginLLMCore::RequestID &requestId) ::LLMCore::BaseClient *OllamaProvider::client() const
{ {
LOG_MESSAGE(QString("OllamaProvider: Cancelling request %1").arg(requestId)); return m_client;
if (m_providerToClientIds.contains(requestId)) {
auto clientId = m_providerToClientIds.take(requestId);
m_clientToProviderIds.remove(clientId);
m_client->cancelRequest(clientId);
}
m_awaitingContinuation.remove(requestId);
}
::LLMCore::ToolsManager *OllamaProvider::toolsManager() const
{
return m_client->tools();
} }
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -19,8 +19,6 @@
#pragma once #pragma once
#include <QSet>
#include <pluginllmcore/Provider.hpp> #include <pluginllmcore/Provider.hpp>
#include <LLMCore/OllamaClient.hpp> #include <LLMCore/OllamaClient.hpp>
@ -49,20 +47,12 @@ public:
QString apiKey() const override; QString apiKey() const override;
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override; void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
PluginLLMCore::ProviderID providerID() const override; PluginLLMCore::ProviderID providerID() const override;
void sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload) override;
PluginLLMCore::ProviderCapabilities capabilities() const override; PluginLLMCore::ProviderCapabilities capabilities() const override;
void cancelRequest(const PluginLLMCore::RequestID &requestId) override;
::LLMCore::ToolsManager *toolsManager() const override; ::LLMCore::BaseClient *client() const override;
private: private:
::LLMCore::OllamaClient *m_client; ::LLMCore::OllamaClient *m_client;
QHash<PluginLLMCore::RequestID, ::LLMCore::RequestID> m_providerToClientIds;
QHash<::LLMCore::RequestID, PluginLLMCore::RequestID> m_clientToProviderIds;
QSet<PluginLLMCore::RequestID> m_awaitingContinuation;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -151,94 +151,14 @@ PluginLLMCore::ProviderID OpenAICompatProvider::providerID() const
return PluginLLMCore::ProviderID::OpenAICompatible; return PluginLLMCore::ProviderID::OpenAICompatible;
} }
void OpenAICompatProvider::sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload)
{
QUrl baseUrl(url);
baseUrl.setPath("");
m_client->setUrl(baseUrl.toString());
m_client->setApiKey(apiKey());
::LLMCore::RequestCallbacks callbacks;
callbacks.onChunk = [this, requestId](const ::LLMCore::RequestID &, const QString &chunk) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
emit partialResponseReceived(requestId, chunk);
};
callbacks.onCompleted
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &fullText) {
emit fullResponseReceived(requestId, fullText);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onFailed
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &error) {
emit requestFailed(requestId, error);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onThinkingBlock = [this, requestId](const ::LLMCore::RequestID &,
const QString &thinking,
const QString &signature) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
if (thinking.isEmpty()) {
emit redactedThinkingBlockReceived(requestId, signature);
} else {
emit thinkingBlockReceived(requestId, thinking, signature);
}
};
callbacks.onToolStarted = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName) {
emit toolExecutionStarted(requestId, toolId, toolName);
m_awaitingContinuation.insert(requestId);
};
callbacks.onToolResult = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName,
const QString &result) {
emit toolExecutionCompleted(requestId, toolId, toolName, result);
};
auto clientId = m_client->sendMessage(payload, callbacks);
m_providerToClientIds[requestId] = clientId;
m_clientToProviderIds[clientId] = requestId;
LOG_MESSAGE(QString("OpenAICompatProvider: Sending request %1 (client: %2) to %3")
.arg(requestId, clientId, url.toString()));
}
PluginLLMCore::ProviderCapabilities OpenAICompatProvider::capabilities() const PluginLLMCore::ProviderCapabilities OpenAICompatProvider::capabilities() const
{ {
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image; return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image;
} }
void OpenAICompatProvider::cancelRequest(const PluginLLMCore::RequestID &requestId) ::LLMCore::BaseClient *OpenAICompatProvider::client() const
{ {
LOG_MESSAGE(QString("OpenAICompatProvider: Cancelling request %1").arg(requestId)); return m_client;
if (m_providerToClientIds.contains(requestId)) {
auto clientId = m_providerToClientIds.take(requestId);
m_clientToProviderIds.remove(clientId);
m_client->cancelRequest(clientId);
}
m_awaitingContinuation.remove(requestId);
}
::LLMCore::ToolsManager *OpenAICompatProvider::toolsManager() const
{
return m_client->tools();
} }
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -19,8 +19,6 @@
#pragma once #pragma once
#include <QSet>
#include <LLMCore/OpenAIClient.hpp> #include <LLMCore/OpenAIClient.hpp>
#include <pluginllmcore/Provider.hpp> #include <pluginllmcore/Provider.hpp>
@ -48,20 +46,12 @@ public:
QString apiKey() const override; QString apiKey() const override;
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override; void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
PluginLLMCore::ProviderID providerID() const override; PluginLLMCore::ProviderID providerID() const override;
void sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload) override;
PluginLLMCore::ProviderCapabilities capabilities() const override; PluginLLMCore::ProviderCapabilities capabilities() const override;
void cancelRequest(const PluginLLMCore::RequestID &requestId) override;
::LLMCore::ToolsManager *toolsManager() const override; ::LLMCore::BaseClient *client() const override;
private: private:
::LLMCore::OpenAIClient *m_client; ::LLMCore::OpenAIClient *m_client;
QHash<PluginLLMCore::RequestID, ::LLMCore::RequestID> m_providerToClientIds;
QHash<::LLMCore::RequestID, PluginLLMCore::RequestID> m_clientToProviderIds;
QSet<PluginLLMCore::RequestID> m_awaitingContinuation;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -181,95 +181,15 @@ PluginLLMCore::ProviderID OpenAIProvider::providerID() const
return PluginLLMCore::ProviderID::OpenAI; return PluginLLMCore::ProviderID::OpenAI;
} }
void OpenAIProvider::sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload)
{
QUrl baseUrl(url);
baseUrl.setPath("");
m_client->setUrl(baseUrl.toString());
m_client->setApiKey(apiKey());
::LLMCore::RequestCallbacks callbacks;
callbacks.onChunk = [this, requestId](const ::LLMCore::RequestID &, const QString &chunk) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
emit partialResponseReceived(requestId, chunk);
};
callbacks.onCompleted
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &fullText) {
emit fullResponseReceived(requestId, fullText);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onFailed
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &error) {
emit requestFailed(requestId, error);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onThinkingBlock = [this, requestId](const ::LLMCore::RequestID &,
const QString &thinking,
const QString &signature) {
if (m_awaitingContinuation.remove(requestId)) {
emit continuationStarted(requestId);
}
if (thinking.isEmpty()) {
emit redactedThinkingBlockReceived(requestId, signature);
} else {
emit thinkingBlockReceived(requestId, thinking, signature);
}
};
callbacks.onToolStarted = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName) {
emit toolExecutionStarted(requestId, toolId, toolName);
m_awaitingContinuation.insert(requestId);
};
callbacks.onToolResult = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName,
const QString &result) {
emit toolExecutionCompleted(requestId, toolId, toolName, result);
};
auto clientId = m_client->sendMessage(payload, callbacks);
m_providerToClientIds[requestId] = clientId;
m_clientToProviderIds[clientId] = requestId;
LOG_MESSAGE(QString("OpenAIProvider: Sending request %1 (client: %2) to %3")
.arg(requestId, clientId, url.toString()));
}
PluginLLMCore::ProviderCapabilities OpenAIProvider::capabilities() const PluginLLMCore::ProviderCapabilities OpenAIProvider::capabilities() const
{ {
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
| PluginLLMCore::ProviderCapability::ModelListing; | PluginLLMCore::ProviderCapability::ModelListing;
} }
void OpenAIProvider::cancelRequest(const PluginLLMCore::RequestID &requestId) ::LLMCore::BaseClient *OpenAIProvider::client() const
{ {
LOG_MESSAGE(QString("OpenAIProvider: Cancelling request %1").arg(requestId)); return m_client;
if (m_providerToClientIds.contains(requestId)) {
auto clientId = m_providerToClientIds.take(requestId);
m_clientToProviderIds.remove(clientId);
m_client->cancelRequest(clientId);
}
m_awaitingContinuation.remove(requestId);
}
::LLMCore::ToolsManager *OpenAIProvider::toolsManager() const
{
return m_client->tools();
} }
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -19,8 +19,6 @@
#pragma once #pragma once
#include <QSet>
#include <LLMCore/OpenAIClient.hpp> #include <LLMCore/OpenAIClient.hpp>
#include <pluginllmcore/Provider.hpp> #include <pluginllmcore/Provider.hpp>
@ -48,20 +46,12 @@ public:
QString apiKey() const override; QString apiKey() const override;
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override; void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
PluginLLMCore::ProviderID providerID() const override; PluginLLMCore::ProviderID providerID() const override;
void sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload) override;
PluginLLMCore::ProviderCapabilities capabilities() const override; PluginLLMCore::ProviderCapabilities capabilities() const override;
void cancelRequest(const PluginLLMCore::RequestID &requestId) override;
::LLMCore::ToolsManager *toolsManager() const override; ::LLMCore::BaseClient *client() const override;
private: private:
::LLMCore::OpenAIClient *m_client; ::LLMCore::OpenAIClient *m_client;
QHash<PluginLLMCore::RequestID, ::LLMCore::RequestID> m_providerToClientIds;
QHash<::LLMCore::RequestID, PluginLLMCore::RequestID> m_clientToProviderIds;
QSet<PluginLLMCore::RequestID> m_awaitingContinuation;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -222,71 +222,6 @@ PluginLLMCore::ProviderID OpenAIResponsesProvider::providerID() const
return PluginLLMCore::ProviderID::OpenAIResponses; return PluginLLMCore::ProviderID::OpenAIResponses;
} }
void OpenAIResponsesProvider::sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload)
{
QUrl baseUrl(url);
baseUrl.setPath("");
m_client->setUrl(baseUrl.toString());
m_client->setApiKey(apiKey());
::LLMCore::RequestCallbacks callbacks;
callbacks.onChunk = [this, requestId](const ::LLMCore::RequestID &, const QString &chunk) {
if (m_awaitingContinuation.remove(requestId))
emit continuationStarted(requestId);
emit partialResponseReceived(requestId, chunk);
};
callbacks.onCompleted
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &fullText) {
emit fullResponseReceived(requestId, fullText);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onFailed
= [this, requestId](const ::LLMCore::RequestID &clientId, const QString &error) {
emit requestFailed(requestId, error);
m_providerToClientIds.remove(requestId);
m_clientToProviderIds.remove(clientId);
m_awaitingContinuation.remove(requestId);
};
callbacks.onThinkingBlock = [this, requestId](const ::LLMCore::RequestID &,
const QString &thinking,
const QString &signature) {
if (m_awaitingContinuation.remove(requestId))
emit continuationStarted(requestId);
if (thinking.isEmpty())
emit redactedThinkingBlockReceived(requestId, signature);
else
emit thinkingBlockReceived(requestId, thinking, signature);
};
callbacks.onToolStarted = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName) {
emit toolExecutionStarted(requestId, toolId, toolName);
m_awaitingContinuation.insert(requestId);
};
callbacks.onToolResult = [this, requestId](const ::LLMCore::RequestID &,
const QString &toolId,
const QString &toolName,
const QString &result) {
emit toolExecutionCompleted(requestId, toolId, toolName, result);
};
auto clientId = m_client->sendMessage(payload, callbacks);
m_providerToClientIds[requestId] = clientId;
m_clientToProviderIds[clientId] = requestId;
LOG_MESSAGE(QString("OpenAIResponsesProvider: Sending request %1 (client: %2) to %3")
.arg(requestId, clientId, url.toString()));
}
PluginLLMCore::ProviderCapabilities OpenAIResponsesProvider::capabilities() const PluginLLMCore::ProviderCapabilities OpenAIResponsesProvider::capabilities() const
{ {
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Thinking return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Thinking
@ -294,21 +229,9 @@ PluginLLMCore::ProviderCapabilities OpenAIResponsesProvider::capabilities() cons
| PluginLLMCore::ProviderCapability::ModelListing; | PluginLLMCore::ProviderCapability::ModelListing;
} }
void OpenAIResponsesProvider::cancelRequest(const PluginLLMCore::RequestID &requestId) ::LLMCore::BaseClient *OpenAIResponsesProvider::client() const
{ {
LOG_MESSAGE(QString("OpenAIResponsesProvider: Cancelling request %1").arg(requestId)); return m_client;
if (m_providerToClientIds.contains(requestId)) {
auto clientId = m_providerToClientIds.take(requestId);
m_clientToProviderIds.remove(clientId);
m_client->cancelRequest(clientId);
}
m_awaitingContinuation.remove(requestId);
}
::LLMCore::ToolsManager *OpenAIResponsesProvider::toolsManager() const
{
return m_client->tools();
} }
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -19,8 +19,6 @@
#pragma once #pragma once
#include <QSet>
#include <LLMCore/OpenAIResponsesClient.hpp> #include <LLMCore/OpenAIResponsesClient.hpp>
#include <pluginllmcore/Provider.hpp> #include <pluginllmcore/Provider.hpp>
@ -48,20 +46,12 @@ public:
QString apiKey() const override; QString apiKey() const override;
void prepareNetworkRequest(QNetworkRequest &networkRequest) const override; void prepareNetworkRequest(QNetworkRequest &networkRequest) const override;
PluginLLMCore::ProviderID providerID() const override; PluginLLMCore::ProviderID providerID() const override;
void sendRequest(
const PluginLLMCore::RequestID &requestId, const QUrl &url, const QJsonObject &payload) override;
PluginLLMCore::ProviderCapabilities capabilities() const override; PluginLLMCore::ProviderCapabilities capabilities() const override;
void cancelRequest(const PluginLLMCore::RequestID &requestId) override;
::LLMCore::ToolsManager *toolsManager() const override; ::LLMCore::BaseClient *client() const override;
private: private:
::LLMCore::OpenAIResponsesClient *m_client; ::LLMCore::OpenAIResponsesClient *m_client;
QHash<PluginLLMCore::RequestID, ::LLMCore::RequestID> m_providerToClientIds;
QHash<::LLMCore::RequestID, PluginLLMCore::RequestID> m_clientToProviderIds;
QSet<PluginLLMCore::RequestID> m_awaitingContinuation;
}; };
} // namespace QodeAssist::Providers } // namespace QodeAssist::Providers

View File

@ -17,6 +17,8 @@ target_link_libraries(QodeAssistTest PRIVATE
GTest::Main GTest::Main
QtCreator::LanguageClient QtCreator::LanguageClient
Context Context
PluginLLMCore
LLMCore
) )
target_compile_definitions(QodeAssistTest PRIVATE CMAKE_CURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") target_compile_definitions(QodeAssistTest PRIVATE CMAKE_CURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")