Fix ruff & mypy errors (#2394)
This commit is contained in:
@@ -3,26 +3,27 @@ import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import webbrowser
|
||||
import uuid
|
||||
import webbrowser
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import List, Optional, Dict, Any, Tuple
|
||||
from typing import Any, Callable, Optional, cast
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import requests # type: ignore
|
||||
import typer
|
||||
from dotenv import load_dotenv, set_key
|
||||
from rich.console import Console
|
||||
from rich.markdown import Markdown
|
||||
from rich.panel import Panel
|
||||
from rich.progress import Progress, SpinnerColumn, TextColumn
|
||||
from rich.table import Table
|
||||
from rich import print as rprint
|
||||
from rich.markdown import Markdown
|
||||
from dotenv import load_dotenv, set_key
|
||||
|
||||
from skyvern.config import settings
|
||||
from skyvern.library import Skyvern
|
||||
from skyvern.forge.sdk.db.enums import OrganizationAuthTokenType
|
||||
from skyvern.forge import app
|
||||
from skyvern.forge.sdk.db.enums import OrganizationAuthTokenType
|
||||
from skyvern.library import Skyvern
|
||||
from skyvern.utils import detect_os, get_windows_appdata_roaming, migrate_db
|
||||
|
||||
# Initialize Rich console for better formatting
|
||||
@@ -59,30 +60,27 @@ DOCUMENTATION = {
|
||||
"api": "https://docs.skyvern.com/integrations/api",
|
||||
}
|
||||
|
||||
|
||||
class DeploymentType(str, Enum):
|
||||
LOCAL = "local"
|
||||
CLOUD = "cloud"
|
||||
|
||||
|
||||
class BrowserType(str, Enum):
|
||||
HEADLESS = "chromium-headless"
|
||||
HEADFUL = "chromium-headful"
|
||||
CDP = "cdp-connect"
|
||||
|
||||
#----------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------
|
||||
# 1. Guided Onboarding Flow
|
||||
#----------------------------------------------------
|
||||
# ----------------------------------------------------
|
||||
|
||||
|
||||
@cli_app.command(name="init")
|
||||
def init(
|
||||
deployment: Optional[DeploymentType] = typer.Option(
|
||||
None,
|
||||
help="Deployment type: local or cloud"
|
||||
),
|
||||
no_postgres: bool = typer.Option(
|
||||
False,
|
||||
"--no-postgres",
|
||||
help="Skip starting PostgreSQL container"
|
||||
)
|
||||
deployment: Optional[DeploymentType] = typer.Option(None, help="Deployment type: local or cloud"),
|
||||
no_postgres: bool = typer.Option(False, "--no-postgres", help="Skip starting PostgreSQL container"),
|
||||
) -> None:
|
||||
"""
|
||||
Initialize Skyvern with a guided setup process.
|
||||
@@ -96,10 +94,11 @@ def init(
|
||||
- Setting up browser automation
|
||||
- Configuring integrations
|
||||
"""
|
||||
console.print(Panel.fit(
|
||||
"[bold blue]Welcome to Skyvern Setup Wizard[/]",
|
||||
subtitle="Let's get you started with browser automation"
|
||||
))
|
||||
console.print(
|
||||
Panel.fit(
|
||||
"[bold blue]Welcome to Skyvern Setup Wizard[/]", subtitle="Let's get you started with browser automation"
|
||||
)
|
||||
)
|
||||
|
||||
# Step 1: Choose deployment type
|
||||
if deployment is None:
|
||||
@@ -111,16 +110,14 @@ def init(
|
||||
console.print(" • Managed service with no local infrastructure")
|
||||
console.print(" • Production-ready with built-in scaling")
|
||||
|
||||
deployment_choice = console.input("\n[bold]Deploy locally or connect to cloud? [cloud/local] [/]").strip().lower()
|
||||
deployment_choice = (
|
||||
console.input("\n[bold]Deploy locally or connect to cloud? [cloud/local] [/]").strip().lower()
|
||||
)
|
||||
run_local = deployment_choice == "local"
|
||||
else:
|
||||
run_local = deployment == DeploymentType.LOCAL
|
||||
|
||||
with Progress(
|
||||
SpinnerColumn(),
|
||||
TextColumn("[progress.description]{task.description}"),
|
||||
console=console
|
||||
) as progress:
|
||||
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console) as progress:
|
||||
if run_local:
|
||||
# Step 2: Set up local infrastructure (for local deployment)
|
||||
setup_task = progress.add_task("[green]Setting up local infrastructure...", total=1)
|
||||
@@ -187,7 +184,9 @@ def init(
|
||||
|
||||
# Step 5: Configure integrations
|
||||
console.print(Markdown("\n## Step 5: Configure Integrations"))
|
||||
configure_mcp = typer.confirm("Would you like to configure AI integrations (Claude, Cursor, Windsurf)?", default=True)
|
||||
configure_mcp = typer.confirm(
|
||||
"Would you like to configure AI integrations (Claude, Cursor, Windsurf)?", default=True
|
||||
)
|
||||
if configure_mcp:
|
||||
setup_mcp()
|
||||
console.print("\n[green]AI integrations configured successfully![/]")
|
||||
@@ -195,16 +194,17 @@ def init(
|
||||
if run_local:
|
||||
# Install required components for local deployment
|
||||
console.print(Markdown("\n## Step 6: Installing Components"))
|
||||
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console) as progress:
|
||||
with Progress(
|
||||
SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console
|
||||
) as progress:
|
||||
browser_install_task = progress.add_task("[green]Installing Chromium browser...", total=1)
|
||||
subprocess.run(["playwright", "install", "chromium"], check=True)
|
||||
progress.update(browser_install_task, completed=1)
|
||||
|
||||
# Success message and next steps
|
||||
console.print(Panel.fit(
|
||||
"[bold green]Skyvern setup complete![/]",
|
||||
subtitle="You're ready to start automating browsers"
|
||||
))
|
||||
console.print(
|
||||
Panel.fit("[bold green]Skyvern setup complete![/]", subtitle="You're ready to start automating browsers")
|
||||
)
|
||||
|
||||
if run_local:
|
||||
console.print("\n[bold]Next steps:[/]")
|
||||
@@ -212,20 +212,19 @@ def init(
|
||||
console.print("2. Start the Skyvern UI: [yellow]skyvern run ui[/]")
|
||||
else:
|
||||
console.print("\n[bold]Next steps:[/]")
|
||||
console.print("1. Visit the Skyvern Cloud dashboard: [link=https://app.skyvern.com]https://app.skyvern.com[/link]")
|
||||
console.print(
|
||||
"1. Visit the Skyvern Cloud dashboard: [link=https://app.skyvern.com]https://app.skyvern.com[/link]"
|
||||
)
|
||||
console.print("2. Try using an AI integration: [yellow]skyvern docs integrations[/]")
|
||||
|
||||
#----------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------
|
||||
# 3. Improved Documentation Integration
|
||||
#----------------------------------------------------
|
||||
# ----------------------------------------------------
|
||||
|
||||
|
||||
@docs_app.command(name="open")
|
||||
def open_docs(
|
||||
section: str = typer.Argument(
|
||||
"quickstart",
|
||||
help="Documentation section to open"
|
||||
)
|
||||
) -> None:
|
||||
def open_docs(section: str = typer.Argument("quickstart", help="Documentation section to open")) -> None:
|
||||
"""
|
||||
Open Skyvern documentation in your web browser.
|
||||
|
||||
@@ -248,17 +247,18 @@ def open_docs(
|
||||
console.print(f"URL: [link={url}]{url}[/link]")
|
||||
webbrowser.open(url)
|
||||
|
||||
|
||||
@docs_app.command(name="prompting")
|
||||
def prompting_guide() -> None:
|
||||
"""
|
||||
Show prompting best practices for Skyvern.
|
||||
"""
|
||||
console.print(Panel.fit(
|
||||
"[bold blue]Skyvern Prompting Best Practices[/]",
|
||||
subtitle="Tips for writing effective prompts"
|
||||
))
|
||||
console.print(
|
||||
Panel.fit("[bold blue]Skyvern Prompting Best Practices[/]", subtitle="Tips for writing effective prompts")
|
||||
)
|
||||
|
||||
console.print(Markdown("""
|
||||
console.print(
|
||||
Markdown("""
|
||||
## General Guidelines
|
||||
|
||||
1. **Be specific and detailed**
|
||||
@@ -293,21 +293,21 @@ Buy wireless headphones and check out.
|
||||
## For More Information
|
||||
|
||||
Run `skyvern docs open prompting` to see the complete prompting guide online.
|
||||
"""))
|
||||
""")
|
||||
)
|
||||
|
||||
#----------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------
|
||||
# 4. User-Friendly Management Commands
|
||||
#----------------------------------------------------
|
||||
# ----------------------------------------------------
|
||||
|
||||
|
||||
@cli_app.command(name="status")
|
||||
def status() -> None:
|
||||
"""
|
||||
Check the status of Skyvern services.
|
||||
"""
|
||||
console.print(Panel.fit(
|
||||
"[bold blue]Skyvern Services Status[/]",
|
||||
subtitle="Checking all system components"
|
||||
))
|
||||
console.print(Panel.fit("[bold blue]Skyvern Services Status[/]", subtitle="Checking all system components"))
|
||||
|
||||
# Check for .env file
|
||||
env_path = Path(".env")
|
||||
@@ -318,7 +318,7 @@ def status() -> None:
|
||||
try:
|
||||
load_dotenv()
|
||||
# Simple check - just see if we can run a migrate command without error
|
||||
migrate_db(dry_run=True)
|
||||
migrate_db()
|
||||
db_status = "✅ Connected"
|
||||
except Exception:
|
||||
db_status = "❌ Not connected"
|
||||
@@ -327,24 +327,26 @@ def status() -> None:
|
||||
server_status = "⏳ Checking..."
|
||||
try:
|
||||
import socket
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(0.5)
|
||||
s.connect(("localhost", 8000))
|
||||
s.close()
|
||||
server_status = "✅ Running"
|
||||
except:
|
||||
except Exception:
|
||||
server_status = "❌ Not running"
|
||||
|
||||
# Check if UI is running (port 8080)
|
||||
ui_status = "⏳ Checking..."
|
||||
try:
|
||||
import socket
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(0.5)
|
||||
s.connect(("localhost", 8080))
|
||||
s.close()
|
||||
ui_status = "✅ Running"
|
||||
except:
|
||||
except Exception:
|
||||
ui_status = "❌ Not running"
|
||||
|
||||
# Check API key
|
||||
@@ -370,15 +372,13 @@ def status() -> None:
|
||||
else:
|
||||
console.print("\n[bold green]All systems operational![/] Skyvern is ready to use.")
|
||||
|
||||
|
||||
@tasks_app.command(name="list")
|
||||
def list_tasks() -> None:
|
||||
"""
|
||||
List recent Skyvern tasks.
|
||||
"""
|
||||
console.print(Panel.fit(
|
||||
"[bold blue]Recent Skyvern Tasks[/]",
|
||||
subtitle="Retrieving task history"
|
||||
))
|
||||
console.print(Panel.fit("[bold blue]Recent Skyvern Tasks[/]", subtitle="Retrieving task history"))
|
||||
|
||||
try:
|
||||
# Initialize Skyvern client
|
||||
@@ -389,7 +389,9 @@ def list_tasks() -> None:
|
||||
)
|
||||
|
||||
# Get tasks
|
||||
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console) as progress:
|
||||
with Progress(
|
||||
SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console
|
||||
) as progress:
|
||||
task = progress.add_task("[green]Fetching recent tasks...", total=1)
|
||||
tasks = asyncio.run(skyvern_agent.get_tasks())
|
||||
progress.update(task, completed=1)
|
||||
@@ -410,7 +412,7 @@ def list_tasks() -> None:
|
||||
str(task.id),
|
||||
task.title or "Untitled",
|
||||
task.status or "Unknown",
|
||||
task.created_at.strftime("%Y-%m-%d %H:%M:%S") if task.created_at else "Unknown"
|
||||
task.created_at.strftime("%Y-%m-%d %H:%M:%S") if task.created_at else "Unknown",
|
||||
)
|
||||
|
||||
console.print(table)
|
||||
@@ -424,20 +426,18 @@ def list_tasks() -> None:
|
||||
console.print(f"[bold red]Error listing tasks:[/] {str(e)}")
|
||||
console.print("[yellow]Make sure your API key is set correctly in .env[/]")
|
||||
|
||||
|
||||
@tasks_app.command(name="create")
|
||||
def create_task(
|
||||
prompt: str = typer.Option(..., "--prompt", "-p", help="Task prompt"),
|
||||
url: str = typer.Option(..., "--url", "-u", help="Starting URL"),
|
||||
schema: Optional[str] = typer.Option(None, "--schema", "-s", help="Data extraction schema (JSON)"),
|
||||
output_json: bool = typer.Option(False, "--json", help="Output results as JSON")
|
||||
output_json: bool = typer.Option(False, "--json", help="Output results as JSON"),
|
||||
) -> None:
|
||||
"""
|
||||
Create and run a new Skyvern task.
|
||||
"""
|
||||
console.print(Panel.fit(
|
||||
"[bold blue]Creating New Skyvern Task[/]",
|
||||
subtitle="Running browser automation"
|
||||
))
|
||||
console.print(Panel.fit("[bold blue]Creating New Skyvern Task[/]", subtitle="Running browser automation"))
|
||||
|
||||
console.print(f"[bold]Prompt:[/] {prompt}")
|
||||
console.print(f"[bold]URL:[/] {url}")
|
||||
@@ -453,15 +453,14 @@ def create_task(
|
||||
)
|
||||
|
||||
# Create and run task
|
||||
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console) as progress:
|
||||
with Progress(
|
||||
SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console
|
||||
) as progress:
|
||||
task = progress.add_task("[green]Running task...", total=1)
|
||||
|
||||
result = asyncio.run(skyvern_agent.run_task(
|
||||
prompt=prompt,
|
||||
url=url,
|
||||
data_extraction_schema=schema,
|
||||
user_agent="skyvern-cli"
|
||||
))
|
||||
result = asyncio.run(
|
||||
skyvern_agent.run_task(prompt=prompt, url=url, data_extraction_schema=schema, user_agent="skyvern-cli")
|
||||
)
|
||||
|
||||
progress.update(task, completed=1)
|
||||
|
||||
@@ -474,22 +473,22 @@ def create_task(
|
||||
|
||||
# Display path to view results
|
||||
base_url = settings.SKYVERN_BASE_URL
|
||||
run_history_url = "https://app.skyvern.com/history" if "skyvern.com" in base_url else "http://localhost:8080/history"
|
||||
run_history_url = (
|
||||
"https://app.skyvern.com/history" if "skyvern.com" in base_url else "http://localhost:8080/history"
|
||||
)
|
||||
console.print(f"\nView details at: [link={run_history_url}]{run_history_url}[/link]")
|
||||
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Error creating task:[/] {str(e)}")
|
||||
console.print("[yellow]Make sure your API key is set correctly in .env[/]")
|
||||
|
||||
|
||||
@workflows_app.command(name="list")
|
||||
def list_workflows() -> None:
|
||||
"""
|
||||
List Skyvern workflows.
|
||||
"""
|
||||
console.print(Panel.fit(
|
||||
"[bold blue]Skyvern Workflows[/]",
|
||||
subtitle="Retrieving available workflows"
|
||||
))
|
||||
console.print(Panel.fit("[bold blue]Skyvern Workflows[/]", subtitle="Retrieving available workflows"))
|
||||
|
||||
try:
|
||||
# Initialize Skyvern client
|
||||
@@ -500,7 +499,9 @@ def list_workflows() -> None:
|
||||
)
|
||||
|
||||
# Get workflows
|
||||
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console) as progress:
|
||||
with Progress(
|
||||
SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console
|
||||
) as progress:
|
||||
task = progress.add_task("[green]Fetching workflows...", total=1)
|
||||
workflows = asyncio.run(skyvern_agent.get_workflows())
|
||||
progress.update(task, completed=1)
|
||||
@@ -521,7 +522,9 @@ def list_workflows() -> None:
|
||||
str(workflow.id),
|
||||
workflow.title or "Untitled",
|
||||
workflow.status or "Unknown",
|
||||
workflow.created_at.strftime("%Y-%m-%d %H:%M:%S") if hasattr(workflow, 'created_at') and workflow.created_at else "Unknown"
|
||||
workflow.created_at.strftime("%Y-%m-%d %H:%M:%S")
|
||||
if hasattr(workflow, "created_at") and workflow.created_at
|
||||
else "Unknown",
|
||||
)
|
||||
|
||||
console.print(table)
|
||||
@@ -535,9 +538,11 @@ def list_workflows() -> None:
|
||||
console.print(f"[bold red]Error listing workflows:[/] {str(e)}")
|
||||
console.print("[yellow]Make sure your API key is set correctly in .env[/]")
|
||||
|
||||
#----------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------
|
||||
# 5. Streamlined Configuration (Original functions enhanced)
|
||||
#----------------------------------------------------
|
||||
# ----------------------------------------------------
|
||||
|
||||
|
||||
def setup_postgresql(no_postgres: bool = False) -> None:
|
||||
"""Set up PostgreSQL database for Skyvern with improved feedback."""
|
||||
@@ -569,8 +574,7 @@ def setup_postgresql(no_postgres: bool = False) -> None:
|
||||
if not no_postgres:
|
||||
console.print("[yellow]![/] No local Postgres detected")
|
||||
start_postgres = typer.confirm(
|
||||
"Start a disposable container now? (Choose 'n' if using Docker Compose)",
|
||||
default=True
|
||||
"Start a disposable container now? (Choose 'n' if using Docker Compose)", default=True
|
||||
)
|
||||
|
||||
if not start_postgres:
|
||||
@@ -617,20 +621,27 @@ def setup_llm_providers() -> None:
|
||||
model_options = []
|
||||
|
||||
# Create sections for each provider
|
||||
providers = [
|
||||
providers: list[dict[str, Any]] = [
|
||||
{
|
||||
"name": "OpenAI",
|
||||
"env_key": "ENABLE_OPENAI",
|
||||
"api_key_env": "OPENAI_API_KEY",
|
||||
"models": ["OPENAI_GPT4_1", "OPENAI_GPT4_1_MINI", "OPENAI_GPT4_1_NANO", "OPENAI_GPT4O", "OPENAI_O4_MINI", "OPENAI_O3"],
|
||||
"setup_message": "To enable OpenAI, you need an API key from your OpenAI account."
|
||||
"models": [
|
||||
"OPENAI_GPT4_1",
|
||||
"OPENAI_GPT4_1_MINI",
|
||||
"OPENAI_GPT4_1_NANO",
|
||||
"OPENAI_GPT4O",
|
||||
"OPENAI_O4_MINI",
|
||||
"OPENAI_O3",
|
||||
],
|
||||
"setup_message": "To enable OpenAI, you need an API key from your OpenAI account.",
|
||||
},
|
||||
{
|
||||
"name": "Anthropic",
|
||||
"env_key": "ENABLE_ANTHROPIC",
|
||||
"api_key_env": "ANTHROPIC_API_KEY",
|
||||
"models": ["ANTHROPIC_CLAUDE3.5_SONNET", "ANTHROPIC_CLAUDE3.7_SONNET"],
|
||||
"setup_message": "To enable Anthropic, you need an API key from your Anthropic account."
|
||||
"setup_message": "To enable Anthropic, you need an API key from your Anthropic account.",
|
||||
},
|
||||
{
|
||||
"name": "Azure OpenAI",
|
||||
@@ -641,27 +652,39 @@ def setup_llm_providers() -> None:
|
||||
"extra_fields": {
|
||||
"AZURE_DEPLOYMENT": "Enter your Azure deployment name",
|
||||
"AZURE_API_BASE": "Enter your Azure API base URL",
|
||||
"AZURE_API_VERSION": "Enter your Azure API version"
|
||||
}
|
||||
"AZURE_API_VERSION": "Enter your Azure API version",
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Google Gemini",
|
||||
"env_key": "ENABLE_GEMINI",
|
||||
"api_key_env": "GEMINI_API_KEY",
|
||||
"models": ["GEMINI_FLASH_2_0", "GEMINI_FLASH_2_0_LITE", "GEMINI_2.5_PRO_PREVIEW_03_25", "GEMINI_2.5_PRO_EXP_03_25"],
|
||||
"setup_message": "To enable Gemini, you need an API key from Google AI Studio."
|
||||
"models": [
|
||||
"GEMINI_FLASH_2_0",
|
||||
"GEMINI_FLASH_2_0_LITE",
|
||||
"GEMINI_2.5_PRO_PREVIEW_03_25",
|
||||
"GEMINI_2.5_PRO_EXP_03_25",
|
||||
],
|
||||
"setup_message": "To enable Gemini, you need an API key from Google AI Studio.",
|
||||
},
|
||||
{
|
||||
"name": "Novita AI",
|
||||
"env_key": "ENABLE_NOVITA",
|
||||
"api_key_env": "NOVITA_API_KEY",
|
||||
"models": [
|
||||
"NOVITA_DEEPSEEK_R1", "NOVITA_DEEPSEEK_V3", "NOVITA_LLAMA_3_3_70B",
|
||||
"NOVITA_LLAMA_3_2_1B", "NOVITA_LLAMA_3_2_3B", "NOVITA_LLAMA_3_2_11B_VISION",
|
||||
"NOVITA_LLAMA_3_1_8B", "NOVITA_LLAMA_3_1_70B", "NOVITA_LLAMA_3_1_405B",
|
||||
"NOVITA_LLAMA_3_8B", "NOVITA_LLAMA_3_70B"
|
||||
"NOVITA_DEEPSEEK_R1",
|
||||
"NOVITA_DEEPSEEK_V3",
|
||||
"NOVITA_LLAMA_3_3_70B",
|
||||
"NOVITA_LLAMA_3_2_1B",
|
||||
"NOVITA_LLAMA_3_2_3B",
|
||||
"NOVITA_LLAMA_3_2_11B_VISION",
|
||||
"NOVITA_LLAMA_3_1_8B",
|
||||
"NOVITA_LLAMA_3_1_70B",
|
||||
"NOVITA_LLAMA_3_1_405B",
|
||||
"NOVITA_LLAMA_3_8B",
|
||||
"NOVITA_LLAMA_3_70B",
|
||||
],
|
||||
"setup_message": "To enable Novita AI, you need an API key from Novita."
|
||||
"setup_message": "To enable Novita AI, you need an API key from Novita.",
|
||||
},
|
||||
{
|
||||
"name": "OpenAI-compatible",
|
||||
@@ -671,20 +694,18 @@ def setup_llm_providers() -> None:
|
||||
"extra_fields": {
|
||||
"OPENAI_COMPATIBLE_MODEL_NAME": "Enter the model name (e.g., 'yi-34b', 'mistral-large')",
|
||||
"OPENAI_COMPATIBLE_API_KEY": "Enter your API key",
|
||||
"OPENAI_COMPATIBLE_API_BASE": "Enter the API base URL (e.g., 'https://api.together.xyz/v1')"
|
||||
"OPENAI_COMPATIBLE_API_BASE": "Enter the API base URL (e.g., 'https://api.together.xyz/v1')",
|
||||
},
|
||||
"extra_questions": [
|
||||
{
|
||||
"question": "Does this model support vision?",
|
||||
"env_key": "OPENAI_COMPATIBLE_SUPPORTS_VISION",
|
||||
"value_if_yes": "true",
|
||||
"value_if_no": "false"
|
||||
"value_if_no": "false",
|
||||
}
|
||||
],
|
||||
"optional_fields": {
|
||||
"OPENAI_COMPATIBLE_API_VERSION": "Enter API version (optional, press enter to skip)"
|
||||
}
|
||||
}
|
||||
"optional_fields": {"OPENAI_COMPATIBLE_API_VERSION": "Enter API version (optional, press enter to skip)"},
|
||||
},
|
||||
]
|
||||
|
||||
# Process each provider
|
||||
@@ -751,10 +772,7 @@ def setup_llm_providers() -> None:
|
||||
|
||||
while True:
|
||||
try:
|
||||
model_choice = typer.prompt(
|
||||
f"Choose a model by number (1-{len(model_options)})",
|
||||
type=int
|
||||
)
|
||||
model_choice = typer.prompt(f"Choose a model by number (1-{len(model_options)})", type=int)
|
||||
if 1 <= model_choice <= len(model_options):
|
||||
break
|
||||
console.print(f"[red]Please enter a number between 1 and {len(model_options)}[/]")
|
||||
@@ -773,9 +791,17 @@ def setup_browser_config() -> tuple[str, Optional[str], Optional[str]]:
|
||||
console.print(Markdown("## Browser Configuration"))
|
||||
|
||||
browser_types = [
|
||||
{"id": "chromium-headless", "name": "Headless Chrome", "description": "Runs Chrome in the background (no visible window)"},
|
||||
{
|
||||
"id": "chromium-headless",
|
||||
"name": "Headless Chrome",
|
||||
"description": "Runs Chrome in the background (no visible window)",
|
||||
},
|
||||
{"id": "chromium-headful", "name": "Visible Chrome", "description": "Runs Chrome with a visible window"},
|
||||
{"id": "cdp-connect", "name": "Connect to Chrome", "description": "Connects to an existing Chrome instance with remote debugging"}
|
||||
{
|
||||
"id": "cdp-connect",
|
||||
"name": "Connect to Chrome",
|
||||
"description": "Connects to an existing Chrome instance with remote debugging",
|
||||
},
|
||||
]
|
||||
|
||||
console.print("Select browser mode:")
|
||||
@@ -812,7 +838,7 @@ def setup_browser_config() -> tuple[str, Optional[str], Optional[str]]:
|
||||
|
||||
console.print("\n[bold]Chrome Remote Debugging Setup:[/]")
|
||||
console.print("Chrome must be running with remote debugging enabled.")
|
||||
console.print(f"Example command: [italic]chrome --remote-debugging-port=9222[/]")
|
||||
console.print("Example command: [italic]chrome --remote-debugging-port=9222[/]")
|
||||
|
||||
default_port = "9222"
|
||||
remote_debugging_url = f"http://localhost:{default_port}"
|
||||
@@ -867,7 +893,9 @@ def setup_browser_config() -> tuple[str, Optional[str], Optional[str]]:
|
||||
console.print(f"Connecting to {remote_debugging_url}")
|
||||
|
||||
# Wait for Chrome to start and verify connection
|
||||
with Progress(SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console) as progress:
|
||||
with Progress(
|
||||
SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console
|
||||
) as progress:
|
||||
wait_task = progress.add_task("[green]Waiting for Chrome to initialize...", total=1)
|
||||
time.sleep(2)
|
||||
progress.update(wait_task, completed=1)
|
||||
@@ -877,13 +905,19 @@ def setup_browser_config() -> tuple[str, Optional[str], Optional[str]]:
|
||||
if verification_response.status_code == 200:
|
||||
try:
|
||||
browser_info = verification_response.json()
|
||||
console.print("[green]✓[/] Connection verified! Chrome is running with remote debugging")
|
||||
console.print(
|
||||
"[green]✓[/] Connection verified! Chrome is running with remote debugging"
|
||||
)
|
||||
if "Browser" in browser_info:
|
||||
console.print(f" Browser: {browser_info['Browser']}")
|
||||
except json.JSONDecodeError:
|
||||
console.print("[yellow]Warning:[/] Response from Chrome debugging port is not valid JSON")
|
||||
console.print(
|
||||
"[yellow]Warning:[/] Response from Chrome debugging port is not valid JSON"
|
||||
)
|
||||
else:
|
||||
console.print(f"[yellow]Warning:[/] Chrome responded with status code {verification_response.status_code}")
|
||||
console.print(
|
||||
f"[yellow]Warning:[/] Chrome responded with status code {verification_response.status_code}"
|
||||
)
|
||||
except requests.RequestException as e:
|
||||
console.print(f"[yellow]Warning:[/] Could not verify Chrome is running: {e}")
|
||||
console.print("You may need to check Chrome manually or try a different port")
|
||||
@@ -1046,20 +1080,20 @@ def setup_mcp() -> None:
|
||||
"name": "Claude Desktop",
|
||||
"check_fn": lambda: is_claude_desktop_installed(host_system),
|
||||
"setup_fn": lambda: setup_claude_desktop_config(host_system, path_to_env),
|
||||
"not_installed_msg": "Claude Desktop is not installed. Please install it first."
|
||||
"not_installed_msg": "Claude Desktop is not installed. Please install it first.",
|
||||
},
|
||||
{
|
||||
"name": "Cursor Editor",
|
||||
"check_fn": lambda: is_cursor_installed(host_system),
|
||||
"setup_fn": lambda: setup_cursor_config(host_system, path_to_env),
|
||||
"not_installed_msg": "Cursor Editor is not installed. Please install it first."
|
||||
"not_installed_msg": "Cursor Editor is not installed. Please install it first.",
|
||||
},
|
||||
{
|
||||
"name": "Windsurf",
|
||||
"check_fn": lambda: is_windsurf_installed(host_system),
|
||||
"setup_fn": lambda: setup_windsurf_config(host_system, path_to_env),
|
||||
"not_installed_msg": "Windsurf is not installed. Please install it first."
|
||||
}
|
||||
"not_installed_msg": "Windsurf is not installed. Please install it first.",
|
||||
},
|
||||
]
|
||||
|
||||
# Set up each integration
|
||||
@@ -1067,7 +1101,8 @@ def setup_mcp() -> None:
|
||||
console.print(f"\n[bold]Setting up {integration['name']}[/]")
|
||||
|
||||
# Check if installed
|
||||
if not integration["check_fn"]():
|
||||
check_fn = cast(Callable[[], bool], integration["check_fn"])
|
||||
if not check_fn():
|
||||
console.print(f"[yellow]![/] {integration['not_installed_msg']}")
|
||||
console.print(f"Skipping {integration['name']} integration setup.")
|
||||
continue
|
||||
@@ -1075,7 +1110,8 @@ def setup_mcp() -> None:
|
||||
# Ask user if they want to set up this integration
|
||||
if typer.confirm(f"Configure {integration['name']} integration?", default=True):
|
||||
# Set up the integration
|
||||
if integration["setup_fn"]():
|
||||
setup_fn = cast(Callable[[], bool], integration["setup_fn"])
|
||||
if setup_fn():
|
||||
console.print(f"[green]✓[/] {integration['name']} integration configured successfully")
|
||||
else:
|
||||
console.print(f"[red]×[/] Error configuring {integration['name']} integration")
|
||||
@@ -1097,8 +1133,7 @@ def setup_mcp_config() -> str:
|
||||
if not python_paths:
|
||||
console.print("[yellow]![/] Could not find Python 3.11 installation")
|
||||
path_to_env = typer.prompt(
|
||||
"Enter the full path to your Python 3.11 environment",
|
||||
default="/opt/homebrew/bin/python3.11"
|
||||
"Enter the full path to your Python 3.11 environment", default="/opt/homebrew/bin/python3.11"
|
||||
)
|
||||
else:
|
||||
# Show found Python installations
|
||||
@@ -1112,10 +1147,7 @@ def setup_mcp_config() -> str:
|
||||
|
||||
if len(python_paths) > 1:
|
||||
# Let user choose if multiple were found
|
||||
choice = typer.prompt(
|
||||
"Which Python installation do you want to use? (Enter number)",
|
||||
default="1"
|
||||
)
|
||||
choice = typer.prompt("Which Python installation do you want to use? (Enter number)", default="1")
|
||||
try:
|
||||
index = int(choice) - 1
|
||||
if 0 <= index < len(python_paths):
|
||||
@@ -1210,3 +1242,19 @@ def is_cursor_installed(host_system: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def setup_cursor_config(host_system: str, path_to_env: str) -> bool:
|
||||
"""Placeholder setup for Cursor integration."""
|
||||
console.print("[yellow]![/] Cursor integration setup is not implemented yet")
|
||||
return False
|
||||
|
||||
|
||||
def is_windsurf_installed(host_system: str) -> bool:
|
||||
"""Check if Windsurf is installed."""
|
||||
# TODO: Implement actual detection logic
|
||||
return False
|
||||
|
||||
|
||||
def setup_windsurf_config(host_system: str, path_to_env: str) -> bool:
|
||||
"""Placeholder setup for Windsurf integration."""
|
||||
console.print("[yellow]![/] Windsurf integration setup is not implemented yet")
|
||||
return False
|
||||
|
||||
@@ -300,7 +300,7 @@ class Skyvern(AsyncSkyvern):
|
||||
totp_url: str | None = None,
|
||||
title: str | None = None,
|
||||
error_code_mapping: dict[str, str] | None = None,
|
||||
data_extraction_schema: dict[str, Any] | None = None,
|
||||
data_extraction_schema: dict[str, Any] | str | None = None,
|
||||
proxy_location: ProxyLocation | None = None,
|
||||
max_steps: int | None = None,
|
||||
wait_for_completion: bool = True,
|
||||
|
||||
Reference in New Issue
Block a user