fix(approval): keep approval polling alive across busy dips (#4041)
This commit is contained in:
@@ -3994,6 +3994,10 @@ function _hideApprovalCardIfOwner(sid, force=false) {
|
||||
if (!sid || _approvalSessionId === sid) hideApprovalCard(force);
|
||||
}
|
||||
|
||||
function _approvalPollingSessionMissingOrMismatched(sid) {
|
||||
return !sid || !S.session || S.session.session_id !== sid;
|
||||
}
|
||||
|
||||
function _renderPendingApprovalForActiveSession() {
|
||||
const sid = _promptActiveSessionId();
|
||||
if (!sid) return;
|
||||
@@ -4160,7 +4164,7 @@ function _startApprovalFallbackPoll(sid) {
|
||||
// shows its card instantly (the removed SSE 'initial' event used to do this);
|
||||
// then poll on the 1500ms cadence. (#3913 SHOULD-FIX)
|
||||
const _tick = async () => {
|
||||
if (!S.busy || !S.session || S.session.session_id !== sid) {
|
||||
if (_approvalPollingSessionMissingOrMismatched(sid)) {
|
||||
stopApprovalPolling(); _hideApprovalCardIfOwner(sid, true); return;
|
||||
}
|
||||
if (_approvalFallbackPollInFlight) return;
|
||||
@@ -4168,7 +4172,11 @@ function _startApprovalFallbackPoll(sid) {
|
||||
try {
|
||||
const data = await api("/api/approval/pending?session_id=" + encodeURIComponent(sid),{timeoutToast:false});
|
||||
if (data.pending) { showApprovalForSession(sid, data.pending, data.pending_count||1); }
|
||||
else { _clearApprovalPendingForSession(sid); _hideApprovalCardIfOwner(sid); }
|
||||
else if (!_approvalPollingSessionMissingOrMismatched(sid) && !S.busy) {
|
||||
_clearApprovalPendingForSession(sid);
|
||||
_hideApprovalCardIfOwner(sid);
|
||||
stopApprovalPollingForSession(sid);
|
||||
}
|
||||
} catch(e) { /* ignore poll errors */ }
|
||||
finally { _approvalFallbackPollInFlight = false; }
|
||||
};
|
||||
|
||||
46
tests/test_issue4041_approval_poll_busy_dip.py
Normal file
46
tests/test_issue4041_approval_poll_busy_dip.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).parent.parent
|
||||
MESSAGES_JS = (REPO_ROOT / "static" / "messages.js").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def _body_from_brace(src: str, brace: int, label: str) -> str:
|
||||
assert brace >= 0, f"body opening brace not found for: {label}"
|
||||
depth = 1
|
||||
i = brace + 1
|
||||
while i < len(src) and depth:
|
||||
ch = src[i]
|
||||
if ch == "{":
|
||||
depth += 1
|
||||
elif ch == "}":
|
||||
depth -= 1
|
||||
i += 1
|
||||
assert depth == 0, f"body did not close for: {label}"
|
||||
return src[brace + 1 : i - 1]
|
||||
|
||||
|
||||
def _function_body(name: str) -> str:
|
||||
marker = f"function {name}("
|
||||
start = MESSAGES_JS.find(marker)
|
||||
assert start >= 0, f"function not found: {name}"
|
||||
signature_end = MESSAGES_JS.find(")", start)
|
||||
assert signature_end >= 0, f"function signature not found: {name}"
|
||||
brace = MESSAGES_JS.find("{", signature_end)
|
||||
return _body_from_brace(MESSAGES_JS, brace, name)
|
||||
|
||||
|
||||
def test_busy_dips_no_longer_force_stop_approval_polling():
|
||||
body = _function_body("_startApprovalFallbackPoll")
|
||||
|
||||
assert "_approvalPollingSessionMissingOrMismatched(sid)" in body
|
||||
assert "!S.busy || !S.session || S.session.session_id !== sid" not in body
|
||||
|
||||
|
||||
def test_empty_pending_only_stops_after_confirmed_idle():
|
||||
fallback_body = _function_body("_startApprovalFallbackPoll")
|
||||
|
||||
assert "else if (!_approvalPollingSessionMissingOrMismatched(sid) && !S.busy)" in fallback_body
|
||||
assert "_clearApprovalPendingForSession(sid);" in fallback_body
|
||||
assert "_hideApprovalCardIfOwner(sid);" in fallback_body
|
||||
assert "stopApprovalPollingForSession(sid);" in fallback_body
|
||||
assert "stopApprovalPolling(); _hideApprovalCardIfOwner(sid, true); return;" in fallback_body
|
||||
Reference in New Issue
Block a user