Completes the STREAM_BROWSER=true behaviour:
- handleJoin auto-starts the broadcast on voice join and wires the session to
the guild streamer; each turn reports the live state to the brain so search
routes Chrome (live) vs Gemini (off).
- New setBroadcast tool lets the user toggle the broadcast by voice ("방송
켜줘/꺼줘") via the LLM (no hardcoded phrases); it refuses when
STREAM_BROWSER=false. The directive flows brain -> bridge (broadcast_action)
-> bot streamer.start/stop, guarded by isActive() so it's idempotent.
- Per-turn IPC uses a thread-local (reply/turn_state.py) instead of threading
params through the whole engine chain: bridge sets broadcasting in, tool
records the directive out; Tool.execute exposes broadcasting on ToolContext.
Bot typecheck clean; brain covered by tests/test_set_broadcast.py (+ existing
routing tests). Specs + docs updated.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1.4 KiB
1.4 KiB
setBroadcast tool
Lets the user turn the live screen-share broadcast (Go-Live) on or off by voice or text, e.g. "방송 켜줘 / 화면 보여줘" or "방송 꺼줘". The LLM picks the intent and calls the tool (no hardcoded phrase matching), so it works in any language.
Contract
- Input:
{ "action": "start" | "stop" }. - The brain cannot drive the Discord broadcast itself (the bot owns it). The
tool records the directive in request-scoped state
(
jarvis/reply/turn_state.request_broadcast);bridge/server.pyreturns it asbroadcast_actionin the/converse(and/text) response, and the bot (voice.ts->index.tsonBroadcastAction) callsstreamer.start/stop. - Mode gate: when
cfg.stream_browseris false (STREAM_BROWSER=false) broadcasting is disabled — the tool refuses with a spoken explanation and records no directive. This is the same capability flag that makes/streamrefuse and forces real-time search to Gemini.
Principles
- Tool returns raw intent/result; it performs no broadcast itself and makes no LLM call.
- Idempotent at the bot edge:
startis a no-op if already live,stopa no-op if already off (streamer.isActive()guard). - Fail-safe: a missing/invalid action records nothing; the bot only acts on an
explicit
"start"/"stop"directive.
See docs/stream_browser_modes.md for how this fits the broadcast-coupled
search routing.