v0.0.32 - Convert send button to stop button during agent runs (remove separate stop-btn)

This commit is contained in:
Laan Tungir
2026-07-16 11:47:57 -04:00
parent 6020df2e92
commit 6f639cd419
7 changed files with 97 additions and 14 deletions
+1 -1
View File
@@ -1 +1 @@
0.0.31
0.0.32
+2 -2
View File
@@ -11,9 +11,9 @@
#ifndef SOVEREIGN_BROWSER_VERSION_H
#define SOVEREIGN_BROWSER_VERSION_H
#define SB_VERSION "v0.0.31"
#define SB_VERSION "v0.0.32"
#define SB_VERSION_MAJOR 0
#define SB_VERSION_MINOR 0
#define SB_VERSION_PATCH 31
#define SB_VERSION_PATCH 32
#endif /* SOVEREIGN_BROWSER_VERSION_H */
+14 -4
View File
@@ -378,10 +378,6 @@ html.dark .skill-badge-unsaved {
#composer-host {
flex: 1; min-width: 0;
}
#stop-btn {
flex-shrink: 0; min-width: 80px; margin-left: 0;
}
/* The shared post-composer library wraps the host element: it inserts a
* .post-composer-wrapper around #composer-host and appends the send
* button as a SIBLING of the host (inside the wrapper). So the send
@@ -408,6 +404,20 @@ html.dark .skill-badge-unsaved {
#input-area .post-composer-send-btn:disabled {
opacity: 0.5; cursor: not-allowed;
}
/* Stop-mode: the send button transforms into a stop button while the
* agent is running. Use a distinct (red-ish) style to signal that
* clicking it will cancel the agent. */
#input-area .post-composer-send-btn.is-stop-mode {
border-color: var(--danger, #c33);
color: var(--danger, #c33);
background: transparent;
}
#input-area .post-composer-send-btn.is-stop-mode:hover,
#input-area .post-composer-send-btn.is-stop-mode:focus {
background: var(--danger, #c33);
color: #fff;
border-color: var(--danger, #c33);
}
/* ── Responsive: narrow sidebar viewport (< 400px) ──────────────
* When the chat page is loaded in the agent sidebar (~350px wide),
-1
View File
@@ -26,7 +26,6 @@
</div>
<div id="input-area">
<div id="composer-host"></div>
<button id="stop-btn" class="btn btn-del" style="display:none" onclick="cancelAgent()">Stop</button>
</div>
</div>
+16 -6
View File
@@ -467,7 +467,6 @@ function clearStatusMessage() {
* fallback. Posts status messages as system bubbles in the chat
* window instead of updating a status bar. */
function applyStatus(s) {
var stopBtn = document.getElementById('stop-btn');
var map = {idle:'Idle', thinking:'Thinking...',
tool_call:'Calling tool', complete:'Complete',
error:'Error', cancelled:'Cancelled'};
@@ -492,13 +491,24 @@ function applyStatus(s) {
}
var running = (s.state === 'thinking' || s.state === 'tool_call');
if (stopBtn) stopBtn.style.display = running ? '' : 'none';
if (composerApi && typeof composerApi.setDisabled === 'function') {
/* Disable while running OR when no chat is selected. The composer
* must never be enabled if there is no active conversation. */
/* Convert the send button into a stop button while the agent is
* running, instead of showing a separate stop button. The user can't
* send again anyway while the agent is working. */
if (composerApi) {
var hasChat = (currentConvId !== null && currentConvId !== undefined &&
String(currentConvId) !== '');
composerApi.setDisabled(running || !hasChat);
if (running) {
if (typeof composerApi.setStopMode === 'function') {
composerApi.setStopMode(cancelAgent);
}
} else {
if (typeof composerApi.clearStopMode === 'function') {
composerApi.clearStopMode();
}
if (typeof composerApi.setDisabled === 'function') {
composerApi.setDisabled(!hasChat);
}
}
}
/* On transition to complete/error/cancelled, fetch final
+35
View File
@@ -264,6 +264,15 @@ window.mountComposer = function mountComposer(hostEl, options = {}) {
sendButton.textContent = 'Send';
sendButton.disabled = true;
/* Stop-mode state: when active, the send button transforms into a
* stop button (different label, click handler, and styling). This is
* used by the agent chat to let the user cancel an in-progress agent
* run without needing a separate stop button. */
let stopModeActive = false;
let stopModeHandler = null;
const sendLabel = 'Send';
const stopLabel = 'Stop';
if (layout === 'inline') {
wrapper.classList.add('post-composer-wrapper--inline');
if (showPreview) wrapper.appendChild(previewEl);
@@ -733,6 +742,11 @@ window.mountComposer = function mountComposer(hostEl, options = {}) {
}
async function onSendClick() {
/* In stop mode, the button acts as Stop — route to the stop handler. */
if (stopModeActive) {
if (stopModeHandler) stopModeHandler();
return;
}
if (sendButton.disabled) return;
if (!onSubmit) return;
@@ -827,6 +841,27 @@ window.mountComposer = function mountComposer(hostEl, options = {}) {
externallyDisabled = !!disabled;
updateSendButtonVisibility();
},
/* Convert the send button into a stop button. The provided handler
* is called when the user clicks the (now stop) button. The text
* area is NOT disabled — the user can type their next message while
* the agent runs, but the button acts as Stop until clearStopMode()
* is called. */
setStopMode(handler) {
stopModeActive = true;
stopModeHandler = typeof handler === 'function' ? handler : null;
sendButton.textContent = stopLabel;
sendButton.classList.add('is-stop-mode');
sendButton.disabled = false;
sendButton.classList.add('is-visible');
},
/* Revert the stop button back to a send button. */
clearStopMode() {
stopModeActive = false;
stopModeHandler = null;
sendButton.textContent = sendLabel;
sendButton.classList.remove('is-stop-mode');
updateSendButtonVisibility();
},
show() {
showComposer();
},
+29
View File
@@ -264,6 +264,15 @@ export function mountComposer(hostEl, options = {}) {
sendButton.textContent = 'Send';
sendButton.disabled = true;
/* Stop-mode state: when active, the send button transforms into a
* stop button (different label, click handler, and styling). This is
* used by the agent chat to let the user cancel an in-progress agent
* run without needing a separate stop button. */
let stopModeActive = false;
let stopModeHandler = null;
const sendLabel = 'Send';
const stopLabel = 'Stop';
if (layout === 'inline') {
wrapper.classList.add('post-composer-wrapper--inline');
if (showPreview) wrapper.appendChild(previewEl);
@@ -733,6 +742,11 @@ export function mountComposer(hostEl, options = {}) {
}
async function onSendClick() {
/* In stop mode, the button acts as Stop — route to the stop handler. */
if (stopModeActive) {
if (stopModeHandler) stopModeHandler();
return;
}
if (sendButton.disabled) return;
if (!onSubmit) return;
@@ -827,6 +841,21 @@ export function mountComposer(hostEl, options = {}) {
externallyDisabled = !!disabled;
updateSendButtonVisibility();
},
setStopMode(handler) {
stopModeActive = true;
stopModeHandler = typeof handler === 'function' ? handler : null;
sendButton.textContent = stopLabel;
sendButton.classList.add('is-stop-mode');
sendButton.disabled = false;
sendButton.classList.add('is-visible');
},
clearStopMode() {
stopModeActive = false;
stopModeHandler = null;
sendButton.textContent = sendLabel;
sendButton.classList.remove('is-stop-mode');
updateSendButtonVisibility();
},
show() {
showComposer();
},