#pragma once #include "message.hpp" #include "messagemodel.hpp" #include #include #include #include #include #include namespace ZShell::llm { class ChatStore; class LlmClient; class Workspace; class ChatSession : public QObject { Q_OBJECT QML_ELEMENT QML_UNCREATABLE("Chat sessions are owned by the LlmClient singleton") Q_PROPERTY(QString id READ id CONSTANT) Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) Q_PROPERTY(QString icon READ icon WRITE setIcon NOTIFY iconChanged) Q_PROPERTY(QDateTime createdAt READ createdAt CONSTANT) Q_PROPERTY(QDateTime updatedAt READ updatedAt NOTIFY updatedAtChanged) Q_PROPERTY(bool pinned READ pinned WRITE setPinned NOTIFY pinnedChanged) Q_PROPERTY(bool loaded READ isLoaded NOTIFY loaded) Q_PROPERTY(int messageCount READ messageCount NOTIFY messageCountChanged) Q_PROPERTY(int usageTokens READ usageTokens NOTIFY usageTokensChanged) Q_PROPERTY( ZShell::llm::ChatMessageModel* messagesModel READ messagesModel CONSTANT) Q_PROPERTY( QString attachmentError READ attachmentError NOTIFY attachmentErrorChanged) public: ChatSession(ChatStore* store, const QString& id, QObject* parent = nullptr); [[nodiscard]] QString id() const { return m_id; } [[nodiscard]] QString title() const { return m_title; } [[nodiscard]] QString icon() const { return m_icon; } [[nodiscard]] QDateTime createdAt() const { return QDateTime::fromMSecsSinceEpoch(m_createdAt); } [[nodiscard]] QDateTime updatedAt() const { return QDateTime::fromMSecsSinceEpoch(m_updatedAt); } [[nodiscard]] qint64 createdAtMs() const { return m_createdAt; } [[nodiscard]] qint64 updatedAtMs() const { return m_updatedAt; } [[nodiscard]] bool pinned() const { return m_pinned; } [[nodiscard]] int messageCount() const { return m_messageCount; } [[nodiscard]] int usageTokens() const { return m_usageTokens; } [[nodiscard]] ChatMessageModel* messagesModel(); void ensureLoaded(); [[nodiscard]] bool isLoaded() const { return m_loaded; } void markLoaded(); [[nodiscard]] QString attachmentError() const { return m_attachmentError; } [[nodiscard]] ChatStore* store() const { return m_store; } [[nodiscard]] LlmClient* client() const; [[nodiscard]] Workspace* workspace() const { return m_workspace; } void setTitle(const QString& value); void setIcon(const QString& value); void setUpdatedAt(qint64 value); void setPinned(bool value); void setUsageTokens(int value); void hydrate( const QString& title, const QString& icon, qint64 createdAt, qint64 updatedAt, int messageCount, bool pinned); [[nodiscard]] bool isCommitted() const { return m_committed; } void setCommitted(bool value) { m_committed = value; } void adoptMessages(QList messages); void persist(); void removeMessage(ChatMessage* message); void clearMessages(); Q_INVOKABLE QVariantList addAttachments(const QStringList& paths); Q_INVOKABLE bool clipboardHasAttachment(); Q_INVOKABLE QVariantList pasteAttachments(); Q_INVOKABLE void sendMessage(const QString& text); Q_INVOKABLE void sendMessage( const QString& text, const QVariantList& attachments); Q_INVOKABLE void retry(ZShell::llm::ChatMessage* target); Q_INVOKABLE void continueFrom(ZShell::llm::ChatMessage* message); Q_INVOKABLE void clear(); Q_SIGNALS: void titleChanged(); void iconChanged(); void updatedAtChanged(); void pinnedChanged(); void messageCountChanged(); void loaded(); void usageTokensChanged(); void attachmentErrorChanged(); private: void onModelRowsChanged(); ChatMessage* appendNewest( ChatMessage::Role role, const QString& content, qint64 timestamp); void startGeneration(ChatMessage* target); void setCount(int value); void setAttachmentError(const QString& value); ChatStore* m_store; QString m_id; bool m_committed = false; QString m_title; QString m_icon; qint64 m_createdAt = 0; qint64 m_updatedAt = 0; bool m_pinned = false; int m_messageCount = 0; int m_usageTokens = 0; ChatMessageModel* m_model = nullptr; Workspace* m_workspace = nullptr; bool m_loadRequested = false; bool m_loaded = false; QString m_attachmentError; }; } // namespace ZShell::llm