fix: deterministic browser navigate for 'go back to <site>' (구글로 돌아가)

The 7B narrated '구글 메인으로 돌아갑니다' without acting, so the screen stayed on
Naver. Split site intent into SEARCH vs NAV: nav words (돌아가/이동/열어/메인/go
back) now drive controlBrowser.navigate to the site homepage directly, search
words run controlBrowser.search — both deterministically, no LLM.
This commit is contained in:
javis-bot
2026-06-15 00:58:53 +09:00
parent c522e1b285
commit 49061d30f0

View File

@@ -833,25 +833,30 @@ _SITE_TOKEN_MAP = {
"다음": "daum", "daum": "daum",
"": "bing", "bing": "bing",
}
# Search / open intent words (Korean deployment + English). Kept explicit because
# this is a DETERMINISTIC fast-path — the small chat model can't be trusted to
# emit the controlBrowser call reliably, so when the user names a site AND
# expresses a search/open intent we run it directly, no LLM judgement.
_SEARCH_INTENT_WORDS = (
"검색해줘", "검색해", "검색", "찾아줘", "찾아봐", "찾아", "열어줘", "열어",
"들어가줘", "들어가", "띄워줘", "띄워", "보여줘",
"search for", "search", "look up", "find", "open", "go to", "navigate",
# Site homepages for the navigate (go-to / go-back) intent.
_SITE_HOME = {
"naver": "naver.com", "google": "google.com", "daum": "daum.net",
"youtube": "youtube.com", "bing": "bing.com",
}
# SEARCH intent (run a query on the site) vs NAV intent (just open / go back to
# the site). Explicit word lists because this is a DETERMINISTIC fast-path — the
# chat model narrates ("돌아갑니다") without emitting the controlBrowser call, so
# we act directly. "돌아가" (go back) is NAV, "검색" is SEARCH.
_SEARCH_WORDS = ("검색", "찾아", "search", "look up", "find")
_NAV_WORDS = (
"돌아가", "돌아와", "이동", "가줘", "가자", "열어", "들어가", "띄워", "보여",
"메인", "홈페이지", "홈으로", "back to", "go back", "go to", "open", "navigate",
)
_ALL_INTENT_WORDS = _SEARCH_WORDS + _NAV_WORDS + (
"검색해줘", "검색해", "찾아줘", "찾아봐", "열어줘", "들어가줘", "띄워줘", "보여줘",
)
def _maybe_deterministic_site_search(text: str, db, cfg, language) -> Optional[str]:
"""When broadcasting AND the user names a site AND asks to search/open it,
run controlBrowser.search directly so the result actually appears on screen.
The 3B chat model reliably narrates ("검색하겠습니다") instead of emitting the
controlBrowser tool call, so site-specified search is executed
deterministically here rather than left to the model. Fail-open: any problem
returns None and the normal reply flow continues.
"""When broadcasting AND the user names a site AND asks to search or open/go
to it, drive the on-screen browser directly (search or navigate) so it
actually happens — the chat model only narrates ("돌아갑니다") without acting.
Fail-open: any problem returns None and the normal reply flow continues.
"""
try:
from . import turn_state
@@ -865,27 +870,34 @@ def _maybe_deterministic_site_search(text: str, db, cfg, language) -> Optional[s
if _t in low:
site, tok = _key, _t
break
if not site or not any(w in low for w in _SEARCH_INTENT_WORDS):
has_search = any(w in low for w in _SEARCH_WORDS)
has_nav = any(w in low for w in _NAV_WORDS)
if not site or not (has_search or has_nav):
return None
import re
q = re.sub(re.escape(tok) + r"(에서|에다가|에다|에|로|를|을)?", " ", text, flags=re.IGNORECASE)
for w in sorted(_SEARCH_INTENT_WORDS, key=len, reverse=True):
q = re.sub(re.escape(tok) + r"(에서|에다가|에다|에|로|를|을|으로)?", " ", text, flags=re.IGNORECASE)
for w in sorted(_ALL_INTENT_WORDS, key=len, reverse=True):
q = re.sub(re.escape(w), " ", q, flags=re.IGNORECASE)
q = re.sub(r"\s+", " ", q).strip(" .,!?。")
if not q:
q = text
from ..tools.registry import run_tool_with_retries
if has_search and len(q) >= 2:
args = {"action": "search", "site": site, "query": q}
else:
# NAV (go back / open) — go to the site's homepage.
args = {"action": "navigate", "url": _SITE_HOME.get(site, site)}
res = run_tool_with_retries(
db=db, cfg=cfg, tool_name="controlBrowser",
tool_args={"action": "search", "site": site, "query": q},
db=db, cfg=cfg, tool_name="controlBrowser", tool_args=args,
system_prompt="", original_prompt="", redacted_text=redact(text),
max_retries=1, language=language,
)
if res and getattr(res, "success", False):
debug_log(f"deterministic site search executed: {site} '{q}'", "tools")
debug_log(f"deterministic browser: {args}", "tools")
if args["action"] == "navigate":
return res.reply_text or f"{site} 메인 페이지로 이동했습니다."
return res.reply_text or f"{site}에서 '{q}'를 검색해 화면에 띄웠습니다."
except Exception as e: # noqa: BLE001
debug_log(f"deterministic site search failed (fail-open): {e}", "tools")
debug_log(f"deterministic browser failed (fail-open): {e}", "tools")
return None