feat: Add Qwen provider

This commit is contained in:
Petr Mironychev
2026-05-29 11:33:06 +02:00
parent 0cf915c4a5
commit ea67ba0e2a
13 changed files with 171 additions and 3 deletions

View File

@@ -116,6 +116,8 @@ add_qtc_plugin(QodeAssist
providers/LlamaCppProvider.hpp providers/LlamaCppProvider.cpp
providers/CodestralProvider.hpp providers/CodestralProvider.cpp
providers/OpenAIResponsesProvider.hpp providers/OpenAIResponsesProvider.cpp
providers/QwenProvider.hpp providers/QwenProvider.cpp
providers/QwenResponsesProvider.hpp providers/QwenResponsesProvider.cpp
QodeAssist.qrc
LSPCompletion.hpp
LLMSuggestion.hpp LLMSuggestion.cpp

View File

@@ -6,7 +6,7 @@
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Discord](https://dcbadge.limes.pink/api/server/BGMkUsXUgf?style=flat)](https://discord.gg/BGMkUsXUgf)
![qodeassist-icon](https://github.com/user-attachments/assets/dc336712-83cb-440d-8761-8d0a31de898d) **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-icon](https://github.com/user-attachments/assets/dc336712-83cb-440d-8761-8d0a31de898d) **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), 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**
> When using paid providers like Claude, OpenRouter or OpenAI-compatible services:
@@ -39,7 +39,7 @@ 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 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
- **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), any OpenAI-compatible endpoint
- **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!
@@ -169,6 +169,7 @@ The Quick Setup feature provides one-click configuration for popular cloud AI mo
- **OpenAI** (gpt-5.2-codex)
- **Mistral AI** (Codestral 2501)
- **Google AI** (Gemini 2.5 Flash)
- **Qwen** (Qwen3.6 Plus, Qwen3.7 Max)
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!
@@ -189,6 +190,7 @@ For advanced users or local models, choose your preferred provider and follow th
- **[OpenAI](docs/openai-configuration.md)** — Chat Completions and Responses API
- **[Mistral AI](docs/mistral-configuration.md)** / **Codestral**
- **[Google AI](docs/google-ai-configuration.md)** — Gemini
- **Qwen (Alibaba)** — DashScope OpenAI-compatible Chat and Responses endpoints
- **OpenAI-compatible** — OpenRouter and any custom endpoint
### Recommended Models for Best Experience

View File

@@ -14,6 +14,7 @@ enum class ProviderID {
MistralAI,
OpenRouter,
GoogleAI,
LlamaCpp
LlamaCpp,
Qwen
};
}

View File

@@ -17,6 +17,8 @@
#include "providers/OpenAIProvider.hpp"
#include "providers/OpenAIResponsesProvider.hpp"
#include "providers/OpenRouterAIProvider.hpp"
#include "providers/QwenProvider.hpp"
#include "providers/QwenResponsesProvider.hpp"
namespace QodeAssist::Providers {
@@ -36,6 +38,8 @@ inline void registerProviders()
providerManager.registerProvider<GoogleAIProvider>();
providerManager.registerProvider<LlamaCppProvider>();
providerManager.registerProvider<CodestralProvider>();
providerManager.registerProvider<QwenProvider>();
providerManager.registerProvider<QwenResponsesProvider>();
}
} // namespace QodeAssist::Providers

View File

@@ -0,0 +1,34 @@
// Copyright (C) 2024-2026 Petr Mironychev
// SPDX-License-Identifier: GPL-3.0-or-later
#include "QwenProvider.hpp"
#include "settings/ProviderSettings.hpp"
namespace QodeAssist::Providers {
QwenProvider::QwenProvider(QObject *parent)
: OpenAICompatProvider(parent)
{}
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";
}
PluginLLMCore::ProviderID QwenProvider::providerID() const
{
return PluginLLMCore::ProviderID::Qwen;
}
} // namespace QodeAssist::Providers

View File

@@ -0,0 +1,21 @@
// Copyright (C) 2024-2026 Petr Mironychev
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "providers/OpenAICompatProvider.hpp"
namespace QodeAssist::Providers {
class QwenProvider : public OpenAICompatProvider
{
public:
explicit QwenProvider(QObject *parent = nullptr);
QString name() const override;
QString url() const override;
QString apiKey() const override;
PluginLLMCore::ProviderID providerID() const override;
};
} // namespace QodeAssist::Providers

View File

@@ -0,0 +1,40 @@
// Copyright (C) 2024-2026 Petr Mironychev
// SPDX-License-Identifier: GPL-3.0-or-later
#include "QwenResponsesProvider.hpp"
#include "settings/ProviderSettings.hpp"
namespace QodeAssist::Providers {
QwenResponsesProvider::QwenResponsesProvider(QObject *parent)
: OpenAIResponsesProvider(parent)
{}
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";
}
QFuture<QList<QString>> QwenResponsesProvider::getInstalledModels(const QString &)
{
return QtFuture::makeReadyFuture(QList<QString>{});
}
PluginLLMCore::ProviderCapabilities QwenResponsesProvider::capabilities() const
{
return PluginLLMCore::ProviderCapability::Tools | PluginLLMCore::ProviderCapability::Thinking
| PluginLLMCore::ProviderCapability::Image;
}
} // namespace QodeAssist::Providers

View File

@@ -0,0 +1,23 @@
// Copyright (C) 2024-2026 Petr Mironychev
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "providers/OpenAIResponsesProvider.hpp"
namespace QodeAssist::Providers {
class QwenResponsesProvider : public OpenAIResponsesProvider
{
Q_OBJECT
public:
explicit QwenResponsesProvider(QObject *parent = nullptr);
QString name() const override;
QString url() const override;
QString apiKey() const override;
QFuture<QList<QString>> getInstalledModels(const QString &url) override;
PluginLLMCore::ProviderCapabilities capabilities() const override;
};
} // namespace QodeAssist::Providers

View File

@@ -99,6 +99,28 @@ QVector<AIConfiguration> ConfigurationManager::getPredefinedConfigurations(
geminiFlash.type = type;
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 gpt;
gpt.id = "preset_gpt";
gpt.name = "gpt-5.5";
@@ -117,6 +139,8 @@ QVector<AIConfiguration> ConfigurationManager::getPredefinedConfigurations(
presets.append(codestral);
presets.append(mistral);
presets.append(geminiFlash);
presets.append(qwenPlus);
presets.append(qwenMax);
return presets;
}

View File

@@ -123,6 +123,15 @@ ProviderSettings::ProviderSettings()
llamaCppApiKey.setDefaultValue("");
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);
resetToDefaults.m_buttonText = Tr::tr("Reset Page to Defaults");
readSettings();
@@ -152,6 +161,8 @@ ProviderSettings::ProviderSettings()
Group{title(Tr::tr("Ollama Settings")), Column{ollamaBasicAuthApiKey}},
Space{8},
Group{title(Tr::tr("llama.cpp Settings")), Column{llamaCppApiKey}},
Space{8},
Group{title(Tr::tr("Qwen (Alibaba) Settings")), Column{qwenApiKey}},
Stretch{1}};
});
}
@@ -189,6 +200,7 @@ void ProviderSettings::setupConnections()
connect(&llamaCppApiKey, &ButtonAspect::changed, this, [this]() {
llamaCppApiKey.writeSettings();
});
connect(&qwenApiKey, &ButtonAspect::changed, this, [this]() { qwenApiKey.writeSettings(); });
}
void ProviderSettings::resetSettingsToDefaults()
@@ -211,6 +223,7 @@ void ProviderSettings::resetSettingsToDefaults()
resetAspect(googleAiApiKey);
resetAspect(ollamaBasicAuthApiKey);
resetAspect(llamaCppApiKey);
resetAspect(qwenApiKey);
writeSettings();
}
}

View File

@@ -28,6 +28,7 @@ public:
Utils::StringAspect googleAiApiKey{this};
Utils::StringAspect ollamaBasicAuthApiKey{this};
Utils::StringAspect llamaCppApiKey{this};
Utils::StringAspect qwenApiKey{this};
private:
void setupConnections();

View File

@@ -163,6 +163,8 @@ const char OLLAMA_BASIC_AUTH_API_KEY[] = "QodeAssist.ollamaBasicAuthApiKey";
const char OLLAMA_BASIC_AUTH_API_KEY_HISTORY[] = "QodeAssist.ollamaBasicAuthApiKeyHistory";
const char LLAMA_CPP_API_KEY[] = "QodeAssist.llamaCppApiKey";
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 CLAUDE_ENABLE_PROMPT_CACHING[] = "QodeAssist.claudeEnablePromptCaching";
const char CLAUDE_USE_EXTENDED_CACHE_TTL[] = "QodeAssist.claudeUseExtendedCacheTTL";

View File

@@ -81,6 +81,7 @@ public:
case PluginLLMCore::ProviderID::OpenRouter:
case PluginLLMCore::ProviderID::LMStudio:
case PluginLLMCore::ProviderID::LlamaCpp:
case PluginLLMCore::ProviderID::Qwen:
return true;
default:
return false;