mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-06-13 17:59:15 -04:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcf5796ad7 | ||
|
|
033c0e8652 | ||
|
|
ea67ba0e2a | ||
|
|
0cf915c4a5 | ||
|
|
99caa853d5 | ||
|
|
278624d412 | ||
|
|
f8adf4d264 | ||
|
|
bfcd8dc1fb | ||
|
|
33321b2499 | ||
|
|
362533a5c0 |
@@ -116,6 +116,9 @@ add_qtc_plugin(QodeAssist
|
|||||||
providers/LlamaCppProvider.hpp providers/LlamaCppProvider.cpp
|
providers/LlamaCppProvider.hpp providers/LlamaCppProvider.cpp
|
||||||
providers/CodestralProvider.hpp providers/CodestralProvider.cpp
|
providers/CodestralProvider.hpp providers/CodestralProvider.cpp
|
||||||
providers/OpenAIResponsesProvider.hpp providers/OpenAIResponsesProvider.cpp
|
providers/OpenAIResponsesProvider.hpp providers/OpenAIResponsesProvider.cpp
|
||||||
|
providers/QwenProvider.hpp providers/QwenProvider.cpp
|
||||||
|
providers/QwenResponsesProvider.hpp providers/QwenResponsesProvider.cpp
|
||||||
|
providers/DeepSeekProvider.hpp providers/DeepSeekProvider.cpp
|
||||||
QodeAssist.qrc
|
QodeAssist.qrc
|
||||||
LSPCompletion.hpp
|
LSPCompletion.hpp
|
||||||
LLMSuggestion.hpp LLMSuggestion.cpp
|
LLMSuggestion.hpp LLMSuggestion.cpp
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"Id" : "qodeassist",
|
"Id" : "qodeassist",
|
||||||
"Name" : "QodeAssist",
|
"Name" : "QodeAssist",
|
||||||
"Version" : "0.9.17",
|
"Version" : "0.9.18",
|
||||||
"CompatVersion" : "${IDE_VERSION}",
|
"CompatVersion" : "${IDE_VERSION}",
|
||||||
"Vendor" : "Petr Mironychev",
|
"Vendor" : "Petr Mironychev",
|
||||||
"VendorId" : "petrmironychev",
|
"VendorId" : "petrmironychev",
|
||||||
|
|||||||
@@ -385,26 +385,26 @@ void QuickRefactorHandler::handleLLMResponse(
|
|||||||
|
|
||||||
void QuickRefactorHandler::cancelRequest()
|
void QuickRefactorHandler::cancelRequest()
|
||||||
{
|
{
|
||||||
if (m_isRefactoringInProgress) {
|
if (!m_isRefactoringInProgress)
|
||||||
auto id = m_lastRequestId;
|
return;
|
||||||
|
|
||||||
for (auto it = m_activeRequests.begin(); it != m_activeRequests.end(); ++it) {
|
|
||||||
if (it.key() == id) {
|
|
||||||
const RequestContext &ctx = it.value();
|
|
||||||
ctx.provider->cancelRequest(id);
|
|
||||||
m_activeRequests.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const auto id = m_lastRequestId;
|
||||||
m_isRefactoringInProgress = false;
|
m_isRefactoringInProgress = false;
|
||||||
|
m_lastRequestId.clear();
|
||||||
|
|
||||||
|
auto it = m_activeRequests.find(id);
|
||||||
|
if (it != m_activeRequests.end()) {
|
||||||
|
auto provider = it.value().provider;
|
||||||
|
m_activeRequests.erase(it);
|
||||||
|
if (provider)
|
||||||
|
provider->cancelRequest(id);
|
||||||
|
}
|
||||||
|
|
||||||
RefactorResult result;
|
RefactorResult result;
|
||||||
result.success = false;
|
result.success = false;
|
||||||
result.errorMessage = "Refactoring request was cancelled";
|
result.errorMessage = "Refactoring request was cancelled";
|
||||||
emit refactoringCompleted(result);
|
emit refactoringCompleted(result);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void QuickRefactorHandler::handleFullResponse(const QString &requestId, const QString &fullText)
|
void QuickRefactorHandler::handleFullResponse(const QString &requestId, const QString &fullText)
|
||||||
{
|
{
|
||||||
|
|||||||
35
README.md
35
README.md
@@ -6,7 +6,7 @@
|
|||||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||||
[](https://discord.gg/BGMkUsXUgf)
|
[](https://discord.gg/BGMkUsXUgf)
|
||||||
|
|
||||||
 **QodeAssist** brings a full AI coding workflow to Qt Creator for C++ and QML — smart code completion, multi-panel chat, inline quick refactoring, and project-aware tool calling. It works with local runtimes (Ollama, llama.cpp, LM Studio) and cloud providers (Claude, OpenAI, Google AI, Mistral), can run as an **MCP server** so other clients reuse its project context, and can also act as an **MCP client** to consume tools from external MCP servers (authenticated MCP servers are not supported yet).
|
 **QodeAssist** brings a full AI coding workflow to Qt Creator for C++ and QML — smart code completion, multi-panel chat, inline quick refactoring, and project-aware tool calling. It works with local runtimes (Ollama, llama.cpp, LM Studio) and cloud providers (Claude, OpenAI, Google AI, Mistral, Qwen, DeepSeek), can run as an **MCP server** so other clients reuse its project context, and can also act as an **MCP client** to consume tools from external MCP servers (authenticated MCP servers are not supported yet).
|
||||||
|
|
||||||
⚠️ **Important Notice About Paid Providers**
|
⚠️ **Important Notice About Paid Providers**
|
||||||
> When using paid providers like Claude, OpenRouter or OpenAI-compatible services:
|
> When using paid providers like Claude, OpenRouter or OpenAI-compatible services:
|
||||||
@@ -39,7 +39,8 @@ QodeAssist enhances Qt Creator with AI-powered coding assistance:
|
|||||||
- **MCP Server** — expose QodeAssist's project-aware tools to external MCP clients (Claude Code, VS Code, Claude Desktop via bridge)
|
- **MCP Server** — expose QodeAssist's project-aware tools to external MCP clients (Claude Code, VS Code, Claude Desktop via bridge)
|
||||||
- **MCP Client Hub** — connect QodeAssist to external MCP servers and use their tools in Chat and Quick Refactor (authenticated MCP servers are not supported yet)
|
- **MCP Client Hub** — connect QodeAssist to external MCP servers and use their tools in Chat and Quick Refactor (authenticated MCP servers are not supported yet)
|
||||||
- **File Context** — attach, link, or auto-sync open editor files for richer prompts
|
- **File Context** — attach, link, or auto-sync open editor files for richer prompts
|
||||||
- **Many Providers** — Ollama, llama.cpp, LM Studio (Chat + Responses), Claude, OpenAI (Chat + Responses), Google AI, Mistral, Codestral, OpenRouter, any OpenAI-compatible endpoint
|
- **Many Providers** — Ollama, llama.cpp, LM Studio (Chat + Responses), Claude, OpenAI (Chat + Responses), Google AI, Mistral, Codestral, OpenRouter, Qwen (OpenAI + Responses), DeepSeek, any OpenAI-compatible endpoint
|
||||||
|
- **Reasoning / Thinking** — streamed chain-of-thought is shown for reasoning models across Claude, Google, OpenAI Responses, and any OpenAI-compatible endpoint that returns `reasoning_content` (DeepSeek, Qwen QwQ/Qwen3-Thinking, LM Studio, OpenRouter, …)
|
||||||
- **Customizable** — per-project rules (`.qodeassist/rules/`), agent roles, reusable refactor templates, full prompt-template control
|
- **Customizable** — per-project rules (`.qodeassist/rules/`), agent roles, reusable refactor templates, full prompt-template control
|
||||||
|
|
||||||
**Join our [Discord Community](https://discord.gg/BGMkUsXUgf)** to get support and connect with other users!
|
**Join our [Discord Community](https://discord.gg/BGMkUsXUgf)** to get support and connect with other users!
|
||||||
@@ -91,7 +92,27 @@ QodeAssist enhances Qt Creator with AI-powered coding assistance:
|
|||||||
|
|
||||||
## Install plugin to QtCreator
|
## Install plugin to QtCreator
|
||||||
|
|
||||||
### Method 1: Using QodeAssistUpdater (Beta)
|
### Method 1: Using the Extension Registry (Recommended)
|
||||||
|
|
||||||
|
You can install and update QodeAssist directly from within Qt Creator by adding the QodeAssist registry as an external extension repository.
|
||||||
|
|
||||||
|
1. Open the Extensions page (`Qt Creator → Extensions`) and switch to the **Browser** tab
|
||||||
|
2. Enable **Use External Repository**
|
||||||
|
3. Next to **Repository URLs**, click **Add** and paste the registry archive URL matching your Qt Creator version:
|
||||||
|
- **Latest (QtC 19)**: `https://github.com/Palm1r/extension-registry/archive/refs/heads/qodeassist.tar.gz`
|
||||||
|
- **QtC 19**: `https://github.com/Palm1r/extension-registry/archive/refs/heads/qodeassist-qtc19.tar.gz`
|
||||||
|
- **QtC 18**: `https://github.com/Palm1r/extension-registry/archive/refs/heads/qodeassist-qtc18.tar.gz`
|
||||||
|
<details>
|
||||||
|
<summary>Example of extension registry: (click to expand)</summary>
|
||||||
|
<img width="600" alt="RegistryExample" src="https://github.com/user-attachments/assets/8ab8cf10-72e7-4961-8c5a-21d530378a05">
|
||||||
|
</details>
|
||||||
|
|
||||||
|
4. Click **Apply** — QodeAssist will appear in the extensions list, where you can **Install** it
|
||||||
|
5. Updates can be installed from the same screen when a new version is published
|
||||||
|
|
||||||
|
> **Note:** This is an external repository not maintained by The Qt Company. By adding it you accept responsibility for managing the associated risks, as stated in the Extensions page.
|
||||||
|
|
||||||
|
### Method 2: Using QodeAssistUpdater (Beta)
|
||||||
|
|
||||||
QodeAssistUpdater is a command-line utility that automates plugin installation and updates with automatic Qt Creator version detection and checksum verification.
|
QodeAssistUpdater is a command-line utility that automates plugin installation and updates with automatic Qt Creator version detection and checksum verification.
|
||||||
|
|
||||||
@@ -119,7 +140,7 @@ Download pre-built binary from [QodeAssistUpdater releases](https://github.com/P
|
|||||||
|
|
||||||
For more information, visit the [QodeAssistUpdater repository](https://github.com/Palm1r/QodeAssistUpdater).
|
For more information, visit the [QodeAssistUpdater repository](https://github.com/Palm1r/QodeAssistUpdater).
|
||||||
|
|
||||||
### Method 2: Manual Installation
|
### Method 3: Manual Installation
|
||||||
|
|
||||||
1. Install Latest Qt Creator
|
1. Install Latest Qt Creator
|
||||||
2. Download the QodeAssist plugin for your Qt Creator
|
2. Download the QodeAssist plugin for your Qt Creator
|
||||||
@@ -149,6 +170,8 @@ The Quick Setup feature provides one-click configuration for popular cloud AI mo
|
|||||||
- **OpenAI** (gpt-5.2-codex)
|
- **OpenAI** (gpt-5.2-codex)
|
||||||
- **Mistral AI** (Codestral 2501)
|
- **Mistral AI** (Codestral 2501)
|
||||||
- **Google AI** (Gemini 2.5 Flash)
|
- **Google AI** (Gemini 2.5 Flash)
|
||||||
|
- **Qwen** (Qwen3.6 Plus, Qwen3.7 Max)
|
||||||
|
- **DeepSeek** (DeepSeek V4 Flash, DeepSeek V4 Pro)
|
||||||
3. **Configure API Key** - Click "Configure API Key" button and enter your API key in Provider Settings
|
3. **Configure API Key** - Click "Configure API Key" button and enter your API key in Provider Settings
|
||||||
|
|
||||||
All settings (provider, model, template, URL) are configured automatically. Just add your API key and you're ready to go!
|
All settings (provider, model, template, URL) are configured automatically. Just add your API key and you're ready to go!
|
||||||
@@ -169,6 +192,8 @@ For advanced users or local models, choose your preferred provider and follow th
|
|||||||
- **[OpenAI](docs/openai-configuration.md)** — Chat Completions and Responses API
|
- **[OpenAI](docs/openai-configuration.md)** — Chat Completions and Responses API
|
||||||
- **[Mistral AI](docs/mistral-configuration.md)** / **Codestral**
|
- **[Mistral AI](docs/mistral-configuration.md)** / **Codestral**
|
||||||
- **[Google AI](docs/google-ai-configuration.md)** — Gemini
|
- **[Google AI](docs/google-ai-configuration.md)** — Gemini
|
||||||
|
- **Qwen (Alibaba)** — DashScope OpenAI-compatible Chat and Responses endpoints
|
||||||
|
- **DeepSeek** — `deepseek-chat` and `deepseek-reasoner` (reasoning shown as thinking)
|
||||||
- **OpenAI-compatible** — OpenRouter and any custom endpoint
|
- **OpenAI-compatible** — OpenRouter and any custom endpoint
|
||||||
|
|
||||||
### Recommended Models for Best Experience
|
### Recommended Models for Best Experience
|
||||||
@@ -233,7 +258,7 @@ Configure in: `Tools → Options → QodeAssist → Code Completion → General
|
|||||||
- **[Chat Summarization](docs/chat-summarization.md)** - Compress long conversations into AI-generated summaries
|
- **[Chat Summarization](docs/chat-summarization.md)** - Compress long conversations into AI-generated summaries
|
||||||
- **[File Context](docs/file-context.md)** - Attach or link files for better context
|
- **[File Context](docs/file-context.md)** - Attach or link files for better context
|
||||||
- Automatic syncing with open editor files (optional)
|
- Automatic syncing with open editor files (optional)
|
||||||
- Extended thinking mode (Claude, other providers in plan) - Enable deeper reasoning for complex tasks
|
- Extended thinking / reasoning mode - shows streamed chain-of-thought for reasoning models (Claude, Google, OpenAI Responses, and OpenAI-compatible endpoints returning `reasoning_content` such as DeepSeek, Qwen, LM Studio, OpenRouter)
|
||||||
|
|
||||||
### Quick Refactoring
|
### Quick Refactoring
|
||||||
- Inline code refactoring directly in the editor with AI assistance
|
- Inline code refactoring directly in the editor with AI assistance
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import QtQuick.Controls.Basic
|
|||||||
Button {
|
Button {
|
||||||
id: control
|
id: control
|
||||||
|
|
||||||
|
focusPolicy: Qt.NoFocus
|
||||||
padding: 4
|
padding: 4
|
||||||
|
|
||||||
icon.width: 16
|
icon.width: 16
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ enum class ProviderID {
|
|||||||
MistralAI,
|
MistralAI,
|
||||||
OpenRouter,
|
OpenRouter,
|
||||||
GoogleAI,
|
GoogleAI,
|
||||||
LlamaCpp
|
LlamaCpp,
|
||||||
|
Qwen,
|
||||||
|
DeepSeek
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
110
providers/DeepSeekProvider.cpp
Normal file
110
providers/DeepSeekProvider.cpp
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
// Copyright (C) 2024-2026 Petr Mironychev
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#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)
|
||||||
|
: PluginLLMCore::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();
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginLLMCore::ProviderID DeepSeekProvider::providerID() const
|
||||||
|
{
|
||||||
|
return PluginLLMCore::ProviderID::DeepSeek;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginLLMCore::ProviderCapabilities DeepSeekProvider::capabilities() const
|
||||||
|
{
|
||||||
|
return PluginLLMCore::ProviderCapability::Tools
|
||||||
|
| PluginLLMCore::ProviderCapability::Thinking
|
||||||
|
| PluginLLMCore::ProviderCapability::ModelListing;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeepSeekProvider::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.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 DeepSeek request").arg(toolsDefinitions.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::LLMQore::BaseClient *DeepSeekProvider::client() const
|
||||||
|
{
|
||||||
|
return m_client;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QodeAssist::Providers
|
||||||
37
providers/DeepSeekProvider.hpp
Normal file
37
providers/DeepSeekProvider.hpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// 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 DeepSeekProvider : public PluginLLMCore::Provider
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit DeepSeekProvider(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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
::LLMQore::OpenAIClient *m_client;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QodeAssist::Providers
|
||||||
@@ -57,7 +57,8 @@ PluginLLMCore::ProviderID LMStudioProvider::providerID() const
|
|||||||
PluginLLMCore::ProviderCapabilities LMStudioProvider::capabilities() const
|
PluginLLMCore::ProviderCapabilities LMStudioProvider::capabilities() const
|
||||||
{
|
{
|
||||||
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
|
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
|
||||||
| PluginLLMCore::ProviderCapability::ModelListing;
|
| PluginLLMCore::ProviderCapability::ModelListing
|
||||||
|
| PluginLLMCore::ProviderCapability::Thinking;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LMStudioProvider::prepareRequest(
|
void LMStudioProvider::prepareRequest(
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ PluginLLMCore::ProviderID MistralAIProvider::providerID() const
|
|||||||
PluginLLMCore::ProviderCapabilities MistralAIProvider::capabilities() const
|
PluginLLMCore::ProviderCapabilities MistralAIProvider::capabilities() const
|
||||||
{
|
{
|
||||||
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
|
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
|
||||||
| PluginLLMCore::ProviderCapability::ModelListing;
|
| PluginLLMCore::ProviderCapability::ModelListing
|
||||||
|
| PluginLLMCore::ProviderCapability::Thinking;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MistralAIProvider::prepareRequest(
|
void MistralAIProvider::prepareRequest(
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ PluginLLMCore::ProviderID OllamaCompatProvider::providerID() const
|
|||||||
PluginLLMCore::ProviderCapabilities OllamaCompatProvider::capabilities() const
|
PluginLLMCore::ProviderCapabilities OllamaCompatProvider::capabilities() const
|
||||||
{
|
{
|
||||||
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
|
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
|
||||||
| PluginLLMCore::ProviderCapability::ModelListing;
|
| PluginLLMCore::ProviderCapability::ModelListing
|
||||||
|
| PluginLLMCore::ProviderCapability::Thinking;
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMQore::BaseClient *OllamaCompatProvider::client() const
|
::LLMQore::BaseClient *OllamaCompatProvider::client() const
|
||||||
|
|||||||
@@ -98,7 +98,8 @@ PluginLLMCore::ProviderID OpenAICompatProvider::providerID() const
|
|||||||
|
|
||||||
PluginLLMCore::ProviderCapabilities OpenAICompatProvider::capabilities() const
|
PluginLLMCore::ProviderCapabilities OpenAICompatProvider::capabilities() const
|
||||||
{
|
{
|
||||||
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image;
|
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
|
||||||
|
| PluginLLMCore::ProviderCapability::Thinking;
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMQore::BaseClient *OpenAICompatProvider::client() const
|
::LLMQore::BaseClient *OpenAICompatProvider::client() const
|
||||||
|
|||||||
@@ -129,7 +129,8 @@ PluginLLMCore::ProviderID OpenAIProvider::providerID() const
|
|||||||
PluginLLMCore::ProviderCapabilities OpenAIProvider::capabilities() const
|
PluginLLMCore::ProviderCapabilities OpenAIProvider::capabilities() const
|
||||||
{
|
{
|
||||||
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
|
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
|
||||||
| PluginLLMCore::ProviderCapability::ModelListing;
|
| PluginLLMCore::ProviderCapability::ModelListing
|
||||||
|
| PluginLLMCore::ProviderCapability::Thinking;
|
||||||
}
|
}
|
||||||
|
|
||||||
::LLMQore::BaseClient *OpenAIProvider::client() const
|
::LLMQore::BaseClient *OpenAIProvider::client() const
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "pluginllmcore/ProvidersManager.hpp"
|
#include "pluginllmcore/ProvidersManager.hpp"
|
||||||
#include "providers/ClaudeProvider.hpp"
|
#include "providers/ClaudeProvider.hpp"
|
||||||
|
#include "providers/DeepSeekProvider.hpp"
|
||||||
#include "providers/CodestralProvider.hpp"
|
#include "providers/CodestralProvider.hpp"
|
||||||
#include "providers/GoogleAIProvider.hpp"
|
#include "providers/GoogleAIProvider.hpp"
|
||||||
#include "providers/LMStudioProvider.hpp"
|
#include "providers/LMStudioProvider.hpp"
|
||||||
@@ -17,6 +18,8 @@
|
|||||||
#include "providers/OpenAIProvider.hpp"
|
#include "providers/OpenAIProvider.hpp"
|
||||||
#include "providers/OpenAIResponsesProvider.hpp"
|
#include "providers/OpenAIResponsesProvider.hpp"
|
||||||
#include "providers/OpenRouterAIProvider.hpp"
|
#include "providers/OpenRouterAIProvider.hpp"
|
||||||
|
#include "providers/QwenProvider.hpp"
|
||||||
|
#include "providers/QwenResponsesProvider.hpp"
|
||||||
|
|
||||||
namespace QodeAssist::Providers {
|
namespace QodeAssist::Providers {
|
||||||
|
|
||||||
@@ -36,6 +39,9 @@ inline void registerProviders()
|
|||||||
providerManager.registerProvider<GoogleAIProvider>();
|
providerManager.registerProvider<GoogleAIProvider>();
|
||||||
providerManager.registerProvider<LlamaCppProvider>();
|
providerManager.registerProvider<LlamaCppProvider>();
|
||||||
providerManager.registerProvider<CodestralProvider>();
|
providerManager.registerProvider<CodestralProvider>();
|
||||||
|
providerManager.registerProvider<QwenProvider>();
|
||||||
|
providerManager.registerProvider<QwenResponsesProvider>();
|
||||||
|
providerManager.registerProvider<DeepSeekProvider>();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QodeAssist::Providers
|
} // namespace QodeAssist::Providers
|
||||||
|
|||||||
112
providers/QwenProvider.cpp
Normal file
112
providers/QwenProvider.cpp
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
// Copyright (C) 2024-2026 Petr Mironychev
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#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)
|
||||||
|
: PluginLLMCore::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();
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginLLMCore::ProviderID QwenProvider::providerID() const
|
||||||
|
{
|
||||||
|
return PluginLLMCore::ProviderID::Qwen;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginLLMCore::ProviderCapabilities QwenProvider::capabilities() const
|
||||||
|
{
|
||||||
|
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Image
|
||||||
|
| PluginLLMCore::ProviderCapability::Thinking
|
||||||
|
| PluginLLMCore::ProviderCapability::ModelListing;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QwenProvider::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 Qwen request").arg(toolsDefinitions.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::LLMQore::BaseClient *QwenProvider::client() const
|
||||||
|
{
|
||||||
|
return m_client;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QodeAssist::Providers
|
||||||
37
providers/QwenProvider.hpp
Normal file
37
providers/QwenProvider.hpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// 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 QwenProvider : public PluginLLMCore::Provider
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit QwenProvider(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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
::LLMQore::OpenAIClient *m_client;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QodeAssist::Providers
|
||||||
135
providers/QwenResponsesProvider.cpp
Normal file
135
providers/QwenResponsesProvider.cpp
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
// Copyright (C) 2024-2026 Petr Mironychev
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#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)
|
||||||
|
: PluginLLMCore::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,
|
||||||
|
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 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginLLMCore::ProviderID QwenResponsesProvider::providerID() const
|
||||||
|
{
|
||||||
|
return PluginLLMCore::ProviderID::OpenAIResponses;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginLLMCore::ProviderCapabilities QwenResponsesProvider::capabilities() const
|
||||||
|
{
|
||||||
|
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Thinking
|
||||||
|
| PluginLLMCore::ProviderCapability::Image | PluginLLMCore::ProviderCapability::ModelListing;
|
||||||
|
}
|
||||||
|
|
||||||
|
::LLMQore::BaseClient *QwenResponsesProvider::client() const
|
||||||
|
{
|
||||||
|
return m_client;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QodeAssist::Providers
|
||||||
37
providers/QwenResponsesProvider.hpp
Normal file
37
providers/QwenResponsesProvider.hpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// 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 QwenResponsesProvider : public PluginLLMCore::Provider
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit QwenResponsesProvider(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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
::LLMQore::OpenAIResponsesClient *m_client;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QodeAssist::Providers
|
||||||
@@ -99,6 +99,50 @@ QVector<AIConfiguration> ConfigurationManager::getPredefinedConfigurations(
|
|||||||
geminiFlash.type = type;
|
geminiFlash.type = type;
|
||||||
geminiFlash.isPredefined = true;
|
geminiFlash.isPredefined = true;
|
||||||
|
|
||||||
|
AIConfiguration qwenPlus;
|
||||||
|
qwenPlus.id = "preset_qwen_plus";
|
||||||
|
qwenPlus.name = "Qwen3.6 Plus";
|
||||||
|
qwenPlus.provider = "Qwen (OpenAI Response)";
|
||||||
|
qwenPlus.model = "qwen3.6-plus";
|
||||||
|
qwenPlus.url = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1";
|
||||||
|
qwenPlus.customEndpoint = "";
|
||||||
|
qwenPlus.templateName = "OpenAI Responses";
|
||||||
|
qwenPlus.type = type;
|
||||||
|
qwenPlus.isPredefined = true;
|
||||||
|
|
||||||
|
AIConfiguration qwenMax;
|
||||||
|
qwenMax.id = "preset_qwen_max";
|
||||||
|
qwenMax.name = "Qwen3.7 Max";
|
||||||
|
qwenMax.provider = "Qwen (OpenAI Response)";
|
||||||
|
qwenMax.model = "qwen3.7-max";
|
||||||
|
qwenMax.url = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1";
|
||||||
|
qwenMax.customEndpoint = "";
|
||||||
|
qwenMax.templateName = "OpenAI Responses";
|
||||||
|
qwenMax.type = type;
|
||||||
|
qwenMax.isPredefined = true;
|
||||||
|
|
||||||
|
AIConfiguration deepSeekFlash;
|
||||||
|
deepSeekFlash.id = "preset_deepseek_flash";
|
||||||
|
deepSeekFlash.name = "DeepSeek V4 Flash";
|
||||||
|
deepSeekFlash.provider = "DeepSeek";
|
||||||
|
deepSeekFlash.model = "deepseek-v4-flash";
|
||||||
|
deepSeekFlash.url = "https://api.deepseek.com";
|
||||||
|
deepSeekFlash.customEndpoint = "";
|
||||||
|
deepSeekFlash.templateName = "OpenAI Compatible";
|
||||||
|
deepSeekFlash.type = type;
|
||||||
|
deepSeekFlash.isPredefined = true;
|
||||||
|
|
||||||
|
AIConfiguration deepSeekPro;
|
||||||
|
deepSeekPro.id = "preset_deepseek_pro";
|
||||||
|
deepSeekPro.name = "DeepSeek V4 Pro";
|
||||||
|
deepSeekPro.provider = "DeepSeek";
|
||||||
|
deepSeekPro.model = "deepseek-v4-pro";
|
||||||
|
deepSeekPro.url = "https://api.deepseek.com";
|
||||||
|
deepSeekPro.customEndpoint = "";
|
||||||
|
deepSeekPro.templateName = "OpenAI Compatible";
|
||||||
|
deepSeekPro.type = type;
|
||||||
|
deepSeekPro.isPredefined = true;
|
||||||
|
|
||||||
AIConfiguration gpt;
|
AIConfiguration gpt;
|
||||||
gpt.id = "preset_gpt";
|
gpt.id = "preset_gpt";
|
||||||
gpt.name = "gpt-5.5";
|
gpt.name = "gpt-5.5";
|
||||||
@@ -117,6 +161,10 @@ QVector<AIConfiguration> ConfigurationManager::getPredefinedConfigurations(
|
|||||||
presets.append(codestral);
|
presets.append(codestral);
|
||||||
presets.append(mistral);
|
presets.append(mistral);
|
||||||
presets.append(geminiFlash);
|
presets.append(geminiFlash);
|
||||||
|
presets.append(qwenPlus);
|
||||||
|
presets.append(qwenMax);
|
||||||
|
presets.append(deepSeekFlash);
|
||||||
|
presets.append(deepSeekPro);
|
||||||
|
|
||||||
return presets;
|
return presets;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,7 +332,23 @@ GeneralSettings::GeneralSettings()
|
|||||||
Row{qrPresetConfig, qrConfigureApiKey, Stretch{1}},
|
Row{qrPresetConfig, qrConfigureApiKey, Stretch{1}},
|
||||||
qrGrid}};
|
qrGrid}};
|
||||||
|
|
||||||
|
auto *supportLabel = new QLabel(Tr::tr("Support the development of QodeAssist:"));
|
||||||
|
|
||||||
|
auto *supportLinks = new QLabel(
|
||||||
|
"<a href='https://ko-fi.com/qodeassist' style='color: #0066cc;'>Support on Ko-fi ☕</a>"
|
||||||
|
" | "
|
||||||
|
"<a href='https://github.com/Palm1r/"
|
||||||
|
"QodeAssist?tab=readme-ov-file#support-the-development-of-qodeassist' "
|
||||||
|
"style='color: #0066cc;'>Support page on GitHub</a>"
|
||||||
|
" | "
|
||||||
|
"<a href='https://www.paypal.com/paypalme/palm1r' style='color: #0066cc;'>Support via "
|
||||||
|
"PayPal 💳</a>");
|
||||||
|
supportLinks->setOpenExternalLinks(true);
|
||||||
|
supportLinks->setTextFormat(Qt::RichText);
|
||||||
|
|
||||||
auto rootLayout = Column{
|
auto rootLayout = Column{
|
||||||
|
Row{supportLabel, supportLinks, Stretch{1}},
|
||||||
|
Space{8},
|
||||||
Row{enableQodeAssist, Stretch{1}, Row{checkUpdate, resetToDefaults}},
|
Row{enableQodeAssist, Stretch{1}, Row{checkUpdate, resetToDefaults}},
|
||||||
Row{enableLogging, Stretch{1}},
|
Row{enableLogging, Stretch{1}},
|
||||||
Row{enableCheckUpdate, Stretch{1}},
|
Row{enableCheckUpdate, Stretch{1}},
|
||||||
|
|||||||
@@ -123,6 +123,24 @@ ProviderSettings::ProviderSettings()
|
|||||||
llamaCppApiKey.setDefaultValue("");
|
llamaCppApiKey.setDefaultValue("");
|
||||||
llamaCppApiKey.setAutoApply(true);
|
llamaCppApiKey.setAutoApply(true);
|
||||||
|
|
||||||
|
// Qwen (Alibaba) Settings
|
||||||
|
qwenApiKey.setSettingsKey(Constants::QWEN_API_KEY);
|
||||||
|
qwenApiKey.setLabelText(Tr::tr("Qwen API Key:"));
|
||||||
|
qwenApiKey.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||||
|
qwenApiKey.setPlaceHolderText(Tr::tr("Enter your API key here"));
|
||||||
|
qwenApiKey.setHistoryCompleter(Constants::QWEN_API_KEY_HISTORY);
|
||||||
|
qwenApiKey.setDefaultValue("");
|
||||||
|
qwenApiKey.setAutoApply(true);
|
||||||
|
|
||||||
|
// DeepSeek Settings
|
||||||
|
deepSeekApiKey.setSettingsKey(Constants::DEEPSEEK_API_KEY);
|
||||||
|
deepSeekApiKey.setLabelText(Tr::tr("DeepSeek API Key:"));
|
||||||
|
deepSeekApiKey.setDisplayStyle(Utils::StringAspect::LineEditDisplay);
|
||||||
|
deepSeekApiKey.setPlaceHolderText(Tr::tr("Enter your API key here"));
|
||||||
|
deepSeekApiKey.setHistoryCompleter(Constants::DEEPSEEK_API_KEY_HISTORY);
|
||||||
|
deepSeekApiKey.setDefaultValue("");
|
||||||
|
deepSeekApiKey.setAutoApply(true);
|
||||||
|
|
||||||
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
|
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
|
||||||
|
|
||||||
readSettings();
|
readSettings();
|
||||||
@@ -152,6 +170,10 @@ ProviderSettings::ProviderSettings()
|
|||||||
Group{title(Tr::tr("Ollama Settings")), Column{ollamaBasicAuthApiKey}},
|
Group{title(Tr::tr("Ollama Settings")), Column{ollamaBasicAuthApiKey}},
|
||||||
Space{8},
|
Space{8},
|
||||||
Group{title(Tr::tr("llama.cpp Settings")), Column{llamaCppApiKey}},
|
Group{title(Tr::tr("llama.cpp Settings")), Column{llamaCppApiKey}},
|
||||||
|
Space{8},
|
||||||
|
Group{title(Tr::tr("Qwen (Alibaba) Settings")), Column{qwenApiKey}},
|
||||||
|
Space{8},
|
||||||
|
Group{title(Tr::tr("DeepSeek Settings")), Column{deepSeekApiKey}},
|
||||||
Stretch{1}};
|
Stretch{1}};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -189,6 +211,10 @@ void ProviderSettings::setupConnections()
|
|||||||
connect(&llamaCppApiKey, &ButtonAspect::changed, this, [this]() {
|
connect(&llamaCppApiKey, &ButtonAspect::changed, this, [this]() {
|
||||||
llamaCppApiKey.writeSettings();
|
llamaCppApiKey.writeSettings();
|
||||||
});
|
});
|
||||||
|
connect(&qwenApiKey, &ButtonAspect::changed, this, [this]() { qwenApiKey.writeSettings(); });
|
||||||
|
connect(&deepSeekApiKey, &ButtonAspect::changed, this, [this]() {
|
||||||
|
deepSeekApiKey.writeSettings();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProviderSettings::resetSettingsToDefaults()
|
void ProviderSettings::resetSettingsToDefaults()
|
||||||
@@ -211,6 +237,8 @@ void ProviderSettings::resetSettingsToDefaults()
|
|||||||
resetAspect(googleAiApiKey);
|
resetAspect(googleAiApiKey);
|
||||||
resetAspect(ollamaBasicAuthApiKey);
|
resetAspect(ollamaBasicAuthApiKey);
|
||||||
resetAspect(llamaCppApiKey);
|
resetAspect(llamaCppApiKey);
|
||||||
|
resetAspect(qwenApiKey);
|
||||||
|
resetAspect(deepSeekApiKey);
|
||||||
writeSettings();
|
writeSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ public:
|
|||||||
Utils::StringAspect googleAiApiKey{this};
|
Utils::StringAspect googleAiApiKey{this};
|
||||||
Utils::StringAspect ollamaBasicAuthApiKey{this};
|
Utils::StringAspect ollamaBasicAuthApiKey{this};
|
||||||
Utils::StringAspect llamaCppApiKey{this};
|
Utils::StringAspect llamaCppApiKey{this};
|
||||||
|
Utils::StringAspect qwenApiKey{this};
|
||||||
|
Utils::StringAspect deepSeekApiKey{this};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupConnections();
|
void setupConnections();
|
||||||
|
|||||||
@@ -163,6 +163,10 @@ const char OLLAMA_BASIC_AUTH_API_KEY[] = "QodeAssist.ollamaBasicAuthApiKey";
|
|||||||
const char OLLAMA_BASIC_AUTH_API_KEY_HISTORY[] = "QodeAssist.ollamaBasicAuthApiKeyHistory";
|
const char OLLAMA_BASIC_AUTH_API_KEY_HISTORY[] = "QodeAssist.ollamaBasicAuthApiKeyHistory";
|
||||||
const char LLAMA_CPP_API_KEY[] = "QodeAssist.llamaCppApiKey";
|
const char LLAMA_CPP_API_KEY[] = "QodeAssist.llamaCppApiKey";
|
||||||
const char LLAMA_CPP_API_KEY_HISTORY[] = "QodeAssist.llamaCppApiKeyHistory";
|
const char LLAMA_CPP_API_KEY_HISTORY[] = "QodeAssist.llamaCppApiKeyHistory";
|
||||||
|
const char QWEN_API_KEY[] = "QodeAssist.qwenApiKey";
|
||||||
|
const char QWEN_API_KEY_HISTORY[] = "QodeAssist.qwenApiKeyHistory";
|
||||||
|
const char DEEPSEEK_API_KEY[] = "QodeAssist.deepSeekApiKey";
|
||||||
|
const char DEEPSEEK_API_KEY_HISTORY[] = "QodeAssist.deepSeekApiKeyHistory";
|
||||||
|
|
||||||
const char CLAUDE_ENABLE_PROMPT_CACHING[] = "QodeAssist.claudeEnablePromptCaching";
|
const char CLAUDE_ENABLE_PROMPT_CACHING[] = "QodeAssist.claudeEnablePromptCaching";
|
||||||
const char CLAUDE_USE_EXTENDED_CACHE_TTL[] = "QodeAssist.claudeUseExtendedCacheTTL";
|
const char CLAUDE_USE_EXTENDED_CACHE_TTL[] = "QodeAssist.claudeUseExtendedCacheTTL";
|
||||||
|
|||||||
@@ -6,7 +6,11 @@
|
|||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
#include <extensionsystem/pluginspec.h>
|
#include <extensionsystem/pluginspec.h>
|
||||||
|
#include <QClipboard>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QGuiApplication>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
@@ -17,8 +21,7 @@ UpdateDialog::UpdateDialog(QWidget *parent)
|
|||||||
, m_updater(new PluginUpdater(this))
|
, m_updater(new PluginUpdater(this))
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("QodeAssist Update"));
|
setWindowTitle(tr("QodeAssist Update"));
|
||||||
setMinimumWidth(400);
|
setFixedSize(700, 720);
|
||||||
setMinimumHeight(300);
|
|
||||||
|
|
||||||
m_layout = new QVBoxLayout(this);
|
m_layout = new QVBoxLayout(this);
|
||||||
m_layout->setSpacing(12);
|
m_layout->setSpacing(12);
|
||||||
@@ -48,24 +51,94 @@ UpdateDialog::UpdateDialog(QWidget *parent)
|
|||||||
githubSupportLink->setAlignment(Qt::AlignCenter);
|
githubSupportLink->setAlignment(Qt::AlignCenter);
|
||||||
m_layout->addWidget(githubSupportLink);
|
m_layout->addWidget(githubSupportLink);
|
||||||
|
|
||||||
|
auto *paypalLink = new QLabel(
|
||||||
|
"<a href='https://www.paypal.com/paypalme/palm1r' style='color: #0066cc;'>Support via PayPal "
|
||||||
|
"💳</a>",
|
||||||
|
this);
|
||||||
|
paypalLink->setOpenExternalLinks(true);
|
||||||
|
paypalLink->setTextFormat(Qt::RichText);
|
||||||
|
paypalLink->setAlignment(Qt::AlignCenter);
|
||||||
|
m_layout->addWidget(paypalLink);
|
||||||
|
|
||||||
m_layout->addSpacing(20);
|
m_layout->addSpacing(20);
|
||||||
|
|
||||||
auto *updaterInfoLabel = new QLabel(
|
auto *registryGroup = new QGroupBox(tr("Install via Extension Registry (recommended)"), this);
|
||||||
tr("QodeAssistUpdater - convenient tool for plugin installation and updates"),
|
auto *registryLayout = new QVBoxLayout(registryGroup);
|
||||||
this);
|
registryLayout->setSpacing(10);
|
||||||
updaterInfoLabel->setAlignment(Qt::AlignCenter);
|
|
||||||
updaterInfoLabel->setWordWrap(true);
|
|
||||||
m_layout->addWidget(updaterInfoLabel);
|
|
||||||
|
|
||||||
m_buttonOpenUpdaterRelease = new QPushButton(tr("Download QodeAssistUpdater"), this);
|
auto *registryInfoLabel = new QLabel(
|
||||||
|
tr("In Qt Creator open Extensions → Browser tab, enable \"Use External Repository\", "
|
||||||
|
"add one of the URLs below and click Apply to install QodeAssist. Updates are then "
|
||||||
|
"installed from the same screen."),
|
||||||
|
registryGroup);
|
||||||
|
registryInfoLabel->setWordWrap(true);
|
||||||
|
registryLayout->addWidget(registryInfoLabel);
|
||||||
|
|
||||||
|
const auto addRegistryRow = [&](const QString &description, const QString &url) {
|
||||||
|
auto *card = new QFrame(registryGroup);
|
||||||
|
card->setFrameShape(QFrame::StyledPanel);
|
||||||
|
auto *cardLayout = new QHBoxLayout(card);
|
||||||
|
cardLayout->setContentsMargins(10, 8, 10, 8);
|
||||||
|
cardLayout->setSpacing(10);
|
||||||
|
|
||||||
|
auto *textLayout = new QVBoxLayout;
|
||||||
|
textLayout->setSpacing(2);
|
||||||
|
|
||||||
|
auto *desc = new QLabel(description, card);
|
||||||
|
desc->setStyleSheet("font-weight: bold;");
|
||||||
|
textLayout->addWidget(desc);
|
||||||
|
|
||||||
|
auto *link = new QLabel(
|
||||||
|
QString("<a href='%1' style='color: #0066cc;'>%1</a>").arg(url), card);
|
||||||
|
link->setOpenExternalLinks(true);
|
||||||
|
link->setTextFormat(Qt::RichText);
|
||||||
|
link->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||||
|
link->setWordWrap(true);
|
||||||
|
textLayout->addWidget(link);
|
||||||
|
|
||||||
|
cardLayout->addLayout(textLayout, 1);
|
||||||
|
|
||||||
|
auto *copyButton = new QPushButton(tr("Copy"), card);
|
||||||
|
copyButton->setMaximumWidth(70);
|
||||||
|
connect(copyButton, &QPushButton::clicked, this, [url]() {
|
||||||
|
QGuiApplication::clipboard()->setText(url);
|
||||||
|
});
|
||||||
|
cardLayout->addWidget(copyButton, 0, Qt::AlignVCenter);
|
||||||
|
|
||||||
|
registryLayout->addWidget(card);
|
||||||
|
};
|
||||||
|
|
||||||
|
addRegistryRow(
|
||||||
|
tr("Latest (for the newest Qt Creator, always up to date)"),
|
||||||
|
"https://github.com/Palm1r/extension-registry/archive/refs/heads/qodeassist.tar.gz");
|
||||||
|
addRegistryRow(
|
||||||
|
tr("Only for Qt Creator %1").arg(QODEASSIST_QT_CREATOR_VERSION_MAJOR),
|
||||||
|
QString("https://github.com/Palm1r/extension-registry/archive/refs/heads/"
|
||||||
|
"qodeassist-qtc%1.tar.gz")
|
||||||
|
.arg(QODEASSIST_QT_CREATOR_VERSION_MAJOR));
|
||||||
|
|
||||||
|
m_layout->addWidget(registryGroup);
|
||||||
|
|
||||||
|
auto *updaterGroup = new QGroupBox(tr("Alternative: QodeAssistUpdater"), this);
|
||||||
|
auto *updaterLayout = new QVBoxLayout(updaterGroup);
|
||||||
|
updaterLayout->setSpacing(10);
|
||||||
|
|
||||||
|
auto *updaterInfoLabel = new QLabel(
|
||||||
|
tr("A standalone tool for installing and updating the plugin."), updaterGroup);
|
||||||
|
updaterInfoLabel->setWordWrap(true);
|
||||||
|
updaterLayout->addWidget(updaterInfoLabel);
|
||||||
|
|
||||||
|
m_buttonOpenUpdaterRelease = new QPushButton(tr("Download QodeAssistUpdater"), updaterGroup);
|
||||||
m_buttonOpenUpdaterRelease->setMaximumWidth(250);
|
m_buttonOpenUpdaterRelease->setMaximumWidth(250);
|
||||||
auto *updaterButtonLayout = new QHBoxLayout;
|
auto *updaterButtonLayout = new QHBoxLayout;
|
||||||
updaterButtonLayout->addStretch();
|
updaterButtonLayout->addStretch();
|
||||||
updaterButtonLayout->addWidget(m_buttonOpenUpdaterRelease);
|
updaterButtonLayout->addWidget(m_buttonOpenUpdaterRelease);
|
||||||
updaterButtonLayout->addStretch();
|
updaterButtonLayout->addStretch();
|
||||||
m_layout->addLayout(updaterButtonLayout);
|
updaterLayout->addLayout(updaterButtonLayout);
|
||||||
|
|
||||||
m_layout->addSpacing(20);
|
m_layout->addWidget(updaterGroup);
|
||||||
|
|
||||||
|
m_layout->addSpacing(10);
|
||||||
|
|
||||||
m_titleLabel = new QLabel(tr("A new version of QodeAssist is available!"), this);
|
m_titleLabel = new QLabel(tr("A new version of QodeAssist is available!"), this);
|
||||||
m_titleLabel->setStyleSheet("font-weight: bold; font-size: 14px;");
|
m_titleLabel->setStyleSheet("font-weight: bold; font-size: 14px;");
|
||||||
|
|||||||
2
sources/external/llmqore
vendored
2
sources/external/llmqore
vendored
Submodule sources/external/llmqore updated: 95a7b3ac51...68ecec3dc9
@@ -81,6 +81,8 @@ public:
|
|||||||
case PluginLLMCore::ProviderID::OpenRouter:
|
case PluginLLMCore::ProviderID::OpenRouter:
|
||||||
case PluginLLMCore::ProviderID::LMStudio:
|
case PluginLLMCore::ProviderID::LMStudio:
|
||||||
case PluginLLMCore::ProviderID::LlamaCpp:
|
case PluginLLMCore::ProviderID::LlamaCpp:
|
||||||
|
case PluginLLMCore::ProviderID::Qwen:
|
||||||
|
case PluginLLMCore::ProviderID::DeepSeek:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -142,10 +142,12 @@ void ProgressWidget::leaveEvent(QEvent *event)
|
|||||||
void ProgressWidget::mousePressEvent(QMouseEvent *event)
|
void ProgressWidget::mousePressEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (event->button() == Qt::LeftButton && m_isHovered) {
|
if (event->button() == Qt::LeftButton && m_isHovered) {
|
||||||
|
event->accept();
|
||||||
|
auto callback = m_cancelCallback;
|
||||||
emit cancelRequested();
|
emit cancelRequested();
|
||||||
if (m_cancelCallback) {
|
if (callback)
|
||||||
m_cancelCallback();
|
callback();
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
QWidget::mousePressEvent(event);
|
QWidget::mousePressEvent(event);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user