From 62e8842d07d6399bd09ae0091b7a8527aa4ec546 Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Sun, 26 Jul 2026 13:26:00 -0700 Subject: [PATCH] =?UTF-8?q?fix(tui):=20emit=20multi=5Fselect=20hint=20only?= =?UTF-8?q?=20when=20true=20=E2=80=94=20single-select=20clarify=20payloads?= =?UTF-8?q?=20keep=20the=20pre-existing=20protocol=20shape?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_tui_gateway_server.py | 24 ++++++++++++++++++++++++ tui_gateway/server.py | 9 +++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/tests/test_tui_gateway_server.py b/tests/test_tui_gateway_server.py index f57373752d39..64ec7f75b2f7 100644 --- a/tests/test_tui_gateway_server.py +++ b/tests/test_tui_gateway_server.py @@ -13869,6 +13869,30 @@ def test_clarify_callback_uses_configured_timeout(monkeypatch): assert captured["payload"] == {"question": "Pick one", "choices": ["a", "b"]} +def test_clarify_callback_multi_select_hint(monkeypatch): + """multi_select=True adds the hint to the payload; the single-select + payload shape stays byte-identical to the pre-multi-select protocol + (older renderers must never see the extra field).""" + captured = {} + + def fake_block(event, sid, payload, timeout=300): + captured.update(payload=payload) + return "answer" + + monkeypatch.setattr(server, "_block", fake_block) + cb = server._agent_cbs("sid-1")["clarify_callback"] + + cb("Pick many", ["a", "b"], multi_select=True) + assert captured["payload"] == { + "question": "Pick many", + "choices": ["a", "b"], + "multi_select": True, + } + + cb("Pick one", ["a", "b"], multi_select=False) + assert captured["payload"] == {"question": "Pick one", "choices": ["a", "b"]} + + @pytest.mark.parametrize( ("configured", "expected"), [(0, None), (-1, None), (42, 42)], diff --git a/tui_gateway/server.py b/tui_gateway/server.py index c4b499cd8603..39253e14561b 100644 --- a/tui_gateway/server.py +++ b/tui_gateway/server.py @@ -5040,8 +5040,13 @@ def _agent_cbs(sid: str) -> dict: # multi_select is a pass-through hint: renderers with checkbox # support can honor it; older renderers ignore the extra field # and stay single-select (a single answer still parses as a - # one-element list on the tool side). - {"question": q, "choices": c, "multi_select": bool(multi_select)}, + # one-element list on the tool side). Only emitted when True so + # single-select payloads keep the exact pre-multi-select shape. + ( + {"question": q, "choices": c, "multi_select": True} + if multi_select + else {"question": q, "choices": c} + ), timeout=_clarify_timeout_seconds(), ), # read_terminal tool (desktop GUI): same blocking bridge as clarify — the