#pragma once #include "segment.hpp" #include #include #include #include #include namespace ZShell::llm { class ChatMessage; class ChatSession; class LlmClient; class ChatGeneration : public QObject { Q_OBJECT QML_ELEMENT QML_UNCREATABLE("Chat generations are managed by ChatMessage") Q_PROPERTY(QString content READ content NOTIFY contentChanged) Q_PROPERTY(QString reasoning READ reasoning NOTIFY reasoningChanged) Q_PROPERTY(bool error READ error NOTIFY errorChanged) Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged) Q_PROPERTY( qint64 reasoningElapsedMs READ reasoningElapsedMs NOTIFY reasoningElapsedMsChanged) Q_PROPERTY( qint64 contentElapsedMs READ contentElapsedMs NOTIFY contentElapsedMsChanged) Q_PROPERTY( qint64 toolsElapsedMs READ toolsElapsedMs NOTIFY toolsElapsedMsChanged) Q_PROPERTY(bool streaming READ streaming NOTIFY streamingChanged) Q_PROPERTY( bool reasoningActive READ reasoningActive NOTIFY reasoningActiveChanged) Q_PROPERTY( bool hasRunningTool READ hasRunningTool NOTIFY hasRunningToolChanged) Q_PROPERTY(qint64 timestamp READ timestamp CONSTANT) Q_PROPERTY( QList segments READ segments NOTIFY segmentsChanged) Q_PROPERTY(int toolCallCount READ toolCallCount NOTIFY toolCallCountChanged) Q_PROPERTY( bool toolApprovalPending READ toolApprovalPending NOTIFY toolApprovalPendingChanged) Q_PROPERTY( QVariantList pendingToolCalls READ pendingToolCalls NOTIFY pendingToolCallsChanged) public: ChatGeneration(ChatMessage* message, qint64 timestamp, QObject* parent); [[nodiscard]] ChatMessage* message() const; [[nodiscard]] QString content() const; [[nodiscard]] QString reasoning() const; [[nodiscard]] bool error() const { return m_hasError; } [[nodiscard]] QString errorMessage() const { return m_errorMessage; } [[nodiscard]] bool reasoningActive() const; [[nodiscard]] qint64 reasoningElapsedMs() const; [[nodiscard]] qint64 contentElapsedMs() const; [[nodiscard]] qint64 toolsElapsedMs() const; [[nodiscard]] bool streaming() const { return m_streaming; } [[nodiscard]] qint64 timestamp() const { return m_timestamp; } [[nodiscard]] QList segments() const { return m_segments; } [[nodiscard]] QList toolCalls() const; [[nodiscard]] int toolCallCount() const; [[nodiscard]] bool hasRunningTool() const; [[nodiscard]] bool hasPendingTool() const; [[nodiscard]] bool toolApprovalPending() const { return m_approvalPending; } [[nodiscard]] QVariantList pendingToolCalls() const; Q_INVOKABLE void approveTools(); Q_INVOKABLE void denyTools(); Q_INVOKABLE void dismissError(); void setContent(const QString& value); void appendContent(const QString& piece); void appendReasoning(const QString& piece); void setStreaming(bool value); void setError(const QString& value); void setApprovalPending(bool value); [[nodiscard]] LlmTextSegment* openTextSegment(LlmSegment::Type type); [[nodiscard]] LlmToolCall* beginToolCall( const QString& name, const QString& toolCallId); void addSegment(LlmSegment* segment); void closeOpenSegments(); Q_SIGNALS: void contentChanged(); void reasoningChanged(); void errorChanged(); void errorMessageChanged(); void reasoningActiveChanged(); void reasoningElapsedMsChanged(); void contentElapsedMsChanged(); void toolsElapsedMsChanged(); void streamingChanged(); void hasRunningToolChanged(); void segmentsChanged(); void toolCallCountChanged(); void toolApprovalPendingChanged(); void pendingToolCallsChanged(); private: void updateReasoningActive(); [[nodiscard]] LlmClient* client() const; ChatMessage* m_message; QTimer m_timer; QList m_segments; bool m_reasoningActive = false; bool m_streaming = false; bool m_approvalPending = false; qint64 m_timestamp; bool m_hasError = false; QString m_errorMessage; }; } // namespace ZShell::llm