#include "session_manager.h" #include "libollie.h" #include #include #include // Global pointer to the singleton — used by C callbacks to route events. static SessionManager *g_instance = nullptr; // --- C callback handlers (called from Go goroutines, must be thread-safe) --- static void onStateChange(const char *session_id, const char *state) { if (!g_instance) return; QString sid = QString::fromUtf8(session_id); QString st = QString::fromUtf8(state); QMetaObject::invokeMethod(g_instance, "handleStateChange", Qt::QueuedConnection, Q_ARG(QString, sid), Q_ARG(QString, st)); } static void onChatUpdate(const char *session_id, int64_t offset, const char *text, int len) { if (!g_instance) return; QString sid = QString::fromUtf8(session_id); QString txt = QString::fromUtf8(text, len); qlonglong off = static_cast(offset); QMetaObject::invokeMethod(g_instance, [sid, off, txt]() { emit g_instance->ChatUpdated(sid, off, txt); }, Qt::QueuedConnection); } // --- SessionManager implementation --- SessionManager::SessionManager(QObject *parent) : QObject(parent) { g_instance = this; ollie_init(nullptr); installCallbacks(); qDebug() << "SessionManager: initialized ollie core"; } SessionManager::~SessionManager() { ollie_shutdown(); g_instance = nullptr; qDebug() << "SessionManager: shut down ollie core"; } void SessionManager::installCallbacks() { ollie_on_state_change(onStateChange); ollie_on_chat_update(onChatUpdate); } // --- Session lifecycle --- QString SessionManager::CreateSession(const QString &cwd, const QString &backend, const QString &model, const QString &agent) { QByteArray cwdUtf8 = cwd.toUtf8(); QByteArray backendUtf8 = backend.toUtf8(); QByteArray modelUtf8 = model.toUtf8(); QByteArray agentUtf8 = agent.toUtf8(); char *outID = nullptr; int rc = ollie_create_session( const_cast(cwdUtf8.constData()), const_cast(backendUtf8.constData()), const_cast(modelUtf8.constData()), const_cast(agentUtf8.constData()), &outID); if (rc != 0 || !outID) { qWarning() << "CreateSession failed, rc=" << rc; return QString(); } QString sessionID = QString::fromUtf8(outID); ollie_free(outID); emit SessionCreated(sessionID); return sessionID; } QStringList SessionManager::ListSessions() { char *buf = nullptr; ollie_list_sessions(&buf); QStringList result; if (buf) { QString raw = QString::fromUtf8(buf); ollie_free(buf); result = raw.split('\n', Qt::SkipEmptyParts); } return result; } bool SessionManager::KillSession(const QString &session_id) { QByteArray idUtf8 = session_id.toUtf8(); int rc = ollie_kill_session(const_cast(idUtf8.constData())); if (rc == 0) { m_sessionStates.remove(session_id); emit SessionKilled(session_id); return true; } return false; } bool SessionManager::RenameSession(const QString &session_id, const QString &new_name) { QByteArray idUtf8 = session_id.toUtf8(); QByteArray nameUtf8 = new_name.toUtf8(); int rc = ollie_rename_session( const_cast(idUtf8.constData()), const_cast(nameUtf8.constData())); return rc == 0; } // --- Interaction --- bool SessionManager::Submit(const QString &session_id, const QString &prompt) { QByteArray idUtf8 = session_id.toUtf8(); QByteArray promptUtf8 = prompt.toUtf8(); int rc = ollie_submit( const_cast(idUtf8.constData()), const_cast(promptUtf8.constData())); return rc == 0; } bool SessionManager::Interrupt(const QString &session_id) { QByteArray idUtf8 = session_id.toUtf8(); int rc = ollie_interrupt(const_cast(idUtf8.constData())); return rc == 0; } // --- State queries --- QString SessionManager::GetState(const QString &session_id) { QByteArray idUtf8 = session_id.toUtf8(); char *out = nullptr; int rc = ollie_get_state(const_cast(idUtf8.constData()), &out); if (rc != 0 || !out) return QString(); QString state = QString::fromUtf8(out); ollie_free(out); return state; } QString SessionManager::GetChat(const QString &session_id, qlonglong offset, qlonglong &new_offset) { QByteArray idUtf8 = session_id.toUtf8(); char *out = nullptr; int64_t newOff = 0; int rc = ollie_get_chat( const_cast(idUtf8.constData()), static_cast(offset), &out, &newOff); if (rc != 0 || !out) { new_offset = offset; return QString(); } QString text = QString::fromUtf8(out); ollie_free(out); new_offset = static_cast(newOff); return text; } QString SessionManager::GetUsage(const QString &session_id) { QByteArray idUtf8 = session_id.toUtf8(); char *out = nullptr; int rc = ollie_get_usage(const_cast(idUtf8.constData()), &out); if (rc != 0 || !out) return QString(); QString usage = QString::fromUtf8(out); ollie_free(out); return usage; } QString SessionManager::GetCost(const QString &session_id) { QByteArray idUtf8 = session_id.toUtf8(); char *out = nullptr; int rc = ollie_get_cost(const_cast(idUtf8.constData()), &out); if (rc != 0 || !out) return QString(); QString cost = QString::fromUtf8(out); ollie_free(out); return cost; } // --- Config --- QString SessionManager::GetConfig(const QString &session_id) { QByteArray idUtf8 = session_id.toUtf8(); char *out = nullptr; int rc = ollie_get_config(const_cast(idUtf8.constData()), &out); if (rc != 0 || !out) return QString(); QString config = QString::fromUtf8(out); ollie_free(out); return config; } bool SessionManager::SetConfig(const QString &session_id, const QString &key, const QString &value) { QByteArray idUtf8 = session_id.toUtf8(); QByteArray keyUtf8 = key.toUtf8(); QByteArray valueUtf8 = value.toUtf8(); int rc = ollie_set_config( const_cast(idUtf8.constData()), const_cast(keyUtf8.constData()), const_cast(valueUtf8.constData())); return rc == 0; } // --- Context --- QString SessionManager::GetContext(const QString &session_id) { QByteArray idUtf8 = session_id.toUtf8(); char *out = nullptr; int rc = ollie_get_context(const_cast(idUtf8.constData()), &out); if (rc != 0 || !out) return QString(); QString context = QString::fromUtf8(out); ollie_free(out); return context; } // --- Backends/models/agents --- QStringList SessionManager::ListBackends() { char *out = nullptr; ollie_list_backends(&out); if (!out) return {}; QString raw = QString::fromUtf8(out); ollie_free(out); return raw.split('\n', Qt::SkipEmptyParts); } QStringList SessionManager::ListModels(const QString &session_id) { QByteArray idUtf8 = session_id.toUtf8(); char *out = nullptr; int rc = ollie_list_models(const_cast(idUtf8.constData()), &out); if (rc != 0 || !out) return {}; QString raw = QString::fromUtf8(out); ollie_free(out); return raw.split('\n', Qt::SkipEmptyParts); } QStringList SessionManager::ListAgents() { char *out = nullptr; ollie_list_agents(&out); if (!out) return {}; QString raw = QString::fromUtf8(out); ollie_free(out); return raw.split('\n', Qt::SkipEmptyParts); } // --- Peers --- bool SessionManager::PeerAdd(const QString &session_id, const QString &peer_id) { QByteArray idUtf8 = session_id.toUtf8(); QByteArray peerUtf8 = peer_id.toUtf8(); int rc = ollie_peer_add( const_cast(idUtf8.constData()), const_cast(peerUtf8.constData())); return rc == 0; } bool SessionManager::PeerRemove(const QString &session_id, const QString &peer_id) { QByteArray idUtf8 = session_id.toUtf8(); QByteArray peerUtf8 = peer_id.toUtf8(); int rc = ollie_peer_remove( const_cast(idUtf8.constData()), const_cast(peerUtf8.constData())); return rc == 0; } QStringList SessionManager::PeerList(const QString &session_id) { QByteArray idUtf8 = session_id.toUtf8(); char *out = nullptr; ollie_peer_list(const_cast(idUtf8.constData()), &out); if (!out) return {}; QString raw = QString::fromUtf8(out); ollie_free(out); return raw.split('\n', Qt::SkipEmptyParts); } bool SessionManager::PeerSubmit(const QString &session_id, const QString &peer_id, const QString &prompt) { QByteArray idUtf8 = session_id.toUtf8(); QByteArray peerUtf8 = peer_id.toUtf8(); QByteArray promptUtf8 = prompt.toUtf8(); int rc = ollie_peer_submit( const_cast(idUtf8.constData()), const_cast(peerUtf8.constData()), const_cast(promptUtf8.constData())); return rc == 0; } // --- Notifications --- void SessionManager::handleStateChange(const QString &session_id, const QString &new_state) { QString prev = m_sessionStates.value(session_id, "idle"); m_sessionStates[session_id] = new_state; if (new_state == "idle" && prev != "idle") { sendNotification("Ollie", "Session " + session_id.left(12) + " finished"); } emit StateChanged(session_id, new_state); } void SessionManager::sendNotification(const QString &title, const QString &body) { QDBusInterface notifyIface( "org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", QDBusConnection::sessionBus()); notifyIface.call("Notify", "ollie-kde", // app_name (uint)0, // replaces_id "system-run", // app_icon title, // summary body, // body QStringList(), // actions QVariantMap(), // hints (int)5000); // timeout ms }