metal-kompanion/src/middleware/orchestrator.h

92 lines
3.0 KiB
C++

#pragma once
#include <QObject>
#include <QDir>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QTimer>
#include <functional>
#include "kompanion_mw_export.h"
// Minimal model provider interface so tests can stub generation.
class IModelProvider {
public:
virtual ~IModelProvider() = default;
virtual QString generate(const QString &prompt, const QString &aspect) = 0;
};
// Default Ollama-backed provider. Uses OLLAMA_BASE and simple /api/generate call.
class OllamaModelProvider : public QObject, public IModelProvider {
Q_OBJECT
public:
explicit OllamaModelProvider(QObject *parent=nullptr);
QString generate(const QString &prompt, const QString &aspect) override;
void setBaseUrl(const QString &base) { baseUrl_ = base; }
void setDefaultModel(const QString &m) { defaultModel_ = m; }
private:
QString chooseModelForAspect(const QString &aspect) const; // simple heuristic
QString baseUrl_;
QString defaultModel_ = QStringLiteral("qwen2.5:7b");
QNetworkAccessManager nam_;
};
// Simple stub provider used by tests; returns deterministic text.
class StubModelProvider : public IModelProvider {
public:
explicit StubModelProvider(QString canned) : canned_(std::move(canned)) {}
QString generate(const QString &prompt, const QString &aspect) override {
Q_UNUSED(prompt); Q_UNUSED(aspect); return canned_;
}
private:
QString canned_;
};
// Orchestrator: replicates runtime/kom_runner.py behaviors in C++.
// - Watches a JSONL tasks file under XDG_STATE_HOME/kompanion
// - Processes tasks like {"type":"journal.from_prompt", "prompt":"...", "aspect":"companion"}
// - Appends to journal (<state>/journal/YYYY-MM-DD.md) and to a simple ledger JSONL
class KOMPANION_MW_EXPORT Orchestrator : public QObject {
Q_OBJECT
public:
explicit Orchestrator(QObject *parent=nullptr);
// Injectable model provider (Ollama by default). Ownership left to caller.
void setModelProvider(IModelProvider *prov) { model_ = prov; }
// Directories resolved from XDG_* on start(); overridable for tests.
void setStateDir(const QDir &dir) { stateDir_ = dir; }
void setConfigDir(const QDir &dir) { configDir_ = dir; }
// Poll loop control.
void start(int intervalMs = 3000);
void stop();
// One-shot tick (public for tests).
void processPendingTasks();
signals:
void taskProcessed(const QString &kind);
private:
void ensureResolvedDirs();
void continuityHandshakeOnce();
void ledgerAppend(const QJsonObject &evt);
void journalAppend(const QString &line); // Also emits ledger entry
QString nowUtc() const;
// Task handlers
void handleJournalFromPrompt(const QJsonObject &obj);
// Helpers
QString tasksPath() const { return stateDir_.filePath("tasks.jsonl"); }
QString journalDirPath() const { return stateDir_.filePath("journal"); }
QString ledgerPath() const { return stateDir_.filePath("trust_ledger.jsonl"); }
QDir stateDir_;
QDir configDir_;
QTimer timer_;
bool continuityDone_ = false;
IModelProvider *model_ = nullptr; // not owned
};