Skip to content

Commit 4f6ba4c

Browse files
committed
fix determination of temporary chat status
1 parent 44acc21 commit 4f6ba4c

2 files changed

Lines changed: 89 additions & 42 deletions

File tree

browser_utils/initialization/core.py

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -560,12 +560,85 @@ async def signal_camoufox_shutdown() -> None: # pragma: no cover
560560
)
561561

562562

563-
async def enable_temporary_chat_mode(page: AsyncPage) -> None: # pragma: no cover
563+
async def _is_temporary_chat_active(page: AsyncPage) -> bool:
564+
"""Best-effort check for whether Temporary chat is currently enabled.
565+
566+
Supports both the legacy toggle-class signal and the newer UI variants:
567+
- menu item checkmark (`data-test-incognito-checkmark`)
568+
- header indicator (`ms-incognito-mode-indicator`)
569+
"""
570+
571+
try:
572+
# Newer UI: header indicator appears only when Temporary chat is active.
573+
indicator_locator = page.locator(
574+
"ms-incognito-mode-indicator [data-test-id='main-text'], "
575+
"ms-incognito-mode-indicator .main-text"
576+
)
577+
indicator_count = await indicator_locator.count()
578+
for i in range(indicator_count):
579+
try:
580+
indicator_item = indicator_locator.nth(i)
581+
if not await indicator_item.is_visible(timeout=500):
582+
continue
583+
indicator_text = (await indicator_item.inner_text()).strip().lower()
584+
if indicator_text == "temporary chat":
585+
return True
586+
except Exception:
587+
continue
588+
589+
# Menu button variants (legacy and gray-release UI).
590+
toggle_locator = page.locator(
591+
"button[data-test-incognito-toggle], "
592+
'button[aria-label="Temporary chat toggle"], '
593+
'button[aria-label="Toggle temporary chat"]'
594+
)
595+
if await toggle_locator.count() > 0:
596+
toggle_button = toggle_locator.first
597+
598+
# New UI: active state is represented by a checkmark inside the menu item.
599+
try:
600+
checkmark_locator = toggle_button.locator(
601+
"[data-test-incognito-checkmark]"
602+
)
603+
if (
604+
await checkmark_locator.count() > 0
605+
and await checkmark_locator.first.is_visible(timeout=500)
606+
):
607+
return True
608+
except Exception:
609+
pass
610+
611+
# Legacy/alternative signals.
612+
for attr_name in ("aria-pressed", "aria-checked"):
613+
try:
614+
attr_value = await toggle_button.get_attribute(attr_name)
615+
if attr_value and attr_value.lower() == "true":
616+
return True
617+
except Exception:
618+
pass
619+
620+
try:
621+
button_classes = await toggle_button.get_attribute("class") or ""
622+
if "ms-button-active" in button_classes:
623+
return True
624+
except Exception:
625+
pass
626+
627+
return False
628+
except Exception:
629+
return False
630+
631+
632+
async def enable_temporary_chat_mode(page: AsyncPage) -> bool: # pragma: no cover
564633
"""
565634
Check and enable "Temporary chat" mode in the AI Studio interface.
566635
Supports both direct UI visibility and collapsed menu visibility.
567636
"""
568-
incognito_selector = 'button[aria-label="Temporary chat toggle"], button[aria-label="Toggle temporary chat"]'
637+
incognito_selector = (
638+
"button[data-test-incognito-toggle], "
639+
'button[aria-label="Temporary chat toggle"], '
640+
'button[aria-label="Toggle temporary chat"]'
641+
)
569642
menu_trigger_selector = 'button[aria-label="View more actions"]'
570643

571644
incognito_locator = page.locator(incognito_selector)
@@ -585,23 +658,23 @@ async def enable_temporary_chat_mode(page: AsyncPage) -> None: # pragma: no cov
585658
await incognito_locator.wait_for(state="visible", timeout=5000)
586659
else:
587660
logger.warning("[UI] Neither button nor menu trigger found")
588-
return
589-
590-
# Status Check
591-
button_classes = await incognito_locator.get_attribute("class") or ""
661+
return False
592662

593-
if "ms-button-active" in button_classes:
663+
if await _is_temporary_chat_active(page):
594664
logger.debug("[UI] Temporary chat mode already active")
595665
else:
596666
logger.debug("[UI] Enabling temporary chat mode")
597667
await incognito_locator.click(timeout=5000, force=True)
598668
await asyncio.sleep(1)
599669

670+
enabled = await _is_temporary_chat_active(page)
671+
600672
# Recovery: Close menu if still expanded
601673
# Checking aria-expanded is more precise than a boolean flag
602674
if await menu_trigger.get_attribute("aria-expanded") == "true":
603675
logger.debug("[UI] Closing menu to restore UI state")
604676
await page.keyboard.press("Escape")
677+
return enabled
605678

606679
except asyncio.CancelledError:
607680
raise
@@ -610,3 +683,4 @@ async def enable_temporary_chat_mode(page: AsyncPage) -> None: # pragma: no cov
610683
# Final safety attempt to clear any stuck UI
611684
if await menu_trigger.get_attribute("aria-expanded") == "true":
612685
await page.keyboard.press("Escape")
686+
return await _is_temporary_chat_active(page)

browser_utils/models/switcher.py

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -160,47 +160,20 @@ async def switch_ai_studio_model(page: AsyncPage, model_id: str, req_id: str) ->
160160
if page_display_match:
161161
try:
162162
logger.debug("[Model] Re-enabling temporary chat mode...")
163-
incognito_selector = 'button[aria-label="Temporary chat toggle"], button[aria-label="Toggle temporary chat"]'
164-
menu_trigger_selector = 'button[aria-label="View more actions"]'
165-
166-
incognito_locator = page.locator(incognito_selector)
167-
menu_trigger = page.locator(menu_trigger_selector)
168-
169-
# Fast path: try to find the button directly
170-
try:
171-
await incognito_locator.wait_for(state="visible", timeout=3000)
172-
except Exception:
173-
# Fallback: check if it's inside the menu
174-
if await menu_trigger.is_visible():
175-
logger.debug("[Model] Button not visible, opening menu...")
176-
await menu_trigger.click()
177-
await incognito_locator.wait_for(state="visible", timeout=5000)
178-
179-
button_classes = await incognito_locator.get_attribute("class") or ""
180-
181-
if "ms-button-active" in button_classes:
182-
logger.debug("[Model] Temporary chat mode already active")
183-
else:
184-
logger.debug("[Model] Clicking to open temporary chat mode...")
185-
await incognito_locator.click(timeout=3000, force=True)
186-
await asyncio.sleep(0.5)
187-
188-
updated_classes = await incognito_locator.get_attribute("class") or ""
189-
if "ms-button-active" in updated_classes:
190-
logger.debug("[Model] Temporary chat mode enabled")
191-
else:
192-
logger.warning("[Model] Temporary chat mode state verification failed")
163+
from browser_utils.initialization import enable_temporary_chat_mode
193164

194-
# Recovery: Close menu if it remains open
195-
if await menu_trigger.get_attribute("aria-expanded") == "true":
196-
await page.keyboard.press("Escape")
165+
enabled = await enable_temporary_chat_mode(page)
166+
if enabled:
167+
logger.debug("[Model] Temporary chat mode enabled or already active")
168+
else:
169+
logger.warning(
170+
"[Model] Temporary chat mode state verification failed"
171+
)
197172

198173
except asyncio.CancelledError:
199174
raise
200175
except Exception as e:
201176
logger.warning(f"Failed to re-enable temporary chat mode after model switching: {e}")
202-
if await menu_trigger.get_attribute("aria-expanded") == "true":
203-
await page.keyboard.press("Escape")
204177

205178
# Invalidate function calling cache on model switch
206179
try:

0 commit comments

Comments
 (0)