fix: prevent false positives from stale approval buttons in chat history
State machine no longer transitions directly from IDLE to WAITING_FOR_USER on approval signals. Must see AGENT_WORKING first — this prevents stale buttons like "Run this time only" persisting in chat history from triggering the flash when no agent task is active. Also removed "Continue" and "Resume" from approval keywords (too generic, appear in normal chat text). Made-with: Cursor
This commit is contained in:
@@ -30,7 +30,7 @@ CURSOR_BUNDLE_ID = "com.todesktop.230313mzl4w4u92"
|
||||
AGENT_WORKING_EXACT = {"Stop", "Cancel generating"}
|
||||
AGENT_WORKING_PATTERNS = [re.compile(r"^Generating\b", re.IGNORECASE)]
|
||||
|
||||
APPROVAL_EXACT = {"Accept", "Reject", "Accept All", "Deny", "Resume", "Continue"}
|
||||
APPROVAL_EXACT = {"Accept", "Reject", "Accept All", "Deny"}
|
||||
APPROVAL_PATTERNS = [
|
||||
re.compile(r"^Run\b", re.IGNORECASE),
|
||||
re.compile(r"^Allow\b", re.IGNORECASE),
|
||||
|
||||
@@ -15,20 +15,25 @@ class StateMachine:
|
||||
self._last_dismiss_time: float = 0
|
||||
|
||||
def update(self, *, agent_working: bool, approval_needed: bool) -> bool:
|
||||
"""Update state based on detected signals. Returns True if state changed."""
|
||||
old = self.state
|
||||
"""Update state based on detected signals. Returns True if state changed.
|
||||
|
||||
if approval_needed and self.state != FlasherState.WAITING_FOR_USER:
|
||||
if not self._in_cooldown():
|
||||
self.state = FlasherState.WAITING_FOR_USER
|
||||
return self.state != old
|
||||
Only transitions to WAITING_FOR_USER after seeing AGENT_WORKING first.
|
||||
This prevents stale approval buttons in chat history from triggering
|
||||
false positives.
|
||||
"""
|
||||
old = self.state
|
||||
|
||||
match self.state:
|
||||
case FlasherState.IDLE:
|
||||
if agent_working:
|
||||
self.state = FlasherState.AGENT_WORKING
|
||||
case FlasherState.AGENT_WORKING:
|
||||
if not agent_working:
|
||||
if approval_needed and not agent_working:
|
||||
if not self._in_cooldown():
|
||||
self.state = FlasherState.WAITING_FOR_USER
|
||||
else:
|
||||
self.state = FlasherState.IDLE
|
||||
elif not agent_working:
|
||||
if not self._in_cooldown():
|
||||
self.state = FlasherState.WAITING_FOR_USER
|
||||
else:
|
||||
|
||||
@@ -66,10 +66,17 @@ class TestStateMachine:
|
||||
changed = sm.update(agent_working=False, approval_needed=False)
|
||||
assert sm.cooldown == 5.0
|
||||
|
||||
def test_direct_approval_from_idle(self):
|
||||
"""If we detect approval buttons without seeing agent_working first,
|
||||
still transition to WAITING_FOR_USER."""
|
||||
def test_stale_approval_from_idle_ignored(self):
|
||||
"""Approval buttons in IDLE state (stale chat history) must not trigger flash."""
|
||||
sm = StateMachine()
|
||||
changed = sm.update(agent_working=False, approval_needed=True)
|
||||
assert sm.state == FlasherState.IDLE
|
||||
assert changed is False
|
||||
|
||||
def test_approval_after_working_triggers(self):
|
||||
"""Approval buttons after seeing agent work should trigger flash."""
|
||||
sm = StateMachine()
|
||||
sm.update(agent_working=True, approval_needed=False)
|
||||
changed = sm.update(agent_working=False, approval_needed=True)
|
||||
assert sm.state == FlasherState.WAITING_FOR_USER
|
||||
assert changed is True
|
||||
|
||||
Reference in New Issue
Block a user