Honor configured Browser model preset
Activate the selected Browser preset after the first Browser tool call so follow-up model turns use it. Clear the temporary override at monologue end and preserve the main model as the safe fallback.
Alessandro committed
Aug 16, 2026 at 15:21 UTC
a0eefe19bd81e180dd6c72bbb4206b265722f827
5 files changed
+117
-3
plugins/_browser/extensions/python/_functions/agent/Agent/get_chat_model/start/_20_browser_model.py
new
+14
@@ -0,0 +1,14 @@
1
+from helpers.extension import Extension
2
+from plugins._browser.helpers.config import (
3
+ browser_model_is_active,
4
+ resolve_browser_model,
5
+)
6
+
7
+
8
+class BrowserModelProvider(Extension):
9
+ def execute(self, data: dict = {}, **kwargs):
10
+ if self.agent and browser_model_is_active(self.agent):
11
+ data["result"] = resolve_browser_model(
12
+ self.agent,
13
+ fallback=data.get("result"),
14
+ )
plugins/_browser/extensions/python/monologue_end/_20_browser_model.py
new
+8
@@ -0,0 +1,8 @@
1
+from helpers.extension import Extension
2
+from plugins._browser.helpers.config import clear_browser_model
3
+
4
+
5
+class BrowserModelCleanup(Extension):
6
+ def execute(self, **kwargs):
7
+ if self.agent:
8
+ clear_browser_model(self.agent)
plugins/_browser/helpers/config.py
+27
-2
@@ -9,6 +9,7 @@ if TYPE_CHECKING:
9
10
PLUGIN_NAME = "_browser"
11
MODEL_PRESET_KEY = "model_preset"
12
+BROWSER_MODEL_ACTIVE_KEY = "_browser_model_active"
13
DEFAULT_HOMEPAGE_KEY = "default_homepage"
14
AUTOFOCUS_ACTIVE_PAGE_KEY = "autofocus_active_page"
15
TAB_SCOPE_KEY = "browser_tab_scope"
@@ -319,10 +320,34 @@ def resolve_browser_model_selection(
320
}
321
322
322
-def resolve_browser_model(agent: "Agent", settings: dict[str, Any] | None = None):
323
+def activate_browser_model(agent: "Agent") -> dict[str, Any]:
324
+ selection = resolve_browser_model_selection(agent=agent)
325
+ agent.set_data(
326
+ BROWSER_MODEL_ACTIVE_KEY,
327
+ selection["selected_preset_name"]
328
+ if selection["source_kind"] == "preset"
329
+ else "",
330
+ )
331
+ return selection
332
+
333
+
334
+def clear_browser_model(agent: "Agent") -> None:
335
+ agent.set_data(BROWSER_MODEL_ACTIVE_KEY, "")
336
+
337
+
338
+def browser_model_is_active(agent: "Agent") -> bool:
339
+ return bool(agent.get_data(BROWSER_MODEL_ACTIVE_KEY))
340
+
341
+
342
+def resolve_browser_model(
343
+ agent: "Agent",
344
+ settings: dict[str, Any] | None = None,
345
+ fallback: Any = None,
346
+):
347
selection = resolve_browser_model_selection(agent=agent, settings=settings)
348
if selection["source_kind"] == "main":
325
- return agent.get_chat_model()
349
+ clear_browser_model(agent)
350
+ return fallback if fallback is not None else agent.get_chat_model()
351
352
import models
353
from plugins._model_config.helpers import model_config
plugins/_browser/tools/browser.py
+5
@@ -10,6 +10,7 @@ from typing import Any
10
from helpers import files
11
from helpers.print_style import PrintStyle
12
from helpers.tool import Response, Tool
13
+from plugins._browser.helpers.config import activate_browser_model
14
from plugins._browser.helpers.selector import get_tool_runtime
15
16
@@ -74,6 +75,10 @@ class Browser(Tool):
75
action = "clipboard"
76
else:
77
action = str(action or self.method or "state").strip().lower().replace("-", "_")
78
+ try:
79
+ activate_browser_model(self.agent)
80
+ except Exception as exc:
81
+ PrintStyle.warning(f"Browser model preset could not be activated: {exc}")
82
try:
83
runtime = await get_runtime(self.agent.context.id, agent=self.agent)
84
except Exception as exc:
tests/test_browser_agent_regressions.py
+63
-1
@@ -22,6 +22,19 @@ class _TestAgentContext:
22
return None
23
24
25
+class _TestAgent:
26
+ pass
27
+
28
+
29
+class _TestAgentConfig:
30
+ pass
31
+
32
+
33
+class _TestAgentContextType:
34
+ BACKGROUND = "background"
35
+ USER = SimpleNamespace(value="user")
36
+
37
+
38
class _TestResponse(SimpleNamespace):
39
def __init__(self, message="", break_loop=False, **kwargs):
40
super().__init__(message=message, break_loop=break_loop, **kwargs)
@@ -67,7 +80,15 @@ class _TestWsResult(dict):
80
)
81
82
70
-sys.modules.setdefault("agent", SimpleNamespace(AgentContext=_TestAgentContext))
83
+sys.modules.setdefault(
84
+ "agent",
85
+ SimpleNamespace(
86
+ Agent=_TestAgent,
87
+ AgentConfig=_TestAgentConfig,
88
+ AgentContext=_TestAgentContext,
89
+ AgentContextType=_TestAgentContextType,
90
+ ),
91
+)
92
sys.modules.setdefault("helpers.tool", SimpleNamespace(Response=_TestResponse, Tool=_TestTool))
93
sys.modules.setdefault("helpers.ws", SimpleNamespace(WsHandler=_TestWsHandler))
94
sys.modules.setdefault("helpers.ws_manager", SimpleNamespace(WsResult=_TestWsResult))
@@ -295,6 +316,47 @@ def test_browser_model_selection_falls_back_to_main_for_missing_preset(monkeypat
316
assert selection["config"] == {"provider": "openrouter", "name": "main/model"}
317
318
319
+def test_browser_model_preset_controls_followup_turn_and_clears(monkeypatch):
320
+ import importlib
321
+ import plugins._browser.helpers.config as browser_config_module
322
+
323
+ state = {}
324
+ agent = SimpleNamespace(
325
+ set_data=lambda key, value: state.__setitem__(key, value),
326
+ get_data=lambda key: state.get(key),
327
+ )
328
+ monkeypatch.setattr(
329
+ browser_config_module,
330
+ "resolve_browser_model_selection",
331
+ lambda agent=None, settings=None: {
332
+ "source_kind": "preset",
333
+ "selected_preset_name": "Browser",
334
+ },
335
+ )
336
+
337
+ browser_config_module.activate_browser_model(agent)
338
+ assert browser_config_module.browser_model_is_active(agent)
339
+
340
+ provider_module = importlib.import_module(
341
+ "plugins._browser.extensions.python._functions.agent.Agent.get_chat_model.start._20_browser_model"
342
+ )
343
+ cleanup_module = importlib.import_module(
344
+ "plugins._browser.extensions.python.monologue_end._20_browser_model"
345
+ )
346
+ selected_model = object()
347
+ monkeypatch.setattr(
348
+ provider_module,
349
+ "resolve_browser_model",
350
+ lambda agent, fallback=None: selected_model,
351
+ )
352
+ model_data = {"result": object()}
353
+ provider_module.BrowserModelProvider(agent).execute(data=model_data)
354
+ assert model_data["result"] is selected_model
355
+
356
+ cleanup_module.BrowserModelCleanup(agent).execute()
357
+ assert not browser_config_module.browser_model_is_active(agent)
358
+
359
+
360
def test_browser_model_preset_options_include_missing_selected(monkeypatch):
361
from plugins._model_config.helpers import model_config
362