fix: retire clarify cards on an explicit no-answer signal, not the '[' prefix
`_clarify_callback_sync` decided "no answer arrived" by testing whether the response text starts with '[' (the shape of the timeout / undeliverable sentinels). A real answer can start with '[' too — a "[A] staging" choice label picked by number, or "[urgent] ..." free text after Other — so the clarify resolved and the agent got the answer, yet the Slack card was rewritten to "This prompt expired" and typing was never re-armed. `_clarify_send_then_wait` now returns `(response, answered)` and the runner branches on that flag only. The Slack click handler popped the retire entry as soon as Other was clicked, but Other is not terminal: the clarify stays pending for typed text, so a later timeout or /new reset found nothing to retire and the card stayed stuck on "Awaiting typed answer". The entry is now popped only on a terminal outcome (a choice click, or Other on an already-dead entry). A typed answer to a native card (numeric pick, or text after Other) never reaches the click handler, so the card kept its buttons forever; the TEXT_RESOLVED intercept now retires it with the answer. Review finding: '[' prefix mistaken for the timeout sentinel; Other click dropped the retire entry; typed answers never rewrote the card.
This commit is contained in:
@@ -5445,7 +5445,6 @@ class SlackAdapter(BasePlatformAdapter):
|
||||
# Double-click guard — atomic pop (mirrors approval).
|
||||
if self._clarify_resolved.pop(msg_ts, True):
|
||||
return
|
||||
self._clarify_messages.pop(clarify_id, None)
|
||||
original_text = self._section_text(message, limit=None)
|
||||
from tools import clarify_gateway as _clarify_mod
|
||||
# "Other" → text-capture mode: mark_awaiting_text flips the entry and the
|
||||
@@ -5454,8 +5453,11 @@ class SlackAdapter(BasePlatformAdapter):
|
||||
if action_id == "hermes_clarify_other" or token == "other":
|
||||
if not _clarify_mod.mark_awaiting_text(clarify_id):
|
||||
# Entry evicted/gateway restarted — a typed answer would go nowhere.
|
||||
self._clarify_messages.pop(clarify_id, None)
|
||||
await self._update_clarify_message(channel_id, msg_ts, original_text, expired_text)
|
||||
return
|
||||
# Not terminal: the clarify stays pending for typed text, so keep the card entry —
|
||||
# the gateway still has to retire it on timeout / reset / typed answer.
|
||||
await self._update_clarify_message(
|
||||
channel_id, msg_ts, original_text, f"✏️ Awaiting typed answer from {user_name}…")
|
||||
return
|
||||
@@ -5464,6 +5466,8 @@ class SlackAdapter(BasePlatformAdapter):
|
||||
except (ValueError, TypeError):
|
||||
logger.warning("[Slack] Invalid clarify choice token: %s", token)
|
||||
return
|
||||
# A choice click is terminal either way (✅ or expired): the card no longer needs retiring.
|
||||
self._clarify_messages.pop(clarify_id, None)
|
||||
# Canonical choice text from the entry; positional fallback on timeout/reset race.
|
||||
resolved_text: Optional[str] = None
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user