mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-06-12 17:29:13 -04:00
Update LLMQore to v0.0.4 (#339)
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -78,3 +78,5 @@ CMakeLists.txt.user*
|
|||||||
/.cursor
|
/.cursor
|
||||||
/.vscode
|
/.vscode
|
||||||
.qtc_clangd/compile_commands.json
|
.qtc_clangd/compile_commands.json
|
||||||
|
CLAUDE.md
|
||||||
|
/.claude
|
||||||
|
|||||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
|||||||
[submodule "sources/external/llmcore"]
|
[submodule "sources/external/llmqore"]
|
||||||
path = sources/external/llmcore
|
path = sources/external/llmqore
|
||||||
url = https://github.com/Palm1r/llmcore.git
|
url = https://github.com/Palm1r/llmqore.git
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ add_definitions(
|
|||||||
-DQODEASSIST_QT_CREATOR_VERSION_PATCH=${QODEASSIST_QT_CREATOR_VERSION_PATCH}
|
-DQODEASSIST_QT_CREATOR_VERSION_PATCH=${QODEASSIST_QT_CREATOR_VERSION_PATCH}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(sources/external/llmcore)
|
add_subdirectory(sources/external/llmqore)
|
||||||
add_subdirectory(pluginllmcore)
|
add_subdirectory(pluginllmcore)
|
||||||
add_subdirectory(settings)
|
add_subdirectory(settings)
|
||||||
add_subdirectory(logger)
|
add_subdirectory(logger)
|
||||||
@@ -62,7 +62,7 @@ add_qtc_plugin(QodeAssist
|
|||||||
QtCreator::ExtensionSystem
|
QtCreator::ExtensionSystem
|
||||||
QtCreator::Utils
|
QtCreator::Utils
|
||||||
QtCreator::CPlusPlus
|
QtCreator::CPlusPlus
|
||||||
LLMCore
|
LLMQore
|
||||||
PluginLLMCore
|
PluginLLMCore
|
||||||
QodeAssistChatViewplugin
|
QodeAssistChatViewplugin
|
||||||
SOURCES
|
SOURCES
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ target_link_libraries(QodeAssistChatView
|
|||||||
Context
|
Context
|
||||||
QodeAssistUIControlsplugin
|
QodeAssistUIControlsplugin
|
||||||
QodeAssistLogger
|
QodeAssistLogger
|
||||||
LLMCore
|
LLMQore
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(QodeAssistChatView
|
target_include_directories(QodeAssistChatView
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "ChatCompressor.hpp"
|
#include "ChatCompressor.hpp"
|
||||||
|
|
||||||
#include <LLMCore/BaseClient.hpp>
|
#include <LLMQore/BaseClient.hpp>
|
||||||
#include "ChatModel.hpp"
|
#include "ChatModel.hpp"
|
||||||
#include "GeneralSettings.hpp"
|
#include "GeneralSettings.hpp"
|
||||||
#include "PromptTemplateManager.hpp"
|
#include "PromptTemplateManager.hpp"
|
||||||
@@ -83,23 +83,16 @@ void ChatCompressor::startCompression(const QString &chatFilePath, ChatModel *ch
|
|||||||
|
|
||||||
connectProviderSignals();
|
connectProviderSignals();
|
||||||
|
|
||||||
QUrl requestUrl;
|
QJsonObject payload{
|
||||||
QJsonObject payload;
|
{"model", Settings::generalSettings().caModel()}, {"stream", true}};
|
||||||
|
|
||||||
if (m_provider->providerID() == PluginLLMCore::ProviderID::GoogleAI) {
|
|
||||||
requestUrl = QUrl(QString("%1/models/%2:streamGenerateContent?alt=sse")
|
|
||||||
.arg(Settings::generalSettings().caUrl(),
|
|
||||||
Settings::generalSettings().caModel()));
|
|
||||||
} else {
|
|
||||||
requestUrl = QUrl(QString("%1%2").arg(Settings::generalSettings().caUrl(),
|
|
||||||
m_provider->chatEndpoint()));
|
|
||||||
payload["model"] = Settings::generalSettings().caModel();
|
|
||||||
payload["stream"] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
buildRequestPayload(payload, promptTemplate);
|
buildRequestPayload(payload, promptTemplate);
|
||||||
|
|
||||||
m_currentRequestId = m_provider->sendRequest(requestUrl, payload);
|
const QString customEndpoint = Settings::generalSettings().caCustomEndpoint();
|
||||||
|
const QString endpoint = !customEndpoint.isEmpty() ? customEndpoint
|
||||||
|
: promptTemplate->endpoint();
|
||||||
|
m_currentRequestId = m_provider->sendRequest(
|
||||||
|
QUrl(Settings::generalSettings().caUrl()), payload, endpoint);
|
||||||
LOG_MESSAGE(QString("Starting compression request: %1").arg(m_currentRequestId));
|
LOG_MESSAGE(QString("Starting compression request: %1").arg(m_currentRequestId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,21 +264,21 @@ void ChatCompressor::connectProviderSignals()
|
|||||||
|
|
||||||
m_connections.append(connect(
|
m_connections.append(connect(
|
||||||
c,
|
c,
|
||||||
&::LLMCore::BaseClient::chunkReceived,
|
&::LLMQore::BaseClient::chunkReceived,
|
||||||
this,
|
this,
|
||||||
&ChatCompressor::onPartialResponseReceived,
|
&ChatCompressor::onPartialResponseReceived,
|
||||||
Qt::UniqueConnection));
|
Qt::UniqueConnection));
|
||||||
|
|
||||||
m_connections.append(connect(
|
m_connections.append(connect(
|
||||||
c,
|
c,
|
||||||
&::LLMCore::BaseClient::requestCompleted,
|
&::LLMQore::BaseClient::requestCompleted,
|
||||||
this,
|
this,
|
||||||
&ChatCompressor::onFullResponseReceived,
|
&ChatCompressor::onFullResponseReceived,
|
||||||
Qt::UniqueConnection));
|
Qt::UniqueConnection));
|
||||||
|
|
||||||
m_connections.append(connect(
|
m_connections.append(connect(
|
||||||
c,
|
c,
|
||||||
&::LLMCore::BaseClient::requestFailed,
|
&::LLMQore::BaseClient::requestFailed,
|
||||||
this,
|
this,
|
||||||
&ChatCompressor::onRequestFailed,
|
&ChatCompressor::onRequestFailed,
|
||||||
Qt::UniqueConnection));
|
Qt::UniqueConnection));
|
||||||
|
|||||||
@@ -1400,8 +1400,6 @@ void ChatRootView::applyConfiguration(const QString &configName)
|
|||||||
settings.caModel.setValue(config.model);
|
settings.caModel.setValue(config.model);
|
||||||
settings.caTemplate.setValue(config.templateName);
|
settings.caTemplate.setValue(config.templateName);
|
||||||
settings.caUrl.setValue(config.url);
|
settings.caUrl.setValue(config.url);
|
||||||
settings.caEndpointMode.setValue(
|
|
||||||
settings.caEndpointMode.indexForDisplay(config.endpointMode));
|
|
||||||
settings.caCustomEndpoint.setValue(config.customEndpoint);
|
settings.caCustomEndpoint.setValue(config.customEndpoint);
|
||||||
|
|
||||||
settings.writeSettings();
|
settings.writeSettings();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "ClientInterface.hpp"
|
#include "ClientInterface.hpp"
|
||||||
|
|
||||||
#include <LLMCore/BaseClient.hpp>
|
#include <LLMQore/BaseClient.hpp>
|
||||||
|
|
||||||
#include <projectexplorer/buildconfiguration.h>
|
#include <projectexplorer/buildconfiguration.h>
|
||||||
#include <projectexplorer/target.h>
|
#include <projectexplorer/target.h>
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
#include <texteditor/textdocument.h>
|
#include <texteditor/textdocument.h>
|
||||||
#include <texteditor/texteditor.h>
|
#include <texteditor/texteditor.h>
|
||||||
|
|
||||||
#include <LLMCore/ToolsManager.hpp>
|
#include <LLMQore/ToolsManager.hpp>
|
||||||
|
|
||||||
#include "tools/TodoTool.hpp"
|
#include "tools/TodoTool.hpp"
|
||||||
|
|
||||||
@@ -51,7 +51,6 @@
|
|||||||
#include "GeneralSettings.hpp"
|
#include "GeneralSettings.hpp"
|
||||||
#include "Logger.hpp"
|
#include "Logger.hpp"
|
||||||
#include "ProvidersManager.hpp"
|
#include "ProvidersManager.hpp"
|
||||||
#include "RequestConfig.hpp"
|
|
||||||
#include "ToolsSettings.hpp"
|
#include "ToolsSettings.hpp"
|
||||||
#include <RulesLoader.hpp>
|
#include <RulesLoader.hpp>
|
||||||
#include <context/ChangesManager.h>
|
#include <context/ChangesManager.h>
|
||||||
@@ -248,26 +247,11 @@ void ClientInterface::sendMessage(
|
|||||||
|
|
||||||
context.history = messages;
|
context.history = messages;
|
||||||
|
|
||||||
PluginLLMCore::LLMConfig config;
|
QJsonObject payload{
|
||||||
config.requestType = PluginLLMCore::RequestType::Chat;
|
{"model", Settings::generalSettings().caModel()}, {"stream", true}};
|
||||||
config.provider = provider;
|
|
||||||
config.promptTemplate = promptTemplate;
|
|
||||||
if (provider->providerID() == PluginLLMCore::ProviderID::GoogleAI) {
|
|
||||||
QString stream = QString{"streamGenerateContent?alt=sse"};
|
|
||||||
config.url = QUrl(QString("%1/models/%2:%3")
|
|
||||||
.arg(
|
|
||||||
Settings::generalSettings().caUrl(),
|
|
||||||
Settings::generalSettings().caModel(),
|
|
||||||
stream));
|
|
||||||
} else {
|
|
||||||
config.url
|
|
||||||
= QString("%1%2").arg(Settings::generalSettings().caUrl(), provider->chatEndpoint());
|
|
||||||
config.providerRequest
|
|
||||||
= {{"model", Settings::generalSettings().caModel()}, {"stream", true}};
|
|
||||||
}
|
|
||||||
|
|
||||||
config.provider->prepareRequest(
|
provider->prepareRequest(
|
||||||
config.providerRequest,
|
payload,
|
||||||
promptTemplate,
|
promptTemplate,
|
||||||
context,
|
context,
|
||||||
PluginLLMCore::RequestType::Chat,
|
PluginLLMCore::RequestType::Chat,
|
||||||
@@ -276,42 +260,46 @@ void ClientInterface::sendMessage(
|
|||||||
|
|
||||||
connect(
|
connect(
|
||||||
provider->client(),
|
provider->client(),
|
||||||
&::LLMCore::BaseClient::chunkReceived,
|
&::LLMQore::BaseClient::chunkReceived,
|
||||||
this,
|
this,
|
||||||
&ClientInterface::handlePartialResponse,
|
&ClientInterface::handlePartialResponse,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
connect(
|
connect(
|
||||||
provider->client(),
|
provider->client(),
|
||||||
&::LLMCore::BaseClient::requestCompleted,
|
&::LLMQore::BaseClient::requestCompleted,
|
||||||
this,
|
this,
|
||||||
&ClientInterface::handleFullResponse,
|
&ClientInterface::handleFullResponse,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
connect(
|
connect(
|
||||||
provider->client(),
|
provider->client(),
|
||||||
&::LLMCore::BaseClient::requestFailed,
|
&::LLMQore::BaseClient::requestFailed,
|
||||||
this,
|
this,
|
||||||
&ClientInterface::handleRequestFailed,
|
&ClientInterface::handleRequestFailed,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
connect(
|
connect(
|
||||||
provider->client(),
|
provider->client(),
|
||||||
&::LLMCore::BaseClient::toolStarted,
|
&::LLMQore::BaseClient::toolStarted,
|
||||||
this,
|
this,
|
||||||
&ClientInterface::handleToolExecutionStarted,
|
&ClientInterface::handleToolExecutionStarted,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
connect(
|
connect(
|
||||||
provider->client(),
|
provider->client(),
|
||||||
&::LLMCore::BaseClient::toolResultReady,
|
&::LLMQore::BaseClient::toolResultReady,
|
||||||
this,
|
this,
|
||||||
&ClientInterface::handleToolExecutionCompleted,
|
&ClientInterface::handleToolExecutionCompleted,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
connect(
|
connect(
|
||||||
provider->client(),
|
provider->client(),
|
||||||
&::LLMCore::BaseClient::thinkingBlockReceived,
|
&::LLMQore::BaseClient::thinkingBlockReceived,
|
||||||
this,
|
this,
|
||||||
&ClientInterface::handleThinkingBlockReceived,
|
&ClientInterface::handleThinkingBlockReceived,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
|
|
||||||
auto requestId = provider->sendRequest(config.url, config.providerRequest);
|
const QString customEndpoint = Settings::generalSettings().caCustomEndpoint();
|
||||||
|
const QString endpoint = !customEndpoint.isEmpty() ? customEndpoint
|
||||||
|
: promptTemplate->endpoint();
|
||||||
|
auto requestId
|
||||||
|
= provider->sendRequest(QUrl(Settings::generalSettings().caUrl()), payload, endpoint);
|
||||||
QJsonObject request{{"id", requestId}};
|
QJsonObject request{{"id", requestId}};
|
||||||
|
|
||||||
m_activeRequests[requestId] = {request, provider};
|
m_activeRequests[requestId] = {request, provider};
|
||||||
@@ -480,8 +468,10 @@ void ClientInterface::handleRequestFailed(const QString &requestId, const QStrin
|
|||||||
if (it == m_activeRequests.end())
|
if (it == m_activeRequests.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG_MESSAGE(QString("Chat request %1 failed: %2").arg(requestId, error));
|
QString enriched = it->provider ? it->provider->enrichErrorMessage(error) : error;
|
||||||
emit errorOccurred(error);
|
|
||||||
|
LOG_MESSAGE(QString("Chat request %1 failed: %2").arg(requestId, enriched));
|
||||||
|
emit errorOccurred(enriched);
|
||||||
|
|
||||||
m_activeRequests.erase(it);
|
m_activeRequests.erase(it);
|
||||||
m_accumulatedResponses.remove(requestId);
|
m_accumulatedResponses.remove(requestId);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "LLMClientInterface.hpp"
|
#include "LLMClientInterface.hpp"
|
||||||
|
|
||||||
#include <LLMCore/BaseClient.hpp>
|
#include <LLMQore/BaseClient.hpp>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
@@ -30,7 +30,6 @@
|
|||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
#include "settings/CodeCompletionSettings.hpp"
|
#include "settings/CodeCompletionSettings.hpp"
|
||||||
#include "settings/GeneralSettings.hpp"
|
#include "settings/GeneralSettings.hpp"
|
||||||
#include <pluginllmcore/RequestConfig.hpp>
|
|
||||||
#include <pluginllmcore/RulesLoader.hpp>
|
#include <pluginllmcore/RulesLoader.hpp>
|
||||||
|
|
||||||
namespace QodeAssist {
|
namespace QodeAssist {
|
||||||
@@ -86,17 +85,19 @@ void LLMClientInterface::handleRequestFailed(const QString &requestId, const QSt
|
|||||||
if (it == m_activeRequests.end())
|
if (it == m_activeRequests.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG_MESSAGE(QString("Request %1 failed: %2").arg(requestId, error));
|
|
||||||
|
|
||||||
// Send LSP error response to client
|
|
||||||
const RequestContext &ctx = it.value();
|
const RequestContext &ctx = it.value();
|
||||||
|
QString enriched = ctx.provider ? ctx.provider->enrichErrorMessage(error) : error;
|
||||||
|
|
||||||
|
LOG_MESSAGE(QString("Request %1 failed: %2").arg(requestId, enriched));
|
||||||
|
|
||||||
|
// Send LSP error response to client
|
||||||
QJsonObject response;
|
QJsonObject response;
|
||||||
response["jsonrpc"] = "2.0";
|
response["jsonrpc"] = "2.0";
|
||||||
response[LanguageServerProtocol::idKey] = ctx.originalRequest["id"];
|
response[LanguageServerProtocol::idKey] = ctx.originalRequest["id"];
|
||||||
|
|
||||||
QJsonObject errorObject;
|
QJsonObject errorObject;
|
||||||
errorObject["code"] = -32603; // Internal error code
|
errorObject["code"] = -32603; // Internal error code
|
||||||
errorObject["message"] = error;
|
errorObject["message"] = enriched;
|
||||||
response["error"] = errorObject;
|
response["error"] = errorObject;
|
||||||
|
|
||||||
emit messageReceived(LanguageServerProtocol::JsonRpcMessage(response));
|
emit messageReceived(LanguageServerProtocol::JsonRpcMessage(response));
|
||||||
@@ -269,25 +270,11 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO refactor to dynamic presets system
|
QJsonObject payload{{"model", modelName}, {"stream", true}};
|
||||||
PluginLLMCore::LLMConfig config;
|
|
||||||
config.requestType = PluginLLMCore::RequestType::CodeCompletion;
|
|
||||||
config.provider = provider;
|
|
||||||
config.promptTemplate = promptTemplate;
|
|
||||||
// TODO refactor networking
|
|
||||||
if (provider->providerID() == PluginLLMCore::ProviderID::GoogleAI) {
|
|
||||||
QString stream = QString{"streamGenerateContent?alt=sse"};
|
|
||||||
config.url = QUrl(QString("%1/models/%2:%3").arg(url, modelName, stream));
|
|
||||||
} else {
|
|
||||||
config.url = QUrl(
|
|
||||||
QString("%1%2").arg(url, endpoint(provider, promptTemplate->type(), isPreset1Active)));
|
|
||||||
config.providerRequest = {{"model", modelName}, {"stream", true}};
|
|
||||||
}
|
|
||||||
config.multiLineCompletion = m_completeSettings.multiLineCompletion();
|
|
||||||
|
|
||||||
const auto stopWords = QJsonArray::fromStringList(config.promptTemplate->stopWords());
|
const auto stopWords = QJsonArray::fromStringList(promptTemplate->stopWords());
|
||||||
if (!stopWords.isEmpty())
|
if (!stopWords.isEmpty())
|
||||||
config.providerRequest["stop"] = stopWords;
|
payload["stop"] = stopWords;
|
||||||
|
|
||||||
QString systemPrompt;
|
QString systemPrompt;
|
||||||
if (m_completeSettings.useSystemPrompt())
|
if (m_completeSettings.useSystemPrompt())
|
||||||
@@ -341,8 +328,8 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
|
|||||||
updatedContext.history = messages;
|
updatedContext.history = messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
config.provider->prepareRequest(
|
provider->prepareRequest(
|
||||||
config.providerRequest,
|
payload,
|
||||||
promptTemplate,
|
promptTemplate,
|
||||||
updatedContext,
|
updatedContext,
|
||||||
PluginLLMCore::RequestType::CodeCompletion,
|
PluginLLMCore::RequestType::CodeCompletion,
|
||||||
@@ -351,18 +338,19 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request)
|
|||||||
|
|
||||||
connect(
|
connect(
|
||||||
provider->client(),
|
provider->client(),
|
||||||
&::LLMCore::BaseClient::requestCompleted,
|
&::LLMQore::BaseClient::requestCompleted,
|
||||||
this,
|
this,
|
||||||
&LLMClientInterface::handleFullResponse,
|
&LLMClientInterface::handleFullResponse,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
connect(
|
connect(
|
||||||
provider->client(),
|
provider->client(),
|
||||||
&::LLMCore::BaseClient::requestFailed,
|
&::LLMQore::BaseClient::requestFailed,
|
||||||
this,
|
this,
|
||||||
&LLMClientInterface::handleRequestFailed,
|
&LLMClientInterface::handleRequestFailed,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
|
|
||||||
auto requestId = provider->sendRequest(config.url, config.providerRequest);
|
auto requestId
|
||||||
|
= provider->sendRequest(QUrl(url), payload, resolveEndpoint(promptTemplate, isPreset1Active));
|
||||||
m_activeRequests[requestId] = {request, provider};
|
m_activeRequests[requestId] = {request, provider};
|
||||||
m_performanceLogger.startTimeMeasurement(requestId);
|
m_performanceLogger.startTimeMeasurement(requestId);
|
||||||
}
|
}
|
||||||
@@ -381,24 +369,12 @@ PluginLLMCore::ContextData LLMClientInterface::prepareContext(
|
|||||||
return reader.prepareContext(lineNumber, cursorPosition, m_completeSettings);
|
return reader.prepareContext(lineNumber, cursorPosition, m_completeSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LLMClientInterface::endpoint(
|
QString LLMClientInterface::resolveEndpoint(
|
||||||
PluginLLMCore::Provider *provider, PluginLLMCore::TemplateType type, bool isLanguageSpecify)
|
PluginLLMCore::PromptTemplate *promptTemplate, bool isLanguageSpecify) const
|
||||||
{
|
{
|
||||||
QString endpoint;
|
const QString custom = isLanguageSpecify ? m_generalSettings.ccPreset1CustomEndpoint()
|
||||||
auto endpointMode = isLanguageSpecify ? m_generalSettings.ccPreset1EndpointMode.stringValue()
|
: m_generalSettings.ccCustomEndpoint();
|
||||||
: m_generalSettings.ccEndpointMode.stringValue();
|
return !custom.isEmpty() ? custom : promptTemplate->endpoint();
|
||||||
if (endpointMode == "Auto") {
|
|
||||||
endpoint = type == PluginLLMCore::TemplateType::FIM ? provider->completionEndpoint()
|
|
||||||
: provider->chatEndpoint();
|
|
||||||
} else if (endpointMode == "Custom") {
|
|
||||||
endpoint = isLanguageSpecify ? m_generalSettings.ccPreset1CustomEndpoint()
|
|
||||||
: m_generalSettings.ccCustomEndpoint();
|
|
||||||
} else if (endpointMode == "FIM") {
|
|
||||||
endpoint = provider->completionEndpoint();
|
|
||||||
} else if (endpointMode == "Chat") {
|
|
||||||
endpoint = provider->chatEndpoint();
|
|
||||||
}
|
|
||||||
return endpoint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Context::ContextManager *LLMClientInterface::contextManager() const
|
Context::ContextManager *LLMClientInterface::contextManager() const
|
||||||
|
|||||||
@@ -87,7 +87,9 @@ private:
|
|||||||
|
|
||||||
PluginLLMCore::ContextData prepareContext(
|
PluginLLMCore::ContextData prepareContext(
|
||||||
const QJsonObject &request, const Context::DocumentInfo &documentInfo);
|
const QJsonObject &request, const Context::DocumentInfo &documentInfo);
|
||||||
QString endpoint(PluginLLMCore::Provider *provider, PluginLLMCore::TemplateType type, bool isLanguageSpecify);
|
|
||||||
|
QString resolveEndpoint(
|
||||||
|
PluginLLMCore::PromptTemplate *promptTemplate, bool isLanguageSpecify) const;
|
||||||
|
|
||||||
const Settings::CodeCompletionSettings &m_completeSettings;
|
const Settings::CodeCompletionSettings &m_completeSettings;
|
||||||
const Settings::GeneralSettings &m_generalSettings;
|
const Settings::GeneralSettings &m_generalSettings;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "QuickRefactorHandler.hpp"
|
#include "QuickRefactorHandler.hpp"
|
||||||
|
|
||||||
#include <LLMCore/BaseClient.hpp>
|
#include <LLMQore/BaseClient.hpp>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
@@ -30,7 +30,6 @@
|
|||||||
#include <context/Utils.hpp>
|
#include <context/Utils.hpp>
|
||||||
#include <pluginllmcore/PromptTemplateManager.hpp>
|
#include <pluginllmcore/PromptTemplateManager.hpp>
|
||||||
#include <pluginllmcore/ProvidersManager.hpp>
|
#include <pluginllmcore/ProvidersManager.hpp>
|
||||||
#include <pluginllmcore/RequestConfig.hpp>
|
|
||||||
#include <pluginllmcore/RulesLoader.hpp>
|
#include <pluginllmcore/RulesLoader.hpp>
|
||||||
#include <logger/Logger.hpp>
|
#include <logger/Logger.hpp>
|
||||||
#include <settings/ChatAssistantSettings.hpp>
|
#include <settings/ChatAssistantSettings.hpp>
|
||||||
@@ -141,32 +140,15 @@ void QuickRefactorHandler::prepareAndSendRequest(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginLLMCore::LLMConfig config;
|
QJsonObject payload{
|
||||||
config.requestType = PluginLLMCore::RequestType::QuickRefactoring;
|
{"model", Settings::generalSettings().qrModel()}, {"stream", true}};
|
||||||
config.provider = provider;
|
|
||||||
config.promptTemplate = promptTemplate;
|
|
||||||
config.url = QString("%1%2").arg(settings.qrUrl(), provider->chatEndpoint());
|
|
||||||
|
|
||||||
if (provider->providerID() == PluginLLMCore::ProviderID::GoogleAI) {
|
|
||||||
QString stream = QString{"streamGenerateContent?alt=sse"};
|
|
||||||
config.url = QUrl(QString("%1/models/%2:%3")
|
|
||||||
.arg(
|
|
||||||
Settings::generalSettings().qrUrl(),
|
|
||||||
Settings::generalSettings().qrModel(),
|
|
||||||
stream));
|
|
||||||
} else {
|
|
||||||
config.url
|
|
||||||
= QString("%1%2").arg(Settings::generalSettings().qrUrl(), provider->chatEndpoint());
|
|
||||||
config.providerRequest
|
|
||||||
= {{"model", Settings::generalSettings().qrModel()}, {"stream", true}};
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginLLMCore::ContextData context = prepareContext(editor, range, instructions);
|
PluginLLMCore::ContextData context = prepareContext(editor, range, instructions);
|
||||||
|
|
||||||
bool enableTools = Settings::quickRefactorSettings().useTools();
|
bool enableTools = Settings::quickRefactorSettings().useTools();
|
||||||
bool enableThinking = Settings::quickRefactorSettings().useThinking();
|
bool enableThinking = Settings::quickRefactorSettings().useThinking();
|
||||||
provider->prepareRequest(
|
provider->prepareRequest(
|
||||||
config.providerRequest,
|
payload,
|
||||||
promptTemplate,
|
promptTemplate,
|
||||||
context,
|
context,
|
||||||
PluginLLMCore::RequestType::QuickRefactoring,
|
PluginLLMCore::RequestType::QuickRefactoring,
|
||||||
@@ -177,19 +159,23 @@ void QuickRefactorHandler::prepareAndSendRequest(
|
|||||||
|
|
||||||
connect(
|
connect(
|
||||||
provider->client(),
|
provider->client(),
|
||||||
&::LLMCore::BaseClient::requestCompleted,
|
&::LLMQore::BaseClient::requestCompleted,
|
||||||
this,
|
this,
|
||||||
&QuickRefactorHandler::handleFullResponse,
|
&QuickRefactorHandler::handleFullResponse,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
provider->client(),
|
provider->client(),
|
||||||
&::LLMCore::BaseClient::requestFailed,
|
&::LLMQore::BaseClient::requestFailed,
|
||||||
this,
|
this,
|
||||||
&QuickRefactorHandler::handleRequestFailed,
|
&QuickRefactorHandler::handleRequestFailed,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
|
|
||||||
auto requestId = provider->sendRequest(config.url, config.providerRequest);
|
const QString customEndpoint = Settings::generalSettings().qrCustomEndpoint();
|
||||||
|
const QString endpoint = !customEndpoint.isEmpty() ? customEndpoint
|
||||||
|
: promptTemplate->endpoint();
|
||||||
|
auto requestId
|
||||||
|
= provider->sendRequest(QUrl(Settings::generalSettings().qrUrl()), payload, endpoint);
|
||||||
m_lastRequestId = requestId;
|
m_lastRequestId = requestId;
|
||||||
QJsonObject request{{"id", requestId}};
|
QJsonObject request{{"id", requestId}};
|
||||||
|
|
||||||
@@ -437,11 +423,16 @@ void QuickRefactorHandler::handleFullResponse(const QString &requestId, const QS
|
|||||||
void QuickRefactorHandler::handleRequestFailed(const QString &requestId, const QString &error)
|
void QuickRefactorHandler::handleRequestFailed(const QString &requestId, const QString &error)
|
||||||
{
|
{
|
||||||
if (requestId == m_lastRequestId) {
|
if (requestId == m_lastRequestId) {
|
||||||
|
auto it = m_activeRequests.find(requestId);
|
||||||
|
QString enriched = (it != m_activeRequests.end() && it->provider)
|
||||||
|
? it->provider->enrichErrorMessage(error)
|
||||||
|
: error;
|
||||||
|
|
||||||
m_activeRequests.remove(requestId);
|
m_activeRequests.remove(requestId);
|
||||||
m_isRefactoringInProgress = false;
|
m_isRefactoringInProgress = false;
|
||||||
RefactorResult result;
|
RefactorResult result;
|
||||||
result.success = false;
|
result.success = false;
|
||||||
result.errorMessage = error;
|
result.errorMessage = enriched;
|
||||||
result.editor = m_currentEditor;
|
result.editor = m_currentEditor;
|
||||||
emit refactoringCompleted(result);
|
emit refactoringCompleted(result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 Petr Mironychev
|
|
||||||
*
|
|
||||||
* This file is part of QodeAssist.
|
|
||||||
*
|
|
||||||
* QodeAssist is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* QodeAssist is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "BaseTool.hpp"
|
|
||||||
|
|
||||||
namespace QodeAssist::PluginLLMCore {
|
|
||||||
|
|
||||||
BaseTool::BaseTool(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{}
|
|
||||||
|
|
||||||
QJsonObject BaseTool::customizeForOpenAI(const QJsonObject &baseDefinition) const
|
|
||||||
{
|
|
||||||
QJsonObject function;
|
|
||||||
function["name"] = name();
|
|
||||||
function["description"] = description();
|
|
||||||
function["parameters"] = baseDefinition;
|
|
||||||
|
|
||||||
QJsonObject tool;
|
|
||||||
tool["type"] = "function";
|
|
||||||
tool["function"] = function;
|
|
||||||
|
|
||||||
return tool;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject BaseTool::customizeForClaude(const QJsonObject &baseDefinition) const
|
|
||||||
{
|
|
||||||
QJsonObject tool;
|
|
||||||
tool["name"] = name();
|
|
||||||
tool["description"] = description();
|
|
||||||
tool["input_schema"] = baseDefinition;
|
|
||||||
|
|
||||||
return tool;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject BaseTool::customizeForOllama(const QJsonObject &baseDefinition) const
|
|
||||||
{
|
|
||||||
return customizeForOpenAI(baseDefinition);
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject BaseTool::customizeForGoogle(const QJsonObject &baseDefinition) const
|
|
||||||
{
|
|
||||||
QJsonObject functionDeclaration;
|
|
||||||
functionDeclaration["name"] = name();
|
|
||||||
functionDeclaration["description"] = description();
|
|
||||||
functionDeclaration["parameters"] = baseDefinition;
|
|
||||||
|
|
||||||
QJsonArray functionDeclarations;
|
|
||||||
functionDeclarations.append(functionDeclaration);
|
|
||||||
|
|
||||||
QJsonObject tool;
|
|
||||||
tool["function_declarations"] = functionDeclarations;
|
|
||||||
|
|
||||||
return tool;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QodeAssist::PluginLLMCore
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 Petr Mironychev
|
|
||||||
*
|
|
||||||
* This file is part of QodeAssist.
|
|
||||||
*
|
|
||||||
* QodeAssist is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* QodeAssist is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QFuture>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
namespace QodeAssist::PluginLLMCore {
|
|
||||||
|
|
||||||
enum class ToolSchemaFormat { OpenAI, Claude, Ollama, Google };
|
|
||||||
|
|
||||||
enum ToolPermission {
|
|
||||||
None = 0,
|
|
||||||
FileSystemRead = 1 << 0,
|
|
||||||
FileSystemWrite = 1 << 1,
|
|
||||||
NetworkAccess = 1 << 2
|
|
||||||
};
|
|
||||||
Q_DECLARE_FLAGS(ToolPermissions, ToolPermission)
|
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(ToolPermissions)
|
|
||||||
|
|
||||||
enum class RunToolsFilter {
|
|
||||||
ALL, // Run all tools (no filtering)
|
|
||||||
OnlyRead, // Run only read tools (FileSystemRead + None)
|
|
||||||
OnlyWrite, // Run only write tools (FileSystemWrite)
|
|
||||||
OnlyNetworking // Run only network tools (NetworkAccess)
|
|
||||||
};
|
|
||||||
|
|
||||||
class BaseTool : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit BaseTool(QObject *parent = nullptr);
|
|
||||||
~BaseTool() override = default;
|
|
||||||
|
|
||||||
virtual QString name() const = 0;
|
|
||||||
virtual QString stringName() const = 0;
|
|
||||||
virtual QString description() const = 0;
|
|
||||||
virtual QJsonObject getDefinition(ToolSchemaFormat format) const = 0;
|
|
||||||
virtual ToolPermissions requiredPermissions() const = 0;
|
|
||||||
|
|
||||||
virtual QFuture<QString> executeAsync(const QJsonObject &input = QJsonObject()) = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual QJsonObject customizeForOpenAI(const QJsonObject &baseDefinition) const;
|
|
||||||
virtual QJsonObject customizeForClaude(const QJsonObject &baseDefinition) const;
|
|
||||||
virtual QJsonObject customizeForOllama(const QJsonObject &baseDefinition) const;
|
|
||||||
virtual QJsonObject customizeForGoogle(const QJsonObject &baseDefinition) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QodeAssist::PluginLLMCore
|
|
||||||
@@ -9,12 +9,10 @@ add_library(PluginLLMCore STATIC
|
|||||||
PromptProviderFim.hpp
|
PromptProviderFim.hpp
|
||||||
PromptTemplate.hpp
|
PromptTemplate.hpp
|
||||||
PromptTemplateManager.hpp PromptTemplateManager.cpp
|
PromptTemplateManager.hpp PromptTemplateManager.cpp
|
||||||
RequestConfig.hpp
|
|
||||||
ProviderID.hpp
|
ProviderID.hpp
|
||||||
HttpClient.hpp HttpClient.cpp
|
HttpClient.hpp HttpClient.cpp
|
||||||
DataBuffers.hpp
|
DataBuffers.hpp
|
||||||
SSEBuffer.hpp SSEBuffer.cpp
|
SSEBuffer.hpp SSEBuffer.cpp
|
||||||
BaseTool.hpp BaseTool.cpp
|
|
||||||
ContentBlocks.hpp
|
ContentBlocks.hpp
|
||||||
RulesLoader.hpp RulesLoader.cpp
|
RulesLoader.hpp RulesLoader.cpp
|
||||||
ResponseCleaner.hpp
|
ResponseCleaner.hpp
|
||||||
@@ -27,7 +25,7 @@ target_link_libraries(PluginLLMCore
|
|||||||
QtCreator::Core
|
QtCreator::Core
|
||||||
QtCreator::Utils
|
QtCreator::Utils
|
||||||
QtCreator::ExtensionSystem
|
QtCreator::ExtensionSystem
|
||||||
LLMCore
|
LLMQore
|
||||||
PRIVATE
|
PRIVATE
|
||||||
QodeAssistLogger
|
QodeAssistLogger
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 Petr Mironychev
|
|
||||||
*
|
|
||||||
* This file is part of QodeAssist.
|
|
||||||
*
|
|
||||||
* QodeAssist is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* QodeAssist is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QHash>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#include "BaseTool.hpp"
|
|
||||||
|
|
||||||
namespace QodeAssist::PluginLLMCore {
|
|
||||||
|
|
||||||
class IToolsManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~IToolsManager() = default;
|
|
||||||
|
|
||||||
virtual void executeToolCall(
|
|
||||||
const QString &requestId,
|
|
||||||
const QString &toolId,
|
|
||||||
const QString &toolName,
|
|
||||||
const QJsonObject &input) = 0;
|
|
||||||
|
|
||||||
virtual QJsonArray getToolsDefinitions(
|
|
||||||
ToolSchemaFormat format,
|
|
||||||
RunToolsFilter filter = RunToolsFilter::ALL) const = 0;
|
|
||||||
|
|
||||||
virtual void cleanupRequest(const QString &requestId) = 0;
|
|
||||||
virtual void setCurrentSessionId(const QString &sessionId) = 0;
|
|
||||||
virtual void clearTodoSession(const QString &sessionId) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QodeAssist::LLMCore
|
|
||||||
@@ -40,5 +40,13 @@ public:
|
|||||||
virtual void prepareRequest(QJsonObject &request, const ContextData &context) const = 0;
|
virtual void prepareRequest(QJsonObject &request, const ContextData &context) const = 0;
|
||||||
virtual QString description() const = 0;
|
virtual QString description() const = 0;
|
||||||
virtual bool isSupportProvider(ProviderID id) const = 0;
|
virtual bool isSupportProvider(ProviderID id) const = 0;
|
||||||
|
|
||||||
|
// Endpoint path this template expects to be sent to. Empty string
|
||||||
|
// (default) means "let the provider's client use its standard chat
|
||||||
|
// path" (/chat/completions, /api/chat, /v1/messages, ...). Templates
|
||||||
|
// producing non-chat payload shapes (e.g. {prompt, suffix} for
|
||||||
|
// Mistral FIM, {input_prefix, input_suffix} for llama.cpp infill)
|
||||||
|
// must override this to the path their payload is valid for.
|
||||||
|
virtual QString endpoint() const { return {}; }
|
||||||
};
|
};
|
||||||
} // namespace QodeAssist::PluginLLMCore
|
} // namespace QodeAssist::PluginLLMCore
|
||||||
|
|||||||
@@ -19,8 +19,14 @@
|
|||||||
|
|
||||||
#include "Provider.hpp"
|
#include "Provider.hpp"
|
||||||
|
|
||||||
#include <LLMCore/BaseClient.hpp>
|
#include <LLMQore/BaseClient.hpp>
|
||||||
#include <LLMCore/ToolsManager.hpp>
|
#include <LLMQore/LlamaCppClient.hpp>
|
||||||
|
#include <LLMQore/MistralClient.hpp>
|
||||||
|
#include <LLMQore/OpenAIClient.hpp>
|
||||||
|
#include <LLMQore/OpenAIResponsesClient.hpp>
|
||||||
|
#include <LLMQore/ToolsManager.hpp>
|
||||||
|
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
#include <Logger.hpp>
|
#include <Logger.hpp>
|
||||||
|
|
||||||
@@ -30,19 +36,21 @@ Provider::Provider(QObject *parent)
|
|||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
RequestID Provider::sendRequest(const QUrl &url, const QJsonObject &payload)
|
RequestID Provider::sendRequest(
|
||||||
|
const QUrl &url, const QJsonObject &payload, const QString &endpoint)
|
||||||
{
|
{
|
||||||
auto *c = client();
|
auto *c = client();
|
||||||
|
|
||||||
QUrl baseUrl(url);
|
c->setUrl(url.toString());
|
||||||
baseUrl.setPath("");
|
|
||||||
c->setUrl(baseUrl.toString());
|
|
||||||
c->setApiKey(apiKey());
|
c->setApiKey(apiKey());
|
||||||
|
|
||||||
auto requestId = c->sendMessage(payload);
|
auto requestId = c->sendMessage(payload, endpoint);
|
||||||
|
|
||||||
LOG_MESSAGE(
|
LOG_MESSAGE(
|
||||||
QString("%1: Sending request %2 to %3").arg(name(), requestId, url.toString()));
|
QString("%1: Sending request %2 to %3%4").arg(name(), requestId, url.toString(), endpoint));
|
||||||
|
LOG_MESSAGE(
|
||||||
|
QString("%1: Payload:\n%2")
|
||||||
|
.arg(name(), QString::fromUtf8(QJsonDocument(payload).toJson(QJsonDocument::Indented))));
|
||||||
|
|
||||||
return requestId;
|
return requestId;
|
||||||
}
|
}
|
||||||
@@ -53,9 +61,35 @@ void Provider::cancelRequest(const RequestID &requestId)
|
|||||||
client()->cancelRequest(requestId);
|
client()->cancelRequest(requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMCore::ToolsManager *Provider::toolsManager() const
|
::LLMQore::ToolsManager *Provider::toolsManager() const
|
||||||
{
|
{
|
||||||
return client()->tools();
|
return client()->tools();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Provider::enrichErrorMessage(const QString &error) const
|
||||||
|
{
|
||||||
|
auto *c = client();
|
||||||
|
|
||||||
|
if (qobject_cast<::LLMQore::MistralClient *>(c))
|
||||||
|
return error;
|
||||||
|
|
||||||
|
const bool isOpenAICompatible = qobject_cast<::LLMQore::OpenAIClient *>(c)
|
||||||
|
|| qobject_cast<::LLMQore::OpenAIResponsesClient *>(c)
|
||||||
|
|| qobject_cast<::LLMQore::LlamaCppClient *>(c);
|
||||||
|
if (!isOpenAICompatible)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
const QString baseUrl = c->url();
|
||||||
|
const QString path = QUrl(baseUrl).path();
|
||||||
|
const bool hasV1Segment = path.contains("/v1/") || path.endsWith("/v1");
|
||||||
|
if (hasV1Segment)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
return error
|
||||||
|
+ tr("\n\nHint: Your base URL (%1) does not contain a '/v1' path segment. "
|
||||||
|
"Most OpenAI-compatible servers require it (e.g., %1/v1). "
|
||||||
|
"Try updating the URL in settings.")
|
||||||
|
.arg(baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QodeAssist::PluginLLMCore
|
} // namespace QodeAssist::PluginLLMCore
|
||||||
|
|||||||
@@ -26,11 +26,10 @@
|
|||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
|
|
||||||
#include "ContextData.hpp"
|
#include "ContextData.hpp"
|
||||||
#include "IToolsManager.hpp"
|
|
||||||
#include "PromptTemplate.hpp"
|
#include "PromptTemplate.hpp"
|
||||||
#include "RequestType.hpp"
|
#include "RequestType.hpp"
|
||||||
|
|
||||||
namespace LLMCore {
|
namespace LLMQore {
|
||||||
class BaseClient;
|
class BaseClient;
|
||||||
class ToolsManager;
|
class ToolsManager;
|
||||||
}
|
}
|
||||||
@@ -58,8 +57,6 @@ public:
|
|||||||
|
|
||||||
virtual QString name() const = 0;
|
virtual QString name() const = 0;
|
||||||
virtual QString url() const = 0;
|
virtual QString url() const = 0;
|
||||||
virtual QString completionEndpoint() const = 0;
|
|
||||||
virtual QString chatEndpoint() const = 0;
|
|
||||||
virtual void prepareRequest(
|
virtual void prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -72,12 +69,15 @@ public:
|
|||||||
virtual ProviderID providerID() const = 0;
|
virtual ProviderID providerID() const = 0;
|
||||||
virtual ProviderCapabilities capabilities() const { return {}; }
|
virtual ProviderCapabilities capabilities() const { return {}; }
|
||||||
|
|
||||||
virtual ::LLMCore::BaseClient *client() const = 0;
|
virtual ::LLMQore::BaseClient *client() const = 0;
|
||||||
virtual QString apiKey() const = 0;
|
virtual QString apiKey() const = 0;
|
||||||
|
|
||||||
RequestID sendRequest(const QUrl &url, const QJsonObject &payload);
|
virtual RequestID sendRequest(
|
||||||
|
const QUrl &url, const QJsonObject &payload, const QString &endpoint);
|
||||||
void cancelRequest(const RequestID &requestId);
|
void cancelRequest(const RequestID &requestId);
|
||||||
::LLMCore::ToolsManager *toolsManager() const;
|
::LLMQore::ToolsManager *toolsManager() const;
|
||||||
|
|
||||||
|
QString enrichErrorMessage(const QString &error) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::PluginLLMCore
|
} // namespace QodeAssist::PluginLLMCore
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "PromptTemplate.hpp"
|
|
||||||
#include "Provider.hpp"
|
|
||||||
#include "RequestType.hpp"
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
namespace QodeAssist::PluginLLMCore {
|
|
||||||
|
|
||||||
struct LLMConfig
|
|
||||||
{
|
|
||||||
QUrl url;
|
|
||||||
Provider *provider;
|
|
||||||
PromptTemplate *promptTemplate;
|
|
||||||
QJsonObject providerRequest;
|
|
||||||
RequestType requestType;
|
|
||||||
bool multiLineCompletion;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QodeAssist::PluginLLMCore
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "RequestHandlerBase.hpp"
|
|
||||||
|
|
||||||
namespace QodeAssist::LLMCore {
|
|
||||||
|
|
||||||
RequestHandlerBase::RequestHandlerBase(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{}
|
|
||||||
|
|
||||||
RequestHandlerBase::~RequestHandlerBase() = default;
|
|
||||||
|
|
||||||
} // namespace QodeAssist::LLMCore
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "RequestConfig.hpp"
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
namespace QodeAssist::LLMCore {
|
|
||||||
|
|
||||||
class RequestHandlerBase : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit RequestHandlerBase(QObject *parent = nullptr);
|
|
||||||
~RequestHandlerBase() override;
|
|
||||||
|
|
||||||
virtual void sendLLMRequest(const LLMConfig &config, const QJsonObject &request) = 0;
|
|
||||||
virtual bool cancelRequest(const QString &id) = 0;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void completionReceived(const QString &completion, const QJsonObject &request, bool isComplete);
|
|
||||||
void requestFinished(const QString &requestId, bool success, const QString &errorString);
|
|
||||||
void requestCancelled(const QString &id);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QodeAssist::LLMCore
|
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
#include <LLMCore/ToolsManager.hpp>
|
#include <LLMQore/ToolsManager.hpp>
|
||||||
|
|
||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
#include "settings/ChatAssistantSettings.hpp"
|
#include "settings/ChatAssistantSettings.hpp"
|
||||||
@@ -37,7 +37,7 @@ namespace QodeAssist::Providers {
|
|||||||
|
|
||||||
ClaudeProvider::ClaudeProvider(QObject *parent)
|
ClaudeProvider::ClaudeProvider(QObject *parent)
|
||||||
: PluginLLMCore::Provider(parent)
|
: PluginLLMCore::Provider(parent)
|
||||||
, m_client(new ::LLMCore::ClaudeClient(QString(), QString(), QString(), this))
|
, m_client(new ::LLMQore::ClaudeClient(QString(), QString(), QString(), this))
|
||||||
{
|
{
|
||||||
Tools::registerQodeAssistTools(m_client->tools());
|
Tools::registerQodeAssistTools(m_client->tools());
|
||||||
}
|
}
|
||||||
@@ -57,16 +57,6 @@ QString ClaudeProvider::url() const
|
|||||||
return "https://api.anthropic.com";
|
return "https://api.anthropic.com";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ClaudeProvider::completionEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/messages";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ClaudeProvider::chatEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/messages";
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClaudeProvider::prepareRequest(
|
void ClaudeProvider::prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -151,7 +141,7 @@ PluginLLMCore::ProviderCapabilities ClaudeProvider::capabilities() const
|
|||||||
| PluginLLMCore::ProviderCapability::ModelListing;
|
| PluginLLMCore::ProviderCapability::ModelListing;
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMCore::BaseClient *ClaudeProvider::client() const
|
::LLMQore::BaseClient *ClaudeProvider::client() const
|
||||||
{
|
{
|
||||||
return m_client;
|
return m_client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include <pluginllmcore/Provider.hpp>
|
#include <pluginllmcore/Provider.hpp>
|
||||||
|
|
||||||
#include <LLMCore/ClaudeClient.hpp>
|
#include <LLMQore/ClaudeClient.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Providers {
|
namespace QodeAssist::Providers {
|
||||||
|
|
||||||
@@ -33,8 +33,6 @@ public:
|
|||||||
|
|
||||||
QString name() const override;
|
QString name() const override;
|
||||||
QString url() const override;
|
QString url() const override;
|
||||||
QString completionEndpoint() const override;
|
|
||||||
QString chatEndpoint() const override;
|
|
||||||
void prepareRequest(
|
void prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -46,11 +44,11 @@ public:
|
|||||||
PluginLLMCore::ProviderID providerID() const override;
|
PluginLLMCore::ProviderID providerID() const override;
|
||||||
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
||||||
|
|
||||||
::LLMCore::BaseClient *client() const override;
|
::LLMQore::BaseClient *client() const override;
|
||||||
QString apiKey() const override;
|
QString apiKey() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
::LLMCore::ClaudeClient *m_client;
|
::LLMQore::ClaudeClient *m_client;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Providers
|
} // namespace QodeAssist::Providers
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "GoogleAIProvider.hpp"
|
#include "GoogleAIProvider.hpp"
|
||||||
|
|
||||||
#include <LLMCore/ToolsManager.hpp>
|
#include <LLMQore/ToolsManager.hpp>
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include "tools/ToolsRegistration.hpp"
|
#include "tools/ToolsRegistration.hpp"
|
||||||
@@ -38,7 +38,7 @@ namespace QodeAssist::Providers {
|
|||||||
|
|
||||||
GoogleAIProvider::GoogleAIProvider(QObject *parent)
|
GoogleAIProvider::GoogleAIProvider(QObject *parent)
|
||||||
: PluginLLMCore::Provider(parent)
|
: PluginLLMCore::Provider(parent)
|
||||||
, m_client(new ::LLMCore::GoogleAIClient(QString(), QString(), QString(), this))
|
, m_client(new ::LLMQore::GoogleAIClient(QString(), QString(), QString(), this))
|
||||||
{
|
{
|
||||||
Tools::registerQodeAssistTools(m_client->tools());
|
Tools::registerQodeAssistTools(m_client->tools());
|
||||||
}
|
}
|
||||||
@@ -58,16 +58,6 @@ QString GoogleAIProvider::url() const
|
|||||||
return "https://generativelanguage.googleapis.com/v1beta";
|
return "https://generativelanguage.googleapis.com/v1beta";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GoogleAIProvider::completionEndpoint() const
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
QString GoogleAIProvider::chatEndpoint() const
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void GoogleAIProvider::prepareRequest(
|
void GoogleAIProvider::prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -165,7 +155,25 @@ PluginLLMCore::ProviderCapabilities GoogleAIProvider::capabilities() const
|
|||||||
| PluginLLMCore::ProviderCapability::ModelListing;
|
| PluginLLMCore::ProviderCapability::ModelListing;
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMCore::BaseClient *GoogleAIProvider::client() const
|
PluginLLMCore::RequestID GoogleAIProvider::sendRequest(
|
||||||
|
const QUrl &url, const QJsonObject &payload, const QString &endpoint)
|
||||||
|
{
|
||||||
|
// Gemini takes the model from the URL path and streaming from the
|
||||||
|
// action suffix (:streamGenerateContent vs :generateContent), and
|
||||||
|
// rejects unknown top-level body fields. The shared call-site seeds
|
||||||
|
// payload with {model, stream}; consume them here into client state
|
||||||
|
// before they hit the wire.
|
||||||
|
QJsonObject cleaned = payload;
|
||||||
|
if (cleaned.contains("model")) {
|
||||||
|
m_client->setModel(cleaned["model"].toString());
|
||||||
|
cleaned.remove("model");
|
||||||
|
}
|
||||||
|
cleaned.remove("stream");
|
||||||
|
|
||||||
|
return PluginLLMCore::Provider::sendRequest(url, cleaned, endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
::LLMQore::BaseClient *GoogleAIProvider::client() const
|
||||||
{
|
{
|
||||||
return m_client;
|
return m_client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include <pluginllmcore/Provider.hpp>
|
#include <pluginllmcore/Provider.hpp>
|
||||||
|
|
||||||
#include <LLMCore/GoogleAIClient.hpp>
|
#include <LLMQore/GoogleAIClient.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Providers {
|
namespace QodeAssist::Providers {
|
||||||
|
|
||||||
@@ -33,8 +33,6 @@ public:
|
|||||||
|
|
||||||
QString name() const override;
|
QString name() const override;
|
||||||
QString url() const override;
|
QString url() const override;
|
||||||
QString completionEndpoint() const override;
|
|
||||||
QString chatEndpoint() const override;
|
|
||||||
void prepareRequest(
|
void prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -46,11 +44,14 @@ public:
|
|||||||
PluginLLMCore::ProviderID providerID() const override;
|
PluginLLMCore::ProviderID providerID() const override;
|
||||||
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
||||||
|
|
||||||
::LLMCore::BaseClient *client() const override;
|
PluginLLMCore::RequestID sendRequest(
|
||||||
|
const QUrl &url, const QJsonObject &payload, const QString &endpoint) override;
|
||||||
|
|
||||||
|
::LLMQore::BaseClient *client() const override;
|
||||||
QString apiKey() const override;
|
QString apiKey() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
::LLMCore::GoogleAIClient *m_client;
|
::LLMQore::GoogleAIClient *m_client;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Providers
|
} // namespace QodeAssist::Providers
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "LMStudioProvider.hpp"
|
#include "LMStudioProvider.hpp"
|
||||||
|
|
||||||
#include <LLMCore/ToolsManager.hpp>
|
#include <LLMQore/ToolsManager.hpp>
|
||||||
|
|
||||||
#include "tools/ToolsRegistration.hpp"
|
#include "tools/ToolsRegistration.hpp"
|
||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
@@ -37,7 +37,7 @@ namespace QodeAssist::Providers {
|
|||||||
|
|
||||||
LMStudioProvider::LMStudioProvider(QObject *parent)
|
LMStudioProvider::LMStudioProvider(QObject *parent)
|
||||||
: PluginLLMCore::Provider(parent)
|
: PluginLLMCore::Provider(parent)
|
||||||
, m_client(new ::LLMCore::OpenAIClient(QString(), QString(), QString(), this))
|
, m_client(new ::LLMQore::OpenAIClient(QString(), QString(), QString(), this))
|
||||||
{
|
{
|
||||||
Tools::registerQodeAssistTools(m_client->tools());
|
Tools::registerQodeAssistTools(m_client->tools());
|
||||||
}
|
}
|
||||||
@@ -54,17 +54,7 @@ QString LMStudioProvider::apiKey() const
|
|||||||
|
|
||||||
QString LMStudioProvider::url() const
|
QString LMStudioProvider::url() const
|
||||||
{
|
{
|
||||||
return "http://localhost:1234";
|
return "http://localhost:1234/v1";
|
||||||
}
|
|
||||||
|
|
||||||
QString LMStudioProvider::completionEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/completions";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString LMStudioProvider::chatEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/chat/completions";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<QList<QString>> LMStudioProvider::getInstalledModels(const QString &url)
|
QFuture<QList<QString>> LMStudioProvider::getInstalledModels(const QString &url)
|
||||||
@@ -130,7 +120,7 @@ void LMStudioProvider::prepareRequest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMCore::BaseClient *LMStudioProvider::client() const
|
::LLMQore::BaseClient *LMStudioProvider::client() const
|
||||||
{
|
{
|
||||||
return m_client;
|
return m_client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LLMCore/OpenAIClient.hpp>
|
#include <LLMQore/OpenAIClient.hpp>
|
||||||
#include <pluginllmcore/Provider.hpp>
|
#include <pluginllmcore/Provider.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Providers {
|
namespace QodeAssist::Providers {
|
||||||
@@ -32,8 +32,6 @@ public:
|
|||||||
|
|
||||||
QString name() const override;
|
QString name() const override;
|
||||||
QString url() const override;
|
QString url() const override;
|
||||||
QString completionEndpoint() const override;
|
|
||||||
QString chatEndpoint() const override;
|
|
||||||
void prepareRequest(
|
void prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -45,11 +43,11 @@ public:
|
|||||||
PluginLLMCore::ProviderID providerID() const override;
|
PluginLLMCore::ProviderID providerID() const override;
|
||||||
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
||||||
|
|
||||||
::LLMCore::BaseClient *client() const override;
|
::LLMQore::BaseClient *client() const override;
|
||||||
QString apiKey() const override;
|
QString apiKey() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
::LLMCore::OpenAIClient *m_client;
|
::LLMQore::OpenAIClient *m_client;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Providers
|
} // namespace QodeAssist::Providers
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "LlamaCppProvider.hpp"
|
#include "LlamaCppProvider.hpp"
|
||||||
|
|
||||||
#include <LLMCore/ToolsManager.hpp>
|
#include <LLMQore/ToolsManager.hpp>
|
||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
#include "settings/ChatAssistantSettings.hpp"
|
#include "settings/ChatAssistantSettings.hpp"
|
||||||
#include "settings/CodeCompletionSettings.hpp"
|
#include "settings/CodeCompletionSettings.hpp"
|
||||||
@@ -35,7 +35,7 @@ namespace QodeAssist::Providers {
|
|||||||
|
|
||||||
LlamaCppProvider::LlamaCppProvider(QObject *parent)
|
LlamaCppProvider::LlamaCppProvider(QObject *parent)
|
||||||
: PluginLLMCore::Provider(parent)
|
: PluginLLMCore::Provider(parent)
|
||||||
, m_client(new ::LLMCore::LlamaCppClient(QString(), QString(), QString(), this))
|
, m_client(new ::LLMQore::LlamaCppClient(QString(), QString(), QString(), this))
|
||||||
{
|
{
|
||||||
Tools::registerQodeAssistTools(m_client->tools());
|
Tools::registerQodeAssistTools(m_client->tools());
|
||||||
}
|
}
|
||||||
@@ -55,16 +55,6 @@ QString LlamaCppProvider::url() const
|
|||||||
return "http://localhost:8080";
|
return "http://localhost:8080";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LlamaCppProvider::completionEndpoint() const
|
|
||||||
{
|
|
||||||
return "/infill";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString LlamaCppProvider::chatEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/chat/completions";
|
|
||||||
}
|
|
||||||
|
|
||||||
void LlamaCppProvider::prepareRequest(
|
void LlamaCppProvider::prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -125,7 +115,7 @@ PluginLLMCore::ProviderCapabilities LlamaCppProvider::capabilities() const
|
|||||||
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image;
|
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image;
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMCore::BaseClient *LlamaCppProvider::client() const
|
::LLMQore::BaseClient *LlamaCppProvider::client() const
|
||||||
{
|
{
|
||||||
return m_client;
|
return m_client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include <pluginllmcore/Provider.hpp>
|
#include <pluginllmcore/Provider.hpp>
|
||||||
|
|
||||||
#include <LLMCore/LlamaCppClient.hpp>
|
#include <LLMQore/LlamaCppClient.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Providers {
|
namespace QodeAssist::Providers {
|
||||||
|
|
||||||
@@ -33,8 +33,6 @@ public:
|
|||||||
|
|
||||||
QString name() const override;
|
QString name() const override;
|
||||||
QString url() const override;
|
QString url() const override;
|
||||||
QString completionEndpoint() const override;
|
|
||||||
QString chatEndpoint() const override;
|
|
||||||
void prepareRequest(
|
void prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -46,11 +44,11 @@ public:
|
|||||||
PluginLLMCore::ProviderID providerID() const override;
|
PluginLLMCore::ProviderID providerID() const override;
|
||||||
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
||||||
|
|
||||||
::LLMCore::BaseClient *client() const override;
|
::LLMQore::BaseClient *client() const override;
|
||||||
QString apiKey() const override;
|
QString apiKey() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
::LLMCore::LlamaCppClient *m_client;
|
::LLMQore::LlamaCppClient *m_client;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Providers
|
} // namespace QodeAssist::Providers
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "MistralAIProvider.hpp"
|
#include "MistralAIProvider.hpp"
|
||||||
|
|
||||||
#include <LLMCore/ToolsManager.hpp>
|
#include <LLMQore/ToolsManager.hpp>
|
||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
#include "settings/ChatAssistantSettings.hpp"
|
#include "settings/ChatAssistantSettings.hpp"
|
||||||
#include "settings/CodeCompletionSettings.hpp"
|
#include "settings/CodeCompletionSettings.hpp"
|
||||||
@@ -36,7 +36,7 @@ namespace QodeAssist::Providers {
|
|||||||
|
|
||||||
MistralAIProvider::MistralAIProvider(QObject *parent)
|
MistralAIProvider::MistralAIProvider(QObject *parent)
|
||||||
: PluginLLMCore::Provider(parent)
|
: PluginLLMCore::Provider(parent)
|
||||||
, m_client(new ::LLMCore::OpenAIClient(QString(), QString(), QString(), this))
|
, m_client(new ::LLMQore::MistralClient(QString(), QString(), QString(), this))
|
||||||
{
|
{
|
||||||
Tools::registerQodeAssistTools(m_client->tools());
|
Tools::registerQodeAssistTools(m_client->tools());
|
||||||
}
|
}
|
||||||
@@ -56,16 +56,6 @@ QString MistralAIProvider::url() const
|
|||||||
return "https://api.mistral.ai";
|
return "https://api.mistral.ai";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MistralAIProvider::completionEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/fim/completions";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString MistralAIProvider::chatEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/chat/completions";
|
|
||||||
}
|
|
||||||
|
|
||||||
QFuture<QList<QString>> MistralAIProvider::getInstalledModels(const QString &url)
|
QFuture<QList<QString>> MistralAIProvider::getInstalledModels(const QString &url)
|
||||||
{
|
{
|
||||||
m_client->setUrl(url);
|
m_client->setUrl(url);
|
||||||
@@ -129,7 +119,7 @@ void MistralAIProvider::prepareRequest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMCore::BaseClient *MistralAIProvider::client() const
|
::LLMQore::BaseClient *MistralAIProvider::client() const
|
||||||
{
|
{
|
||||||
return m_client;
|
return m_client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LLMCore/OpenAIClient.hpp>
|
#include <LLMQore/MistralClient.hpp>
|
||||||
#include <pluginllmcore/Provider.hpp>
|
#include <pluginllmcore/Provider.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Providers {
|
namespace QodeAssist::Providers {
|
||||||
@@ -32,8 +32,6 @@ public:
|
|||||||
|
|
||||||
QString name() const override;
|
QString name() const override;
|
||||||
QString url() const override;
|
QString url() const override;
|
||||||
QString completionEndpoint() const override;
|
|
||||||
QString chatEndpoint() const override;
|
|
||||||
void prepareRequest(
|
void prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -45,11 +43,11 @@ public:
|
|||||||
PluginLLMCore::ProviderID providerID() const override;
|
PluginLLMCore::ProviderID providerID() const override;
|
||||||
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
||||||
|
|
||||||
::LLMCore::BaseClient *client() const override;
|
::LLMQore::BaseClient *client() const override;
|
||||||
QString apiKey() const override;
|
QString apiKey() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
::LLMCore::OpenAIClient *m_client;
|
::LLMQore::MistralClient *m_client;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Providers
|
} // namespace QodeAssist::Providers
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "OllamaProvider.hpp"
|
#include "OllamaProvider.hpp"
|
||||||
|
|
||||||
#include <LLMCore/ToolsManager.hpp>
|
#include <LLMQore/ToolsManager.hpp>
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
@@ -37,7 +37,7 @@ namespace QodeAssist::Providers {
|
|||||||
|
|
||||||
OllamaProvider::OllamaProvider(QObject *parent)
|
OllamaProvider::OllamaProvider(QObject *parent)
|
||||||
: PluginLLMCore::Provider(parent)
|
: PluginLLMCore::Provider(parent)
|
||||||
, m_client(new ::LLMCore::OllamaClient(QString(), QString(), QString(), this))
|
, m_client(new ::LLMQore::OllamaClient(QString(), QString(), QString(), this))
|
||||||
{
|
{
|
||||||
Tools::registerQodeAssistTools(m_client->tools());
|
Tools::registerQodeAssistTools(m_client->tools());
|
||||||
}
|
}
|
||||||
@@ -57,16 +57,6 @@ QString OllamaProvider::url() const
|
|||||||
return "http://localhost:11434";
|
return "http://localhost:11434";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString OllamaProvider::completionEndpoint() const
|
|
||||||
{
|
|
||||||
return "/api/generate";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OllamaProvider::chatEndpoint() const
|
|
||||||
{
|
|
||||||
return "/api/chat";
|
|
||||||
}
|
|
||||||
|
|
||||||
void OllamaProvider::prepareRequest(
|
void OllamaProvider::prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -156,7 +146,7 @@ PluginLLMCore::ProviderCapabilities OllamaProvider::capabilities() const
|
|||||||
| PluginLLMCore::ProviderCapability::ModelListing;
|
| PluginLLMCore::ProviderCapability::ModelListing;
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMCore::BaseClient *OllamaProvider::client() const
|
::LLMQore::BaseClient *OllamaProvider::client() const
|
||||||
{
|
{
|
||||||
return m_client;
|
return m_client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include <pluginllmcore/Provider.hpp>
|
#include <pluginllmcore/Provider.hpp>
|
||||||
|
|
||||||
#include <LLMCore/OllamaClient.hpp>
|
#include <LLMQore/OllamaClient.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Providers {
|
namespace QodeAssist::Providers {
|
||||||
|
|
||||||
@@ -33,8 +33,6 @@ public:
|
|||||||
|
|
||||||
QString name() const override;
|
QString name() const override;
|
||||||
QString url() const override;
|
QString url() const override;
|
||||||
QString completionEndpoint() const override;
|
|
||||||
QString chatEndpoint() const override;
|
|
||||||
void prepareRequest(
|
void prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -46,11 +44,11 @@ public:
|
|||||||
PluginLLMCore::ProviderID providerID() const override;
|
PluginLLMCore::ProviderID providerID() const override;
|
||||||
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
||||||
|
|
||||||
::LLMCore::BaseClient *client() const override;
|
::LLMQore::BaseClient *client() const override;
|
||||||
QString apiKey() const override;
|
QString apiKey() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
::LLMCore::OllamaClient *m_client;
|
::LLMQore::OllamaClient *m_client;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Providers
|
} // namespace QodeAssist::Providers
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "OpenAICompatProvider.hpp"
|
#include "OpenAICompatProvider.hpp"
|
||||||
#include <LLMCore/ToolsManager.hpp>
|
#include <LLMQore/ToolsManager.hpp>
|
||||||
|
|
||||||
#include "tools/ToolsRegistration.hpp"
|
#include "tools/ToolsRegistration.hpp"
|
||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
@@ -36,7 +36,7 @@ namespace QodeAssist::Providers {
|
|||||||
|
|
||||||
OpenAICompatProvider::OpenAICompatProvider(QObject *parent)
|
OpenAICompatProvider::OpenAICompatProvider(QObject *parent)
|
||||||
: PluginLLMCore::Provider(parent)
|
: PluginLLMCore::Provider(parent)
|
||||||
, m_client(new ::LLMCore::OpenAIClient(QString(), QString(), QString(), this))
|
, m_client(new ::LLMQore::OpenAIClient(QString(), QString(), QString(), this))
|
||||||
{
|
{
|
||||||
Tools::registerQodeAssistTools(m_client->tools());
|
Tools::registerQodeAssistTools(m_client->tools());
|
||||||
}
|
}
|
||||||
@@ -53,17 +53,7 @@ QString OpenAICompatProvider::apiKey() const
|
|||||||
|
|
||||||
QString OpenAICompatProvider::url() const
|
QString OpenAICompatProvider::url() const
|
||||||
{
|
{
|
||||||
return "http://localhost:1234";
|
return "http://localhost:1234/v1";
|
||||||
}
|
|
||||||
|
|
||||||
QString OpenAICompatProvider::completionEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/chat/completions";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OpenAICompatProvider::chatEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/chat/completions";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenAICompatProvider::prepareRequest(
|
void OpenAICompatProvider::prepareRequest(
|
||||||
@@ -127,7 +117,7 @@ PluginLLMCore::ProviderCapabilities OpenAICompatProvider::capabilities() const
|
|||||||
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image;
|
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image;
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMCore::BaseClient *OpenAICompatProvider::client() const
|
::LLMQore::BaseClient *OpenAICompatProvider::client() const
|
||||||
{
|
{
|
||||||
return m_client;
|
return m_client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LLMCore/OpenAIClient.hpp>
|
#include <LLMQore/OpenAIClient.hpp>
|
||||||
#include <pluginllmcore/Provider.hpp>
|
#include <pluginllmcore/Provider.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Providers {
|
namespace QodeAssist::Providers {
|
||||||
@@ -32,8 +32,6 @@ public:
|
|||||||
|
|
||||||
QString name() const override;
|
QString name() const override;
|
||||||
QString url() const override;
|
QString url() const override;
|
||||||
QString completionEndpoint() const override;
|
|
||||||
QString chatEndpoint() const override;
|
|
||||||
void prepareRequest(
|
void prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -45,11 +43,11 @@ public:
|
|||||||
PluginLLMCore::ProviderID providerID() const override;
|
PluginLLMCore::ProviderID providerID() const override;
|
||||||
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
||||||
|
|
||||||
::LLMCore::BaseClient *client() const override;
|
::LLMQore::BaseClient *client() const override;
|
||||||
QString apiKey() const override;
|
QString apiKey() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
::LLMCore::OpenAIClient *m_client;
|
::LLMQore::OpenAIClient *m_client;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Providers
|
} // namespace QodeAssist::Providers
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "OpenAIProvider.hpp"
|
#include "OpenAIProvider.hpp"
|
||||||
|
|
||||||
#include <LLMCore/ToolsManager.hpp>
|
#include <LLMQore/ToolsManager.hpp>
|
||||||
#include "tools/ToolsRegistration.hpp"
|
#include "tools/ToolsRegistration.hpp"
|
||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
#include "settings/ChatAssistantSettings.hpp"
|
#include "settings/ChatAssistantSettings.hpp"
|
||||||
@@ -36,7 +36,7 @@ namespace QodeAssist::Providers {
|
|||||||
|
|
||||||
OpenAIProvider::OpenAIProvider(QObject *parent)
|
OpenAIProvider::OpenAIProvider(QObject *parent)
|
||||||
: PluginLLMCore::Provider(parent)
|
: PluginLLMCore::Provider(parent)
|
||||||
, m_client(new ::LLMCore::OpenAIClient(QString(), QString(), QString(), this))
|
, m_client(new ::LLMQore::OpenAIClient(QString(), QString(), QString(), this))
|
||||||
{
|
{
|
||||||
Tools::registerQodeAssistTools(m_client->tools());
|
Tools::registerQodeAssistTools(m_client->tools());
|
||||||
}
|
}
|
||||||
@@ -53,17 +53,7 @@ QString OpenAIProvider::apiKey() const
|
|||||||
|
|
||||||
QString OpenAIProvider::url() const
|
QString OpenAIProvider::url() const
|
||||||
{
|
{
|
||||||
return "https://api.openai.com";
|
return "https://api.openai.com/v1";
|
||||||
}
|
|
||||||
|
|
||||||
QString OpenAIProvider::completionEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/chat/completions";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OpenAIProvider::chatEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/chat/completions";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenAIProvider::prepareRequest(
|
void OpenAIProvider::prepareRequest(
|
||||||
@@ -158,7 +148,7 @@ PluginLLMCore::ProviderCapabilities OpenAIProvider::capabilities() const
|
|||||||
| PluginLLMCore::ProviderCapability::ModelListing;
|
| PluginLLMCore::ProviderCapability::ModelListing;
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMCore::BaseClient *OpenAIProvider::client() const
|
::LLMQore::BaseClient *OpenAIProvider::client() const
|
||||||
{
|
{
|
||||||
return m_client;
|
return m_client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LLMCore/OpenAIClient.hpp>
|
#include <LLMQore/OpenAIClient.hpp>
|
||||||
#include <pluginllmcore/Provider.hpp>
|
#include <pluginllmcore/Provider.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Providers {
|
namespace QodeAssist::Providers {
|
||||||
@@ -32,8 +32,6 @@ public:
|
|||||||
|
|
||||||
QString name() const override;
|
QString name() const override;
|
||||||
QString url() const override;
|
QString url() const override;
|
||||||
QString completionEndpoint() const override;
|
|
||||||
QString chatEndpoint() const override;
|
|
||||||
void prepareRequest(
|
void prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -45,11 +43,11 @@ public:
|
|||||||
PluginLLMCore::ProviderID providerID() const override;
|
PluginLLMCore::ProviderID providerID() const override;
|
||||||
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
||||||
|
|
||||||
::LLMCore::BaseClient *client() const override;
|
::LLMQore::BaseClient *client() const override;
|
||||||
QString apiKey() const override;
|
QString apiKey() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
::LLMCore::OpenAIClient *m_client;
|
::LLMQore::OpenAIClient *m_client;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Providers
|
} // namespace QodeAssist::Providers
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "OpenAIResponsesProvider.hpp"
|
#include "OpenAIResponsesProvider.hpp"
|
||||||
#include <LLMCore/ToolsManager.hpp>
|
#include <LLMQore/ToolsManager.hpp>
|
||||||
#include "tools/ToolsRegistration.hpp"
|
#include "tools/ToolsRegistration.hpp"
|
||||||
|
|
||||||
#include "logger/Logger.hpp"
|
#include "logger/Logger.hpp"
|
||||||
@@ -36,7 +36,7 @@ namespace QodeAssist::Providers {
|
|||||||
|
|
||||||
OpenAIResponsesProvider::OpenAIResponsesProvider(QObject *parent)
|
OpenAIResponsesProvider::OpenAIResponsesProvider(QObject *parent)
|
||||||
: PluginLLMCore::Provider(parent)
|
: PluginLLMCore::Provider(parent)
|
||||||
, m_client(new ::LLMCore::OpenAIResponsesClient(QString(), QString(), QString(), this))
|
, m_client(new ::LLMQore::OpenAIResponsesClient(QString(), QString(), QString(), this))
|
||||||
{
|
{
|
||||||
Tools::registerQodeAssistTools(m_client->tools());
|
Tools::registerQodeAssistTools(m_client->tools());
|
||||||
}
|
}
|
||||||
@@ -53,17 +53,7 @@ QString OpenAIResponsesProvider::apiKey() const
|
|||||||
|
|
||||||
QString OpenAIResponsesProvider::url() const
|
QString OpenAIResponsesProvider::url() const
|
||||||
{
|
{
|
||||||
return "https://api.openai.com";
|
return "https://api.openai.com/v1";
|
||||||
}
|
|
||||||
|
|
||||||
QString OpenAIResponsesProvider::completionEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/responses";
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OpenAIResponsesProvider::chatEndpoint() const
|
|
||||||
{
|
|
||||||
return "/v1/responses";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenAIResponsesProvider::prepareRequest(
|
void OpenAIResponsesProvider::prepareRequest(
|
||||||
@@ -179,7 +169,7 @@ PluginLLMCore::ProviderCapabilities OpenAIResponsesProvider::capabilities() cons
|
|||||||
| PluginLLMCore::ProviderCapability::ModelListing;
|
| PluginLLMCore::ProviderCapability::ModelListing;
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMCore::BaseClient *OpenAIResponsesProvider::client() const
|
::LLMQore::BaseClient *OpenAIResponsesProvider::client() const
|
||||||
{
|
{
|
||||||
return m_client;
|
return m_client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LLMCore/OpenAIResponsesClient.hpp>
|
#include <LLMQore/OpenAIResponsesClient.hpp>
|
||||||
#include <pluginllmcore/Provider.hpp>
|
#include <pluginllmcore/Provider.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Providers {
|
namespace QodeAssist::Providers {
|
||||||
@@ -32,8 +32,6 @@ public:
|
|||||||
|
|
||||||
QString name() const override;
|
QString name() const override;
|
||||||
QString url() const override;
|
QString url() const override;
|
||||||
QString completionEndpoint() const override;
|
|
||||||
QString chatEndpoint() const override;
|
|
||||||
void prepareRequest(
|
void prepareRequest(
|
||||||
QJsonObject &request,
|
QJsonObject &request,
|
||||||
PluginLLMCore::PromptTemplate *prompt,
|
PluginLLMCore::PromptTemplate *prompt,
|
||||||
@@ -45,11 +43,11 @@ public:
|
|||||||
PluginLLMCore::ProviderID providerID() const override;
|
PluginLLMCore::ProviderID providerID() const override;
|
||||||
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
||||||
|
|
||||||
::LLMCore::BaseClient *client() const override;
|
::LLMQore::BaseClient *client() const override;
|
||||||
QString apiKey() const override;
|
QString apiKey() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
::LLMCore::OpenAIResponsesClient *m_client;
|
::LLMQore::OpenAIResponsesClient *m_client;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Providers
|
} // namespace QodeAssist::Providers
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
add_library(QodeAssistSettings STATIC
|
add_library(QodeAssistSettings STATIC
|
||||||
GeneralSettings.hpp GeneralSettings.cpp
|
GeneralSettings.hpp GeneralSettings.cpp
|
||||||
CustomPromptSettings.hpp CustomPromptSettings.cpp
|
|
||||||
ConfigurationManager.hpp ConfigurationManager.cpp
|
ConfigurationManager.hpp ConfigurationManager.cpp
|
||||||
SettingsUtils.hpp
|
SettingsUtils.hpp
|
||||||
SettingsConstants.hpp
|
SettingsConstants.hpp
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ QVector<AIConfiguration> ConfigurationManager::getPredefinedConfigurations(
|
|||||||
claudeOpus.provider = "Claude";
|
claudeOpus.provider = "Claude";
|
||||||
claudeOpus.model = "claude-opus-4-6";
|
claudeOpus.model = "claude-opus-4-6";
|
||||||
claudeOpus.url = "https://api.anthropic.com";
|
claudeOpus.url = "https://api.anthropic.com";
|
||||||
claudeOpus.endpointMode = "Auto";
|
|
||||||
claudeOpus.customEndpoint = "";
|
claudeOpus.customEndpoint = "";
|
||||||
claudeOpus.templateName = "Claude";
|
claudeOpus.templateName = "Claude";
|
||||||
claudeOpus.type = type;
|
claudeOpus.type = type;
|
||||||
@@ -66,7 +65,6 @@ QVector<AIConfiguration> ConfigurationManager::getPredefinedConfigurations(
|
|||||||
claudeSonnet.provider = "Claude";
|
claudeSonnet.provider = "Claude";
|
||||||
claudeSonnet.model = "claude-sonnet-4-6";
|
claudeSonnet.model = "claude-sonnet-4-6";
|
||||||
claudeSonnet.url = "https://api.anthropic.com";
|
claudeSonnet.url = "https://api.anthropic.com";
|
||||||
claudeSonnet.endpointMode = "Auto";
|
|
||||||
claudeSonnet.customEndpoint = "";
|
claudeSonnet.customEndpoint = "";
|
||||||
claudeSonnet.templateName = "Claude";
|
claudeSonnet.templateName = "Claude";
|
||||||
claudeSonnet.type = type;
|
claudeSonnet.type = type;
|
||||||
@@ -78,7 +76,6 @@ QVector<AIConfiguration> ConfigurationManager::getPredefinedConfigurations(
|
|||||||
claudeHaiku.provider = "Claude";
|
claudeHaiku.provider = "Claude";
|
||||||
claudeHaiku.model = "claude-haiku-4-5-20251001";
|
claudeHaiku.model = "claude-haiku-4-5-20251001";
|
||||||
claudeHaiku.url = "https://api.anthropic.com";
|
claudeHaiku.url = "https://api.anthropic.com";
|
||||||
claudeHaiku.endpointMode = "Auto";
|
|
||||||
claudeHaiku.customEndpoint = "";
|
claudeHaiku.customEndpoint = "";
|
||||||
claudeHaiku.templateName = "Claude";
|
claudeHaiku.templateName = "Claude";
|
||||||
claudeHaiku.type = type;
|
claudeHaiku.type = type;
|
||||||
@@ -90,7 +87,6 @@ QVector<AIConfiguration> ConfigurationManager::getPredefinedConfigurations(
|
|||||||
codestral.provider = "Codestral";
|
codestral.provider = "Codestral";
|
||||||
codestral.model = "codestral-latest";
|
codestral.model = "codestral-latest";
|
||||||
codestral.url = "https://codestral.mistral.ai";
|
codestral.url = "https://codestral.mistral.ai";
|
||||||
codestral.endpointMode = "Auto";
|
|
||||||
codestral.customEndpoint = "";
|
codestral.customEndpoint = "";
|
||||||
codestral.templateName = type == ConfigurationType::CodeCompletion ? "Mistral AI FIM" : "Mistral AI Chat";
|
codestral.templateName = type == ConfigurationType::CodeCompletion ? "Mistral AI FIM" : "Mistral AI Chat";
|
||||||
codestral.type = type;
|
codestral.type = type;
|
||||||
@@ -100,9 +96,8 @@ QVector<AIConfiguration> ConfigurationManager::getPredefinedConfigurations(
|
|||||||
mistral.id = "preset_mistral";
|
mistral.id = "preset_mistral";
|
||||||
mistral.name = "Mistral";
|
mistral.name = "Mistral";
|
||||||
mistral.provider = "Mistral AI";
|
mistral.provider = "Mistral AI";
|
||||||
mistral.model = type == ConfigurationType::CodeCompletion ? "mistral-medium-latest" : "mistral-large-latest";
|
mistral.model = type == ConfigurationType::CodeCompletion ? "codestral-latest" : "mistral-large-latest";
|
||||||
mistral.url = "https://api.mistral.ai";
|
mistral.url = "https://api.mistral.ai";
|
||||||
mistral.endpointMode = "Auto";
|
|
||||||
mistral.customEndpoint = "";
|
mistral.customEndpoint = "";
|
||||||
mistral.templateName = type == ConfigurationType::CodeCompletion ? "Mistral AI FIM" : "Mistral AI Chat";
|
mistral.templateName = type == ConfigurationType::CodeCompletion ? "Mistral AI FIM" : "Mistral AI Chat";
|
||||||
mistral.type = type;
|
mistral.type = type;
|
||||||
@@ -114,7 +109,6 @@ QVector<AIConfiguration> ConfigurationManager::getPredefinedConfigurations(
|
|||||||
geminiFlash.provider = "Google AI";
|
geminiFlash.provider = "Google AI";
|
||||||
geminiFlash.model = "gemini-2.5-flash";
|
geminiFlash.model = "gemini-2.5-flash";
|
||||||
geminiFlash.url = "https://generativelanguage.googleapis.com/v1beta";
|
geminiFlash.url = "https://generativelanguage.googleapis.com/v1beta";
|
||||||
geminiFlash.endpointMode = "Auto";
|
|
||||||
geminiFlash.customEndpoint = "";
|
geminiFlash.customEndpoint = "";
|
||||||
geminiFlash.templateName = "Google AI";
|
geminiFlash.templateName = "Google AI";
|
||||||
geminiFlash.type = type;
|
geminiFlash.type = type;
|
||||||
@@ -125,8 +119,7 @@ QVector<AIConfiguration> ConfigurationManager::getPredefinedConfigurations(
|
|||||||
gpt.name = "gpt-5.4";
|
gpt.name = "gpt-5.4";
|
||||||
gpt.provider = "OpenAI Responses";
|
gpt.provider = "OpenAI Responses";
|
||||||
gpt.model = "gpt-5.4";
|
gpt.model = "gpt-5.4";
|
||||||
gpt.url = "https://api.openai.com";
|
gpt.url = "https://api.openai.com/v1";
|
||||||
gpt.endpointMode = "Auto";
|
|
||||||
gpt.customEndpoint = "";
|
gpt.customEndpoint = "";
|
||||||
gpt.templateName = "OpenAI Responses";
|
gpt.templateName = "OpenAI Responses";
|
||||||
gpt.type = type;
|
gpt.type = type;
|
||||||
@@ -230,10 +223,10 @@ bool ConfigurationManager::loadConfigurations(ConfigurationType type)
|
|||||||
config.model = obj["model"].toString();
|
config.model = obj["model"].toString();
|
||||||
config.templateName = obj["template"].toString();
|
config.templateName = obj["template"].toString();
|
||||||
config.url = obj["url"].toString();
|
config.url = obj["url"].toString();
|
||||||
config.endpointMode = obj["endpointMode"].toString();
|
|
||||||
config.customEndpoint = obj["customEndpoint"].toString();
|
config.customEndpoint = obj["customEndpoint"].toString();
|
||||||
config.type = type;
|
config.type = type;
|
||||||
config.formatVersion = obj.value("formatVersion").toInt(1);
|
config.formatVersion = obj.value("formatVersion").toInt(1);
|
||||||
|
|
||||||
config.isPredefined = false;
|
config.isPredefined = false;
|
||||||
|
|
||||||
if (config.id.isEmpty() || config.name.isEmpty()) {
|
if (config.id.isEmpty() || config.name.isEmpty()) {
|
||||||
@@ -263,7 +256,6 @@ bool ConfigurationManager::saveConfiguration(const AIConfiguration &config)
|
|||||||
obj["model"] = config.model;
|
obj["model"] = config.model;
|
||||||
obj["template"] = config.templateName;
|
obj["template"] = config.templateName;
|
||||||
obj["url"] = config.url;
|
obj["url"] = config.url;
|
||||||
obj["endpointMode"] = config.endpointMode;
|
|
||||||
obj["customEndpoint"] = config.customEndpoint;
|
obj["customEndpoint"] = config.customEndpoint;
|
||||||
|
|
||||||
QString sanitizedName = config.name;
|
QString sanitizedName = config.name;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ struct AIConfiguration
|
|||||||
QString model;
|
QString model;
|
||||||
QString templateName;
|
QString templateName;
|
||||||
QString url;
|
QString url;
|
||||||
QString endpointMode;
|
// Empty = use the template's endpoint; non-empty = override path.
|
||||||
QString customEndpoint;
|
QString customEndpoint;
|
||||||
ConfigurationType type;
|
ConfigurationType type;
|
||||||
int formatVersion = CONFIGURATION_FORMAT_VERSION;
|
int formatVersion = CONFIGURATION_FORMAT_VERSION;
|
||||||
|
|||||||
@@ -1,200 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 "CustomPromptSettings.hpp"
|
|
||||||
|
|
||||||
#include <coreplugin/dialogs/ioptionspage.h>
|
|
||||||
#include <coreplugin/icore.h>
|
|
||||||
#include <utils/layoutbuilder.h>
|
|
||||||
#include <QFileDialog>
|
|
||||||
#include <QJsonParseError>
|
|
||||||
#include <QMessageBox>
|
|
||||||
|
|
||||||
#include "SettingsConstants.hpp"
|
|
||||||
#include "SettingsTr.hpp"
|
|
||||||
#include "SettingsUtils.hpp"
|
|
||||||
|
|
||||||
namespace QodeAssist::Settings {
|
|
||||||
|
|
||||||
CustomPromptSettings &customPromptSettings()
|
|
||||||
{
|
|
||||||
static CustomPromptSettings settings;
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomPromptSettings::CustomPromptSettings()
|
|
||||||
{
|
|
||||||
setAutoApply(false);
|
|
||||||
|
|
||||||
setDisplayName(Tr::tr("Custom Prompt"));
|
|
||||||
|
|
||||||
customJsonLabel.setLabelText("Custom JSON Template:");
|
|
||||||
customJsonLabel.setDisplayStyle(Utils::StringAspect::LabelDisplay);
|
|
||||||
|
|
||||||
customJsonLegend.setLabelText(Tr::tr(R"(Prompt components:
|
|
||||||
- model is set on General Page
|
|
||||||
- {{QODE_INSTRUCTIONS}}: Placeholder for specific instructions or context.
|
|
||||||
- {{QODE_PREFIX}}: Will be replaced with the actual code before the cursor.
|
|
||||||
- {{QODE_SUFFIX}}: Will be replaced with the actual code after the cursor.
|
|
||||||
)"));
|
|
||||||
|
|
||||||
customJsonTemplate.setSettingsKey(Constants::CUSTOM_JSON_TEMPLATE);
|
|
||||||
customJsonTemplate.setDisplayStyle(Utils::StringAspect::TextEditDisplay);
|
|
||||||
|
|
||||||
customJsonTemplate.setDefaultValue(R"({
|
|
||||||
"prompt": "{{QODE_INSTRUCTIONS}}<fim_prefix>{{QODE_PREFIX}}<fim_suffix>{{QODE_SUFFIX}}<fim_middle>",
|
|
||||||
"options": {
|
|
||||||
"temperature": 0.7,
|
|
||||||
"top_p": 0.95,
|
|
||||||
"top_k": 40,
|
|
||||||
"num_predict": 100,
|
|
||||||
"stop": [
|
|
||||||
"<|endoftext|>",
|
|
||||||
"<file_sep>",
|
|
||||||
"<fim_prefix>",
|
|
||||||
"<fim_suffix>",
|
|
||||||
"<fim_middle>"
|
|
||||||
],
|
|
||||||
"frequency_penalty": 0,
|
|
||||||
"presence_penalty": 0
|
|
||||||
},
|
|
||||||
"stream": true
|
|
||||||
})");
|
|
||||||
saveCustomTemplateButton.m_buttonText = (Tr::tr("Save Custom Template to JSON"));
|
|
||||||
loadCustomTemplateButton.m_buttonText = (Tr::tr("Load Custom Template from JSON"));
|
|
||||||
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
|
|
||||||
|
|
||||||
readSettings();
|
|
||||||
|
|
||||||
setupConnection();
|
|
||||||
|
|
||||||
setLayouter([this]() {
|
|
||||||
using namespace Layouting;
|
|
||||||
return Column{Group{
|
|
||||||
title(Tr::tr("Custom prompt for FIM model")),
|
|
||||||
Column{
|
|
||||||
Row{customJsonLabel, Stretch{1}, resetToDefaults},
|
|
||||||
Row{customJsonTemplate,
|
|
||||||
Column{
|
|
||||||
saveCustomTemplateButton,
|
|
||||||
loadCustomTemplateButton,
|
|
||||||
customJsonLegend,
|
|
||||||
Stretch{1}}}}}};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void CustomPromptSettings::setupConnection()
|
|
||||||
{
|
|
||||||
connect(
|
|
||||||
&resetToDefaults,
|
|
||||||
&ButtonAspect::clicked,
|
|
||||||
this,
|
|
||||||
&CustomPromptSettings::resetSettingsToDefaults);
|
|
||||||
connect(
|
|
||||||
&saveCustomTemplateButton,
|
|
||||||
&ButtonAspect::clicked,
|
|
||||||
this,
|
|
||||||
&CustomPromptSettings::saveCustomTemplate);
|
|
||||||
connect(
|
|
||||||
&loadCustomTemplateButton,
|
|
||||||
&ButtonAspect::clicked,
|
|
||||||
this,
|
|
||||||
&CustomPromptSettings::loadCustomTemplate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CustomPromptSettings::resetSettingsToDefaults()
|
|
||||||
{
|
|
||||||
QMessageBox::StandardButton reply;
|
|
||||||
reply = QMessageBox::question(
|
|
||||||
Core::ICore::dialogParent(),
|
|
||||||
Tr::tr("Reset Settings"),
|
|
||||||
Tr::tr("Are you sure you want to reset all settings to default values?"),
|
|
||||||
QMessageBox::Yes | QMessageBox::No);
|
|
||||||
|
|
||||||
if (reply == QMessageBox::Yes) {
|
|
||||||
resetAspect(customJsonTemplate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CustomPromptSettings::saveCustomTemplate()
|
|
||||||
{
|
|
||||||
QString fileName = QFileDialog::getSaveFileName(
|
|
||||||
nullptr, Tr::tr("Save JSON Template"), QString(), Tr::tr("JSON Files (*.json)"));
|
|
||||||
if (fileName.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QFile file(fileName);
|
|
||||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
|
||||||
QTextStream out(&file);
|
|
||||||
out << customJsonTemplate.value();
|
|
||||||
file.close();
|
|
||||||
QMessageBox::information(
|
|
||||||
nullptr,
|
|
||||||
Tr::tr("Save Successful"),
|
|
||||||
Tr::tr("JSON template has been saved successfully."));
|
|
||||||
} else {
|
|
||||||
QMessageBox::critical(nullptr, Tr::tr("Save Failed"), Tr::tr("Failed to save JSON template."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CustomPromptSettings::loadCustomTemplate()
|
|
||||||
{
|
|
||||||
QString fileName = QFileDialog::getOpenFileName(
|
|
||||||
nullptr, Tr::tr("Load JSON Template"), QString(), Tr::tr("JSON Files (*.json)"));
|
|
||||||
if (fileName.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QFile file(fileName);
|
|
||||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
||||||
QTextStream in(&file);
|
|
||||||
QString jsonContent = in.readAll();
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
QJsonParseError parseError;
|
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonContent.toUtf8(), &parseError);
|
|
||||||
if (parseError.error == QJsonParseError::NoError) {
|
|
||||||
customJsonTemplate.setVolatileValue(jsonContent);
|
|
||||||
QMessageBox::information(
|
|
||||||
nullptr,
|
|
||||||
Tr::tr("Load Successful"),
|
|
||||||
Tr::tr("JSON template has been loaded successfully."));
|
|
||||||
} else {
|
|
||||||
QMessageBox::critical(
|
|
||||||
nullptr, Tr::tr("Invalid JSON"), Tr::tr("The selected file contains invalid JSON."));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
QMessageBox::critical(nullptr, Tr::tr("Load Failed"), Tr::tr("Failed to load JSON template."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CustomPromptSettingsPage : public Core::IOptionsPage
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CustomPromptSettingsPage()
|
|
||||||
{
|
|
||||||
setId(Constants::QODE_ASSIST_CUSTOM_PROMPT_SETTINGS_PAGE_ID);
|
|
||||||
setDisplayName(Tr::tr("Custom Prompt"));
|
|
||||||
setCategory(Constants::QODE_ASSIST_GENERAL_OPTIONS_CATEGORY);
|
|
||||||
setSettingsProvider([] { return &customPromptSettings(); });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const CustomPromptSettingsPage customPromptSettingsPage;
|
|
||||||
|
|
||||||
} // namespace QodeAssist::Settings
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <utils/aspects.h>
|
|
||||||
|
|
||||||
#include "ButtonAspect.hpp"
|
|
||||||
|
|
||||||
namespace QodeAssist::Settings {
|
|
||||||
|
|
||||||
class CustomPromptSettings : public Utils::AspectContainer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CustomPromptSettings();
|
|
||||||
|
|
||||||
Utils::StringAspect customJsonLabel{this};
|
|
||||||
Utils::StringAspect customJsonTemplate{this};
|
|
||||||
Utils::StringAspect customJsonLegend{this};
|
|
||||||
ButtonAspect saveCustomTemplateButton{this};
|
|
||||||
ButtonAspect loadCustomTemplateButton{this};
|
|
||||||
ButtonAspect resetToDefaults{this};
|
|
||||||
|
|
||||||
private:
|
|
||||||
void setupConnection();
|
|
||||||
void resetSettingsToDefaults();
|
|
||||||
void saveCustomTemplate();
|
|
||||||
void loadCustomTemplate();
|
|
||||||
};
|
|
||||||
|
|
||||||
CustomPromptSettings &customPromptSettings();
|
|
||||||
|
|
||||||
} // namespace QodeAssist::Settings
|
|
||||||
@@ -124,18 +124,10 @@ GeneralSettings::GeneralSettings()
|
|||||||
ccSelectTemplate.m_buttonText = TrConstants::SELECT;
|
ccSelectTemplate.m_buttonText = TrConstants::SELECT;
|
||||||
|
|
||||||
initStringAspect(ccUrl, Constants::CC_URL, TrConstants::URL, "http://localhost:11434");
|
initStringAspect(ccUrl, Constants::CC_URL, TrConstants::URL, "http://localhost:11434");
|
||||||
ccUrl.setHistoryCompleter(Constants::CC_CUSTOM_ENDPOINT_HISTORY);
|
ccUrl.setHistoryCompleter(Constants::CC_URL_HISTORY);
|
||||||
ccSetUrl.m_buttonText = TrConstants::SELECT;
|
ccSetUrl.m_buttonText = TrConstants::SELECT;
|
||||||
|
|
||||||
ccEndpointMode.setSettingsKey(Constants::CC_ENDPOINT_MODE);
|
initStringAspect(ccCustomEndpoint, Constants::CC_CUSTOM_ENDPOINT, TrConstants::CUSTOM_ENDPOINT, "");
|
||||||
ccEndpointMode.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
|
|
||||||
ccEndpointMode.addOption("Auto");
|
|
||||||
ccEndpointMode.addOption("Custom");
|
|
||||||
ccEndpointMode.addOption("FIM");
|
|
||||||
ccEndpointMode.addOption("Chat");
|
|
||||||
ccEndpointMode.setDefaultValue("Auto");
|
|
||||||
|
|
||||||
initStringAspect(ccCustomEndpoint, Constants::CC_CUSTOM_ENDPOINT, TrConstants::ENDPOINT_MODE, "");
|
|
||||||
ccCustomEndpoint.setHistoryCompleter(Constants::CC_CUSTOM_ENDPOINT_HISTORY);
|
ccCustomEndpoint.setHistoryCompleter(Constants::CC_CUSTOM_ENDPOINT_HISTORY);
|
||||||
|
|
||||||
ccStatus.setDisplayStyle(Utils::StringAspect::LabelDisplay);
|
ccStatus.setDisplayStyle(Utils::StringAspect::LabelDisplay);
|
||||||
@@ -176,18 +168,10 @@ GeneralSettings::GeneralSettings()
|
|||||||
ccPreset1Url.setHistoryCompleter(Constants::CC_PRESET1_URL_HISTORY);
|
ccPreset1Url.setHistoryCompleter(Constants::CC_PRESET1_URL_HISTORY);
|
||||||
ccPreset1SetUrl.m_buttonText = TrConstants::SELECT;
|
ccPreset1SetUrl.m_buttonText = TrConstants::SELECT;
|
||||||
|
|
||||||
ccPreset1EndpointMode.setSettingsKey(Constants::CC_PRESET1_ENDPOINT_MODE);
|
|
||||||
ccPreset1EndpointMode.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
|
|
||||||
ccPreset1EndpointMode.addOption("Auto");
|
|
||||||
ccPreset1EndpointMode.addOption("Custom");
|
|
||||||
ccPreset1EndpointMode.addOption("FIM");
|
|
||||||
ccPreset1EndpointMode.addOption("Chat");
|
|
||||||
ccPreset1EndpointMode.setDefaultValue("Auto");
|
|
||||||
|
|
||||||
initStringAspect(
|
initStringAspect(
|
||||||
ccPreset1CustomEndpoint,
|
ccPreset1CustomEndpoint,
|
||||||
Constants::CC_PRESET1_CUSTOM_ENDPOINT,
|
Constants::CC_PRESET1_CUSTOM_ENDPOINT,
|
||||||
TrConstants::ENDPOINT_MODE,
|
TrConstants::CUSTOM_ENDPOINT,
|
||||||
"");
|
"");
|
||||||
ccPreset1CustomEndpoint.setHistoryCompleter(Constants::CC_PRESET1_CUSTOM_ENDPOINT_HISTORY);
|
ccPreset1CustomEndpoint.setHistoryCompleter(Constants::CC_PRESET1_CUSTOM_ENDPOINT_HISTORY);
|
||||||
|
|
||||||
@@ -219,15 +203,7 @@ GeneralSettings::GeneralSettings()
|
|||||||
caUrl.setHistoryCompleter(Constants::CA_URL_HISTORY);
|
caUrl.setHistoryCompleter(Constants::CA_URL_HISTORY);
|
||||||
caSetUrl.m_buttonText = TrConstants::SELECT;
|
caSetUrl.m_buttonText = TrConstants::SELECT;
|
||||||
|
|
||||||
caEndpointMode.setSettingsKey(Constants::CA_ENDPOINT_MODE);
|
initStringAspect(caCustomEndpoint, Constants::CA_CUSTOM_ENDPOINT, TrConstants::CUSTOM_ENDPOINT, "");
|
||||||
caEndpointMode.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
|
|
||||||
caEndpointMode.addOption("Auto");
|
|
||||||
caEndpointMode.addOption("Custom");
|
|
||||||
caEndpointMode.addOption("FIM");
|
|
||||||
caEndpointMode.addOption("Chat");
|
|
||||||
caEndpointMode.setDefaultValue("Auto");
|
|
||||||
|
|
||||||
initStringAspect(caCustomEndpoint, Constants::CA_CUSTOM_ENDPOINT, TrConstants::ENDPOINT_MODE, "");
|
|
||||||
caCustomEndpoint.setHistoryCompleter(Constants::CA_CUSTOM_ENDPOINT_HISTORY);
|
caCustomEndpoint.setHistoryCompleter(Constants::CA_CUSTOM_ENDPOINT_HISTORY);
|
||||||
|
|
||||||
caStatus.setDisplayStyle(Utils::StringAspect::LabelDisplay);
|
caStatus.setDisplayStyle(Utils::StringAspect::LabelDisplay);
|
||||||
@@ -264,15 +240,7 @@ GeneralSettings::GeneralSettings()
|
|||||||
qrUrl.setHistoryCompleter(Constants::QR_URL_HISTORY);
|
qrUrl.setHistoryCompleter(Constants::QR_URL_HISTORY);
|
||||||
qrSetUrl.m_buttonText = TrConstants::SELECT;
|
qrSetUrl.m_buttonText = TrConstants::SELECT;
|
||||||
|
|
||||||
qrEndpointMode.setSettingsKey(Constants::QR_ENDPOINT_MODE);
|
initStringAspect(qrCustomEndpoint, Constants::QR_CUSTOM_ENDPOINT, TrConstants::CUSTOM_ENDPOINT, "");
|
||||||
qrEndpointMode.setDisplayStyle(Utils::SelectionAspect::DisplayStyle::ComboBox);
|
|
||||||
qrEndpointMode.addOption("Auto");
|
|
||||||
qrEndpointMode.addOption("Custom");
|
|
||||||
qrEndpointMode.addOption("FIM");
|
|
||||||
qrEndpointMode.addOption("Chat");
|
|
||||||
qrEndpointMode.setDefaultValue("Auto");
|
|
||||||
|
|
||||||
initStringAspect(qrCustomEndpoint, Constants::QR_CUSTOM_ENDPOINT, TrConstants::ENDPOINT_MODE, "");
|
|
||||||
qrCustomEndpoint.setHistoryCompleter(Constants::QR_CUSTOM_ENDPOINT_HISTORY);
|
qrCustomEndpoint.setHistoryCompleter(Constants::QR_CUSTOM_ENDPOINT_HISTORY);
|
||||||
|
|
||||||
qrStatus.setDisplayStyle(Utils::StringAspect::LabelDisplay);
|
qrStatus.setDisplayStyle(Utils::StringAspect::LabelDisplay);
|
||||||
@@ -310,10 +278,6 @@ GeneralSettings::GeneralSettings()
|
|||||||
setupConnections();
|
setupConnections();
|
||||||
|
|
||||||
updatePreset1Visiblity(specifyPreset1.value());
|
updatePreset1Visiblity(specifyPreset1.value());
|
||||||
ccCustomEndpoint.setEnabled(ccEndpointMode.stringValue() == "Custom");
|
|
||||||
ccPreset1CustomEndpoint.setEnabled(ccPreset1EndpointMode.stringValue() == "Custom");
|
|
||||||
caCustomEndpoint.setEnabled(caEndpointMode.stringValue() == "Custom");
|
|
||||||
qrCustomEndpoint.setEnabled(qrEndpointMode.stringValue() == "Custom");
|
|
||||||
|
|
||||||
setLayouter([this]() {
|
setLayouter([this]() {
|
||||||
using namespace Layouting;
|
using namespace Layouting;
|
||||||
@@ -321,28 +285,28 @@ GeneralSettings::GeneralSettings()
|
|||||||
auto ccGrid = Grid{};
|
auto ccGrid = Grid{};
|
||||||
ccGrid.addRow({ccProvider, ccSelectProvider});
|
ccGrid.addRow({ccProvider, ccSelectProvider});
|
||||||
ccGrid.addRow({ccUrl, ccSetUrl});
|
ccGrid.addRow({ccUrl, ccSetUrl});
|
||||||
ccGrid.addRow({ccCustomEndpoint, ccEndpointMode});
|
ccGrid.addRow({ccCustomEndpoint});
|
||||||
ccGrid.addRow({ccModel, ccSelectModel});
|
ccGrid.addRow({ccModel, ccSelectModel});
|
||||||
ccGrid.addRow({ccTemplate, ccSelectTemplate, ccShowTemplateInfo});
|
ccGrid.addRow({ccTemplate, ccSelectTemplate, ccShowTemplateInfo});
|
||||||
|
|
||||||
auto ccPreset1Grid = Grid{};
|
auto ccPreset1Grid = Grid{};
|
||||||
ccPreset1Grid.addRow({ccPreset1Provider, ccPreset1SelectProvider});
|
ccPreset1Grid.addRow({ccPreset1Provider, ccPreset1SelectProvider});
|
||||||
ccPreset1Grid.addRow({ccPreset1Url, ccPreset1SetUrl});
|
ccPreset1Grid.addRow({ccPreset1Url, ccPreset1SetUrl});
|
||||||
ccPreset1Grid.addRow({ccPreset1CustomEndpoint, ccPreset1EndpointMode});
|
ccPreset1Grid.addRow({ccPreset1CustomEndpoint});
|
||||||
ccPreset1Grid.addRow({ccPreset1Model, ccPreset1SelectModel});
|
ccPreset1Grid.addRow({ccPreset1Model, ccPreset1SelectModel});
|
||||||
ccPreset1Grid.addRow({ccPreset1Template, ccPreset1SelectTemplate});
|
ccPreset1Grid.addRow({ccPreset1Template, ccPreset1SelectTemplate});
|
||||||
|
|
||||||
auto caGrid = Grid{};
|
auto caGrid = Grid{};
|
||||||
caGrid.addRow({caProvider, caSelectProvider});
|
caGrid.addRow({caProvider, caSelectProvider});
|
||||||
caGrid.addRow({caUrl, caSetUrl});
|
caGrid.addRow({caUrl, caSetUrl});
|
||||||
caGrid.addRow({caCustomEndpoint, caEndpointMode});
|
caGrid.addRow({caCustomEndpoint});
|
||||||
caGrid.addRow({caModel, caSelectModel});
|
caGrid.addRow({caModel, caSelectModel});
|
||||||
caGrid.addRow({caTemplate, caSelectTemplate, caShowTemplateInfo});
|
caGrid.addRow({caTemplate, caSelectTemplate, caShowTemplateInfo});
|
||||||
|
|
||||||
auto qrGrid = Grid{};
|
auto qrGrid = Grid{};
|
||||||
qrGrid.addRow({qrProvider, qrSelectProvider});
|
qrGrid.addRow({qrProvider, qrSelectProvider});
|
||||||
qrGrid.addRow({qrUrl, qrSetUrl});
|
qrGrid.addRow({qrUrl, qrSetUrl});
|
||||||
qrGrid.addRow({qrCustomEndpoint, qrEndpointMode});
|
qrGrid.addRow({qrCustomEndpoint});
|
||||||
qrGrid.addRow({qrModel, qrSelectModel});
|
qrGrid.addRow({qrModel, qrSelectModel});
|
||||||
qrGrid.addRow({qrTemplate, qrSelectTemplate, qrShowTemplateInfo});
|
qrGrid.addRow({qrTemplate, qrSelectTemplate, qrShowTemplateInfo});
|
||||||
|
|
||||||
@@ -589,7 +553,6 @@ void GeneralSettings::updatePreset1Visiblity(bool state)
|
|||||||
ccPreset1SelectModel.updateVisibility(specifyPreset1.volatileValue());
|
ccPreset1SelectModel.updateVisibility(specifyPreset1.volatileValue());
|
||||||
ccPreset1Template.setVisible(specifyPreset1.volatileValue());
|
ccPreset1Template.setVisible(specifyPreset1.volatileValue());
|
||||||
ccPreset1SelectTemplate.updateVisibility(specifyPreset1.volatileValue());
|
ccPreset1SelectTemplate.updateVisibility(specifyPreset1.volatileValue());
|
||||||
ccPreset1EndpointMode.setVisible(specifyPreset1.volatileValue());
|
|
||||||
ccPreset1CustomEndpoint.setVisible(specifyPreset1.volatileValue());
|
ccPreset1CustomEndpoint.setVisible(specifyPreset1.volatileValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,24 +596,6 @@ void GeneralSettings::setupConnections()
|
|||||||
connect(&specifyPreset1, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
connect(&specifyPreset1, &Utils::BoolAspect::volatileValueChanged, this, [this]() {
|
||||||
updatePreset1Visiblity(specifyPreset1.volatileValue());
|
updatePreset1Visiblity(specifyPreset1.volatileValue());
|
||||||
});
|
});
|
||||||
connect(&ccEndpointMode, &Utils::BaseAspect::volatileValueChanged, this, [this]() {
|
|
||||||
ccCustomEndpoint.setEnabled(
|
|
||||||
ccEndpointMode.volatileValue() == ccEndpointMode.indexForDisplay("Custom"));
|
|
||||||
});
|
|
||||||
connect(&ccPreset1EndpointMode, &Utils::BaseAspect::volatileValueChanged, this, [this]() {
|
|
||||||
ccPreset1CustomEndpoint.setEnabled(
|
|
||||||
ccPreset1EndpointMode.volatileValue()
|
|
||||||
== ccPreset1EndpointMode.indexForDisplay("Custom"));
|
|
||||||
});
|
|
||||||
connect(&caEndpointMode, &Utils::BaseAspect::volatileValueChanged, this, [this]() {
|
|
||||||
caCustomEndpoint.setEnabled(
|
|
||||||
caEndpointMode.volatileValue() == caEndpointMode.indexForDisplay("Custom"));
|
|
||||||
});
|
|
||||||
connect(&qrEndpointMode, &Utils::BaseAspect::volatileValueChanged, this, [this]() {
|
|
||||||
qrCustomEndpoint.setEnabled(
|
|
||||||
qrEndpointMode.volatileValue() == qrEndpointMode.indexForDisplay("Custom"));
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(&ccShowTemplateInfo, &ButtonAspect::clicked, this, [this]() {
|
connect(&ccShowTemplateInfo, &ButtonAspect::clicked, this, [this]() {
|
||||||
showTemplateInfoDialog(ccTemplateDescription, ccTemplate.value());
|
showTemplateInfoDialog(ccTemplateDescription, ccTemplate.value());
|
||||||
});
|
});
|
||||||
@@ -733,17 +678,13 @@ void GeneralSettings::resetPageToDefaults()
|
|||||||
resetAspect(ccPreset1Model);
|
resetAspect(ccPreset1Model);
|
||||||
resetAspect(ccPreset1Template);
|
resetAspect(ccPreset1Template);
|
||||||
resetAspect(ccPreset1Url);
|
resetAspect(ccPreset1Url);
|
||||||
resetAspect(ccEndpointMode);
|
|
||||||
resetAspect(ccCustomEndpoint);
|
resetAspect(ccCustomEndpoint);
|
||||||
resetAspect(ccPreset1EndpointMode);
|
|
||||||
resetAspect(ccPreset1CustomEndpoint);
|
resetAspect(ccPreset1CustomEndpoint);
|
||||||
resetAspect(caEndpointMode);
|
|
||||||
resetAspect(caCustomEndpoint);
|
resetAspect(caCustomEndpoint);
|
||||||
resetAspect(qrProvider);
|
resetAspect(qrProvider);
|
||||||
resetAspect(qrModel);
|
resetAspect(qrModel);
|
||||||
resetAspect(qrTemplate);
|
resetAspect(qrTemplate);
|
||||||
resetAspect(qrUrl);
|
resetAspect(qrUrl);
|
||||||
resetAspect(qrEndpointMode);
|
|
||||||
resetAspect(qrCustomEndpoint);
|
resetAspect(qrCustomEndpoint);
|
||||||
writeSettings();
|
writeSettings();
|
||||||
}
|
}
|
||||||
@@ -773,7 +714,6 @@ void GeneralSettings::onSaveConfiguration(const QString &prefix)
|
|||||||
config.model = ccModel.value();
|
config.model = ccModel.value();
|
||||||
config.templateName = ccTemplate.value();
|
config.templateName = ccTemplate.value();
|
||||||
config.url = ccUrl.value();
|
config.url = ccUrl.value();
|
||||||
config.endpointMode = ccEndpointMode.stringValue();
|
|
||||||
config.customEndpoint = ccCustomEndpoint.value();
|
config.customEndpoint = ccCustomEndpoint.value();
|
||||||
config.type = ConfigurationType::CodeCompletion;
|
config.type = ConfigurationType::CodeCompletion;
|
||||||
} else if (prefix == "ca") {
|
} else if (prefix == "ca") {
|
||||||
@@ -781,7 +721,6 @@ void GeneralSettings::onSaveConfiguration(const QString &prefix)
|
|||||||
config.model = caModel.value();
|
config.model = caModel.value();
|
||||||
config.templateName = caTemplate.value();
|
config.templateName = caTemplate.value();
|
||||||
config.url = caUrl.value();
|
config.url = caUrl.value();
|
||||||
config.endpointMode = caEndpointMode.stringValue();
|
|
||||||
config.customEndpoint = caCustomEndpoint.value();
|
config.customEndpoint = caCustomEndpoint.value();
|
||||||
config.type = ConfigurationType::Chat;
|
config.type = ConfigurationType::Chat;
|
||||||
} else if (prefix == "qr") {
|
} else if (prefix == "qr") {
|
||||||
@@ -789,7 +728,6 @@ void GeneralSettings::onSaveConfiguration(const QString &prefix)
|
|||||||
config.model = qrModel.value();
|
config.model = qrModel.value();
|
||||||
config.templateName = qrTemplate.value();
|
config.templateName = qrTemplate.value();
|
||||||
config.url = qrUrl.value();
|
config.url = qrUrl.value();
|
||||||
config.endpointMode = qrEndpointMode.stringValue();
|
|
||||||
config.customEndpoint = qrCustomEndpoint.value();
|
config.customEndpoint = qrCustomEndpoint.value();
|
||||||
config.type = ConfigurationType::QuickRefactor;
|
config.type = ConfigurationType::QuickRefactor;
|
||||||
}
|
}
|
||||||
@@ -926,21 +864,18 @@ void GeneralSettings::onLoadConfiguration(const QString &prefix)
|
|||||||
ccModel.setValue(config.model);
|
ccModel.setValue(config.model);
|
||||||
ccTemplate.setValue(config.templateName);
|
ccTemplate.setValue(config.templateName);
|
||||||
ccUrl.setValue(config.url);
|
ccUrl.setValue(config.url);
|
||||||
ccEndpointMode.setValue(ccEndpointMode.indexForDisplay(config.endpointMode));
|
|
||||||
ccCustomEndpoint.setValue(config.customEndpoint);
|
ccCustomEndpoint.setValue(config.customEndpoint);
|
||||||
} else if (prefix == "ca") {
|
} else if (prefix == "ca") {
|
||||||
caProvider.setValue(config.provider);
|
caProvider.setValue(config.provider);
|
||||||
caModel.setValue(config.model);
|
caModel.setValue(config.model);
|
||||||
caTemplate.setValue(config.templateName);
|
caTemplate.setValue(config.templateName);
|
||||||
caUrl.setValue(config.url);
|
caUrl.setValue(config.url);
|
||||||
caEndpointMode.setValue(caEndpointMode.indexForDisplay(config.endpointMode));
|
|
||||||
caCustomEndpoint.setValue(config.customEndpoint);
|
caCustomEndpoint.setValue(config.customEndpoint);
|
||||||
} else if (prefix == "qr") {
|
} else if (prefix == "qr") {
|
||||||
qrProvider.setValue(config.provider);
|
qrProvider.setValue(config.provider);
|
||||||
qrModel.setValue(config.model);
|
qrModel.setValue(config.model);
|
||||||
qrTemplate.setValue(config.templateName);
|
qrTemplate.setValue(config.templateName);
|
||||||
qrUrl.setValue(config.url);
|
qrUrl.setValue(config.url);
|
||||||
qrEndpointMode.setValue(qrEndpointMode.indexForDisplay(config.endpointMode));
|
|
||||||
qrCustomEndpoint.setValue(config.customEndpoint);
|
qrCustomEndpoint.setValue(config.customEndpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1008,21 +943,18 @@ void GeneralSettings::applyPresetConfiguration(int index, ConfigurationType type
|
|||||||
ccModel.setValue(config.model);
|
ccModel.setValue(config.model);
|
||||||
ccTemplate.setValue(config.templateName);
|
ccTemplate.setValue(config.templateName);
|
||||||
ccUrl.setValue(config.url);
|
ccUrl.setValue(config.url);
|
||||||
ccEndpointMode.setValue(ccEndpointMode.indexForDisplay(config.endpointMode));
|
|
||||||
ccCustomEndpoint.setValue(config.customEndpoint);
|
ccCustomEndpoint.setValue(config.customEndpoint);
|
||||||
} else if (type == ConfigurationType::Chat) {
|
} else if (type == ConfigurationType::Chat) {
|
||||||
caProvider.setValue(config.provider);
|
caProvider.setValue(config.provider);
|
||||||
caModel.setValue(config.model);
|
caModel.setValue(config.model);
|
||||||
caTemplate.setValue(config.templateName);
|
caTemplate.setValue(config.templateName);
|
||||||
caUrl.setValue(config.url);
|
caUrl.setValue(config.url);
|
||||||
caEndpointMode.setValue(caEndpointMode.indexForDisplay(config.endpointMode));
|
|
||||||
caCustomEndpoint.setValue(config.customEndpoint);
|
caCustomEndpoint.setValue(config.customEndpoint);
|
||||||
} else if (type == ConfigurationType::QuickRefactor) {
|
} else if (type == ConfigurationType::QuickRefactor) {
|
||||||
qrProvider.setValue(config.provider);
|
qrProvider.setValue(config.provider);
|
||||||
qrModel.setValue(config.model);
|
qrModel.setValue(config.model);
|
||||||
qrTemplate.setValue(config.templateName);
|
qrTemplate.setValue(config.templateName);
|
||||||
qrUrl.setValue(config.url);
|
qrUrl.setValue(config.url);
|
||||||
qrEndpointMode.setValue(qrEndpointMode.indexForDisplay(config.endpointMode));
|
|
||||||
qrCustomEndpoint.setValue(config.customEndpoint);
|
qrCustomEndpoint.setValue(config.customEndpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ public:
|
|||||||
Utils::StringAspect ccUrl{this};
|
Utils::StringAspect ccUrl{this};
|
||||||
ButtonAspect ccSetUrl{this};
|
ButtonAspect ccSetUrl{this};
|
||||||
|
|
||||||
Utils::SelectionAspect ccEndpointMode{this};
|
|
||||||
Utils::StringAspect ccCustomEndpoint{this};
|
Utils::StringAspect ccCustomEndpoint{this};
|
||||||
|
|
||||||
Utils::StringAspect ccStatus{this};
|
Utils::StringAspect ccStatus{this};
|
||||||
@@ -85,7 +84,6 @@ public:
|
|||||||
Utils::StringAspect ccPreset1Url{this};
|
Utils::StringAspect ccPreset1Url{this};
|
||||||
ButtonAspect ccPreset1SetUrl{this};
|
ButtonAspect ccPreset1SetUrl{this};
|
||||||
|
|
||||||
Utils::SelectionAspect ccPreset1EndpointMode{this};
|
|
||||||
Utils::StringAspect ccPreset1CustomEndpoint{this};
|
Utils::StringAspect ccPreset1CustomEndpoint{this};
|
||||||
|
|
||||||
Utils::StringAspect ccPreset1Model{this};
|
Utils::StringAspect ccPreset1Model{this};
|
||||||
@@ -110,7 +108,6 @@ public:
|
|||||||
Utils::StringAspect caUrl{this};
|
Utils::StringAspect caUrl{this};
|
||||||
ButtonAspect caSetUrl{this};
|
ButtonAspect caSetUrl{this};
|
||||||
|
|
||||||
Utils::SelectionAspect caEndpointMode{this};
|
|
||||||
Utils::StringAspect caCustomEndpoint{this};
|
Utils::StringAspect caCustomEndpoint{this};
|
||||||
|
|
||||||
Utils::StringAspect caStatus{this};
|
Utils::StringAspect caStatus{this};
|
||||||
@@ -138,7 +135,6 @@ public:
|
|||||||
Utils::StringAspect qrUrl{this};
|
Utils::StringAspect qrUrl{this};
|
||||||
ButtonAspect qrSetUrl{this};
|
ButtonAspect qrSetUrl{this};
|
||||||
|
|
||||||
Utils::SelectionAspect qrEndpointMode{this};
|
|
||||||
Utils::StringAspect qrCustomEndpoint{this};
|
Utils::StringAspect qrCustomEndpoint{this};
|
||||||
|
|
||||||
Utils::StringAspect qrStatus{this};
|
Utils::StringAspect qrStatus{this};
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ const char CC_MODEL_HISTORY[] = "QodeAssist.ccModelHistory";
|
|||||||
const char CC_TEMPLATE[] = "QodeAssist.ccTemplate";
|
const char CC_TEMPLATE[] = "QodeAssist.ccTemplate";
|
||||||
const char CC_URL[] = "QodeAssist.ccUrl";
|
const char CC_URL[] = "QodeAssist.ccUrl";
|
||||||
const char CC_URL_HISTORY[] = "QodeAssist.ccUrlHistory";
|
const char CC_URL_HISTORY[] = "QodeAssist.ccUrlHistory";
|
||||||
const char CC_ENDPOINT_MODE[] = "QodeAssist.ccEndpointMode";
|
|
||||||
const char CC_CUSTOM_ENDPOINT[] = "QodeAssist.ccCustomEndpoint";
|
const char CC_CUSTOM_ENDPOINT[] = "QodeAssist.ccCustomEndpoint";
|
||||||
const char CC_CUSTOM_ENDPOINT_HISTORY[] = "QodeAssist.ccCustomEndpointHistory";
|
const char CC_CUSTOM_ENDPOINT_HISTORY[] = "QodeAssist.ccCustomEndpointHistory";
|
||||||
|
|
||||||
@@ -45,7 +44,6 @@ const char CA_MODEL_HISTORY[] = "QodeAssist.caModelHistory";
|
|||||||
const char CA_TEMPLATE[] = "QodeAssist.caTemplate";
|
const char CA_TEMPLATE[] = "QodeAssist.caTemplate";
|
||||||
const char CA_URL[] = "QodeAssist.caUrl";
|
const char CA_URL[] = "QodeAssist.caUrl";
|
||||||
const char CA_URL_HISTORY[] = "QodeAssist.caUrlHistory";
|
const char CA_URL_HISTORY[] = "QodeAssist.caUrlHistory";
|
||||||
const char CA_ENDPOINT_MODE[] = "QodeAssist.caEndpointMode";
|
|
||||||
const char CA_CUSTOM_ENDPOINT[] = "QodeAssist.caCustomEndpoint";
|
const char CA_CUSTOM_ENDPOINT[] = "QodeAssist.caCustomEndpoint";
|
||||||
const char CA_CUSTOM_ENDPOINT_HISTORY[] = "QodeAssist.caCustomEndpointHistory";
|
const char CA_CUSTOM_ENDPOINT_HISTORY[] = "QodeAssist.caCustomEndpointHistory";
|
||||||
|
|
||||||
@@ -56,7 +54,6 @@ const char QR_MODEL_HISTORY[] = "QodeAssist.qrModelHistory";
|
|||||||
const char QR_TEMPLATE[] = "QodeAssist.qrTemplate";
|
const char QR_TEMPLATE[] = "QodeAssist.qrTemplate";
|
||||||
const char QR_URL[] = "QodeAssist.qrUrl";
|
const char QR_URL[] = "QodeAssist.qrUrl";
|
||||||
const char QR_URL_HISTORY[] = "QodeAssist.qrUrlHistory";
|
const char QR_URL_HISTORY[] = "QodeAssist.qrUrlHistory";
|
||||||
const char QR_ENDPOINT_MODE[] = "QodeAssist.qrEndpointMode";
|
|
||||||
const char QR_CUSTOM_ENDPOINT[] = "QodeAssist.qrCustomEndpoint";
|
const char QR_CUSTOM_ENDPOINT[] = "QodeAssist.qrCustomEndpoint";
|
||||||
const char QR_CUSTOM_ENDPOINT_HISTORY[] = "QodeAssist.qrCustomEndpointHistory";
|
const char QR_CUSTOM_ENDPOINT_HISTORY[] = "QodeAssist.qrCustomEndpointHistory";
|
||||||
|
|
||||||
@@ -68,9 +65,8 @@ const char CC_PRESET1_MODEL_HISTORY[] = "QodeAssist.ccPreset1ModelHistory";
|
|||||||
const char CC_PRESET1_TEMPLATE[] = "QodeAssist.ccPreset1Template";
|
const char CC_PRESET1_TEMPLATE[] = "QodeAssist.ccPreset1Template";
|
||||||
const char CC_PRESET1_URL[] = "QodeAssist.ccPreset1Url";
|
const char CC_PRESET1_URL[] = "QodeAssist.ccPreset1Url";
|
||||||
const char CC_PRESET1_URL_HISTORY[] = "QodeAssist.ccPreset1UrlHistory";
|
const char CC_PRESET1_URL_HISTORY[] = "QodeAssist.ccPreset1UrlHistory";
|
||||||
const char CC_PRESET1_ENDPOINT_MODE[] = "QodeAssist.caPreset1EndpointMode";
|
const char CC_PRESET1_CUSTOM_ENDPOINT[] = "QodeAssist.ccPreset1CustomEndpoint";
|
||||||
const char CC_PRESET1_CUSTOM_ENDPOINT[] = "QodeAssist.caPreset1CustomEndpointHistory";
|
const char CC_PRESET1_CUSTOM_ENDPOINT_HISTORY[] = "QodeAssist.ccPreset1CustomEndpointHistory";
|
||||||
const char CC_PRESET1_CUSTOM_ENDPOINT_HISTORY[] = "QodeAssist.caPreset1CustomEndpointHistory";
|
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
const char ENABLE_QODE_ASSIST[] = "QodeAssist.enableQodeAssist";
|
const char ENABLE_QODE_ASSIST[] = "QodeAssist.enableQodeAssist";
|
||||||
@@ -93,7 +89,6 @@ const char CC_IGNORE_WHITESPACE_IN_CHAR_COUNT[] = "QodeAssist.ccIgnoreWhitespace
|
|||||||
const char MAX_FILE_THRESHOLD[] = "QodeAssist.maxFileThreshold";
|
const char MAX_FILE_THRESHOLD[] = "QodeAssist.maxFileThreshold";
|
||||||
const char CC_MULTILINE_COMPLETION[] = "QodeAssist.ccMultilineCompletion";
|
const char CC_MULTILINE_COMPLETION[] = "QodeAssist.ccMultilineCompletion";
|
||||||
const char CC_MODEL_OUTPUT_HANDLER[] = "QodeAssist.ccModelOutputHandler";
|
const char CC_MODEL_OUTPUT_HANDLER[] = "QodeAssist.ccModelOutputHandler";
|
||||||
const char CUSTOM_JSON_TEMPLATE[] = "QodeAssist.customJsonTemplate";
|
|
||||||
const char CA_AUTO_APPLY_FILE_EDITS[] = "QodeAssist.caAutoApplyFileEdits";
|
const char CA_AUTO_APPLY_FILE_EDITS[] = "QodeAssist.caAutoApplyFileEdits";
|
||||||
const char CA_TOKENS_THRESHOLD[] = "QodeAssist.caTokensThreshold";
|
const char CA_TOKENS_THRESHOLD[] = "QodeAssist.caTokensThreshold";
|
||||||
const char CA_LINK_OPEN_FILES[] = "QodeAssist.caLinkOpenFiles";
|
const char CA_LINK_OPEN_FILES[] = "QodeAssist.caLinkOpenFiles";
|
||||||
@@ -127,7 +122,6 @@ const char QODE_ASSIST_CHAT_ASSISTANT_SETTINGS_PAGE_ID[]
|
|||||||
const char QODE_ASSIST_QUICK_REFACTOR_SETTINGS_PAGE_ID[]
|
const char QODE_ASSIST_QUICK_REFACTOR_SETTINGS_PAGE_ID[]
|
||||||
= "QodeAssist.4QuickRefactorSettingsPageId";
|
= "QodeAssist.4QuickRefactorSettingsPageId";
|
||||||
const char QODE_ASSIST_TOOLS_SETTINGS_PAGE_ID[] = "QodeAssist.5ToolsSettingsPageId";
|
const char QODE_ASSIST_TOOLS_SETTINGS_PAGE_ID[] = "QodeAssist.5ToolsSettingsPageId";
|
||||||
const char QODE_ASSIST_CUSTOM_PROMPT_SETTINGS_PAGE_ID[] = "QodeAssist.6CustomPromptSettingsPageId";
|
|
||||||
|
|
||||||
const char QODE_ASSIST_GENERAL_OPTIONS_CATEGORY[] = "QodeAssist.Category";
|
const char QODE_ASSIST_GENERAL_OPTIONS_CATEGORY[] = "QodeAssist.Category";
|
||||||
const char QODE_ASSIST_GENERAL_OPTIONS_DISPLAY_CATEGORY[] = "QodeAssist";
|
const char QODE_ASSIST_GENERAL_OPTIONS_DISPLAY_CATEGORY[] = "QodeAssist";
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ inline const char *ENABLE_CHECK_UPDATE_ON_START
|
|||||||
inline const char *ENABLE_CHAT = QT_TRANSLATE_NOOP(
|
inline const char *ENABLE_CHAT = QT_TRANSLATE_NOOP(
|
||||||
"QtC::QodeAssist",
|
"QtC::QodeAssist",
|
||||||
"Enable Chat(If you have performance issues try disabling this, need restart QtC)");
|
"Enable Chat(If you have performance issues try disabling this, need restart QtC)");
|
||||||
inline const char *ENDPOINT_MODE = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Endpoint Mode:");
|
inline const char *CUSTOM_ENDPOINT = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Custom endpoint:");
|
||||||
|
|
||||||
inline const char *CODE_COMPLETION = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Code Completion");
|
inline const char *CODE_COMPLETION = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Code Completion");
|
||||||
inline const char *CHAT_ASSISTANT = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Chat Assistant");
|
inline const char *CHAT_ASSISTANT = QT_TRANSLATE_NOOP("QtC::QodeAssist", "Chat Assistant");
|
||||||
|
|||||||
1
sources/external/llmcore
vendored
1
sources/external/llmcore
vendored
Submodule sources/external/llmcore deleted from d1fb0dca95
1
sources/external/llmqore
vendored
Submodule
1
sources/external/llmqore
vendored
Submodule
Submodule sources/external/llmqore added at 55a4e293fe
@@ -28,6 +28,7 @@ class CodeLlamaFim : public PluginLLMCore::PromptTemplate
|
|||||||
public:
|
public:
|
||||||
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
||||||
QString name() const override { return "CodeLlama FIM"; }
|
QString name() const override { return "CodeLlama FIM"; }
|
||||||
|
QString endpoint() const override { return QStringLiteral("/api/generate"); }
|
||||||
QStringList stopWords() const override
|
QStringList stopWords() const override
|
||||||
{
|
{
|
||||||
return QStringList() << "<EOT>" << "<PRE>" << "<SUF" << "<MID>";
|
return QStringList() << "<EOT>" << "<PRE>" << "<SUF" << "<MID>";
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class CodeLlamaQMLFim : public PluginLLMCore::PromptTemplate
|
|||||||
public:
|
public:
|
||||||
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
||||||
QString name() const override { return "CodeLlama QML FIM"; }
|
QString name() const override { return "CodeLlama QML FIM"; }
|
||||||
|
QString endpoint() const override { return QStringLiteral("/api/generate"); }
|
||||||
QStringList stopWords() const override
|
QStringList stopWords() const override
|
||||||
{
|
{
|
||||||
return QStringList() << "<SUF>" << "<PRE>" << "</PRE>" << "</SUF>" << "< EOT >" << "\\end"
|
return QStringList() << "<SUF>" << "<PRE>" << "</PRE>" << "</SUF>" << "< EOT >" << "\\end"
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2024 Petr Mironychev
|
|
||||||
*
|
|
||||||
* This file is part of QodeAssist.
|
|
||||||
*
|
|
||||||
* QodeAssist is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* QodeAssist is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "llmcore/PromptTemplate.hpp"
|
|
||||||
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
|
|
||||||
#include "logger/Logger.hpp"
|
|
||||||
#include "settings/CustomPromptSettings.hpp"
|
|
||||||
|
|
||||||
namespace QodeAssist::Templates {
|
|
||||||
|
|
||||||
class CustomTemplate : public LLMCore::PromptTemplate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LLMCore::TemplateType type() const override { return LLMCore::TemplateType::Fim; }
|
|
||||||
QString name() const override { return "Custom FIM Template"; }
|
|
||||||
QString promptTemplate() const override
|
|
||||||
{
|
|
||||||
return Settings::customPromptSettings().customJsonTemplate();
|
|
||||||
}
|
|
||||||
QStringList stopWords() const override { return QStringList(); }
|
|
||||||
void prepareRequest(QJsonObject &request, const LLMCore::ContextData &context) const override
|
|
||||||
{
|
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(promptTemplate().toUtf8());
|
|
||||||
if (doc.isNull() || !doc.isObject()) {
|
|
||||||
LOG_MESSAGE(QString("Invalid JSON template in settings"));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject templateObj = doc.object();
|
|
||||||
QJsonObject processedObj = processJsonTemplate(templateObj, context);
|
|
||||||
|
|
||||||
for (auto it = processedObj.begin(); it != processedObj.end(); ++it) {
|
|
||||||
request[it.key()] = it.value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QString description() const override { return promptTemplate(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
QJsonValue processJsonValue(const QJsonValue &value, const LLMCore::ContextData &context) const
|
|
||||||
{
|
|
||||||
if (value.isString()) {
|
|
||||||
QString str = value.toString();
|
|
||||||
str.replace("{{QODE_PREFIX}}", context.prefix);
|
|
||||||
str.replace("{{QODE_SUFFIX}}", context.suffix);
|
|
||||||
return str;
|
|
||||||
} else if (value.isObject()) {
|
|
||||||
return processJsonTemplate(value.toObject(), context);
|
|
||||||
} else if (value.isArray()) {
|
|
||||||
QJsonArray newArray;
|
|
||||||
for (const QJsonValue &arrayValue : value.toArray()) {
|
|
||||||
newArray.append(processJsonValue(arrayValue, context));
|
|
||||||
}
|
|
||||||
return newArray;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject processJsonTemplate(
|
|
||||||
const QJsonObject &templateObj, const LLMCore::ContextData &context) const
|
|
||||||
{
|
|
||||||
QJsonObject result;
|
|
||||||
for (auto it = templateObj.begin(); it != templateObj.end(); ++it) {
|
|
||||||
result[it.key()] = processJsonValue(it.value(), context);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace QodeAssist::Templates
|
|
||||||
@@ -23,17 +23,17 @@
|
|||||||
|
|
||||||
namespace QodeAssist::Templates {
|
namespace QodeAssist::Templates {
|
||||||
|
|
||||||
class DeepSeekCoderFim : public LLMCore::PromptTemplate
|
class DeepSeekCoderFim : public LLMQore::PromptTemplate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LLMCore::TemplateType type() const override { return LLMCore::TemplateType::Fim; }
|
LLMQore::TemplateType type() const override { return LLMQore::TemplateType::Fim; }
|
||||||
QString name() const override { return "DeepSeekCoder FIM"; }
|
QString name() const override { return "DeepSeekCoder FIM"; }
|
||||||
QString promptTemplate() const override
|
QString promptTemplate() const override
|
||||||
{
|
{
|
||||||
return "<|fim▁begin|>%1<|fim▁hole|>%2<|fim▁end|>";
|
return "<|fim▁begin|>%1<|fim▁hole|>%2<|fim▁end|>";
|
||||||
}
|
}
|
||||||
QStringList stopWords() const override { return QStringList(); }
|
QStringList stopWords() const override { return QStringList(); }
|
||||||
void prepareRequest(QJsonObject &request, const LLMCore::ContextData &context) const override
|
void prepareRequest(QJsonObject &request, const LLMQore::ContextData &context) const override
|
||||||
{
|
{
|
||||||
QString formattedPrompt = promptTemplate().arg(context.prefix, context.suffix);
|
QString formattedPrompt = promptTemplate().arg(context.prefix, context.suffix);
|
||||||
request["prompt"] = formattedPrompt;
|
request["prompt"] = formattedPrompt;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class LlamaCppFim : public PluginLLMCore::PromptTemplate
|
|||||||
public:
|
public:
|
||||||
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
||||||
QString name() const override { return "llama.cpp FIM"; }
|
QString name() const override { return "llama.cpp FIM"; }
|
||||||
|
QString endpoint() const override { return QStringLiteral("/infill"); }
|
||||||
QStringList stopWords() const override { return {}; }
|
QStringList stopWords() const override { return {}; }
|
||||||
|
|
||||||
void prepareRequest(QJsonObject &request, const PluginLLMCore::ContextData &context) const override
|
void prepareRequest(QJsonObject &request, const PluginLLMCore::ContextData &context) const override
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class MistralAIFim : public PluginLLMCore::PromptTemplate
|
|||||||
public:
|
public:
|
||||||
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
||||||
QString name() const override { return "Mistral AI FIM"; }
|
QString name() const override { return "Mistral AI FIM"; }
|
||||||
|
QString endpoint() const override { return QStringLiteral("/v1/fim/completions"); }
|
||||||
QStringList stopWords() const override { return QStringList(); }
|
QStringList stopWords() const override { return QStringList(); }
|
||||||
void prepareRequest(QJsonObject &request, const PluginLLMCore::ContextData &context) const override
|
void prepareRequest(QJsonObject &request, const PluginLLMCore::ContextData &context) const override
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class OllamaFim : public PluginLLMCore::PromptTemplate
|
|||||||
public:
|
public:
|
||||||
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
||||||
QString name() const override { return "Ollama FIM"; }
|
QString name() const override { return "Ollama FIM"; }
|
||||||
|
QString endpoint() const override { return QStringLiteral("/api/generate"); }
|
||||||
QStringList stopWords() const override { return QStringList() << "<EOT>"; }
|
QStringList stopWords() const override { return QStringList() << "<EOT>"; }
|
||||||
void prepareRequest(QJsonObject &request, const PluginLLMCore::ContextData &context) const override
|
void prepareRequest(QJsonObject &request, const PluginLLMCore::ContextData &context) const override
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class Qwen25CoderFIM : public PluginLLMCore::PromptTemplate
|
|||||||
public:
|
public:
|
||||||
QString name() const override { return "Qwen2.5 Coder FIM"; }
|
QString name() const override { return "Qwen2.5 Coder FIM"; }
|
||||||
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
||||||
|
QString endpoint() const override { return QStringLiteral("/api/generate"); }
|
||||||
QStringList stopWords() const override { return QStringList() << "<|endoftext|>" << "<|EOT|>"; }
|
QStringList stopWords() const override { return QStringList() << "<|endoftext|>" << "<|EOT|>"; }
|
||||||
void prepareRequest(QJsonObject &request, const PluginLLMCore::ContextData &context) const override
|
void prepareRequest(QJsonObject &request, const PluginLLMCore::ContextData &context) const override
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class StarCoder2Fim : public PluginLLMCore::PromptTemplate
|
|||||||
public:
|
public:
|
||||||
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
PluginLLMCore::TemplateType type() const override { return PluginLLMCore::TemplateType::FIM; }
|
||||||
QString name() const override { return "StarCoder2 FIM"; }
|
QString name() const override { return "StarCoder2 FIM"; }
|
||||||
|
QString endpoint() const override { return QStringLiteral("/api/generate"); }
|
||||||
QStringList stopWords() const override
|
QStringList stopWords() const override
|
||||||
{
|
{
|
||||||
return QStringList() << "<|endoftext|>" << "<file_sep>" << "<fim_prefix>" << "<fim_suffix>"
|
return QStringList() << "<|endoftext|>" << "<file_sep>" << "<fim_prefix>" << "<fim_suffix>"
|
||||||
|
|||||||
@@ -30,8 +30,6 @@
|
|||||||
#include "templates/OpenAI.hpp"
|
#include "templates/OpenAI.hpp"
|
||||||
#include "templates/OpenAICompatible.hpp"
|
#include "templates/OpenAICompatible.hpp"
|
||||||
#include "templates/OpenAIResponses.hpp"
|
#include "templates/OpenAIResponses.hpp"
|
||||||
// #include "templates/CustomFimTemplate.hpp"
|
|
||||||
// #include "templates/DeepSeekCoderFim.hpp"
|
|
||||||
#include "templates/GoogleAI.hpp"
|
#include "templates/GoogleAI.hpp"
|
||||||
#include "templates/Llama2.hpp"
|
#include "templates/Llama2.hpp"
|
||||||
#include "templates/Llama3.hpp"
|
#include "templates/Llama3.hpp"
|
||||||
@@ -58,8 +56,6 @@ inline void registerTemplates()
|
|||||||
templateManager.registerTemplate<Llama2>();
|
templateManager.registerTemplate<Llama2>();
|
||||||
templateManager.registerTemplate<Llama3>();
|
templateManager.registerTemplate<Llama3>();
|
||||||
templateManager.registerTemplate<StarCoder2Fim>();
|
templateManager.registerTemplate<StarCoder2Fim>();
|
||||||
// templateManager.registerTemplate<DeepSeekCoderFim>();
|
|
||||||
// templateManager.registerTemplate<CustomTemplate>();
|
|
||||||
templateManager.registerTemplate<Qwen25CoderFIM>();
|
templateManager.registerTemplate<Qwen25CoderFIM>();
|
||||||
templateManager.registerTemplate<Qwen3CoderFIM>();
|
templateManager.registerTemplate<Qwen3CoderFIM>();
|
||||||
templateManager.registerTemplate<OpenAICompatible>();
|
templateManager.registerTemplate<OpenAICompatible>();
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ target_link_libraries(QodeAssistTest PRIVATE
|
|||||||
QtCreator::LanguageClient
|
QtCreator::LanguageClient
|
||||||
Context
|
Context
|
||||||
PluginLLMCore
|
PluginLLMCore
|
||||||
LLMCore
|
LLMQore
|
||||||
)
|
)
|
||||||
|
|
||||||
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}")
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ void PrintTo(const ContextData &data, std::ostream *os)
|
|||||||
} // namespace QodeAssist::PluginLLMCore
|
} // namespace QodeAssist::PluginLLMCore
|
||||||
|
|
||||||
using namespace QodeAssist::Context;
|
using namespace QodeAssist::Context;
|
||||||
using namespace QodeAssist::LLMCore;
|
using namespace QodeAssist::PluginLLMCore;
|
||||||
using namespace QodeAssist::Settings;
|
using namespace QodeAssist::Settings;
|
||||||
|
|
||||||
class DocumentContextReaderTest : public QObject, public testing::Test
|
class DocumentContextReaderTest : public QObject, public testing::Test
|
||||||
|
|||||||
@@ -1,209 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 Povilas Kanapickas
|
|
||||||
*
|
|
||||||
* 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 <gmock/gmock.h>
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QSignalSpy>
|
|
||||||
|
|
||||||
#include "LLMClientInterface.hpp"
|
|
||||||
#include "MockDocumentReader.hpp"
|
|
||||||
#include "MockRequestHandler.hpp"
|
|
||||||
#include "llmcore/IPromptProvider.hpp"
|
|
||||||
#include "llmcore/IProviderRegistry.hpp"
|
|
||||||
#include "logger/EmptyRequestPerformanceLogger.hpp"
|
|
||||||
#include "settings/CodeCompletionSettings.hpp"
|
|
||||||
#include "settings/GeneralSettings.hpp"
|
|
||||||
#include "templates/Templates.hpp"
|
|
||||||
#include <coreplugin/editormanager/documentmodel.h>
|
|
||||||
|
|
||||||
using namespace testing;
|
|
||||||
|
|
||||||
namespace QodeAssist {
|
|
||||||
|
|
||||||
class MockPromptProvider : public LLMCore::IPromptProvider
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MOCK_METHOD(LLMCore::PromptTemplate *, getTemplateByName, (const QString &), (const override));
|
|
||||||
MOCK_METHOD(QStringList, templatesNames, (), (const override));
|
|
||||||
MOCK_METHOD(QStringList, getTemplatesForProvider, (LLMCore::ProviderID id), (const override));
|
|
||||||
};
|
|
||||||
|
|
||||||
class MockProviderRegistry : public LLMCore::IProviderRegistry
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MOCK_METHOD(LLMCore::Provider *, getProviderByName, (const QString &), (override));
|
|
||||||
MOCK_METHOD(QStringList, providersNames, (), (const override));
|
|
||||||
};
|
|
||||||
|
|
||||||
class MockProvider : public LLMCore::Provider
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QString name() const override { return "mock_provider"; }
|
|
||||||
QString url() const override { return "https://mock_url"; }
|
|
||||||
QString completionEndpoint() const override { return "/v1/completions"; }
|
|
||||||
QString chatEndpoint() const override { return "/v1/chat/completions"; }
|
|
||||||
void prepareRequest(
|
|
||||||
QJsonObject &request,
|
|
||||||
LLMCore::PromptTemplate *promptTemplate,
|
|
||||||
LLMCore::ContextData context,
|
|
||||||
LLMCore::RequestType requestType,
|
|
||||||
bool isToolsEnabled,
|
|
||||||
bool isThinkingEnabled) override
|
|
||||||
{
|
|
||||||
promptTemplate->prepareRequest(request, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool handleResponse(QNetworkReply *reply, QString &accumulatedResponse) override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QFuture<QList<QString>> getInstalledModels(const QString &) override
|
|
||||||
{
|
|
||||||
return QtFuture::makeReadyFuture(QList<QString>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
LLMCore::ProviderID providerID() const override { return LLMCore::ProviderID::OpenAI; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class LLMClientInterfaceTest : public Test
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
void SetUp() override
|
|
||||||
{
|
|
||||||
Core::DocumentModel::init();
|
|
||||||
|
|
||||||
m_provider = std::make_unique<MockProvider>();
|
|
||||||
m_fimTemplate = std::make_unique<Templates::CodeLlamaQMLFim>();
|
|
||||||
m_chatTemplate = std::make_unique<Templates::Claude>();
|
|
||||||
|
|
||||||
ON_CALL(m_providerRegistry, getProviderByName(_)).WillByDefault(Return(m_provider.get()));
|
|
||||||
ON_CALL(m_promptProvider, getTemplateByName(_)).WillByDefault(Return(m_fimTemplate.get()));
|
|
||||||
|
|
||||||
EXPECT_CALL(m_providerRegistry, getProviderByName(_)).Times(testing::AnyNumber());
|
|
||||||
EXPECT_CALL(m_promptProvider, getTemplateByName(_)).Times(testing::AnyNumber());
|
|
||||||
|
|
||||||
m_generalSettings.ccProvider.setValue("mock_provider");
|
|
||||||
m_generalSettings.ccModel.setValue("mock_model");
|
|
||||||
m_generalSettings.ccTemplate.setValue("mock_template");
|
|
||||||
m_generalSettings.ccUrl.setValue("http://localhost:8000");
|
|
||||||
|
|
||||||
m_completeSettings.systemPromptForNonFimModels.setValue("system prompt non fim");
|
|
||||||
m_completeSettings.systemPrompt.setValue("system prompt");
|
|
||||||
m_completeSettings.userMessageTemplateForCC.setValue(
|
|
||||||
"user message template prefix:\n${prefix}\nsuffix:\n${suffix}\n");
|
|
||||||
|
|
||||||
m_client = std::make_unique<LLMClientInterface>(
|
|
||||||
m_generalSettings,
|
|
||||||
m_completeSettings,
|
|
||||||
m_providerRegistry,
|
|
||||||
&m_promptProvider,
|
|
||||||
m_documentReader,
|
|
||||||
m_performanceLogger);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown() override { Core::DocumentModel::destroy(); }
|
|
||||||
|
|
||||||
QJsonObject createInitializeRequest()
|
|
||||||
{
|
|
||||||
QJsonObject request;
|
|
||||||
request["jsonrpc"] = "2.0";
|
|
||||||
request["id"] = "init-1";
|
|
||||||
request["method"] = "initialize";
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString buildTestFilePath() { return QString(CMAKE_CURRENT_SOURCE_DIR) + "/test_file.py"; }
|
|
||||||
|
|
||||||
QJsonObject createCompletionRequest()
|
|
||||||
{
|
|
||||||
QJsonObject position;
|
|
||||||
position["line"] = 2;
|
|
||||||
position["character"] = 5;
|
|
||||||
|
|
||||||
QJsonObject doc;
|
|
||||||
// change next line to link to test_file.py in current directory of the cmake project
|
|
||||||
doc["uri"] = "file://" + buildTestFilePath();
|
|
||||||
doc["position"] = position;
|
|
||||||
|
|
||||||
QJsonObject params;
|
|
||||||
params["doc"] = doc;
|
|
||||||
|
|
||||||
QJsonObject request;
|
|
||||||
request["jsonrpc"] = "2.0";
|
|
||||||
request["id"] = "completion-1";
|
|
||||||
request["method"] = "getCompletionsCycling";
|
|
||||||
request["params"] = params;
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject createCancelRequest(const QString &idToCancel)
|
|
||||||
{
|
|
||||||
QJsonObject params;
|
|
||||||
params["id"] = idToCancel;
|
|
||||||
|
|
||||||
QJsonObject request;
|
|
||||||
request["jsonrpc"] = "2.0";
|
|
||||||
request["id"] = "cancel-1";
|
|
||||||
request["method"] = "$/cancelRequest";
|
|
||||||
request["params"] = params;
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::GeneralSettings m_generalSettings;
|
|
||||||
Settings::CodeCompletionSettings m_completeSettings;
|
|
||||||
MockProviderRegistry m_providerRegistry;
|
|
||||||
MockPromptProvider m_promptProvider;
|
|
||||||
MockDocumentReader m_documentReader;
|
|
||||||
EmptyRequestPerformanceLogger m_performanceLogger;
|
|
||||||
std::unique_ptr<LLMClientInterface> m_client;
|
|
||||||
std::unique_ptr<MockProvider> m_provider;
|
|
||||||
std::unique_ptr<LLMCore::PromptTemplate> m_fimTemplate;
|
|
||||||
std::unique_ptr<LLMCore::PromptTemplate> m_chatTemplate;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(LLMClientInterfaceTest, initialize)
|
|
||||||
{
|
|
||||||
QSignalSpy spy(m_client.get(), &LanguageClient::BaseClientInterface::messageReceived);
|
|
||||||
|
|
||||||
QJsonObject request = createInitializeRequest();
|
|
||||||
m_client->sendData(QJsonDocument(request).toJson());
|
|
||||||
|
|
||||||
ASSERT_EQ(spy.count(), 1);
|
|
||||||
auto message = spy.takeFirst().at(0).value<LanguageServerProtocol::JsonRpcMessage>();
|
|
||||||
QJsonObject response = message.toJsonObject();
|
|
||||||
|
|
||||||
EXPECT_EQ(response["id"].toString(), "init-1");
|
|
||||||
EXPECT_TRUE(response.contains("result"));
|
|
||||||
EXPECT_TRUE(response["result"].toObject().contains("capabilities"));
|
|
||||||
EXPECT_TRUE(response["result"].toObject().contains("serverInfo"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(LLMClientInterfaceTest, ServerDeviceTemplate)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(m_client->serverDeviceTemplate().toFSPathString(), "QodeAssist");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QodeAssist
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 Povilas Kanapickas <povilas@radix.lt>
|
|
||||||
*
|
|
||||||
* This file is part of QodeAssist.
|
|
||||||
*
|
|
||||||
* QodeAssist is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* QodeAssist is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <llmcore/RequestHandlerBase.hpp>
|
|
||||||
|
|
||||||
namespace QodeAssist::LLMCore {
|
|
||||||
|
|
||||||
class MockRequestHandler : public RequestHandlerBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit MockRequestHandler(QObject *parent = nullptr)
|
|
||||||
: RequestHandlerBase(parent)
|
|
||||||
, m_fakeCompletion("")
|
|
||||||
{}
|
|
||||||
|
|
||||||
void setFakeCompletion(const QString &completion) { m_fakeCompletion = completion; }
|
|
||||||
|
|
||||||
void sendLLMRequest(const LLMConfig &config, const QJsonObject &request) override
|
|
||||||
{
|
|
||||||
m_receivedRequests.append(config);
|
|
||||||
|
|
||||||
emit completionReceived(m_fakeCompletion, request, true);
|
|
||||||
|
|
||||||
QString requestId = request["id"].toString();
|
|
||||||
emit requestFinished(requestId, true, QString());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cancelRequest(const QString &id) override
|
|
||||||
{
|
|
||||||
emit requestCancelled(id);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QVector<LLMConfig> &receivedRequests() const { return m_receivedRequests; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_fakeCompletion;
|
|
||||||
QVector<LLMConfig> m_receivedRequests;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QodeAssist::LLMCore
|
|
||||||
@@ -59,16 +59,16 @@ std::ostream &operator<<(std::ostream &out, const std::optional<T> &value)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace QodeAssist::LLMCore {
|
namespace QodeAssist::PluginLLMCore {
|
||||||
|
|
||||||
inline std::ostream &operator<<(std::ostream &out, const PluginLLMCore::Message &value)
|
inline std::ostream &operator<<(std::ostream &out, const Message &value)
|
||||||
{
|
{
|
||||||
out << "Message{"
|
out << "Message{"
|
||||||
<< "role=" << value.role << "content=" << value.content << "}";
|
<< "role=" << value.role << "content=" << value.content << "}";
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::ostream &operator<<(std::ostream &out, const PluginLLMCore::ContextData &value)
|
inline std::ostream &operator<<(std::ostream &out, const ContextData &value)
|
||||||
{
|
{
|
||||||
out << "ContextData{"
|
out << "ContextData{"
|
||||||
<< "\n systemPrompt=" << value.systemPrompt << "\n prefix=" << value.prefix
|
<< "\n systemPrompt=" << value.systemPrompt << "\n prefix=" << value.prefix
|
||||||
@@ -77,4 +77,4 @@ inline std::ostream &operator<<(std::ostream &out, const PluginLLMCore::ContextD
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QodeAssist::LLMCore
|
} // namespace QodeAssist::PluginLLMCore
|
||||||
|
|||||||
@@ -99,23 +99,23 @@ QJsonObject BuildProjectTool::parametersSchema() const
|
|||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<QString> BuildProjectTool::executeAsync(const QJsonObject &input)
|
QFuture<LLMQore::ToolResult> BuildProjectTool::executeAsync(const QJsonObject &input)
|
||||||
{
|
{
|
||||||
auto *project = ProjectExplorer::ProjectManager::startupProject();
|
auto *project = ProjectExplorer::ProjectManager::startupProject();
|
||||||
if (!project) {
|
if (!project) {
|
||||||
return QtFuture::makeReadyFuture(
|
return QtFuture::makeReadyFuture(
|
||||||
QString("Error: No active project found. Please open a project in Qt Creator."));
|
LLMQore::ToolResult::error("Error: No active project found. Please open a project in Qt Creator."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ProjectExplorer::BuildManager::isBuilding(project)) {
|
if (ProjectExplorer::BuildManager::isBuilding(project)) {
|
||||||
return QtFuture::makeReadyFuture(
|
return QtFuture::makeReadyFuture(
|
||||||
QString("Error: Build is already in progress. Please wait for it to complete."));
|
LLMQore::ToolResult::error("Error: Build is already in progress. Please wait for it to complete."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_activeBuilds.contains(project)) {
|
if (m_activeBuilds.contains(project)) {
|
||||||
return QtFuture::makeReadyFuture(
|
return QtFuture::makeReadyFuture(
|
||||||
QString("Error: Build is already being tracked for project '%1'.")
|
LLMQore::ToolResult::error(QString("Error: Build is already being tracked for project '%1'.")
|
||||||
.arg(project->displayName()));
|
.arg(project->displayName())));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rebuild = input.value("rebuild").toBool(false);
|
bool rebuild = input.value("rebuild").toBool(false);
|
||||||
@@ -126,7 +126,7 @@ QFuture<QString> BuildProjectTool::executeAsync(const QJsonObject &input)
|
|||||||
.arg(project->displayName())
|
.arg(project->displayName())
|
||||||
.arg(runAfterBuild ? QString(" (run after build)") : QString()));
|
.arg(runAfterBuild ? QString(" (run after build)") : QString()));
|
||||||
|
|
||||||
auto promise = QSharedPointer<QPromise<QString>>::create();
|
auto promise = QSharedPointer<QPromise<LLMQore::ToolResult>>::create();
|
||||||
promise->start();
|
promise->start();
|
||||||
|
|
||||||
BuildInfo buildInfo;
|
BuildInfo buildInfo;
|
||||||
@@ -187,7 +187,7 @@ void BuildProjectTool::onBuildQueueFinished(bool success)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (info.promise) {
|
if (info.promise) {
|
||||||
info.promise->addResult(result);
|
info.promise->addResult(LLMQore::ToolResult::text(result));
|
||||||
info.promise->finish();
|
info.promise->finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LLMCore/BaseTool.hpp>
|
#include <LLMQore/BaseTool.hpp>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
@@ -34,7 +34,7 @@ namespace QodeAssist::Tools {
|
|||||||
|
|
||||||
struct BuildInfo
|
struct BuildInfo
|
||||||
{
|
{
|
||||||
QSharedPointer<QPromise<QString>> promise;
|
QSharedPointer<QPromise<LLMQore::ToolResult>> promise;
|
||||||
QPointer<ProjectExplorer::Project> project;
|
QPointer<ProjectExplorer::Project> project;
|
||||||
QString projectName;
|
QString projectName;
|
||||||
bool isRebuild = false;
|
bool isRebuild = false;
|
||||||
@@ -42,7 +42,7 @@ struct BuildInfo
|
|||||||
QMetaObject::Connection buildFinishedConnection;
|
QMetaObject::Connection buildFinishedConnection;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BuildProjectTool : public ::LLMCore::BaseTool
|
class BuildProjectTool : public ::LLMQore::BaseTool
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@@ -54,7 +54,7 @@ public:
|
|||||||
QString description() const override;
|
QString description() const override;
|
||||||
QJsonObject parametersSchema() const override;
|
QJsonObject parametersSchema() const override;
|
||||||
|
|
||||||
QFuture<QString> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
QFuture<LLMQore::ToolResult> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onBuildQueueFinished(bool success);
|
void onBuildQueueFinished(bool success);
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CreateNewFileTool.hpp"
|
#include "CreateNewFileTool.hpp"
|
||||||
#include "ToolExceptions.hpp"
|
|
||||||
|
#include <LLMQore/ToolExceptions.hpp>
|
||||||
|
|
||||||
#include <context/ProjectUtils.hpp>
|
#include <context/ProjectUtils.hpp>
|
||||||
#include <logger/Logger.hpp>
|
#include <logger/Logger.hpp>
|
||||||
@@ -73,24 +74,24 @@ QJsonObject CreateNewFileTool::parametersSchema() const
|
|||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<QString> CreateNewFileTool::executeAsync(const QJsonObject &input)
|
QFuture<LLMQore::ToolResult> CreateNewFileTool::executeAsync(const QJsonObject &input)
|
||||||
{
|
{
|
||||||
return QtConcurrent::run([this, input]() -> QString {
|
return QtConcurrent::run([this, input]() -> LLMQore::ToolResult {
|
||||||
QString filePath = input["filepath"].toString();
|
QString filePath = input["filepath"].toString();
|
||||||
|
|
||||||
if (filePath.isEmpty()) {
|
if (filePath.isEmpty()) {
|
||||||
throw ToolInvalidArgument("Error: 'filepath' parameter is required");
|
throw LLMQore::ToolInvalidArgument("Error: 'filepath' parameter is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
QFileInfo fileInfo(filePath);
|
QFileInfo fileInfo(filePath);
|
||||||
QString absolutePath = fileInfo.absoluteFilePath();
|
QString absolutePath = fileInfo.absoluteFilePath();
|
||||||
|
|
||||||
bool isInProject = Context::ProjectUtils::isFileInProject(absolutePath);
|
bool isInProject = Context::ProjectUtils::isFileInProject(absolutePath);
|
||||||
|
|
||||||
if (!isInProject) {
|
if (!isInProject) {
|
||||||
const auto &settings = Settings::toolsSettings();
|
const auto &settings = Settings::toolsSettings();
|
||||||
if (!settings.allowAccessOutsideProject()) {
|
if (!settings.allowAccessOutsideProject()) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
QString("Error: File path '%1' is not within the current project. "
|
QString("Error: File path '%1' is not within the current project. "
|
||||||
"Enable 'Allow file access outside project' in settings to create files outside project scope.")
|
"Enable 'Allow file access outside project' in settings to create files outside project scope.")
|
||||||
.arg(absolutePath));
|
.arg(absolutePath));
|
||||||
@@ -99,14 +100,14 @@ QFuture<QString> CreateNewFileTool::executeAsync(const QJsonObject &input)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fileInfo.exists()) {
|
if (fileInfo.exists()) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
QString("Error: File already exists at path '%1'").arg(filePath));
|
QString("Error: File already exists at path '%1'").arg(filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
QDir dir = fileInfo.absoluteDir();
|
QDir dir = fileInfo.absoluteDir();
|
||||||
if (!dir.exists()) {
|
if (!dir.exists()) {
|
||||||
if (!dir.mkpath(".")) {
|
if (!dir.mkpath(".")) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
QString("Error: Could not create directory: '%1'").arg(dir.absolutePath()));
|
QString("Error: Could not create directory: '%1'").arg(dir.absolutePath()));
|
||||||
}
|
}
|
||||||
LOG_MESSAGE(QString("Created directory path: %1").arg(dir.absolutePath()));
|
LOG_MESSAGE(QString("Created directory path: %1").arg(dir.absolutePath()));
|
||||||
@@ -114,7 +115,7 @@ QFuture<QString> CreateNewFileTool::executeAsync(const QJsonObject &input)
|
|||||||
|
|
||||||
QFile file(absolutePath);
|
QFile file(absolutePath);
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
QString("Error: Could not create file '%1': %2").arg(absolutePath, file.errorString()));
|
QString("Error: Could not create file '%1': %2").arg(absolutePath, file.errorString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@ QFuture<QString> CreateNewFileTool::executeAsync(const QJsonObject &input)
|
|||||||
|
|
||||||
LOG_MESSAGE(QString("Successfully created new file: %1").arg(absolutePath));
|
LOG_MESSAGE(QString("Successfully created new file: %1").arg(absolutePath));
|
||||||
|
|
||||||
return QString("Successfully created new file: %1").arg(absolutePath);
|
return LLMQore::ToolResult::text(QString("Successfully created new file: %1").arg(absolutePath));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LLMCore/BaseTool.hpp>
|
#include <LLMQore/BaseTool.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
namespace QodeAssist::Tools {
|
||||||
|
|
||||||
class CreateNewFileTool : public ::LLMCore::BaseTool
|
class CreateNewFileTool : public ::LLMQore::BaseTool
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@@ -34,7 +34,7 @@ public:
|
|||||||
QString description() const override;
|
QString description() const override;
|
||||||
QJsonObject parametersSchema() const override;
|
QJsonObject parametersSchema() const override;
|
||||||
|
|
||||||
QFuture<QString> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
QFuture<LLMQore::ToolResult> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Tools
|
} // namespace QodeAssist::Tools
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "EditFileTool.hpp"
|
#include "EditFileTool.hpp"
|
||||||
#include "ToolExceptions.hpp"
|
|
||||||
|
#include <LLMQore/ToolExceptions.hpp>
|
||||||
|
|
||||||
#include <context/ChangesManager.h>
|
#include <context/ChangesManager.h>
|
||||||
#include <context/ProjectUtils.hpp>
|
#include <context/ProjectUtils.hpp>
|
||||||
@@ -107,20 +108,20 @@ QJsonObject EditFileTool::parametersSchema() const
|
|||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<QString> EditFileTool::executeAsync(const QJsonObject &input)
|
QFuture<LLMQore::ToolResult> EditFileTool::executeAsync(const QJsonObject &input)
|
||||||
{
|
{
|
||||||
return QtConcurrent::run([this, input]() -> QString {
|
return QtConcurrent::run([this, input]() -> LLMQore::ToolResult {
|
||||||
QString filename = input["filename"].toString().trimmed();
|
QString filename = input["filename"].toString().trimmed();
|
||||||
QString oldContent = input["old_content"].toString();
|
QString oldContent = input["old_content"].toString();
|
||||||
QString newContent = input["new_content"].toString();
|
QString newContent = input["new_content"].toString();
|
||||||
QString requestId = input["_request_id"].toString();
|
QString requestId = input["_request_id"].toString();
|
||||||
|
|
||||||
if (filename.isEmpty()) {
|
if (filename.isEmpty()) {
|
||||||
throw ToolInvalidArgument("'filename' parameter is required and cannot be empty");
|
throw LLMQore::ToolInvalidArgument("'filename' parameter is required and cannot be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newContent.isEmpty()) {
|
if (newContent.isEmpty()) {
|
||||||
throw ToolInvalidArgument("'new_content' parameter is required and cannot be empty");
|
throw LLMQore::ToolInvalidArgument("'new_content' parameter is required and cannot be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -132,7 +133,7 @@ QFuture<QString> EditFileTool::executeAsync(const QJsonObject &input)
|
|||||||
} else {
|
} else {
|
||||||
QString projectRoot = Context::ProjectUtils::getProjectRoot();
|
QString projectRoot = Context::ProjectUtils::getProjectRoot();
|
||||||
if (projectRoot.isEmpty()) {
|
if (projectRoot.isEmpty()) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
QString("Cannot resolve relative path '%1': no project is open. "
|
QString("Cannot resolve relative path '%1': no project is open. "
|
||||||
"Please provide an absolute path or open a project.")
|
"Please provide an absolute path or open a project.")
|
||||||
.arg(filename));
|
.arg(filename));
|
||||||
@@ -145,12 +146,12 @@ QFuture<QString> EditFileTool::executeAsync(const QJsonObject &input)
|
|||||||
|
|
||||||
QFile file(filePath);
|
QFile file(filePath);
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
throw ToolRuntimeError(QString("File does not exist: %1").arg(filePath));
|
throw LLMQore::ToolRuntimeError(QString("File does not exist: %1").arg(filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
QFileInfo finalFileInfo(filePath);
|
QFileInfo finalFileInfo(filePath);
|
||||||
if (!finalFileInfo.isWritable()) {
|
if (!finalFileInfo.isWritable()) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
QString("File is not writable (read-only or permission denied): %1").arg(filePath));
|
QString("File is not writable (read-only or permission denied): %1").arg(filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +159,7 @@ QFuture<QString> EditFileTool::executeAsync(const QJsonObject &input)
|
|||||||
if (!isInProject) {
|
if (!isInProject) {
|
||||||
const auto &settings = Settings::toolsSettings();
|
const auto &settings = Settings::toolsSettings();
|
||||||
if (!settings.allowAccessOutsideProject()) {
|
if (!settings.allowAccessOutsideProject()) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
QString("File path '%1' is not within the current project. "
|
QString("File path '%1' is not within the current project. "
|
||||||
"Enable 'Allow file access outside project' in settings to edit files outside the project.")
|
"Enable 'Allow file access outside project' in settings to edit files outside the project.")
|
||||||
.arg(filePath));
|
.arg(filePath));
|
||||||
@@ -220,7 +221,7 @@ QFuture<QString> EditFileTool::executeAsync(const QJsonObject &input)
|
|||||||
|
|
||||||
QString resultStr = "QODEASSIST_FILE_EDIT:"
|
QString resultStr = "QODEASSIST_FILE_EDIT:"
|
||||||
+ QString::fromUtf8(QJsonDocument(result).toJson(QJsonDocument::Compact));
|
+ QString::fromUtf8(QJsonDocument(result).toJson(QJsonDocument::Compact));
|
||||||
return resultStr;
|
return LLMQore::ToolResult::text(resultStr);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LLMCore/BaseTool.hpp>
|
#include <LLMQore/BaseTool.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
namespace QodeAssist::Tools {
|
||||||
|
|
||||||
class EditFileTool : public ::LLMCore::BaseTool
|
class EditFileTool : public ::LLMQore::BaseTool
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@@ -34,7 +34,7 @@ public:
|
|||||||
QString description() const override;
|
QString description() const override;
|
||||||
QJsonObject parametersSchema() const override;
|
QJsonObject parametersSchema() const override;
|
||||||
|
|
||||||
QFuture<QString> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
QFuture<LLMQore::ToolResult> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Tools
|
} // namespace QodeAssist::Tools
|
||||||
|
|||||||
@@ -80,30 +80,32 @@ QJsonObject ExecuteTerminalCommandTool::parametersSchema() const
|
|||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<QString> ExecuteTerminalCommandTool::executeAsync(const QJsonObject &input)
|
QFuture<LLMQore::ToolResult> ExecuteTerminalCommandTool::executeAsync(const QJsonObject &input)
|
||||||
{
|
{
|
||||||
|
using LLMQore::ToolResult;
|
||||||
|
|
||||||
const QString command = input.value("command").toString().trimmed();
|
const QString command = input.value("command").toString().trimmed();
|
||||||
const QString args = input.value("args").toString().trimmed();
|
const QString args = input.value("args").toString().trimmed();
|
||||||
|
|
||||||
if (command.isEmpty()) {
|
if (command.isEmpty()) {
|
||||||
LOG_MESSAGE("ExecuteTerminalCommandTool: Command is empty");
|
LOG_MESSAGE("ExecuteTerminalCommandTool: Command is empty");
|
||||||
return QtFuture::makeReadyFuture(QString("Error: Command parameter is required."));
|
return QtFuture::makeReadyFuture(ToolResult::error("Error: Command parameter is required."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.length() > MAX_COMMAND_LENGTH) {
|
if (command.length() > MAX_COMMAND_LENGTH) {
|
||||||
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Command too long (%1 chars)")
|
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Command too long (%1 chars)")
|
||||||
.arg(command.length()));
|
.arg(command.length()));
|
||||||
return QtFuture::makeReadyFuture(
|
return QtFuture::makeReadyFuture(
|
||||||
QString("Error: Command exceeds maximum length of %1 characters.")
|
ToolResult::error(QString("Error: Command exceeds maximum length of %1 characters.")
|
||||||
.arg(MAX_COMMAND_LENGTH));
|
.arg(MAX_COMMAND_LENGTH)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length() > MAX_ARGS_LENGTH) {
|
if (args.length() > MAX_ARGS_LENGTH) {
|
||||||
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Arguments too long (%1 chars)")
|
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Arguments too long (%1 chars)")
|
||||||
.arg(args.length()));
|
.arg(args.length()));
|
||||||
return QtFuture::makeReadyFuture(
|
return QtFuture::makeReadyFuture(
|
||||||
QString("Error: Arguments exceed maximum length of %1 characters.")
|
ToolResult::error(QString("Error: Arguments exceed maximum length of %1 characters.")
|
||||||
.arg(MAX_ARGS_LENGTH));
|
.arg(MAX_ARGS_LENGTH)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isCommandAllowed(command)) {
|
if (!isCommandAllowed(command)) {
|
||||||
@@ -112,9 +114,9 @@ QFuture<QString> ExecuteTerminalCommandTool::executeAsync(const QJsonObject &inp
|
|||||||
const QStringList allowed = getAllowedCommands();
|
const QStringList allowed = getAllowedCommands();
|
||||||
const QString allowedList = allowed.isEmpty() ? "none" : allowed.join(", ");
|
const QString allowedList = allowed.isEmpty() ? "none" : allowed.join(", ");
|
||||||
return QtFuture::makeReadyFuture(
|
return QtFuture::makeReadyFuture(
|
||||||
QString("Error: Command '%1' is not in the allowed list. Allowed commands: %2")
|
ToolResult::error(QString("Error: Command '%1' is not in the allowed list. Allowed commands: %2")
|
||||||
.arg(command)
|
.arg(command)
|
||||||
.arg(allowedList));
|
.arg(allowedList)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isCommandSafe(command)) {
|
if (!isCommandSafe(command)) {
|
||||||
@@ -127,18 +129,18 @@ QFuture<QString> ExecuteTerminalCommandTool::executeAsync(const QJsonObject &inp
|
|||||||
const QString allowedChars = "alphanumeric characters, hyphens, underscores, dots, and slashes";
|
const QString allowedChars = "alphanumeric characters, hyphens, underscores, dots, and slashes";
|
||||||
#endif
|
#endif
|
||||||
return QtFuture::makeReadyFuture(
|
return QtFuture::makeReadyFuture(
|
||||||
QString("Error: Command '%1' contains potentially dangerous characters. "
|
ToolResult::error(QString("Error: Command '%1' contains potentially dangerous characters. "
|
||||||
"Only %2 are allowed.")
|
"Only %2 are allowed.")
|
||||||
.arg(command)
|
.arg(command)
|
||||||
.arg(allowedChars));
|
.arg(allowedChars)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args.isEmpty() && !areArgumentsSafe(args)) {
|
if (!args.isEmpty() && !areArgumentsSafe(args)) {
|
||||||
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Arguments contain unsafe patterns: '%1'")
|
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Arguments contain unsafe patterns: '%1'")
|
||||||
.arg(args));
|
.arg(args));
|
||||||
return QtFuture::makeReadyFuture(
|
return QtFuture::makeReadyFuture(
|
||||||
QString("Error: Arguments contain potentially dangerous patterns (command chaining, "
|
ToolResult::error(QString("Error: Arguments contain potentially dangerous patterns (command chaining, "
|
||||||
"redirection, or pipe operators)."));
|
"redirection, or pipe operators).")));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *project = ProjectExplorer::ProjectManager::startupProject();
|
auto *project = ProjectExplorer::ProjectManager::startupProject();
|
||||||
@@ -159,8 +161,8 @@ QFuture<QString> ExecuteTerminalCommandTool::executeAsync(const QJsonObject &inp
|
|||||||
QString("ExecuteTerminalCommandTool: Working directory '%1' is not accessible")
|
QString("ExecuteTerminalCommandTool: Working directory '%1' is not accessible")
|
||||||
.arg(workingDir));
|
.arg(workingDir));
|
||||||
return QtFuture::makeReadyFuture(
|
return QtFuture::makeReadyFuture(
|
||||||
QString("Error: Working directory '%1' does not exist or is not accessible.")
|
ToolResult::error(QString("Error: Working directory '%1' does not exist or is not accessible.")
|
||||||
.arg(workingDir));
|
.arg(workingDir)));
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Executing command '%1' with args '%2' in '%3'")
|
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Executing command '%1' with args '%2' in '%3'")
|
||||||
@@ -168,8 +170,8 @@ QFuture<QString> ExecuteTerminalCommandTool::executeAsync(const QJsonObject &inp
|
|||||||
.arg(args.isEmpty() ? "(no args)" : args)
|
.arg(args.isEmpty() ? "(no args)" : args)
|
||||||
.arg(workingDir));
|
.arg(workingDir));
|
||||||
|
|
||||||
auto promise = QSharedPointer<QPromise<QString>>::create();
|
auto promise = QSharedPointer<QPromise<ToolResult>>::create();
|
||||||
QFuture<QString> future = promise->future();
|
QFuture<ToolResult> future = promise->future();
|
||||||
promise->start();
|
promise->start();
|
||||||
|
|
||||||
auto resolved = std::make_shared<std::atomic<bool>>(false);
|
auto resolved = std::make_shared<std::atomic<bool>>(false);
|
||||||
@@ -206,11 +208,11 @@ QFuture<QString> ExecuteTerminalCommandTool::executeAsync(const QJsonObject &inp
|
|||||||
process->deleteLater();
|
process->deleteLater();
|
||||||
});
|
});
|
||||||
|
|
||||||
promise->addResult(QString("Error: Command '%1 %2' timed out after %3 seconds. "
|
promise->addResult(ToolResult::error(QString("Error: Command '%1 %2' timed out after %3 seconds. "
|
||||||
"The process has been terminated.")
|
"The process has been terminated.")
|
||||||
.arg(command)
|
.arg(command)
|
||||||
.arg(args.isEmpty() ? "" : args)
|
.arg(args.isEmpty() ? "" : args)
|
||||||
.arg(timeoutMs / 1000));
|
.arg(timeoutMs / 1000)));
|
||||||
promise->finish();
|
promise->finish();
|
||||||
timeoutTimer->deleteLater();
|
timeoutTimer->deleteLater();
|
||||||
});
|
});
|
||||||
@@ -241,21 +243,21 @@ QFuture<QString> ExecuteTerminalCommandTool::executeAsync(const QJsonObject &inp
|
|||||||
"successfully (output size: %2 bytes)")
|
"successfully (output size: %2 bytes)")
|
||||||
.arg(fullCommand)
|
.arg(fullCommand)
|
||||||
.arg(outputSize));
|
.arg(outputSize));
|
||||||
promise->addResult(
|
promise->addResult(ToolResult::text(
|
||||||
QString("Command '%1' executed successfully.\n\nOutput:\n%2")
|
QString("Command '%1' executed successfully.\n\nOutput:\n%2")
|
||||||
.arg(fullCommand)
|
.arg(fullCommand)
|
||||||
.arg(output.isEmpty() ? "(no output)" : output));
|
.arg(output.isEmpty() ? "(no output)" : output)));
|
||||||
} else {
|
} else {
|
||||||
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Command '%1' failed with "
|
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Command '%1' failed with "
|
||||||
"exit code %2 (output size: %3 bytes)")
|
"exit code %2 (output size: %3 bytes)")
|
||||||
.arg(fullCommand)
|
.arg(fullCommand)
|
||||||
.arg(exitCode)
|
.arg(exitCode)
|
||||||
.arg(outputSize));
|
.arg(outputSize));
|
||||||
promise->addResult(
|
promise->addResult(ToolResult::error(
|
||||||
QString("Command '%1' failed with exit code %2.\n\nOutput:\n%3")
|
QString("Command '%1' failed with exit code %2.\n\nOutput:\n%3")
|
||||||
.arg(fullCommand)
|
.arg(fullCommand)
|
||||||
.arg(exitCode)
|
.arg(exitCode)
|
||||||
.arg(output.isEmpty() ? "(no output)" : output));
|
.arg(output.isEmpty() ? "(no output)" : output)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Command '%1' crashed or was "
|
LOG_MESSAGE(QString("ExecuteTerminalCommandTool: Command '%1' crashed or was "
|
||||||
@@ -263,11 +265,11 @@ QFuture<QString> ExecuteTerminalCommandTool::executeAsync(const QJsonObject &inp
|
|||||||
.arg(fullCommand)
|
.arg(fullCommand)
|
||||||
.arg(outputSize));
|
.arg(outputSize));
|
||||||
const QString error = process->errorString();
|
const QString error = process->errorString();
|
||||||
promise->addResult(
|
promise->addResult(ToolResult::error(
|
||||||
QString("Command '%1' crashed or was terminated.\n\nError: %2\n\nOutput:\n%3")
|
QString("Command '%1' crashed or was terminated.\n\nError: %2\n\nOutput:\n%3")
|
||||||
.arg(fullCommand)
|
.arg(fullCommand)
|
||||||
.arg(error)
|
.arg(error)
|
||||||
.arg(output.isEmpty() ? "(no output)" : output));
|
.arg(output.isEmpty() ? "(no output)" : output)));
|
||||||
}
|
}
|
||||||
|
|
||||||
promise->finish();
|
promise->finish();
|
||||||
@@ -317,7 +319,7 @@ QFuture<QString> ExecuteTerminalCommandTool::executeAsync(const QJsonObject &inp
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
promise->addResult(QString("Error: %1").arg(errorMessage));
|
promise->addResult(ToolResult::error(QString("Error: %1").arg(errorMessage)));
|
||||||
promise->finish();
|
promise->finish();
|
||||||
process->deleteLater();
|
process->deleteLater();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,12 +19,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LLMCore/BaseTool.hpp>
|
#include <LLMQore/BaseTool.hpp>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
namespace QodeAssist::Tools {
|
||||||
|
|
||||||
class ExecuteTerminalCommandTool : public ::LLMCore::BaseTool
|
class ExecuteTerminalCommandTool : public ::LLMQore::BaseTool
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@@ -35,7 +35,7 @@ public:
|
|||||||
QString description() const override;
|
QString description() const override;
|
||||||
QJsonObject parametersSchema() const override;
|
QJsonObject parametersSchema() const override;
|
||||||
|
|
||||||
QFuture<QString> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
QFuture<LLMQore::ToolResult> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isCommandAllowed(const QString &command) const;
|
bool isCommandAllowed(const QString &command) const;
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FindAndReadFileTool.hpp"
|
#include "FindAndReadFileTool.hpp"
|
||||||
#include "ToolExceptions.hpp"
|
|
||||||
|
#include <LLMQore/ToolExceptions.hpp>
|
||||||
|
|
||||||
#include <logger/Logger.hpp>
|
#include <logger/Logger.hpp>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
@@ -71,12 +72,12 @@ QJsonObject FindAndReadFileTool::parametersSchema() const
|
|||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<QString> FindAndReadFileTool::executeAsync(const QJsonObject &input)
|
QFuture<LLMQore::ToolResult> FindAndReadFileTool::executeAsync(const QJsonObject &input)
|
||||||
{
|
{
|
||||||
return QtConcurrent::run([this, input]() -> QString {
|
return QtConcurrent::run([this, input]() -> LLMQore::ToolResult {
|
||||||
QString query = input["query"].toString().trimmed();
|
QString query = input["query"].toString().trimmed();
|
||||||
if (query.isEmpty()) {
|
if (query.isEmpty()) {
|
||||||
throw ToolInvalidArgument("Query parameter is required");
|
throw LLMQore::ToolInvalidArgument("Query parameter is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString filePattern = input["file_pattern"].toString();
|
QString filePattern = input["file_pattern"].toString();
|
||||||
@@ -90,7 +91,7 @@ QFuture<QString> FindAndReadFileTool::executeAsync(const QJsonObject &input)
|
|||||||
query, filePattern, 10, m_ignoreManager);
|
query, filePattern, 10, m_ignoreManager);
|
||||||
|
|
||||||
if (bestMatch.absolutePath.isEmpty()) {
|
if (bestMatch.absolutePath.isEmpty()) {
|
||||||
return QString("No file found matching '%1'").arg(query);
|
return LLMQore::ToolResult::text(QString("No file found matching '%1'").arg(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readContent) {
|
if (readContent) {
|
||||||
@@ -100,7 +101,7 @@ QFuture<QString> FindAndReadFileTool::executeAsync(const QJsonObject &input)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatResult(bestMatch, readContent);
|
return LLMQore::ToolResult::text(formatResult(bestMatch, readContent));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,14 +22,14 @@
|
|||||||
#include "FileSearchUtils.hpp"
|
#include "FileSearchUtils.hpp"
|
||||||
|
|
||||||
#include <context/IgnoreManager.hpp>
|
#include <context/IgnoreManager.hpp>
|
||||||
#include <LLMCore/BaseTool.hpp>
|
#include <LLMQore/BaseTool.hpp>
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
namespace QodeAssist::Tools {
|
||||||
|
|
||||||
class FindAndReadFileTool : public ::LLMCore::BaseTool
|
class FindAndReadFileTool : public ::LLMQore::BaseTool
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ public:
|
|||||||
QString displayName() const override;
|
QString displayName() const override;
|
||||||
QString description() const override;
|
QString description() const override;
|
||||||
QJsonObject parametersSchema() const override;
|
QJsonObject parametersSchema() const override;
|
||||||
QFuture<QString> executeAsync(const QJsonObject &input) override;
|
QFuture<LLMQore::ToolResult> executeAsync(const QJsonObject &input) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString formatResult(const FileSearchUtils::FileMatch &match, bool readContent) const;
|
QString formatResult(const FileSearchUtils::FileMatch &match, bool readContent) const;
|
||||||
|
|||||||
@@ -155,16 +155,16 @@ QJsonObject GetIssuesListTool::parametersSchema() const
|
|||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<QString> GetIssuesListTool::executeAsync(const QJsonObject &input)
|
QFuture<LLMQore::ToolResult> GetIssuesListTool::executeAsync(const QJsonObject &input)
|
||||||
{
|
{
|
||||||
return QtConcurrent::run([input]() -> QString {
|
return QtConcurrent::run([input]() -> LLMQore::ToolResult {
|
||||||
|
|
||||||
QString severityFilter = input.value("severity").toString("all");
|
QString severityFilter = input.value("severity").toString("all");
|
||||||
|
|
||||||
const auto tasks = IssuesTracker::instance().getTasks();
|
const auto tasks = IssuesTracker::instance().getTasks();
|
||||||
|
|
||||||
if (tasks.isEmpty()) {
|
if (tasks.isEmpty()) {
|
||||||
return "No issues found in Qt Creator Issues panel.";
|
return LLMQore::ToolResult::text("No issues found in Qt Creator Issues panel.");
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList results;
|
QStringList results;
|
||||||
@@ -235,7 +235,7 @@ QFuture<QString> GetIssuesListTool::executeAsync(const QJsonObject &input)
|
|||||||
.arg(processedCount);
|
.arg(processedCount);
|
||||||
results.prepend(summary);
|
results.prepend(summary);
|
||||||
|
|
||||||
return results.join("\n\n");
|
return LLMQore::ToolResult::text(results.join("\n\n"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LLMCore/BaseTool.hpp>
|
#include <LLMQore/BaseTool.hpp>
|
||||||
#include <projectexplorer/task.h>
|
#include <projectexplorer/task.h>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
@@ -46,7 +46,7 @@ private:
|
|||||||
mutable QMutex m_mutex;
|
mutable QMutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GetIssuesListTool : public ::LLMCore::BaseTool
|
class GetIssuesListTool : public ::LLMQore::BaseTool
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@@ -57,7 +57,7 @@ public:
|
|||||||
QString description() const override;
|
QString description() const override;
|
||||||
QJsonObject parametersSchema() const override;
|
QJsonObject parametersSchema() const override;
|
||||||
|
|
||||||
QFuture<QString> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
QFuture<LLMQore::ToolResult> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QodeAssist::Tools
|
} // namespace QodeAssist::Tools
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ListProjectFilesTool.hpp"
|
#include "ListProjectFilesTool.hpp"
|
||||||
#include "ToolExceptions.hpp"
|
|
||||||
|
#include <LLMQore/ToolExceptions.hpp>
|
||||||
|
|
||||||
#include <logger/Logger.hpp>
|
#include <logger/Logger.hpp>
|
||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
@@ -63,15 +64,15 @@ QJsonObject ListProjectFilesTool::parametersSchema() const
|
|||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<QString> ListProjectFilesTool::executeAsync(const QJsonObject &input)
|
QFuture<LLMQore::ToolResult> ListProjectFilesTool::executeAsync(const QJsonObject &input)
|
||||||
{
|
{
|
||||||
Q_UNUSED(input)
|
Q_UNUSED(input)
|
||||||
|
|
||||||
return QtConcurrent::run([this]() -> QString {
|
return QtConcurrent::run([this]() -> LLMQore::ToolResult {
|
||||||
QList<ProjectExplorer::Project *> projects = ProjectExplorer::ProjectManager::projects();
|
QList<ProjectExplorer::Project *> projects = ProjectExplorer::ProjectManager::projects();
|
||||||
if (projects.isEmpty()) {
|
if (projects.isEmpty()) {
|
||||||
QString error = "No projects found";
|
QString error = "No projects found";
|
||||||
throw ToolRuntimeError(error);
|
throw LLMQore::ToolRuntimeError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString result;
|
QString result;
|
||||||
@@ -123,7 +124,7 @@ QFuture<QString> ListProjectFilesTool::executeAsync(const QJsonObject &input)
|
|||||||
result += "\n";
|
result += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.trimmed();
|
return LLMQore::ToolResult::text(result.trimmed());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,13 +19,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LLMCore/BaseTool.hpp>
|
#include <LLMQore/BaseTool.hpp>
|
||||||
|
|
||||||
#include <context/IgnoreManager.hpp>
|
#include <context/IgnoreManager.hpp>
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
namespace QodeAssist::Tools {
|
||||||
|
|
||||||
class ListProjectFilesTool : public ::LLMCore::BaseTool
|
class ListProjectFilesTool : public ::LLMQore::BaseTool
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@@ -36,7 +36,7 @@ public:
|
|||||||
QString description() const override;
|
QString description() const override;
|
||||||
QJsonObject parametersSchema() const override;
|
QJsonObject parametersSchema() const override;
|
||||||
|
|
||||||
QFuture<QString> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
QFuture<LLMQore::ToolResult> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString formatFileList(const QStringList &files) const;
|
QString formatFileList(const QStringList &files) const;
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ProjectSearchTool.hpp"
|
#include "ProjectSearchTool.hpp"
|
||||||
#include "ToolExceptions.hpp"
|
|
||||||
|
#include <LLMQore/ToolExceptions.hpp>
|
||||||
|
|
||||||
#include <cplusplus/Overview.h>
|
#include <cplusplus/Overview.h>
|
||||||
#include <cplusplus/Scope.h>
|
#include <cplusplus/Scope.h>
|
||||||
@@ -97,17 +98,17 @@ QJsonObject ProjectSearchTool::parametersSchema() const
|
|||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<QString> ProjectSearchTool::executeAsync(const QJsonObject &input)
|
QFuture<LLMQore::ToolResult> ProjectSearchTool::executeAsync(const QJsonObject &input)
|
||||||
{
|
{
|
||||||
return QtConcurrent::run([this, input]() -> QString {
|
return QtConcurrent::run([this, input]() -> LLMQore::ToolResult {
|
||||||
QString query = input["query"].toString().trimmed();
|
QString query = input["query"].toString().trimmed();
|
||||||
if (query.isEmpty()) {
|
if (query.isEmpty()) {
|
||||||
throw ToolInvalidArgument("Query parameter is required");
|
throw LLMQore::ToolInvalidArgument("Query parameter is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString searchTypeStr = input["search_type"].toString();
|
QString searchTypeStr = input["search_type"].toString();
|
||||||
if (searchTypeStr != "text" && searchTypeStr != "symbol") {
|
if (searchTypeStr != "text" && searchTypeStr != "symbol") {
|
||||||
throw ToolInvalidArgument("search_type must be 'text' or 'symbol'");
|
throw LLMQore::ToolInvalidArgument("search_type must be 'text' or 'symbol'");
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchType searchType = (searchTypeStr == "symbol") ? SearchType::Symbol : SearchType::Text;
|
SearchType searchType = (searchTypeStr == "symbol") ? SearchType::Symbol : SearchType::Text;
|
||||||
@@ -129,10 +130,10 @@ QFuture<QString> ProjectSearchTool::executeAsync(const QJsonObject &input)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (results.isEmpty()) {
|
if (results.isEmpty()) {
|
||||||
return QString("No matches found for '%1'").arg(query);
|
return LLMQore::ToolResult::text(QString("No matches found for '%1'").arg(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatResults(results, query);
|
return LLMQore::ToolResult::text(formatResults(results, query));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,14 +20,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <context/IgnoreManager.hpp>
|
#include <context/IgnoreManager.hpp>
|
||||||
#include <LLMCore/BaseTool.hpp>
|
#include <LLMQore/BaseTool.hpp>
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
namespace QodeAssist::Tools {
|
||||||
|
|
||||||
class ProjectSearchTool : public ::LLMCore::BaseTool
|
class ProjectSearchTool : public ::LLMQore::BaseTool
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ public:
|
|||||||
QString displayName() const override;
|
QString displayName() const override;
|
||||||
QString description() const override;
|
QString description() const override;
|
||||||
QJsonObject parametersSchema() const override;
|
QJsonObject parametersSchema() const override;
|
||||||
QFuture<QString> executeAsync(const QJsonObject &input) override;
|
QFuture<LLMQore::ToolResult> executeAsync(const QJsonObject &input) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class SearchType { Text, Symbol };
|
enum class SearchType { Text, Symbol };
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "TodoTool.hpp"
|
#include "TodoTool.hpp"
|
||||||
#include "ToolExceptions.hpp"
|
|
||||||
|
#include <LLMQore/ToolExceptions.hpp>
|
||||||
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
@@ -100,9 +101,9 @@ QJsonObject TodoTool::parametersSchema() const
|
|||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<QString> TodoTool::executeAsync(const QJsonObject &input)
|
QFuture<LLMQore::ToolResult> TodoTool::executeAsync(const QJsonObject &input)
|
||||||
{
|
{
|
||||||
return QtConcurrent::run([this, input]() -> QString {
|
return QtConcurrent::run([this, input]() -> LLMQore::ToolResult {
|
||||||
QMutexLocker sessionLocker(&m_mutex);
|
QMutexLocker sessionLocker(&m_mutex);
|
||||||
QString sessionId = m_currentSessionId.isEmpty() ? "current" : m_currentSessionId;
|
QString sessionId = m_currentSessionId.isEmpty() ? "current" : m_currentSessionId;
|
||||||
sessionLocker.unlock();
|
sessionLocker.unlock();
|
||||||
@@ -111,14 +112,14 @@ QFuture<QString> TodoTool::executeAsync(const QJsonObject &input)
|
|||||||
|
|
||||||
if (operation == "add") {
|
if (operation == "add") {
|
||||||
if (!input.contains("tasks") || !input.value("tasks").isArray()) {
|
if (!input.contains("tasks") || !input.value("tasks").isArray()) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
tr("Error: 'tasks' parameter (array) is required for 'add' operation. "
|
tr("Error: 'tasks' parameter (array) is required for 'add' operation. "
|
||||||
"Example: {\"operation\": \"add\", \"tasks\": [\"Task 1\", \"Task 2\"]}"));
|
"Example: {\"operation\": \"add\", \"tasks\": [\"Task 1\", \"Task 2\"]}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const QJsonArray tasksArray = input.value("tasks").toArray();
|
const QJsonArray tasksArray = input.value("tasks").toArray();
|
||||||
if (tasksArray.isEmpty()) {
|
if (tasksArray.isEmpty()) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
tr("Error: 'tasks' array cannot be empty. Provide at least one task."));
|
tr("Error: 'tasks' array cannot be empty. Provide at least one task."));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,22 +132,22 @@ QFuture<QString> TodoTool::executeAsync(const QJsonObject &input)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tasks.isEmpty()) {
|
if (tasks.isEmpty()) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
tr("Error: All tasks in 'tasks' array are empty strings."));
|
tr("Error: All tasks in 'tasks' array are empty strings."));
|
||||||
}
|
}
|
||||||
|
|
||||||
return addTodos(sessionId, tasks);
|
return LLMQore::ToolResult::text(addTodos(sessionId, tasks));
|
||||||
|
|
||||||
} else if (operation == "complete") {
|
} else if (operation == "complete") {
|
||||||
if (!input.contains("todo_ids") || !input.value("todo_ids").isArray()) {
|
if (!input.contains("todo_ids") || !input.value("todo_ids").isArray()) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
tr("Error: 'todo_ids' parameter (array) is required for 'complete' operation. "
|
tr("Error: 'todo_ids' parameter (array) is required for 'complete' operation. "
|
||||||
"Example: {\"operation\": \"complete\", \"todo_ids\": [1, 2, 3]}"));
|
"Example: {\"operation\": \"complete\", \"todo_ids\": [1, 2, 3]}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const QJsonArray idsArray = input.value("todo_ids").toArray();
|
const QJsonArray idsArray = input.value("todo_ids").toArray();
|
||||||
if (idsArray.isEmpty()) {
|
if (idsArray.isEmpty()) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
tr("Error: 'todo_ids' array cannot be empty. Provide at least one ID."));
|
tr("Error: 'todo_ids' array cannot be empty. Provide at least one ID."));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,18 +160,18 @@ QFuture<QString> TodoTool::executeAsync(const QJsonObject &input)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ids.isEmpty()) {
|
if (ids.isEmpty()) {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
tr("Error: All IDs in 'todo_ids' array are invalid. IDs must be positive "
|
tr("Error: All IDs in 'todo_ids' array are invalid. IDs must be positive "
|
||||||
"integers."));
|
"integers."));
|
||||||
}
|
}
|
||||||
|
|
||||||
return completeTodos(sessionId, ids);
|
return LLMQore::ToolResult::text(completeTodos(sessionId, ids));
|
||||||
|
|
||||||
} else if (operation == "list") {
|
} else if (operation == "list") {
|
||||||
return listTodos(sessionId);
|
return LLMQore::ToolResult::text(listTodos(sessionId));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw ToolRuntimeError(
|
throw LLMQore::ToolRuntimeError(
|
||||||
tr("Error: Unknown operation '%1'. Valid operations: 'add', 'complete', 'list'")
|
tr("Error: Unknown operation '%1'. Valid operations: 'add', 'complete', 'list'")
|
||||||
.arg(operation));
|
.arg(operation));
|
||||||
}
|
}
|
||||||
@@ -215,7 +216,7 @@ QString TodoTool::completeTodos(const QString &sessionId, const QList<int> &todo
|
|||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
|
|
||||||
if (!m_sessionTodos.contains(sessionId)) {
|
if (!m_sessionTodos.contains(sessionId)) {
|
||||||
throw ToolRuntimeError(tr("Error: No todos found in this session"));
|
throw LLMQore::ToolRuntimeError(tr("Error: No todos found in this session"));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &todos = m_sessionTodos[sessionId];
|
auto &todos = m_sessionTodos[sessionId];
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <LLMCore/BaseTool.hpp>
|
#include <LLMQore/BaseTool.hpp>
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
@@ -34,7 +34,7 @@ struct TodoItem
|
|||||||
bool completed;
|
bool completed;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TodoTool : public ::LLMCore::BaseTool
|
class TodoTool : public ::LLMQore::BaseTool
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ public:
|
|||||||
QString description() const override;
|
QString description() const override;
|
||||||
QJsonObject parametersSchema() const override;
|
QJsonObject parametersSchema() const override;
|
||||||
|
|
||||||
QFuture<QString> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
QFuture<LLMQore::ToolResult> executeAsync(const QJsonObject &input = QJsonObject()) override;
|
||||||
|
|
||||||
void setCurrentSessionId(const QString &sessionId);
|
void setCurrentSessionId(const QString &sessionId);
|
||||||
void clearSession(const QString &sessionId);
|
void clearSession(const QString &sessionId);
|
||||||
|
|||||||
@@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 Petr Mironychev
|
|
||||||
*
|
|
||||||
* This file is part of QodeAssist.
|
|
||||||
*
|
|
||||||
* QodeAssist is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* QodeAssist is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ToolHandler.hpp"
|
|
||||||
#include "ToolExceptions.hpp"
|
|
||||||
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QtConcurrent>
|
|
||||||
|
|
||||||
#include "logger/Logger.hpp"
|
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
|
||||||
|
|
||||||
ToolHandler::ToolHandler(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{}
|
|
||||||
|
|
||||||
QFuture<QString> ToolHandler::executeToolAsync(
|
|
||||||
const QString &requestId,
|
|
||||||
const QString &toolId,
|
|
||||||
PluginLLMCore::BaseTool *tool,
|
|
||||||
const QJsonObject &input)
|
|
||||||
{
|
|
||||||
if (!tool) {
|
|
||||||
return QtConcurrent::run([]() -> QString { throw std::runtime_error("Tool is null"); });
|
|
||||||
}
|
|
||||||
|
|
||||||
auto execution = std::make_unique<ToolExecution>();
|
|
||||||
execution->requestId = requestId;
|
|
||||||
execution->toolId = toolId;
|
|
||||||
execution->toolName = tool->name();
|
|
||||||
execution->watcher = new QFutureWatcher<QString>(this);
|
|
||||||
|
|
||||||
connect(execution->watcher, &QFutureWatcher<QString>::finished, this, [this, toolId]() {
|
|
||||||
onToolExecutionFinished(toolId);
|
|
||||||
});
|
|
||||||
|
|
||||||
LOG_MESSAGE(QString("Starting tool execution: %1 (ID: %2)").arg(tool->name(), toolId));
|
|
||||||
|
|
||||||
auto future = tool->executeAsync(input);
|
|
||||||
execution->watcher->setFuture(future);
|
|
||||||
m_activeExecutions.insert(toolId, execution.release());
|
|
||||||
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolHandler::cleanupRequest(const QString &requestId)
|
|
||||||
{
|
|
||||||
auto it = m_activeExecutions.begin();
|
|
||||||
while (it != m_activeExecutions.end()) {
|
|
||||||
if (it.value()->requestId == requestId) {
|
|
||||||
auto execution = it.value();
|
|
||||||
LOG_MESSAGE(
|
|
||||||
QString("Canceling tool %1 for request %2").arg(execution->toolName, requestId));
|
|
||||||
|
|
||||||
if (execution->watcher) {
|
|
||||||
execution->watcher->cancel();
|
|
||||||
execution->watcher->deleteLater();
|
|
||||||
}
|
|
||||||
delete execution;
|
|
||||||
it = m_activeExecutions.erase(it);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolHandler::onToolExecutionFinished(const QString &toolId)
|
|
||||||
{
|
|
||||||
if (!m_activeExecutions.contains(toolId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto execution = m_activeExecutions.take(toolId);
|
|
||||||
|
|
||||||
try {
|
|
||||||
QString result = execution->watcher->result();
|
|
||||||
LOG_MESSAGE(QString("Tool %1 completed").arg(execution->toolName));
|
|
||||||
emit toolCompleted(execution->requestId, execution->toolId, result);
|
|
||||||
} catch (const ToolException &e) {
|
|
||||||
QString error = e.message();
|
|
||||||
if (error.isEmpty()) {
|
|
||||||
error = "Tool execution failed with empty error message";
|
|
||||||
}
|
|
||||||
LOG_MESSAGE(QString("Tool %1 failed: %2").arg(execution->toolName, error));
|
|
||||||
emit toolFailed(execution->requestId, execution->toolId, error);
|
|
||||||
} catch (const QException &e) {
|
|
||||||
QString error = QString::fromUtf8(e.what());
|
|
||||||
if (error.isEmpty()) {
|
|
||||||
error = "Tool execution failed (QException with empty message)";
|
|
||||||
}
|
|
||||||
LOG_MESSAGE(QString("Tool %1 failed: %2").arg(execution->toolName, error));
|
|
||||||
emit toolFailed(execution->requestId, execution->toolId, error);
|
|
||||||
} catch (const std::runtime_error &e) {
|
|
||||||
QString error = QString::fromStdString(e.what());
|
|
||||||
if (error.isEmpty()) {
|
|
||||||
error = "Unknown runtime error occurred";
|
|
||||||
}
|
|
||||||
LOG_MESSAGE(QString("Tool %1 failed: %2").arg(execution->toolName, error));
|
|
||||||
emit toolFailed(execution->requestId, execution->toolId, error);
|
|
||||||
} catch (const std::invalid_argument &e) {
|
|
||||||
QString error = QString::fromStdString(e.what());
|
|
||||||
if (error.isEmpty()) {
|
|
||||||
error = "Invalid argument provided";
|
|
||||||
}
|
|
||||||
LOG_MESSAGE(QString("Tool %1 failed: %2").arg(execution->toolName, error));
|
|
||||||
emit toolFailed(execution->requestId, execution->toolId, error);
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
QString error = QString::fromStdString(e.what());
|
|
||||||
if (error.isEmpty()) {
|
|
||||||
error = "Unknown exception occurred";
|
|
||||||
}
|
|
||||||
LOG_MESSAGE(QString("Tool %1 failed: %2").arg(execution->toolName, error));
|
|
||||||
emit toolFailed(execution->requestId, execution->toolId, error);
|
|
||||||
} catch (...) {
|
|
||||||
QString error = "Unknown error occurred during tool execution";
|
|
||||||
LOG_MESSAGE(QString("Tool %1 failed: %2").arg(execution->toolName, error));
|
|
||||||
emit toolFailed(execution->requestId, execution->toolId, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
execution->watcher->deleteLater();
|
|
||||||
delete execution;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QodeAssist::Tools
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 Petr Mironychev
|
|
||||||
*
|
|
||||||
* This file is part of QodeAssist.
|
|
||||||
*
|
|
||||||
* QodeAssist is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* QodeAssist is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QFutureWatcher>
|
|
||||||
#include <QHash>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#include <pluginllmcore/BaseTool.hpp>
|
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
|
||||||
|
|
||||||
class ToolHandler : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ToolHandler(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
QFuture<QString> executeToolAsync(
|
|
||||||
const QString &requestId,
|
|
||||||
const QString &toolId,
|
|
||||||
PluginLLMCore::BaseTool *tool,
|
|
||||||
const QJsonObject &input);
|
|
||||||
|
|
||||||
void cleanupRequest(const QString &requestId);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void toolCompleted(const QString &requestId, const QString &toolId, const QString &result);
|
|
||||||
void toolFailed(const QString &requestId, const QString &toolId, const QString &error);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct ToolExecution
|
|
||||||
{
|
|
||||||
QString requestId;
|
|
||||||
QString toolId;
|
|
||||||
QString toolName;
|
|
||||||
QFutureWatcher<QString> *watcher;
|
|
||||||
};
|
|
||||||
|
|
||||||
QHash<QString, ToolExecution *> m_activeExecutions; // toolId -> execution
|
|
||||||
|
|
||||||
void onToolExecutionFinished(const QString &toolId);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QodeAssist::Tools
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 Petr Mironychev
|
|
||||||
*
|
|
||||||
* This file is part of QodeAssist.
|
|
||||||
*
|
|
||||||
* QodeAssist is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* QodeAssist is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ToolsFactory.hpp"
|
|
||||||
|
|
||||||
#include "logger/Logger.hpp"
|
|
||||||
#include <settings/GeneralSettings.hpp>
|
|
||||||
#include <settings/ToolsSettings.hpp>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include "BuildProjectTool.hpp"
|
|
||||||
#include "CreateNewFileTool.hpp"
|
|
||||||
#include "EditFileTool.hpp"
|
|
||||||
#include "ExecuteTerminalCommandTool.hpp"
|
|
||||||
#include "FindAndReadFileTool.hpp"
|
|
||||||
#include "GetIssuesListTool.hpp"
|
|
||||||
#include "ListProjectFilesTool.hpp"
|
|
||||||
#include "ProjectSearchTool.hpp"
|
|
||||||
#include "TodoTool.hpp"
|
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
|
||||||
|
|
||||||
ToolsFactory::ToolsFactory(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
registerTools();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolsFactory::registerTools()
|
|
||||||
{
|
|
||||||
registerTool(new ListProjectFilesTool(this));
|
|
||||||
registerTool(new GetIssuesListTool(this));
|
|
||||||
registerTool(new CreateNewFileTool(this));
|
|
||||||
registerTool(new EditFileTool(this));
|
|
||||||
registerTool(new BuildProjectTool(this));
|
|
||||||
registerTool(new ExecuteTerminalCommandTool(this));
|
|
||||||
registerTool(new ProjectSearchTool(this));
|
|
||||||
registerTool(new FindAndReadFileTool(this));
|
|
||||||
registerTool(new TodoTool(this));
|
|
||||||
|
|
||||||
LOG_MESSAGE(QString("Registered %1 tools").arg(m_tools.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolsFactory::registerTool(PluginLLMCore::BaseTool *tool)
|
|
||||||
{
|
|
||||||
if (!tool) {
|
|
||||||
LOG_MESSAGE("Warning: Attempted to register null tool");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString toolName = tool->name();
|
|
||||||
if (m_tools.contains(toolName)) {
|
|
||||||
LOG_MESSAGE(QString("Warning: Tool '%1' already registered, replacing").arg(toolName));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_tools.insert(toolName, tool);
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<PluginLLMCore::BaseTool *> ToolsFactory::getAvailableTools() const
|
|
||||||
{
|
|
||||||
return m_tools.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginLLMCore::BaseTool *ToolsFactory::getToolByName(const QString &name) const
|
|
||||||
{
|
|
||||||
return m_tools.value(name, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonArray ToolsFactory::getToolsDefinitions(
|
|
||||||
PluginLLMCore::ToolSchemaFormat format, PluginLLMCore::RunToolsFilter filter) const
|
|
||||||
{
|
|
||||||
QJsonArray toolsArray;
|
|
||||||
const auto &settings = Settings::toolsSettings();
|
|
||||||
|
|
||||||
for (auto it = m_tools.constBegin(); it != m_tools.constEnd(); ++it) {
|
|
||||||
if (!it.value()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it.value()->name() == "edit_file" && !settings.enableEditFileTool()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it.value()->name() == "build_project" && !settings.enableBuildProjectTool()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it.value()->name() == "execute_terminal_command"
|
|
||||||
&& !settings.enableTerminalCommandTool()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it.value()->name() == "todo_tool" && !settings.enableTodoTool()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto requiredPerms = it.value()->requiredPermissions();
|
|
||||||
|
|
||||||
if (filter != PluginLLMCore::RunToolsFilter::ALL) {
|
|
||||||
bool matchesFilter = false;
|
|
||||||
|
|
||||||
switch (filter) {
|
|
||||||
case PluginLLMCore::RunToolsFilter::OnlyRead:
|
|
||||||
if (requiredPerms == PluginLLMCore::ToolPermission::None
|
|
||||||
|| requiredPerms.testFlag(PluginLLMCore::ToolPermission::FileSystemRead)) {
|
|
||||||
matchesFilter = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PluginLLMCore::RunToolsFilter::OnlyWrite:
|
|
||||||
if (requiredPerms.testFlag(PluginLLMCore::ToolPermission::FileSystemWrite)) {
|
|
||||||
matchesFilter = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PluginLLMCore::RunToolsFilter::OnlyNetworking:
|
|
||||||
if (requiredPerms.testFlag(PluginLLMCore::ToolPermission::NetworkAccess)) {
|
|
||||||
matchesFilter = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PluginLLMCore::RunToolsFilter::ALL:
|
|
||||||
matchesFilter = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!matchesFilter) {
|
|
||||||
LOG_MESSAGE(QString("Tool '%1' skipped by tools filter")
|
|
||||||
.arg(it.value()->name()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasPermission = true;
|
|
||||||
|
|
||||||
if (requiredPerms.testFlag(PluginLLMCore::ToolPermission::FileSystemRead)) {
|
|
||||||
if (!settings.allowFileSystemRead()) {
|
|
||||||
hasPermission = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requiredPerms.testFlag(PluginLLMCore::ToolPermission::FileSystemWrite)) {
|
|
||||||
if (!settings.allowFileSystemWrite()) {
|
|
||||||
hasPermission = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requiredPerms.testFlag(PluginLLMCore::ToolPermission::NetworkAccess)) {
|
|
||||||
if (!settings.allowNetworkAccess()) {
|
|
||||||
hasPermission = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasPermission) {
|
|
||||||
toolsArray.append(it.value()->getDefinition(format));
|
|
||||||
} else {
|
|
||||||
LOG_MESSAGE(
|
|
||||||
QString("Tool '%1' skipped due to missing permissions").arg(it.value()->name()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return toolsArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ToolsFactory::getStringName(const QString &name) const
|
|
||||||
{
|
|
||||||
return m_tools.contains(name) ? m_tools.value(name)->stringName() : QString("Unknown tools");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QodeAssist::Tools
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 Petr Mironychev
|
|
||||||
*
|
|
||||||
* This file is part of QodeAssist.
|
|
||||||
*
|
|
||||||
* QodeAssist is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* QodeAssist is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
#include <pluginllmcore/BaseTool.hpp>
|
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
|
||||||
|
|
||||||
class ToolsFactory : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
ToolsFactory(QObject *parent = nullptr);
|
|
||||||
~ToolsFactory() override = default;
|
|
||||||
|
|
||||||
QList<PluginLLMCore::BaseTool *> getAvailableTools() const;
|
|
||||||
PluginLLMCore::BaseTool *getToolByName(const QString &name) const;
|
|
||||||
QJsonArray getToolsDefinitions(
|
|
||||||
PluginLLMCore::ToolSchemaFormat format,
|
|
||||||
PluginLLMCore::RunToolsFilter filter = PluginLLMCore::RunToolsFilter::ALL) const;
|
|
||||||
QString getStringName(const QString &name) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void registerTools();
|
|
||||||
void registerTool(PluginLLMCore::BaseTool *tool);
|
|
||||||
|
|
||||||
QHash<QString, PluginLLMCore::BaseTool *> m_tools;
|
|
||||||
};
|
|
||||||
} // namespace QodeAssist::Tools
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 Petr Mironychev
|
|
||||||
*
|
|
||||||
* This file is part of QodeAssist.
|
|
||||||
*
|
|
||||||
* QodeAssist is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* QodeAssist is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ToolsManager.hpp"
|
|
||||||
#include "TodoTool.hpp"
|
|
||||||
#include "logger/Logger.hpp"
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
constexpr int kToolExecutionDelayMs = 300;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
|
||||||
|
|
||||||
ToolsManager::ToolsManager(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, m_toolsFactory(new ToolsFactory(this))
|
|
||||||
, m_toolHandler(new ToolHandler(this))
|
|
||||||
{
|
|
||||||
connect(
|
|
||||||
m_toolHandler,
|
|
||||||
&ToolHandler::toolCompleted,
|
|
||||||
this,
|
|
||||||
[this](const QString &requestId, const QString &toolId, const QString &result) {
|
|
||||||
onToolFinished(requestId, toolId, result, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(
|
|
||||||
m_toolHandler,
|
|
||||||
&ToolHandler::toolFailed,
|
|
||||||
this,
|
|
||||||
[this](const QString &requestId, const QString &toolId, const QString &error) {
|
|
||||||
onToolFinished(requestId, toolId, error, false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolsManager::executeToolCall(
|
|
||||||
const QString &requestId,
|
|
||||||
const QString &toolId,
|
|
||||||
const QString &toolName,
|
|
||||||
const QJsonObject &input)
|
|
||||||
{
|
|
||||||
LOG_MESSAGE(QString("ToolsManager: Queueing tool %1 (ID: %2) for request %3")
|
|
||||||
.arg(toolName, toolId, requestId));
|
|
||||||
|
|
||||||
if (!m_toolQueues.contains(requestId)) {
|
|
||||||
m_toolQueues[requestId] = ToolQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &queue = m_toolQueues[requestId];
|
|
||||||
|
|
||||||
for (const auto &tool : queue.queue) {
|
|
||||||
if (tool.id == toolId) {
|
|
||||||
LOG_MESSAGE(QString("Tool %1 already in queue for request %2").arg(toolId, requestId));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queue.completed.contains(toolId)) {
|
|
||||||
LOG_MESSAGE(
|
|
||||||
QString("Tool %1 already completed for request %2").arg(toolId, requestId));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject modifiedInput = input;
|
|
||||||
modifiedInput["_request_id"] = requestId;
|
|
||||||
|
|
||||||
if (!m_currentSessionId.isEmpty()) {
|
|
||||||
modifiedInput["session_id"] = m_currentSessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingTool pendingTool{toolId, toolName, modifiedInput, "", false};
|
|
||||||
queue.queue.append(pendingTool);
|
|
||||||
|
|
||||||
LOG_MESSAGE(QString("ToolsManager: Tool %1 added to queue (position %2)")
|
|
||||||
.arg(toolName)
|
|
||||||
.arg(queue.queue.size()));
|
|
||||||
|
|
||||||
if (!queue.isExecuting) {
|
|
||||||
executeNextTool(requestId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolsManager::executeNextTool(const QString &requestId)
|
|
||||||
{
|
|
||||||
if (!m_toolQueues.contains(requestId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &queue = m_toolQueues[requestId];
|
|
||||||
|
|
||||||
if (queue.queue.isEmpty()) {
|
|
||||||
LOG_MESSAGE(QString("ToolsManager: All tools complete for request %1, emitting results")
|
|
||||||
.arg(requestId));
|
|
||||||
QHash<QString, QString> results = getToolResults(requestId);
|
|
||||||
emit toolExecutionComplete(requestId, results);
|
|
||||||
queue.isExecuting = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingTool tool = queue.queue.takeFirst();
|
|
||||||
queue.isExecuting = true;
|
|
||||||
|
|
||||||
LOG_MESSAGE(QString("ToolsManager: Executing tool %1 (ID: %2) for request %3 (%4 remaining)")
|
|
||||||
.arg(tool.name, tool.id, requestId)
|
|
||||||
.arg(queue.queue.size()));
|
|
||||||
|
|
||||||
auto toolInstance = m_toolsFactory->getToolByName(tool.name);
|
|
||||||
if (!toolInstance) {
|
|
||||||
LOG_MESSAGE(QString("ToolsManager: Tool not found: %1").arg(tool.name));
|
|
||||||
tool.result = QString("Error: Tool not found: %1").arg(tool.name);
|
|
||||||
tool.complete = true;
|
|
||||||
queue.completed[tool.id] = tool;
|
|
||||||
executeNextTool(requestId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
queue.completed[tool.id] = tool;
|
|
||||||
|
|
||||||
m_toolHandler->executeToolAsync(requestId, tool.id, toolInstance, tool.input);
|
|
||||||
LOG_MESSAGE(QString("ToolsManager: Started async execution of %1").arg(tool.name));
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonArray ToolsManager::getToolsDefinitions(
|
|
||||||
PluginLLMCore::ToolSchemaFormat format, PluginLLMCore::RunToolsFilter filter) const
|
|
||||||
{
|
|
||||||
if (!m_toolsFactory) {
|
|
||||||
return QJsonArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_toolsFactory->getToolsDefinitions(format, filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolsManager::cleanupRequest(const QString &requestId)
|
|
||||||
{
|
|
||||||
if (m_toolQueues.contains(requestId)) {
|
|
||||||
m_toolHandler->cleanupRequest(requestId);
|
|
||||||
m_toolQueues.remove(requestId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolsManager::onToolFinished(
|
|
||||||
const QString &requestId, const QString &toolId, const QString &result, bool success)
|
|
||||||
{
|
|
||||||
if (!m_toolQueues.contains(requestId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &queue = m_toolQueues[requestId];
|
|
||||||
|
|
||||||
if (!queue.completed.contains(toolId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingTool &tool = queue.completed[toolId];
|
|
||||||
tool.result = success ? result : QString("Error: %1").arg(result);
|
|
||||||
tool.complete = true;
|
|
||||||
|
|
||||||
LOG_MESSAGE(QString("ToolsManager: Tool %1 %2 for request %3")
|
|
||||||
.arg(toolId)
|
|
||||||
.arg(success ? QString("completed") : QString("failed"))
|
|
||||||
.arg(requestId));
|
|
||||||
|
|
||||||
if (kToolExecutionDelayMs > 0 && !queue.queue.isEmpty()) {
|
|
||||||
QTimer::singleShot(kToolExecutionDelayMs, this, [this, requestId]() {
|
|
||||||
executeNextTool(requestId);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
executeNextTool(requestId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ToolsFactory *ToolsManager::toolsFactory() const
|
|
||||||
{
|
|
||||||
return m_toolsFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<QString, QString> ToolsManager::getToolResults(const QString &requestId) const
|
|
||||||
{
|
|
||||||
QHash<QString, QString> results;
|
|
||||||
|
|
||||||
if (m_toolQueues.contains(requestId)) {
|
|
||||||
const auto &queue = m_toolQueues[requestId];
|
|
||||||
for (auto it = queue.completed.begin(); it != queue.completed.end(); ++it) {
|
|
||||||
if (it.value().complete) {
|
|
||||||
results[it.key()] = it.value().result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolsManager::clearTodoSession(const QString &sessionId)
|
|
||||||
{
|
|
||||||
auto *todoTool = qobject_cast<TodoTool *>(m_toolsFactory->getToolByName("todo_tool"));
|
|
||||||
if (todoTool) {
|
|
||||||
todoTool->clearSession(sessionId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolsManager::setCurrentSessionId(const QString &sessionId)
|
|
||||||
{
|
|
||||||
m_currentSessionId = sessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QodeAssist::Tools
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2025 Petr Mironychev
|
|
||||||
*
|
|
||||||
* This file is part of QodeAssist.
|
|
||||||
*
|
|
||||||
* QodeAssist is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* QodeAssist is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with QodeAssist. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QHash>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
#include "ToolHandler.hpp"
|
|
||||||
#include "ToolsFactory.hpp"
|
|
||||||
#include <pluginllmcore/BaseTool.hpp>
|
|
||||||
#include <pluginllmcore/IToolsManager.hpp>
|
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
|
||||||
|
|
||||||
struct PendingTool
|
|
||||||
{
|
|
||||||
QString id;
|
|
||||||
QString name;
|
|
||||||
QJsonObject input;
|
|
||||||
QString result;
|
|
||||||
bool complete = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ToolQueue
|
|
||||||
{
|
|
||||||
QList<PendingTool> queue;
|
|
||||||
QHash<QString, PendingTool> completed;
|
|
||||||
bool isExecuting = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ToolsManager : public QObject, public PluginLLMCore::IToolsManager
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ToolsManager(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
void executeToolCall(
|
|
||||||
const QString &requestId,
|
|
||||||
const QString &toolId,
|
|
||||||
const QString &toolName,
|
|
||||||
const QJsonObject &input) override;
|
|
||||||
|
|
||||||
QJsonArray getToolsDefinitions(
|
|
||||||
PluginLLMCore::ToolSchemaFormat format,
|
|
||||||
PluginLLMCore::RunToolsFilter filter = PluginLLMCore::RunToolsFilter::ALL) const override;
|
|
||||||
|
|
||||||
void cleanupRequest(const QString &requestId) override;
|
|
||||||
void setCurrentSessionId(const QString &sessionId) override;
|
|
||||||
void clearTodoSession(const QString &sessionId) override;
|
|
||||||
|
|
||||||
ToolsFactory *toolsFactory() const;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void toolExecutionComplete(const QString &requestId, const QHash<QString, QString> &toolResults);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void onToolFinished(
|
|
||||||
const QString &requestId, const QString &toolId, const QString &result, bool success);
|
|
||||||
|
|
||||||
private:
|
|
||||||
ToolsFactory *m_toolsFactory;
|
|
||||||
ToolHandler *m_toolHandler;
|
|
||||||
QHash<QString, ToolQueue> m_toolQueues;
|
|
||||||
QString m_currentSessionId;
|
|
||||||
|
|
||||||
void executeNextTool(const QString &requestId);
|
|
||||||
QHash<QString, QString> getToolResults(const QString &requestId) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace QodeAssist::Tools
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "ToolsRegistration.hpp"
|
#include "ToolsRegistration.hpp"
|
||||||
|
|
||||||
#include <LLMCore/ToolsManager.hpp>
|
#include <LLMQore/ToolsManager.hpp>
|
||||||
|
|
||||||
#include "BuildProjectTool.hpp"
|
#include "BuildProjectTool.hpp"
|
||||||
#include "CreateNewFileTool.hpp"
|
#include "CreateNewFileTool.hpp"
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
namespace QodeAssist::Tools {
|
namespace QodeAssist::Tools {
|
||||||
|
|
||||||
void registerQodeAssistTools(::LLMCore::ToolsManager *manager)
|
void registerQodeAssistTools(::LLMQore::ToolsManager *manager)
|
||||||
{
|
{
|
||||||
manager->addTool(new ListProjectFilesTool(manager));
|
manager->addTool(new ListProjectFilesTool(manager));
|
||||||
manager->addTool(new GetIssuesListTool(manager));
|
manager->addTool(new GetIssuesListTool(manager));
|
||||||
|
|||||||
@@ -19,12 +19,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace LLMCore {
|
namespace LLMQore {
|
||||||
class ToolsManager;
|
class ToolsManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace QodeAssist::Tools {
|
namespace QodeAssist::Tools {
|
||||||
|
|
||||||
void registerQodeAssistTools(::LLMCore::ToolsManager *manager);
|
void registerQodeAssistTools(::LLMQore::ToolsManager *manager);
|
||||||
|
|
||||||
} // namespace QodeAssist::Tools
|
} // namespace QodeAssist::Tools
|
||||||
|
|||||||
@@ -640,8 +640,6 @@ void QuickRefactorDialog::onConfigurationChanged(int index)
|
|||||||
settings.qrModel.setValue(config.model);
|
settings.qrModel.setValue(config.model);
|
||||||
settings.qrTemplate.setValue(config.templateName);
|
settings.qrTemplate.setValue(config.templateName);
|
||||||
settings.qrUrl.setValue(config.url);
|
settings.qrUrl.setValue(config.url);
|
||||||
settings.qrEndpointMode.setValue(
|
|
||||||
settings.qrEndpointMode.indexForDisplay(config.endpointMode));
|
|
||||||
settings.qrCustomEndpoint.setValue(config.customEndpoint);
|
settings.qrCustomEndpoint.setValue(config.customEndpoint);
|
||||||
|
|
||||||
settings.writeSettings();
|
settings.writeSettings();
|
||||||
|
|||||||
Reference in New Issue
Block a user