Split workflow/variant into two dropdowns in NewSessionDialog

- loadWorkflows() parses tab-separated 'name<TAB>variants' 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
This commit is contained in:
Levi Neely 2026-08-19 18:01:36 +02:00
parent 5fdd80c26c
commit 620cd6c66e
3 changed files with 47 additions and 4 deletions

View File

@ -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
}
}

View File

@ -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());

View File

@ -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<QString, QStringList> m_workflowVariants;
bool m_rootModelsLoaded = false;
QVariantMap m_rootModels;
QString m_currentBackend;