gui: support multiple concurrent bypass requests per agent
Frontend changes to match the backend's multi-request support: - bypassResolved signal now includes the request ID - ChatPane tracks pendingBypasses as a map (id -> request) - onBypassRequested adds to the map; onBypassResolved removes by ID - currentBypass shows the first pending request for the active agent - Switching agents updates the banner to show that agent's pending request - Approve/Deny now remove only the specific resolved request This allows each agent to have multiple pending bypass requests without blocking other agents, and the banner correctly shows requests only for the currently active agent.
This commit is contained in:
parent
5c0f463e4d
commit
50ebcedb8a
|
|
@ -7,12 +7,27 @@ Item {
|
||||||
id: chatPane
|
id: chatPane
|
||||||
property bool sidebarVisible: true
|
property bool sidebarVisible: true
|
||||||
property int maxVisibleBlocks: 80
|
property int maxVisibleBlocks: 80
|
||||||
property var pendingBypass: null // {sessionId, id, cmd, cwd}
|
// Map of pending bypass requests: id -> {sessionId, agentId, id, cmd, cwd}
|
||||||
property bool hasPendingBypass: false
|
property var pendingBypasses: ({})
|
||||||
|
property var currentBypass: null // The one currently shown in the banner
|
||||||
signal toggleSidebar()
|
signal toggleSidebar()
|
||||||
// Do not opt the chat pane into focus navigation.
|
// Do not opt the chat pane into focus navigation.
|
||||||
activeFocusOnTab: false
|
activeFocusOnTab: false
|
||||||
|
|
||||||
|
// Helper to get the first pending bypass for the active agent
|
||||||
|
function updateCurrentBypass() {
|
||||||
|
var activeKey = ollie.activeSessionId + ":" + ollie.activeAgentId
|
||||||
|
for (var id in pendingBypasses) {
|
||||||
|
var req = pendingBypasses[id]
|
||||||
|
var key = req.sessionId + ":" + req.agentId
|
||||||
|
if (key === activeKey) {
|
||||||
|
currentBypass = req
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentBypass = null
|
||||||
|
}
|
||||||
|
|
||||||
// Expose method to set prompt text (for Edit & Resend)
|
// Expose method to set prompt text (for Edit & Resend)
|
||||||
function setPromptText(text) {
|
function setPromptText(text) {
|
||||||
promptInput.text = text
|
promptInput.text = text
|
||||||
|
|
@ -175,7 +190,7 @@ Item {
|
||||||
color: "#fff3e0" // amber light
|
color: "#fff3e0" // amber light
|
||||||
border.color: "#ff9800"
|
border.color: "#ff9800"
|
||||||
border.width: 1
|
border.width: 1
|
||||||
visible: chatPane.hasPendingBypass
|
visible: chatPane.currentBypass !== null
|
||||||
z: 100
|
z: 100
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
|
@ -192,7 +207,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: chatPane.pendingBypass ? chatPane.pendingBypass.cmd : ""
|
text: chatPane.currentBypass ? chatPane.currentBypass.cmd : ""
|
||||||
font.family: "monospace"
|
font.family: "monospace"
|
||||||
font.pixelSize: theme.fontSize > 0 ? theme.fontSize : 12
|
font.pixelSize: theme.fontSize > 0 ? theme.fontSize : 12
|
||||||
wrapMode: Text.WrapAnywhere
|
wrapMode: Text.WrapAnywhere
|
||||||
|
|
@ -201,10 +216,10 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: chatPane.pendingBypass ? "cwd: " + chatPane.pendingBypass.cwd : ""
|
text: chatPane.currentBypass ? "cwd: " + chatPane.currentBypass.cwd : ""
|
||||||
font.pixelSize: theme.fontSize > 0 ? theme.fontSize - 1 : 10
|
font.pixelSize: theme.fontSize > 0 ? theme.fontSize - 1 : 10
|
||||||
color: "#666"
|
color: "#666"
|
||||||
visible: chatPane.pendingBypass && chatPane.pendingBypass.cwd !== ""
|
visible: chatPane.currentBypass && chatPane.currentBypass.cwd !== ""
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
|
@ -215,10 +230,8 @@ Item {
|
||||||
text: "Approve"
|
text: "Approve"
|
||||||
highlighted: true
|
highlighted: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (chatPane.pendingBypass) {
|
if (chatPane.currentBypass) {
|
||||||
ollie.resolveBypass(chatPane.pendingBypass.sessionId, chatPane.pendingBypass.agentId, chatPane.pendingBypass.id, true)
|
ollie.resolveBypass(chatPane.currentBypass.sessionId, chatPane.currentBypass.agentId, chatPane.currentBypass.id, true)
|
||||||
chatPane.pendingBypass = null
|
|
||||||
chatPane.hasPendingBypass = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -226,10 +239,8 @@ Item {
|
||||||
Button {
|
Button {
|
||||||
text: "Deny"
|
text: "Deny"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (chatPane.pendingBypass) {
|
if (chatPane.currentBypass) {
|
||||||
ollie.resolveBypass(chatPane.pendingBypass.sessionId, chatPane.pendingBypass.agentId, chatPane.pendingBypass.id, false)
|
ollie.resolveBypass(chatPane.currentBypass.sessionId, chatPane.currentBypass.agentId, chatPane.currentBypass.id, false)
|
||||||
chatPane.pendingBypass = null
|
|
||||||
chatPane.hasPendingBypass = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -580,56 +591,46 @@ Connections {
|
||||||
target: ollie
|
target: ollie
|
||||||
function onActiveSessionIdChanged() {
|
function onActiveSessionIdChanged() {
|
||||||
if (!ollie.activeAgentId) chatPane.loadChat()
|
if (!ollie.activeAgentId) chatPane.loadChat()
|
||||||
// Hide bypass banner if it's not for the now-active session
|
// Update current bypass for the new active agent
|
||||||
if (chatPane.pendingBypass && chatPane.pendingBypass.sessionId !== ollie.activeSessionId) {
|
chatPane.updateCurrentBypass()
|
||||||
chatPane.hasPendingBypass = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
function onActiveAgentIdChanged() {
|
function onActiveAgentIdChanged() {
|
||||||
if (ollie.activeAgentId) chatPane.loadChat()
|
if (ollie.activeAgentId) chatPane.loadChat()
|
||||||
// Hide bypass banner if it's not for the now-active agent
|
// Update current bypass for the new active agent
|
||||||
if (chatPane.pendingBypass &&
|
chatPane.updateCurrentBypass()
|
||||||
(chatPane.pendingBypass.sessionId !== ollie.activeSessionId ||
|
|
||||||
chatPane.pendingBypass.agentId !== ollie.activeAgentId)) {
|
|
||||||
chatPane.hasPendingBypass = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
function onBypassRequested(sessionId, agentId, id, cmd, cwd) {
|
function onBypassRequested(sessionId, agentId, id, cmd, cwd) {
|
||||||
// Show bypass request only for the currently active agent
|
// Add to pending bypasses map
|
||||||
if (sessionId === ollie.activeSessionId && agentId === ollie.activeAgentId) {
|
var newMap = chatPane.pendingBypasses
|
||||||
chatPane.pendingBypass = {
|
newMap[id] = {
|
||||||
sessionId: sessionId,
|
sessionId: sessionId,
|
||||||
agentId: agentId,
|
agentId: agentId,
|
||||||
id: id,
|
id: id,
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
cwd: cwd
|
cwd: cwd
|
||||||
}
|
}
|
||||||
chatPane.hasPendingBypass = true
|
chatPane.pendingBypasses = newMap
|
||||||
|
chatPane.updateCurrentBypass()
|
||||||
}
|
}
|
||||||
}
|
function onBypassResolved(sessionId, agentId, requestId) {
|
||||||
function onBypassResolved(sessionId, agentId) {
|
// Remove the specific resolved request from the map
|
||||||
// Clear bypass banner if it was for this agent (resolved by CLI or another client)
|
if (chatPane.pendingBypasses[requestId]) {
|
||||||
if (chatPane.pendingBypass &&
|
var newMap = chatPane.pendingBypasses
|
||||||
chatPane.pendingBypass.sessionId === sessionId &&
|
delete newMap[requestId]
|
||||||
chatPane.pendingBypass.agentId === agentId) {
|
chatPane.pendingBypasses = newMap
|
||||||
chatPane.pendingBypass = null
|
chatPane.updateCurrentBypass()
|
||||||
chatPane.hasPendingBypass = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public functions for keyboard shortcuts
|
// Public functions for keyboard shortcuts
|
||||||
function approveBypass() {
|
function approveBypass() {
|
||||||
if (chatPane.pendingBypass) {
|
if (chatPane.currentBypass) {
|
||||||
ollie.resolveBypass(chatPane.pendingBypass.sessionId, chatPane.pendingBypass.agentId, chatPane.pendingBypass.id, true)
|
ollie.resolveBypass(chatPane.currentBypass.sessionId, chatPane.currentBypass.agentId, chatPane.currentBypass.id, true)
|
||||||
chatPane.pendingBypass = null
|
|
||||||
chatPane.hasPendingBypass = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function denyBypass() {
|
function denyBypass() {
|
||||||
if (chatPane.pendingBypass) {
|
if (chatPane.currentBypass) {
|
||||||
ollie.resolveBypass(chatPane.pendingBypass.sessionId, chatPane.pendingBypass.agentId, chatPane.pendingBypass.id, false)
|
ollie.resolveBypass(chatPane.currentBypass.sessionId, chatPane.currentBypass.agentId, chatPane.currentBypass.id, false)
|
||||||
chatPane.pendingBypass = null
|
|
||||||
chatPane.hasPendingBypass = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@ void Ollie9pClient::handleEvent(const QString &eventLine)
|
||||||
}
|
}
|
||||||
emit pendingBypassCountChanged(sidStr, aidStr);
|
emit pendingBypassCountChanged(sidStr, aidStr);
|
||||||
}
|
}
|
||||||
emit bypassResolved(sidStr, aidStr);
|
emit bypassResolved(sidStr, aidStr, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -895,7 +895,7 @@ bool Ollie9pClient::resolveBypass(const QString &sessionId, const QString &agent
|
||||||
m_pendingBypasses.remove(key);
|
m_pendingBypasses.remove(key);
|
||||||
}
|
}
|
||||||
emit pendingBypassCountChanged(sessionId, agentId);
|
emit pendingBypassCountChanged(sessionId, agentId);
|
||||||
emit bypassResolved(sessionId, agentId);
|
emit bypassResolved(sessionId, agentId, id);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ signals:
|
||||||
void agentStateChanged(const QString &sessionId, const QString &agentId, const QString &state);
|
void agentStateChanged(const QString &sessionId, const QString &agentId, const QString &state);
|
||||||
void chatReceived(const QString &text);
|
void chatReceived(const QString &text);
|
||||||
void bypassRequested(const QString &sessionId, const QString &agentId, const QString &id, const QString &cmd, const QString &cwd);
|
void bypassRequested(const QString &sessionId, const QString &agentId, const QString &id, const QString &cmd, const QString &cwd);
|
||||||
void bypassResolved(const QString &sessionId, const QString &agentId);
|
void bypassResolved(const QString &sessionId, const QString &agentId, const QString &requestId);
|
||||||
void pendingBypassCountChanged(const QString &sessionId, const QString &agentId);
|
void pendingBypassCountChanged(const QString &sessionId, const QString &agentId);
|
||||||
void procStarted(const QString &sessionId, const QString &agentId, const QString &payload);
|
void procStarted(const QString &sessionId, const QString &agentId, const QString &payload);
|
||||||
void rootBackendsLoadedChanged();
|
void rootBackendsLoadedChanged();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue