SDK: file uploading (public url only) (#3867)

This commit is contained in:
Stanislav Novosad
2025-11-07 15:21:40 -07:00
committed by GitHub
parent 581d6e5332
commit d1d0c9414b
14 changed files with 379 additions and 12 deletions

View File

@@ -13,6 +13,7 @@ from skyvern.constants import SPECIAL_FIELD_VERIFICATION_CODE
from skyvern.core.script_generations.skyvern_page_ai import SkyvernPageAi
from skyvern.forge import app
from skyvern.forge.prompts import prompt_engine
from skyvern.forge.sdk.api.files import validate_download_url
from skyvern.forge.sdk.core import skyvern_context
from skyvern.forge.sdk.schemas.totp_codes import OTPType
from skyvern.services.otp_service import poll_otp_value
@@ -322,10 +323,11 @@ class RealSkyvernPageAi(SkyvernPageAi):
async def ai_upload_file(
self,
selector: str | None,
files: str,
files: str | None,
intention: str,
data: str | dict[str, Any] | None = None,
timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS,
public_url_only: bool = False,
) -> str:
"""Upload a file using AI to process the file URL."""
@@ -410,6 +412,9 @@ class RealSkyvernPageAi(SkyvernPageAi):
except Exception:
LOG.exception(f"Failed to adapt value for upload file action on selector={selector}, file={files}")
if public_url_only and not validate_download_url(files):
raise Exception("Only public URLs are allowed")
if action and organization_id and task and step:
result = await handle_upload_file_action(action, self.page, self.scraped_page, task, step)
if result and result[-1].success is False:

View File

@@ -411,13 +411,38 @@ class SkyvernPage:
await handler_utils.input_sequentially(locator, value, timeout=timeout)
return value
@overload
async def upload_file(
self,
selector: str,
files: str,
*,
prompt: str | None = None,
ai: str | None = "fallback",
data: str | dict[str, Any] | None = None,
timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS,
) -> str: ...
@overload
async def upload_file(
self,
*,
prompt: str,
files: str | None = None,
selector: str | None = None,
ai: str | None = "fallback",
data: str | dict[str, Any] | None = None,
timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS,
) -> str: ...
@action_wrap(ActionType.UPLOAD_FILE)
async def upload_file(
self,
selector: str | None,
files: str,
ai: str | None = "fallback",
selector: str | None = None,
files: str | None = None,
*,
prompt: str | None = None,
ai: str | None = "fallback",
data: str | dict[str, Any] | None = None,
timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS,
intention: str | None = None, # backward compatibility
@@ -433,8 +458,11 @@ class SkyvernPage:
if context and context.ai_mode_override:
ai = context.ai_mode_override
if ai == "fallback":
if not files and not prompt:
raise ValueError("Missing input: files should be provided explicitly or in prompt")
error_to_raise = None
if selector:
if selector and files:
try:
file_path = await download_file(files)
locator = self.page.locator(selector)
@@ -453,6 +481,8 @@ class SkyvernPage:
)
if error_to_raise:
raise error_to_raise
elif not files:
raise ValueError("Parameter 'files' is required but was not provided")
else:
return files
elif ai == "proactive" and prompt:
@@ -466,6 +496,8 @@ class SkyvernPage:
if not selector:
raise ValueError("Selector is required but was not provided")
if not files:
raise ValueError("Parameter 'files' is required but was not provided")
file_path = await download_file(files)
locator = self.page.locator(selector)

View File

@@ -34,10 +34,11 @@ class SkyvernPageAi(Protocol):
async def ai_upload_file(
self,
selector: str | None,
files: str,
files: str | None,
intention: str,
data: str | dict[str, Any] | None = None,
timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS,
public_url_only: bool = False,
) -> str:
"""Upload a file using AI to process the file URL."""
...