refactor: Remove project rules

This commit is contained in:
Petr Mironychev
2026-06-11 13:36:23 +02:00
parent 2c9475cddf
commit 05fe38e289
45 changed files with 1333 additions and 299 deletions

View File

@@ -3,6 +3,7 @@ add_library(Providers STATIC
Provider.hpp Provider.cpp
ProviderFactory.hpp ProviderFactory.cpp
GenericProvider.hpp GenericProvider.cpp
ClaudeCacheControl.hpp
)
target_link_libraries(Providers

View File

@@ -0,0 +1,90 @@
// Copyright (C) 2024-2026 Petr Mironychev
// SPDX-License-Identifier: GPL-3.0-or-later
// Additional attribution terms under GPLv3 §7(b) apply — see LICENSE
#pragma once
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonValue>
#include <QString>
namespace QodeAssist::Providers::ClaudeCacheControl {
inline QJsonObject buildBreakpoint(bool extendedTtl)
{
QJsonObject cacheControl{{"type", "ephemeral"}};
if (extendedTtl)
cacheControl["ttl"] = "1h";
return cacheControl;
}
inline void markLastBlock(QJsonArray &blocks, const QJsonObject &cacheControl)
{
if (blocks.isEmpty())
return;
QJsonObject last = blocks.last().toObject();
last["cache_control"] = cacheControl;
blocks.replace(blocks.size() - 1, last);
}
inline void applyToSystem(QJsonObject &request, const QJsonObject &cacheControl)
{
if (!request.contains("system"))
return;
const QJsonValue sys = request.value("system");
if (sys.isString()) {
const QString text = sys.toString();
if (!text.isEmpty()) {
request["system"] = QJsonArray{QJsonObject{
{"type", "text"}, {"text", text}, {"cache_control", cacheControl}}};
}
} else if (sys.isArray()) {
QJsonArray blocks = sys.toArray();
markLastBlock(blocks, cacheControl);
request["system"] = blocks;
}
}
inline void applyToTools(QJsonObject &request, const QJsonObject &cacheControl)
{
if (!request.contains("tools"))
return;
QJsonArray tools = request.value("tools").toArray();
markLastBlock(tools, cacheControl);
request["tools"] = tools;
}
inline void applyToHistory(QJsonObject &request, const QJsonObject &cacheControl)
{
if (!request.contains("messages"))
return;
QJsonArray messages = request.value("messages").toArray();
if (messages.size() < 2)
return;
const int idx = messages.size() - 2;
QJsonObject msg = messages[idx].toObject();
const QJsonValue content = msg.value("content");
if (content.isString()) {
msg["content"] = QJsonArray{QJsonObject{
{"type", "text"}, {"text", content.toString()}, {"cache_control", cacheControl}}};
} else if (content.isArray()) {
QJsonArray blocks = content.toArray();
markLastBlock(blocks, cacheControl);
msg["content"] = blocks;
}
messages.replace(idx, msg);
request["messages"] = messages;
}
inline void apply(QJsonObject &request, bool extendedTtl)
{
const QJsonObject cacheControl = buildBreakpoint(extendedTtl);
applyToSystem(request, cacheControl);
applyToTools(request, cacheControl);
applyToHistory(request, cacheControl);
}
} // namespace QodeAssist::Providers::ClaudeCacheControl

View File

@@ -4,9 +4,11 @@
#include "Provider.hpp"
#include "ClaudeCacheControl.hpp"
#include "PromptTemplate.hpp"
#include <LLMQore/BaseClient.hpp>
#include <LLMQore/ClaudeClient.hpp>
#include <LLMQore/ToolsManager.hpp>
#include <QJsonArray>
@@ -25,24 +27,27 @@ bool Provider::prepareRequest(
PromptTemplate *prompt,
const ContextData &context,
bool isToolsEnabled,
bool isThinkingEnabled)
QString *errorOut)
{
if (!prompt) {
LOG_MESSAGE(QString("Provider '%1': null template").arg(name()));
const auto fail = [errorOut](const QString &message) {
LOG_MESSAGE(message);
if (errorOut)
*errorOut = message;
return false;
}
};
if (!prompt)
return fail(QString("Provider '%1': null template").arg(name()));
if (!prompt->isSupportProvider(providerID())) {
LOG_MESSAGE(QString("Template '%1' doesn't support provider '%2'")
return fail(QString("Template '%1' doesn't support provider '%2'")
.arg(prompt->name(), name()));
return false;
}
if (!prompt->buildFullRequest(request, context, isThinkingEnabled)) {
LOG_MESSAGE(
QString("Provider '%1': template '%2' failed to build request")
if (!prompt->buildFullRequest(request, context)) {
return fail(
QString("Provider '%1': template '%2' failed to build request (see log)")
.arg(name(), prompt->name()));
return false;
}
if (isToolsEnabled) {
@@ -51,9 +56,21 @@ bool Provider::prepareRequest(
request["tools"] = toolsDefinitions;
}
}
if (m_promptCachingEnabled)
ClaudeCacheControl::apply(request, m_promptCachingExtendedTtl);
return true;
}
void Provider::setPromptCaching(bool enabled, bool extendedTtl)
{
m_promptCachingEnabled = enabled;
m_promptCachingExtendedTtl = enabled && extendedTtl;
if (auto *claude = qobject_cast<::LLMQore::ClaudeClient *>(client()))
claude->setUseExtendedCacheTTL(m_promptCachingExtendedTtl);
}
RequestID Provider::sendRequest(
const QUrl &url, const QJsonObject &payload, const QString &endpoint)
{

View File

@@ -61,7 +61,7 @@ public:
PromptTemplate *prompt,
const ContextData &context,
bool isToolsEnabled,
bool isThinkingEnabled);
QString *errorOut = nullptr);
virtual QFuture<QList<QString>> getInstalledModels(const QString &url) = 0;
virtual ProviderID providerID() const = 0;
virtual ProviderCapabilities capabilities() const { return {}; }
@@ -73,9 +73,13 @@ public:
void cancelRequest(const RequestID &requestId);
::LLMQore::ToolsManager *toolsManager() const;
void setPromptCaching(bool enabled, bool extendedTtl);
private:
QString m_url;
QString m_apiKey;
bool m_promptCachingEnabled = false;
bool m_promptCachingExtendedTtl = false;
};
} // namespace QodeAssist::Providers