mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-07-20 18:20:58 -04:00
refactor: Restructure project into sources/tests layout and dissolve PluginLLMCore
This commit is contained in:
90
sources/providers/ClaudeCacheControl.hpp
Normal file
90
sources/providers/ClaudeCacheControl.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QString>
|
||||
|
||||
namespace QodeAssist::Providers::ClaudeCacheControl {
|
||||
|
||||
inline QJsonObject buildBreakpoint(bool extendedTtl)
|
||||
{
|
||||
QJsonObject cacheControl{{"type", "ephemeral"}};
|
||||
if (extendedTtl)
|
||||
cacheControl["ttl"] = "1h";
|
||||
return cacheControl;
|
||||
}
|
||||
|
||||
inline void markLastBlock(QJsonArray &blocks, const QJsonObject &cacheControl)
|
||||
{
|
||||
if (blocks.isEmpty())
|
||||
return;
|
||||
QJsonObject last = blocks.last().toObject();
|
||||
last["cache_control"] = cacheControl;
|
||||
blocks.replace(blocks.size() - 1, last);
|
||||
}
|
||||
|
||||
inline void applyToSystem(QJsonObject &request, const QJsonObject &cacheControl)
|
||||
{
|
||||
if (!request.contains("system"))
|
||||
return;
|
||||
|
||||
const QJsonValue sys = request.value("system");
|
||||
if (sys.isString()) {
|
||||
const QString text = sys.toString();
|
||||
if (!text.isEmpty()) {
|
||||
request["system"] = QJsonArray{QJsonObject{
|
||||
{"type", "text"}, {"text", text}, {"cache_control", cacheControl}}};
|
||||
}
|
||||
} else if (sys.isArray()) {
|
||||
QJsonArray blocks = sys.toArray();
|
||||
markLastBlock(blocks, cacheControl);
|
||||
request["system"] = blocks;
|
||||
}
|
||||
}
|
||||
|
||||
inline void applyToTools(QJsonObject &request, const QJsonObject &cacheControl)
|
||||
{
|
||||
if (!request.contains("tools"))
|
||||
return;
|
||||
QJsonArray tools = request.value("tools").toArray();
|
||||
markLastBlock(tools, cacheControl);
|
||||
request["tools"] = tools;
|
||||
}
|
||||
|
||||
inline void applyToHistory(QJsonObject &request, const QJsonObject &cacheControl)
|
||||
{
|
||||
if (!request.contains("messages"))
|
||||
return;
|
||||
QJsonArray messages = request.value("messages").toArray();
|
||||
if (messages.size() < 2)
|
||||
return;
|
||||
|
||||
const int idx = messages.size() - 2;
|
||||
QJsonObject msg = messages[idx].toObject();
|
||||
const QJsonValue content = msg.value("content");
|
||||
if (content.isString()) {
|
||||
msg["content"] = QJsonArray{QJsonObject{
|
||||
{"type", "text"}, {"text", content.toString()}, {"cache_control", cacheControl}}};
|
||||
} else if (content.isArray()) {
|
||||
QJsonArray blocks = content.toArray();
|
||||
markLastBlock(blocks, cacheControl);
|
||||
msg["content"] = blocks;
|
||||
}
|
||||
messages.replace(idx, msg);
|
||||
request["messages"] = messages;
|
||||
}
|
||||
|
||||
inline void apply(QJsonObject &request, bool extendedTtl)
|
||||
{
|
||||
const QJsonObject cacheControl = buildBreakpoint(extendedTtl);
|
||||
applyToSystem(request, cacheControl);
|
||||
applyToTools(request, cacheControl);
|
||||
applyToHistory(request, cacheControl);
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers::ClaudeCacheControl
|
||||
162
sources/providers/ClaudeProvider.cpp
Normal file
162
sources/providers/ClaudeProvider.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "ClaudeProvider.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
|
||||
#include "ClaudeCacheControl.hpp"
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
ClaudeProvider::ClaudeProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::ClaudeClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString ClaudeProvider::name() const
|
||||
{
|
||||
return "Claude";
|
||||
}
|
||||
|
||||
QString ClaudeProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().claudeApiKey();
|
||||
}
|
||||
|
||||
QString ClaudeProvider::url() const
|
||||
{
|
||||
return "https://api.anthropic.com";
|
||||
}
|
||||
|
||||
void ClaudeProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
if (settings.useTopP())
|
||||
request["top_p"] = settings.topP();
|
||||
if (settings.useTopK())
|
||||
request["top_k"] = settings.topK();
|
||||
request["stream"] = true;
|
||||
};
|
||||
|
||||
auto applyThinkingMode = [&request](const auto &settings) {
|
||||
const QString model = request.value("model").toString().toLower();
|
||||
const bool useAdaptiveThinking = model.contains("opus-4-8") || model.contains("opus-4-7")
|
||||
|| model.contains("opus-4-6") || model.contains("sonnet-4-6");
|
||||
|
||||
QJsonObject thinkingObj;
|
||||
if (useAdaptiveThinking) {
|
||||
thinkingObj["type"] = "adaptive";
|
||||
|
||||
const int budget = settings.thinkingBudgetTokens();
|
||||
QString effort = "high";
|
||||
if (budget < 8000)
|
||||
effort = "low";
|
||||
else if (budget < 24000)
|
||||
effort = "medium";
|
||||
|
||||
QJsonObject outputConfig;
|
||||
outputConfig["effort"] = effort;
|
||||
request["output_config"] = outputConfig;
|
||||
} else {
|
||||
thinkingObj["type"] = "enabled";
|
||||
thinkingObj["budget_tokens"] = settings.thinkingBudgetTokens();
|
||||
}
|
||||
request["thinking"] = thinkingObj;
|
||||
request["max_tokens"] = settings.thinkingMaxTokens();
|
||||
request["temperature"] = 1.0;
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
request["temperature"] = Settings::codeCompletionSettings().temperature();
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
const auto &qrSettings = Settings::quickRefactorSettings();
|
||||
applyModelParams(qrSettings);
|
||||
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode(qrSettings);
|
||||
} else {
|
||||
request["temperature"] = qrSettings.temperature();
|
||||
}
|
||||
} else {
|
||||
const auto &chatSettings = Settings::chatAssistantSettings();
|
||||
applyModelParams(chatSettings);
|
||||
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode(chatSettings);
|
||||
} else {
|
||||
request["temperature"] = chatSettings.temperature();
|
||||
}
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(QString("Added %1 tools to Claude request").arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
|
||||
const auto &ps = Settings::providerSettings();
|
||||
const bool cachingOn = ps.claudeEnablePromptCaching()
|
||||
&& type != LLMCore::RequestType::CodeCompletion;
|
||||
m_client->setUseExtendedCacheTTL(cachingOn && ps.claudeUseExtendedCacheTTL());
|
||||
if (cachingOn) {
|
||||
ClaudeCacheControl::apply(request, ps.claudeUseExtendedCacheTTL());
|
||||
}
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> ClaudeProvider::getInstalledModels(const QString &baseUrl)
|
||||
{
|
||||
m_client->setUrl(baseUrl);
|
||||
m_client->setApiKey(apiKey());
|
||||
return m_client->listModels();
|
||||
}
|
||||
|
||||
Providers::ProviderID ClaudeProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::Claude;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities ClaudeProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Thinking
|
||||
| Providers::ProviderCapability::Image
|
||||
| Providers::ProviderCapability::ModelListing;
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *ClaudeProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
39
sources/providers/ClaudeProvider.hpp
Normal file
39
sources/providers/ClaudeProvider.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
#include <LLMQore/ClaudeClient.hpp>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class ClaudeProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ClaudeProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
private:
|
||||
::LLMQore::ClaudeClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
35
sources/providers/CodestralProvider.cpp
Normal file
35
sources/providers/CodestralProvider.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2025-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "CodestralProvider.hpp"
|
||||
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
CodestralProvider::CodestralProvider(QObject *parent)
|
||||
: MistralAIProvider(parent)
|
||||
{}
|
||||
|
||||
QString CodestralProvider::name() const
|
||||
{
|
||||
return "Codestral";
|
||||
}
|
||||
|
||||
QString CodestralProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().codestralApiKey();
|
||||
}
|
||||
|
||||
QString CodestralProvider::url() const
|
||||
{
|
||||
return "https://codestral.mistral.ai";
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities CodestralProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Image;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
22
sources/providers/CodestralProvider.hpp
Normal file
22
sources/providers/CodestralProvider.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (C) 2025-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MistralAIProvider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class CodestralProvider : public MistralAIProvider
|
||||
{
|
||||
public:
|
||||
explicit CodestralProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
QString apiKey() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
111
sources/providers/DeepSeekProvider.cpp
Normal file
111
sources/providers/DeepSeekProvider.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "DeepSeekProvider.hpp"
|
||||
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
DeepSeekProvider::DeepSeekProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::OpenAIClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString DeepSeekProvider::name() const
|
||||
{
|
||||
return "DeepSeek";
|
||||
}
|
||||
|
||||
QString DeepSeekProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().deepSeekApiKey();
|
||||
}
|
||||
|
||||
QString DeepSeekProvider::url() const
|
||||
{
|
||||
return "https://api.deepseek.com";
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> DeepSeekProvider::getInstalledModels(const QString &url)
|
||||
{
|
||||
m_client->setUrl(url);
|
||||
m_client->setApiKey(apiKey());
|
||||
return m_client->listModels();
|
||||
}
|
||||
|
||||
Providers::ProviderID DeepSeekProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::DeepSeek;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities DeepSeekProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools
|
||||
| Providers::ProviderCapability::Thinking
|
||||
| Providers::ProviderCapability::ModelListing;
|
||||
}
|
||||
|
||||
void DeepSeekProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
request["temperature"] = settings.temperature();
|
||||
|
||||
if (settings.useTopP())
|
||||
request["top_p"] = settings.topP();
|
||||
if (settings.useFrequencyPenalty())
|
||||
request["frequency_penalty"] = settings.frequencyPenalty();
|
||||
if (settings.usePresencePenalty())
|
||||
request["presence_penalty"] = settings.presencePenalty();
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
applyModelParams(Settings::quickRefactorSettings());
|
||||
} else {
|
||||
applyModelParams(Settings::chatAssistantSettings());
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(QString("Added %1 tools to DeepSeek request").arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *DeepSeekProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
38
sources/providers/DeepSeekProvider.hpp
Normal file
38
sources/providers/DeepSeekProvider.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LLMQore/OpenAIClient.hpp>
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class DeepSeekProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DeepSeekProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
private:
|
||||
::LLMQore::OpenAIClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
161
sources/providers/GoogleAIProvider.cpp
Normal file
161
sources/providers/GoogleAIProvider.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "GoogleAIProvider.hpp"
|
||||
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QtCore/qurlquery.h>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
GoogleAIProvider::GoogleAIProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::GoogleAIClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString GoogleAIProvider::name() const
|
||||
{
|
||||
return "Google AI";
|
||||
}
|
||||
|
||||
QString GoogleAIProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().googleAiApiKey();
|
||||
}
|
||||
|
||||
QString GoogleAIProvider::url() const
|
||||
{
|
||||
return "https://generativelanguage.googleapis.com/v1beta";
|
||||
}
|
||||
|
||||
void GoogleAIProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
QJsonObject generationConfig;
|
||||
generationConfig["maxOutputTokens"] = settings.maxTokens();
|
||||
generationConfig["temperature"] = settings.temperature();
|
||||
|
||||
if (settings.useTopP())
|
||||
generationConfig["topP"] = settings.topP();
|
||||
if (settings.useTopK())
|
||||
generationConfig["topK"] = settings.topK();
|
||||
|
||||
request["generationConfig"] = generationConfig;
|
||||
};
|
||||
|
||||
auto applyThinkingMode = [&request](const auto &settings) {
|
||||
QJsonObject generationConfig;
|
||||
generationConfig["maxOutputTokens"] = settings.thinkingMaxTokens();
|
||||
|
||||
if (settings.useTopP())
|
||||
generationConfig["topP"] = settings.topP();
|
||||
if (settings.useTopK())
|
||||
generationConfig["topK"] = settings.topK();
|
||||
|
||||
generationConfig["temperature"] = 1.0;
|
||||
|
||||
QJsonObject thinkingConfig;
|
||||
thinkingConfig["includeThoughts"] = true;
|
||||
int budgetTokens = settings.thinkingBudgetTokens();
|
||||
if (budgetTokens != -1) {
|
||||
thinkingConfig["thinkingBudget"] = budgetTokens;
|
||||
}
|
||||
|
||||
generationConfig["thinkingConfig"] = thinkingConfig;
|
||||
request["generationConfig"] = generationConfig;
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
const auto &qrSettings = Settings::quickRefactorSettings();
|
||||
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode(qrSettings);
|
||||
} else {
|
||||
applyModelParams(qrSettings);
|
||||
}
|
||||
} else {
|
||||
const auto &chatSettings = Settings::chatAssistantSettings();
|
||||
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode(chatSettings);
|
||||
} else {
|
||||
applyModelParams(chatSettings);
|
||||
}
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(QString("Added %1 tools to Google AI request").arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> GoogleAIProvider::getInstalledModels(const QString &baseUrl)
|
||||
{
|
||||
m_client->setUrl(baseUrl);
|
||||
m_client->setApiKey(apiKey());
|
||||
return m_client->listModels();
|
||||
}
|
||||
|
||||
Providers::ProviderID GoogleAIProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::GoogleAI;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities GoogleAIProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Thinking
|
||||
| Providers::ProviderCapability::Image
|
||||
| Providers::ProviderCapability::ModelListing;
|
||||
}
|
||||
|
||||
LLMQore::RequestID GoogleAIProvider::sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint)
|
||||
{
|
||||
QJsonObject cleaned = payload;
|
||||
if (cleaned.contains("model")) {
|
||||
m_client->setModel(cleaned["model"].toString());
|
||||
cleaned.remove("model");
|
||||
}
|
||||
cleaned.remove("stream");
|
||||
|
||||
return Providers::Provider::sendRequest(url, cleaned, endpoint);
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *GoogleAIProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
42
sources/providers/GoogleAIProvider.hpp
Normal file
42
sources/providers/GoogleAIProvider.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
#include <LLMQore/GoogleAIClient.hpp>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class GoogleAIProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GoogleAIProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
LLMQore::RequestID sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint) override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
private:
|
||||
::LLMQore::GoogleAIClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
21
sources/providers/IProviderRegistry.hpp
Normal file
21
sources/providers/IProviderRegistry.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (C) 2025 Povilas Kanapickas <povilas@radix.lt>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class IProviderRegistry
|
||||
{
|
||||
public:
|
||||
virtual ~IProviderRegistry() = default;
|
||||
|
||||
virtual Provider *getProviderByName(const QString &providerName) = 0;
|
||||
|
||||
virtual QStringList providersNames() const = 0;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
122
sources/providers/LMStudioProvider.cpp
Normal file
122
sources/providers/LMStudioProvider.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "LMStudioProvider.hpp"
|
||||
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
|
||||
#include "providers/ProviderUrlUtils.hpp"
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
LMStudioProvider::LMStudioProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::OpenAIClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString LMStudioProvider::name() const
|
||||
{
|
||||
return "LM Studio (Chat Completions)";
|
||||
}
|
||||
|
||||
QString LMStudioProvider::apiKey() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
QString LMStudioProvider::url() const
|
||||
{
|
||||
return "http://localhost:1234";
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> LMStudioProvider::getInstalledModels(const QString &url)
|
||||
{
|
||||
m_client->setUrl(ensureOpenAIV1Base(url));
|
||||
m_client->setApiKey(apiKey());
|
||||
return m_client->listModels();
|
||||
}
|
||||
|
||||
Providers::ProviderID LMStudioProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::LMStudio;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities LMStudioProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Image
|
||||
| Providers::ProviderCapability::ModelListing
|
||||
| Providers::ProviderCapability::Thinking;
|
||||
}
|
||||
|
||||
void LMStudioProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
request["temperature"] = settings.temperature();
|
||||
|
||||
if (settings.useTopP())
|
||||
request["top_p"] = settings.topP();
|
||||
if (settings.useTopK())
|
||||
request["top_k"] = settings.topK();
|
||||
if (settings.useFrequencyPenalty())
|
||||
request["frequency_penalty"] = settings.frequencyPenalty();
|
||||
if (settings.usePresencePenalty())
|
||||
request["presence_penalty"] = settings.presencePenalty();
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
applyModelParams(Settings::quickRefactorSettings());
|
||||
} else {
|
||||
applyModelParams(Settings::chatAssistantSettings());
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(QString("Added %1 tools to LMStudio request").arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLMQore::RequestID LMStudioProvider::sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint)
|
||||
{
|
||||
return Providers::Provider::sendRequest(
|
||||
QUrl(ensureOpenAIV1Base(url.toString())), payload, endpoint);
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *LMStudioProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
41
sources/providers/LMStudioProvider.hpp
Normal file
41
sources/providers/LMStudioProvider.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LLMQore/OpenAIClient.hpp>
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class LMStudioProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LMStudioProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
LLMQore::RequestID sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint) override;
|
||||
|
||||
private:
|
||||
::LLMQore::OpenAIClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
146
sources/providers/LMStudioResponsesProvider.cpp
Normal file
146
sources/providers/LMStudioResponsesProvider.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "LMStudioResponsesProvider.hpp"
|
||||
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
#include "providers/ProviderUrlUtils.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
LMStudioResponsesProvider::LMStudioResponsesProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::OpenAIResponsesClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString LMStudioResponsesProvider::name() const
|
||||
{
|
||||
return "LM Studio (Responses API)";
|
||||
}
|
||||
|
||||
QString LMStudioResponsesProvider::apiKey() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
QString LMStudioResponsesProvider::url() const
|
||||
{
|
||||
return "http://localhost:1234";
|
||||
}
|
||||
|
||||
void LMStudioResponsesProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
request["max_output_tokens"] = settings.maxTokens();
|
||||
|
||||
if (settings.useTopP()) {
|
||||
request["top_p"] = settings.topP();
|
||||
}
|
||||
};
|
||||
|
||||
auto applyThinkingMode = [&request](const auto &settings) {
|
||||
QString effortStr = settings.openAIResponsesReasoningEffort.stringValue().toLower();
|
||||
if (effortStr.isEmpty()) {
|
||||
effortStr = "medium";
|
||||
}
|
||||
|
||||
QJsonObject reasoning;
|
||||
reasoning["effort"] = effortStr;
|
||||
request["reasoning"] = reasoning;
|
||||
request["max_output_tokens"] = settings.thinkingMaxTokens();
|
||||
request["store"] = true;
|
||||
|
||||
QJsonArray include;
|
||||
include.append("reasoning.encrypted_content");
|
||||
request["include"] = include;
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
const auto &qrSettings = Settings::quickRefactorSettings();
|
||||
applyModelParams(qrSettings);
|
||||
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode(qrSettings);
|
||||
}
|
||||
} else {
|
||||
const auto &chatSettings = Settings::chatAssistantSettings();
|
||||
applyModelParams(chatSettings);
|
||||
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode(chatSettings);
|
||||
}
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
const auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(QString("Added %1 tools to LM Studio Responses request")
|
||||
.arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
|
||||
request["stream"] = true;
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> LMStudioResponsesProvider::getInstalledModels(const QString &baseUrl)
|
||||
{
|
||||
m_client->setUrl(ensureOpenAIV1Base(baseUrl));
|
||||
m_client->setApiKey(apiKey());
|
||||
return m_client->listModels();
|
||||
}
|
||||
|
||||
LLMQore::RequestID LMStudioResponsesProvider::sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint)
|
||||
{
|
||||
return Providers::Provider::sendRequest(
|
||||
QUrl(ensureOpenAIV1Base(url.toString())), payload, endpoint);
|
||||
}
|
||||
|
||||
Providers::ProviderID LMStudioResponsesProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::OpenAIResponses;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities LMStudioResponsesProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Thinking
|
||||
| Providers::ProviderCapability::Image
|
||||
| Providers::ProviderCapability::ModelListing;
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *LMStudioResponsesProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
41
sources/providers/LMStudioResponsesProvider.hpp
Normal file
41
sources/providers/LMStudioResponsesProvider.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LLMQore/OpenAIResponsesClient.hpp>
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class LMStudioResponsesProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LMStudioResponsesProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
LLMQore::RequestID sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint) override;
|
||||
|
||||
private:
|
||||
::LLMQore::OpenAIResponsesClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
127
sources/providers/LlamaCppProvider.cpp
Normal file
127
sources/providers/LlamaCppProvider.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "LlamaCppProvider.hpp"
|
||||
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
LlamaCppProvider::LlamaCppProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::LlamaCppClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString LlamaCppProvider::name() const
|
||||
{
|
||||
return "llama.cpp";
|
||||
}
|
||||
|
||||
QString LlamaCppProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().llamaCppApiKey();
|
||||
}
|
||||
|
||||
QString LlamaCppProvider::url() const
|
||||
{
|
||||
return "http://localhost:8080";
|
||||
}
|
||||
|
||||
void LlamaCppProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
request["temperature"] = settings.temperature();
|
||||
|
||||
if (settings.useTopP())
|
||||
request["top_p"] = settings.topP();
|
||||
if (settings.useTopK())
|
||||
request["top_k"] = settings.topK();
|
||||
if (settings.useFrequencyPenalty())
|
||||
request["frequency_penalty"] = settings.frequencyPenalty();
|
||||
if (settings.usePresencePenalty())
|
||||
request["presence_penalty"] = settings.presencePenalty();
|
||||
};
|
||||
|
||||
auto applyThinkingMode = [&request]() {
|
||||
QJsonObject chatTemplateKwargs = request["chat_template_kwargs"].toObject();
|
||||
chatTemplateKwargs["enable_thinking"] = true;
|
||||
request["chat_template_kwargs"] = chatTemplateKwargs;
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
applyModelParams(Settings::quickRefactorSettings());
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode();
|
||||
LOG_MESSAGE(QString("LlamaCppProvider: Thinking mode enabled for QuickRefactoring"));
|
||||
}
|
||||
} else {
|
||||
applyModelParams(Settings::chatAssistantSettings());
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode();
|
||||
LOG_MESSAGE(QString("LlamaCppProvider: Thinking mode enabled for Chat"));
|
||||
}
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(QString("Added %1 tools to llama.cpp request").arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> LlamaCppProvider::getInstalledModels(const QString &baseUrl)
|
||||
{
|
||||
m_client->setUrl(baseUrl);
|
||||
m_client->setApiKey(Settings::providerSettings().llamaCppApiKey());
|
||||
return m_client->listModels();
|
||||
}
|
||||
|
||||
Providers::ProviderID LlamaCppProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::LlamaCpp;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities LlamaCppProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Thinking
|
||||
| Providers::ProviderCapability::Image
|
||||
| Providers::ProviderCapability::ModelListing;
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *LlamaCppProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
39
sources/providers/LlamaCppProvider.hpp
Normal file
39
sources/providers/LlamaCppProvider.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
#include <LLMQore/LlamaCppClient.hpp>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class LlamaCppProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LlamaCppProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
private:
|
||||
::LLMQore::LlamaCppClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
113
sources/providers/MistralAIProvider.cpp
Normal file
113
sources/providers/MistralAIProvider.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "MistralAIProvider.hpp"
|
||||
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
MistralAIProvider::MistralAIProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::MistralClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString MistralAIProvider::name() const
|
||||
{
|
||||
return "Mistral AI";
|
||||
}
|
||||
|
||||
QString MistralAIProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().mistralAiApiKey();
|
||||
}
|
||||
|
||||
QString MistralAIProvider::url() const
|
||||
{
|
||||
return "https://api.mistral.ai";
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> MistralAIProvider::getInstalledModels(const QString &url)
|
||||
{
|
||||
m_client->setUrl(url);
|
||||
m_client->setApiKey(apiKey());
|
||||
return m_client->listModels();
|
||||
}
|
||||
|
||||
Providers::ProviderID MistralAIProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::MistralAI;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities MistralAIProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Image
|
||||
| Providers::ProviderCapability::ModelListing
|
||||
| Providers::ProviderCapability::Thinking;
|
||||
}
|
||||
|
||||
void MistralAIProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
request["temperature"] = settings.temperature();
|
||||
|
||||
if (settings.useTopP())
|
||||
request["top_p"] = settings.topP();
|
||||
if (settings.useTopK())
|
||||
request["top_k"] = settings.topK();
|
||||
if (settings.useFrequencyPenalty())
|
||||
request["frequency_penalty"] = settings.frequencyPenalty();
|
||||
if (settings.usePresencePenalty())
|
||||
request["presence_penalty"] = settings.presencePenalty();
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
applyModelParams(Settings::quickRefactorSettings());
|
||||
} else {
|
||||
applyModelParams(Settings::chatAssistantSettings());
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(QString("Added %1 tools to Mistral request").arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *MistralAIProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
38
sources/providers/MistralAIProvider.hpp
Normal file
38
sources/providers/MistralAIProvider.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LLMQore/MistralClient.hpp>
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class MistralAIProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MistralAIProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
private:
|
||||
::LLMQore::MistralClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
126
sources/providers/OllamaCompatProvider.cpp
Normal file
126
sources/providers/OllamaCompatProvider.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "OllamaCompatProvider.hpp"
|
||||
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
OllamaCompatProvider::OllamaCompatProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::OpenAIClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString OllamaCompatProvider::name() const
|
||||
{
|
||||
return "Ollama (OpenAI-compatible)";
|
||||
}
|
||||
|
||||
QString OllamaCompatProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().ollamaBasicAuthApiKey();
|
||||
}
|
||||
|
||||
QString OllamaCompatProvider::url() const
|
||||
{
|
||||
return "http://localhost:11434";
|
||||
}
|
||||
|
||||
void OllamaCompatProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
request["temperature"] = settings.temperature();
|
||||
|
||||
if (settings.useTopP())
|
||||
request["top_p"] = settings.topP();
|
||||
if (settings.useTopK())
|
||||
request["top_k"] = settings.topK();
|
||||
if (settings.useFrequencyPenalty())
|
||||
request["frequency_penalty"] = settings.frequencyPenalty();
|
||||
if (settings.usePresencePenalty())
|
||||
request["presence_penalty"] = settings.presencePenalty();
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
applyModelParams(Settings::quickRefactorSettings());
|
||||
} else {
|
||||
applyModelParams(Settings::chatAssistantSettings());
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(
|
||||
QString("Added %1 tools to OllamaCompat request").arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> OllamaCompatProvider::getInstalledModels(const QString &baseUrl)
|
||||
{
|
||||
QString url = baseUrl;
|
||||
if (!url.endsWith(QStringLiteral("/v1")))
|
||||
url += QStringLiteral("/v1");
|
||||
m_client->setUrl(url);
|
||||
m_client->setApiKey(apiKey());
|
||||
return m_client->listModels();
|
||||
}
|
||||
|
||||
LLMQore::RequestID OllamaCompatProvider::sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint)
|
||||
{
|
||||
const QString effectiveEndpoint
|
||||
= endpoint.isEmpty() ? QStringLiteral("/v1/chat/completions") : endpoint;
|
||||
return Providers::Provider::sendRequest(url, payload, effectiveEndpoint);
|
||||
}
|
||||
|
||||
Providers::ProviderID OllamaCompatProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::OpenAICompatible;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities OllamaCompatProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Image
|
||||
| Providers::ProviderCapability::ModelListing
|
||||
| Providers::ProviderCapability::Thinking;
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *OllamaCompatProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
41
sources/providers/OllamaCompatProvider.hpp
Normal file
41
sources/providers/OllamaCompatProvider.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LLMQore/OpenAIClient.hpp>
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class OllamaCompatProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OllamaCompatProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
LLMQore::RequestID sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint) override;
|
||||
|
||||
private:
|
||||
::LLMQore::OpenAIClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
139
sources/providers/OllamaProvider.cpp
Normal file
139
sources/providers/OllamaProvider.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "OllamaProvider.hpp"
|
||||
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
OllamaProvider::OllamaProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::OllamaClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString OllamaProvider::name() const
|
||||
{
|
||||
return "Ollama (Native)";
|
||||
}
|
||||
|
||||
QString OllamaProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().ollamaBasicAuthApiKey();
|
||||
}
|
||||
|
||||
QString OllamaProvider::url() const
|
||||
{
|
||||
return "http://localhost:11434";
|
||||
}
|
||||
|
||||
void OllamaProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applySettings = [&request](const auto &settings) {
|
||||
QJsonObject options;
|
||||
options["num_predict"] = settings.maxTokens();
|
||||
options["temperature"] = settings.temperature();
|
||||
options["stop"] = request.take("stop");
|
||||
|
||||
if (settings.useTopP())
|
||||
options["top_p"] = settings.topP();
|
||||
if (settings.useTopK())
|
||||
options["top_k"] = settings.topK();
|
||||
if (settings.useFrequencyPenalty())
|
||||
options["frequency_penalty"] = settings.frequencyPenalty();
|
||||
if (settings.usePresencePenalty())
|
||||
options["presence_penalty"] = settings.presencePenalty();
|
||||
|
||||
request["options"] = options;
|
||||
request["keep_alive"] = settings.ollamaLivetime();
|
||||
};
|
||||
|
||||
auto applyThinkingMode = [&request]() {
|
||||
request["enable_thinking"] = true;
|
||||
QJsonObject options = request["options"].toObject();
|
||||
options["temperature"] = 1.0;
|
||||
request["options"] = options;
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applySettings(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
const auto &qrSettings = Settings::quickRefactorSettings();
|
||||
applySettings(qrSettings);
|
||||
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode();
|
||||
LOG_MESSAGE(QString("OllamaProvider: Thinking mode enabled for QuickRefactoring"));
|
||||
}
|
||||
} else {
|
||||
const auto &chatSettings = Settings::chatAssistantSettings();
|
||||
applySettings(chatSettings);
|
||||
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode();
|
||||
LOG_MESSAGE(QString("OllamaProvider: Thinking mode enabled for Chat"));
|
||||
}
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(
|
||||
QString("OllamaProvider: Added %1 tools to request").arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> OllamaProvider::getInstalledModels(const QString &baseUrl)
|
||||
{
|
||||
m_client->setUrl(baseUrl);
|
||||
m_client->setApiKey(Settings::providerSettings().ollamaBasicAuthApiKey());
|
||||
return m_client->listModels();
|
||||
}
|
||||
|
||||
Providers::ProviderID OllamaProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::Ollama;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities OllamaProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Thinking
|
||||
| Providers::ProviderCapability::Image
|
||||
| Providers::ProviderCapability::ModelListing;
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *OllamaProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
39
sources/providers/OllamaProvider.hpp
Normal file
39
sources/providers/OllamaProvider.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
#include <LLMQore/OllamaClient.hpp>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class OllamaProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OllamaProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
private:
|
||||
::LLMQore::OllamaClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
111
sources/providers/OpenAICompatProvider.cpp
Normal file
111
sources/providers/OpenAICompatProvider.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "OpenAICompatProvider.hpp"
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
OpenAICompatProvider::OpenAICompatProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::OpenAIClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString OpenAICompatProvider::name() const
|
||||
{
|
||||
return "OpenAI Compatible";
|
||||
}
|
||||
|
||||
QString OpenAICompatProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().openAiCompatApiKey();
|
||||
}
|
||||
|
||||
QString OpenAICompatProvider::url() const
|
||||
{
|
||||
return "http://localhost:1234/v1";
|
||||
}
|
||||
|
||||
void OpenAICompatProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
request["temperature"] = settings.temperature();
|
||||
|
||||
if (settings.useTopP())
|
||||
request["top_p"] = settings.topP();
|
||||
if (settings.useTopK())
|
||||
request["top_k"] = settings.topK();
|
||||
if (settings.useFrequencyPenalty())
|
||||
request["frequency_penalty"] = settings.frequencyPenalty();
|
||||
if (settings.usePresencePenalty())
|
||||
request["presence_penalty"] = settings.presencePenalty();
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
applyModelParams(Settings::quickRefactorSettings());
|
||||
} else {
|
||||
applyModelParams(Settings::chatAssistantSettings());
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(
|
||||
QString("Added %1 tools to OpenAICompat request").arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> OpenAICompatProvider::getInstalledModels(const QString &)
|
||||
{
|
||||
return QtFuture::makeReadyFuture(QList<QString>{});
|
||||
}
|
||||
|
||||
Providers::ProviderID OpenAICompatProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::OpenAICompatible;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities OpenAICompatProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Image
|
||||
| Providers::ProviderCapability::Thinking;
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *OpenAICompatProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
38
sources/providers/OpenAICompatProvider.hpp
Normal file
38
sources/providers/OpenAICompatProvider.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LLMQore/OpenAIClient.hpp>
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class OpenAICompatProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OpenAICompatProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
private:
|
||||
::LLMQore::OpenAIClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
142
sources/providers/OpenAIProvider.cpp
Normal file
142
sources/providers/OpenAIProvider.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "OpenAIProvider.hpp"
|
||||
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
OpenAIProvider::OpenAIProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::OpenAIClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString OpenAIProvider::name() const
|
||||
{
|
||||
return "OpenAI (Chat Completions)";
|
||||
}
|
||||
|
||||
QString OpenAIProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().openAiApiKey();
|
||||
}
|
||||
|
||||
QString OpenAIProvider::url() const
|
||||
{
|
||||
return "https://api.openai.com/v1";
|
||||
}
|
||||
|
||||
void OpenAIProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
QString model = request.value("model").toString().toLower();
|
||||
bool useNewParameter = model.contains("gpt-4o") || model.contains("gpt-4-turbo")
|
||||
|| model.contains("o1-") || model.contains("gpt-5")
|
||||
|| model.startsWith("o1") || model.contains("o3");
|
||||
|
||||
bool isReasoningModel = model.contains("o1-") || model.contains("gpt-5")
|
||||
|| model.startsWith("o1") || model.contains("o3");
|
||||
|
||||
if (useNewParameter) {
|
||||
request["max_completion_tokens"] = settings.maxTokens();
|
||||
} else {
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
}
|
||||
|
||||
if (!isReasoningModel) {
|
||||
request["temperature"] = settings.temperature();
|
||||
|
||||
if (settings.useTopP())
|
||||
request["top_p"] = settings.topP();
|
||||
if (settings.useTopK())
|
||||
request["top_k"] = settings.topK();
|
||||
|
||||
} else {
|
||||
request["temperature"] = 1.0;
|
||||
}
|
||||
|
||||
if (settings.useFrequencyPenalty())
|
||||
request["frequency_penalty"] = settings.frequencyPenalty();
|
||||
if (settings.usePresencePenalty())
|
||||
request["presence_penalty"] = settings.presencePenalty();
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
applyModelParams(Settings::quickRefactorSettings());
|
||||
} else {
|
||||
applyModelParams(Settings::chatAssistantSettings());
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(QString("Added %1 tools to OpenAI request").arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> OpenAIProvider::getInstalledModels(const QString &baseUrl)
|
||||
{
|
||||
m_client->setUrl(baseUrl);
|
||||
m_client->setApiKey(apiKey());
|
||||
return m_client->listModels().then([](const QList<QString> &allModels) {
|
||||
QList<QString> filtered;
|
||||
for (const QString &modelId : allModels) {
|
||||
if (!modelId.contains("dall-e") && !modelId.contains("whisper")
|
||||
&& !modelId.contains("tts") && !modelId.contains("davinci")
|
||||
&& !modelId.contains("babbage") && !modelId.contains("omni")) {
|
||||
filtered.append(modelId);
|
||||
}
|
||||
}
|
||||
return filtered;
|
||||
});
|
||||
}
|
||||
|
||||
Providers::ProviderID OpenAIProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::OpenAI;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities OpenAIProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Image
|
||||
| Providers::ProviderCapability::ModelListing
|
||||
| Providers::ProviderCapability::Thinking;
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *OpenAIProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
38
sources/providers/OpenAIProvider.hpp
Normal file
38
sources/providers/OpenAIProvider.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LLMQore/OpenAIClient.hpp>
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class OpenAIProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OpenAIProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
private:
|
||||
::LLMQore::OpenAIClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
149
sources/providers/OpenAIResponsesProvider.cpp
Normal file
149
sources/providers/OpenAIResponsesProvider.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "OpenAIResponsesProvider.hpp"
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
OpenAIResponsesProvider::OpenAIResponsesProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::OpenAIResponsesClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString OpenAIResponsesProvider::name() const
|
||||
{
|
||||
return "OpenAI (Responses API)";
|
||||
}
|
||||
|
||||
QString OpenAIResponsesProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().openAiApiKey();
|
||||
}
|
||||
|
||||
QString OpenAIResponsesProvider::url() const
|
||||
{
|
||||
return "https://api.openai.com/v1";
|
||||
}
|
||||
|
||||
void OpenAIResponsesProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
request["max_output_tokens"] = settings.maxTokens();
|
||||
|
||||
if (settings.useTopP()) {
|
||||
request["top_p"] = settings.topP();
|
||||
}
|
||||
};
|
||||
|
||||
auto applyThinkingMode = [&request](const auto &settings) {
|
||||
QString effortStr = settings.openAIResponsesReasoningEffort.stringValue().toLower();
|
||||
if (effortStr.isEmpty()) {
|
||||
effortStr = "medium";
|
||||
}
|
||||
|
||||
QJsonObject reasoning;
|
||||
reasoning["effort"] = effortStr;
|
||||
request["reasoning"] = reasoning;
|
||||
request["max_output_tokens"] = settings.thinkingMaxTokens();
|
||||
request["store"] = true;
|
||||
|
||||
QJsonArray include;
|
||||
include.append("reasoning.encrypted_content");
|
||||
request["include"] = include;
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
const auto &qrSettings = Settings::quickRefactorSettings();
|
||||
applyModelParams(qrSettings);
|
||||
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode(qrSettings);
|
||||
}
|
||||
} else {
|
||||
const auto &chatSettings = Settings::chatAssistantSettings();
|
||||
applyModelParams(chatSettings);
|
||||
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode(chatSettings);
|
||||
}
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
const auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(QString("Added %1 tools to OpenAI Responses request")
|
||||
.arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
|
||||
request["stream"] = true;
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> OpenAIResponsesProvider::getInstalledModels(const QString &baseUrl)
|
||||
{
|
||||
m_client->setUrl(baseUrl);
|
||||
m_client->setApiKey(apiKey());
|
||||
return m_client->listModels().then([](const QList<QString> &models) {
|
||||
QList<QString> filtered;
|
||||
static const QStringList modelPrefixes = {"gpt-5", "o1", "o2", "o3", "o4"};
|
||||
for (const QString &modelId : models) {
|
||||
for (const QString &prefix : modelPrefixes) {
|
||||
if (modelId.contains(prefix)) {
|
||||
filtered.append(modelId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return filtered;
|
||||
});
|
||||
}
|
||||
|
||||
Providers::ProviderID OpenAIResponsesProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::OpenAIResponses;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities OpenAIResponsesProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Thinking
|
||||
| Providers::ProviderCapability::Image
|
||||
| Providers::ProviderCapability::ModelListing;
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *OpenAIResponsesProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
38
sources/providers/OpenAIResponsesProvider.hpp
Normal file
38
sources/providers/OpenAIResponsesProvider.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LLMQore/OpenAIResponsesClient.hpp>
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class OpenAIResponsesProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OpenAIResponsesProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
private:
|
||||
::LLMQore::OpenAIResponsesClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
40
sources/providers/OpenRouterAIProvider.cpp
Normal file
40
sources/providers/OpenRouterAIProvider.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "OpenRouterAIProvider.hpp"
|
||||
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
OpenRouterProvider::OpenRouterProvider(QObject *parent)
|
||||
: OpenAICompatProvider(parent)
|
||||
{}
|
||||
|
||||
QString OpenRouterProvider::name() const
|
||||
{
|
||||
return "OpenRouter";
|
||||
}
|
||||
|
||||
QString OpenRouterProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().openRouterApiKey();
|
||||
}
|
||||
|
||||
QString OpenRouterProvider::url() const
|
||||
{
|
||||
return "https://openrouter.ai/api";
|
||||
}
|
||||
|
||||
Providers::ProviderID OpenRouterProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::OpenRouter;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
22
sources/providers/OpenRouterAIProvider.hpp
Normal file
22
sources/providers/OpenRouterAIProvider.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "providers/OpenAICompatProvider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class OpenRouterProvider : public OpenAICompatProvider
|
||||
{
|
||||
public:
|
||||
explicit OpenRouterProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
QString apiKey() const override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
50
sources/providers/Provider.cpp
Normal file
50
sources/providers/Provider.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
#include <LLMQore/BaseClient.hpp>
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "logger/Logger.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
Provider::Provider(QObject *parent)
|
||||
: QObject(parent)
|
||||
{}
|
||||
|
||||
LLMQore::RequestID Provider::sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint)
|
||||
{
|
||||
auto *c = client();
|
||||
|
||||
c->setUrl(url.toString());
|
||||
c->setApiKey(apiKey());
|
||||
|
||||
auto requestId = c->sendMessage(payload, endpoint);
|
||||
|
||||
LOG_MESSAGE(
|
||||
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;
|
||||
}
|
||||
|
||||
void Provider::cancelRequest(const LLMQore::RequestID &requestId)
|
||||
{
|
||||
LOG_MESSAGE(QString("%1: Cancelling request %2").arg(name(), requestId));
|
||||
client()->cancelRequest(requestId);
|
||||
}
|
||||
|
||||
::LLMQore::ToolsManager *Provider::toolsManager() const
|
||||
{
|
||||
return client()->tools();
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
67
sources/providers/Provider.hpp
Normal file
67
sources/providers/Provider.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QFlags>
|
||||
#include <QFuture>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <utils/environment.h>
|
||||
|
||||
#include "llmcore/ContextData.hpp"
|
||||
#include "templates/PromptTemplate.hpp"
|
||||
#include "LLMQore/BaseClient.hpp"
|
||||
#include "llmcore/RequestType.hpp"
|
||||
|
||||
namespace LLMQore {
|
||||
class BaseClient;
|
||||
class ToolsManager;
|
||||
}
|
||||
|
||||
class QJsonObject;
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
enum class ProviderCapability {
|
||||
Tools = 0x1,
|
||||
Thinking = 0x2,
|
||||
Image = 0x4,
|
||||
ModelListing = 0x8,
|
||||
};
|
||||
Q_DECLARE_FLAGS(ProviderCapabilities, ProviderCapability)
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(ProviderCapabilities)
|
||||
|
||||
class Provider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Provider(QObject *parent = nullptr);
|
||||
|
||||
virtual ~Provider() = default;
|
||||
|
||||
virtual QString name() const = 0;
|
||||
virtual QString url() const = 0;
|
||||
virtual void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
= 0;
|
||||
virtual QFuture<QList<QString>> getInstalledModels(const QString &url) = 0;
|
||||
virtual ProviderID providerID() const = 0;
|
||||
virtual ProviderCapabilities capabilities() const { return {}; }
|
||||
|
||||
virtual ::LLMQore::BaseClient *client() const = 0;
|
||||
virtual QString apiKey() const = 0;
|
||||
|
||||
virtual LLMQore::RequestID sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint);
|
||||
void cancelRequest(const LLMQore::RequestID &requestId);
|
||||
::LLMQore::ToolsManager *toolsManager() const;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
22
sources/providers/ProviderID.hpp
Normal file
22
sources/providers/ProviderID.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
enum class ProviderID {
|
||||
Any,
|
||||
Ollama,
|
||||
LMStudio,
|
||||
Claude,
|
||||
OpenAI,
|
||||
OpenAICompatible,
|
||||
OpenAIResponses,
|
||||
MistralAI,
|
||||
OpenRouter,
|
||||
GoogleAI,
|
||||
LlamaCpp,
|
||||
Qwen,
|
||||
DeepSeek
|
||||
};
|
||||
}
|
||||
24
sources/providers/ProviderUrlUtils.hpp
Normal file
24
sources/providers/ProviderUrlUtils.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
// LM Studio presents its OpenAI-compatible API as <host>/v1/..., while the
|
||||
// OpenAI-style clients expect the base URL to already include /v1. Accept the
|
||||
// configured URL either with or without the /v1 suffix and return it normalized.
|
||||
inline QString ensureOpenAIV1Base(const QString &url)
|
||||
{
|
||||
QString base = url.trimmed();
|
||||
while (base.endsWith(QLatin1Char('/')))
|
||||
base.chop(1);
|
||||
if (!base.endsWith(QStringLiteral("/v1")))
|
||||
base += QStringLiteral("/v1");
|
||||
return base;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
48
sources/providers/Providers.hpp
Normal file
48
sources/providers/Providers.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "providers/ProvidersManager.hpp"
|
||||
#include "providers/ClaudeProvider.hpp"
|
||||
#include "providers/DeepSeekProvider.hpp"
|
||||
#include "providers/CodestralProvider.hpp"
|
||||
#include "providers/GoogleAIProvider.hpp"
|
||||
#include "providers/LMStudioProvider.hpp"
|
||||
#include "providers/LMStudioResponsesProvider.hpp"
|
||||
#include "providers/LlamaCppProvider.hpp"
|
||||
#include "providers/MistralAIProvider.hpp"
|
||||
#include "providers/OllamaCompatProvider.hpp"
|
||||
#include "providers/OllamaProvider.hpp"
|
||||
#include "providers/OpenAICompatProvider.hpp"
|
||||
#include "providers/OpenAIProvider.hpp"
|
||||
#include "providers/OpenAIResponsesProvider.hpp"
|
||||
#include "providers/OpenRouterAIProvider.hpp"
|
||||
#include "providers/QwenProvider.hpp"
|
||||
#include "providers/QwenResponsesProvider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
inline void registerProviders()
|
||||
{
|
||||
auto &providerManager = Providers::ProvidersManager::instance();
|
||||
providerManager.registerProvider<OllamaProvider>();
|
||||
providerManager.registerProvider<OllamaCompatProvider>();
|
||||
providerManager.registerProvider<ClaudeProvider>();
|
||||
providerManager.registerProvider<OpenAIProvider>();
|
||||
providerManager.registerProvider<OpenAIResponsesProvider>();
|
||||
providerManager.registerProvider<OpenAICompatProvider>();
|
||||
providerManager.registerProvider<LMStudioProvider>();
|
||||
providerManager.registerProvider<LMStudioResponsesProvider>();
|
||||
providerManager.registerProvider<OpenRouterProvider>();
|
||||
providerManager.registerProvider<MistralAIProvider>();
|
||||
providerManager.registerProvider<GoogleAIProvider>();
|
||||
providerManager.registerProvider<LlamaCppProvider>();
|
||||
providerManager.registerProvider<CodestralProvider>();
|
||||
providerManager.registerProvider<QwenProvider>();
|
||||
providerManager.registerProvider<QwenResponsesProvider>();
|
||||
providerManager.registerProvider<DeepSeekProvider>();
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
32
sources/providers/ProvidersManager.cpp
Normal file
32
sources/providers/ProvidersManager.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "providers/ProvidersManager.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
ProvidersManager &ProvidersManager::instance()
|
||||
{
|
||||
static ProvidersManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
QStringList ProvidersManager::providersNames() const
|
||||
{
|
||||
return m_providers.keys();
|
||||
}
|
||||
|
||||
ProvidersManager::~ProvidersManager()
|
||||
{
|
||||
qDeleteAll(m_providers);
|
||||
}
|
||||
|
||||
Provider *ProvidersManager::getProviderByName(const QString &providerName)
|
||||
{
|
||||
if (!m_providers.contains(providerName))
|
||||
return m_providers.first();
|
||||
return m_providers[providerName];
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
41
sources/providers/ProvidersManager.hpp
Normal file
41
sources/providers/ProvidersManager.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "providers/IProviderRegistry.hpp"
|
||||
#include <QMap>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class ProvidersManager : public IProviderRegistry
|
||||
{
|
||||
public:
|
||||
static ProvidersManager &instance();
|
||||
~ProvidersManager();
|
||||
|
||||
template<typename T>
|
||||
void registerProvider()
|
||||
{
|
||||
static_assert(std::is_base_of<Provider, T>::value, "T must inherit from Provider");
|
||||
T *provider = new T();
|
||||
QString name = provider->name();
|
||||
m_providers[name] = provider;
|
||||
}
|
||||
|
||||
Provider *getProviderByName(const QString &providerName) override;
|
||||
|
||||
QStringList providersNames() const override;
|
||||
|
||||
private:
|
||||
ProvidersManager() = default;
|
||||
ProvidersManager(const ProvidersManager &) = delete;
|
||||
ProvidersManager &operator=(const ProvidersManager &) = delete;
|
||||
|
||||
QMap<QString, Provider *> m_providers;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
113
sources/providers/QwenProvider.cpp
Normal file
113
sources/providers/QwenProvider.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "QwenProvider.hpp"
|
||||
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
QwenProvider::QwenProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::OpenAIClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString QwenProvider::name() const
|
||||
{
|
||||
return "Qwen (OpenAI)";
|
||||
}
|
||||
|
||||
QString QwenProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().qwenApiKey();
|
||||
}
|
||||
|
||||
QString QwenProvider::url() const
|
||||
{
|
||||
return "https://dashscope-intl.aliyuncs.com/compatible-mode/v1";
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> QwenProvider::getInstalledModels(const QString &url)
|
||||
{
|
||||
m_client->setUrl(url);
|
||||
m_client->setApiKey(apiKey());
|
||||
return m_client->listModels();
|
||||
}
|
||||
|
||||
Providers::ProviderID QwenProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::Qwen;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities QwenProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Image
|
||||
| Providers::ProviderCapability::Thinking
|
||||
| Providers::ProviderCapability::ModelListing;
|
||||
}
|
||||
|
||||
void QwenProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
request["max_tokens"] = settings.maxTokens();
|
||||
request["temperature"] = settings.temperature();
|
||||
|
||||
if (settings.useTopP())
|
||||
request["top_p"] = settings.topP();
|
||||
if (settings.useTopK())
|
||||
request["top_k"] = settings.topK();
|
||||
if (settings.useFrequencyPenalty())
|
||||
request["frequency_penalty"] = settings.frequencyPenalty();
|
||||
if (settings.usePresencePenalty())
|
||||
request["presence_penalty"] = settings.presencePenalty();
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
applyModelParams(Settings::quickRefactorSettings());
|
||||
} else {
|
||||
applyModelParams(Settings::chatAssistantSettings());
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(QString("Added %1 tools to Qwen request").arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *QwenProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
38
sources/providers/QwenProvider.hpp
Normal file
38
sources/providers/QwenProvider.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LLMQore/OpenAIClient.hpp>
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class QwenProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QwenProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
private:
|
||||
::LLMQore::OpenAIClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
136
sources/providers/QwenResponsesProvider.cpp
Normal file
136
sources/providers/QwenResponsesProvider.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#include "QwenResponsesProvider.hpp"
|
||||
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
#include "logger/Logger.hpp"
|
||||
#include "settings/ChatAssistantSettings.hpp"
|
||||
#include "settings/CodeCompletionSettings.hpp"
|
||||
#include "settings/GeneralSettings.hpp"
|
||||
#include "settings/ProviderSettings.hpp"
|
||||
#include "settings/QuickRefactorSettings.hpp"
|
||||
#include "tools/ToolsRegistration.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
QwenResponsesProvider::QwenResponsesProvider(QObject *parent)
|
||||
: Providers::Provider(parent)
|
||||
, m_client(new ::LLMQore::OpenAIResponsesClient(QString(), QString(), QString(), this))
|
||||
{
|
||||
Tools::registerQodeAssistTools(m_client->tools());
|
||||
}
|
||||
|
||||
QString QwenResponsesProvider::name() const
|
||||
{
|
||||
return "Qwen (OpenAI Response)";
|
||||
}
|
||||
|
||||
QString QwenResponsesProvider::apiKey() const
|
||||
{
|
||||
return Settings::providerSettings().qwenApiKey();
|
||||
}
|
||||
|
||||
QString QwenResponsesProvider::url() const
|
||||
{
|
||||
return "https://dashscope-intl.aliyuncs.com/compatible-mode/v1";
|
||||
}
|
||||
|
||||
void QwenResponsesProvider::prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled)
|
||||
{
|
||||
if (!prompt->isSupportProvider(providerID())) {
|
||||
LOG_MESSAGE(QString("Template %1 doesn't support %2 provider").arg(name(), prompt->name()));
|
||||
}
|
||||
|
||||
prompt->prepareRequest(request, context);
|
||||
|
||||
auto applyModelParams = [&request](const auto &settings) {
|
||||
request["max_output_tokens"] = settings.maxTokens();
|
||||
|
||||
if (settings.useTopP()) {
|
||||
request["top_p"] = settings.topP();
|
||||
}
|
||||
};
|
||||
|
||||
auto applyThinkingMode = [&request](const auto &settings) {
|
||||
QString effortStr = settings.openAIResponsesReasoningEffort.stringValue().toLower();
|
||||
if (effortStr.isEmpty()) {
|
||||
effortStr = "medium";
|
||||
}
|
||||
|
||||
QJsonObject reasoning;
|
||||
reasoning["effort"] = effortStr;
|
||||
request["reasoning"] = reasoning;
|
||||
request["max_output_tokens"] = settings.thinkingMaxTokens();
|
||||
request["store"] = true;
|
||||
|
||||
QJsonArray include;
|
||||
include.append("reasoning.encrypted_content");
|
||||
request["include"] = include;
|
||||
};
|
||||
|
||||
if (type == LLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == LLMCore::RequestType::QuickRefactoring) {
|
||||
const auto &qrSettings = Settings::quickRefactorSettings();
|
||||
applyModelParams(qrSettings);
|
||||
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode(qrSettings);
|
||||
}
|
||||
} else {
|
||||
const auto &chatSettings = Settings::chatAssistantSettings();
|
||||
applyModelParams(chatSettings);
|
||||
|
||||
if (isThinkingEnabled) {
|
||||
applyThinkingMode(chatSettings);
|
||||
}
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
const auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(
|
||||
QString("Added %1 tools to Qwen Responses request").arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
|
||||
request["stream"] = true;
|
||||
}
|
||||
|
||||
QFuture<QList<QString>> QwenResponsesProvider::getInstalledModels(const QString &url)
|
||||
{
|
||||
m_client->setUrl(url);
|
||||
m_client->setApiKey(apiKey());
|
||||
return m_client->listModels();
|
||||
}
|
||||
|
||||
Providers::ProviderID QwenResponsesProvider::providerID() const
|
||||
{
|
||||
return Providers::ProviderID::OpenAIResponses;
|
||||
}
|
||||
|
||||
Providers::ProviderCapabilities QwenResponsesProvider::capabilities() const
|
||||
{
|
||||
return Providers::ProviderCapability::Tools | Providers::ProviderCapability::Thinking
|
||||
| Providers::ProviderCapability::Image | Providers::ProviderCapability::ModelListing;
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *QwenResponsesProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
38
sources/providers/QwenResponsesProvider.hpp
Normal file
38
sources/providers/QwenResponsesProvider.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LLMQore/OpenAIResponsesClient.hpp>
|
||||
#include "providers/Provider.hpp"
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class QwenResponsesProvider : public Providers::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QwenResponsesProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
Templates::PromptTemplate *prompt,
|
||||
LLMCore::ContextData context,
|
||||
LLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
Providers::ProviderID providerID() const override;
|
||||
Providers::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
private:
|
||||
::LLMQore::OpenAIResponsesClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
Reference in New Issue
Block a user