shu/removeSettingsManager.get_settings (#1305)
This commit is contained in:
@@ -6,7 +6,7 @@ from typing import Any, Dict
|
|||||||
import typer
|
import typer
|
||||||
from posthog import Posthog
|
from posthog import Posthog
|
||||||
|
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
from skyvern.config import settings
|
||||||
|
|
||||||
posthog = Posthog(
|
posthog = Posthog(
|
||||||
"phc_bVT2ugnZhMHRWqMvSRHPdeTjaPxQqT3QSsI3r5FlQR5",
|
"phc_bVT2ugnZhMHRWqMvSRHPdeTjaPxQqT3QSsI3r5FlQR5",
|
||||||
@@ -31,7 +31,7 @@ def analytics_metadata() -> Dict[str, Any]:
|
|||||||
"machine": platform.machine(),
|
"machine": platform.machine(),
|
||||||
"platform": platform.platform(),
|
"platform": platform.platform(),
|
||||||
"python_version": platform.python_version(),
|
"python_version": platform.python_version(),
|
||||||
"environment": SettingsManager.get_settings().ENV,
|
"environment": settings.ENV,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -40,10 +40,10 @@ def capture(
|
|||||||
data: dict[str, Any] | None = None,
|
data: dict[str, Any] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
# If telemetry is disabled, don't send any data
|
# If telemetry is disabled, don't send any data
|
||||||
if not SettingsManager.get_settings().SKYVERN_TELEMETRY:
|
if not settings.SKYVERN_TELEMETRY:
|
||||||
return
|
return
|
||||||
|
|
||||||
distinct_id = SettingsManager.get_settings().ANALYTICS_ID
|
distinct_id = settings.ANALYTICS_ID
|
||||||
|
|
||||||
payload: dict[str, Any] = data or {}
|
payload: dict[str, Any] = data or {}
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ class Settings(BaseSettings):
|
|||||||
ENABLE_AZURE: bool = False
|
ENABLE_AZURE: bool = False
|
||||||
ENABLE_AZURE_GPT4O_MINI: bool = False
|
ENABLE_AZURE_GPT4O_MINI: bool = False
|
||||||
ENABLE_BEDROCK: bool = False
|
ENABLE_BEDROCK: bool = False
|
||||||
|
ENABLE_GEMINI: bool = False
|
||||||
# OPENAI
|
# OPENAI
|
||||||
OPENAI_API_KEY: str | None = None
|
OPENAI_API_KEY: str | None = None
|
||||||
# ANTHROPIC
|
# ANTHROPIC
|
||||||
@@ -119,6 +120,9 @@ class Settings(BaseSettings):
|
|||||||
AZURE_GPT4O_MINI_API_BASE: str | None = None
|
AZURE_GPT4O_MINI_API_BASE: str | None = None
|
||||||
AZURE_GPT4O_MINI_API_VERSION: str | None = None
|
AZURE_GPT4O_MINI_API_VERSION: str | None = None
|
||||||
|
|
||||||
|
# GEMINI
|
||||||
|
GEMINI_API_KEY: str | None = None
|
||||||
|
|
||||||
# TOTP Settings
|
# TOTP Settings
|
||||||
TOTP_LIFESPAN_MINUTES: int = 10
|
TOTP_LIFESPAN_MINUTES: int = 10
|
||||||
VERIFICATION_CODE_INITIAL_WAIT_TIME_SECS: int = 40
|
VERIFICATION_CODE_INITIAL_WAIT_TIME_SECS: int = 40
|
||||||
|
|||||||
@@ -3,18 +3,18 @@ import uvicorn
|
|||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
from skyvern import analytics
|
from skyvern import analytics
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
from skyvern.config import settings
|
||||||
|
|
||||||
LOG = structlog.stdlib.get_logger()
|
LOG = structlog.stdlib.get_logger()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
analytics.capture("skyvern-oss-run-server")
|
analytics.capture("skyvern-oss-run-server")
|
||||||
port = SettingsManager.get_settings().PORT
|
port = settings.PORT
|
||||||
LOG.info("Agent server starting.", host="0.0.0.0", port=port)
|
LOG.info("Agent server starting.", host="0.0.0.0", port=port)
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
reload = SettingsManager.get_settings().ENV == "local"
|
reload = settings.ENV == "local"
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
"skyvern.forge.api_app:app",
|
"skyvern.forge.api_app:app",
|
||||||
host="0.0.0.0",
|
host="0.0.0.0",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from playwright._impl._errors import TargetClosedError
|
|||||||
from playwright.async_api import Page
|
from playwright.async_api import Page
|
||||||
|
|
||||||
from skyvern import analytics
|
from skyvern import analytics
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.constants import (
|
from skyvern.constants import (
|
||||||
GET_DOWNLOADED_FILES_TIMEOUT,
|
GET_DOWNLOADED_FILES_TIMEOUT,
|
||||||
SAVE_DOWNLOADED_FILES_TIMEOUT,
|
SAVE_DOWNLOADED_FILES_TIMEOUT,
|
||||||
@@ -51,7 +52,6 @@ from skyvern.forge.sdk.core.validators import validate_url
|
|||||||
from skyvern.forge.sdk.db.enums import TaskType
|
from skyvern.forge.sdk.db.enums import TaskType
|
||||||
from skyvern.forge.sdk.models import Organization, Step, StepStatus
|
from skyvern.forge.sdk.models import Organization, Step, StepStatus
|
||||||
from skyvern.forge.sdk.schemas.tasks import Task, TaskRequest, TaskStatus
|
from skyvern.forge.sdk.schemas.tasks import Task, TaskRequest, TaskStatus
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
from skyvern.forge.sdk.workflow.context_manager import WorkflowRunContext
|
from skyvern.forge.sdk.workflow.context_manager import WorkflowRunContext
|
||||||
from skyvern.forge.sdk.workflow.models.block import ActionBlock, BaseTaskBlock, ValidationBlock
|
from skyvern.forge.sdk.workflow.models.block import ActionBlock, BaseTaskBlock, ValidationBlock
|
||||||
from skyvern.forge.sdk.workflow.models.workflow import Workflow, WorkflowRun, WorkflowRunStatus
|
from skyvern.forge.sdk.workflow.models.workflow import Workflow, WorkflowRun, WorkflowRunStatus
|
||||||
@@ -84,25 +84,25 @@ class ActionLinkedNode:
|
|||||||
|
|
||||||
class ForgeAgent:
|
class ForgeAgent:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
if SettingsManager.get_settings().ADDITIONAL_MODULES:
|
if settings.ADDITIONAL_MODULES:
|
||||||
for module in SettingsManager.get_settings().ADDITIONAL_MODULES:
|
for module in settings.ADDITIONAL_MODULES:
|
||||||
LOG.info("Loading additional module", module=module)
|
LOG.info("Loading additional module", module=module)
|
||||||
__import__(module)
|
__import__(module)
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"Additional modules loaded",
|
"Additional modules loaded",
|
||||||
modules=SettingsManager.get_settings().ADDITIONAL_MODULES,
|
modules=settings.ADDITIONAL_MODULES,
|
||||||
)
|
)
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"Initializing ForgeAgent",
|
"Initializing ForgeAgent",
|
||||||
env=SettingsManager.get_settings().ENV,
|
env=settings.ENV,
|
||||||
execute_all_steps=SettingsManager.get_settings().EXECUTE_ALL_STEPS,
|
execute_all_steps=settings.EXECUTE_ALL_STEPS,
|
||||||
browser_type=SettingsManager.get_settings().BROWSER_TYPE,
|
browser_type=settings.BROWSER_TYPE,
|
||||||
max_scraping_retries=SettingsManager.get_settings().MAX_SCRAPING_RETRIES,
|
max_scraping_retries=settings.MAX_SCRAPING_RETRIES,
|
||||||
video_path=SettingsManager.get_settings().VIDEO_PATH,
|
video_path=settings.VIDEO_PATH,
|
||||||
browser_action_timeout_ms=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
browser_action_timeout_ms=settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
max_steps_per_run=SettingsManager.get_settings().MAX_STEPS_PER_RUN,
|
max_steps_per_run=settings.MAX_STEPS_PER_RUN,
|
||||||
long_running_task_warning_ratio=SettingsManager.get_settings().LONG_RUNNING_TASK_WARNING_RATIO,
|
long_running_task_warning_ratio=settings.LONG_RUNNING_TASK_WARNING_RATIO,
|
||||||
debug_mode=SettingsManager.get_settings().DEBUG_MODE,
|
debug_mode=settings.DEBUG_MODE,
|
||||||
)
|
)
|
||||||
self.async_operation_pool = AsyncOperationPool()
|
self.async_operation_pool = AsyncOperationPool()
|
||||||
|
|
||||||
@@ -290,7 +290,7 @@ class ForgeAgent:
|
|||||||
override_max_steps_per_run
|
override_max_steps_per_run
|
||||||
or task.max_steps_per_run
|
or task.max_steps_per_run
|
||||||
or organization.max_steps_per_run
|
or organization.max_steps_per_run
|
||||||
or SettingsManager.get_settings().MAX_STEPS_PER_RUN
|
or settings.MAX_STEPS_PER_RUN
|
||||||
)
|
)
|
||||||
if max_steps_per_run and task.max_steps_per_run != max_steps_per_run:
|
if max_steps_per_run and task.max_steps_per_run != max_steps_per_run:
|
||||||
await app.DATABASE.update_task(
|
await app.DATABASE.update_task(
|
||||||
@@ -423,7 +423,7 @@ class ForgeAgent:
|
|||||||
close_browser_on_completion=close_browser_on_completion,
|
close_browser_on_completion=close_browser_on_completion,
|
||||||
task_block=task_block,
|
task_block=task_block,
|
||||||
)
|
)
|
||||||
elif SettingsManager.get_settings().execute_all_steps() and next_step:
|
elif settings.execute_all_steps() and next_step:
|
||||||
return await self.execute_step(
|
return await self.execute_step(
|
||||||
organization,
|
organization,
|
||||||
task,
|
task,
|
||||||
@@ -437,8 +437,8 @@ class ForgeAgent:
|
|||||||
"Step executed but continuous execution is disabled.",
|
"Step executed but continuous execution is disabled.",
|
||||||
task_id=task.task_id,
|
task_id=task.task_id,
|
||||||
step_id=step.step_id,
|
step_id=step.step_id,
|
||||||
is_cloud_env=SettingsManager.get_settings().is_cloud_environment(),
|
is_cloud_env=settings.is_cloud_environment(),
|
||||||
execute_all_steps=SettingsManager.get_settings().execute_all_steps(),
|
execute_all_steps=settings.execute_all_steps(),
|
||||||
next_step_id=next_step.step_id if next_step else None,
|
next_step_id=next_step.step_id if next_step else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1342,7 +1342,7 @@ class ForgeAgent:
|
|||||||
# Get action results from the last app.SETTINGS.PROMPT_ACTION_HISTORY_WINDOW steps
|
# Get action results from the last app.SETTINGS.PROMPT_ACTION_HISTORY_WINDOW steps
|
||||||
steps = await app.DATABASE.get_task_steps(task_id=task.task_id, organization_id=task.organization_id)
|
steps = await app.DATABASE.get_task_steps(task_id=task.task_id, organization_id=task.organization_id)
|
||||||
# the last step is always the newly created one and it should be excluded from the history window
|
# the last step is always the newly created one and it should be excluded from the history window
|
||||||
window_steps = steps[-1 - SettingsManager.get_settings().PROMPT_ACTION_HISTORY_WINDOW : -1]
|
window_steps = steps[-1 - settings.PROMPT_ACTION_HISTORY_WINDOW : -1]
|
||||||
actions_and_results: list[tuple[Action, list[ActionResult]]] = []
|
actions_and_results: list[tuple[Action, list[ActionResult]]] = []
|
||||||
for window_step in window_steps:
|
for window_step in window_steps:
|
||||||
if window_step.output and window_step.output.actions_and_results:
|
if window_step.output and window_step.output.actions_and_results:
|
||||||
@@ -1576,7 +1576,7 @@ class ForgeAgent:
|
|||||||
task_id=task.task_id,
|
task_id=task.task_id,
|
||||||
organization_id=task.organization_id,
|
organization_id=task.organization_id,
|
||||||
artifact_types=[ArtifactType.SCREENSHOT_ACTION],
|
artifact_types=[ArtifactType.SCREENSHOT_ACTION],
|
||||||
n=SettingsManager.get_settings().TASK_RESPONSE_ACTION_SCREENSHOT_COUNT,
|
n=settings.TASK_RESPONSE_ACTION_SCREENSHOT_COUNT,
|
||||||
)
|
)
|
||||||
if latest_action_screenshot_artifacts:
|
if latest_action_screenshot_artifacts:
|
||||||
latest_action_screenshot_urls = await app.ARTIFACT_MANAGER.get_share_links(
|
latest_action_screenshot_urls = await app.ARTIFACT_MANAGER.get_share_links(
|
||||||
@@ -1790,7 +1790,7 @@ class ForgeAgent:
|
|||||||
organization.max_retries_per_step
|
organization.max_retries_per_step
|
||||||
# we need to check by None because 0 is a valid value for max_retries_per_step
|
# we need to check by None because 0 is a valid value for max_retries_per_step
|
||||||
if organization.max_retries_per_step is not None
|
if organization.max_retries_per_step is not None
|
||||||
else SettingsManager.get_settings().MAX_RETRIES_PER_STEP
|
else settings.MAX_RETRIES_PER_STEP
|
||||||
)
|
)
|
||||||
if step.retry_index >= max_retries_per_step:
|
if step.retry_index >= max_retries_per_step:
|
||||||
LOG.warning(
|
LOG.warning(
|
||||||
@@ -1799,7 +1799,7 @@ class ForgeAgent:
|
|||||||
step_id=step.step_id,
|
step_id=step.step_id,
|
||||||
step_order=step.order,
|
step_order=step.order,
|
||||||
step_retry=step.retry_index,
|
step_retry=step.retry_index,
|
||||||
max_retries=SettingsManager.get_settings().MAX_RETRIES_PER_STEP,
|
max_retries=settings.MAX_RETRIES_PER_STEP,
|
||||||
)
|
)
|
||||||
await self.update_task(
|
await self.update_task(
|
||||||
task,
|
task,
|
||||||
@@ -1923,7 +1923,7 @@ class ForgeAgent:
|
|||||||
override_max_steps_per_run
|
override_max_steps_per_run
|
||||||
or task.max_steps_per_run
|
or task.max_steps_per_run
|
||||||
or organization.max_steps_per_run
|
or organization.max_steps_per_run
|
||||||
or SettingsManager.get_settings().MAX_STEPS_PER_RUN
|
or settings.MAX_STEPS_PER_RUN
|
||||||
)
|
)
|
||||||
|
|
||||||
# HACK: action block only have one step to execute without complete action, so we consider the task is completed as long as the step is completed
|
# HACK: action block only have one step to execute without complete action, so we consider the task is completed as long as the step is completed
|
||||||
@@ -1985,14 +1985,12 @@ class ForgeAgent:
|
|||||||
organization_id=task.organization_id,
|
organization_id=task.organization_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
if step.order == int(
|
if step.order == int(max_steps_per_run * settings.LONG_RUNNING_TASK_WARNING_RATIO - 1):
|
||||||
max_steps_per_run * SettingsManager.get_settings().LONG_RUNNING_TASK_WARNING_RATIO - 1
|
|
||||||
):
|
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"Long running task warning",
|
"Long running task warning",
|
||||||
order=step.order,
|
order=step.order,
|
||||||
max_steps=max_steps_per_run,
|
max_steps=max_steps_per_run,
|
||||||
warning_ratio=SettingsManager.get_settings().LONG_RUNNING_TASK_WARNING_RATIO,
|
warning_ratio=settings.LONG_RUNNING_TASK_WARNING_RATIO,
|
||||||
)
|
)
|
||||||
return None, None, next_step
|
return None, None, next_step
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from starlette.requests import HTTPConnection, Request
|
|||||||
from starlette_context.middleware import RawContextMiddleware
|
from starlette_context.middleware import RawContextMiddleware
|
||||||
from starlette_context.plugins.base import Plugin
|
from starlette_context.plugins.base import Plugin
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.exceptions import SkyvernHTTPException
|
from skyvern.exceptions import SkyvernHTTPException
|
||||||
from skyvern.forge import app as forge_app
|
from skyvern.forge import app as forge_app
|
||||||
from skyvern.forge.sdk.core import skyvern_context
|
from skyvern.forge.sdk.core import skyvern_context
|
||||||
@@ -18,7 +19,6 @@ from skyvern.forge.sdk.core.skyvern_context import SkyvernContext
|
|||||||
from skyvern.forge.sdk.db.exceptions import NotFoundError
|
from skyvern.forge.sdk.db.exceptions import NotFoundError
|
||||||
from skyvern.forge.sdk.routes.agent_protocol import base_router
|
from skyvern.forge.sdk.routes.agent_protocol import base_router
|
||||||
from skyvern.forge.sdk.routes.streaming import websocket_router
|
from skyvern.forge.sdk.routes.streaming import websocket_router
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
|
|
||||||
LOG = structlog.get_logger()
|
LOG = structlog.get_logger()
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ def get_agent_app() -> FastAPI:
|
|||||||
# Add CORS middleware
|
# Add CORS middleware
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
CORSMiddleware,
|
CORSMiddleware,
|
||||||
allow_origins=SettingsManager.get_settings().ALLOWED_ORIGINS,
|
allow_origins=settings.ALLOWED_ORIGINS,
|
||||||
allow_credentials=True,
|
allow_credentials=True,
|
||||||
allow_methods=["*"],
|
allow_methods=["*"],
|
||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
@@ -90,13 +90,13 @@ def get_agent_app() -> FastAPI:
|
|||||||
finally:
|
finally:
|
||||||
skyvern_context.reset()
|
skyvern_context.reset()
|
||||||
|
|
||||||
if SettingsManager.get_settings().ADDITIONAL_MODULES:
|
if settings.ADDITIONAL_MODULES:
|
||||||
for module in SettingsManager.get_settings().ADDITIONAL_MODULES:
|
for module in settings.ADDITIONAL_MODULES:
|
||||||
LOG.info("Loading additional module to set up api app", module=module)
|
LOG.info("Loading additional module to set up api app", module=module)
|
||||||
__import__(module)
|
__import__(module)
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"Additional modules loaded to set up api app",
|
"Additional modules loaded to set up api app",
|
||||||
modules=SettingsManager.get_settings().ADDITIONAL_MODULES,
|
modules=settings.ADDITIONAL_MODULES,
|
||||||
)
|
)
|
||||||
|
|
||||||
if forge_app.setup_api_app:
|
if forge_app.setup_api_app:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from typing import Awaitable, Callable
|
|||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.forge.agent import ForgeAgent
|
from skyvern.forge.agent import ForgeAgent
|
||||||
from skyvern.forge.agent_functions import AgentFunction
|
from skyvern.forge.agent_functions import AgentFunction
|
||||||
from skyvern.forge.sdk.api.llm.api_handler_factory import LLMAPIHandlerFactory
|
from skyvern.forge.sdk.api.llm.api_handler_factory import LLMAPIHandlerFactory
|
||||||
@@ -12,25 +13,24 @@ from skyvern.forge.sdk.cache.factory import CacheFactory
|
|||||||
from skyvern.forge.sdk.db.client import AgentDB
|
from skyvern.forge.sdk.db.client import AgentDB
|
||||||
from skyvern.forge.sdk.experimentation.providers import BaseExperimentationProvider, NoOpExperimentationProvider
|
from skyvern.forge.sdk.experimentation.providers import BaseExperimentationProvider, NoOpExperimentationProvider
|
||||||
from skyvern.forge.sdk.models import Organization
|
from skyvern.forge.sdk.models import Organization
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
from skyvern.forge.sdk.workflow.context_manager import WorkflowContextManager
|
from skyvern.forge.sdk.workflow.context_manager import WorkflowContextManager
|
||||||
from skyvern.forge.sdk.workflow.service import WorkflowService
|
from skyvern.forge.sdk.workflow.service import WorkflowService
|
||||||
from skyvern.webeye.browser_manager import BrowserManager
|
from skyvern.webeye.browser_manager import BrowserManager
|
||||||
from skyvern.webeye.scraper.scraper import ScrapeExcludeFunc
|
from skyvern.webeye.scraper.scraper import ScrapeExcludeFunc
|
||||||
|
|
||||||
SETTINGS_MANAGER = SettingsManager.get_settings()
|
SETTINGS_MANAGER = settings
|
||||||
DATABASE = AgentDB(
|
DATABASE = AgentDB(
|
||||||
SettingsManager.get_settings().DATABASE_STRING,
|
settings.DATABASE_STRING,
|
||||||
debug_enabled=SettingsManager.get_settings().DEBUG_MODE,
|
debug_enabled=settings.DEBUG_MODE,
|
||||||
)
|
)
|
||||||
if SettingsManager.get_settings().SKYVERN_STORAGE_TYPE == "s3":
|
if settings.SKYVERN_STORAGE_TYPE == "s3":
|
||||||
StorageFactory.set_storage(S3Storage())
|
StorageFactory.set_storage(S3Storage())
|
||||||
STORAGE = StorageFactory.get_storage()
|
STORAGE = StorageFactory.get_storage()
|
||||||
CACHE = CacheFactory.get_cache()
|
CACHE = CacheFactory.get_cache()
|
||||||
ARTIFACT_MANAGER = ArtifactManager()
|
ARTIFACT_MANAGER = ArtifactManager()
|
||||||
BROWSER_MANAGER = BrowserManager()
|
BROWSER_MANAGER = BrowserManager()
|
||||||
EXPERIMENTATION_PROVIDER: BaseExperimentationProvider = NoOpExperimentationProvider()
|
EXPERIMENTATION_PROVIDER: BaseExperimentationProvider = NoOpExperimentationProvider()
|
||||||
LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(SettingsManager.get_settings().LLM_KEY)
|
LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(settings.LLM_KEY)
|
||||||
SECONDARY_LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(
|
SECONDARY_LLM_API_HANDLER = LLMAPIHandlerFactory.get_llm_api_handler(
|
||||||
SETTINGS_MANAGER.SECONDARY_LLM_KEY if SETTINGS_MANAGER.SECONDARY_LLM_KEY else SETTINGS_MANAGER.LLM_KEY
|
SETTINGS_MANAGER.SECONDARY_LLM_KEY if SETTINGS_MANAGER.SECONDARY_LLM_KEY else SETTINGS_MANAGER.LLM_KEY
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import aioboto3
|
|||||||
import structlog
|
import structlog
|
||||||
from aiobotocore.client import AioBaseClient
|
from aiobotocore.client import AioBaseClient
|
||||||
|
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
from skyvern.config import settings
|
||||||
|
|
||||||
LOG = structlog.get_logger()
|
LOG = structlog.get_logger()
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ def execute_with_async_client(client_type: AWSClientType) -> Callable:
|
|||||||
self = args[0]
|
self = args[0]
|
||||||
assert isinstance(self, AsyncAWSClient)
|
assert isinstance(self, AsyncAWSClient)
|
||||||
session = aioboto3.Session()
|
session = aioboto3.Session()
|
||||||
async with session.client(client_type, region_name=SettingsManager.get_settings().AWS_REGION) as client:
|
async with session.client(client_type, region_name=settings.AWS_REGION) as client:
|
||||||
return await f(*args, client=client, **kwargs)
|
return await f(*args, client=client, **kwargs)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
@@ -95,7 +95,7 @@ class AsyncAWSClient:
|
|||||||
url = await client.generate_presigned_url(
|
url = await client.generate_presigned_url(
|
||||||
"get_object",
|
"get_object",
|
||||||
Params={"Bucket": parsed_uri.bucket, "Key": parsed_uri.key},
|
Params={"Bucket": parsed_uri.bucket, "Key": parsed_uri.key},
|
||||||
ExpiresIn=SettingsManager.get_settings().PRESIGNED_URL_EXPIRATION,
|
ExpiresIn=settings.PRESIGNED_URL_EXPIRATION,
|
||||||
)
|
)
|
||||||
presigned_urls.append(url)
|
presigned_urls.append(url)
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import aiohttp
|
|||||||
import structlog
|
import structlog
|
||||||
from multidict import CIMultiDictProxy
|
from multidict import CIMultiDictProxy
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.constants import REPO_ROOT_DIR
|
from skyvern.constants import REPO_ROOT_DIR
|
||||||
from skyvern.exceptions import DownloadFileMaxSizeExceeded
|
from skyvern.exceptions import DownloadFileMaxSizeExceeded
|
||||||
from skyvern.forge.sdk.api.aws import AsyncAWSClient
|
from skyvern.forge.sdk.api.aws import AsyncAWSClient
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
|
|
||||||
LOG = structlog.get_logger()
|
LOG = structlog.get_logger()
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ def create_folder_if_not_exist(dir: str) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def get_skyvern_temp_dir() -> str:
|
def get_skyvern_temp_dir() -> str:
|
||||||
temp_dir = SettingsManager.get_settings().TEMP_PATH
|
temp_dir = settings.TEMP_PATH
|
||||||
create_folder_if_not_exist(temp_dir)
|
create_folder_if_not_exist(temp_dir)
|
||||||
return temp_dir
|
return temp_dir
|
||||||
|
|
||||||
@@ -178,13 +178,13 @@ def make_temp_directory(
|
|||||||
suffix: str | None = None,
|
suffix: str | None = None,
|
||||||
prefix: str | None = None,
|
prefix: str | None = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
temp_dir = SettingsManager.get_settings().TEMP_PATH
|
temp_dir = settings.TEMP_PATH
|
||||||
create_folder_if_not_exist(temp_dir)
|
create_folder_if_not_exist(temp_dir)
|
||||||
return tempfile.mkdtemp(suffix=suffix, prefix=prefix, dir=temp_dir)
|
return tempfile.mkdtemp(suffix=suffix, prefix=prefix, dir=temp_dir)
|
||||||
|
|
||||||
|
|
||||||
def create_named_temporary_file(delete: bool = True) -> tempfile._TemporaryFileWrapper:
|
def create_named_temporary_file(delete: bool = True) -> tempfile._TemporaryFileWrapper:
|
||||||
temp_dir = SettingsManager.get_settings().TEMP_PATH
|
temp_dir = settings.TEMP_PATH
|
||||||
create_folder_if_not_exist(temp_dir)
|
create_folder_if_not_exist(temp_dir)
|
||||||
return tempfile.NamedTemporaryFile(dir=temp_dir, delete=delete)
|
return tempfile.NamedTemporaryFile(dir=temp_dir, delete=delete)
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from typing import Any
|
|||||||
import litellm
|
import litellm
|
||||||
import structlog
|
import structlog
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.forge import app
|
from skyvern.forge import app
|
||||||
from skyvern.forge.sdk.api.llm.config_registry import LLMConfigRegistry
|
from skyvern.forge.sdk.api.llm.config_registry import LLMConfigRegistry
|
||||||
from skyvern.forge.sdk.api.llm.exceptions import (
|
from skyvern.forge.sdk.api.llm.exceptions import (
|
||||||
@@ -19,7 +20,6 @@ from skyvern.forge.sdk.api.llm.models import LLMAPIHandler, LLMConfig, LLMRouter
|
|||||||
from skyvern.forge.sdk.api.llm.utils import llm_messages_builder, parse_api_response
|
from skyvern.forge.sdk.api.llm.utils import llm_messages_builder, parse_api_response
|
||||||
from skyvern.forge.sdk.artifact.models import ArtifactType
|
from skyvern.forge.sdk.artifact.models import ArtifactType
|
||||||
from skyvern.forge.sdk.models import Step
|
from skyvern.forge.sdk.models import Step
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
|
|
||||||
LOG = structlog.get_logger()
|
LOG = structlog.get_logger()
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ class LLMAPIHandlerFactory:
|
|||||||
allowed_fails=llm_config.allowed_fails,
|
allowed_fails=llm_config.allowed_fails,
|
||||||
allowed_fails_policy=llm_config.allowed_fails_policy,
|
allowed_fails_policy=llm_config.allowed_fails_policy,
|
||||||
cooldown_time=llm_config.cooldown_time,
|
cooldown_time=llm_config.cooldown_time,
|
||||||
set_verbose=(False if SettingsManager.get_settings().is_cloud_environment() else llm_config.set_verbose),
|
set_verbose=(False if settings.is_cloud_environment() else llm_config.set_verbose),
|
||||||
enable_pre_call_checks=True,
|
enable_pre_call_checks=True,
|
||||||
)
|
)
|
||||||
main_model_group = llm_config.main_model_group
|
main_model_group = llm_config.main_model_group
|
||||||
@@ -213,7 +213,7 @@ class LLMAPIHandlerFactory:
|
|||||||
response = await litellm.acompletion(
|
response = await litellm.acompletion(
|
||||||
model=llm_config.model_name,
|
model=llm_config.model_name,
|
||||||
messages=messages,
|
messages=messages,
|
||||||
timeout=SettingsManager.get_settings().LLM_CONFIG_TIMEOUT,
|
timeout=settings.LLM_CONFIG_TIMEOUT,
|
||||||
**active_parameters,
|
**active_parameters,
|
||||||
)
|
)
|
||||||
LOG.info("LLM API call successful", llm_key=llm_key, model=llm_config.model_name)
|
LOG.info("LLM API call successful", llm_key=llm_key, model=llm_config.model_name)
|
||||||
@@ -263,7 +263,7 @@ class LLMAPIHandlerFactory:
|
|||||||
def get_api_parameters(llm_config: LLMConfig | LLMRouterConfig) -> dict[str, Any]:
|
def get_api_parameters(llm_config: LLMConfig | LLMRouterConfig) -> dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
"max_tokens": llm_config.max_output_tokens,
|
"max_tokens": llm_config.max_output_tokens,
|
||||||
"temperature": SettingsManager.get_settings().LLM_CONFIG_TEMPERATURE,
|
"temperature": settings.LLM_CONFIG_TEMPERATURE,
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import structlog
|
import structlog
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.forge.sdk.api.llm.exceptions import (
|
from skyvern.forge.sdk.api.llm.exceptions import (
|
||||||
DuplicateLLMConfigError,
|
DuplicateLLMConfigError,
|
||||||
InvalidLLMConfigError,
|
InvalidLLMConfigError,
|
||||||
@@ -7,7 +8,6 @@ from skyvern.forge.sdk.api.llm.exceptions import (
|
|||||||
NoProviderEnabledError,
|
NoProviderEnabledError,
|
||||||
)
|
)
|
||||||
from skyvern.forge.sdk.api.llm.models import LiteLLMParams, LLMConfig, LLMRouterConfig
|
from skyvern.forge.sdk.api.llm.models import LiteLLMParams, LLMConfig, LLMRouterConfig
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
|
|
||||||
LOG = structlog.get_logger()
|
LOG = structlog.get_logger()
|
||||||
|
|
||||||
@@ -46,17 +46,17 @@ class LLMConfigRegistry:
|
|||||||
# if none of the LLM providers are enabled, raise an error
|
# if none of the LLM providers are enabled, raise an error
|
||||||
if not any(
|
if not any(
|
||||||
[
|
[
|
||||||
SettingsManager.get_settings().ENABLE_OPENAI,
|
settings.ENABLE_OPENAI,
|
||||||
SettingsManager.get_settings().ENABLE_ANTHROPIC,
|
settings.ENABLE_ANTHROPIC,
|
||||||
SettingsManager.get_settings().ENABLE_AZURE,
|
settings.ENABLE_AZURE,
|
||||||
SettingsManager.get_settings().ENABLE_AZURE_GPT4O_MINI,
|
settings.ENABLE_AZURE_GPT4O_MINI,
|
||||||
SettingsManager.get_settings().ENABLE_BEDROCK,
|
settings.ENABLE_BEDROCK,
|
||||||
]
|
]
|
||||||
):
|
):
|
||||||
raise NoProviderEnabledError()
|
raise NoProviderEnabledError()
|
||||||
|
|
||||||
|
|
||||||
if SettingsManager.get_settings().ENABLE_OPENAI:
|
if settings.ENABLE_OPENAI:
|
||||||
LLMConfigRegistry.register_config(
|
LLMConfigRegistry.register_config(
|
||||||
"OPENAI_GPT4_TURBO",
|
"OPENAI_GPT4_TURBO",
|
||||||
LLMConfig(
|
LLMConfig(
|
||||||
@@ -103,7 +103,7 @@ if SettingsManager.get_settings().ENABLE_OPENAI:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if SettingsManager.get_settings().ENABLE_ANTHROPIC:
|
if settings.ENABLE_ANTHROPIC:
|
||||||
LLMConfigRegistry.register_config(
|
LLMConfigRegistry.register_config(
|
||||||
"ANTHROPIC_CLAUDE3",
|
"ANTHROPIC_CLAUDE3",
|
||||||
LLMConfig(
|
LLMConfig(
|
||||||
@@ -151,7 +151,7 @@ if SettingsManager.get_settings().ENABLE_ANTHROPIC:
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
if SettingsManager.get_settings().ENABLE_BEDROCK:
|
if settings.ENABLE_BEDROCK:
|
||||||
# Supported through AWS IAM authentication
|
# Supported through AWS IAM authentication
|
||||||
LLMConfigRegistry.register_config(
|
LLMConfigRegistry.register_config(
|
||||||
"BEDROCK_ANTHROPIC_CLAUDE3_OPUS",
|
"BEDROCK_ANTHROPIC_CLAUDE3_OPUS",
|
||||||
@@ -209,11 +209,11 @@ if SettingsManager.get_settings().ENABLE_BEDROCK:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if SettingsManager.get_settings().ENABLE_AZURE:
|
if settings.ENABLE_AZURE:
|
||||||
LLMConfigRegistry.register_config(
|
LLMConfigRegistry.register_config(
|
||||||
"AZURE_OPENAI",
|
"AZURE_OPENAI",
|
||||||
LLMConfig(
|
LLMConfig(
|
||||||
f"azure/{SettingsManager.get_settings().AZURE_DEPLOYMENT}",
|
f"azure/{settings.AZURE_DEPLOYMENT}",
|
||||||
[
|
[
|
||||||
"AZURE_DEPLOYMENT",
|
"AZURE_DEPLOYMENT",
|
||||||
"AZURE_API_KEY",
|
"AZURE_API_KEY",
|
||||||
@@ -225,11 +225,11 @@ if SettingsManager.get_settings().ENABLE_AZURE:
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
if SettingsManager.get_settings().ENABLE_AZURE_GPT4O_MINI:
|
if settings.ENABLE_AZURE_GPT4O_MINI:
|
||||||
LLMConfigRegistry.register_config(
|
LLMConfigRegistry.register_config(
|
||||||
"AZURE_OPENAI_GPT4O_MINI",
|
"AZURE_OPENAI_GPT4O_MINI",
|
||||||
LLMConfig(
|
LLMConfig(
|
||||||
f"azure/{SettingsManager.get_settings().AZURE_GPT4O_MINI_DEPLOYMENT}",
|
f"azure/{settings.AZURE_GPT4O_MINI_DEPLOYMENT}",
|
||||||
[
|
[
|
||||||
"AZURE_GPT4O_MINI_DEPLOYMENT",
|
"AZURE_GPT4O_MINI_DEPLOYMENT",
|
||||||
"AZURE_GPT4O_MINI_API_KEY",
|
"AZURE_GPT4O_MINI_API_KEY",
|
||||||
@@ -237,9 +237,9 @@ if SettingsManager.get_settings().ENABLE_AZURE_GPT4O_MINI:
|
|||||||
"AZURE_GPT4O_MINI_API_VERSION",
|
"AZURE_GPT4O_MINI_API_VERSION",
|
||||||
],
|
],
|
||||||
litellm_params=LiteLLMParams(
|
litellm_params=LiteLLMParams(
|
||||||
api_base=SettingsManager.get_settings().AZURE_GPT4O_MINI_API_BASE,
|
api_base=settings.AZURE_GPT4O_MINI_API_BASE,
|
||||||
api_key=SettingsManager.get_settings().AZURE_GPT4O_MINI_API_KEY,
|
api_key=settings.AZURE_GPT4O_MINI_API_KEY,
|
||||||
api_version=SettingsManager.get_settings().AZURE_GPT4O_MINI_API_VERSION,
|
api_version=settings.AZURE_GPT4O_MINI_API_VERSION,
|
||||||
model_info={"model_name": "azure/gpt-4o-mini"},
|
model_info={"model_name": "azure/gpt-4o-mini"},
|
||||||
),
|
),
|
||||||
supports_vision=True,
|
supports_vision=True,
|
||||||
|
|||||||
@@ -6,17 +6,17 @@ from urllib.parse import unquote, urlparse
|
|||||||
|
|
||||||
import structlog
|
import structlog
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.forge.sdk.api.files import get_download_dir, get_skyvern_temp_dir
|
from skyvern.forge.sdk.api.files import get_download_dir, get_skyvern_temp_dir
|
||||||
from skyvern.forge.sdk.artifact.models import Artifact, ArtifactType
|
from skyvern.forge.sdk.artifact.models import Artifact, ArtifactType
|
||||||
from skyvern.forge.sdk.artifact.storage.base import FILE_EXTENTSION_MAP, BaseStorage
|
from skyvern.forge.sdk.artifact.storage.base import FILE_EXTENTSION_MAP, BaseStorage
|
||||||
from skyvern.forge.sdk.models import Step
|
from skyvern.forge.sdk.models import Step
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
|
|
||||||
LOG = structlog.get_logger()
|
LOG = structlog.get_logger()
|
||||||
|
|
||||||
|
|
||||||
class LocalStorage(BaseStorage):
|
class LocalStorage(BaseStorage):
|
||||||
def __init__(self, artifact_path: str = SettingsManager.get_settings().ARTIFACT_STORAGE_PATH) -> None:
|
def __init__(self, artifact_path: str = settings.ARTIFACT_STORAGE_PATH) -> None:
|
||||||
self.artifact_path = artifact_path
|
self.artifact_path = artifact_path
|
||||||
|
|
||||||
def build_uri(self, artifact_id: str, step: Step, artifact_type: ArtifactType) -> str:
|
def build_uri(self, artifact_id: str, step: Step, artifact_type: ArtifactType) -> str:
|
||||||
@@ -84,9 +84,7 @@ class LocalStorage(BaseStorage):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
async def store_browser_session(self, organization_id: str, workflow_permanent_id: str, directory: str) -> None:
|
async def store_browser_session(self, organization_id: str, workflow_permanent_id: str, directory: str) -> None:
|
||||||
stored_folder_path = (
|
stored_folder_path = Path(settings.BROWSER_SESSION_BASE_PATH) / organization_id / workflow_permanent_id
|
||||||
Path(SettingsManager.get_settings().BROWSER_SESSION_BASE_PATH) / organization_id / workflow_permanent_id
|
|
||||||
)
|
|
||||||
if directory == str(stored_folder_path):
|
if directory == str(stored_folder_path):
|
||||||
return
|
return
|
||||||
self._create_directories_if_not_exists(stored_folder_path)
|
self._create_directories_if_not_exists(stored_folder_path)
|
||||||
@@ -108,9 +106,7 @@ class LocalStorage(BaseStorage):
|
|||||||
shutil.copy2(source_file_path, target_file_path)
|
shutil.copy2(source_file_path, target_file_path)
|
||||||
|
|
||||||
async def retrieve_browser_session(self, organization_id: str, workflow_permanent_id: str) -> str | None:
|
async def retrieve_browser_session(self, organization_id: str, workflow_permanent_id: str) -> str | None:
|
||||||
stored_folder_path = (
|
stored_folder_path = Path(settings.BROWSER_SESSION_BASE_PATH) / organization_id / workflow_permanent_id
|
||||||
Path(SettingsManager.get_settings().BROWSER_SESSION_BASE_PATH) / organization_id / workflow_permanent_id
|
|
||||||
)
|
|
||||||
if not stored_folder_path.exists():
|
if not stored_folder_path.exists():
|
||||||
return None
|
return None
|
||||||
return str(stored_folder_path)
|
return str(stored_folder_path)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from typing import Any, Union
|
|||||||
|
|
||||||
from jose import jwt
|
from jose import jwt
|
||||||
|
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
from skyvern.config import settings
|
||||||
|
|
||||||
|
|
||||||
def create_access_token(
|
def create_access_token(
|
||||||
@@ -16,13 +16,13 @@ def create_access_token(
|
|||||||
expire = datetime.utcnow() + expires_delta
|
expire = datetime.utcnow() + expires_delta
|
||||||
else:
|
else:
|
||||||
expire = datetime.utcnow() + timedelta(
|
expire = datetime.utcnow() + timedelta(
|
||||||
minutes=SettingsManager.get_settings().ACCESS_TOKEN_EXPIRE_MINUTES,
|
minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES,
|
||||||
)
|
)
|
||||||
to_encode = {"exp": expire, "sub": str(subject)}
|
to_encode = {"exp": expire, "sub": str(subject)}
|
||||||
encoded_jwt = jwt.encode(
|
encoded_jwt = jwt.encode(
|
||||||
to_encode,
|
to_encode,
|
||||||
SettingsManager.get_settings().SECRET_KEY,
|
settings.SECRET_KEY,
|
||||||
algorithm=SettingsManager.get_settings().SIGNATURE_ALGORITHM,
|
algorithm=settings.SIGNATURE_ALGORITHM,
|
||||||
)
|
)
|
||||||
return encoded_jwt
|
return encoded_jwt
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import logging
|
|||||||
import structlog
|
import structlog
|
||||||
from structlog.typing import EventDict
|
from structlog.typing import EventDict
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.forge.sdk.core import skyvern_context
|
from skyvern.forge.sdk.core import skyvern_context
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
|
|
||||||
LOGGING_LEVEL_MAP: dict[str, int] = {
|
LOGGING_LEVEL_MAP: dict[str, int] = {
|
||||||
"DEBUG": logging.DEBUG,
|
"DEBUG": logging.DEBUG,
|
||||||
@@ -34,7 +34,7 @@ def add_kv_pairs_to_msg(logger: logging.Logger, method_name: str, event_dict: Ev
|
|||||||
event_dict["workflow_run_id"] = context.workflow_run_id
|
event_dict["workflow_run_id"] = context.workflow_run_id
|
||||||
|
|
||||||
# Add env to the log
|
# Add env to the log
|
||||||
event_dict["env"] = SettingsManager.get_settings().ENV
|
event_dict["env"] = settings.ENV
|
||||||
|
|
||||||
if method_name not in ["info", "warning", "error", "critical", "exception"]:
|
if method_name not in ["info", "warning", "error", "critical", "exception"]:
|
||||||
# Only modify the log for these log levels
|
# Only modify the log for these log levels
|
||||||
@@ -59,11 +59,7 @@ def setup_logger() -> None:
|
|||||||
Setup the logger with the specified format
|
Setup the logger with the specified format
|
||||||
"""
|
"""
|
||||||
# logging.config.dictConfig(logging_config)
|
# logging.config.dictConfig(logging_config)
|
||||||
renderer = (
|
renderer = structlog.processors.JSONRenderer() if settings.JSON_LOGGING else structlog.dev.ConsoleRenderer()
|
||||||
structlog.processors.JSONRenderer()
|
|
||||||
if SettingsManager.get_settings().JSON_LOGGING
|
|
||||||
else structlog.dev.ConsoleRenderer()
|
|
||||||
)
|
|
||||||
additional_processors = (
|
additional_processors = (
|
||||||
[
|
[
|
||||||
structlog.processors.EventRenamer("msg"),
|
structlog.processors.EventRenamer("msg"),
|
||||||
@@ -78,10 +74,10 @@ def setup_logger() -> None:
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
if SettingsManager.get_settings().JSON_LOGGING
|
if settings.JSON_LOGGING
|
||||||
else []
|
else []
|
||||||
)
|
)
|
||||||
LOG_LEVEL_VAL = LOGGING_LEVEL_MAP.get(SettingsManager.get_settings().LOG_LEVEL, logging.INFO)
|
LOG_LEVEL_VAL = LOGGING_LEVEL_MAP.get(settings.LOG_LEVEL, logging.INFO)
|
||||||
|
|
||||||
structlog.configure(
|
structlog.configure(
|
||||||
wrapper_class=structlog.make_filtering_bound_logger(LOG_LEVEL_VAL),
|
wrapper_class=structlog.make_filtering_bound_logger(LOG_LEVEL_VAL),
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from pydantic import BaseModel
|
|||||||
from sqlalchemy.exc import OperationalError
|
from sqlalchemy.exc import OperationalError
|
||||||
|
|
||||||
from skyvern import analytics
|
from skyvern import analytics
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.exceptions import StepNotFound
|
from skyvern.exceptions import StepNotFound
|
||||||
from skyvern.forge import app
|
from skyvern.forge import app
|
||||||
from skyvern.forge.prompts import prompt_engine
|
from skyvern.forge.prompts import prompt_engine
|
||||||
@@ -50,7 +51,6 @@ from skyvern.forge.sdk.schemas.tasks import (
|
|||||||
TaskStatus,
|
TaskStatus,
|
||||||
)
|
)
|
||||||
from skyvern.forge.sdk.services import org_auth_service
|
from skyvern.forge.sdk.services import org_auth_service
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
from skyvern.forge.sdk.workflow.exceptions import (
|
from skyvern.forge.sdk.workflow.exceptions import (
|
||||||
FailedToCreateWorkflow,
|
FailedToCreateWorkflow,
|
||||||
FailedToUpdateWorkflow,
|
FailedToUpdateWorkflow,
|
||||||
@@ -95,7 +95,7 @@ async def webhook(
|
|||||||
|
|
||||||
generated_signature = generate_skyvern_signature(
|
generated_signature = generate_skyvern_signature(
|
||||||
payload.decode("utf-8"),
|
payload.decode("utf-8"),
|
||||||
SettingsManager.get_settings().SKYVERN_API_KEY,
|
settings.SKYVERN_API_KEY,
|
||||||
)
|
)
|
||||||
|
|
||||||
LOG.info(
|
LOG.info(
|
||||||
@@ -291,7 +291,7 @@ async def get_task(
|
|||||||
task_id=task_obj.task_id,
|
task_id=task_obj.task_id,
|
||||||
organization_id=task_obj.organization_id,
|
organization_id=task_obj.organization_id,
|
||||||
artifact_types=[ArtifactType.SCREENSHOT_ACTION],
|
artifact_types=[ArtifactType.SCREENSHOT_ACTION],
|
||||||
n=SettingsManager.get_settings().TASK_RESPONSE_ACTION_SCREENSHOT_COUNT,
|
n=settings.TASK_RESPONSE_ACTION_SCREENSHOT_COUNT,
|
||||||
)
|
)
|
||||||
latest_action_screenshot_urls: list[str] | None = None
|
latest_action_screenshot_urls: list[str] | None = None
|
||||||
if latest_action_screenshot_artifacts:
|
if latest_action_screenshot_artifacts:
|
||||||
@@ -532,7 +532,7 @@ async def get_agent_task_step_artifacts(
|
|||||||
step_id,
|
step_id,
|
||||||
organization_id=current_org.organization_id,
|
organization_id=current_org.organization_id,
|
||||||
)
|
)
|
||||||
if SettingsManager.get_settings().ENV != "local" or SettingsManager.get_settings().GENERATE_PRESIGNED_URLS:
|
if settings.ENV != "local" or settings.GENERATE_PRESIGNED_URLS:
|
||||||
signed_urls = await app.ARTIFACT_MANAGER.get_share_links(artifacts)
|
signed_urls = await app.ARTIFACT_MANAGER.get_share_links(artifacts)
|
||||||
if signed_urls:
|
if signed_urls:
|
||||||
for i, artifact in enumerate(artifacts):
|
for i, artifact in enumerate(artifacts):
|
||||||
@@ -863,7 +863,7 @@ async def generate_task(
|
|||||||
# check if there's a same user_prompt within the past x Hours
|
# check if there's a same user_prompt within the past x Hours
|
||||||
# in the future, we can use vector db to fetch similar prompts
|
# in the future, we can use vector db to fetch similar prompts
|
||||||
existing_task_generation = await app.DATABASE.get_task_generation_by_prompt_hash(
|
existing_task_generation = await app.DATABASE.get_task_generation_by_prompt_hash(
|
||||||
user_prompt_hash=user_prompt_hash, query_window_hours=SettingsManager.get_settings().PROMPT_CACHE_WINDOW_HOURS
|
user_prompt_hash=user_prompt_hash, query_window_hours=settings.PROMPT_CACHE_WINDOW_HOURS
|
||||||
)
|
)
|
||||||
if existing_task_generation:
|
if existing_task_generation:
|
||||||
new_task_generation = await app.DATABASE.create_task_generation(
|
new_task_generation = await app.DATABASE.create_task_generation(
|
||||||
@@ -898,7 +898,7 @@ async def generate_task(
|
|||||||
data_extraction_goal=parsed_task_generation_obj.data_extraction_goal,
|
data_extraction_goal=parsed_task_generation_obj.data_extraction_goal,
|
||||||
extracted_information_schema=parsed_task_generation_obj.extracted_information_schema,
|
extracted_information_schema=parsed_task_generation_obj.extracted_information_schema,
|
||||||
suggested_title=parsed_task_generation_obj.suggested_title,
|
suggested_title=parsed_task_generation_obj.suggested_title,
|
||||||
llm=SettingsManager.get_settings().LLM_KEY,
|
llm=settings.LLM_KEY,
|
||||||
llm_prompt=llm_prompt,
|
llm_prompt=llm_prompt,
|
||||||
llm_response=str(llm_response),
|
llm_response=str(llm_response),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ from jose import jwt
|
|||||||
from jose.exceptions import JWTError
|
from jose.exceptions import JWTError
|
||||||
from pydantic import ValidationError
|
from pydantic import ValidationError
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.forge import app
|
from skyvern.forge import app
|
||||||
from skyvern.forge.sdk.core import skyvern_context
|
from skyvern.forge.sdk.core import skyvern_context
|
||||||
from skyvern.forge.sdk.db.client import AgentDB
|
from skyvern.forge.sdk.db.client import AgentDB
|
||||||
from skyvern.forge.sdk.models import Organization, OrganizationAuthTokenType, TokenPayload
|
from skyvern.forge.sdk.models import Organization, OrganizationAuthTokenType, TokenPayload
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
|
|
||||||
AUTHENTICATION_TTL = 60 * 60 # one hour
|
AUTHENTICATION_TTL = 60 * 60 # one hour
|
||||||
CACHE_SIZE = 128
|
CACHE_SIZE = 128
|
||||||
@@ -85,7 +85,7 @@ async def _get_current_org_cached(x_api_key: str, db: AgentDB) -> Organization:
|
|||||||
try:
|
try:
|
||||||
payload = jwt.decode(
|
payload = jwt.decode(
|
||||||
x_api_key,
|
x_api_key,
|
||||||
SettingsManager.get_settings().SECRET_KEY,
|
settings.SECRET_KEY,
|
||||||
algorithms=[ALGORITHM],
|
algorithms=[ALGORITHM],
|
||||||
)
|
)
|
||||||
api_key_data = TokenPayload(**payload)
|
api_key_data = TokenPayload(**payload)
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ from skyvern.forge.sdk.api.files import (
|
|||||||
from skyvern.forge.sdk.api.llm.api_handler_factory import LLMAPIHandlerFactory
|
from skyvern.forge.sdk.api.llm.api_handler_factory import LLMAPIHandlerFactory
|
||||||
from skyvern.forge.sdk.db.enums import TaskType
|
from skyvern.forge.sdk.db.enums import TaskType
|
||||||
from skyvern.forge.sdk.schemas.tasks import Task, TaskOutput, TaskStatus
|
from skyvern.forge.sdk.schemas.tasks import Task, TaskOutput, TaskStatus
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
from skyvern.forge.sdk.workflow.context_manager import WorkflowRunContext
|
from skyvern.forge.sdk.workflow.context_manager import WorkflowRunContext
|
||||||
from skyvern.forge.sdk.workflow.exceptions import (
|
from skyvern.forge.sdk.workflow.exceptions import (
|
||||||
InvalidEmailClientConfiguration,
|
InvalidEmailClientConfiguration,
|
||||||
@@ -376,8 +375,8 @@ class BaseTaskBlock(Block):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
browser_state = app.BROWSER_MANAGER.get_for_workflow_run(workflow_run_id=workflow_run_id)
|
browser_state = app.BROWSER_MANAGER.get_for_workflow_run(workflow_run_id=workflow_run_id)
|
||||||
if browser_state is None:
|
if browser_state is None:
|
||||||
raise MissingBrowserState(task_id=task.task_id, workflow_run_id=workflow_run_id)
|
raise MissingBrowserState(task_id=task.task_id, workflow_run_id=workflow_run_id)
|
||||||
except FailedToNavigateToUrl as e:
|
except FailedToNavigateToUrl as e:
|
||||||
# Make sure the task is marked as failed in the database before raising the exception
|
# Make sure the task is marked as failed in the database before raising the exception
|
||||||
await app.DATABASE.update_task(
|
await app.DATABASE.update_task(
|
||||||
@@ -982,7 +981,7 @@ class DownloadToS3Block(Block):
|
|||||||
|
|
||||||
uri = None
|
uri = None
|
||||||
try:
|
try:
|
||||||
uri = f"s3://{SettingsManager.get_settings().AWS_S3_BUCKET_UPLOADS}/{SettingsManager.get_settings().ENV}/{workflow_run_id}/{uuid.uuid4()}"
|
uri = f"s3://{settings.AWS_S3_BUCKET_UPLOADS}/{settings.ENV}/{workflow_run_id}/{uuid.uuid4()}"
|
||||||
await self._upload_file_to_s3(uri, file_path)
|
await self._upload_file_to_s3(uri, file_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error("DownloadToS3Block: Failed to upload file to S3", uri=uri, error=str(e))
|
LOG.error("DownloadToS3Block: Failed to upload file to S3", uri=uri, error=str(e))
|
||||||
@@ -1019,8 +1018,8 @@ class UploadToS3Block(Block):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_s3_uri(workflow_run_id: str, path: str) -> str:
|
def _get_s3_uri(workflow_run_id: str, path: str) -> str:
|
||||||
s3_bucket = SettingsManager.get_settings().AWS_S3_BUCKET_UPLOADS
|
s3_bucket = settings.AWS_S3_BUCKET_UPLOADS
|
||||||
s3_key = f"{SettingsManager.get_settings().ENV}/{workflow_run_id}/{uuid.uuid4()}_{Path(path).name}"
|
s3_key = f"{settings.ENV}/{workflow_run_id}/{uuid.uuid4()}_{Path(path).name}"
|
||||||
return f"s3://{s3_bucket}/{s3_key}"
|
return f"s3://{s3_bucket}/{s3_key}"
|
||||||
|
|
||||||
async def execute(self, workflow_run_id: str, **kwargs: dict) -> BlockResult:
|
async def execute(self, workflow_run_id: str, **kwargs: dict) -> BlockResult:
|
||||||
@@ -1037,7 +1036,7 @@ class UploadToS3Block(Block):
|
|||||||
)
|
)
|
||||||
self.path = file_path_parameter_value
|
self.path = file_path_parameter_value
|
||||||
# if the path is WORKFLOW_DOWNLOAD_DIRECTORY_PARAMETER_KEY, use the download directory for the workflow run
|
# if the path is WORKFLOW_DOWNLOAD_DIRECTORY_PARAMETER_KEY, use the download directory for the workflow run
|
||||||
elif self.path == SettingsManager.get_settings().WORKFLOW_DOWNLOAD_DIRECTORY_PARAMETER_KEY:
|
elif self.path == settings.WORKFLOW_DOWNLOAD_DIRECTORY_PARAMETER_KEY:
|
||||||
self.path = str(get_path_for_workflow_download_directory(workflow_run_id).absolute())
|
self.path = str(get_path_for_workflow_download_directory(workflow_run_id).absolute())
|
||||||
|
|
||||||
self.format_potential_template_parameters(workflow_run_context)
|
self.format_potential_template_parameters(workflow_run_context)
|
||||||
@@ -1173,7 +1172,7 @@ class SendEmailBlock(Block):
|
|||||||
else:
|
else:
|
||||||
path = file_path_parameter_value
|
path = file_path_parameter_value
|
||||||
|
|
||||||
if path == SettingsManager.get_settings().WORKFLOW_DOWNLOAD_DIRECTORY_PARAMETER_KEY:
|
if path == settings.WORKFLOW_DOWNLOAD_DIRECTORY_PARAMETER_KEY:
|
||||||
# if the path is WORKFLOW_DOWNLOAD_DIRECTORY_PARAMETER_KEY, use download directory for the workflow run
|
# if the path is WORKFLOW_DOWNLOAD_DIRECTORY_PARAMETER_KEY, use download directory for the workflow run
|
||||||
path = str(get_path_for_workflow_download_directory(workflow_run_id).absolute())
|
path = str(get_path_for_workflow_download_directory(workflow_run_id).absolute())
|
||||||
LOG.info(
|
LOG.info(
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import httpx
|
|||||||
import structlog
|
import structlog
|
||||||
|
|
||||||
from skyvern import analytics
|
from skyvern import analytics
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.constants import GET_DOWNLOADED_FILES_TIMEOUT, SAVE_DOWNLOADED_FILES_TIMEOUT
|
from skyvern.constants import GET_DOWNLOADED_FILES_TIMEOUT, SAVE_DOWNLOADED_FILES_TIMEOUT
|
||||||
from skyvern.exceptions import (
|
from skyvern.exceptions import (
|
||||||
FailedToSendWebhook,
|
FailedToSendWebhook,
|
||||||
@@ -23,7 +24,6 @@ from skyvern.forge.sdk.core.skyvern_context import SkyvernContext
|
|||||||
from skyvern.forge.sdk.db.enums import TaskType
|
from skyvern.forge.sdk.db.enums import TaskType
|
||||||
from skyvern.forge.sdk.models import Organization, Step
|
from skyvern.forge.sdk.models import Organization, Step
|
||||||
from skyvern.forge.sdk.schemas.tasks import ProxyLocation, Task
|
from skyvern.forge.sdk.schemas.tasks import ProxyLocation, Task
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
from skyvern.forge.sdk.workflow.exceptions import (
|
from skyvern.forge.sdk.workflow.exceptions import (
|
||||||
ContextParameterSourceNotDefined,
|
ContextParameterSourceNotDefined,
|
||||||
InvalidWaitBlockTime,
|
InvalidWaitBlockTime,
|
||||||
@@ -1508,11 +1508,8 @@ class WorkflowService:
|
|||||||
)
|
)
|
||||||
|
|
||||||
elif block_yaml.block_type == BlockType.WAIT:
|
elif block_yaml.block_type == BlockType.WAIT:
|
||||||
if (
|
if block_yaml.wait_sec <= 0 or block_yaml.wait_sec > settings.WORKFLOW_WAIT_BLOCK_MAX_SEC:
|
||||||
block_yaml.wait_sec <= 0
|
raise InvalidWaitBlockTime(settings.WORKFLOW_WAIT_BLOCK_MAX_SEC)
|
||||||
or block_yaml.wait_sec > SettingsManager.get_settings().WORKFLOW_WAIT_BLOCK_MAX_SEC
|
|
||||||
):
|
|
||||||
raise InvalidWaitBlockTime(SettingsManager.get_settings().WORKFLOW_WAIT_BLOCK_MAX_SEC)
|
|
||||||
|
|
||||||
return WaitBlock(
|
return WaitBlock(
|
||||||
label=block_yaml.label,
|
label=block_yaml.label,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import structlog
|
|||||||
from playwright.async_api import FileChooser, Frame, Locator, Page, TimeoutError
|
from playwright.async_api import FileChooser, Frame, Locator, Page, TimeoutError
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.constants import REPO_ROOT_DIR, SKYVERN_ID_ATTR
|
from skyvern.constants import REPO_ROOT_DIR, SKYVERN_ID_ATTR
|
||||||
from skyvern.exceptions import (
|
from skyvern.exceptions import (
|
||||||
EmptySelect,
|
EmptySelect,
|
||||||
@@ -52,7 +53,6 @@ from skyvern.forge.sdk.db.enums import OrganizationAuthTokenType
|
|||||||
from skyvern.forge.sdk.models import Step
|
from skyvern.forge.sdk.models import Step
|
||||||
from skyvern.forge.sdk.schemas.tasks import Task
|
from skyvern.forge.sdk.schemas.tasks import Task
|
||||||
from skyvern.forge.sdk.services.bitwarden import BitwardenConstants
|
from skyvern.forge.sdk.services.bitwarden import BitwardenConstants
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
from skyvern.webeye.actions import actions
|
from skyvern.webeye.actions import actions
|
||||||
from skyvern.webeye.actions.actions import (
|
from skyvern.webeye.actions.actions import (
|
||||||
Action,
|
Action,
|
||||||
@@ -371,7 +371,7 @@ async def handle_click_action(
|
|||||||
page,
|
page,
|
||||||
action,
|
action,
|
||||||
skyvern_element,
|
skyvern_element,
|
||||||
timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout=settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
)
|
)
|
||||||
|
|
||||||
if results and task.workflow_run_id and download_dir:
|
if results and task.workflow_run_id and download_dir:
|
||||||
@@ -400,8 +400,8 @@ async def handle_click_to_download_file_action(
|
|||||||
locator = skyvern_element.locator
|
locator = skyvern_element.locator
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await locator.click(timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS)
|
await locator.click(timeout=settings.BROWSER_ACTION_TIMEOUT_MS)
|
||||||
await page.wait_for_load_state(timeout=SettingsManager.get_settings().BROWSER_LOADING_TIMEOUT_MS)
|
await page.wait_for_load_state(timeout=settings.BROWSER_LOADING_TIMEOUT_MS)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.exception("ClickAction with download failed", action=action, exc_info=True)
|
LOG.exception("ClickAction with download failed", action=action, exc_info=True)
|
||||||
return [ActionFailure(e, download_triggered=False)]
|
return [ActionFailure(e, download_triggered=False)]
|
||||||
@@ -420,7 +420,7 @@ async def handle_input_text_action(
|
|||||||
skyvern_element = await dom.get_skyvern_element_by_id(action.element_id)
|
skyvern_element = await dom.get_skyvern_element_by_id(action.element_id)
|
||||||
skyvern_frame = await SkyvernFrame.create_instance(skyvern_element.get_frame())
|
skyvern_frame = await SkyvernFrame.create_instance(skyvern_element.get_frame())
|
||||||
incremental_scraped = IncrementalScrapePage(skyvern_frame=skyvern_frame)
|
incremental_scraped = IncrementalScrapePage(skyvern_frame=skyvern_frame)
|
||||||
timeout = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
timeout = settings.BROWSER_ACTION_TIMEOUT_MS
|
||||||
|
|
||||||
current_text = await get_input_value(skyvern_element.get_tag_name(), skyvern_element.get_locator())
|
current_text = await get_input_value(skyvern_element.get_tag_name(), skyvern_element.get_locator())
|
||||||
if current_text == action.text:
|
if current_text == action.text:
|
||||||
@@ -656,7 +656,7 @@ async def handle_upload_file_action(
|
|||||||
if file_path:
|
if file_path:
|
||||||
await locator.set_input_files(
|
await locator.set_input_files(
|
||||||
file_path,
|
file_path,
|
||||||
timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout=settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Sleep for 10 seconds after uploading a file to let the page process it
|
# Sleep for 10 seconds after uploading a file to let the page process it
|
||||||
@@ -675,7 +675,7 @@ async def handle_upload_file_action(
|
|||||||
page,
|
page,
|
||||||
action,
|
action,
|
||||||
skyvern_element,
|
skyvern_element,
|
||||||
timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout=settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -699,7 +699,7 @@ async def handle_download_file_action(
|
|||||||
|
|
||||||
locator = skyvern_element.locator
|
locator = skyvern_element.locator
|
||||||
await locator.click(
|
await locator.click(
|
||||||
timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout=settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
modifiers=["Alt"],
|
modifiers=["Alt"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -847,7 +847,7 @@ async def handle_select_option_action(
|
|||||||
action=action,
|
action=action,
|
||||||
)
|
)
|
||||||
|
|
||||||
timeout = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
timeout = settings.BROWSER_ACTION_TIMEOUT_MS
|
||||||
skyvern_frame = await SkyvernFrame.create_instance(skyvern_element.get_frame())
|
skyvern_frame = await SkyvernFrame.create_instance(skyvern_element.get_frame())
|
||||||
incremental_scraped = IncrementalScrapePage(skyvern_frame=skyvern_frame)
|
incremental_scraped = IncrementalScrapePage(skyvern_frame=skyvern_frame)
|
||||||
is_open = False
|
is_open = False
|
||||||
@@ -935,7 +935,7 @@ async def handle_select_option_action(
|
|||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
await incremental_scraped.start_listen_dom_increment()
|
await incremental_scraped.start_listen_dom_increment()
|
||||||
timeout = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
timeout = settings.BROWSER_ACTION_TIMEOUT_MS
|
||||||
await skyvern_element.scroll_into_view()
|
await skyvern_element.scroll_into_view()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -999,9 +999,9 @@ async def handle_checkbox_action(
|
|||||||
locator = skyvern_element.locator
|
locator = skyvern_element.locator
|
||||||
|
|
||||||
if action.is_checked:
|
if action.is_checked:
|
||||||
await locator.check(timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS)
|
await locator.check(timeout=settings.BROWSER_ACTION_TIMEOUT_MS)
|
||||||
else:
|
else:
|
||||||
await locator.uncheck(timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS)
|
await locator.uncheck(timeout=settings.BROWSER_ACTION_TIMEOUT_MS)
|
||||||
|
|
||||||
# TODO (suchintan): Why does checking the label work, but not the actual input element?
|
# TODO (suchintan): Why does checking the label work, but not the actual input element?
|
||||||
return [ActionSuccess()]
|
return [ActionSuccess()]
|
||||||
@@ -1136,7 +1136,7 @@ async def chain_click(
|
|||||||
page: Page,
|
page: Page,
|
||||||
action: ClickAction | UploadFileAction,
|
action: ClickAction | UploadFileAction,
|
||||||
skyvern_element: SkyvernElement,
|
skyvern_element: SkyvernElement,
|
||||||
timeout: int = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout: int = settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
) -> List[ActionResult]:
|
) -> List[ActionResult]:
|
||||||
# Add a defensive page handler here in case a click action opens a file chooser.
|
# Add a defensive page handler here in case a click action opens a file chooser.
|
||||||
# This automatically dismisses the dialog
|
# This automatically dismisses the dialog
|
||||||
@@ -1374,9 +1374,7 @@ async def choose_auto_completion_dropdown(
|
|||||||
if cnt == 0:
|
if cnt == 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
element_handler = await locator.element_handle(
|
element_handler = await locator.element_handle(timeout=settings.BROWSER_ACTION_TIMEOUT_MS)
|
||||||
timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
|
||||||
)
|
|
||||||
if not element_handler:
|
if not element_handler:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -1444,7 +1442,7 @@ async def choose_auto_completion_dropdown(
|
|||||||
if await locator.count() == 0:
|
if await locator.count() == 0:
|
||||||
raise MissingElement(element_id=element_id)
|
raise MissingElement(element_id=element_id)
|
||||||
|
|
||||||
await locator.click(timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS)
|
await locator.click(timeout=settings.BROWSER_ACTION_TIMEOUT_MS)
|
||||||
clear_input = False
|
clear_input = False
|
||||||
return result
|
return result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -1776,7 +1774,7 @@ async def select_from_dropdown(
|
|||||||
select_history = [] if select_history is None else select_history
|
select_history = [] if select_history is None else select_history
|
||||||
single_select_result = CustomSingleSelectResult(skyvern_frame=skyvern_frame)
|
single_select_result = CustomSingleSelectResult(skyvern_frame=skyvern_frame)
|
||||||
|
|
||||||
timeout = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
timeout = settings.BROWSER_ACTION_TIMEOUT_MS
|
||||||
|
|
||||||
if dropdown_menu_element is None:
|
if dropdown_menu_element is None:
|
||||||
dropdown_menu_element = await locate_dropdown_menu(
|
dropdown_menu_element = await locate_dropdown_menu(
|
||||||
@@ -1927,7 +1925,7 @@ async def select_from_dropdown_by_value(
|
|||||||
step: Step,
|
step: Step,
|
||||||
dropdown_menu_element: SkyvernElement | None = None,
|
dropdown_menu_element: SkyvernElement | None = None,
|
||||||
) -> ActionResult:
|
) -> ActionResult:
|
||||||
timeout = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
timeout = settings.BROWSER_ACTION_TIMEOUT_MS
|
||||||
await incremental_scraped.get_incremental_element_tree(
|
await incremental_scraped.get_incremental_element_tree(
|
||||||
clean_and_remove_element_tree_factory(task=task, step=step, check_exist_funcs=[dom.check_id_in_dom]),
|
clean_and_remove_element_tree_factory(task=task, step=step, check_exist_funcs=[dom.check_id_in_dom]),
|
||||||
)
|
)
|
||||||
@@ -2061,9 +2059,7 @@ async def locate_dropdown_menu(
|
|||||||
|
|
||||||
# sometimes taking screenshot might scroll away, need to scroll back after the screenshot
|
# sometimes taking screenshot might scroll away, need to scroll back after the screenshot
|
||||||
x, y = await skyvern_frame.get_scroll_x_y()
|
x, y = await skyvern_frame.get_scroll_x_y()
|
||||||
screenshot = await head_element.get_locator().screenshot(
|
screenshot = await head_element.get_locator().screenshot(timeout=settings.BROWSER_SCREENSHOT_TIMEOUT_MS)
|
||||||
timeout=SettingsManager.get_settings().BROWSER_SCREENSHOT_TIMEOUT_MS
|
|
||||||
)
|
|
||||||
await skyvern_frame.scroll_to_x_y(x, y)
|
await skyvern_frame.scroll_to_x_y(x, y)
|
||||||
|
|
||||||
# TODO: better to send untrimmed HTML without skyvern attributes in the future
|
# TODO: better to send untrimmed HTML without skyvern attributes in the future
|
||||||
@@ -2139,7 +2135,7 @@ async def scroll_down_to_load_all_options(
|
|||||||
step_id=step.step_id if step else "none",
|
step_id=step.step_id if step else "none",
|
||||||
task_id=task.task_id if task else "none",
|
task_id=task.task_id if task else "none",
|
||||||
)
|
)
|
||||||
timeout = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
timeout = settings.BROWSER_ACTION_TIMEOUT_MS
|
||||||
|
|
||||||
dropdown_menu_element_handle = await scrollable_element.get_locator().element_handle(timeout=timeout)
|
dropdown_menu_element_handle = await scrollable_element.get_locator().element_handle(timeout=timeout)
|
||||||
if dropdown_menu_element_handle is None:
|
if dropdown_menu_element_handle is None:
|
||||||
@@ -2153,12 +2149,10 @@ async def scroll_down_to_load_all_options(
|
|||||||
scroll_pace = 0
|
scroll_pace = 0
|
||||||
previous_num = await incremental_scraped.get_incremental_elements_num()
|
previous_num = await incremental_scraped.get_incremental_elements_num()
|
||||||
|
|
||||||
deadline = datetime.now(timezone.utc) + timedelta(
|
deadline = datetime.now(timezone.utc) + timedelta(milliseconds=settings.OPTION_LOADING_TIMEOUT_MS)
|
||||||
milliseconds=SettingsManager.get_settings().OPTION_LOADING_TIMEOUT_MS
|
|
||||||
)
|
|
||||||
while datetime.now(timezone.utc) < deadline:
|
while datetime.now(timezone.utc) < deadline:
|
||||||
# make sure we can scroll to the bottom
|
# make sure we can scroll to the bottom
|
||||||
scroll_interval = SettingsManager.get_settings().BROWSER_HEIGHT * 5
|
scroll_interval = settings.BROWSER_HEIGHT * 5
|
||||||
if dropdown_menu_element_handle is None:
|
if dropdown_menu_element_handle is None:
|
||||||
LOG.info("element handle is None, using mouse to scroll down", element_id=scrollable_element.get_id())
|
LOG.info("element handle is None, using mouse to scroll down", element_id=scrollable_element.get_id())
|
||||||
await page.mouse.wheel(0, scroll_interval)
|
await page.mouse.wheel(0, scroll_interval)
|
||||||
@@ -2250,7 +2244,7 @@ async def normal_select(
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
await locator.click(
|
await locator.click(
|
||||||
timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout=settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.info(
|
LOG.info(
|
||||||
@@ -2267,7 +2261,7 @@ async def normal_select(
|
|||||||
# click by value (if it matches)
|
# click by value (if it matches)
|
||||||
await locator.select_option(
|
await locator.select_option(
|
||||||
value=value,
|
value=value,
|
||||||
timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout=settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
)
|
)
|
||||||
is_success = True
|
is_success = True
|
||||||
action_result.append(ActionSuccess())
|
action_result.append(ActionSuccess())
|
||||||
@@ -2293,7 +2287,7 @@ async def normal_select(
|
|||||||
# This means the supplied index was for the select element, not a reference to the css dict
|
# This means the supplied index was for the select element, not a reference to the css dict
|
||||||
await locator.select_option(
|
await locator.select_option(
|
||||||
index=index,
|
index=index,
|
||||||
timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout=settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
)
|
)
|
||||||
is_success = True
|
is_success = True
|
||||||
action_result.append(ActionSuccess())
|
action_result.append(ActionSuccess())
|
||||||
@@ -2308,7 +2302,7 @@ async def normal_select(
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
await locator.click(
|
await locator.click(
|
||||||
timeout=SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout=settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.info(
|
LOG.info(
|
||||||
@@ -2464,7 +2458,7 @@ async def poll_verification_code(
|
|||||||
totp_verification_url: str | None = None,
|
totp_verification_url: str | None = None,
|
||||||
totp_identifier: str | None = None,
|
totp_identifier: str | None = None,
|
||||||
) -> str | None:
|
) -> str | None:
|
||||||
timeout = timedelta(minutes=SettingsManager.get_settings().VERIFICATION_CODE_POLLING_TIMEOUT_MINS)
|
timeout = timedelta(minutes=settings.VERIFICATION_CODE_POLLING_TIMEOUT_MINS)
|
||||||
start_datetime = datetime.utcnow()
|
start_datetime = datetime.utcnow()
|
||||||
timeout_datetime = start_datetime + timeout
|
timeout_datetime = start_datetime + timeout
|
||||||
org_token = await app.DATABASE.get_valid_org_auth_token(organization_id, OrganizationAuthTokenType.api)
|
org_token = await app.DATABASE.get_valid_org_auth_token(organization_id, OrganizationAuthTokenType.api)
|
||||||
@@ -2472,7 +2466,7 @@ async def poll_verification_code(
|
|||||||
LOG.error("Failed to get organization token when trying to get verification code")
|
LOG.error("Failed to get organization token when trying to get verification code")
|
||||||
return None
|
return None
|
||||||
# wait for 40 seconds to let the verification code comes in before polling
|
# wait for 40 seconds to let the verification code comes in before polling
|
||||||
await asyncio.sleep(SettingsManager.get_settings().VERIFICATION_CODE_INITIAL_WAIT_TIME_SECS)
|
await asyncio.sleep(settings.VERIFICATION_CODE_INITIAL_WAIT_TIME_SECS)
|
||||||
while True:
|
while True:
|
||||||
# check timeout
|
# check timeout
|
||||||
if datetime.utcnow() > timeout_datetime:
|
if datetime.utcnow() > timeout_datetime:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from typing import Any
|
|||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
from skyvern.config import settings
|
||||||
from skyvern.webeye.actions.actions import Action, DecisiveAction, UserDefinedError
|
from skyvern.webeye.actions.actions import Action, DecisiveAction, UserDefinedError
|
||||||
from skyvern.webeye.actions.responses import ActionResult
|
from skyvern.webeye.actions.responses import ActionResult
|
||||||
from skyvern.webeye.scraper.scraper import ScrapedPage
|
from skyvern.webeye.scraper.scraper import ScrapedPage
|
||||||
@@ -45,7 +45,7 @@ class DetailedAgentStepOutput(BaseModel):
|
|||||||
exclude = ["scraped_page", "extract_action_prompt"]
|
exclude = ["scraped_page", "extract_action_prompt"]
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
if SettingsManager.get_settings().DEBUG_MODE:
|
if settings.DEBUG_MODE:
|
||||||
return f"DetailedAgentStepOutput({self.model_dump()})"
|
return f"DetailedAgentStepOutput({self.model_dump()})"
|
||||||
else:
|
else:
|
||||||
return f"AgentStepOutput({self.to_agent_step_output().model_dump()})"
|
return f"AgentStepOutput({self.to_agent_step_output().model_dump()})"
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ from skyvern.exceptions import (
|
|||||||
from skyvern.forge.sdk.api.files import make_temp_directory
|
from skyvern.forge.sdk.api.files import make_temp_directory
|
||||||
from skyvern.forge.sdk.core.skyvern_context import current
|
from skyvern.forge.sdk.core.skyvern_context import current
|
||||||
from skyvern.forge.sdk.schemas.tasks import ProxyLocation
|
from skyvern.forge.sdk.schemas.tasks import ProxyLocation
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
from skyvern.webeye.utils.page import SkyvernFrame
|
from skyvern.webeye.utils.page import SkyvernFrame
|
||||||
|
|
||||||
LOG = structlog.get_logger()
|
LOG = structlog.get_logger()
|
||||||
@@ -143,12 +142,14 @@ class BrowserContextFactory:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def build_browser_args() -> dict[str, Any]:
|
def build_browser_args() -> dict[str, Any]:
|
||||||
video_dir = f"{SettingsManager.get_settings().VIDEO_PATH}/{datetime.utcnow().strftime('%Y-%m-%d')}"
|
video_dir = f"{settings.VIDEO_PATH}/{datetime.utcnow().strftime('%Y-%m-%d')}"
|
||||||
har_dir = f"{SettingsManager.get_settings().HAR_PATH}/{datetime.utcnow().strftime('%Y-%m-%d')}/{BrowserContextFactory.get_subdir()}.har"
|
har_dir = (
|
||||||
|
f"{settings.HAR_PATH}/{datetime.utcnow().strftime('%Y-%m-%d')}/{BrowserContextFactory.get_subdir()}.har"
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
"user_data_dir": make_temp_directory(prefix="skyvern_browser_"),
|
"user_data_dir": make_temp_directory(prefix="skyvern_browser_"),
|
||||||
"locale": SettingsManager.get_settings().BROWSER_LOCALE,
|
"locale": settings.BROWSER_LOCALE,
|
||||||
"timezone_id": SettingsManager.get_settings().BROWSER_TIMEZONE,
|
"timezone_id": settings.BROWSER_TIMEZONE,
|
||||||
"color_scheme": "no-preference",
|
"color_scheme": "no-preference",
|
||||||
"args": [
|
"args": [
|
||||||
"--disable-blink-features=AutomationControlled",
|
"--disable-blink-features=AutomationControlled",
|
||||||
@@ -191,7 +192,7 @@ class BrowserContextFactory:
|
|||||||
async def create_browser_context(
|
async def create_browser_context(
|
||||||
cls, playwright: Playwright, **kwargs: Any
|
cls, playwright: Playwright, **kwargs: Any
|
||||||
) -> tuple[BrowserContext, BrowserArtifacts, BrowserCleanupFunc]:
|
) -> tuple[BrowserContext, BrowserArtifacts, BrowserCleanupFunc]:
|
||||||
browser_type = SettingsManager.get_settings().BROWSER_TYPE
|
browser_type = settings.BROWSER_TYPE
|
||||||
browser_context: BrowserContext | None = None
|
browser_context: BrowserContext | None = None
|
||||||
try:
|
try:
|
||||||
creator = cls._creators.get(browser_type)
|
creator = cls._creators.get(browser_type)
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import structlog
|
|||||||
from playwright.async_api import Frame, Locator, Page
|
from playwright.async_api import Frame, Locator, Page
|
||||||
from pydantic import BaseModel, PrivateAttr
|
from pydantic import BaseModel, PrivateAttr
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.constants import BUILDING_ELEMENT_TREE_TIMEOUT_MS, SKYVERN_DIR, SKYVERN_ID_ATTR
|
from skyvern.constants import BUILDING_ELEMENT_TREE_TIMEOUT_MS, SKYVERN_DIR, SKYVERN_ID_ATTR
|
||||||
from skyvern.exceptions import FailedToTakeScreenshot, UnknownElementTreeFormat
|
from skyvern.exceptions import FailedToTakeScreenshot, UnknownElementTreeFormat
|
||||||
from skyvern.forge.sdk.api.crypto import calculate_sha256
|
from skyvern.forge.sdk.api.crypto import calculate_sha256
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
from skyvern.webeye.browser_factory import BrowserState
|
from skyvern.webeye.browser_factory import BrowserState
|
||||||
from skyvern.webeye.utils.page import SkyvernFrame
|
from skyvern.webeye.utils.page import SkyvernFrame
|
||||||
|
|
||||||
@@ -301,10 +301,10 @@ async def scrape_website(
|
|||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# NOTE: MAX_SCRAPING_RETRIES is set to 0 in both staging and production
|
# NOTE: MAX_SCRAPING_RETRIES is set to 0 in both staging and production
|
||||||
if num_retry > SettingsManager.get_settings().MAX_SCRAPING_RETRIES:
|
if num_retry > settings.MAX_SCRAPING_RETRIES:
|
||||||
LOG.error(
|
LOG.error(
|
||||||
"Scraping failed after max retries, aborting.",
|
"Scraping failed after max retries, aborting.",
|
||||||
max_retries=SettingsManager.get_settings().MAX_SCRAPING_RETRIES,
|
max_retries=settings.MAX_SCRAPING_RETRIES,
|
||||||
url=url,
|
url=url,
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from random import uniform
|
|||||||
import structlog
|
import structlog
|
||||||
from playwright.async_api import ElementHandle, Frame, FrameLocator, Locator, Page, TimeoutError
|
from playwright.async_api import ElementHandle, Frame, FrameLocator, Locator, Page, TimeoutError
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.constants import SKYVERN_ID_ATTR
|
from skyvern.constants import SKYVERN_ID_ATTR
|
||||||
from skyvern.exceptions import (
|
from skyvern.exceptions import (
|
||||||
ElementIsNotLabel,
|
ElementIsNotLabel,
|
||||||
@@ -21,7 +22,6 @@ from skyvern.exceptions import (
|
|||||||
NoneFrameError,
|
NoneFrameError,
|
||||||
SkyvernException,
|
SkyvernException,
|
||||||
)
|
)
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
from skyvern.webeye.scraper.scraper import IncrementalScrapePage, ScrapedPage, json_to_html, trim_element
|
from skyvern.webeye.scraper.scraper import IncrementalScrapePage, ScrapedPage, json_to_html, trim_element
|
||||||
from skyvern.webeye.utils.page import SkyvernFrame
|
from skyvern.webeye.utils.page import SkyvernFrame
|
||||||
|
|
||||||
@@ -313,9 +313,7 @@ class SkyvernElement:
|
|||||||
def get_locator(self) -> Locator:
|
def get_locator(self) -> Locator:
|
||||||
return self.locator
|
return self.locator
|
||||||
|
|
||||||
async def get_element_handler(
|
async def get_element_handler(self, timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS) -> ElementHandle:
|
||||||
self, timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
|
||||||
) -> ElementHandle:
|
|
||||||
handler = await self.locator.element_handle(timeout=timeout)
|
handler = await self.locator.element_handle(timeout=timeout)
|
||||||
assert handler is not None
|
assert handler is not None
|
||||||
return handler
|
return handler
|
||||||
@@ -368,7 +366,7 @@ class SkyvernElement:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
async def find_label_for(
|
async def find_label_for(
|
||||||
self, dom: DomUtil, timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
self, dom: DomUtil, timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS
|
||||||
) -> SkyvernElement | None:
|
) -> SkyvernElement | None:
|
||||||
if self.get_tag_name() != "label":
|
if self.get_tag_name() != "label":
|
||||||
return None
|
return None
|
||||||
@@ -388,9 +386,7 @@ class SkyvernElement:
|
|||||||
|
|
||||||
return await dom.get_skyvern_element_by_id(unique_id)
|
return await dom.get_skyvern_element_by_id(unique_id)
|
||||||
|
|
||||||
async def find_bound_label_by_attr_id(
|
async def find_bound_label_by_attr_id(self, timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS) -> Locator | None:
|
||||||
self, timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
|
||||||
) -> Locator | None:
|
|
||||||
if self.get_tag_name() == "label":
|
if self.get_tag_name() == "label":
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -406,7 +402,7 @@ class SkyvernElement:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
async def find_bound_label_by_direct_parent(
|
async def find_bound_label_by_direct_parent(
|
||||||
self, timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
self, timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS
|
||||||
) -> Locator | None:
|
) -> Locator | None:
|
||||||
if self.get_tag_name() == "label":
|
if self.get_tag_name() == "label":
|
||||||
return None
|
return None
|
||||||
@@ -490,7 +486,7 @@ class SkyvernElement:
|
|||||||
self,
|
self,
|
||||||
attr_name: str,
|
attr_name: str,
|
||||||
dynamic: bool = False,
|
dynamic: bool = False,
|
||||||
timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
) -> typing.Any:
|
) -> typing.Any:
|
||||||
if not dynamic:
|
if not dynamic:
|
||||||
attr = self.get_attributes().get(attr_name)
|
attr = self.get_attributes().get(attr_name)
|
||||||
@@ -499,12 +495,10 @@ class SkyvernElement:
|
|||||||
|
|
||||||
return await self.locator.get_attribute(attr_name, timeout=timeout)
|
return await self.locator.get_attribute(attr_name, timeout=timeout)
|
||||||
|
|
||||||
async def focus(self, timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS) -> None:
|
async def focus(self, timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS) -> None:
|
||||||
await self.get_locator().focus(timeout=timeout)
|
await self.get_locator().focus(timeout=timeout)
|
||||||
|
|
||||||
async def input_sequentially(
|
async def input_sequentially(self, text: str, default_timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS) -> None:
|
||||||
self, text: str, default_timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
|
||||||
) -> None:
|
|
||||||
length = len(text)
|
length = len(text)
|
||||||
if length > TEXT_PRESS_MAX_LENGTH:
|
if length > TEXT_PRESS_MAX_LENGTH:
|
||||||
# if the text is longer than TEXT_PRESS_MAX_LENGTH characters, we will locator.fill in initial texts until the last TEXT_PRESS_MAX_LENGTH characters
|
# if the text is longer than TEXT_PRESS_MAX_LENGTH characters, we will locator.fill in initial texts until the last TEXT_PRESS_MAX_LENGTH characters
|
||||||
@@ -514,22 +508,16 @@ class SkyvernElement:
|
|||||||
|
|
||||||
await self.press_fill(text, timeout=default_timeout)
|
await self.press_fill(text, timeout=default_timeout)
|
||||||
|
|
||||||
async def press_key(
|
async def press_key(self, key: str, timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS) -> None:
|
||||||
self, key: str, timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
|
||||||
) -> None:
|
|
||||||
await self.get_locator().press(key=key, timeout=timeout)
|
await self.get_locator().press(key=key, timeout=timeout)
|
||||||
|
|
||||||
async def press_fill(
|
async def press_fill(self, text: str, timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS) -> None:
|
||||||
self, text: str, timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
|
||||||
) -> None:
|
|
||||||
await self.get_locator().press_sequentially(text, delay=TEXT_INPUT_DELAY, timeout=timeout)
|
await self.get_locator().press_sequentially(text, delay=TEXT_INPUT_DELAY, timeout=timeout)
|
||||||
|
|
||||||
async def input_fill(
|
async def input_fill(self, text: str, timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS) -> None:
|
||||||
self, text: str, timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
|
||||||
) -> None:
|
|
||||||
await self.get_locator().fill(text, timeout=timeout)
|
await self.get_locator().fill(text, timeout=timeout)
|
||||||
|
|
||||||
async def input_clear(self, timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS) -> None:
|
async def input_clear(self, timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS) -> None:
|
||||||
await self.get_locator().clear(timeout=timeout)
|
await self.get_locator().clear(timeout=timeout)
|
||||||
|
|
||||||
async def move_mouse_to_safe(
|
async def move_mouse_to_safe(
|
||||||
@@ -537,7 +525,7 @@ class SkyvernElement:
|
|||||||
page: Page,
|
page: Page,
|
||||||
task_id: str | None = None,
|
task_id: str | None = None,
|
||||||
step_id: str | None = None,
|
step_id: str | None = None,
|
||||||
timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
) -> tuple[float, float] | tuple[None, None]:
|
) -> tuple[float, float] | tuple[None, None]:
|
||||||
element_id = self.get_id()
|
element_id = self.get_id()
|
||||||
try:
|
try:
|
||||||
@@ -561,7 +549,7 @@ class SkyvernElement:
|
|||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
async def move_mouse_to(
|
async def move_mouse_to(
|
||||||
self, page: Page, timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
self, page: Page, timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS
|
||||||
) -> tuple[float, float]:
|
) -> tuple[float, float]:
|
||||||
bounding_box = await self.get_locator().bounding_box(timeout=timeout)
|
bounding_box = await self.get_locator().bounding_box(timeout=timeout)
|
||||||
if not bounding_box:
|
if not bounding_box:
|
||||||
@@ -580,9 +568,7 @@ class SkyvernElement:
|
|||||||
skyvern_frame = await SkyvernFrame.create_instance(self.get_frame())
|
skyvern_frame = await SkyvernFrame.create_instance(self.get_frame())
|
||||||
await skyvern_frame.click_element_in_javascript(await self.get_element_handler())
|
await skyvern_frame.click_element_in_javascript(await self.get_element_handler())
|
||||||
|
|
||||||
async def coordinate_click(
|
async def coordinate_click(self, page: Page, timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS) -> None:
|
||||||
self, page: Page, timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS
|
|
||||||
) -> None:
|
|
||||||
click_x, click_y = await self.move_mouse_to(page=page, timeout=timeout)
|
click_x, click_y = await self.move_mouse_to(page=page, timeout=timeout)
|
||||||
await page.mouse.click(click_x, click_y)
|
await page.mouse.click(click_x, click_y)
|
||||||
|
|
||||||
@@ -591,7 +577,7 @@ class SkyvernElement:
|
|||||||
frame=self.get_frame(), expression="(element) => element.blur()", arg=await self.get_element_handler()
|
frame=self.get_frame(), expression="(element) => element.blur()", arg=await self.get_element_handler()
|
||||||
)
|
)
|
||||||
|
|
||||||
async def scroll_into_view(self, timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS) -> None:
|
async def scroll_into_view(self, timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS) -> None:
|
||||||
element_handler = await self.get_element_handler(timeout=timeout)
|
element_handler = await self.get_element_handler(timeout=timeout)
|
||||||
try:
|
try:
|
||||||
await element_handler.scroll_into_view_if_needed(timeout=timeout)
|
await element_handler.scroll_into_view_if_needed(timeout=timeout)
|
||||||
@@ -608,7 +594,7 @@ class SkyvernElement:
|
|||||||
self,
|
self,
|
||||||
target_locator: Locator,
|
target_locator: Locator,
|
||||||
mode: typing.Literal["inner", "outer"],
|
mode: typing.Literal["inner", "outer"],
|
||||||
timeout: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
) -> float:
|
) -> float:
|
||||||
self_rect = await self.get_locator().bounding_box(timeout=timeout)
|
self_rect = await self.get_locator().bounding_box(timeout=timeout)
|
||||||
if self_rect is None:
|
if self_rect is None:
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import structlog
|
|||||||
from playwright._impl._errors import TimeoutError
|
from playwright._impl._errors import TimeoutError
|
||||||
from playwright.async_api import ElementHandle, Frame, Page
|
from playwright.async_api import ElementHandle, Frame, Page
|
||||||
|
|
||||||
|
from skyvern.config import settings
|
||||||
from skyvern.constants import BUILDING_ELEMENT_TREE_TIMEOUT_MS, PAGE_CONTENT_TIMEOUT, SKYVERN_DIR
|
from skyvern.constants import BUILDING_ELEMENT_TREE_TIMEOUT_MS, PAGE_CONTENT_TIMEOUT, SKYVERN_DIR
|
||||||
from skyvern.exceptions import FailedToTakeScreenshot
|
from skyvern.exceptions import FailedToTakeScreenshot
|
||||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
|
||||||
|
|
||||||
LOG = structlog.get_logger()
|
LOG = structlog.get_logger()
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ class SkyvernFrame:
|
|||||||
frame: Page | Frame,
|
frame: Page | Frame,
|
||||||
expression: str,
|
expression: str,
|
||||||
arg: Any | None = None,
|
arg: Any | None = None,
|
||||||
timeout_ms: float = SettingsManager.get_settings().BROWSER_ACTION_TIMEOUT_MS,
|
timeout_ms: float = settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
try:
|
try:
|
||||||
async with asyncio.timeout(timeout_ms / 1000):
|
async with asyncio.timeout(timeout_ms / 1000):
|
||||||
@@ -51,12 +51,12 @@ class SkyvernFrame:
|
|||||||
page: Page,
|
page: Page,
|
||||||
full_page: bool = False,
|
full_page: bool = False,
|
||||||
file_path: str | None = None,
|
file_path: str | None = None,
|
||||||
timeout: float = SettingsManager.get_settings().BROWSER_LOADING_TIMEOUT_MS,
|
timeout: float = settings.BROWSER_LOADING_TIMEOUT_MS,
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
if page.is_closed():
|
if page.is_closed():
|
||||||
raise FailedToTakeScreenshot(error_message="Page is closed")
|
raise FailedToTakeScreenshot(error_message="Page is closed")
|
||||||
try:
|
try:
|
||||||
await page.wait_for_load_state(timeout=SettingsManager.get_settings().BROWSER_LOADING_TIMEOUT_MS)
|
await page.wait_for_load_state(timeout=settings.BROWSER_LOADING_TIMEOUT_MS)
|
||||||
LOG.debug("Page is fully loaded, agent is about to take screenshots")
|
LOG.debug("Page is fully loaded, agent is about to take screenshots")
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
screenshot: bytes = bytes()
|
screenshot: bytes = bytes()
|
||||||
@@ -92,7 +92,7 @@ class SkyvernFrame:
|
|||||||
page: Page,
|
page: Page,
|
||||||
url: str,
|
url: str,
|
||||||
draw_boxes: bool = False,
|
draw_boxes: bool = False,
|
||||||
max_number: int = SettingsManager.get_settings().MAX_NUM_SCREENSHOTS,
|
max_number: int = settings.MAX_NUM_SCREENSHOTS,
|
||||||
) -> List[bytes]:
|
) -> List[bytes]:
|
||||||
skyvern_page = await SkyvernFrame.create_instance(frame=page)
|
skyvern_page = await SkyvernFrame.create_instance(frame=page)
|
||||||
assert isinstance(skyvern_page.frame, Page)
|
assert isinstance(skyvern_page.frame, Page)
|
||||||
|
|||||||
Reference in New Issue
Block a user