[Haik]: ckpt, removed legacy deps from run_browser_loop. Now gonna refactor the new schemas.py to behave more like every other toolkit

This commit is contained in:
haikdc
2026-04-02 14:54:28 -07:00
parent 91fc6377ec
commit 804aeb74f9
3 changed files with 178 additions and 12 deletions
@@ -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,
@@ -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}",
)
@@ -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