mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2026-07-01 10:39:14 -04:00
feat: Add possibility to overwrite agent config tools enabling
This commit is contained in:
@@ -9,12 +9,15 @@
|
|||||||
#include "SettingsTheme.hpp"
|
#include "SettingsTheme.hpp"
|
||||||
#include "SettingsUiBuilders.hpp"
|
#include "SettingsUiBuilders.hpp"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include <utils/theme/theme.h>
|
#include <utils/theme/theme.h>
|
||||||
|
|
||||||
#include <AgentFactory.hpp>
|
#include <AgentFactory.hpp>
|
||||||
#include <ProviderInstance.hpp>
|
#include <ProviderInstance.hpp>
|
||||||
#include <ProviderInstanceFactory.hpp>
|
#include <ProviderInstanceFactory.hpp>
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
@@ -29,6 +32,7 @@
|
|||||||
#include <QPlainTextEdit>
|
#include <QPlainTextEdit>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QScopedValueRollback>
|
#include <QScopedValueRollback>
|
||||||
|
#include <QSignalBlocker>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
@@ -247,6 +251,43 @@ AgentDetailPane::AgentDetailPane(QWidget *parent)
|
|||||||
m_effectiveUrl->setAutoFillBackground(true);
|
m_effectiveUrl->setAutoFillBackground(true);
|
||||||
connection->bodyLayout()->addWidget(m_effectiveUrl);
|
connection->bodyLayout()->addWidget(m_effectiveUrl);
|
||||||
|
|
||||||
|
auto *capabilities = new SectionBox(tr("Capabilities"), this);
|
||||||
|
m_thinkingValue = new QLabel(this);
|
||||||
|
|
||||||
|
m_toolsCheck = new QCheckBox(tr("Allow tool calls"), this);
|
||||||
|
m_toolsCheck->setEnabled(false);
|
||||||
|
connect(m_toolsCheck, &QCheckBox::clicked, this, [this](bool on) { onToggleTools(on); });
|
||||||
|
|
||||||
|
m_toolsResetBtn = new QPushButton(tr("Reset"), this);
|
||||||
|
m_toolsResetBtn->setToolTip(tr("Remove the tools override and restore the agent's default"));
|
||||||
|
m_toolsResetBtn->setVisible(false);
|
||||||
|
connect(m_toolsResetBtn, &QPushButton::clicked, this, [this] { onResetTools(); });
|
||||||
|
|
||||||
|
auto *toolsHolder = new QWidget(this);
|
||||||
|
auto *toolsRow = new QHBoxLayout(toolsHolder);
|
||||||
|
toolsRow->setContentsMargins(0, 0, 0, 0);
|
||||||
|
toolsRow->setSpacing(6);
|
||||||
|
toolsRow->addWidget(m_toolsCheck);
|
||||||
|
toolsRow->addStretch(1);
|
||||||
|
toolsRow->addWidget(m_toolsResetBtn);
|
||||||
|
|
||||||
|
auto *capGrid = new QGridLayout;
|
||||||
|
capGrid->setContentsMargins(0, 0, 0, 0);
|
||||||
|
capGrid->setHorizontalSpacing(8);
|
||||||
|
capGrid->setVerticalSpacing(4);
|
||||||
|
FormBuilder(capGrid)
|
||||||
|
.row(
|
||||||
|
tr("Thinking:"),
|
||||||
|
m_thinkingValue,
|
||||||
|
tr("Whether this agent requests extended thinking. Defined by the "
|
||||||
|
"agent template."))
|
||||||
|
.row(
|
||||||
|
tr("Tools:"),
|
||||||
|
toolsHolder,
|
||||||
|
tr("Whether the agent may call tools. Toggle to save a per-agent "
|
||||||
|
"override in settings; Reset restores the agent's default."));
|
||||||
|
capabilities->bodyLayout()->addLayout(capGrid);
|
||||||
|
|
||||||
auto *match = new SectionBox(tr("Match"), this);
|
auto *match = new SectionBox(tr("Match"), this);
|
||||||
auto *matchHint = makeHintLabel(
|
auto *matchHint = makeHintLabel(
|
||||||
tr("When a feature slot has multiple bound agents, the first whose "
|
tr("When a feature slot has multiple bound agents, the first whose "
|
||||||
@@ -286,6 +327,7 @@ AgentDetailPane::AgentDetailPane(QWidget *parent)
|
|||||||
root->addWidget(m_description);
|
root->addWidget(m_description);
|
||||||
root->addWidget(identity);
|
root->addWidget(identity);
|
||||||
root->addWidget(connection);
|
root->addWidget(connection);
|
||||||
|
root->addWidget(capabilities);
|
||||||
root->addWidget(match);
|
root->addWidget(match);
|
||||||
root->addWidget(m_rawToggle, 0, Qt::AlignLeft);
|
root->addWidget(m_rawToggle, 0, Qt::AlignLeft);
|
||||||
root->addWidget(m_rawToml);
|
root->addWidget(m_rawToml);
|
||||||
@@ -414,6 +456,38 @@ void AgentDetailPane::onResetProvider()
|
|||||||
setAgent(*cfg);
|
setAgent(*cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AgentDetailPane::onToggleTools(bool enabled)
|
||||||
|
{
|
||||||
|
if (!m_agentFactory || !m_current)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QString name = m_current->name;
|
||||||
|
QString err;
|
||||||
|
if (!m_agentFactory->setAgentToolsOverride(name, enabled, &err)) {
|
||||||
|
QMessageBox::warning(this, tr("Set tools"), err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (const AgentConfig *cfg = m_agentFactory->configByName(name))
|
||||||
|
setAgent(*cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgentDetailPane::onResetTools()
|
||||||
|
{
|
||||||
|
if (!m_agentFactory || !m_current)
|
||||||
|
return;
|
||||||
|
if (!m_agentFactory->agentToolsOverride(m_current->name).has_value())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QString name = m_current->name;
|
||||||
|
QString err;
|
||||||
|
if (!m_agentFactory->setAgentToolsOverride(name, std::nullopt, &err)) {
|
||||||
|
QMessageBox::warning(this, tr("Reset tools"), err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (const AgentConfig *cfg = m_agentFactory->configByName(name))
|
||||||
|
setAgent(*cfg);
|
||||||
|
}
|
||||||
|
|
||||||
void AgentDetailPane::setAgent(const AgentConfig &cfg)
|
void AgentDetailPane::setAgent(const AgentConfig &cfg)
|
||||||
{
|
{
|
||||||
m_currentStorage = cfg;
|
m_currentStorage = cfg;
|
||||||
@@ -481,6 +555,19 @@ void AgentDetailPane::setAgent(const AgentConfig &cfg)
|
|||||||
hasModelOverride ? tr("Overridden in settings. Reset to use the agent's default model.")
|
hasModelOverride ? tr("Overridden in settings. Reset to use the agent's default model.")
|
||||||
: QString());
|
: QString());
|
||||||
|
|
||||||
|
m_thinkingValue->setText(cfg.enableThinking ? tr("Enabled") : tr("Disabled"));
|
||||||
|
{
|
||||||
|
QSignalBlocker block(m_toolsCheck);
|
||||||
|
m_toolsCheck->setChecked(cfg.enableTools);
|
||||||
|
}
|
||||||
|
m_toolsCheck->setEnabled(m_agentFactory != nullptr);
|
||||||
|
const bool hasToolsOverride = m_agentFactory
|
||||||
|
&& m_agentFactory->agentToolsOverride(cfg.name).has_value();
|
||||||
|
m_toolsResetBtn->setVisible(hasToolsOverride);
|
||||||
|
m_toolsCheck->setToolTip(
|
||||||
|
hasToolsOverride ? tr("Overridden in settings. Reset to use the agent's default.")
|
||||||
|
: QString());
|
||||||
|
|
||||||
const QString eff = resolvedUrl + cfg.endpoint;
|
const QString eff = resolvedUrl + cfg.endpoint;
|
||||||
m_effectiveUrl->setText(
|
m_effectiveUrl->setText(
|
||||||
eff.isEmpty() ? tr("# effective request line\n(unknown — provider instance not found)")
|
eff.isEmpty() ? tr("# effective request line\n(unknown — provider instance not found)")
|
||||||
@@ -542,6 +629,13 @@ void AgentDetailPane::clear()
|
|||||||
m_modelChangeBtn->setEnabled(false);
|
m_modelChangeBtn->setEnabled(false);
|
||||||
m_modelResetBtn->setVisible(false);
|
m_modelResetBtn->setVisible(false);
|
||||||
m_effectiveUrl->clear();
|
m_effectiveUrl->clear();
|
||||||
|
m_thinkingValue->clear();
|
||||||
|
{
|
||||||
|
QSignalBlocker block(m_toolsCheck);
|
||||||
|
m_toolsCheck->setChecked(false);
|
||||||
|
}
|
||||||
|
m_toolsCheck->setEnabled(false);
|
||||||
|
m_toolsResetBtn->setVisible(false);
|
||||||
m_filePatternsValue->clear();
|
m_filePatternsValue->clear();
|
||||||
m_rawToml->clear();
|
m_rawToml->clear();
|
||||||
m_openBtn->setEnabled(false);
|
m_openBtn->setEnabled(false);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <AgentConfig.hpp>
|
#include <AgentConfig.hpp>
|
||||||
|
|
||||||
|
class QCheckBox;
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
@@ -56,6 +57,8 @@ private:
|
|||||||
void onResetModel();
|
void onResetModel();
|
||||||
void onChangeProvider(int index);
|
void onChangeProvider(int index);
|
||||||
void onResetProvider();
|
void onResetProvider();
|
||||||
|
void onToggleTools(bool enabled);
|
||||||
|
void onResetTools();
|
||||||
|
|
||||||
bool m_inApplyPalette = false;
|
bool m_inApplyPalette = false;
|
||||||
bool m_providerComboPopulated = false;
|
bool m_providerComboPopulated = false;
|
||||||
@@ -88,6 +91,10 @@ private:
|
|||||||
QPushButton *m_modelResetBtn = nullptr;
|
QPushButton *m_modelResetBtn = nullptr;
|
||||||
QLabel *m_effectiveUrl = nullptr;
|
QLabel *m_effectiveUrl = nullptr;
|
||||||
|
|
||||||
|
QLabel *m_thinkingValue = nullptr;
|
||||||
|
QCheckBox *m_toolsCheck = nullptr;
|
||||||
|
QPushButton *m_toolsResetBtn = nullptr;
|
||||||
|
|
||||||
QLineEdit *m_filePatternsValue = nullptr;
|
QLineEdit *m_filePatternsValue = nullptr;
|
||||||
|
|
||||||
QToolButton *m_rawToggle = nullptr;
|
QToolButton *m_rawToggle = nullptr;
|
||||||
|
|||||||
@@ -243,6 +243,7 @@ private:
|
|||||||
}
|
}
|
||||||
m_agentFactory->clearAgentModelOverride(name);
|
m_agentFactory->clearAgentModelOverride(name);
|
||||||
m_agentFactory->clearAgentProviderOverride(name);
|
m_agentFactory->clearAgentProviderOverride(name);
|
||||||
|
m_agentFactory->clearAgentToolsOverride(name);
|
||||||
reloadFromDisk();
|
reloadFromDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
#include <QScopedValueRollback>
|
#include <QScopedValueRollback>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
|
#include <QScrollBar>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
@@ -164,6 +165,7 @@ void TagFilterStrip::rebuild()
|
|||||||
return a.first.localeAwareCompare(b.first) < 0;
|
return a.first.localeAwareCompare(b.first) < 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
constexpr int kMaxColumns = 3;
|
||||||
auto *gridHost = new QWidget(this);
|
auto *gridHost = new QWidget(this);
|
||||||
auto *grid = new QGridLayout(gridHost);
|
auto *grid = new QGridLayout(gridHost);
|
||||||
grid->setContentsMargins(0, 0, 0, 0);
|
grid->setContentsMargins(0, 0, 0, 0);
|
||||||
@@ -176,12 +178,11 @@ void TagFilterStrip::rebuild()
|
|||||||
connect(chip, &TagChip::clicked, this, &TagFilterStrip::toggleTag);
|
connect(chip, &TagChip::clicked, this, &TagFilterStrip::toggleTag);
|
||||||
grid->addWidget(chip, gridRow, col, Qt::AlignLeft);
|
grid->addWidget(chip, gridRow, col, Qt::AlignLeft);
|
||||||
m_chipByTag.insert(tag, chip);
|
m_chipByTag.insert(tag, chip);
|
||||||
if (++col >= 4) {
|
if (++col >= kMaxColumns) {
|
||||||
col = 0;
|
col = 0;
|
||||||
++gridRow;
|
++gridRow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
grid->setColumnStretch(4, 1);
|
|
||||||
|
|
||||||
constexpr int kMaxVisibleRows = 4;
|
constexpr int kMaxVisibleRows = 4;
|
||||||
constexpr int kRowSpacing = 5;
|
constexpr int kRowSpacing = 5;
|
||||||
@@ -194,10 +195,12 @@ void TagFilterStrip::rebuild()
|
|||||||
scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
scroll->setWidget(gridHost);
|
scroll->setWidget(gridHost);
|
||||||
scroll->setMaximumHeight(
|
scroll->setMaximumHeight(
|
||||||
kMaxVisibleRows * chipHeight + (kMaxVisibleRows - 1) * kRowSpacing + 4);
|
kMaxVisibleRows * chipHeight + (kMaxVisibleRows - 1) * kRowSpacing + chipHeight / 2 + 4);
|
||||||
m_layout->addWidget(scroll);
|
const int scrollBarWidth = scroll->verticalScrollBar()->sizeHint().width();
|
||||||
|
scroll->setFixedWidth(gridHost->sizeHint().width() + scrollBarWidth + 2);
|
||||||
|
m_layout->addWidget(scroll, 0, Qt::AlignLeft);
|
||||||
} else {
|
} else {
|
||||||
m_layout->addWidget(gridHost);
|
m_layout->addWidget(gridHost, 0, Qt::AlignLeft);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,37 @@ void writeProviderOverride(const QString &name, const QString &providerInstance)
|
|||||||
s->setValue(providerOverrideKey(name), providerInstance);
|
s->setValue(providerOverrideKey(name), providerInstance);
|
||||||
s->sync();
|
s->sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr auto kToolsOverrideGroup = "QodeAssist/AgentToolsOverrides";
|
||||||
|
|
||||||
|
Utils::Key toolsOverrideKey(const QString &name)
|
||||||
|
{
|
||||||
|
return Utils::Key(
|
||||||
|
QStringLiteral("%1/%2").arg(QLatin1StringView(kToolsOverrideGroup), name).toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<bool> readToolsOverride(const QString &name)
|
||||||
|
{
|
||||||
|
auto *s = Core::ICore::settings();
|
||||||
|
if (!s)
|
||||||
|
return std::nullopt;
|
||||||
|
const Utils::Key key = toolsOverrideKey(name);
|
||||||
|
if (!s->contains(key))
|
||||||
|
return std::nullopt;
|
||||||
|
return s->value(key).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToolsOverride(const QString &name, std::optional<bool> enabled)
|
||||||
|
{
|
||||||
|
auto *s = Core::ICore::settings();
|
||||||
|
if (!s)
|
||||||
|
return;
|
||||||
|
if (!enabled.has_value())
|
||||||
|
s->remove(toolsOverrideKey(name));
|
||||||
|
else
|
||||||
|
s->setValue(toolsOverrideKey(name), *enabled);
|
||||||
|
s->sync();
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace QodeAssist {
|
namespace QodeAssist {
|
||||||
@@ -146,6 +177,11 @@ void AgentFactory::reload()
|
|||||||
const QString overrideProvider = readProviderOverride(cfg.name);
|
const QString overrideProvider = readProviderOverride(cfg.name);
|
||||||
if (!overrideProvider.isEmpty())
|
if (!overrideProvider.isEmpty())
|
||||||
cfg.providerInstance = overrideProvider;
|
cfg.providerInstance = overrideProvider;
|
||||||
|
|
||||||
|
m_baseToolsByName.insert(cfg.name, cfg.enableTools);
|
||||||
|
const std::optional<bool> overrideTools = readToolsOverride(cfg.name);
|
||||||
|
if (overrideTools.has_value())
|
||||||
|
cfg.enableTools = *overrideTools;
|
||||||
}
|
}
|
||||||
emit agentsChanged();
|
emit agentsChanged();
|
||||||
}
|
}
|
||||||
@@ -289,6 +325,7 @@ void AgentFactory::clear()
|
|||||||
m_indexByName.clear();
|
m_indexByName.clear();
|
||||||
m_baseModelByName.clear();
|
m_baseModelByName.clear();
|
||||||
m_baseProviderByName.clear();
|
m_baseProviderByName.clear();
|
||||||
|
m_baseToolsByName.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Providers::ProviderInstanceFactory *AgentFactory::instanceFactory() const noexcept
|
Providers::ProviderInstanceFactory *AgentFactory::instanceFactory() const noexcept
|
||||||
@@ -361,4 +398,37 @@ void AgentFactory::clearAgentProviderOverride(const QString &name)
|
|||||||
writeProviderOverride(name, QString());
|
writeProviderOverride(name, QString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AgentFactory::setAgentToolsOverride(
|
||||||
|
const QString &name, std::optional<bool> enabled, QString *error)
|
||||||
|
{
|
||||||
|
Q_ASSERT(thread() == QThread::currentThread());
|
||||||
|
|
||||||
|
const auto it = m_indexByName.constFind(name);
|
||||||
|
if (it == m_indexByName.constEnd()) {
|
||||||
|
if (error)
|
||||||
|
*error = QStringLiteral("Agent '%1' is not registered").arg(name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AgentConfig &cfg = m_configs[it.value()];
|
||||||
|
const bool effective = enabled.has_value() ? *enabled
|
||||||
|
: m_baseToolsByName.value(name, cfg.enableTools);
|
||||||
|
if (cfg.enableTools == effective && readToolsOverride(name) == enabled)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
writeToolsOverride(name, enabled);
|
||||||
|
cfg.enableTools = effective;
|
||||||
|
emit agentToolsChanged(name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<bool> AgentFactory::agentToolsOverride(const QString &name) const
|
||||||
|
{
|
||||||
|
return readToolsOverride(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgentFactory::clearAgentToolsOverride(const QString &name)
|
||||||
|
{
|
||||||
|
writeToolsOverride(name, std::nullopt);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QodeAssist
|
} // namespace QodeAssist
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
@@ -60,18 +61,25 @@ public:
|
|||||||
[[nodiscard]] QString agentProviderOverride(const QString &name) const;
|
[[nodiscard]] QString agentProviderOverride(const QString &name) const;
|
||||||
void clearAgentProviderOverride(const QString &name);
|
void clearAgentProviderOverride(const QString &name);
|
||||||
|
|
||||||
|
bool setAgentToolsOverride(
|
||||||
|
const QString &name, std::optional<bool> enabled, QString *error = nullptr);
|
||||||
|
[[nodiscard]] std::optional<bool> agentToolsOverride(const QString &name) const;
|
||||||
|
void clearAgentToolsOverride(const QString &name);
|
||||||
|
|
||||||
[[nodiscard]] Providers::ProviderInstanceFactory *instanceFactory() const noexcept;
|
[[nodiscard]] Providers::ProviderInstanceFactory *instanceFactory() const noexcept;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void agentsChanged();
|
void agentsChanged();
|
||||||
void agentModelChanged(const QString &name);
|
void agentModelChanged(const QString &name);
|
||||||
void agentProviderChanged(const QString &name);
|
void agentProviderChanged(const QString &name);
|
||||||
|
void agentToolsChanged(const QString &name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<AgentConfig> m_configs;
|
std::vector<AgentConfig> m_configs;
|
||||||
QHash<QString, qsizetype> m_indexByName;
|
QHash<QString, qsizetype> m_indexByName;
|
||||||
QHash<QString, QString> m_baseModelByName;
|
QHash<QString, QString> m_baseModelByName;
|
||||||
QHash<QString, QString> m_baseProviderByName;
|
QHash<QString, QString> m_baseProviderByName;
|
||||||
|
QHash<QString, bool> m_baseToolsByName;
|
||||||
QPointer<Providers::ProviderInstanceFactory> m_instanceFactory;
|
QPointer<Providers::ProviderInstanceFactory> m_instanceFactory;
|
||||||
QPointer<Providers::ProviderSecretsStore> m_secrets;
|
QPointer<Providers::ProviderSecretsStore> m_secrets;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user