// 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 #include #include #include "ChatController.hpp" #include "AttachmentStaging.hpp" #include "ChatModel.hpp" #include "ConversationCoordinator.hpp" #include "templates/PromptProviderChat.hpp" #include namespace QodeAssist::Skills { class SkillsManager; } namespace QodeAssist::Chat { class ChatCompressor; class ChatConfigurationController; class FileEditController; class InputTokenCounter; class ChatFileStore; class SessionFileRegistry; class ChatRootView : public QQuickItem, private IAgentCatalogPort, private ICompressionPort, private ISendPort { Q_OBJECT Q_PROPERTY(QodeAssist::Chat::ChatModel *chatModel READ chatModel NOTIFY chatModelChanged FINAL) Q_PROPERTY(QString currentTemplate READ currentTemplate NOTIFY currentTemplateChanged FINAL) Q_PROPERTY(QStringList attachmentFiles READ attachmentFiles NOTIFY attachmentFilesChanged FINAL) Q_PROPERTY(int inputTokensCount READ inputTokensCount NOTIFY inputTokensCountChanged FINAL) Q_PROPERTY(QString chatFileName READ chatFileName NOTIFY chatFileNameChanged FINAL) Q_PROPERTY(QString textFontFamily READ textFontFamily NOTIFY textFamilyChanged FINAL) Q_PROPERTY(QString codeFontFamily READ codeFontFamily NOTIFY codeFamilyChanged FINAL) Q_PROPERTY(int codeFontSize READ codeFontSize NOTIFY codeFontSizeChanged FINAL) Q_PROPERTY(int textFontSize READ textFontSize NOTIFY textFontSizeChanged FINAL) Q_PROPERTY(int textFormat READ textFormat NOTIFY textFormatChanged FINAL) Q_PROPERTY(bool isRequestInProgress READ isRequestInProgress NOTIFY isRequestInProgressChanged FINAL) Q_PROPERTY(QString lastErrorMessage READ lastErrorMessage NOTIFY lastErrorMessageChanged FINAL) Q_PROPERTY(QString lastInfoMessage READ lastInfoMessage NOTIFY lastInfoMessageChanged FINAL) Q_PROPERTY(QString sendShortcutText READ sendShortcutText NOTIFY sendShortcutTextChanged FINAL) Q_PROPERTY(int currentMessageTotalEdits READ currentMessageTotalEdits NOTIFY currentMessageEditsStatsChanged FINAL) Q_PROPERTY(int currentMessageAppliedEdits READ currentMessageAppliedEdits NOTIFY currentMessageEditsStatsChanged FINAL) Q_PROPERTY(int currentMessagePendingEdits READ currentMessagePendingEdits NOTIFY currentMessageEditsStatsChanged FINAL) Q_PROPERTY(int currentMessageRejectedEdits READ currentMessageRejectedEdits NOTIFY currentMessageEditsStatsChanged FINAL) Q_PROPERTY(bool isAgentBound READ isAgentBound NOTIFY isAgentBoundChanged FINAL) Q_PROPERTY(QString agentSessionIssue READ agentSessionIssue NOTIFY agentSessionIssueChanged FINAL) Q_PROPERTY(bool canStartNewAgentSession READ canStartNewAgentSession NOTIFY agentSessionIssueChanged FINAL) Q_PROPERTY(bool canHandOverSummary READ canHandOverSummary NOTIFY agentSessionIssueChanged FINAL) Q_PROPERTY(QString summaryHandoverTooltip READ summaryHandoverTooltip NOTIFY agentSessionIssueChanged FINAL) Q_PROPERTY(bool canShrinkContext READ canShrinkContext NOTIFY shrinkContextStateChanged FINAL) Q_PROPERTY(QString shrinkContextTooltip READ shrinkContextTooltip NOTIFY shrinkContextStateChanged FINAL) Q_PROPERTY(QStringList availableConfigurations READ availableConfigurations NOTIFY availableConfigurationsChanged FINAL) Q_PROPERTY(QString currentConfiguration READ currentConfiguration NOTIFY currentConfigurationChanged FINAL) Q_PROPERTY(QString baseSystemPrompt READ baseSystemPrompt NOTIFY baseSystemPromptChanged FINAL) Q_PROPERTY(bool isCompressing READ isCompressing NOTIFY isCompressingChanged FINAL) Q_PROPERTY(bool isInEditor READ isInEditor NOTIFY isInEditorChanged FINAL) Q_PROPERTY(QString chatTitle READ chatTitle NOTIFY chatTitleChanged FINAL) QML_ELEMENT public: ChatRootView(QQuickItem *parent = nullptr); ~ChatRootView() override; ChatModel *chatModel() const; QString currentTemplate() const; void saveHistory(const QString &filePath); void loadHistory(const QString &filePath); Q_INVOKABLE void showSaveDialog(); Q_INVOKABLE void showLoadDialog(); void autosave(); QString getAutosaveFilePath() const; QString getAutosaveFilePath(const QString &firstMessage, const QStringList &attachments) const; QStringList attachmentFiles() const; Q_INVOKABLE void showAttachFilesDialog(); Q_INVOKABLE void addFilesToAttachList(const QStringList &filePaths); Q_INVOKABLE void removeFileFromAttachList(int index); Q_INVOKABLE QStringList convertUrlsToLocalPaths(const QVariantList &urls) const; Q_INVOKABLE void showAddImageDialog(); Q_INVOKABLE bool isImageFile(const QString &filePath) const; Q_INVOKABLE void calculateMessageTokensCount(const QString &message); Q_INVOKABLE bool isSendShortcut(int key, int modifiers) const; QString sendShortcutText() const; Q_INVOKABLE void openChatHistoryFolder(); Q_INVOKABLE void openSettings(); Q_INVOKABLE void openFileInEditor(const QString &filePath); Q_INVOKABLE void relocateToSplit(); Q_INVOKABLE void relocateToWindow(); void consumePendingChatFile(); Q_INVOKABLE void updateInputTokensCount(); int inputTokensCount() const; QString chatFileName() const; Q_INVOKABLE QString chatFilePath() const; void setRecentFilePath(const QString &filePath); QString textFontFamily() const; QString codeFontFamily() const; int codeFontSize() const; int textFontSize() const; int textFormat() const; bool isRequestInProgress() const; void setRequestProgressStatus(bool state); QString lastErrorMessage() const; Q_INVOKABLE QVariantList searchSlashCommands(const QString &query) const; Q_INVOKABLE void respondToPermission(const QString &requestId, const QString &optionId); Q_INVOKABLE void applyFileEdit(const QString &editId); Q_INVOKABLE void rejectFileEdit(const QString &editId); Q_INVOKABLE void undoFileEdit(const QString &editId); Q_INVOKABLE void openFileEditInEditor(const QString &editId); Q_INVOKABLE void applyAllFileEditsForCurrentMessage(); Q_INVOKABLE void undoAllFileEditsForCurrentMessage(); Q_INVOKABLE void updateCurrentMessageEditsStats(); Q_INVOKABLE void loadAvailableConfigurations(); Q_INVOKABLE void applyConfiguration(const QString &configName); Q_INVOKABLE void confirmChatTargetSwitch(); Q_INVOKABLE void cancelChatTargetSwitch(); QStringList availableConfigurations() const; QString currentConfiguration() const; Q_INVOKABLE void compressCurrentChat(); Q_INVOKABLE void cancelCompression(); QString baseSystemPrompt() const; int currentMessageTotalEdits() const; int currentMessageAppliedEdits() const; int currentMessagePendingEdits() const; int currentMessageRejectedEdits() const; QString lastInfoMessage() const; bool isAgentBound() const; QString agentSessionIssue() const; bool canStartNewAgentSession() const; bool canHandOverSummary() const; QString summaryHandoverTooltip() const; bool canShrinkContext() const; QString shrinkContextTooltip() const; Q_INVOKABLE void startNewAgentSession(); Q_INVOKABLE void startNewAgentSessionWithSummary(); bool isCompressing() const; bool isInEditor() const; void setInEditor(bool value); QString chatTitle() const; Q_INVOKABLE void requestNewChat(); public slots: void sendMessage(const QString &message); void copyToClipboard(const QString &text); void cancelRequest(); void clearAttachmentFiles(); void clearMessages(); void resetChatToMessage(int index); signals: void chatModelChanged(); void currentTemplateChanged(); void attachmentFilesChanged(); void inputTokensCountChanged(); void chatFileNameChanged(); void textFamilyChanged(); void codeFamilyChanged(); void codeFontSizeChanged(); void textFontSizeChanged(); void textFormatChanged(); void chatRequestStarted(); void isRequestInProgressChanged(); void lastErrorMessageChanged(); void lastInfoMessageChanged(); void sendShortcutTextChanged(); void currentMessageEditsStatsChanged(); void isAgentBoundChanged(); void agentSessionIssueChanged(); void shrinkContextStateChanged(); void slashCommandsChanged(); void availableConfigurationsChanged(); void currentConfigurationChanged(); void chatTargetSwitchNeedsNewChat(const QString &targetName); void baseSystemPromptChanged(); void isCompressingChanged(); void compressionCompleted(const QString &compressedChatPath); void compressionFailed(const QString &error); void isInEditorChanged(); void chatTitleChanged(); void closeHostRequested(); protected: void componentComplete() override; private: QVariantList searchSkills(const QString &query) const; QVariantList searchAgentCommands(const QString &query) const; QString computeChatTitle() const; void triggerOpenChatCommand(Utils::Id commandId); void handOffSession(); bool hasImageAttachments(const QStringList &attachments) const; std::optional agentById(const QString &agentId) const override; QString compressionConfigurationIssue() const override; bool isCompressionRunning() const override; void startTranscriptSummary() override; void startCompression() override; bool autoCompressEnabled() const override; int autoCompressThreshold() const override; int estimatedNextTokens() const override; bool prepareChatFileForCompression( const QString &message, const QStringList &attachments) override; void dispatch(const QString &message, const QStringList &attachments) override; SessionFileRegistry *sessionFileRegistry() const; Skills::SkillsManager *skillsManager() const; ChatModel *m_chatModel; Templates::PromptProviderChat m_promptProvider; ChatController *m_controller; AttachmentStaging *m_attachmentStaging; QString m_currentTemplate; QString m_recentFilePath; QStringList m_attachmentFiles; bool m_isInEditor = false; mutable QString m_cachedChatTitle; bool m_isRequestInProgress; QString m_lastErrorMessage; QString m_lastInfoMessage; ChatCompressor *m_chatCompressor; ChatConfigurationController *m_configurationController; FileEditController *m_fileEditController; InputTokenCounter *m_tokenCounter; ChatFileStore *m_historyStore; mutable QPointer m_sessionFileRegistry; mutable bool m_sessionFileRegistryResolved = false; mutable QPointer m_skillsManager; mutable bool m_skillsManagerResolved = false; ConversationCoordinator *m_coordinator = nullptr; }; } // namespace QodeAssist::Chat