From 620cd6c66e4e70275ed17b9ed32421e0dbef0afa Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Wed, 19 Aug 2026 18:01:36 +0200 Subject: [PATCH] Split workflow/variant into two dropdowns in NewSessionDialog - loadWorkflows() parses tab-separated 'namevariants' format - Add variantsForWorkflow() to return variant list for a workflow - Add m_workflowVariants map to cache per-workflow variant lists - createSession() accepts variant parameter, passes to server - QML: separate Workflow and Variant ComboBoxes - Variant dropdown repopulates on workflow selection change - 'default' always present; non-default variants pass through to launcher --- kde/gui/NewSessionDialog.qml | 19 ++++++++++++++++++- kde/gui/ollie9pclient.cpp | 28 ++++++++++++++++++++++++++-- kde/gui/ollie9pclient.h | 4 +++- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/kde/gui/NewSessionDialog.qml b/kde/gui/NewSessionDialog.qml index b10e070..1f0a2fd 100644 --- a/kde/gui/NewSessionDialog.qml +++ b/kde/gui/NewSessionDialog.qml @@ -125,6 +125,21 @@ Dialog { var idx = ollie.availableWorkflows.indexOf("conductor") return idx >= 0 ? idx : 0 } + onCurrentTextChanged: { + variantCombo.model = ollie.variantsForWorkflow(currentText) + variantCombo.currentIndex = 0 + } + } + } + + RowLayout { + Layout.fillWidth: true + Label { text: "Variant:"; Layout.preferredWidth: 80 } + ComboBox { + id: variantCombo + Layout.fillWidth: true + enabled: ollie.workflowsLoaded + model: ollie.variantsForWorkflow(workflowCombo.currentText) } } @@ -155,7 +170,8 @@ Dialog { var cwd = cwdField.text.trim() var workflow = workflowCombo.currentText - var err = ollie.createSession(name, remote, cwd, workflow, yoloCheckBox.checked) + var variant = variantCombo.currentText + var err = ollie.createSession(name, remote, cwd, workflow, variant, yoloCheckBox.checked) if (err === "") { ollie.refreshSessions() root.sessionCreated() @@ -182,5 +198,6 @@ Dialog { yoloCheckBox.checked = false var idx = ollie.availableWorkflows.indexOf("conductor") workflowCombo.currentIndex = idx >= 0 ? idx : 0 + variantCombo.currentIndex = 0 } } diff --git a/kde/gui/ollie9pclient.cpp b/kde/gui/ollie9pclient.cpp index 2ca25ba..2e1cf8c 100644 --- a/kde/gui/ollie9pclient.cpp +++ b/kde/gui/ollie9pclient.cpp @@ -584,16 +584,39 @@ void Ollie9pClient::loadWorkflows() if (!m_9p || !m_9p->isConnected()) return; QByteArray out = m_9p->read(QStringLiteral("workflows")); QString raw = QString::fromUtf8(out).trimmed(); + m_availableWorkflows.clear(); + m_workflowVariants.clear(); if (!raw.isEmpty()) { - m_availableWorkflows = raw.split('\n', Qt::SkipEmptyParts); + const auto lines = raw.split('\n', Qt::SkipEmptyParts); + for (const auto &line : lines) { + int tab = line.indexOf('\t'); + if (tab > 0) { + QString name = line.left(tab); + QString variantStr = line.mid(tab + 1); + m_availableWorkflows << name; + m_workflowVariants[name] = variantStr.split(',', Qt::SkipEmptyParts); + } else { + // Legacy format: just the workflow name + m_availableWorkflows << line; + m_workflowVariants[line] = QStringList() << QStringLiteral("default"); + } + } } else { m_availableWorkflows = QStringList() << QStringLiteral("conductor"); + m_workflowVariants[QStringLiteral("conductor")] = QStringList() << QStringLiteral("default"); } m_workflowsLoaded = true; emit availableWorkflowsChanged(); emit workflowsLoadedChanged(); } +QStringList Ollie9pClient::variantsForWorkflow(const QString &workflow) const +{ + auto it = m_workflowVariants.find(workflow); + if (it != m_workflowVariants.end()) return it.value(); + return QStringList() << QStringLiteral("default"); +} + QStringList Ollie9pClient::getAvailableModels(const QString &backend) const { if (!m_rootModelsLoaded) return {}; @@ -609,7 +632,7 @@ bool Ollie9pClient::createQuickSession() return !result.isEmpty() || m_9p->lastError().isEmpty(); } -QString Ollie9pClient::createSession(const QString &name, const QString &remote, const QString &cwd, const QString &workflow, bool yolo) +QString Ollie9pClient::createSession(const QString &name, const QString &remote, const QString &cwd, const QString &workflow, const QString &variant, bool yolo) { if (!m_9p || !m_9p->isConnected()) return QStringLiteral("not connected"); @@ -618,6 +641,7 @@ QString Ollie9pClient::createSession(const QString &name, const QString &remote, if (!remote.isEmpty()) args << "remote=" + remote; if (!cwd.isEmpty()) args << "cwd=" + cwd; if (!workflow.isEmpty()) args << "workflow=" + workflow; + if (!variant.isEmpty() && variant != QStringLiteral("default")) args << "variant=" + variant; if (yolo) args << "yolo=true"; QByteArray result = m_9p->rdwr(QStringLiteral("session/new"), (args.join(" ") + "\n").toUtf8()); diff --git a/kde/gui/ollie9pclient.h b/kde/gui/ollie9pclient.h index 84624d9..1cd6203 100644 --- a/kde/gui/ollie9pclient.h +++ b/kde/gui/ollie9pclient.h @@ -83,9 +83,10 @@ public: Q_INVOKABLE void loadRootBackends(); Q_INVOKABLE void loadRootAgents(); Q_INVOKABLE void loadWorkflows(); + Q_INVOKABLE QStringList variantsForWorkflow(const QString &workflow) const; Q_INVOKABLE QStringList getAvailableModels(const QString &backend) const; Q_INVOKABLE bool createQuickSession(); - Q_INVOKABLE QString createSession(const QString &name, const QString &remote, const QString &cwd = QString(), const QString &workflow = QString(), bool yolo = false); + Q_INVOKABLE QString createSession(const QString &name, const QString &remote, const QString &cwd = QString(), const QString &workflow = QString(), const QString &variant = QString(), bool yolo = false); Q_INVOKABLE void setGoal(const QString &sessionName, const QString &goalText); Q_INVOKABLE QString createAgent(const QString &sessionId, 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); @@ -136,6 +137,7 @@ private: QStringList m_availableAgents; bool m_workflowsLoaded = false; QStringList m_availableWorkflows; + QHash m_workflowVariants; bool m_rootModelsLoaded = false; QVariantMap m_rootModels; QString m_currentBackend;