Update LLMQore to v0.0.4 (#339)

This commit is contained in:
Petr Mironychev
2026-04-19 11:58:54 +02:00
committed by GitHub
parent 6c05f0d594
commit ede2c01eb7
91 changed files with 381 additions and 2225 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -9,12 +9,10 @@ add_library(PluginLLMCore STATIC
PromptProviderFim.hpp
PromptTemplate.hpp
PromptTemplateManager.hpp PromptTemplateManager.cpp
RequestConfig.hpp
ProviderID.hpp
HttpClient.hpp HttpClient.cpp
DataBuffers.hpp
SSEBuffer.hpp SSEBuffer.cpp
BaseTool.hpp BaseTool.cpp
ContentBlocks.hpp
RulesLoader.hpp RulesLoader.cpp
ResponseCleaner.hpp
@@ -27,7 +25,7 @@ target_link_libraries(PluginLLMCore
QtCreator::Core
QtCreator::Utils
QtCreator::ExtensionSystem
LLMCore
LLMQore
PRIVATE
QodeAssistLogger
)

View File

@@ -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

View File

@@ -40,5 +40,13 @@ public:
virtual void prepareRequest(QJsonObject &request, const ContextData &context) const = 0;
virtual QString description() 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

View File

@@ -19,8 +19,14 @@
#include "Provider.hpp"
#include <LLMCore/BaseClient.hpp>
#include <LLMCore/ToolsManager.hpp>
#include <LLMQore/BaseClient.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>
@@ -30,19 +36,21 @@ Provider::Provider(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();
QUrl baseUrl(url);
baseUrl.setPath("");
c->setUrl(baseUrl.toString());
c->setUrl(url.toString());
c->setApiKey(apiKey());
auto requestId = c->sendMessage(payload);
auto requestId = c->sendMessage(payload, endpoint);
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;
}
@@ -53,9 +61,35 @@ void Provider::cancelRequest(const RequestID &requestId)
client()->cancelRequest(requestId);
}
::LLMCore::ToolsManager *Provider::toolsManager() const
::LLMQore::ToolsManager *Provider::toolsManager() const
{
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

View File

@@ -26,11 +26,10 @@
#include <utils/environment.h>
#include "ContextData.hpp"
#include "IToolsManager.hpp"
#include "PromptTemplate.hpp"
#include "RequestType.hpp"
namespace LLMCore {
namespace LLMQore {
class BaseClient;
class ToolsManager;
}
@@ -58,8 +57,6 @@ public:
virtual QString name() const = 0;
virtual QString url() const = 0;
virtual QString completionEndpoint() const = 0;
virtual QString chatEndpoint() const = 0;
virtual void prepareRequest(
QJsonObject &request,
PluginLLMCore::PromptTemplate *prompt,
@@ -72,12 +69,15 @@ public:
virtual ProviderID providerID() const = 0;
virtual ProviderCapabilities capabilities() const { return {}; }
virtual ::LLMCore::BaseClient *client() const = 0;
virtual ::LLMQore::BaseClient *client() 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);
::LLMCore::ToolsManager *toolsManager() const;
::LLMQore::ToolsManager *toolsManager() const;
QString enrichErrorMessage(const QString &error) const;
};
} // namespace QodeAssist::PluginLLMCore

View File

@@ -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

View File

@@ -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

View File

@@ -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