ollie/kde/gui/ollie9pclient.h

146 lines
6.2 KiB
C++

#ifndef OLLIE9PCLIENT_H
#define OLLIE9PCLIENT_H
#include <QObject>
#include <QVariantList>
#include <QHash>
#include <QSet>
#include <QTimer>
#if QT_VERSION_MAJOR >= 6
#include <QQmlEngine>
#endif
#include "lib9pclient.h"
#include "nativestreamer.h"
// 9P-based client for ollie. Uses native libollie9p for all operations.
// Streaming files (chat, statewait, eventwait) use NativeStreamer threads.
class Ollie9pClient : public QObject
{
Q_OBJECT
#if QT_VERSION_MAJOR >= 6
QML_ELEMENT
QML_SINGLETON
#endif
Q_PROPERTY(QVariantList sessions READ sessions NOTIFY sessionsChanged)
Q_PROPERTY(QString activeSessionId READ activeSessionId WRITE setActiveSessionId NOTIFY activeSessionIdChanged)
Q_PROPERTY(QString activeAgentId READ activeAgentId NOTIFY activeAgentIdChanged)
Q_PROPERTY(QString activeState READ activeState NOTIFY activeStateChanged)
Q_PROPERTY(bool rootBackendsLoaded READ rootBackendsLoaded NOTIFY rootBackendsLoadedChanged)
Q_PROPERTY(QStringList availableBackends READ availableBackends NOTIFY availableBackendsChanged)
Q_PROPERTY(bool rootAgentsLoaded READ rootAgentsLoaded NOTIFY rootAgentsLoadedChanged)
Q_PROPERTY(QStringList availableAgents READ availableAgents NOTIFY availableAgentsChanged)
Q_PROPERTY(bool rootModelsLoaded READ rootModelsLoaded NOTIFY rootModelsLoadedChanged)
Q_PROPERTY(QString currentBackend READ currentBackend WRITE setCurrentBackend NOTIFY currentBackendChanged)
Q_PROPERTY(bool daemonConnected READ daemonConnected NOTIFY daemonConnectedChanged)
public:
explicit Ollie9pClient(QObject *parent = nullptr);
~Ollie9pClient();
QVariantList sessions() const { return m_sessions; }
QString activeSessionId() const { return m_activeSessionId; }
Q_INVOKABLE void setActiveSessionId(const QString &id);
QString activeAgentId() const { return m_agentId; }
QString activeState() const { return m_activeState; }
bool rootBackendsLoaded() const { return m_rootBackendsLoaded; }
QStringList availableBackends() const { return m_availableBackends; }
bool rootAgentsLoaded() const { return m_rootAgentsLoaded; }
QStringList availableAgents() const { return m_availableAgents; }
bool rootModelsLoaded() const { return m_rootModelsLoaded; }
QString currentBackend() const { return m_currentBackend; }
bool daemonConnected() const { return m_daemonConnected; }
Q_INVOKABLE QString agentState(const QString &sessionId, const QString &agentId) const;
Q_INVOKABLE QString sessionConnectionColor(const QString &sessionId) const;
Q_INVOKABLE void setCurrentBackend(const QString &backend) {
if (m_currentBackend == backend) return;
m_currentBackend = backend;
emit currentBackendChanged();
}
Q_INVOKABLE void refreshSessions();
Q_INVOKABLE QString readLog();
Q_INVOKABLE QString readLogForSession(const QString &sessionId, const QString &agentId);
Q_INVOKABLE bool submit(const QString &prompt);
Q_INVOKABLE bool interrupt();
Q_INVOKABLE bool kill();
Q_INVOKABLE bool killSession(const QString &sessionId);
Q_INVOKABLE bool pauseSession(const QString &sessionId);
Q_INVOKABLE bool resumeSession(const QString &sessionId);
Q_INVOKABLE bool isSessionPaused(const QString &sessionId) const;
Q_INVOKABLE QString getConfig();
Q_INVOKABLE QStringList getAgents(const QString &sessionId);
QString agentKey(const QString &sessionId, const QString &agentId) const;
Q_INVOKABLE void setActiveAgentId(const QString &agentId);
Q_INVOKABLE void switchAgent(const QString &sessionId, const QString &agentId);
Q_INVOKABLE void loadRootBackends();
Q_INVOKABLE void loadRootAgents();
Q_INVOKABLE QStringList getAvailableModels(const QString &backend) const;
Q_INVOKABLE bool createQuickSession();
Q_INVOKABLE QString createSession(const QString &name, const QString &remote);
Q_INVOKABLE QString createAgent(const QString &sessionId, const QString &cwd, const QString &backend, const QString &model, const QString &agent, const QString &remote, const QString &agentAlias);
Q_INVOKABLE bool killAgent(const QString &sessionId, const QString &agentId);
Q_INVOKABLE bool renameSession(const QString &sessionId, const QString &newName);
Q_INVOKABLE bool renameAgent(const QString &sessionId, const QString &agentId, const QString &newName);
Q_INVOKABLE QString lastError() const { return m_9p ? m_9p->lastError() : QString(); }
signals:
void sessionsChanged();
void activeSessionIdChanged();
void activeAgentIdChanged();
void activeStateChanged();
void agentStateChanged(const QString &sessionId, const QString &agentId, const QString &state);
void chatReceived(const QString &text);
void rootBackendsLoadedChanged();
void availableBackendsChanged();
void rootAgentsLoadedChanged();
void availableAgentsChanged();
void rootModelsLoadedChanged();
void currentBackendChanged();
void daemonConnectedChanged();
private:
void stopAgentStreams();
void stopStreams();
QString agentPath() const;
void ensureRootDataLoaded();
void setDaemonConnected(bool connected);
void startActiveAgentStreams();
void startEventStream();
void handleEvent(const QString &eventLine);
void heartbeat();
// Native 9P client (persistent connection, no subprocess overhead)
Lib9pClient *m_9p = nullptr;
// Heartbeat timer — detects daemon death
QTimer *m_heartbeatTimer = nullptr;
QVariantList m_sessions;
QString m_activeSessionId;
QString m_activeState = "idle";
QString m_agentId;
// Root data cache
bool m_rootBackendsLoaded = false;
QStringList m_availableBackends;
bool m_rootAgentsLoaded = false;
QStringList m_availableAgents;
bool m_rootModelsLoaded = false;
QVariantMap m_rootModels;
QString m_currentBackend;
bool m_daemonConnected = false;
// Agent state cache — updated via delta events
QHash<QString, QString> m_agentStateValues;
// Native streaming readers (replace StreamFsm/NinePConnection)
NativeStreamer *m_chat = nullptr; // Oneshot — reads agent chat log
NativeStreamer *m_state = nullptr; // Guarded — reads agent statewait
NativeStreamer *m_event = nullptr; // Looping — reads server eventwait
};
#endif // OLLIE9PCLIENT_H