feat(ui): add Beta dynamic tools toggle to Agent UI settings (#1798) - #1857
Conversation
|
Verdict: Approve ✅ This adds a Beta Settings → Dynamic Tools toggle so Agent UI users can opt into the semantic tool loader that previously only The bottom line: the plumbing is threaded through every agent-construction path (not just the visible one), the env-precedence parse is centralized so the toggle and the agent can't disagree, and there's no silent-fallback — a failed save reverts the optimistic flip and surfaces a visible error. Backend and frontend unit coverage is genuinely thorough, including cold-state default-off and a contract-shape assertion that the toggle actually reaches the factory kwargs. The "no eval run" call is correctly justified: the default-off path is byte-identical to today and touches no prompt/tool-selection logic. No blocking issues found. 🔍 Technical detailsStrengths
🟢 Minor (optional)
|
|
Both failing checks are CI infrastructure, not this PR — they died at Lemonade server startup, before any GAIA test ran:
Both are Windows integration jobs that gate on a live Lemonade server; the server didn't come up on the runner, so no code under test executed. This PR only changes the Agent UI dynamic-tools toggle, the settings router/plumbing, docs, and unit tests — it touches nothing in the Lemonade backend or LLM-client path. The backend ( A re-run should clear these once Lemonade starts on the runner. @kovtcharov-amd — could you kick a re-run if the flake sticks? |
Summary
The semantic dynamic tool loader — which cuts first-turn latency on the Doc Agent by trimming each turn's tool prompt to a semantically-matched subset — has shipped dark since #1449: the only way to switch it on was exporting
GAIA_DYNAMIC_TOOLSor editing SDK config, so no Agent UI user could discover or try it. This PR adds a single Beta toggle under Settings → Dynamic Tools so users can opt in without touching env vars. It stays off by default and changes no loader behavior — it only controls whether the UI-built agent setsconfig.dynamic_tools=true.Why
The feature was complete but undiscoverable from the UI — its only on-ramps were a dev/CI env var and an SDK field.
GAIA_DYNAMIC_TOOLSmust stay the authoritative dev/CI/eval override (eval tooling and CI depend on it), so the toggle layers on top rather than replacing it: when the env var is set it wins, and the toggle then reflects the effective value and disables itself with an explanation — never a silent no-op that lies about the running state.Linked issue
Closes #1798
Changes
.toggle-switchpattern with an immediate optimistic save; on failure it reverts and surfaces a visible error (no silent fallback). WhenGAIA_DYNAMIC_TOOLSis set, the toggle shows the effective value, disables, and explains why.dynamic_tools_env_override()so the agent resolver and the settings router parse the same truthy set — no drift between what the toggle shows and what the agent does.GET/PUT /api/settingsnow returndynamic_tools+dynamic_tools_locked;PUTpersists the user's intent even while the env var locks the effective value, so their choice applies once it's unset._session_agent_kwargscarries the field to both the streaming and non-streaming Doc-agent builds (the only path where the loader is observable). The scheduled-prompt build and the autonomous agent-loop tick also read it — inert on their"full"profile today, wired and commented so they can't silently diverge if that ever changes.Deviations from the issue sketch (flagged per plan)
_chat_helpers.pychatsites"full"profile, where the loader is inert; the loader-active path is thedocagent built viaregistry.create_agentin theelsebranchdynamic_toolsthrough_session_agent_kwargs, which reaches the activedocpath and the inertchatsites in one place_session_agent_kwargscovers all sites"server.py's scheduled-prompt path does not call that helperserver.pygets its owndb.get_setting("dynamic_tools")read + an inert-on-"full"commentcustom_model(text input + Save button).toggle-switchpattern (immediate save) — appropriate for a boolean, not a text+Save fieldagent_mode""true"/"false"(precedent:memory_enabled)"true"/"false"; read with the same string compare; missing → offSettingsmirrorsSettingsResponseSettingsomitsagent_mode(backend-only)dynamic_tools+dynamic_tools_lockedto the TS type onlyserver.pyfor the inert future-proofed readagent_loop.pytick is a separateChatAgentConfigbuild site with the same concernNo eval run — deliberate, not skipped. The default-off path is byte-identical to today (
config.dynamic_tools is False⇒ loaderNone); this PR adds a UI surface + plumbing that sets an already-eval-covered config field and touches no prompt, tool registration, or selection logic. Loader behavior remains covered by #1449/#1762's committedscorecard_tool_selection.json.Test plan
python util/lint.py --all→ clean (black/isort/ruff).dynamic_toolskey),GET /api/settingsreturnsdynamic_tools: false, dynamic_tools_locked: false.gaia chat --ui→ Settings → toggle Dynamic Tools on → start a Doc Agent session → confirm oneTOOL_LOADER {…}INFO line in the server log (off ⇒ none). WithGAIA_DYNAMIC_TOOLS=1exported, the toggle renders on and disabled.Checklist
Closes #1798).python util/lint.py --all,pytest tests/unit/).docs/guides/chat.mdx— the toggle as a third enable path).