diff --git a/gateway/platforms/base.py b/gateway/platforms/base.py index 0bf7b9a2ad9..ad9dac170ee 100644 --- a/gateway/platforms/base.py +++ b/gateway/platforms/base.py @@ -1774,8 +1774,12 @@ class BasePlatformAdapter(ABC): The default implementation falls back to a numbered text list, which works on every platform — the user replies with a number ("2") or with the literal choice text, and the gateway intercepts - and resolves. Adapters with native button UIs (Telegram, Discord) - SHOULD override this for a richer UX. + and resolves. For the text fallback path, the default calls + ``mark_awaiting_text()`` so that the gateway text-intercept + (:meth:`GatewayRunner._maybe_intercept_clarify_text`) catches the + user's reply instead of timing out. + Adapters with native button UIs (Telegram, Discord) SHOULD + override this for a richer UX. """ if choices: lines = [f"❓ {question}", ""] @@ -1784,6 +1788,10 @@ class BasePlatformAdapter(ABC): lines.append("") lines.append("Reply with the number, the option text, or your own answer.") text = "\n".join(lines) + # Text fallback: enable text-capture so the gateway intercept + # picks up the user's typed reply (e.g. "2" or choice text). + from tools.clarify_gateway import mark_awaiting_text + mark_awaiting_text(clarify_id) else: text = f"❓ {question}" return await self.send( diff --git a/tests/tools/test_clarify_gateway.py b/tests/tools/test_clarify_gateway.py index 61ea55c8cfc..86385be3571 100644 --- a/tests/tools/test_clarify_gateway.py +++ b/tests/tools/test_clarify_gateway.py @@ -205,3 +205,23 @@ class TestGatewayTextIntercept: pending2 = cm.get_pending_for_session("sk") assert pending2 is not None assert pending2.clarify_id == "first" + def test_text_fallback_enables_awaiting_text_for_multi_choice(self): + """When base send_clarify renders choices as text, mark_awaiting_text + is called so the gateway text-intercept can capture the reply.""" + from tools import clarify_gateway as cm + + entry = cm.register("id-tf", "sk-tf", "Pick one", ["A", "B", "C"]) + # Initially, multi-choice does NOT await text (button path) + assert entry.awaiting_text is False + + # After the base send_clarify text fallback calls mark_awaiting_text: + flipped = cm.mark_awaiting_text("id-tf") + assert flipped is True + + # Now get_pending_for_session should find it + pending = cm.get_pending_for_session("sk-tf") + assert pending is not None + assert pending.clarify_id == "id-tf" + + # Clean up + cm.clear_session("sk-tf")