feat: Add agents and agents settings

This commit is contained in:
Petr Mironychev
2026-05-26 12:30:11 +02:00
parent 51ebe3e523
commit 97236c6069
70 changed files with 4308 additions and 296 deletions

94
sources/agents/Agent.cpp Normal file
View File

@@ -0,0 +1,94 @@
// Copyright (C) 2024-2026 Petr Mironychev
// SPDX-License-Identifier: GPL-3.0-or-later
#include "Agent.hpp"
#include <QThread>
#include "JsonPromptTemplate.hpp"
#include "PromptTemplate.hpp"
#include "Provider.hpp"
namespace QodeAssist {
using Providers::Provider;
using Templates::JsonPromptTemplate;
using Templates::PromptTemplate;
QString AgentConfig::validate(const AgentConfig &config)
{
if (config.name.isEmpty())
return QStringLiteral("Agent config has no name");
if (config.schemaVersion > AgentConfig::kSupportedSchemaVersion) {
return QStringLiteral(
"Agent config '%1' declares schema_version %2 but this plugin "
"supports at most %3 — update QodeAssist to use this profile")
.arg(config.name)
.arg(config.schemaVersion)
.arg(AgentConfig::kSupportedSchemaVersion);
}
if (config.providerInstance.isEmpty())
return QStringLiteral("Agent config '%1' has no provider_instance").arg(config.name);
if (config.model.isEmpty())
return QStringLiteral("Agent config '%1' has no model").arg(config.name);
if (config.endpoint.isEmpty())
return QStringLiteral("Agent config '%1' has no endpoint").arg(config.name);
if (config.messageFormat.isEmpty()) {
return QStringLiteral("Agent config '%1' has no [template].message_format")
.arg(config.name);
}
return {};
}
Agent::Agent(AgentConfig config, Providers::Provider *providerOwned, QObject *parent)
: QObject(parent)
, m_config(std::move(config))
, m_provider(providerOwned)
{
m_invalidReason = AgentConfig::validate(m_config);
if (!m_invalidReason.isEmpty())
return;
if (!m_provider) {
m_invalidReason
= QStringLiteral("Agent '%1' was constructed without a provider").arg(m_config.name);
return;
}
m_provider->setParent(this);
QString tmplErr;
m_promptTemplate = JsonPromptTemplate::fromConfig(m_config, &tmplErr);
if (!m_promptTemplate) {
m_invalidReason = tmplErr.isEmpty()
? QStringLiteral("Failed to build prompt template for agent '%1'")
.arg(m_config.name)
: tmplErr;
}
}
Agent::~Agent() = default;
PromptTemplate *Agent::promptTemplate() noexcept
{
return m_promptTemplate.get();
}
const PromptTemplate *Agent::promptTemplate() const noexcept
{
return m_promptTemplate.get();
}
QFuture<QList<QString>> Agent::installedModels()
{
Q_ASSERT_X(thread() == QThread::currentThread(), Q_FUNC_INFO,
"Agent::installedModels called from non-owning thread; "
"the underlying BaseClient is not thread-safe and must be "
"accessed from the Agent's owner thread");
if (!m_provider) {
return QtFuture::makeReadyValueFuture(QList<QString>{});
}
return m_provider->getInstalledModels(m_provider->url());
}
} // namespace QodeAssist