mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-05-30 02:49:12 -04:00
feat: LM Studio response API and Ollama OpenAI API
This commit is contained in:
@@ -96,10 +96,12 @@ add_qtc_plugin(QodeAssist
|
||||
templates/OpenAIResponses.hpp
|
||||
providers/Providers.hpp
|
||||
providers/OllamaProvider.hpp providers/OllamaProvider.cpp
|
||||
providers/OllamaCompatProvider.hpp providers/OllamaCompatProvider.cpp
|
||||
providers/ClaudeProvider.hpp providers/ClaudeProvider.cpp
|
||||
providers/OpenAIProvider.hpp providers/OpenAIProvider.cpp
|
||||
providers/MistralAIProvider.hpp providers/MistralAIProvider.cpp
|
||||
providers/LMStudioProvider.hpp providers/LMStudioProvider.cpp
|
||||
providers/LMStudioResponsesProvider.hpp providers/LMStudioResponsesProvider.cpp
|
||||
providers/OpenAICompatProvider.hpp providers/OpenAICompatProvider.cpp
|
||||
providers/OpenRouterAIProvider.hpp providers/OpenRouterAIProvider.cpp
|
||||
providers/GoogleAIProvider.hpp providers/GoogleAIProvider.cpp
|
||||
|
||||
@@ -452,10 +452,8 @@ void ClientInterface::handleRequestFailed(const QString &requestId, const QStrin
|
||||
if (it == m_activeRequests.end())
|
||||
return;
|
||||
|
||||
QString enriched = it->provider ? it->provider->enrichErrorMessage(error) : error;
|
||||
|
||||
LOG_MESSAGE(QString("Chat request %1 failed: %2").arg(requestId, enriched));
|
||||
emit errorOccurred(enriched);
|
||||
LOG_MESSAGE(QString("Chat request %1 failed: %2").arg(requestId, error));
|
||||
emit errorOccurred(error);
|
||||
|
||||
m_activeRequests.erase(it);
|
||||
m_accumulatedResponses.remove(requestId);
|
||||
|
||||
@@ -70,9 +70,8 @@ void LLMClientInterface::handleRequestFailed(const QString &requestId, const QSt
|
||||
return;
|
||||
|
||||
const RequestContext &ctx = it.value();
|
||||
QString enriched = ctx.provider ? ctx.provider->enrichErrorMessage(error) : error;
|
||||
|
||||
LOG_MESSAGE(QString("Request %1 failed: %2").arg(requestId, enriched));
|
||||
LOG_MESSAGE(QString("Request %1 failed: %2").arg(requestId, error));
|
||||
|
||||
// Send LSP error response to client
|
||||
QJsonObject response;
|
||||
@@ -81,7 +80,7 @@ void LLMClientInterface::handleRequestFailed(const QString &requestId, const QSt
|
||||
|
||||
QJsonObject errorObject;
|
||||
errorObject["code"] = -32603; // Internal error code
|
||||
errorObject["message"] = enriched;
|
||||
errorObject["message"] = error;
|
||||
response["error"] = errorObject;
|
||||
|
||||
emit messageReceived(LanguageServerProtocol::JsonRpcMessage(response));
|
||||
|
||||
@@ -407,16 +407,11 @@ void QuickRefactorHandler::handleFullResponse(const QString &requestId, const QS
|
||||
void QuickRefactorHandler::handleRequestFailed(const QString &requestId, const QString &error)
|
||||
{
|
||||
if (requestId == m_lastRequestId) {
|
||||
auto it = m_activeRequests.find(requestId);
|
||||
QString enriched = (it != m_activeRequests.end() && it->provider)
|
||||
? it->provider->enrichErrorMessage(error)
|
||||
: error;
|
||||
|
||||
m_activeRequests.remove(requestId);
|
||||
m_isRefactoringInProgress = false;
|
||||
RefactorResult result;
|
||||
result.success = false;
|
||||
result.errorMessage = enriched;
|
||||
result.errorMessage = error;
|
||||
result.editor = m_currentEditor;
|
||||
emit refactoringCompleted(result);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
#include "Provider.hpp"
|
||||
|
||||
#include <LLMQore/BaseClient.hpp>
|
||||
#include <LLMQore/LlamaCppClient.hpp>
|
||||
#include <LLMQore/MistralClient.hpp>
|
||||
#include <LLMQore/OpenAIClient.hpp>
|
||||
#include <LLMQore/OpenAIResponsesClient.hpp>
|
||||
#include <LLMQore/ToolsManager.hpp>
|
||||
|
||||
#include <QJsonDocument>
|
||||
@@ -50,30 +46,4 @@ void Provider::cancelRequest(const RequestID &requestId)
|
||||
return client()->tools();
|
||||
}
|
||||
|
||||
QString Provider::enrichErrorMessage(const QString &error) const
|
||||
{
|
||||
auto *c = client();
|
||||
|
||||
if (qobject_cast<::LLMQore::MistralClient *>(c))
|
||||
return error;
|
||||
|
||||
const bool isOpenAICompatible = qobject_cast<::LLMQore::OpenAIClient *>(c)
|
||||
|| qobject_cast<::LLMQore::OpenAIResponsesClient *>(c)
|
||||
|| qobject_cast<::LLMQore::LlamaCppClient *>(c);
|
||||
if (!isOpenAICompatible)
|
||||
return error;
|
||||
|
||||
const QString baseUrl = c->url();
|
||||
const QString path = QUrl(baseUrl).path();
|
||||
const bool hasV1Segment = path.contains("/v1/") || path.endsWith("/v1");
|
||||
if (hasV1Segment)
|
||||
return error;
|
||||
|
||||
return error
|
||||
+ tr("\n\nHint: Your base URL (%1) does not contain a '/v1' path segment. "
|
||||
"Most OpenAI-compatible servers require it (e.g., %1/v1). "
|
||||
"Try updating the URL in settings.")
|
||||
.arg(baseUrl);
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::PluginLLMCore
|
||||
|
||||
@@ -60,8 +60,6 @@ public:
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint);
|
||||
void cancelRequest(const RequestID &requestId);
|
||||
::LLMQore::ToolsManager *toolsManager() const;
|
||||
|
||||
QString enrichErrorMessage(const QString &error) const;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::PluginLLMCore
|
||||
|
||||
@@ -28,7 +28,7 @@ LMStudioProvider::LMStudioProvider(QObject *parent)
|
||||
|
||||
QString LMStudioProvider::name() const
|
||||
{
|
||||
return "LM Studio";
|
||||
return "LM Studio (Chat Completions)";
|
||||
}
|
||||
|
||||
QString LMStudioProvider::apiKey() const
|
||||
|
||||
148
providers/LMStudioResponsesProvider.cpp
Normal file
148
providers/LMStudioResponsesProvider.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "LMStudioResponsesProvider.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 {
|
||||
|
||||
LMStudioResponsesProvider::LMStudioResponsesProvider(QObject *parent)
|
||||
: PluginLLMCore::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,
|
||||
PluginLLMCore::PromptTemplate *prompt,
|
||||
PluginLLMCore::ContextData context,
|
||||
PluginLLMCore::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 == PluginLLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == PluginLLMCore::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)
|
||||
{
|
||||
QString url = baseUrl;
|
||||
if (!url.endsWith(QStringLiteral("/v1")))
|
||||
url += QStringLiteral("/v1");
|
||||
m_client->setUrl(url);
|
||||
m_client->setApiKey(apiKey());
|
||||
return m_client->listModels();
|
||||
}
|
||||
|
||||
PluginLLMCore::RequestID LMStudioResponsesProvider::sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint)
|
||||
{
|
||||
const QString effectiveEndpoint
|
||||
= endpoint.isEmpty() ? QStringLiteral("/v1/responses") : endpoint;
|
||||
return PluginLLMCore::Provider::sendRequest(url, payload, effectiveEndpoint);
|
||||
}
|
||||
|
||||
PluginLLMCore::ProviderID LMStudioResponsesProvider::providerID() const
|
||||
{
|
||||
return PluginLLMCore::ProviderID::OpenAIResponses;
|
||||
}
|
||||
|
||||
PluginLLMCore::ProviderCapabilities LMStudioResponsesProvider::capabilities() const
|
||||
{
|
||||
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Thinking
|
||||
| PluginLLMCore::ProviderCapability::Image
|
||||
| PluginLLMCore::ProviderCapability::ModelListing;
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *LMStudioResponsesProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
40
providers/LMStudioResponsesProvider.hpp
Normal file
40
providers/LMStudioResponsesProvider.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LLMQore/OpenAIResponsesClient.hpp>
|
||||
#include <pluginllmcore/Provider.hpp>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class LMStudioResponsesProvider : public PluginLLMCore::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LMStudioResponsesProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
PluginLLMCore::PromptTemplate *prompt,
|
||||
PluginLLMCore::ContextData context,
|
||||
PluginLLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
PluginLLMCore::ProviderID providerID() const override;
|
||||
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
PluginLLMCore::RequestID sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint) override;
|
||||
|
||||
private:
|
||||
::LLMQore::OpenAIResponsesClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
124
providers/OllamaCompatProvider.cpp
Normal file
124
providers/OllamaCompatProvider.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#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)
|
||||
: PluginLLMCore::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,
|
||||
PluginLLMCore::PromptTemplate *prompt,
|
||||
PluginLLMCore::ContextData context,
|
||||
PluginLLMCore::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 == PluginLLMCore::RequestType::CodeCompletion) {
|
||||
applyModelParams(Settings::codeCompletionSettings());
|
||||
} else if (type == PluginLLMCore::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();
|
||||
}
|
||||
|
||||
PluginLLMCore::RequestID OllamaCompatProvider::sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint)
|
||||
{
|
||||
const QString effectiveEndpoint
|
||||
= endpoint.isEmpty() ? QStringLiteral("/v1/chat/completions") : endpoint;
|
||||
return PluginLLMCore::Provider::sendRequest(url, payload, effectiveEndpoint);
|
||||
}
|
||||
|
||||
PluginLLMCore::ProviderID OllamaCompatProvider::providerID() const
|
||||
{
|
||||
return PluginLLMCore::ProviderID::OpenAICompatible;
|
||||
}
|
||||
|
||||
PluginLLMCore::ProviderCapabilities OllamaCompatProvider::capabilities() const
|
||||
{
|
||||
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
|
||||
| PluginLLMCore::ProviderCapability::ModelListing;
|
||||
}
|
||||
|
||||
::LLMQore::BaseClient *OllamaCompatProvider::client() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
40
providers/OllamaCompatProvider.hpp
Normal file
40
providers/OllamaCompatProvider.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LLMQore/OpenAIClient.hpp>
|
||||
#include <pluginllmcore/Provider.hpp>
|
||||
|
||||
namespace QodeAssist::Providers {
|
||||
|
||||
class OllamaCompatProvider : public PluginLLMCore::Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OllamaCompatProvider(QObject *parent = nullptr);
|
||||
|
||||
QString name() const override;
|
||||
QString url() const override;
|
||||
void prepareRequest(
|
||||
QJsonObject &request,
|
||||
PluginLLMCore::PromptTemplate *prompt,
|
||||
PluginLLMCore::ContextData context,
|
||||
PluginLLMCore::RequestType type,
|
||||
bool isToolsEnabled,
|
||||
bool isThinkingEnabled) override;
|
||||
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
|
||||
PluginLLMCore::ProviderID providerID() const override;
|
||||
PluginLLMCore::ProviderCapabilities capabilities() const override;
|
||||
|
||||
::LLMQore::BaseClient *client() const override;
|
||||
QString apiKey() const override;
|
||||
|
||||
PluginLLMCore::RequestID sendRequest(
|
||||
const QUrl &url, const QJsonObject &payload, const QString &endpoint) override;
|
||||
|
||||
private:
|
||||
::LLMQore::OpenAIClient *m_client;
|
||||
};
|
||||
|
||||
} // namespace QodeAssist::Providers
|
||||
@@ -28,7 +28,7 @@ OllamaProvider::OllamaProvider(QObject *parent)
|
||||
|
||||
QString OllamaProvider::name() const
|
||||
{
|
||||
return "Ollama";
|
||||
return "Ollama (Native)";
|
||||
}
|
||||
|
||||
QString OllamaProvider::apiKey() const
|
||||
|
||||
@@ -27,7 +27,7 @@ OpenAIProvider::OpenAIProvider(QObject *parent)
|
||||
|
||||
QString OpenAIProvider::name() const
|
||||
{
|
||||
return "OpenAI";
|
||||
return "OpenAI (Chat Completions)";
|
||||
}
|
||||
|
||||
QString OpenAIProvider::apiKey() const
|
||||
|
||||
@@ -27,7 +27,7 @@ OpenAIResponsesProvider::OpenAIResponsesProvider(QObject *parent)
|
||||
|
||||
QString OpenAIResponsesProvider::name() const
|
||||
{
|
||||
return "OpenAI Responses";
|
||||
return "OpenAI (Responses API)";
|
||||
}
|
||||
|
||||
QString OpenAIResponsesProvider::apiKey() const
|
||||
@@ -98,24 +98,11 @@ void OpenAIResponsesProvider::prepareRequest(
|
||||
}
|
||||
|
||||
if (isToolsEnabled) {
|
||||
const auto toolsDefinitions
|
||||
= m_client->tools()->getToolsDefinitions();
|
||||
const auto toolsDefinitions = m_client->tools()->getToolsDefinitions();
|
||||
if (!toolsDefinitions.isEmpty()) {
|
||||
QJsonArray responsesTools;
|
||||
|
||||
for (const QJsonValue &toolValue : toolsDefinitions) {
|
||||
const QJsonObject tool = toolValue.toObject();
|
||||
if (tool.contains("function")) {
|
||||
const QJsonObject functionObj = tool["function"].toObject();
|
||||
QJsonObject responsesTool;
|
||||
responsesTool["type"] = "function";
|
||||
responsesTool["name"] = functionObj["name"];
|
||||
responsesTool["description"] = functionObj["description"];
|
||||
responsesTool["parameters"] = functionObj["parameters"];
|
||||
responsesTools.append(responsesTool);
|
||||
}
|
||||
}
|
||||
request["tools"] = responsesTools;
|
||||
request["tools"] = toolsDefinitions;
|
||||
LOG_MESSAGE(QString("Added %1 tools to OpenAI Responses request")
|
||||
.arg(toolsDefinitions.size()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
#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"
|
||||
@@ -22,11 +24,13 @@ inline void registerProviders()
|
||||
{
|
||||
auto &providerManager = PluginLLMCore::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>();
|
||||
|
||||
@@ -14,6 +14,7 @@ add_library(QodeAssistSettings STATIC
|
||||
ProjectSettings.hpp ProjectSettings.cpp
|
||||
ProjectSettingsPanel.hpp ProjectSettingsPanel.cpp
|
||||
ProviderSettings.hpp ProviderSettings.cpp
|
||||
ProviderNameMigration.hpp
|
||||
PluginUpdater.hpp PluginUpdater.cpp
|
||||
UpdateDialog.hpp UpdateDialog.cpp
|
||||
AgentRole.hpp AgentRole.cpp
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include "Logger.hpp"
|
||||
#include "ProviderNameMigration.hpp"
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
@@ -101,7 +102,7 @@ QVector<AIConfiguration> ConfigurationManager::getPredefinedConfigurations(
|
||||
AIConfiguration gpt;
|
||||
gpt.id = "preset_gpt";
|
||||
gpt.name = "gpt-5.4";
|
||||
gpt.provider = "OpenAI Responses";
|
||||
gpt.provider = "OpenAI (Responses API)";
|
||||
gpt.model = "gpt-5.4";
|
||||
gpt.url = "https://api.openai.com/v1";
|
||||
gpt.customEndpoint = "";
|
||||
@@ -203,7 +204,7 @@ bool ConfigurationManager::loadConfigurations(ConfigurationType type)
|
||||
AIConfiguration config;
|
||||
config.id = obj["id"].toString();
|
||||
config.name = obj["name"].toString();
|
||||
config.provider = obj["provider"].toString();
|
||||
config.provider = migrateProviderName(obj["provider"].toString());
|
||||
config.model = obj["model"].toString();
|
||||
config.templateName = obj["template"].toString();
|
||||
config.url = obj["url"].toString();
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "../Version.hpp"
|
||||
#include "ConfigurationManager.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "ProviderNameMigration.hpp"
|
||||
#include "SettingsConstants.hpp"
|
||||
#include "SettingsDialog.hpp"
|
||||
#include "SettingsTr.hpp"
|
||||
@@ -95,7 +96,7 @@ GeneralSettings::GeneralSettings()
|
||||
qrConfigureApiKey.m_buttonText = Tr::tr("Configure API Key");
|
||||
qrConfigureApiKey.m_tooltip = Tr::tr("Open Provider Settings to configure API keys");
|
||||
|
||||
initStringAspect(ccProvider, Constants::CC_PROVIDER, TrConstants::PROVIDER, "Ollama");
|
||||
initStringAspect(ccProvider, Constants::CC_PROVIDER, TrConstants::PROVIDER, "Ollama (Native)");
|
||||
ccProvider.setReadOnly(true);
|
||||
ccSelectProvider.m_buttonText = TrConstants::SELECT;
|
||||
|
||||
@@ -143,7 +144,10 @@ GeneralSettings::GeneralSettings()
|
||||
preset1Language.addOption("python");
|
||||
|
||||
initStringAspect(
|
||||
ccPreset1Provider, Constants::CC_PRESET1_PROVIDER, TrConstants::PROVIDER, "Ollama");
|
||||
ccPreset1Provider,
|
||||
Constants::CC_PRESET1_PROVIDER,
|
||||
TrConstants::PROVIDER,
|
||||
"Ollama (Native)");
|
||||
ccPreset1Provider.setReadOnly(true);
|
||||
ccPreset1SelectProvider.m_buttonText = TrConstants::SELECT;
|
||||
|
||||
@@ -170,7 +174,7 @@ GeneralSettings::GeneralSettings()
|
||||
ccPreset1SelectTemplate.m_buttonText = TrConstants::SELECT;
|
||||
|
||||
// chat assistance
|
||||
initStringAspect(caProvider, Constants::CA_PROVIDER, TrConstants::PROVIDER, "Ollama");
|
||||
initStringAspect(caProvider, Constants::CA_PROVIDER, TrConstants::PROVIDER, "Ollama (Native)");
|
||||
caProvider.setReadOnly(true);
|
||||
caSelectProvider.m_buttonText = TrConstants::SELECT;
|
||||
|
||||
@@ -207,7 +211,7 @@ GeneralSettings::GeneralSettings()
|
||||
caOpenConfigFolder.m_isCompact = true;
|
||||
|
||||
// quick refactor settings
|
||||
initStringAspect(qrProvider, Constants::QR_PROVIDER, TrConstants::PROVIDER, "Ollama");
|
||||
initStringAspect(qrProvider, Constants::QR_PROVIDER, TrConstants::PROVIDER, "Ollama (Native)");
|
||||
qrProvider.setReadOnly(true);
|
||||
qrSelectProvider.m_buttonText = TrConstants::SELECT;
|
||||
|
||||
@@ -257,6 +261,17 @@ GeneralSettings::GeneralSettings()
|
||||
|
||||
readSettings();
|
||||
|
||||
auto migrateProviderAspect = [](Utils::StringAspect &aspect) {
|
||||
const QString migrated = migrateProviderName(aspect.value());
|
||||
if (migrated != aspect.value())
|
||||
aspect.setValue(migrated);
|
||||
};
|
||||
migrateProviderAspect(ccProvider);
|
||||
migrateProviderAspect(ccPreset1Provider);
|
||||
migrateProviderAspect(caProvider);
|
||||
migrateProviderAspect(qrProvider);
|
||||
writeSettings();
|
||||
|
||||
Logger::instance().setLoggingEnabled(enableLogging());
|
||||
|
||||
setupConnections();
|
||||
|
||||
29
settings/ProviderNameMigration.hpp
Normal file
29
settings/ProviderNameMigration.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2024-2026 Petr Mironychev
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QHash>
|
||||
#include <QString>
|
||||
|
||||
namespace QodeAssist::Settings {
|
||||
|
||||
// Maps legacy provider names (used before multi-API providers were introduced
|
||||
// with parenthetical suffixes) to their current canonical names. Returns the
|
||||
// input unchanged if it is not a known legacy name.
|
||||
inline QString migrateProviderName(const QString &oldName)
|
||||
{
|
||||
static const QHash<QString, QString> renames{
|
||||
{QStringLiteral("Ollama"), QStringLiteral("Ollama (Native)")},
|
||||
{QStringLiteral("Ollama Compatible"), QStringLiteral("Ollama (OpenAI-compatible)")},
|
||||
{QStringLiteral("OpenAI"), QStringLiteral("OpenAI (Chat Completions)")},
|
||||
{QStringLiteral("OpenAI Responses"), QStringLiteral("OpenAI (Responses API)")},
|
||||
{QStringLiteral("LM Studio"), QStringLiteral("LM Studio (Chat Completions)")},
|
||||
{QStringLiteral("LM Studio Responses"), QStringLiteral("LM Studio (Responses API)")},
|
||||
};
|
||||
|
||||
const auto it = renames.constFind(oldName);
|
||||
return it != renames.constEnd() ? it.value() : oldName;
|
||||
}
|
||||
|
||||
} // namespace QodeAssist::Settings
|
||||
Reference in New Issue
Block a user