vibesurf 0.1.3__py3-none-any.whl → 0.1.5__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.
Potentially problematic release.
This version of vibesurf might be problematic. Click here for more details.
- vibe_surf/_version.py +2 -2
- vibe_surf/agents/report_writer_agent.py +16 -0
- vibe_surf/agents/vibe_surf_agent.py +16 -0
- vibe_surf/backend/api/config.py +18 -4
- vibe_surf/backend/api/task.py +5 -0
- vibe_surf/backend/shared_state.py +4 -3
- vibe_surf/backend/utils/llm_factory.py +23 -6
- vibe_surf/chrome_extension/scripts/ui-manager.js +118 -1
- vibe_surf/chrome_extension/styles/components.css +40 -0
- vibe_surf/cli.py +68 -3
- {vibesurf-0.1.3.dist-info → vibesurf-0.1.5.dist-info}/METADATA +5 -1
- {vibesurf-0.1.3.dist-info → vibesurf-0.1.5.dist-info}/RECORD +16 -16
- {vibesurf-0.1.3.dist-info → vibesurf-0.1.5.dist-info}/WHEEL +0 -0
- {vibesurf-0.1.3.dist-info → vibesurf-0.1.5.dist-info}/entry_points.txt +0 -0
- {vibesurf-0.1.3.dist-info → vibesurf-0.1.5.dist-info}/licenses/LICENSE +0 -0
- {vibesurf-0.1.3.dist-info → vibesurf-0.1.5.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.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
31
|
+
__version__ = version = '0.1.5'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 5)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -91,6 +91,14 @@ class ReportWriterAgent:
|
|
|
91
91
|
)
|
|
92
92
|
|
|
93
93
|
response = await self.llm.ainvoke([UserMessage(content=content_prompt)])
|
|
94
|
+
logger.debug(f"Content generation response type: {type(response)}")
|
|
95
|
+
logger.debug(f"Content generation completion: {response.completion}")
|
|
96
|
+
logger.debug(f"Content generation completion type: {type(response.completion)}")
|
|
97
|
+
|
|
98
|
+
if response.completion is None:
|
|
99
|
+
logger.error("❌ Content generation returned None completion")
|
|
100
|
+
raise ValueError("LLM response completion is None - unable to generate report content")
|
|
101
|
+
|
|
94
102
|
return response.completion
|
|
95
103
|
|
|
96
104
|
async def _format_as_html(self, content: str) -> str:
|
|
@@ -98,6 +106,14 @@ class ReportWriterAgent:
|
|
|
98
106
|
format_prompt = REPORT_FORMAT_PROMPT.format(report_content=content)
|
|
99
107
|
|
|
100
108
|
response = await self.llm.ainvoke([UserMessage(content=format_prompt)])
|
|
109
|
+
logger.debug(f"Format generation response type: {type(response)}")
|
|
110
|
+
logger.debug(f"Format generation completion: {response.completion}")
|
|
111
|
+
logger.debug(f"Format generation completion type: {type(response.completion)}")
|
|
112
|
+
|
|
113
|
+
if response.completion is None:
|
|
114
|
+
logger.error("❌ Format generation returned None completion")
|
|
115
|
+
raise ValueError("LLM response completion is None - unable to format report as HTML")
|
|
116
|
+
|
|
101
117
|
html_content = response.completion
|
|
102
118
|
|
|
103
119
|
# Clean up the HTML content if needed
|
|
@@ -1565,9 +1565,25 @@ class VibeSurfAgent:
|
|
|
1565
1565
|
|
|
1566
1566
|
except asyncio.CancelledError:
|
|
1567
1567
|
logger.info("🛑 VibeSurfAgent execution was cancelled")
|
|
1568
|
+
# Add cancellation activity log
|
|
1569
|
+
if agent_activity_logs:
|
|
1570
|
+
activity_entry = {
|
|
1571
|
+
"agent_name": "VibeSurfAgent",
|
|
1572
|
+
"agent_status": "cancelled",
|
|
1573
|
+
"agent_msg": "Task execution was cancelled by user request."
|
|
1574
|
+
}
|
|
1575
|
+
agent_activity_logs.append(activity_entry)
|
|
1568
1576
|
return f"# Task Execution Cancelled\n\n**Task:** {task}\n\nExecution was stopped by user request."
|
|
1569
1577
|
except Exception as e:
|
|
1570
1578
|
logger.error(f"❌ VibeSurfAgent execution failed: {e}")
|
|
1579
|
+
# Add error activity log
|
|
1580
|
+
if agent_activity_logs:
|
|
1581
|
+
activity_entry = {
|
|
1582
|
+
"agent_name": "VibeSurfAgent",
|
|
1583
|
+
"agent_status": "error",
|
|
1584
|
+
"agent_msg": f"Task execution failed: {str(e)}"
|
|
1585
|
+
}
|
|
1586
|
+
agent_activity_logs.append(activity_entry)
|
|
1571
1587
|
return f"# Task Execution Failed\n\n**Task:** {task}\n\n**Error:** {str(e)}\n\nPlease try again or contact support."
|
|
1572
1588
|
finally:
|
|
1573
1589
|
# Reset state
|
vibe_surf/backend/api/config.py
CHANGED
|
@@ -115,10 +115,24 @@ async def create_llm_profile(
|
|
|
115
115
|
|
|
116
116
|
except Exception as e:
|
|
117
117
|
logger.error(f"Failed to create LLM profile: {e}")
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
|
|
119
|
+
# Handle specific database constraint errors
|
|
120
|
+
error_msg = str(e)
|
|
121
|
+
if "UNIQUE constraint failed: llm_profiles.profile_name" in error_msg:
|
|
122
|
+
raise HTTPException(
|
|
123
|
+
status_code=400,
|
|
124
|
+
detail=f"Profile with name '{profile_request.profile_name}' already exists. Please choose a different name."
|
|
125
|
+
)
|
|
126
|
+
elif "IntegrityError" in error_msg and "profile_name" in error_msg:
|
|
127
|
+
raise HTTPException(
|
|
128
|
+
status_code=400,
|
|
129
|
+
detail=f"Profile name '{profile_request.profile_name}' is already in use. Please choose a different name."
|
|
130
|
+
)
|
|
131
|
+
else:
|
|
132
|
+
raise HTTPException(
|
|
133
|
+
status_code=500,
|
|
134
|
+
detail=f"Failed to create LLM profile: {str(e)}"
|
|
135
|
+
)
|
|
122
136
|
|
|
123
137
|
@router.get("/llm-profiles", response_model=List[LLMProfileResponse])
|
|
124
138
|
async def list_llm_profiles(
|
vibe_surf/backend/api/task.py
CHANGED
|
@@ -80,6 +80,11 @@ async def submit_task(
|
|
|
80
80
|
if not mcp_server_config and controller and hasattr(controller, 'mcp_server_config'):
|
|
81
81
|
mcp_server_config = controller.mcp_server_config
|
|
82
82
|
|
|
83
|
+
# Ensure we have a valid MCP server config (never None)
|
|
84
|
+
if mcp_server_config is None:
|
|
85
|
+
mcp_server_config = {"mcpServers": {}}
|
|
86
|
+
logger.info("Using default empty MCP server configuration")
|
|
87
|
+
|
|
83
88
|
# DEBUG: Log the type and content of mcp_server_config
|
|
84
89
|
logger.info(f"mcp_server_config type: {type(mcp_server_config)}, value: {mcp_server_config}")
|
|
85
90
|
|
|
@@ -277,7 +277,8 @@ async def _load_active_mcp_servers():
|
|
|
277
277
|
|
|
278
278
|
try:
|
|
279
279
|
if not db_manager:
|
|
280
|
-
|
|
280
|
+
logger.info("Database manager not available, returning empty MCP config")
|
|
281
|
+
return {"mcpServers": {}}
|
|
281
282
|
|
|
282
283
|
from .database.queries import McpProfileQueries
|
|
283
284
|
|
|
@@ -298,13 +299,13 @@ async def _load_active_mcp_servers():
|
|
|
298
299
|
|
|
299
300
|
except Exception as e:
|
|
300
301
|
logger.warning(f"Failed to load MCP servers from database: {e}")
|
|
301
|
-
return {}
|
|
302
|
+
return {"mcpServers": {}}
|
|
302
303
|
finally:
|
|
303
304
|
break
|
|
304
305
|
|
|
305
306
|
except Exception as e:
|
|
306
307
|
logger.warning(f"Database not available for MCP server loading: {e}")
|
|
307
|
-
return {}
|
|
308
|
+
return {"mcpServers": {}}
|
|
308
309
|
|
|
309
310
|
|
|
310
311
|
async def initialize_vibesurf_components():
|
|
@@ -41,17 +41,34 @@ def create_llm_from_profile(llm_profile):
|
|
|
41
41
|
if not is_provider_supported(provider):
|
|
42
42
|
raise ValueError(f"Unsupported provider: {provider}. Supported: {get_supported_providers()}")
|
|
43
43
|
|
|
44
|
-
#
|
|
44
|
+
# Define provider-specific parameter support
|
|
45
|
+
provider_param_support = {
|
|
46
|
+
"openai": ["temperature", "top_p", "frequency_penalty", "seed"],
|
|
47
|
+
"anthropic": ["temperature", "top_p"],
|
|
48
|
+
"google": ["temperature", "top_p"],
|
|
49
|
+
"azure_openai": ["temperature", "top_p", "frequency_penalty", "seed"],
|
|
50
|
+
"groq": ["temperature", "top_p"],
|
|
51
|
+
"ollama": ["temperature"],
|
|
52
|
+
"openrouter": ["temperature", "top_p"], # OpenRouter doesn't support max_tokens
|
|
53
|
+
"deepseek": ["temperature", "top_p"],
|
|
54
|
+
"aws_bedrock": ["temperature"],
|
|
55
|
+
"anthropic_bedrock": ["temperature"],
|
|
56
|
+
"openai_compatible": ["temperature", "top_p", "frequency_penalty", "seed"]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Build common parameters based on provider support
|
|
60
|
+
supported_params = provider_param_support.get(provider, ["temperature", "top_p", "frequency_penalty", "seed"])
|
|
45
61
|
common_params = {}
|
|
46
|
-
|
|
62
|
+
|
|
63
|
+
if temperature is not None and "temperature" in supported_params:
|
|
47
64
|
common_params["temperature"] = temperature
|
|
48
|
-
if max_tokens is not None:
|
|
65
|
+
if max_tokens is not None and "max_tokens" in supported_params:
|
|
49
66
|
common_params["max_tokens"] = max_tokens
|
|
50
|
-
if top_p is not None:
|
|
67
|
+
if top_p is not None and "top_p" in supported_params:
|
|
51
68
|
common_params["top_p"] = top_p
|
|
52
|
-
if frequency_penalty is not None:
|
|
69
|
+
if frequency_penalty is not None and "frequency_penalty" in supported_params:
|
|
53
70
|
common_params["frequency_penalty"] = frequency_penalty
|
|
54
|
-
if seed is not None:
|
|
71
|
+
if seed is not None and "seed" in supported_params:
|
|
55
72
|
common_params["seed"] = seed
|
|
56
73
|
|
|
57
74
|
# Add provider-specific config if available
|
|
@@ -1609,6 +1609,13 @@ class VibeSurfUIManager {
|
|
|
1609
1609
|
console.log('[UIManager] Profile form submit triggered');
|
|
1610
1610
|
|
|
1611
1611
|
const form = event.target;
|
|
1612
|
+
|
|
1613
|
+
// Prevent multiple submissions
|
|
1614
|
+
if (form.dataset.submitting === 'true') {
|
|
1615
|
+
console.log('[UIManager] Form already submitting, ignoring duplicate submission');
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1612
1619
|
const formData = new FormData(form);
|
|
1613
1620
|
const type = form.dataset.type;
|
|
1614
1621
|
const mode = form.dataset.mode;
|
|
@@ -1616,6 +1623,10 @@ class VibeSurfUIManager {
|
|
|
1616
1623
|
|
|
1617
1624
|
console.log('[UIManager] Form submission details:', { type, mode, profileId });
|
|
1618
1625
|
|
|
1626
|
+
// Set submitting state and disable form
|
|
1627
|
+
form.dataset.submitting = 'true';
|
|
1628
|
+
this.setProfileFormSubmitting(true);
|
|
1629
|
+
|
|
1619
1630
|
// Convert FormData to object
|
|
1620
1631
|
const data = {};
|
|
1621
1632
|
|
|
@@ -1746,7 +1757,113 @@ class VibeSurfUIManager {
|
|
|
1746
1757
|
|
|
1747
1758
|
} catch (error) {
|
|
1748
1759
|
console.error(`[UIManager] Failed to ${mode} ${type} profile:`, error);
|
|
1749
|
-
|
|
1760
|
+
|
|
1761
|
+
// Handle specific error types for better user experience
|
|
1762
|
+
let errorMessage = error.message || 'Unknown error occurred';
|
|
1763
|
+
|
|
1764
|
+
if (errorMessage.includes('already exists') || errorMessage.includes('already in use')) {
|
|
1765
|
+
// For duplicate profile name errors, highlight the name field
|
|
1766
|
+
this.highlightProfileNameError(errorMessage);
|
|
1767
|
+
errorMessage = errorMessage; // Use the specific error message from backend
|
|
1768
|
+
} else if (errorMessage.includes('UNIQUE constraint')) {
|
|
1769
|
+
errorMessage = `Profile name '${data.profile_name || data.display_name}' already exists. Please choose a different name.`;
|
|
1770
|
+
this.highlightProfileNameError(errorMessage);
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
this.showNotification(`Failed to ${mode} ${type} profile: ${errorMessage}`, 'error');
|
|
1774
|
+
} finally {
|
|
1775
|
+
// Reset form state
|
|
1776
|
+
form.dataset.submitting = 'false';
|
|
1777
|
+
this.setProfileFormSubmitting(false);
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
setProfileFormSubmitting(isSubmitting) {
|
|
1782
|
+
const form = this.elements.profileForm;
|
|
1783
|
+
const submitButton = this.elements.profileFormSubmit;
|
|
1784
|
+
const cancelButton = this.elements.profileFormCancel;
|
|
1785
|
+
|
|
1786
|
+
if (!form) return;
|
|
1787
|
+
|
|
1788
|
+
// Disable/enable form inputs
|
|
1789
|
+
const inputs = form.querySelectorAll('input, select, textarea');
|
|
1790
|
+
inputs.forEach(input => {
|
|
1791
|
+
input.disabled = isSubmitting;
|
|
1792
|
+
});
|
|
1793
|
+
|
|
1794
|
+
// Update submit button
|
|
1795
|
+
if (submitButton) {
|
|
1796
|
+
submitButton.disabled = isSubmitting;
|
|
1797
|
+
submitButton.textContent = isSubmitting ? 'Saving...' : 'Save Profile';
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
// Update cancel button
|
|
1801
|
+
if (cancelButton) {
|
|
1802
|
+
cancelButton.disabled = isSubmitting;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
console.log(`[UIManager] Profile form submitting state: ${isSubmitting}`);
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
highlightProfileNameError(errorMessage) {
|
|
1809
|
+
const nameInput = this.elements.profileForm?.querySelector('input[name="profile_name"], input[name="display_name"]');
|
|
1810
|
+
|
|
1811
|
+
if (nameInput) {
|
|
1812
|
+
// Add error styling
|
|
1813
|
+
nameInput.classList.add('form-error');
|
|
1814
|
+
nameInput.focus();
|
|
1815
|
+
|
|
1816
|
+
// Create or update error message
|
|
1817
|
+
let errorElement = nameInput.parentElement.querySelector('.profile-name-error');
|
|
1818
|
+
if (!errorElement) {
|
|
1819
|
+
errorElement = document.createElement('div');
|
|
1820
|
+
errorElement.className = 'form-error-message profile-name-error';
|
|
1821
|
+
nameInput.parentElement.appendChild(errorElement);
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
errorElement.textContent = errorMessage;
|
|
1825
|
+
|
|
1826
|
+
// Remove error styling after user starts typing
|
|
1827
|
+
const removeError = () => {
|
|
1828
|
+
nameInput.classList.remove('form-error');
|
|
1829
|
+
if (errorElement) {
|
|
1830
|
+
errorElement.remove();
|
|
1831
|
+
}
|
|
1832
|
+
nameInput.removeEventListener('input', removeError);
|
|
1833
|
+
};
|
|
1834
|
+
|
|
1835
|
+
nameInput.addEventListener('input', removeError);
|
|
1836
|
+
|
|
1837
|
+
console.log('[UIManager] Highlighted profile name error:', errorMessage);
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
// Real-time profile name validation
|
|
1842
|
+
async validateProfileNameAvailability(profileName, profileType) {
|
|
1843
|
+
if (!profileName || profileName.trim().length < 2) {
|
|
1844
|
+
return { isValid: true, message: '' }; // Don't validate very short names
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
try {
|
|
1848
|
+
// Check if profile already exists
|
|
1849
|
+
const profiles = profileType === 'llm' ? this.state.llmProfiles : this.state.mcpProfiles;
|
|
1850
|
+
const nameField = profileType === 'llm' ? 'profile_name' : 'display_name';
|
|
1851
|
+
|
|
1852
|
+
const existingProfile = profiles.find(profile =>
|
|
1853
|
+
profile[nameField].toLowerCase() === profileName.toLowerCase()
|
|
1854
|
+
);
|
|
1855
|
+
|
|
1856
|
+
if (existingProfile) {
|
|
1857
|
+
return {
|
|
1858
|
+
isValid: false,
|
|
1859
|
+
message: `${profileType.toUpperCase()} profile "${profileName}" already exists. Please choose a different name.`
|
|
1860
|
+
};
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
return { isValid: true, message: '' };
|
|
1864
|
+
} catch (error) {
|
|
1865
|
+
console.error('[UIManager] Error validating profile name:', error);
|
|
1866
|
+
return { isValid: true, message: '' }; // Don't block on validation errors
|
|
1750
1867
|
}
|
|
1751
1868
|
}
|
|
1752
1869
|
|
|
@@ -366,6 +366,46 @@
|
|
|
366
366
|
padding-right: 32px;
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
+
/* Form input error state */
|
|
370
|
+
.form-input.form-error {
|
|
371
|
+
border-color: var(--danger-color) !important;
|
|
372
|
+
box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.1) !important;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.form-input.form-error:focus {
|
|
376
|
+
border-color: var(--danger-color) !important;
|
|
377
|
+
box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.2) !important;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/* Form error message */
|
|
381
|
+
.form-error-message {
|
|
382
|
+
font-size: var(--font-size-xs);
|
|
383
|
+
color: var(--danger-color);
|
|
384
|
+
margin-top: var(--spacing-xs);
|
|
385
|
+
display: block;
|
|
386
|
+
font-weight: var(--font-weight-medium);
|
|
387
|
+
animation: slideDown 0.2s ease-out;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.profile-name-error {
|
|
391
|
+
background-color: rgba(220, 53, 69, 0.05);
|
|
392
|
+
padding: var(--spacing-xs) var(--spacing-sm);
|
|
393
|
+
border-radius: var(--radius-sm);
|
|
394
|
+
border: 1px solid rgba(220, 53, 69, 0.2);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
@keyframes slideDown {
|
|
398
|
+
from {
|
|
399
|
+
opacity: 0;
|
|
400
|
+
transform: translateY(-10px);
|
|
401
|
+
}
|
|
402
|
+
to {
|
|
403
|
+
opacity: 1;
|
|
404
|
+
transform: translateY(0);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/* Legacy form error class for backwards compatibility */
|
|
369
409
|
.form-error {
|
|
370
410
|
font-size: var(--font-size-xs);
|
|
371
411
|
color: var(--danger-color);
|
vibe_surf/cli.py
CHANGED
|
@@ -7,6 +7,7 @@ A command-line interface for VibeSurf browser automation tool.
|
|
|
7
7
|
import os
|
|
8
8
|
import sys
|
|
9
9
|
import glob
|
|
10
|
+
import json
|
|
10
11
|
import socket
|
|
11
12
|
import platform
|
|
12
13
|
import importlib.util
|
|
@@ -35,6 +36,17 @@ VIBESURF_LOGO = """
|
|
|
35
36
|
|
|
36
37
|
console = Console()
|
|
37
38
|
|
|
39
|
+
# Add logger import for the workspace directory logging
|
|
40
|
+
try:
|
|
41
|
+
import logging
|
|
42
|
+
logger = logging.getLogger(__name__)
|
|
43
|
+
logging.basicConfig(level=logging.INFO)
|
|
44
|
+
except ImportError:
|
|
45
|
+
class SimpleLogger:
|
|
46
|
+
def info(self, msg):
|
|
47
|
+
console.print(f"[dim]{msg}[/dim]")
|
|
48
|
+
logger = SimpleLogger()
|
|
49
|
+
|
|
38
50
|
|
|
39
51
|
def find_chrome_browser() -> Optional[str]:
|
|
40
52
|
"""Find Chrome browser executable."""
|
|
@@ -322,6 +334,55 @@ def start_backend(port: int) -> None:
|
|
|
322
334
|
sys.exit(1)
|
|
323
335
|
|
|
324
336
|
|
|
337
|
+
def get_browser_execution_path() -> Optional[str]:
|
|
338
|
+
"""Get browser execution path from envs.json or environment variables."""
|
|
339
|
+
# 1. Load environment variables
|
|
340
|
+
env_workspace_dir = os.getenv("VIBESURF_WORKSPACE", "")
|
|
341
|
+
if not env_workspace_dir or not env_workspace_dir.strip():
|
|
342
|
+
# Set default workspace directory based on OS
|
|
343
|
+
if platform.system() == "Windows":
|
|
344
|
+
default_workspace = os.path.join(os.environ.get("APPDATA", ""), "VibeSurf")
|
|
345
|
+
elif platform.system() == "Darwin": # macOS
|
|
346
|
+
default_workspace = os.path.join(os.path.expanduser("~"), "Library", "Application Support", "VibeSurf")
|
|
347
|
+
else: # Linux and others
|
|
348
|
+
default_workspace = os.path.join(os.path.expanduser("~"), ".vibesurf")
|
|
349
|
+
workspace_dir = default_workspace
|
|
350
|
+
else:
|
|
351
|
+
workspace_dir = env_workspace_dir
|
|
352
|
+
workspace_dir = os.path.abspath(workspace_dir)
|
|
353
|
+
os.makedirs(workspace_dir, exist_ok=True)
|
|
354
|
+
logger.info("WorkSpace directory: {}".format(workspace_dir))
|
|
355
|
+
|
|
356
|
+
# Load environment configuration from envs.json
|
|
357
|
+
envs_file_path = os.path.join(workspace_dir, "envs.json")
|
|
358
|
+
browser_path_from_envs = None
|
|
359
|
+
try:
|
|
360
|
+
if os.path.exists(envs_file_path):
|
|
361
|
+
with open(envs_file_path, 'r', encoding='utf-8') as f:
|
|
362
|
+
envs = json.load(f)
|
|
363
|
+
browser_path_from_envs = envs.get("BROWSER_EXECUTION_PATH", "")
|
|
364
|
+
if browser_path_from_envs:
|
|
365
|
+
browser_path_from_envs = browser_path_from_envs.strip()
|
|
366
|
+
except (json.JSONDecodeError, IOError) as e:
|
|
367
|
+
logger.info(f"Failed to load envs.json: {e}")
|
|
368
|
+
browser_path_from_envs = None
|
|
369
|
+
|
|
370
|
+
# 2. Get BROWSER_EXECUTION_PATH from environment variables
|
|
371
|
+
browser_path_from_env = os.getenv("BROWSER_EXECUTION_PATH", "")
|
|
372
|
+
if browser_path_from_env:
|
|
373
|
+
browser_path_from_env = browser_path_from_env.strip()
|
|
374
|
+
|
|
375
|
+
# Check paths in priority order: 1. envs.json -> 2. environment variables
|
|
376
|
+
for source, path in [("envs.json", browser_path_from_envs), ("environment variable", browser_path_from_env)]:
|
|
377
|
+
if path and os.path.exists(path) and os.path.isfile(path):
|
|
378
|
+
console.print(f"[green]✅ Using browser path from {source}: {path}[/green]")
|
|
379
|
+
return path
|
|
380
|
+
elif path:
|
|
381
|
+
console.print(f"[yellow]⚠️ Browser path from {source} exists but file not found: {path}[/yellow]")
|
|
382
|
+
|
|
383
|
+
return None
|
|
384
|
+
|
|
385
|
+
|
|
325
386
|
def main():
|
|
326
387
|
"""Main CLI entry point."""
|
|
327
388
|
try:
|
|
@@ -329,10 +390,14 @@ def main():
|
|
|
329
390
|
console.print(Panel(VIBESURF_LOGO, title="[bold cyan]VibeSurf CLI[/bold cyan]", border_style="cyan"))
|
|
330
391
|
console.print("[dim]A powerful browser automation tool for vibe surfing 🏄♂️[/dim]\n")
|
|
331
392
|
|
|
332
|
-
#
|
|
333
|
-
browser_path =
|
|
393
|
+
# Check for existing browser path from configuration
|
|
394
|
+
browser_path = get_browser_execution_path()
|
|
395
|
+
|
|
396
|
+
# If no valid browser path found, ask user to select
|
|
334
397
|
if not browser_path:
|
|
335
|
-
|
|
398
|
+
browser_path = select_browser()
|
|
399
|
+
if not browser_path:
|
|
400
|
+
return
|
|
336
401
|
|
|
337
402
|
# Port configuration
|
|
338
403
|
port = configure_port()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vibesurf
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: VibeSurf: A powerful browser assistant for vibe surfing
|
|
5
5
|
Author: Shao Warm
|
|
6
6
|
License: Apache-2.0
|
|
@@ -40,9 +40,13 @@ Requires-Dist: greenlet>=3.2.4
|
|
|
40
40
|
Dynamic: license-file
|
|
41
41
|
|
|
42
42
|
# VibeSurf: A powerful browser assistant for vibe surfing
|
|
43
|
+
[](https://discord.gg/TXNnP9gJ)
|
|
44
|
+
[](https://x.com/warmshao)
|
|
43
45
|
|
|
44
46
|
VibeSurf is an open-source AI agentic browser that revolutionizes browser automation and research.
|
|
45
47
|
|
|
48
|
+
If you're as excited about open-source AI browsing as I am, give it a star! ⭐
|
|
49
|
+
|
|
46
50
|
## ✨ Key Features
|
|
47
51
|
|
|
48
52
|
- 🧠 **Advanced AI Automation**: Beyond browser automation, VibeSurf performs deep research, intelligent crawling, content summarization, and more to exploration.
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
vibe_surf/__init__.py,sha256=WtduuMFGauMD_9dpk4fnRnLTAP6ka9Lfu0feAFNzLfo,339
|
|
2
|
-
vibe_surf/_version.py,sha256=
|
|
3
|
-
vibe_surf/cli.py,sha256=
|
|
2
|
+
vibe_surf/_version.py,sha256=rdxBMYpwzYxiWk08QbPLHSAxHoDfeKWwyaJIAM0lSic,704
|
|
3
|
+
vibe_surf/cli.py,sha256=2VqPZMqgFMsB9siE-16adeeCaO6RUSc2KzoIH3ZiAjQ,16912
|
|
4
4
|
vibe_surf/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
vibe_surf/agents/browser_use_agent.py,sha256=NSSdZ9lnjtv_RyfR5Ay2rMnzJRJ-67S8Q3ytGAguiB0,50266
|
|
6
|
-
vibe_surf/agents/report_writer_agent.py,sha256=
|
|
7
|
-
vibe_surf/agents/vibe_surf_agent.py,sha256=
|
|
6
|
+
vibe_surf/agents/report_writer_agent.py,sha256=E5mSirewzH4Oyv385-Nn2Mf1Ug3OCVBz99PoTbvKRfQ,13860
|
|
7
|
+
vibe_surf/agents/vibe_surf_agent.py,sha256=EiWa58QPfE8w9RnoT8ibYKQAecl9RbEbiaARFyPPBoo,70616
|
|
8
8
|
vibe_surf/agents/prompts/__init__.py,sha256=l4ieA0D8kLJthyNN85FKLNe4ExBa3stY3l-aImLDRD0,36
|
|
9
9
|
vibe_surf/agents/prompts/vibe_surf_prompt.py,sha256=u-6KgLSnBbQohS5kiLZDcZ3aoT90ScVONXi9gNvdMoo,11006
|
|
10
10
|
vibe_surf/backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
vibe_surf/backend/llm_config.py,sha256=9V8Gg065TQALbOKQnOqFWd8RzOJjegOD8w6YOf90Q7Y,5036
|
|
12
12
|
vibe_surf/backend/main.py,sha256=Y1xZJNBjOhgOjNegmetZj9AGUIn2ft10FSCCvMl4XRo,4047
|
|
13
|
-
vibe_surf/backend/shared_state.py,sha256=
|
|
13
|
+
vibe_surf/backend/shared_state.py,sha256=AJ_GU5krYBimWM0n0KTzJeNvm-jE4cqvLkwl91hjOKg,23140
|
|
14
14
|
vibe_surf/backend/api/__init__.py,sha256=XxF1jUOORpLYCfFuPrrnUGRnOrr6ClH0_MNPU-4RnSs,68
|
|
15
15
|
vibe_surf/backend/api/activity.py,sha256=NRSTsN3JnE63kDFhfgH3rmC9qxAeIaMKUqbXrOuZlSQ,9364
|
|
16
|
-
vibe_surf/backend/api/config.py,sha256=
|
|
16
|
+
vibe_surf/backend/api/config.py,sha256=9yTip3L0dBCy8jP6MqbpX_hk1Zk8KYrR-W18R0i7wjI,27091
|
|
17
17
|
vibe_surf/backend/api/files.py,sha256=cJ2XYm9ERI-yHL1smldPEe8WJ3vfKxMvcfyXSmqEdcc,12056
|
|
18
18
|
vibe_surf/backend/api/models.py,sha256=HVWiwGo3375LuQRPmRU93Mm6POq2ZpvQ8kKXq31zOj8,10357
|
|
19
|
-
vibe_surf/backend/api/task.py,sha256=
|
|
19
|
+
vibe_surf/backend/api/task.py,sha256=htVJwTBXX5Fwsy4P0lT-OSiN41xOKUf105SvK1qwyeI,11063
|
|
20
20
|
vibe_surf/backend/database/__init__.py,sha256=XhmcscnhgMhUyXML7m4SnuQIqkFpyY_zJ0D3yYa2RqQ,239
|
|
21
21
|
vibe_surf/backend/database/manager.py,sha256=Hbelc7CfcZlGm7i99_IKg8FO7ZLMc6_dBDVxru-GMPc,4466
|
|
22
22
|
vibe_surf/backend/database/models.py,sha256=mePuHsaSqJKA4TthvXbup_Ioann2_chxywiLKqAWyh4,7009
|
|
@@ -27,7 +27,7 @@ vibe_surf/backend/migrations/init_db.py,sha256=pY2Yq7K1vPxqT8r3jlAQcYEQWK-GGbb0F
|
|
|
27
27
|
vibe_surf/backend/migrations/seed_data.py,sha256=L6Ll-u8P4cICAUlD5y9urQPSUld6M67erSBCEIdw8Uc,8239
|
|
28
28
|
vibe_surf/backend/utils/__init__.py,sha256=V8leMFp7apAglUAoCHPZrNNcRHthSLYIudIJE5qwjb0,184
|
|
29
29
|
vibe_surf/backend/utils/encryption.py,sha256=ppDRRsNX8pu9Or9yADcLS8KJUTm-edrSb-nZqVThNI0,4802
|
|
30
|
-
vibe_surf/backend/utils/llm_factory.py,sha256=
|
|
30
|
+
vibe_surf/backend/utils/llm_factory.py,sha256=qxEQWSvio17d3mMWlrIB1x-RjWv7gLE08N5cSLjA-PY,9395
|
|
31
31
|
vibe_surf/browser/__init__.py,sha256=_UToO2fZfSCrfjOcxhn4Qq7ZLbYeyPuUUEmqIva-Yv8,325
|
|
32
32
|
vibe_surf/browser/agen_browser_profile.py,sha256=TPH2H7Og4OxDUnjNn1nNeIJ621H4Gws5c8jkFbvZoz0,5644
|
|
33
33
|
vibe_surf/browser/agent_browser_session.py,sha256=-o24Y0BfjPBURuQDfKlCTpOHntjx8QxqxeKxgBxs0WY,19551
|
|
@@ -50,9 +50,9 @@ vibe_surf/chrome_extension/scripts/api-client.js,sha256=XwKmH4lP5eAkBqAM8EcQezI0
|
|
|
50
50
|
vibe_surf/chrome_extension/scripts/main.js,sha256=WhmCGktQoSl7aaMl8a9ysJJiysAjf12bWGypMucCSVg,16913
|
|
51
51
|
vibe_surf/chrome_extension/scripts/markdown-it.min.js,sha256=gZ3xe0BdCJplNiHWTKrm6AGZydPy34jJKZqFIf-7hIw,102948
|
|
52
52
|
vibe_surf/chrome_extension/scripts/session-manager.js,sha256=MZHOgj4aucNP8c51xXKjXATxlyh1ODEky9BXIYuphvA,18070
|
|
53
|
-
vibe_surf/chrome_extension/scripts/ui-manager.js,sha256=
|
|
53
|
+
vibe_surf/chrome_extension/scripts/ui-manager.js,sha256=kq9PpyZWhDSdnzlhUryNrW4QTHoNYgm39KExTdGhU5k,141125
|
|
54
54
|
vibe_surf/chrome_extension/styles/animations.css,sha256=TLAet_xXBxCA-H36BWP4xBGBIVjbDdAj7Q6OPxPsbE8,7891
|
|
55
|
-
vibe_surf/chrome_extension/styles/components.css,sha256=
|
|
55
|
+
vibe_surf/chrome_extension/styles/components.css,sha256=7K6khbJcONVAArfeS4qmPBUJxvGGs20-eEw62bD_7VI,14741
|
|
56
56
|
vibe_surf/chrome_extension/styles/main.css,sha256=4KLqHoX8CV3sUuK_GGouiB8CN3p07iukcSbZkCMFKR8,47267
|
|
57
57
|
vibe_surf/chrome_extension/styles/settings.css,sha256=oKyLUiRsxW92f9VNkYwGkn7TNaXvjG0NPY2sxtYz5vo,20464
|
|
58
58
|
vibe_surf/controller/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -62,9 +62,9 @@ vibe_surf/controller/vibesurf_controller.py,sha256=UWz8SvOAHr9KG8tn4nTciZvt3JkxY
|
|
|
62
62
|
vibe_surf/controller/views.py,sha256=BaPlvcHTy5h-Lfr0OSgR_t6ynitgzNQF4-VUJJt8Hi0,1072
|
|
63
63
|
vibe_surf/llm/__init__.py,sha256=_vDVPo6STf343p1SgMQrF5023hicAx0g83pK2Gbk4Ek,601
|
|
64
64
|
vibe_surf/llm/openai_compatible.py,sha256=oY32VZF4oDS6ZG0h1WGtqAlWzdlximlJVTw8e8p5Zrg,10175
|
|
65
|
-
vibesurf-0.1.
|
|
66
|
-
vibesurf-0.1.
|
|
67
|
-
vibesurf-0.1.
|
|
68
|
-
vibesurf-0.1.
|
|
69
|
-
vibesurf-0.1.
|
|
70
|
-
vibesurf-0.1.
|
|
65
|
+
vibesurf-0.1.5.dist-info/licenses/LICENSE,sha256=czn6QYya0-jhLnStD9JqnMS-hwP5wRByipkrGTvoXLI,11355
|
|
66
|
+
vibesurf-0.1.5.dist-info/METADATA,sha256=II0EPpYw63rX35ubQwFdn5yz9CfTqoXxr3KsoCC6K70,3851
|
|
67
|
+
vibesurf-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
68
|
+
vibesurf-0.1.5.dist-info/entry_points.txt,sha256=UxqpvMocL-PR33S6vLF2OmXn-kVzM-DneMeZeHcPMM8,48
|
|
69
|
+
vibesurf-0.1.5.dist-info/top_level.txt,sha256=VPZGHqSb6EEqcJ4ZX6bHIuWfon5f6HXl3c7BYpbRqnY,10
|
|
70
|
+
vibesurf-0.1.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|