mirror of
https://github.com/langchain-ai/deepagents.git
synced 2026-07-21 17:25:26 -04:00
fix(code): re-apply theme preference on /reload (#4514)
`/reload` now picks up a theme default saved in another session and switches to it. --- `/reload` (in `libs/code`) rebuilt the theme *registry* (`theme.reload_registry()` + `_register_custom_themes()`) but never re-evaluated which theme should be *active* — it never re-ran `_load_theme_preference()` or reassigned `self.theme`. So a per-terminal default (`[ui.terminal_themes][TERM_PROGRAM]`) or global default saved by another session was ignored until the app restarted. This re-resolves the preference after the registry reload and applies it (with terminal-background sync + CSS refresh), matching startup resolution order (env → terminal default → `[ui].theme` → default). Re-applying the on-disk preference is the intended `/reload` semantic, so it deliberately overrides an unsaved in-session `/theme` choice. Made by [Open SWE](https://openswe.vercel.app/agents/7edbf211-076a-afd0-c0a8-76c44c422e00) Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
This commit is contained in:
@@ -9642,6 +9642,28 @@ class DeepAgentsApp(App):
|
||||
theme_reload_ok = False
|
||||
logger.warning("Failed to reload user themes", exc_info=True)
|
||||
|
||||
# Re-resolve and apply the theme preference so a per-terminal or
|
||||
# global default saved by another session is picked up. This
|
||||
# re-syncs to on-disk config using the same resolution as startup
|
||||
# (env -> [ui.terminal_themes][TERM_PROGRAM] -> [ui].theme ->
|
||||
# default), which intentionally overrides an unsaved in-session
|
||||
# `/theme` choice. Guarded on the registry reload succeeding since
|
||||
# the target theme must be registered before it can be applied.
|
||||
theme_switched_to: str | None = None
|
||||
if theme_reload_ok:
|
||||
try:
|
||||
new_theme = _load_theme_preference()
|
||||
if new_theme != self.theme and new_theme in theme.get_registry():
|
||||
self.theme = new_theme
|
||||
self.sync_terminal_background()
|
||||
self.refresh_css(animate=False)
|
||||
theme_switched_to = new_theme
|
||||
except Exception:
|
||||
logger.warning(
|
||||
"Failed to re-apply theme preference on reload",
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
# Re-discover skills so autocomplete reflects any new/removed
|
||||
# skills. Run via the same exclusive-group worker used at
|
||||
# startup so any in-flight startup discovery is cancelled
|
||||
@@ -9667,6 +9689,10 @@ class DeepAgentsApp(App):
|
||||
report += "\nModel config caches cleared."
|
||||
if theme_reload_ok:
|
||||
report += "\nTheme registry reloaded."
|
||||
if theme_switched_to is not None:
|
||||
entry = theme.get_registry().get(theme_switched_to)
|
||||
label = entry.label if entry is not None else theme_switched_to
|
||||
report += f"\nSwitched theme to {label}."
|
||||
else:
|
||||
report += (
|
||||
"\nTheme registry reload failed. Check config.toml for errors."
|
||||
|
||||
@@ -828,3 +828,88 @@ class TestReloadSkillReport:
|
||||
# Critical: must not claim every prior skill was removed.
|
||||
assert "Removed:" not in text
|
||||
assert "Skills updated" not in text
|
||||
|
||||
|
||||
class TestReloadThemeReapply:
|
||||
"""`/reload` should re-apply the resolved theme preference.
|
||||
|
||||
Guards the cross-session behavior: saving a per-terminal (or global)
|
||||
default theme in one window should be picked up by an already-running
|
||||
session's `/reload`, matching startup resolution.
|
||||
"""
|
||||
|
||||
async def _run_reload_theme(
|
||||
self,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
*,
|
||||
initial_theme: str,
|
||||
resolved_theme: str,
|
||||
) -> tuple[str, str]:
|
||||
"""Drive `/reload` once with a stubbed preference resolver.
|
||||
|
||||
Args:
|
||||
monkeypatch: pytest fixture for restorable patching.
|
||||
initial_theme: theme active before reload.
|
||||
resolved_theme: value `_load_theme_preference` returns on reload.
|
||||
|
||||
Returns:
|
||||
The active theme after reload and the mounted `AppMessage` text.
|
||||
"""
|
||||
from deepagents_code import app as app_module
|
||||
from deepagents_code.app import DeepAgentsApp
|
||||
from deepagents_code.widgets.messages import AppMessage
|
||||
|
||||
app = DeepAgentsApp()
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.pause()
|
||||
app.theme = initial_theme
|
||||
|
||||
async def _fake_discover() -> bool: # noqa: RUF029 # awaited by handler
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(app, "_discover_skills", _fake_discover)
|
||||
monkeypatch.setattr(
|
||||
app_module, "_load_theme_preference", lambda: resolved_theme
|
||||
)
|
||||
|
||||
await app._handle_command("/reload")
|
||||
await pilot.pause()
|
||||
|
||||
text = "\n".join(str(w._content) for w in app.query(AppMessage))
|
||||
return app.theme, text
|
||||
|
||||
async def test_switches_to_new_default(
|
||||
self, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""A newly resolved preference should become the active theme."""
|
||||
active, text = await self._run_reload_theme(
|
||||
monkeypatch,
|
||||
initial_theme="langchain",
|
||||
resolved_theme="langchain-light",
|
||||
)
|
||||
assert active == "langchain-light"
|
||||
assert "Switched theme to" in text
|
||||
|
||||
async def test_no_switch_when_unchanged(
|
||||
self, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""When the resolved preference matches the active theme, no switch."""
|
||||
active, text = await self._run_reload_theme(
|
||||
monkeypatch,
|
||||
initial_theme="langchain",
|
||||
resolved_theme="langchain",
|
||||
)
|
||||
assert active == "langchain"
|
||||
assert "Switched theme to" not in text
|
||||
|
||||
async def test_unregistered_preference_ignored(
|
||||
self, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""A resolved name that isn't registered must not change the theme."""
|
||||
active, text = await self._run_reload_theme(
|
||||
monkeypatch,
|
||||
initial_theme="langchain",
|
||||
resolved_theme="not-a-real-theme",
|
||||
)
|
||||
assert active == "langchain"
|
||||
assert "Switched theme to" not in text
|
||||
|
||||
Reference in New Issue
Block a user