vibesurf 0.1.6__tar.gz → 0.1.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vibesurf-0.1.6 → vibesurf-0.1.8}/PKG-INFO +8 -3
- {vibesurf-0.1.6 → vibesurf-0.1.8}/README.md +5 -1
- {vibesurf-0.1.6 → vibesurf-0.1.8}/pyproject.toml +2 -1
- {vibesurf-0.1.6 → vibesurf-0.1.8}/tests/test_agents.py +10 -12
- {vibesurf-0.1.6 → vibesurf-0.1.8}/tests/test_browser.py +5 -4
- {vibesurf-0.1.6 → vibesurf-0.1.8}/tests/test_controller.py +1 -2
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/_version.py +3 -3
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/agents/browser_use_agent.py +48 -154
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/agents/vibe_surf_agent.py +13 -12
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/shared_state.py +1 -1
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/utils/encryption.py +5 -35
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/browser/agen_browser_profile.py +3 -4
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/browser/agent_browser_session.py +115 -52
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/browser/browser_manager.py +2 -2
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/browser/utils.py +8 -15
- vibesurf-0.1.8/vibe_surf/browser/watchdogs/action_watchdog.py +105 -0
- vibesurf-0.1.8/vibe_surf/browser/watchdogs/dom_watchdog.py +282 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/scripts/session-manager.js +0 -2
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/scripts/ui-manager.js +3 -3
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/cli.py +7 -1
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/controller/mcp_client.py +0 -4
- vibesurf-0.1.6/vibe_surf/controller/vibesurf_controller.py → vibesurf-0.1.8/vibe_surf/controller/vibesurf_tools.py +13 -48
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibesurf.egg-info/PKG-INFO +8 -3
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibesurf.egg-info/SOURCES.txt +2 -2
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibesurf.egg-info/requires.txt +2 -1
- vibesurf-0.1.6/vibe_surf/browser/watchdogs/action_watchdog.py +0 -291
- vibesurf-0.1.6/vibe_surf/browser/watchdogs/dom_watchdog.py +0 -954
- {vibesurf-0.1.6 → vibesurf-0.1.8}/.env.example +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/.github/workflows/publish.yml +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/.gitignore +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/.python-version +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/LICENSE +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/MANIFEST.in +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/docs/PYPI_SETUP.md +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/setup.cfg +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/tests/test_backend_api.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/__init__.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/agents/__init__.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/agents/prompts/__init__.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/agents/prompts/vibe_surf_prompt.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/agents/report_writer_agent.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/__init__.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/api/__init__.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/api/activity.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/api/config.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/api/files.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/api/models.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/api/task.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/database/__init__.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/database/manager.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/database/models.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/database/queries.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/database/schemas.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/llm_config.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/main.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/migrations/__init__.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/migrations/init_db.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/migrations/seed_data.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/utils/__init__.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/backend/utils/llm_factory.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/browser/__init__.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/browser/watchdogs/__init__.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/background.js +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/config.js +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/content.js +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/dev-reload.js +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/icons/convert-svg.js +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/icons/logo-preview.html +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/icons/logo.png +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/manifest.json +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/popup.html +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/scripts/api-client.js +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/scripts/main.js +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/scripts/markdown-it.min.js +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/sidepanel.html +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/styles/animations.css +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/styles/components.css +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/styles/main.css +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/chrome_extension/styles/settings.css +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/controller/__init__.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/controller/file_system.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/controller/views.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/llm/__init__.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibe_surf/llm/openai_compatible.py +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibesurf.egg-info/dependency_links.txt +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibesurf.egg-info/entry_points.txt +0 -0
- {vibesurf-0.1.6 → vibesurf-0.1.8}/vibesurf.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vibesurf
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8
|
|
4
4
|
Summary: VibeSurf: A powerful browser assistant for vibe surfing
|
|
5
5
|
Author: Shao Warm
|
|
6
6
|
License: Apache-2.0
|
|
@@ -26,7 +26,7 @@ Requires-Dist: json-repair>=0.48.0
|
|
|
26
26
|
Requires-Dist: aiohttp>=3.12.15
|
|
27
27
|
Requires-Dist: scikit-image>=0.25.2
|
|
28
28
|
Requires-Dist: python-socks>=2.7.2
|
|
29
|
-
Requires-Dist: browser-use==0.
|
|
29
|
+
Requires-Dist: browser-use==0.7.1
|
|
30
30
|
Requires-Dist: langgraph>=0.6.4
|
|
31
31
|
Requires-Dist: fastapi>=0.104.0
|
|
32
32
|
Requires-Dist: uvicorn[standard]>=0.24.0
|
|
@@ -37,6 +37,7 @@ Requires-Dist: sqlalchemy>=2.0.43
|
|
|
37
37
|
Requires-Dist: aiosqlite>=0.21.0
|
|
38
38
|
Requires-Dist: rich>=13.0.0
|
|
39
39
|
Requires-Dist: greenlet>=3.2.4
|
|
40
|
+
Requires-Dist: getmac>=0.9.5
|
|
40
41
|
Dynamic: license-file
|
|
41
42
|
|
|
42
43
|
# VibeSurf: A powerful browser assistant for vibe surfing
|
|
@@ -75,7 +76,7 @@ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | ie
|
|
|
75
76
|
### Step 2: Setup and Install
|
|
76
77
|
```bash
|
|
77
78
|
uv venv --python 3.12
|
|
78
|
-
uv pip install vibesurf
|
|
79
|
+
uv pip install vibesurf -U
|
|
79
80
|
```
|
|
80
81
|
|
|
81
82
|
### Step 3: Launch
|
|
@@ -85,8 +86,12 @@ vibesurf
|
|
|
85
86
|
|
|
86
87
|
## 🎬 Demo
|
|
87
88
|
|
|
89
|
+
### How to use?
|
|
88
90
|
<video src="https://github.com/user-attachments/assets/0a4650c0-c4ed-423e-9e16-7889e9f9816d" controls="controls">Your browser does not support playing this video!</video>
|
|
89
91
|
|
|
92
|
+
### Dozens of agent running in on browser
|
|
93
|
+
<video src="https://github.com/user-attachments/assets/9c461a6e-5d97-4335-ba09-59e8ec4ad47b" controls="controls">Your browser does not support playing this video!</video>
|
|
94
|
+
|
|
90
95
|
|
|
91
96
|
## 📝 License
|
|
92
97
|
|
|
@@ -34,7 +34,7 @@ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | ie
|
|
|
34
34
|
### Step 2: Setup and Install
|
|
35
35
|
```bash
|
|
36
36
|
uv venv --python 3.12
|
|
37
|
-
uv pip install vibesurf
|
|
37
|
+
uv pip install vibesurf -U
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
### Step 3: Launch
|
|
@@ -44,8 +44,12 @@ vibesurf
|
|
|
44
44
|
|
|
45
45
|
## 🎬 Demo
|
|
46
46
|
|
|
47
|
+
### How to use?
|
|
47
48
|
<video src="https://github.com/user-attachments/assets/0a4650c0-c4ed-423e-9e16-7889e9f9816d" controls="controls">Your browser does not support playing this video!</video>
|
|
48
49
|
|
|
50
|
+
### Dozens of agent running in on browser
|
|
51
|
+
<video src="https://github.com/user-attachments/assets/9c461a6e-5d97-4335-ba09-59e8ec4ad47b" controls="controls">Your browser does not support playing this video!</video>
|
|
52
|
+
|
|
49
53
|
|
|
50
54
|
## 📝 License
|
|
51
55
|
|
|
@@ -27,7 +27,7 @@ dependencies = [
|
|
|
27
27
|
"aiohttp>=3.12.15",
|
|
28
28
|
"scikit-image>=0.25.2",
|
|
29
29
|
"python-socks>=2.7.2",
|
|
30
|
-
"browser-use==0.
|
|
30
|
+
"browser-use==0.7.1",
|
|
31
31
|
"langgraph>=0.6.4",
|
|
32
32
|
"fastapi>=0.104.0",
|
|
33
33
|
"uvicorn[standard]>=0.24.0",
|
|
@@ -38,6 +38,7 @@ dependencies = [
|
|
|
38
38
|
"aiosqlite>=0.21.0",
|
|
39
39
|
"rich>=13.0.0",
|
|
40
40
|
"greenlet>=3.2.4",
|
|
41
|
+
"getmac>=0.9.5",
|
|
41
42
|
]
|
|
42
43
|
|
|
43
44
|
[project.urls]
|
|
@@ -14,10 +14,7 @@ from vibe_surf.browser.browser_manager import BrowserManager
|
|
|
14
14
|
from vibe_surf.browser.agent_browser_session import AgentBrowserSession
|
|
15
15
|
|
|
16
16
|
from vibe_surf.browser.agent_browser_session import AgentBrowserSession
|
|
17
|
-
from
|
|
18
|
-
from browser_use.controller.service import Controller
|
|
19
|
-
from browser_use.agent.service import Agent as OrgBrowserUseAgent
|
|
20
|
-
from vibe_surf.controller.vibesurf_controller import VibeSurfController
|
|
17
|
+
from vibe_surf.controller.vibesurf_tools import VibeSurfController
|
|
21
18
|
from vibe_surf.llm.openai_compatible import ChatOpenAICompatible
|
|
22
19
|
from vibe_surf.agents.browser_use_agent import BrowserUseAgent
|
|
23
20
|
from vibe_surf.agents.vibe_surf_agent import VibeSurfAgent
|
|
@@ -89,8 +86,8 @@ async def run_multi_bu_agents():
|
|
|
89
86
|
await main_browser_session.start()
|
|
90
87
|
browser_manager = BrowserManager(main_browser_session=main_browser_session)
|
|
91
88
|
controller = VibeSurfController()
|
|
92
|
-
await controller.register_mcp_clients(mcp_server_config)
|
|
93
|
-
llm = ChatOpenAICompatible(model='gemini-2.5-
|
|
89
|
+
# await controller.register_mcp_clients(mcp_server_config)
|
|
90
|
+
llm = ChatOpenAICompatible(model='gemini-2.5-flash', base_url=os.getenv("OPENAI_ENDPOINT"),
|
|
94
91
|
api_key=os.getenv("OPENAI_API_KEY"))
|
|
95
92
|
agent_browser_sessions = await asyncio.gather(
|
|
96
93
|
browser_manager.register_agent("agent-1"),
|
|
@@ -129,7 +126,7 @@ async def run_multi_bu_agents():
|
|
|
129
126
|
await main_browser_session.kill()
|
|
130
127
|
|
|
131
128
|
|
|
132
|
-
async def
|
|
129
|
+
async def test_vibe_surf_agent():
|
|
133
130
|
"""Test VibeSurfAgent with both simple and browser tasks"""
|
|
134
131
|
import platform
|
|
135
132
|
if platform.system() != "Darwin":
|
|
@@ -143,6 +140,7 @@ async def test_swarm_surf_agent():
|
|
|
143
140
|
user_data_dir=os.path.abspath('./tmp/chrome/profiles/default'),
|
|
144
141
|
headless=False,
|
|
145
142
|
keep_alive=True,
|
|
143
|
+
highlight_elements=True,
|
|
146
144
|
window_size={"width": 1100, "height": 1280}
|
|
147
145
|
# window_size={"width": primary_monitor.width, "height": primary_monitor.height}
|
|
148
146
|
)
|
|
@@ -196,7 +194,7 @@ async def test_swarm_surf_agent():
|
|
|
196
194
|
|
|
197
195
|
# Test 4: Browser parallel task
|
|
198
196
|
print("🧪 Testing browser parallel tasks...")
|
|
199
|
-
browser_task = "Search for Dify, n8n, browser-use and
|
|
197
|
+
browser_task = "Search for Dify, n8n, browser-use and get latest news"
|
|
200
198
|
result4 = await agent.run(browser_task)
|
|
201
199
|
print(f"✅ Browser task result:")
|
|
202
200
|
pprint.pprint(result4)
|
|
@@ -214,7 +212,7 @@ async def test_swarm_surf_agent():
|
|
|
214
212
|
await main_browser_session.kill()
|
|
215
213
|
|
|
216
214
|
|
|
217
|
-
async def
|
|
215
|
+
async def test_vibe_surf_agent_control():
|
|
218
216
|
"""Test VibeSurfAgent control functionality (pause/resume/stop)"""
|
|
219
217
|
import platform
|
|
220
218
|
if platform.system() != "Darwin":
|
|
@@ -377,6 +375,6 @@ async def test_swarm_surf_agent_control():
|
|
|
377
375
|
|
|
378
376
|
if __name__ == "__main__":
|
|
379
377
|
# asyncio.run(run_single_bu_agent())
|
|
380
|
-
|
|
381
|
-
asyncio.run(
|
|
382
|
-
# asyncio.run(
|
|
378
|
+
asyncio.run(run_multi_bu_agents())
|
|
379
|
+
# asyncio.run(test_vibe_surf_agent())
|
|
380
|
+
# asyncio.run(test_vibe_surf_agent_control())
|
|
@@ -163,8 +163,8 @@ async def test_browser_state_capture(manager: BrowserManager):
|
|
|
163
163
|
task_start = time.time()
|
|
164
164
|
logging.info(f"🔍 DIAGNOSIS: {agent_name} get state started at {task_start - start_time:.3f}s")
|
|
165
165
|
# 使用新的并发导航方法绕过串行瓶颈
|
|
166
|
-
|
|
167
|
-
state = await agent.get_browser_state()
|
|
166
|
+
state = await agent.get_browser_state_summary()
|
|
167
|
+
# state = await agent.get_browser_state()
|
|
168
168
|
task_end = time.time()
|
|
169
169
|
logging.info(
|
|
170
170
|
f"🔍 DIAGNOSIS: {agent_name} get state completed at {task_end - start_time:.3f}s (duration: {task_end - task_start:.3f}s)")
|
|
@@ -215,7 +215,7 @@ async def test_browser_state_capture(manager: BrowserManager):
|
|
|
215
215
|
|
|
216
216
|
# Get new state for agent 1
|
|
217
217
|
logging.info("Capturing new state for agent 1...")
|
|
218
|
-
state1_new = await agent1.
|
|
218
|
+
state1_new = await agent1.get_browser_state_summary()
|
|
219
219
|
|
|
220
220
|
# Print new tabs and save screenshot
|
|
221
221
|
logging.info(f"Agent 1 new tabs: {state1_new.tabs}")
|
|
@@ -255,13 +255,14 @@ async def main():
|
|
|
255
255
|
from pathlib import Path
|
|
256
256
|
current_file = Path(__file__)
|
|
257
257
|
project_root = current_file.parent.parent # vibe_surf/browser -> vibe_surf -> project_root
|
|
258
|
-
chrome_extension_path = project_root / "chrome_extension"
|
|
258
|
+
chrome_extension_path = project_root / "vibe_surf" / "chrome_extension"
|
|
259
259
|
assert os.path.exists(chrome_extension_path)
|
|
260
260
|
|
|
261
261
|
browser_profile = AgentBrowserProfile(
|
|
262
262
|
executable_path=browser_exec_path,
|
|
263
263
|
user_data_dir=os.path.abspath('./tmp/chrome/profiles/default'),
|
|
264
264
|
headless=False,
|
|
265
|
+
highlight_elements=True,
|
|
265
266
|
custom_extensions=[str(chrome_extension_path.absolute())]
|
|
266
267
|
)
|
|
267
268
|
# Use SwarmBrowserSession instead of BrowserSession to disable DVD animation
|
|
@@ -12,8 +12,7 @@ load_dotenv()
|
|
|
12
12
|
|
|
13
13
|
async def test_controller_with_mcp():
|
|
14
14
|
import os
|
|
15
|
-
from vibe_surf.controller.
|
|
16
|
-
from browser_use.controller.registry.views import ActionModel
|
|
15
|
+
from vibe_surf.controller.vibesurf_tools import VibeSurfController
|
|
17
16
|
|
|
18
17
|
mcp_server_config = {
|
|
19
18
|
"mcpServers": {
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.1.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
31
|
+
__version__ = version = '0.1.8'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 8)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'gaa38d8984'
|
|
@@ -53,12 +53,12 @@ from browser_use.agent.views import (
|
|
|
53
53
|
StepMetadata,
|
|
54
54
|
)
|
|
55
55
|
from pydantic import BaseModel, ConfigDict, Field, ValidationError, create_model, model_validator
|
|
56
|
-
from browser_use
|
|
56
|
+
from browser_use import Browser, BrowserProfile, BrowserSession
|
|
57
57
|
from browser_use.browser.session import DEFAULT_BROWSER_PROFILE
|
|
58
58
|
from browser_use.browser.views import BrowserStateSummary
|
|
59
59
|
from browser_use.config import CONFIG
|
|
60
|
-
from browser_use.
|
|
61
|
-
from browser_use.
|
|
60
|
+
from browser_use.tools.registry.views import ActionModel
|
|
61
|
+
from browser_use.tools.service import Controller, Tools
|
|
62
62
|
from browser_use.dom.views import DOMInteractedElement
|
|
63
63
|
from browser_use.filesystem.file_system import FileSystem
|
|
64
64
|
from browser_use.observability import observe, observe_debug
|
|
@@ -79,45 +79,6 @@ from vibe_surf.controller.file_system import CustomFileSystem
|
|
|
79
79
|
Context = TypeVar('Context')
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
def log_response(response: AgentOutput, registry=None, logger=None) -> None:
|
|
83
|
-
"""Utility function to log the model's response."""
|
|
84
|
-
|
|
85
|
-
# Use module logger if no logger provided
|
|
86
|
-
if logger is None:
|
|
87
|
-
logger = logging.getLogger(__name__)
|
|
88
|
-
|
|
89
|
-
# Only log thinking if it's present
|
|
90
|
-
if response.current_state.thinking:
|
|
91
|
-
logger.info(f'💡 Thinking:\n{response.current_state.thinking}')
|
|
92
|
-
|
|
93
|
-
# Only log evaluation if it's not empty
|
|
94
|
-
eval_goal = response.current_state.evaluation_previous_goal
|
|
95
|
-
if eval_goal:
|
|
96
|
-
if 'success' in eval_goal.lower():
|
|
97
|
-
emoji = '👍'
|
|
98
|
-
# Green color for success
|
|
99
|
-
logger.info(f' \033[32m{emoji} Eval: {eval_goal}\033[0m')
|
|
100
|
-
elif 'failure' in eval_goal.lower():
|
|
101
|
-
emoji = '⚠️'
|
|
102
|
-
# Red color for failure
|
|
103
|
-
logger.info(f' \033[31m{emoji} Eval: {eval_goal}\033[0m')
|
|
104
|
-
else:
|
|
105
|
-
emoji = '❔'
|
|
106
|
-
# No color for unknown/neutral
|
|
107
|
-
logger.info(f' {emoji} Eval: {eval_goal}')
|
|
108
|
-
|
|
109
|
-
# Always log memory if present
|
|
110
|
-
if response.current_state.memory:
|
|
111
|
-
logger.debug(f'🧠 Memory: {response.current_state.memory}')
|
|
112
|
-
|
|
113
|
-
# Only log next goal if it's not empty
|
|
114
|
-
next_goal = response.current_state.next_goal
|
|
115
|
-
if next_goal:
|
|
116
|
-
# Blue color for next goal
|
|
117
|
-
logger.info(f' \033[34m🎯 Next goal: {next_goal}\033[0m')
|
|
118
|
-
else:
|
|
119
|
-
logger.info('') # Add empty line for spacing
|
|
120
|
-
|
|
121
82
|
|
|
122
83
|
class BrowserUseAgent(Agent):
|
|
123
84
|
@time_execution_sync('--init')
|
|
@@ -128,7 +89,9 @@ class BrowserUseAgent(Agent):
|
|
|
128
89
|
# Optional parameters
|
|
129
90
|
browser_profile: BrowserProfile | None = None,
|
|
130
91
|
browser_session: BrowserSession | None = None,
|
|
131
|
-
|
|
92
|
+
browser: Browser | None = None, # Alias for browser_session
|
|
93
|
+
tools: Tools[Context] | None = None,
|
|
94
|
+
controller: Tools[Context] | None = None, # Alias for tools
|
|
132
95
|
# Initial agent run parameters
|
|
133
96
|
sensitive_data: dict[str, str | dict[str, str]] | None = None,
|
|
134
97
|
initial_actions: list[dict[str, dict[str, Any]]] | None = None,
|
|
@@ -147,14 +110,11 @@ class BrowserUseAgent(Agent):
|
|
|
147
110
|
# Agent settings
|
|
148
111
|
output_model_schema: type[AgentStructuredOutput] | None = None,
|
|
149
112
|
use_vision: bool = True,
|
|
150
|
-
use_vision_for_planner: bool = False, # Deprecated
|
|
151
113
|
save_conversation_path: str | Path | None = None,
|
|
152
114
|
save_conversation_path_encoding: str | None = 'utf-8',
|
|
153
115
|
max_failures: int = 3,
|
|
154
|
-
retry_delay: int = 10,
|
|
155
116
|
override_system_message: str | None = None,
|
|
156
117
|
extend_system_message: str | None = None,
|
|
157
|
-
validate_output: bool = False,
|
|
158
118
|
generate_gif: bool | str = False,
|
|
159
119
|
available_file_paths: list[str] | None = None,
|
|
160
120
|
include_attributes: list[str] | None = None,
|
|
@@ -163,12 +123,7 @@ class BrowserUseAgent(Agent):
|
|
|
163
123
|
flash_mode: bool = False,
|
|
164
124
|
max_history_items: int | None = None,
|
|
165
125
|
page_extraction_llm: BaseChatModel | None = None,
|
|
166
|
-
planner_llm: BaseChatModel | None = None, # Deprecated
|
|
167
|
-
planner_interval: int = 1, # Deprecated
|
|
168
|
-
is_planner_reasoning: bool = False, # Deprecated
|
|
169
|
-
extend_planner_system_message: str | None = None, # Deprecated
|
|
170
126
|
injected_agent_state: AgentState | None = None,
|
|
171
|
-
context: Context | None = None,
|
|
172
127
|
source: str | None = None,
|
|
173
128
|
file_system_path: str | None = None,
|
|
174
129
|
task_id: str | None = None,
|
|
@@ -179,38 +134,11 @@ class BrowserUseAgent(Agent):
|
|
|
179
134
|
vision_detail_level: Literal['auto', 'low', 'high'] = 'auto',
|
|
180
135
|
llm_timeout: int = 90,
|
|
181
136
|
step_timeout: int = 120,
|
|
182
|
-
|
|
137
|
+
directly_open_url: bool = True,
|
|
183
138
|
include_recent_events: bool = False,
|
|
184
139
|
allow_parallel_action_types: list[str] = ["extract_structured_data", "extract_content_from_file"],
|
|
185
140
|
**kwargs,
|
|
186
141
|
):
|
|
187
|
-
if not isinstance(llm, BaseChatModel):
|
|
188
|
-
raise ValueError('invalid llm, must be from browser_use.llm')
|
|
189
|
-
# Check for deprecated planner parameters
|
|
190
|
-
planner_params = [
|
|
191
|
-
planner_llm,
|
|
192
|
-
use_vision_for_planner,
|
|
193
|
-
is_planner_reasoning,
|
|
194
|
-
extend_planner_system_message,
|
|
195
|
-
]
|
|
196
|
-
if any(param is not None and param is not False for param in planner_params) or planner_interval != 1:
|
|
197
|
-
self.logger.warning(
|
|
198
|
-
'⚠️ Planner functionality has been removed in browser-use v0.3.3+. '
|
|
199
|
-
'The planner_llm, use_vision_for_planner, planner_interval, is_planner_reasoning, '
|
|
200
|
-
'and extend_planner_system_message parameters are deprecated and will be ignored. '
|
|
201
|
-
'Please remove these parameters from your Agent() initialization.'
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
# Check for deprecated memory parameters
|
|
205
|
-
if kwargs.get('enable_memory', False) or kwargs.get('memory_config') is not None:
|
|
206
|
-
self.logger.warning(
|
|
207
|
-
'Memory support has been removed as of version 0.3.2. '
|
|
208
|
-
'The agent context for memory is significantly improved and no longer requires the old memory system. '
|
|
209
|
-
"Please remove the 'enable_memory' and 'memory_config' parameters."
|
|
210
|
-
)
|
|
211
|
-
kwargs['enable_memory'] = False
|
|
212
|
-
kwargs['memory_config'] = None
|
|
213
|
-
|
|
214
142
|
if page_extraction_llm is None:
|
|
215
143
|
page_extraction_llm = llm
|
|
216
144
|
if available_file_paths is None:
|
|
@@ -221,39 +149,49 @@ class BrowserUseAgent(Agent):
|
|
|
221
149
|
self.session_id: str = uuid7str()
|
|
222
150
|
self.allow_parallel_action_types = allow_parallel_action_types
|
|
223
151
|
|
|
152
|
+
browser_profile = browser_profile or DEFAULT_BROWSER_PROFILE
|
|
153
|
+
|
|
154
|
+
# Handle browser vs browser_session parameter (browser takes precedence)
|
|
155
|
+
if browser and browser_session:
|
|
156
|
+
raise ValueError(
|
|
157
|
+
'Cannot specify both "browser" and "browser_session" parameters. Use "browser" for the cleaner API.')
|
|
158
|
+
browser_session = browser or browser_session
|
|
159
|
+
|
|
160
|
+
self.browser_session = browser_session or BrowserSession(
|
|
161
|
+
browser_profile=browser_profile,
|
|
162
|
+
id=uuid7str()[:-4] + self.id[-4:], # re-use the same 4-char suffix so they show up together in logs
|
|
163
|
+
)
|
|
164
|
+
|
|
224
165
|
# Initialize available file paths as direct attribute
|
|
225
166
|
self.available_file_paths = available_file_paths
|
|
226
167
|
|
|
227
|
-
# Temporary logger for initialization (will be replaced by property)
|
|
228
|
-
self._logger = None
|
|
229
|
-
|
|
230
168
|
# Core components
|
|
231
169
|
self.task = task
|
|
232
170
|
self.llm = llm
|
|
233
|
-
self.
|
|
171
|
+
self.directly_open_url = directly_open_url
|
|
234
172
|
self.include_recent_events = include_recent_events
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
173
|
+
if tools is not None:
|
|
174
|
+
self.tools = tools
|
|
175
|
+
elif controller is not None:
|
|
176
|
+
self.tools = controller
|
|
177
|
+
else:
|
|
178
|
+
self.tools = Tools(display_files_in_done_text=display_files_in_done_text)
|
|
238
179
|
|
|
239
180
|
# Structured output
|
|
240
181
|
self.output_model_schema = output_model_schema
|
|
241
182
|
if self.output_model_schema is not None:
|
|
242
|
-
self.
|
|
183
|
+
self.tools.use_structured_output_action(self.output_model_schema)
|
|
243
184
|
|
|
244
185
|
self.sensitive_data = sensitive_data
|
|
245
186
|
|
|
246
187
|
self.settings = AgentSettings(
|
|
247
188
|
use_vision=use_vision,
|
|
248
189
|
vision_detail_level=vision_detail_level,
|
|
249
|
-
use_vision_for_planner=False, # Always False now (deprecated)
|
|
250
190
|
save_conversation_path=save_conversation_path,
|
|
251
191
|
save_conversation_path_encoding=save_conversation_path_encoding,
|
|
252
192
|
max_failures=max_failures,
|
|
253
|
-
retry_delay=retry_delay,
|
|
254
193
|
override_system_message=override_system_message,
|
|
255
194
|
extend_system_message=extend_system_message,
|
|
256
|
-
validate_output=validate_output,
|
|
257
195
|
generate_gif=generate_gif,
|
|
258
196
|
include_attributes=include_attributes,
|
|
259
197
|
max_actions_per_step=max_actions_per_step,
|
|
@@ -261,10 +199,6 @@ class BrowserUseAgent(Agent):
|
|
|
261
199
|
flash_mode=flash_mode,
|
|
262
200
|
max_history_items=max_history_items,
|
|
263
201
|
page_extraction_llm=page_extraction_llm,
|
|
264
|
-
planner_llm=None, # Always None now (deprecated)
|
|
265
|
-
planner_interval=1, # Always 1 now (deprecated)
|
|
266
|
-
is_planner_reasoning=False, # Always False now (deprecated)
|
|
267
|
-
extend_planner_system_message=None, # Always None now (deprecated)
|
|
268
202
|
calculate_cost=calculate_cost,
|
|
269
203
|
include_tool_call_examples=include_tool_call_examples,
|
|
270
204
|
llm_timeout=llm_timeout,
|
|
@@ -275,7 +209,6 @@ class BrowserUseAgent(Agent):
|
|
|
275
209
|
self.token_cost_service = TokenCost(include_cost=calculate_cost)
|
|
276
210
|
self.token_cost_service.register_llm(llm)
|
|
277
211
|
self.token_cost_service.register_llm(page_extraction_llm)
|
|
278
|
-
# Note: No longer registering planner_llm (deprecated)
|
|
279
212
|
|
|
280
213
|
# Initialize state
|
|
281
214
|
self.state = injected_agent_state or AgentState()
|
|
@@ -297,8 +230,19 @@ class BrowserUseAgent(Agent):
|
|
|
297
230
|
# Action setup
|
|
298
231
|
self._setup_action_models()
|
|
299
232
|
self._set_browser_use_version_and_source(source)
|
|
300
|
-
self.initial_actions = self._convert_initial_actions(initial_actions) if initial_actions else None
|
|
301
233
|
|
|
234
|
+
initial_url = None
|
|
235
|
+
|
|
236
|
+
# only load url if no initial actions are provided
|
|
237
|
+
if self.directly_open_url and not self.state.follow_up_task and not initial_actions:
|
|
238
|
+
initial_url = self._extract_url_from_task(self.task)
|
|
239
|
+
if initial_url:
|
|
240
|
+
self.logger.info(f'🔗 Found URL in task: {initial_url}, adding as initial action...')
|
|
241
|
+
initial_actions = [{'go_to_url': {'url': initial_url, 'new_tab': False}}]
|
|
242
|
+
|
|
243
|
+
self.initial_url = initial_url
|
|
244
|
+
|
|
245
|
+
self.initial_actions = self._convert_initial_actions(initial_actions) if initial_actions else None
|
|
302
246
|
# Verify we can connect to the model
|
|
303
247
|
self._verify_and_setup_llm()
|
|
304
248
|
|
|
@@ -308,40 +252,35 @@ class BrowserUseAgent(Agent):
|
|
|
308
252
|
self.logger.warning(
|
|
309
253
|
'⚠️ DeepSeek models do not support use_vision=True yet. Setting use_vision=False for now...')
|
|
310
254
|
self.settings.use_vision = False
|
|
311
|
-
# Note: No longer checking planner_llm for DeepSeek (deprecated)
|
|
312
255
|
|
|
313
256
|
# Handle users trying to use use_vision=True with XAI models
|
|
314
257
|
if 'grok' in self.llm.model.lower():
|
|
315
258
|
self.logger.warning('⚠️ XAI models do not support use_vision=True yet. Setting use_vision=False for now...')
|
|
316
259
|
self.settings.use_vision = False
|
|
317
|
-
# Note: No longer checking planner_llm for XAI models (deprecated)
|
|
318
260
|
|
|
319
261
|
self.logger.info(f'🧠 Starting a browser-use version {self.version} with model={self.llm.model}')
|
|
320
|
-
self.logger.
|
|
262
|
+
self.logger.info(
|
|
321
263
|
f'{" +vision" if self.settings.use_vision else ""}'
|
|
322
264
|
f' extraction_model={self.settings.page_extraction_llm.model if self.settings.page_extraction_llm else "Unknown"}'
|
|
323
|
-
# Note: No longer logging planner_model (deprecated)
|
|
324
265
|
f'{" +file_system" if self.file_system else ""}'
|
|
325
266
|
)
|
|
326
267
|
|
|
327
268
|
# Initialize available actions for system prompt (only non-filtered actions)
|
|
328
269
|
# These will be used for the system prompt to maintain caching
|
|
329
|
-
self.unfiltered_actions = self.
|
|
270
|
+
self.unfiltered_actions = self.tools.registry.get_prompt_description()
|
|
330
271
|
|
|
331
272
|
# Initialize message manager with state
|
|
332
273
|
# Initial system prompt with all actions - will be updated during each step
|
|
333
|
-
|
|
274
|
+
self._message_manager = MessageManager(
|
|
275
|
+
task=task,
|
|
276
|
+
system_message=SystemPrompt(
|
|
334
277
|
action_description=self.unfiltered_actions,
|
|
335
278
|
max_actions_per_step=self.settings.max_actions_per_step,
|
|
336
279
|
override_system_message=override_system_message,
|
|
337
280
|
extend_system_message=extend_system_message,
|
|
338
281
|
use_thinking=self.settings.use_thinking,
|
|
339
282
|
flash_mode=self.settings.flash_mode,
|
|
340
|
-
).get_system_message()
|
|
341
|
-
self.logger.debug(system_message)
|
|
342
|
-
self._message_manager = MessageManager(
|
|
343
|
-
task=task,
|
|
344
|
-
system_message=system_message,
|
|
283
|
+
).get_system_message(),
|
|
345
284
|
file_system=self.file_system,
|
|
346
285
|
state=self.state.message_manager_state,
|
|
347
286
|
use_thinking=self.settings.use_thinking,
|
|
@@ -354,13 +293,6 @@ class BrowserUseAgent(Agent):
|
|
|
354
293
|
include_recent_events=self.include_recent_events,
|
|
355
294
|
)
|
|
356
295
|
|
|
357
|
-
browser_profile = browser_profile or DEFAULT_BROWSER_PROFILE
|
|
358
|
-
|
|
359
|
-
self.browser_session = browser_session or BrowserSession(
|
|
360
|
-
browser_profile=browser_profile,
|
|
361
|
-
id=uuid7str()[:-4] + self.id[-4:], # re-use the same 4-char suffix so they show up together in logs
|
|
362
|
-
)
|
|
363
|
-
|
|
364
296
|
if self.sensitive_data:
|
|
365
297
|
# Check if sensitive_data has domain-specific credentials
|
|
366
298
|
has_domain_specific_credentials = any(isinstance(v, dict) for v in self.sensitive_data.values())
|
|
@@ -430,9 +362,6 @@ class BrowserUseAgent(Agent):
|
|
|
430
362
|
self.register_done_callback = register_done_callback
|
|
431
363
|
self.register_external_agent_status_raise_error_callback = register_external_agent_status_raise_error_callback
|
|
432
364
|
|
|
433
|
-
# Context
|
|
434
|
-
self.context: Context | None = context
|
|
435
|
-
|
|
436
365
|
# Telemetry
|
|
437
366
|
self.telemetry = ProductTelemetry()
|
|
438
367
|
|
|
@@ -586,39 +515,6 @@ class BrowserUseAgent(Agent):
|
|
|
586
515
|
|
|
587
516
|
self.logger.debug('🔧 Browser session started with watchdogs attached')
|
|
588
517
|
|
|
589
|
-
# Check if task contains a URL and add it as an initial action (only if preload is enabled)
|
|
590
|
-
if self.preload:
|
|
591
|
-
initial_url = self._extract_url_from_task(self.task)
|
|
592
|
-
if initial_url:
|
|
593
|
-
self.logger.info(f'🔗 Found URL in task: {initial_url}, adding as initial action...')
|
|
594
|
-
|
|
595
|
-
# Create a go_to_url action for the initial URL
|
|
596
|
-
go_to_url_action = {
|
|
597
|
-
'go_to_url': {
|
|
598
|
-
'url': initial_url,
|
|
599
|
-
'new_tab': False, # Navigate in current tab
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
# Add to initial_actions or create new list if none exist
|
|
604
|
-
if self.initial_actions:
|
|
605
|
-
# Convert back to dict format, prepend URL navigation, then convert back
|
|
606
|
-
initial_actions_dicts = []
|
|
607
|
-
for action in self.initial_actions:
|
|
608
|
-
action_data = action.model_dump(exclude_unset=True)
|
|
609
|
-
initial_actions_dicts.append(action_data)
|
|
610
|
-
|
|
611
|
-
# Prepend the go_to_url action
|
|
612
|
-
initial_actions_dicts = [go_to_url_action] + initial_actions_dicts
|
|
613
|
-
|
|
614
|
-
# Convert back to ActionModel instances
|
|
615
|
-
self.initial_actions = self._convert_initial_actions(initial_actions_dicts)
|
|
616
|
-
else:
|
|
617
|
-
# Create new initial_actions with just the go_to_url
|
|
618
|
-
self.initial_actions = self._convert_initial_actions([go_to_url_action])
|
|
619
|
-
|
|
620
|
-
self.logger.debug(f'✅ Added navigation to {initial_url} as initial action')
|
|
621
|
-
|
|
622
518
|
# Execute initial actions if provided
|
|
623
519
|
if self.initial_actions:
|
|
624
520
|
self.logger.debug(f'⚡ Executing {len(self.initial_actions)} initial actions...')
|
|
@@ -964,14 +860,13 @@ class BrowserUseAgent(Agent):
|
|
|
964
860
|
self.logger.info(f' 🦾 {blue}[PARALLEL ACTION {action_index + 1}/{total_actions}]{reset} {action_params}')
|
|
965
861
|
|
|
966
862
|
# Execute the action
|
|
967
|
-
result = await self.
|
|
863
|
+
result = await self.tools.act(
|
|
968
864
|
action=action,
|
|
969
865
|
browser_session=self.browser_session,
|
|
970
866
|
file_system=self.file_system,
|
|
971
867
|
page_extraction_llm=self.settings.page_extraction_llm,
|
|
972
868
|
sensitive_data=self.sensitive_data,
|
|
973
869
|
available_file_paths=self.available_file_paths,
|
|
974
|
-
context=self.context,
|
|
975
870
|
)
|
|
976
871
|
|
|
977
872
|
time_end = time.time()
|
|
@@ -1086,14 +981,13 @@ class BrowserUseAgent(Agent):
|
|
|
1086
981
|
|
|
1087
982
|
self.logger.info(f' 🦾 {blue}[ACTION {action_index + 1}/{total_actions}]{reset} {action_params}')
|
|
1088
983
|
|
|
1089
|
-
result = await self.
|
|
984
|
+
result = await self.tools.act(
|
|
1090
985
|
action=action,
|
|
1091
986
|
browser_session=self.browser_session,
|
|
1092
987
|
file_system=self.file_system,
|
|
1093
988
|
page_extraction_llm=self.settings.page_extraction_llm,
|
|
1094
989
|
sensitive_data=self.sensitive_data,
|
|
1095
990
|
available_file_paths=self.available_file_paths,
|
|
1096
|
-
context=self.context,
|
|
1097
991
|
)
|
|
1098
992
|
|
|
1099
993
|
time_end = time.time()
|