From 804aeb74f9d10e49299bf0e0cd3834b015f3fb06 Mon Sep 17 00:00:00 2001 From: haikdc Date: Thu, 2 Apr 2026 14:54:28 -0700 Subject: [PATCH] [Haik]: ckpt, removed legacy deps from run_browser_loop. Now gonna refactor the new schemas.py to behave more like every other toolkit --- .../handlers/utils/run_browser_loop.py | 23 ++- .../utils/temp_sub_utils/model_ids.py | 30 ++++ .../handlers/utils/temp_sub_utils/schemas.py | 137 ++++++++++++++++++ 3 files changed, 178 insertions(+), 12 deletions(-) create mode 100644 backend/apps/agents/HaikFix/tools/make_builtin_toolkit/open_swarm_toolkits/browser_toolkit/handlers/utils/temp_sub_utils/model_ids.py create mode 100644 backend/apps/agents/HaikFix/tools/make_builtin_toolkit/open_swarm_toolkits/browser_toolkit/handlers/utils/temp_sub_utils/schemas.py diff --git a/backend/apps/agents/HaikFix/tools/make_builtin_toolkit/open_swarm_toolkits/browser_toolkit/handlers/utils/run_browser_loop.py b/backend/apps/agents/HaikFix/tools/make_builtin_toolkit/open_swarm_toolkits/browser_toolkit/handlers/utils/run_browser_loop.py index 78ff64e6..8f4b5e8f 100644 --- a/backend/apps/agents/HaikFix/tools/make_builtin_toolkit/open_swarm_toolkits/browser_toolkit/handlers/utils/run_browser_loop.py +++ b/backend/apps/agents/HaikFix/tools/make_builtin_toolkit/open_swarm_toolkits/browser_toolkit/handlers/utils/run_browser_loop.py @@ -1,20 +1,18 @@ import time from typing import Dict, List, Any -from backend.apps.agents.browser.schemas import ( - BROWSER_TOOLS_SCHEMA, SYSTEM_PROMPT, MAX_TURNS, -) + # NOTE: Hella dependancies, this baddddddd # TODO: fix this shit cuh from backend.apps.agents.browser.executor import execute_browser_tool, _format_tool_result -from backend.apps.settings.settings import load_settings -from backend.apps.settings.credentials import get_anthropic_client -from backend.apps.common.model_registry import resolve_model_id -from backend.apps.common.llm_helpers import _resolve_model as _resolve_9r + +from backend.apps.agents.HaikFix.tools.make_builtin_toolkit.open_swarm_toolkits.browser_toolkit.handlers.utils.temp_sub_utils.model_ids import is_valid_model_id +from backend.apps.agents.HaikFix.tools.make_builtin_toolkit.open_swarm_toolkits.browser_toolkit.handlers.utils.temp_sub_utils.model_ids import get_anthropic_client +from backend.apps.agents.HaikFix.tools.make_builtin_toolkit.open_swarm_toolkits.browser_toolkit.handlers.utils.temp_sub_utils.schemas import BROWSER_TOOLS_SCHEMA, SYSTEM_PROMPT, MAX_TURNS async def run_browser_loop( task: str, browser_id: str, - model: str, + model_id: str, initial_url: str | None = None, tab_id: str = "", ) -> Dict[str, Any]: @@ -23,9 +21,10 @@ async def run_browser_loop( if initial_url: await execute_browser_tool("BrowserNavigate", {"url": initial_url}, browser_id, tab_id) - settings = load_settings() - api_model = _resolve_9r(resolve_model_id(model), settings) - client = get_anthropic_client(settings) + if not is_valid_model_id(model_id): + raise ValueError(f"Invalid model ID: {model_id}") + + client = get_anthropic_client() messages: List[Dict] = [{"role": "user", "content": task}] action_log: List[Dict] = [] @@ -34,7 +33,7 @@ async def run_browser_loop( for _ in range(MAX_TURNS): response = await client.messages.create( - model=api_model, + model=f"cc/{model_id}", max_tokens=4096, system=SYSTEM_PROMPT, tools=BROWSER_TOOLS_SCHEMA, diff --git a/backend/apps/agents/HaikFix/tools/make_builtin_toolkit/open_swarm_toolkits/browser_toolkit/handlers/utils/temp_sub_utils/model_ids.py b/backend/apps/agents/HaikFix/tools/make_builtin_toolkit/open_swarm_toolkits/browser_toolkit/handlers/utils/temp_sub_utils/model_ids.py new file mode 100644 index 00000000..c82ed351 --- /dev/null +++ b/backend/apps/agents/HaikFix/tools/make_builtin_toolkit/open_swarm_toolkits/browser_toolkit/handlers/utils/temp_sub_utils/model_ids.py @@ -0,0 +1,30 @@ +from typeguard import typechecked +from backend.ports import NINE_ROUTER_PORT +import anthropic +import httpx + +SONNET: str = "claude-sonnet-4-6" +OPUS: str = "claude-opus-4-6" +HAIKU: str = "claude-haiku-4-5" + +@typechecked +def is_valid_model_id(model_id: str) -> bool: + return model_id in [SONNET, OPUS, HAIKU] + +@typechecked +def check_9router() -> bool: + """Check if 9Router is running locally.""" + try: + response: httpx.Response = httpx.get(f"http://localhost:{NINE_ROUTER_PORT}/v1/models", timeout=2.0) + return response.status_code == 200 + except Exception: + return False + +@typechecked +def get_anthropic_client() -> anthropic.AsyncAnthropic: + if not check_9router(): + raise ValueError("9Router is not running") + return anthropic.AsyncAnthropic( + api_key="9router", + base_url=f"http://localhost:{NINE_ROUTER_PORT}", + ) \ No newline at end of file diff --git a/backend/apps/agents/HaikFix/tools/make_builtin_toolkit/open_swarm_toolkits/browser_toolkit/handlers/utils/temp_sub_utils/schemas.py b/backend/apps/agents/HaikFix/tools/make_builtin_toolkit/open_swarm_toolkits/browser_toolkit/handlers/utils/temp_sub_utils/schemas.py new file mode 100644 index 00000000..a68b0f22 --- /dev/null +++ b/backend/apps/agents/HaikFix/tools/make_builtin_toolkit/open_swarm_toolkits/browser_toolkit/handlers/utils/temp_sub_utils/schemas.py @@ -0,0 +1,137 @@ +"""Browser tool schemas, constants, and system prompt.""" + +BROWSER_TOOLS_SCHEMA = [ + { + "name": "BrowserScreenshot", + "description": ( + "Capture a screenshot of the browser page. Returns the screenshot as a " + "base64-encoded PNG image. Use this to see what is currently displayed." + ), + "input_schema": {"type": "object", "properties": {}, "required": []}, + }, + { + "name": "BrowserGetText", + "description": "Get the visible text content of the browser page. Returns up to 15000 characters.", + "input_schema": {"type": "object", "properties": {}, "required": []}, + }, + { + "name": "BrowserNavigate", + "description": "Navigate the browser to a URL.", + "input_schema": { + "type": "object", + "properties": {"url": {"type": "string", "description": "The URL to navigate to."}}, + "required": ["url"], + }, + }, + { + "name": "BrowserClick", + "description": "Click an element identified by a CSS selector. Use BrowserGetElements first to discover valid selectors.", + "input_schema": { + "type": "object", + "properties": {"selector": {"type": "string", "description": "CSS selector of the element to click."}}, + "required": ["selector"], + }, + }, + { + "name": "BrowserType", + "description": "Type text into an input element. Clears existing value first.", + "input_schema": { + "type": "object", + "properties": { + "selector": {"type": "string", "description": "CSS selector of the input element."}, + "text": {"type": "string", "description": "The text to type."}, + }, + "required": ["selector", "text"], + }, + }, + { + "name": "BrowserEvaluate", + "description": "Evaluate a JavaScript expression in the browser page and return the result.", + "input_schema": { + "type": "object", + "properties": {"expression": {"type": "string", "description": "JavaScript expression to evaluate."}}, + "required": ["expression"], + }, + }, + { + "name": "BrowserGetElements", + "description": ( + "Get a list of interactive elements on the page with CSS selectors. " + "Call this BEFORE clicking or typing so you know which selectors are valid." + ), + "input_schema": { + "type": "object", + "properties": { + "selector": { + "type": "string", + "description": "Optional CSS selector to scope the search (e.g. 'form', '#main'). Defaults to 'body'.", + }, + }, + "required": [], + }, + }, + { + "name": "BrowserScroll", + "description": ( + "Scroll the page up or down. Automatically finds the correct scrollable " + "container. Returns scroll position info including whether top/bottom has been reached." + ), + "input_schema": { + "type": "object", + "properties": { + "direction": {"type": "string", "enum": ["up", "down"], "description": "Scroll direction. Defaults to 'down'."}, + "amount": {"type": "number", "description": "Pixels to scroll. Defaults to 500."}, + }, + "required": [], + }, + }, + { + "name": "BrowserWait", + "description": ( + "Wait for a specified duration. Useful after navigation or actions that " + "trigger page loads. Min 100ms, max 10000ms." + ), + "input_schema": { + "type": "object", + "properties": {"milliseconds": {"type": "number", "description": "Duration to wait in milliseconds. Defaults to 1000."}}, + "required": [], + }, + }, +] + +ACTION_MAP = { + "BrowserScreenshot": "screenshot", + "BrowserGetText": "get_text", + "BrowserNavigate": "navigate", + "BrowserClick": "click", + "BrowserType": "type", + "BrowserEvaluate": "evaluate", + "BrowserGetElements": "get_elements", + "BrowserScroll": "scroll", + "BrowserWait": "wait", +} + +SYSTEM_PROMPT = ( + "You are a browser automation agent. You control a single browser tab and " + "execute the task you are given.\n\n" + "Strategy:\n" + "1. Start by taking a screenshot to understand the page.\n" + "2. After navigation, use BrowserWait (1-3 seconds) to let the page finish loading.\n" + "3. Use BrowserScroll to scroll through pages — do NOT use BrowserEvaluate with " + "window.scrollBy() as many sites use nested scroll containers that BrowserScroll " + "handles automatically.\n" + "4. Use BrowserGetElements BEFORE clicking or typing to discover valid CSS selectors.\n" + "5. After performing actions, take a screenshot to verify the result.\n" + "6. If an action fails, try alternative selectors or approaches.\n" + "7. When the task is complete, provide a clear summary of what you accomplished.\n\n" + "Important notes:\n" + "- BrowserGetText returns up to 15000 chars of visible text — use it to read page content.\n" + "- BrowserScroll returns position info including atTop/atBottom — use this to know when " + "you've reached the end of the page.\n" + "- For complex SPAs (Notion, Gmail, etc.), prefer BrowserScroll over BrowserEvaluate for scrolling.\n" + "- Avoid looping: if scrolling shows no new content (scrolled 0px), you're at the boundary.\n\n" + "You have access ONLY to browser tools. Do not ask the user questions — " + "complete the task autonomously to the best of your ability." +) + +MAX_TURNS = 25