Files
QodeAssist/sources/agents/AgentRouter.cpp
2026-05-26 12:31:00 +02:00

86 lines
2.4 KiB
C++

// Copyright (C) 2024-2026 Petr Mironychev
// SPDX-License-Identifier: GPL-3.0-or-later
#include "AgentRouter.hpp"
#include <QFileInfo>
#include <QRegularExpression>
#include "AgentFactory.hpp"
namespace QodeAssist::AgentRouter {
namespace {
bool matchesAnyGlob(const QStringList &patterns, const QString &subject)
{
if (subject.isEmpty())
return false;
for (const QString &pat : patterns) {
const QRegularExpression re(
QRegularExpression::anchoredPattern(
QRegularExpression::wildcardToRegularExpression(
pat, QRegularExpression::NonPathWildcardConversion)),
QRegularExpression::CaseInsensitiveOption);
if (re.isValid() && re.match(subject).hasMatch())
return true;
}
return false;
}
bool matchesFilePatterns(const QStringList &patterns, const QString &filePath)
{
if (patterns.isEmpty())
return true;
if (filePath.isEmpty())
return false;
const QString name = QFileInfo(filePath).fileName();
return matchesAnyGlob(patterns, name) || matchesAnyGlob(patterns, filePath);
}
bool matchesPathPatterns(const QStringList &patterns, const QString &filePath)
{
if (patterns.isEmpty())
return true;
if (filePath.isEmpty())
return false;
return matchesAnyGlob(patterns, filePath);
}
bool matchesProjectNames(const QStringList &names, const QString &projectName)
{
if (names.isEmpty())
return true; // dimension unconstrained
if (projectName.isEmpty())
return false;
// Project names are user-facing identifiers, not paths — case
// sensitive comparison matches what ProjectExplorer hands us.
return names.contains(projectName);
}
} // namespace
bool matches(const AgentConfig::Match &m, const Context &ctx)
{
if (m.isEmpty())
return true; // explicit catch-all
return matchesFilePatterns(m.filePatterns, ctx.filePath)
&& matchesPathPatterns(m.pathPatterns, ctx.filePath)
&& matchesProjectNames(m.projectNames, ctx.projectName);
}
QString pickAgent(
const QStringList &roster, const Context &ctx, const AgentFactory &factory)
{
for (const QString &name : roster) {
const AgentConfig *cfg = factory.configByName(name);
if (!cfg)
continue; // stale roster entry — silently skip
if (matches(cfg->match, ctx))
return name;
}
return {};
}
} // namespace QodeAssist::AgentRouter