vibesurf 0.1.9a6__py3-none-any.whl → 0.1.10__py3-none-any.whl

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.
Files changed (41) hide show
  1. vibe_surf/_version.py +2 -2
  2. vibe_surf/agents/vibe_surf_agent.py +25 -15
  3. vibe_surf/backend/api/browser.py +66 -0
  4. vibe_surf/backend/api/task.py +2 -1
  5. vibe_surf/backend/main.py +76 -1
  6. vibe_surf/backend/shared_state.py +2 -0
  7. vibe_surf/browser/agent_browser_session.py +312 -62
  8. vibe_surf/browser/browser_manager.py +57 -92
  9. vibe_surf/browser/watchdogs/dom_watchdog.py +43 -43
  10. vibe_surf/chrome_extension/background.js +84 -0
  11. vibe_surf/chrome_extension/manifest.json +3 -1
  12. vibe_surf/chrome_extension/scripts/file-manager.js +526 -0
  13. vibe_surf/chrome_extension/scripts/history-manager.js +658 -0
  14. vibe_surf/chrome_extension/scripts/modal-manager.js +487 -0
  15. vibe_surf/chrome_extension/scripts/session-manager.js +31 -8
  16. vibe_surf/chrome_extension/scripts/settings-manager.js +1214 -0
  17. vibe_surf/chrome_extension/scripts/ui-manager.js +770 -3186
  18. vibe_surf/chrome_extension/sidepanel.html +27 -4
  19. vibe_surf/chrome_extension/styles/activity.css +574 -0
  20. vibe_surf/chrome_extension/styles/base.css +76 -0
  21. vibe_surf/chrome_extension/styles/history-modal.css +791 -0
  22. vibe_surf/chrome_extension/styles/input.css +429 -0
  23. vibe_surf/chrome_extension/styles/layout.css +186 -0
  24. vibe_surf/chrome_extension/styles/responsive.css +454 -0
  25. vibe_surf/chrome_extension/styles/settings-environment.css +165 -0
  26. vibe_surf/chrome_extension/styles/settings-forms.css +389 -0
  27. vibe_surf/chrome_extension/styles/settings-modal.css +141 -0
  28. vibe_surf/chrome_extension/styles/settings-profiles.css +244 -0
  29. vibe_surf/chrome_extension/styles/settings-responsive.css +144 -0
  30. vibe_surf/chrome_extension/styles/settings-utilities.css +25 -0
  31. vibe_surf/chrome_extension/styles/variables.css +54 -0
  32. vibe_surf/cli.py +1 -0
  33. vibe_surf/controller/vibesurf_tools.py +0 -2
  34. {vibesurf-0.1.9a6.dist-info → vibesurf-0.1.10.dist-info}/METADATA +18 -2
  35. {vibesurf-0.1.9a6.dist-info → vibesurf-0.1.10.dist-info}/RECORD +39 -23
  36. vibe_surf/chrome_extension/styles/main.css +0 -2338
  37. vibe_surf/chrome_extension/styles/settings.css +0 -1100
  38. {vibesurf-0.1.9a6.dist-info → vibesurf-0.1.10.dist-info}/WHEEL +0 -0
  39. {vibesurf-0.1.9a6.dist-info → vibesurf-0.1.10.dist-info}/entry_points.txt +0 -0
  40. {vibesurf-0.1.9a6.dist-info → vibesurf-0.1.10.dist-info}/licenses/LICENSE +0 -0
  41. {vibesurf-0.1.9a6.dist-info → vibesurf-0.1.10.dist-info}/top_level.txt +0 -0
vibe_surf/_version.py CHANGED
@@ -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.9a6'
32
- __version_tuple__ = version_tuple = (0, 1, 9, 'a6')
31
+ __version__ = version = '0.1.10'
32
+ __version_tuple__ = version_tuple = (0, 1, 10)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -473,7 +473,12 @@ async def _supervisor_agent_node_impl(state: VibeSurfState) -> VibeSurfState:
473
473
  browser_tabs_md = format_browser_tabs(browser_tabs)
474
474
  if browser_tabs_md:
475
475
  supervisor_message_history.append(UserMessage(
476
- content=f"Available Browser Tabs:\n{browser_tabs_md}"))
476
+ content=f"Available Browser Tabs:\n{browser_tabs_md}\n"))
477
+ active_browser_tab = await state.browser_manager.get_activate_tab()
478
+ if active_browser_tab:
479
+ active_tab_md = f"Page Title: {active_browser_tab.title}, Page Url: {active_browser_tab.url}, Page ID: {active_browser_tab.target_id}"
480
+ supervisor_message_history.append(UserMessage(
481
+ content=f"Current Active Browser Tab:\n{active_tab_md}\n"))
477
482
 
478
483
  # Reset prev_browser_results
479
484
  state.prev_browser_results = []
@@ -536,23 +541,28 @@ async def _supervisor_agent_node_impl(state: VibeSurfState) -> VibeSurfState:
536
541
  if tasks_to_execute:
537
542
  tasks_to_execute_new = []
538
543
  todo_indices = [] # Track which todo items are being executed
539
-
540
544
  for task_item in tasks_to_execute:
541
545
  if isinstance(task_item, list):
542
546
  # Format: [page_index, todo_index]
543
547
  page_index, todo_index = task_item
544
- if todo_index < len(state.todo_list):
545
- task_description = state.todo_list[todo_index].task
546
- tasks_to_execute_new.append([browser_tabs[page_index].target_id, task_description])
547
- todo_indices.append(todo_index)
548
+ if isinstance(todo_index, int):
549
+ if todo_index < len(state.todo_list):
550
+ task_description = state.todo_list[todo_index].task
551
+ tasks_to_execute_new.append([browser_tabs[page_index].target_id, task_description])
552
+ todo_indices.append(todo_index)
553
+ elif isinstance(todo_index, str):
554
+ tasks_to_execute_new.append([browser_tabs[page_index].target_id, todo_index])
548
555
  else:
549
556
  # Format: todo_index
550
557
  todo_index = task_item
551
- if todo_index < len(state.todo_list):
552
- task_description = state.todo_list[todo_index].task
553
- tasks_to_execute_new.append(task_description)
554
- todo_indices.append(todo_index)
555
-
558
+ if isinstance(todo_index, int):
559
+ if todo_index < len(state.todo_list):
560
+ task_description = state.todo_list[todo_index].task
561
+ tasks_to_execute_new.append(task_description)
562
+ todo_indices.append(todo_index)
563
+ elif isinstance(todo_index, str):
564
+ tasks_to_execute_new.append(todo_index)
565
+ logger.info(f"tasks_to_execute: {tasks_to_execute}")
556
566
  state.execution_mode = ExecutionMode(
557
567
  mode=task_type,
558
568
  reason=reasoning
@@ -795,7 +805,7 @@ async def execute_parallel_browser_tasks(state: VibeSurfState) -> List[BrowserTa
795
805
  browser_session=agent_browser_sessions[i],
796
806
  controller=state.vibesurf_controller,
797
807
  task_id=f"{state.task_id}-{i + 1}",
798
- file_system_path=state.task_dir,
808
+ file_system_path=os.path.join(state.task_dir, f"{state.task_id}-{i + 1}"),
799
809
  register_new_step_callback=step_callback,
800
810
  extend_system_message="Please make sure the language of your output in JSON value should remain the same as the user's request or task.",
801
811
  )
@@ -867,17 +877,17 @@ async def execute_single_browser_tasks(state: VibeSurfState) -> List[BrowserTask
867
877
  for i, task in enumerate(state.pending_tasks):
868
878
  if isinstance(task, list):
869
879
  target_id, task_description = task
880
+ await state.browser_manager.main_browser_session.get_or_create_cdp_session(target_id, focus=True)
870
881
  else:
871
882
  task_description = task
883
+ await state.browser_manager.get_activate_tab()
872
884
  logger.info(f"🔄 Executing task ({i + 1}/{len(state.pending_tasks)}): {task_description}")
873
885
 
874
886
  agent_id = f"agent-single-{state.task_id[-4:]}-{i}"
875
887
 
876
888
  # Log agent activity
877
889
  log_agent_activity(state, f"browser_use_agent-{state.task_id[-4:]}", "working", f"{task_description}")
878
-
879
890
  try:
880
- await state.browser_manager._get_active_target()
881
891
  if state.upload_files:
882
892
  upload_files_md = format_upload_files_list(state.upload_files)
883
893
  bu_task = task_description + f"\nAvailable user uploaded files:\n{upload_files_md}\n"
@@ -893,7 +903,7 @@ async def execute_single_browser_tasks(state: VibeSurfState) -> List[BrowserTask
893
903
  browser_session=state.browser_manager.main_browser_session,
894
904
  controller=state.vibesurf_controller,
895
905
  task_id=f"{state.task_id}-{i}",
896
- file_system_path=state.task_dir,
906
+ file_system_path=os.path.join(state.task_dir, f"{state.task_id}-{i}"),
897
907
  register_new_step_callback=step_callback,
898
908
  extend_system_message="Please make sure the language of your output in JSON values should remain the same as the user's request or task."
899
909
  )
@@ -0,0 +1,66 @@
1
+ """
2
+ Browser Tabs Router
3
+
4
+ Handles retrieval of browser tab information including active tab and all tabs.
5
+ """
6
+
7
+ from fastapi import APIRouter, HTTPException
8
+ from typing import Dict, Any, Optional
9
+ import logging
10
+
11
+ # Import global variables from shared_state
12
+ from ..shared_state import browser_manager
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ router = APIRouter(prefix="/browser", tags=["browser"])
17
+
18
+
19
+ @router.get("/active-tab")
20
+ async def get_active_tab() -> Dict[str, Dict[str, str]]:
21
+ """Get the current active tab information"""
22
+ if not browser_manager:
23
+ raise HTTPException(status_code=503, detail="Browser manager not initialized")
24
+
25
+ try:
26
+ # Get active tab info using browser manager
27
+ active_tab_info = await browser_manager.get_activate_tab()
28
+
29
+ if not active_tab_info:
30
+ return {}
31
+
32
+ # Return dict format: {tab_id: {url: , title: }}
33
+ return {
34
+ active_tab_info.target_id: {
35
+ "url": active_tab_info.url,
36
+ "title": active_tab_info.title
37
+ }
38
+ }
39
+
40
+ except Exception as e:
41
+ logger.error(f"Failed to get active tab: {e}")
42
+ raise HTTPException(status_code=500, detail=f"Failed to get active tab: {str(e)}")
43
+
44
+
45
+ @router.get("/all-tabs")
46
+ async def get_all_tabs() -> Dict[str, Dict[str, str]]:
47
+ """Get all browser tabs information"""
48
+ if not browser_manager:
49
+ raise HTTPException(status_code=503, detail="Browser manager not initialized")
50
+
51
+ try:
52
+ all_tab_infos = await browser_manager.get_all_tabs()
53
+
54
+ # Filter only page targets and build result dict
55
+ result = {}
56
+ for tab_info in all_tab_infos:
57
+ result[tab_info.target_id] = {
58
+ "url": tab_info.url,
59
+ "title": tab_info.title
60
+ }
61
+
62
+ return result
63
+
64
+ except Exception as e:
65
+ logger.error(f"Failed to get all tabs: {e}")
66
+ raise HTTPException(status_code=500, detail=f"Failed to get all tabs: {str(e)}")
@@ -21,7 +21,8 @@ from ..shared_state import (
21
21
  execute_task_background,
22
22
  is_task_running,
23
23
  get_active_task_info,
24
- clear_active_task
24
+ clear_active_task,
25
+ browser_manager
25
26
  )
26
27
 
27
28
  logger = logging.getLogger(__name__)
vibe_surf/backend/main.py CHANGED
@@ -11,6 +11,7 @@ from fastapi.middleware.cors import CORSMiddleware
11
11
  import logging
12
12
  import argparse
13
13
  import os
14
+ import asyncio
14
15
  from datetime import datetime
15
16
 
16
17
  # Import routers
@@ -18,6 +19,7 @@ from .api.task import router as agents_router
18
19
  from .api.files import router as files_router
19
20
  from .api.activity import router as activity_router
20
21
  from .api.config import router as config_router
22
+ from .api.browser import router as browser_router
21
23
 
22
24
  # Import shared state
23
25
  from . import shared_state
@@ -46,18 +48,86 @@ app.include_router(agents_router, prefix="/api", tags=["tasks"])
46
48
  app.include_router(files_router, prefix="/api", tags=["files"])
47
49
  app.include_router(activity_router, prefix="/api", tags=["activity"])
48
50
  app.include_router(config_router, prefix="/api", tags=["config"])
51
+ app.include_router(browser_router, prefix="/api", tags=["browser"])
52
+
53
+ # Global variable to control browser monitoring task
54
+ browser_monitor_task = None
55
+
56
+ async def monitor_browser_connection():
57
+ """Background task to monitor browser connection"""
58
+ while True:
59
+ try:
60
+ await asyncio.sleep(2) # Check every 1 second
61
+
62
+ if shared_state.browser_manager:
63
+ is_connected = await shared_state.browser_manager.check_browser_connected()
64
+ if not is_connected:
65
+ logger.error("No Available Browser, Exiting...")
66
+
67
+ # Schedule a graceful shutdown using os.kill in a separate thread
68
+ import threading
69
+ import signal
70
+ import os
71
+
72
+ def trigger_shutdown():
73
+ try:
74
+ # Give a brief moment for any cleanup
75
+ import time
76
+ time.sleep(0.5)
77
+ # Send SIGTERM to current process for graceful shutdown
78
+ os.kill(os.getpid(), signal.SIGTERM)
79
+ except Exception as e:
80
+ logger.error(f"Error during shutdown trigger: {e}")
81
+ # Fallback to SIGKILL if SIGTERM doesn't work
82
+ try:
83
+ os.kill(os.getpid(), signal.SIGKILL)
84
+ except:
85
+ pass
86
+
87
+ # Start shutdown in a separate thread to avoid blocking the async loop
88
+ shutdown_thread = threading.Thread(target=trigger_shutdown)
89
+ shutdown_thread.daemon = True
90
+ shutdown_thread.start()
91
+
92
+ # Exit the monitoring loop
93
+ break
94
+
95
+ except asyncio.CancelledError:
96
+ logger.info("Browser monitor task cancelled")
97
+ break
98
+ except Exception as e:
99
+ logger.warning(f"Browser monitor error: {e}")
100
+ # Continue monitoring even if there's an error
49
101
 
50
102
  @app.on_event("startup")
51
103
  async def startup_event():
52
104
  """Initialize database and VibeSurf components on startup"""
105
+ global browser_monitor_task
106
+
53
107
  # Initialize VibeSurf components and update shared state
54
108
  await shared_state.initialize_vibesurf_components()
55
109
 
110
+ # Start browser monitoring task
111
+ browser_monitor_task = asyncio.create_task(monitor_browser_connection())
112
+ logger.info("🔍 Started browser connection monitor")
113
+
56
114
  logger.info("🚀 VibeSurf Backend API started with single-task execution model")
57
115
 
58
116
  @app.on_event("shutdown")
59
117
  async def shutdown_event():
60
118
  """Cleanup on shutdown"""
119
+ global browser_monitor_task
120
+
121
+ logger.info("🛑 Starting graceful shutdown...")
122
+
123
+ # Cancel browser monitor task
124
+ if browser_monitor_task and not browser_monitor_task.done():
125
+ browser_monitor_task.cancel()
126
+ try:
127
+ await asyncio.wait_for(browser_monitor_task, timeout=2.0)
128
+ except (asyncio.CancelledError, asyncio.TimeoutError):
129
+ pass
130
+ logger.info("✅ Browser monitor task stopped")
61
131
 
62
132
  # Cleanup VibeSurf components
63
133
  if shared_state.browser_manager:
@@ -70,7 +140,12 @@ async def shutdown_event():
70
140
 
71
141
  # Close database
72
142
  if shared_state.db_manager:
73
- await shared_state.db_manager.close()
143
+ try:
144
+ await shared_state.db_manager.close()
145
+ logger.info("✅ Database manager closed")
146
+ except Exception as e:
147
+ logger.error(f"❌ Error closing database manager: {e}")
148
+
74
149
  logger.info("🛑 VibeSurf Backend API stopped")
75
150
 
76
151
  # Health check endpoint
@@ -422,6 +422,8 @@ async def initialize_vibesurf_components():
422
422
  user_data_dir=browser_user_data,
423
423
  headless=False,
424
424
  keep_alive=True,
425
+ auto_download_pdfs=False,
426
+ highlight_elements=True,
425
427
  custom_extensions=[envs["VIBESURF_EXTENSION"]],
426
428
  window_size={"width": primary_monitor.width, "height": primary_monitor.height}
427
429
  )