gui: track all agent states via revision counter for proper QML binding

- Add agentStateRevision property that increments on any state change
- QML binds to revision to trigger re-evaluation of agentState() calls
- All agent dots now show correct live state, not just active agent
This commit is contained in:
Levi Neely 2026-08-04 16:23:04 +02:00
parent 1d79d0ee89
commit 22980e376a
3 changed files with 16 additions and 9 deletions

View File

@ -1125,7 +1125,10 @@ ApplicationWindow {
Layout.alignment: Qt.AlignVCenter
radius: 4
visible: type !== "header"
// Bind to revision so we re-evaluate when any agent state changes
property int _rev: ollie.agentStateRevision
color: {
void(_rev) // force dependency
if (type === "session") {
var cc = connectionColor || "gray"
if (cc === "green") return "#4caf50"
@ -1133,16 +1136,12 @@ ApplicationWindow {
if (cc === "red") return "#f44336"
return "#9e9e9e"
}
// Agent: match top indicator exactly when this is the active agent
if (agentId === ollie.activeAgentId && parentId === ollie.activeSessionId) {
if (ollie.isSessionPaused(ollie.activeSessionId)) return "#9e9e9e"
if (ollie.activeState === "idle") return "#4caf50"
if (ollie.activeState.startsWith("calling")) return "#ff9800"
return "#2196f3"
}
// Non-active agent: gray if paused, green otherwise
// Agent: gray if paused, else state color
if (ollie.isSessionPaused(parentId)) return "#9e9e9e"
return "#4caf50"
var s = ollie.agentState(parentId, agentId)
if (s === "idle") return "#4caf50"
if (s.startsWith("calling")) return "#ff9800"
return "#2196f3"
}
}
}

View File

@ -212,7 +212,9 @@ void Ollie9pClient::handleEvent(const QString &eventLine)
const QString aidStr = agentId.toString();
const QString key = agentKey(sidStr, aidStr);
m_agentStateValues[key] = payloadStr;
++m_agentStateRevision;
emit agentStateChanged(sidStr, aidStr, payloadStr);
emit agentStateRevisionChanged();
emit activeStateChanged();
} else {
// Non-active agent: need to check cache
@ -226,7 +228,9 @@ void Ollie9pClient::handleEvent(const QString &eventLine)
if (it != m_agentStateValues.end() && it.value() == payloadStr) return;
m_agentStateValues[key] = payloadStr;
++m_agentStateRevision;
emit agentStateChanged(sidStr, aidStr, payloadStr);
emit agentStateRevisionChanged();
}
} else if (agentAction == QLatin1String("new") || agentAction == QLatin1String("kill")) {
refreshSessions();

View File

@ -34,6 +34,7 @@ class Ollie9pClient : public QObject
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)
Q_PROPERTY(int agentStateRevision READ agentStateRevision NOTIFY agentStateRevisionChanged)
public:
explicit Ollie9pClient(QObject *parent = nullptr);
@ -52,6 +53,7 @@ public:
bool rootModelsLoaded() const { return m_rootModelsLoaded; }
QString currentBackend() const { return m_currentBackend; }
bool daemonConnected() const { return m_daemonConnected; }
int agentStateRevision() const { return m_agentStateRevision; }
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) {
@ -92,6 +94,7 @@ signals:
void activeAgentIdChanged();
void activeStateChanged();
void agentStateChanged(const QString &sessionId, const QString &agentId, const QString &state);
void agentStateRevisionChanged();
void chatReceived(const QString &text);
void rootBackendsLoadedChanged();
void availableBackendsChanged();
@ -132,6 +135,7 @@ private:
// Agent state cache — updated via delta events
QHash<QString, QString> m_agentStateValues;
int m_agentStateRevision = 0;
// Streaming FSMs — each wraps a QProcess lifecycle
StreamFsm *m_chat = nullptr; // Oneshot — reads agent chat log