feat(brain): wire STREAM_BROWSER real-time modes into the reply engine (browser + Gemini)

Completes the two info modes in the Python brain:

- config.py: read STREAM_BROWSER / GEMINI_API_KEY / GEMINI_MODEL from env into
  Settings (stream_browser, gemini_api_key, gemini_model). Verified load_settings
  reads both modes.
- realtime_search.py: two fail-open backends returning the same fenced
  UNTRUSTED-WEB-EXTRACT envelope: browser_search() shells the Node CDP helper to
  drive the on-screen Chrome (visible on the broadcast); gemini_search() calls
  the Gemini REST API with google_search grounding.
- web_search.run(): routes by mode before the DDG cascade (true->browser,
  false->Gemini), falling through to DDG/Brave/Wikipedia on any miss.
- browse_and_play tool: plays a YouTube video on the shared screen (true mode
  only); registered in the tool registry.
- specs + docs/llm_contexts.md updated (new Gemini LLM context); CLAUDE.md spec
  registry updated.

Verified live against the running Chrome: true-mode webSearch returned real
Google results for "오늘 서울 날씨", browseAndPlay played the IU 밤편지 MV, and
false-mode degrades gracefully on a bad/absent key. A valid GEMINI_API_KEY is
still needed to confirm the real Gemini grounding output.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
javis-bot
2026-06-10 16:46:58 +09:00
parent c420d5da53
commit 702fe8017e
9 changed files with 257 additions and 1 deletions

View File

@@ -594,6 +594,26 @@ class WebSearchTool(Tool):
context.user_print(f"🌐 Searching the web for '{search_query}'")
debug_log(f" 🌐 searching for '{search_query}'", "web")
# Real-time info routing by STREAM_BROWSER (docs/stream_browser_modes.md):
# true -> drive the on-screen Chrome (visible on the broadcast),
# false -> Gemini grounded search. Either falls through to the
# DDG/Brave/Wikipedia cascade below if it yields nothing (fail-open).
from .realtime_search import browser_search, gemini_search
if getattr(cfg, "stream_browser", True):
routed = browser_search(search_query)
if routed:
debug_log(" 🌐 routed via browser (STREAM_BROWSER=true)", "web")
return ToolExecutionResult(success=True, reply_text=routed)
elif getattr(cfg, "gemini_api_key", ""):
routed = gemini_search(
search_query,
cfg.gemini_api_key,
getattr(cfg, "gemini_model", "gemini-2.0-flash"),
)
if routed:
debug_log(" 🌐 routed via Gemini (STREAM_BROWSER=false)", "web")
return ToolExecutionResult(success=True, reply_text=routed)
# Overall wall-clock deadline across the full provider chain.
# Individual providers have their own per-call timeouts, but
# stacking DDG + Brave + Wikipedia worst-cases can otherwise