Spaces:
Paused
Paused
frdel commited on
Commit ·
bedc13b
1
Parent(s): fba8c75
browser use upgrade
Browse files- models.py +69 -20
- python/tools/browser_agent.py +2 -1
- requirements.txt +2 -2
- run_ui.py +3 -1
models.py
CHANGED
|
@@ -19,7 +19,7 @@ import litellm
|
|
| 19 |
import openai
|
| 20 |
|
| 21 |
from python.helpers import dotenv
|
| 22 |
-
from python.helpers import settings
|
| 23 |
from python.helpers.dotenv import load_dotenv
|
| 24 |
from python.helpers.providers import get_provider_config
|
| 25 |
from python.helpers.rate_limiter import RateLimiter
|
|
@@ -545,7 +545,27 @@ class LiteLLMChatWrapper(SimpleChatModel):
|
|
| 545 |
await asyncio.sleep(retry_delay_s)
|
| 546 |
|
| 547 |
|
| 548 |
-
class
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 549 |
"""
|
| 550 |
A wrapper for browser agent that can filter/sanitize messages
|
| 551 |
before sending them to the LLM.
|
|
@@ -553,32 +573,61 @@ class BrowserCompatibleChatWrapper(LiteLLMChatWrapper):
|
|
| 553 |
|
| 554 |
def __init__(self, *args, **kwargs):
|
| 555 |
turn_off_logging()
|
| 556 |
-
|
|
|
|
| 557 |
# Browser-use may expect a 'model' attribute
|
| 558 |
-
self.model = self.model_name
|
|
|
|
| 559 |
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
|
| 563 |
-
stop: Optional[List[str]] = None,
|
| 564 |
-
run_manager: Optional[CallbackManagerForLLMRun] = None,
|
| 565 |
-
**kwargs: Any,
|
| 566 |
-
) -> str:
|
| 567 |
-
turn_off_logging()
|
| 568 |
-
result = super()._call(messages, stop, run_manager, **kwargs)
|
| 569 |
-
return result
|
| 570 |
|
| 571 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 572 |
self,
|
| 573 |
messages: List[BaseMessage],
|
| 574 |
stop: Optional[List[str]] = None,
|
| 575 |
-
run_manager: Optional[
|
| 576 |
**kwargs: Any,
|
| 577 |
-
)
|
| 578 |
-
|
| 579 |
-
|
| 580 |
-
yield chunk
|
| 581 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 582 |
|
| 583 |
class LiteLLMEmbeddingWrapper(Embeddings):
|
| 584 |
model_name: str
|
|
|
|
| 19 |
import openai
|
| 20 |
|
| 21 |
from python.helpers import dotenv
|
| 22 |
+
from python.helpers import settings, dirty_json
|
| 23 |
from python.helpers.dotenv import load_dotenv
|
| 24 |
from python.helpers.providers import get_provider_config
|
| 25 |
from python.helpers.rate_limiter import RateLimiter
|
|
|
|
| 545 |
await asyncio.sleep(retry_delay_s)
|
| 546 |
|
| 547 |
|
| 548 |
+
class AsyncAIChatReplacement:
|
| 549 |
+
class _Completions:
|
| 550 |
+
def __init__(self, wrapper):
|
| 551 |
+
self._wrapper = wrapper
|
| 552 |
+
|
| 553 |
+
async def create(self, *args, **kwargs):
|
| 554 |
+
# call the async _acall method on the wrapper
|
| 555 |
+
return await self._wrapper._acall(*args, **kwargs)
|
| 556 |
+
|
| 557 |
+
class _Chat:
|
| 558 |
+
def __init__(self, wrapper):
|
| 559 |
+
self.completions = AsyncAIChatReplacement._Completions(wrapper)
|
| 560 |
+
|
| 561 |
+
def __init__(self, wrapper, *args, **kwargs):
|
| 562 |
+
self._wrapper = wrapper
|
| 563 |
+
self.chat = AsyncAIChatReplacement._Chat(wrapper)
|
| 564 |
+
|
| 565 |
+
|
| 566 |
+
from browser_use.llm import ChatOllama, ChatOpenRouter, ChatGoogle, ChatAnthropic, ChatGroq, ChatOpenAI
|
| 567 |
+
|
| 568 |
+
class BrowserCompatibleChatWrapper(ChatOpenRouter):
|
| 569 |
"""
|
| 570 |
A wrapper for browser agent that can filter/sanitize messages
|
| 571 |
before sending them to the LLM.
|
|
|
|
| 573 |
|
| 574 |
def __init__(self, *args, **kwargs):
|
| 575 |
turn_off_logging()
|
| 576 |
+
# Create the underlying LiteLLM wrapper
|
| 577 |
+
self._wrapper = LiteLLMChatWrapper(*args, **kwargs)
|
| 578 |
# Browser-use may expect a 'model' attribute
|
| 579 |
+
self.model = self._wrapper.model_name
|
| 580 |
+
self.kwargs = self._wrapper.kwargs
|
| 581 |
|
| 582 |
+
@property
|
| 583 |
+
def model_name(self) -> str:
|
| 584 |
+
return self._wrapper.model_name
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 585 |
|
| 586 |
+
@property
|
| 587 |
+
def provider(self) -> str:
|
| 588 |
+
return self._wrapper.provider
|
| 589 |
+
|
| 590 |
+
def get_client(self, *args, **kwargs): # type: ignore
|
| 591 |
+
return AsyncAIChatReplacement(self, *args, **kwargs)
|
| 592 |
+
|
| 593 |
+
async def _acall(
|
| 594 |
self,
|
| 595 |
messages: List[BaseMessage],
|
| 596 |
stop: Optional[List[str]] = None,
|
| 597 |
+
run_manager: Optional[CallbackManagerForLLMRun] = None,
|
| 598 |
**kwargs: Any,
|
| 599 |
+
):
|
| 600 |
+
# Apply rate limiting if configured
|
| 601 |
+
apply_rate_limiter_sync(self._wrapper.a0_model_conf, str(messages))
|
|
|
|
| 602 |
|
| 603 |
+
# Call the model
|
| 604 |
+
try:
|
| 605 |
+
model = kwargs.pop("model", None)
|
| 606 |
+
kwrgs = {**self._wrapper.kwargs, **kwargs}
|
| 607 |
+
|
| 608 |
+
# hack from browser-use to fix json schema for gemini
|
| 609 |
+
if "response_format" in kwrgs and "json_schema" in kwrgs["response_format"] and model.startswith("gemini/"):
|
| 610 |
+
kwrgs["response_format"]["json_schema"] = ChatGoogle("")._fix_gemini_schema(self._wrapper.kwargs)
|
| 611 |
+
|
| 612 |
+
resp = await acompletion(
|
| 613 |
+
model=self._wrapper.model_name,
|
| 614 |
+
messages=messages,
|
| 615 |
+
stop=stop,
|
| 616 |
+
**kwrgs,
|
| 617 |
+
)
|
| 618 |
+
except Exception as e:
|
| 619 |
+
raise e
|
| 620 |
+
|
| 621 |
+
# another hack for browser-use post process invalid jsons
|
| 622 |
+
try:
|
| 623 |
+
if "response_format" in kwrgs and "json_schema" in kwrgs["response_format"] or "json_object" in kwrgs["response_format"]:
|
| 624 |
+
if resp.choices[0].message.content is not None and not resp.choices[0].message.content.startswith("{"): # type: ignore
|
| 625 |
+
js = dirty_json.parse(resp.choices[0].message.content) # type: ignore
|
| 626 |
+
resp.choices[0].message.content = dirty_json.stringify(js) # type: ignore
|
| 627 |
+
except Exception as e:
|
| 628 |
+
pass
|
| 629 |
+
|
| 630 |
+
return resp
|
| 631 |
|
| 632 |
class LiteLLMEmbeddingWrapper(Embeddings):
|
| 633 |
model_name: str
|
python/tools/browser_agent.py
CHANGED
|
@@ -148,6 +148,7 @@ class State:
|
|
| 148 |
),
|
| 149 |
controller=controller,
|
| 150 |
enable_memory=False, # Disable memory to avoid state conflicts
|
|
|
|
| 151 |
sensitive_data=cast(dict[str, str | dict[str, str]] | None, secrets_dict or {}), # Pass secrets
|
| 152 |
)
|
| 153 |
except Exception as e:
|
|
@@ -387,7 +388,7 @@ class BrowserAgent(Tool):
|
|
| 387 |
def get_use_agent_log(use_agent: browser_use.Agent | None):
|
| 388 |
result = ["🚦 Starting task"]
|
| 389 |
if use_agent:
|
| 390 |
-
action_results = use_agent.
|
| 391 |
short_log = []
|
| 392 |
for item in action_results:
|
| 393 |
# final results
|
|
|
|
| 148 |
),
|
| 149 |
controller=controller,
|
| 150 |
enable_memory=False, # Disable memory to avoid state conflicts
|
| 151 |
+
llm_timeout=3000, # TODO rem
|
| 152 |
sensitive_data=cast(dict[str, str | dict[str, str]] | None, secrets_dict or {}), # Pass secrets
|
| 153 |
)
|
| 154 |
except Exception as e:
|
|
|
|
| 388 |
def get_use_agent_log(use_agent: browser_use.Agent | None):
|
| 389 |
result = ["🚦 Starting task"]
|
| 390 |
if use_agent:
|
| 391 |
+
action_results = use_agent.history.action_results() or []
|
| 392 |
short_log = []
|
| 393 |
for item in action_results:
|
| 394 |
# final results
|
requirements.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
a2wsgi==1.10.8
|
| 2 |
ansio==0.0.1
|
| 3 |
-
browser-use==0.
|
| 4 |
docker==7.1.0
|
| 5 |
duckduckgo-search==6.1.12
|
| 6 |
faiss-cpu==1.11.0
|
|
@@ -19,7 +19,7 @@ langchain-unstructured[all-docs]==0.1.6
|
|
| 19 |
openai-whisper==20240930
|
| 20 |
lxml_html_clean==0.3.1
|
| 21 |
markdown==3.7
|
| 22 |
-
mcp==1.
|
| 23 |
newspaper3k==0.2.8
|
| 24 |
paramiko==3.5.0
|
| 25 |
playwright==1.52.0
|
|
|
|
| 1 |
a2wsgi==1.10.8
|
| 2 |
ansio==0.0.1
|
| 3 |
+
browser-use==0.5.11
|
| 4 |
docker==7.1.0
|
| 5 |
duckduckgo-search==6.1.12
|
| 6 |
faiss-cpu==1.11.0
|
|
|
|
| 19 |
openai-whisper==20240930
|
| 20 |
lxml_html_clean==0.3.1
|
| 21 |
markdown==3.7
|
| 22 |
+
mcp==1.13.1
|
| 23 |
newspaper3k==0.2.8
|
| 24 |
paramiko==3.5.0
|
| 25 |
playwright==1.52.0
|
run_ui.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
from datetime import timedelta
|
| 2 |
import os
|
| 3 |
import secrets
|
|
@@ -8,6 +9,7 @@ import struct
|
|
| 8 |
from functools import wraps
|
| 9 |
import threading
|
| 10 |
from flask import Flask, request, Response, session, redirect, url_for, render_template_string
|
|
|
|
| 11 |
import initialize
|
| 12 |
from python.helpers import files, git, mcp_server, fasta2a_server
|
| 13 |
from python.helpers.files import get_abs_path
|
|
@@ -217,7 +219,7 @@ def run():
|
|
| 217 |
name = handler.__module__.split(".")[-1]
|
| 218 |
instance = handler(app, lock)
|
| 219 |
|
| 220 |
-
async def handler_wrap():
|
| 221 |
return await instance.handle_request(request=request)
|
| 222 |
|
| 223 |
if handler.requires_loopback():
|
|
|
|
| 1 |
+
import asyncio
|
| 2 |
from datetime import timedelta
|
| 3 |
import os
|
| 4 |
import secrets
|
|
|
|
| 9 |
from functools import wraps
|
| 10 |
import threading
|
| 11 |
from flask import Flask, request, Response, session, redirect, url_for, render_template_string
|
| 12 |
+
from werkzeug.wrappers.response import Response as BaseResponse
|
| 13 |
import initialize
|
| 14 |
from python.helpers import files, git, mcp_server, fasta2a_server
|
| 15 |
from python.helpers.files import get_abs_path
|
|
|
|
| 219 |
name = handler.__module__.split(".")[-1]
|
| 220 |
instance = handler(app, lock)
|
| 221 |
|
| 222 |
+
async def handler_wrap() -> BaseResponse:
|
| 223 |
return await instance.handle_request(request=request)
|
| 224 |
|
| 225 |
if handler.requires_loopback():
|