fix: Remove token calibration

This commit is contained in:
Petr Mironychev
2026-06-28 22:10:29 +02:00
parent dc3100f054
commit a6921f523a
3 changed files with 30 additions and 35 deletions

View File

@@ -131,6 +131,7 @@ ChatRootView::ChatRootView(QQuickItem *parent)
connect(m_chatModel, &ChatModel::modelReseted, this, [this]() { connect(m_chatModel, &ChatModel::modelReseted, this, [this]() {
setRecentFilePath(QString{}); setRecentFilePath(QString{});
m_tokenCounter->resetServerUsage();
m_fileEditController->clearCurrentRequestId(); m_fileEditController->clearCurrentRequestId();
}); });
auto maybeEmitTitle = [this] { auto maybeEmitTitle = [this] {
@@ -231,8 +232,8 @@ ChatRootView::ChatRootView(QQuickItem *parent)
m_clientInterface, m_clientInterface,
&ClientInterface::messageUsageReceived, &ClientInterface::messageUsageReceived,
this, this,
[this](int promptTokens, int /*completionTokens*/, int /*cached*/, int /*reasoning*/) { [this](int promptTokens, int /*completionTokens*/, int cachedTokens, int /*reasoning*/) {
m_tokenCounter->recordServerUsage(promptTokens); m_tokenCounter->recordServerUsage(promptTokens, cachedTokens);
}); });
connect( connect(
@@ -489,8 +490,6 @@ void ChatRootView::dispatchSend(
} }
} }
m_tokenCounter->recordSent();
if (currentChatAgent().isEmpty()) if (currentChatAgent().isEmpty())
loadAvailableChatAgents(); loadAvailableChatAgents();

View File

@@ -4,9 +4,6 @@
#include "InputTokenCounter.hpp" #include "InputTokenCounter.hpp"
#include <algorithm>
#include "Logger.hpp"
#include "context/ContextManager.hpp" #include "context/ContextManager.hpp"
#include "context/TokenUtils.hpp" #include "context/TokenUtils.hpp"
@@ -49,8 +46,6 @@ void InputTokenCounter::setLinkedFiles(const QStringList &linkedFiles)
void InputTokenCounter::recompute() void InputTokenCounter::recompute()
{ {
int inputTokens = m_messageTokens;
const auto splitImageEstimate = [](const QStringList &paths, QStringList &textPaths) { const auto splitImageEstimate = [](const QStringList &paths, QStringList &textPaths) {
int imageTokens = 0; int imageTokens = 0;
for (const QString &p : paths) { for (const QString &p : paths) {
@@ -62,15 +57,24 @@ void InputTokenCounter::recompute()
return imageTokens; return imageTokens;
}; };
int pendingTokens = m_messageTokens;
if (!m_attachments.isEmpty()) { if (!m_attachments.isEmpty()) {
QStringList textPaths; QStringList textPaths;
inputTokens += splitImageEstimate(m_attachments, textPaths); pendingTokens += splitImageEstimate(m_attachments, textPaths);
if (!textPaths.isEmpty()) { if (!textPaths.isEmpty()) {
auto attachFiles = m_contextManager->getContentFiles(textPaths); auto attachFiles = m_contextManager->getContentFiles(textPaths);
inputTokens += Context::TokenUtils::estimateFilesTokens(attachFiles); pendingTokens += Context::TokenUtils::estimateFilesTokens(attachFiles);
} }
} }
if (m_hasServerUsage && m_history && !m_history->isEmpty()) {
m_inputTokens = m_serverInputTokens + pendingTokens;
emit inputTokensChanged();
return;
}
int inputTokens = pendingTokens;
if (!m_linkedFiles.isEmpty()) { if (!m_linkedFiles.isEmpty()) {
QStringList textPaths; QStringList textPaths;
inputTokens += splitImageEstimate(m_linkedFiles, textPaths); inputTokens += splitImageEstimate(m_linkedFiles, textPaths);
@@ -87,33 +91,25 @@ void InputTokenCounter::recompute()
} }
} }
m_inputTokens = static_cast<int>(inputTokens * m_calibrationFactor); m_inputTokens = inputTokens;
emit inputTokensChanged(); emit inputTokensChanged();
} }
void InputTokenCounter::recordSent() void InputTokenCounter::recordServerUsage(int promptTokens, int cachedTokens)
{ {
m_lastSentEstimate = m_calibrationFactor > 0.0 const int serverInput = promptTokens + cachedTokens;
? static_cast<int>(m_inputTokens / m_calibrationFactor) if (serverInput <= 0)
: m_inputTokens;
}
void InputTokenCounter::recordServerUsage(int promptTokens)
{
if (promptTokens <= 0 || m_lastSentEstimate <= 0)
return; return;
const double rawFactor m_serverInputTokens = serverInput;
= static_cast<double>(promptTokens) / static_cast<double>(m_lastSentEstimate); m_hasServerUsage = true;
const double clamped = std::clamp(rawFactor, 0.5, 3.0); recompute();
m_calibrationFactor = 0.5 * m_calibrationFactor + 0.5 * clamped; }
LOG_MESSAGE(QString("Token calibration: server=%1 estimated=%2 ratio=%3 ema=%4")
.arg(promptTokens)
.arg(m_lastSentEstimate)
.arg(rawFactor, 0, 'f', 3)
.arg(m_calibrationFactor, 0, 'f', 3));
void InputTokenCounter::resetServerUsage()
{
m_serverInputTokens = 0;
m_hasServerUsage = false;
recompute(); recompute();
} }

View File

@@ -34,8 +34,8 @@ public:
void setLinkedFiles(const QStringList &linkedFiles); void setLinkedFiles(const QStringList &linkedFiles);
void recompute(); void recompute();
void recordSent(); void recordServerUsage(int promptTokens, int cachedTokens);
void recordServerUsage(int promptTokens); void resetServerUsage();
signals: signals:
void inputTokensChanged(); void inputTokensChanged();
@@ -48,8 +48,8 @@ private:
QStringList m_linkedFiles; QStringList m_linkedFiles;
int m_messageTokens{0}; int m_messageTokens{0};
int m_inputTokens{0}; int m_inputTokens{0};
int m_lastSentEstimate{0}; int m_serverInputTokens{0};
double m_calibrationFactor{1.0}; bool m_hasServerUsage{false};
}; };
} // namespace QodeAssist::Chat } // namespace QodeAssist::Chat