diff --git a/ChatView/ChatCompressor.cpp b/ChatView/ChatCompressor.cpp index 2ce9808..e655b33 100644 --- a/ChatView/ChatCompressor.cpp +++ b/ChatView/ChatCompressor.cpp @@ -76,6 +76,8 @@ void ChatCompressor::startCompression(const QString &chatFilePath, ChatModel *ch const QString customEndpoint = Settings::generalSettings().caCustomEndpoint(); const QString endpoint = !customEndpoint.isEmpty() ? customEndpoint : promptTemplate->endpoint(); + m_provider->client()->setTransferTimeout( + static_cast(Settings::generalSettings().requestTimeout() * 1000)); m_currentRequestId = m_provider->sendRequest( QUrl(Settings::generalSettings().caUrl()), payload, endpoint); LOG_MESSAGE(QString("Starting compression request: %1").arg(m_currentRequestId)); diff --git a/ChatView/ClientInterface.cpp b/ChatView/ClientInterface.cpp index 726c935..365233f 100644 --- a/ChatView/ClientInterface.cpp +++ b/ChatView/ClientInterface.cpp @@ -338,6 +338,9 @@ void ClientInterface::sendMessage( provider->client()->setMaxToolContinuations( Settings::toolsSettings().maxToolContinuations()); + provider->client()->setTransferTimeout( + static_cast(Settings::generalSettings().requestTimeout() * 1000)); + connect( provider->client(), &::LLMQore::BaseClient::chunkReceived, diff --git a/LLMClientInterface.cpp b/LLMClientInterface.cpp index e44fd71..4938f4e 100644 --- a/LLMClientInterface.cpp +++ b/LLMClientInterface.cpp @@ -354,6 +354,9 @@ void LLMClientInterface::handleCompletion(const QJsonObject &request) &LLMClientInterface::handleRequestFailed, Qt::UniqueConnection); + provider->client()->setTransferTimeout( + static_cast(m_generalSettings.requestTimeout() * 1000)); + auto requestId = provider->sendRequest(QUrl(url), payload, resolveEndpoint(promptTemplate, isPreset1Active)); m_activeRequests[requestId] = {request, provider}; diff --git a/QuickRefactorHandler.cpp b/QuickRefactorHandler.cpp index 888b9a3..3eccf10 100644 --- a/QuickRefactorHandler.cpp +++ b/QuickRefactorHandler.cpp @@ -144,6 +144,9 @@ void QuickRefactorHandler::prepareAndSendRequest( provider->client()->setMaxToolContinuations( Settings::toolsSettings().maxToolContinuations()); + provider->client()->setTransferTimeout( + static_cast(Settings::generalSettings().requestTimeout() * 1000)); + m_isRefactoringInProgress = true; connect( diff --git a/settings/GeneralSettings.cpp b/settings/GeneralSettings.cpp index ab8f361..8f7df30 100644 --- a/settings/GeneralSettings.cpp +++ b/settings/GeneralSettings.cpp @@ -73,6 +73,17 @@ GeneralSettings::GeneralSettings() enableCheckUpdate.setLabelText(TrConstants::ENABLE_CHECK_UPDATE_ON_START); enableCheckUpdate.setDefaultValue(true); + requestTimeout.setSettingsKey(Constants::REQUEST_TIMEOUT); + requestTimeout.setLabelText(Tr::tr("Request timeout (seconds):")); + requestTimeout.setToolTip(Tr::tr( + "Maximum time to wait for the model to send data before a request is aborted. " + "Applies to all requests — chat, code completion, quick refactor and chat compression. " + "The timer resets every time data is received, so this effectively limits the " + "time-to-first-token and any stall between tokens. Increase it for slow or local " + "models that need a long time to start responding. Set to 0 to disable the timeout.")); + requestTimeout.setRange(0, 3600); + requestTimeout.setDefaultValue(120); + resetToDefaults.m_buttonText = TrConstants::RESET_TO_DEFAULTS; checkUpdate.m_buttonText = TrConstants::CHECK_UPDATE; @@ -333,6 +344,10 @@ GeneralSettings::GeneralSettings() Row{qrPresetConfig, qrConfigureApiKey, Stretch{1}}, qrGrid}}; + auto networkGroup = Group{ + title(Tr::tr("Network")), + Column{Row{requestTimeout, Stretch{1}}}}; + auto *supportLabel = new QLabel(Tr::tr("Support the development of QodeAssist:")); auto *supportLinks = new QLabel( @@ -348,12 +363,14 @@ GeneralSettings::GeneralSettings() supportLinks->setTextFormat(Qt::RichText); auto rootLayout = Column{ - Row{supportLabel, supportLinks, Stretch{1}}, + Row{supportLabel, supportLinks, Stretch{1}, checkUpdate, resetToDefaults}, Space{8}, - Row{enableQodeAssist, Stretch{1}, Row{checkUpdate, resetToDefaults}}, + Row{enableQodeAssist, Stretch{1}}, Row{enableLogging, Stretch{1}}, Row{enableCheckUpdate, Stretch{1}}, Space{8}, + networkGroup, + Space{8}, ccGroup, Space{8}, caGroup, @@ -679,6 +696,7 @@ void GeneralSettings::resetPageToDefaults() if (reply == QMessageBox::Yes) { resetAspect(enableQodeAssist); resetAspect(enableLogging); + resetAspect(requestTimeout); resetAspect(ccProvider); resetAspect(ccModel); resetAspect(ccTemplate); diff --git a/settings/GeneralSettings.hpp b/settings/GeneralSettings.hpp index 09963a5..abc1cd0 100644 --- a/settings/GeneralSettings.hpp +++ b/settings/GeneralSettings.hpp @@ -28,6 +28,8 @@ public: Utils::BoolAspect enableLogging{this}; Utils::BoolAspect enableCheckUpdate{this}; + Utils::IntegerAspect requestTimeout{this}; + ButtonAspect checkUpdate{this}; ButtonAspect resetToDefaults{this}; diff --git a/settings/SettingsConstants.hpp b/settings/SettingsConstants.hpp index 1b310e2..57f2c97 100644 --- a/settings/SettingsConstants.hpp +++ b/settings/SettingsConstants.hpp @@ -60,6 +60,7 @@ const char CC_SHOW_PROGRESS_WIDGET[] = "QodeAssist.ccShowProgressWidget"; const char CC_USE_OPEN_FILES_CONTEXT[] = "QodeAssist.ccUseOpenFilesContext"; const char ENABLE_LOGGING[] = "QodeAssist.enableLogging"; const char ENABLE_CHECK_UPDATE[] = "QodeAssist.enableCheckUpdate"; +const char REQUEST_TIMEOUT[] = "QodeAssist.requestTimeout"; const char PROVIDER_PATHS[] = "QodeAssist.providerPaths"; const char СС_START_SUGGESTION_TIMER[] = "QodeAssist.startSuggestionTimer"; diff --git a/sources/external/llmqore b/sources/external/llmqore index 68ecec3..48e6dfb 160000 --- a/sources/external/llmqore +++ b/sources/external/llmqore @@ -1 +1 @@ -Subproject commit 68ecec3dc9fe2600eab20c53dad8327e8696dc60 +Subproject commit 48e6dfb30db49162f5ebbdbedaa9049f5cfd077c