diff --git a/alembic/versions/2026_01_07_0735-18a4ed894511_add_browser_type_to_pbs.py b/alembic/versions/2026_01_07_0735-18a4ed894511_add_browser_type_to_pbs.py new file mode 100644 index 00000000..3378bb35 --- /dev/null +++ b/alembic/versions/2026_01_07_0735-18a4ed894511_add_browser_type_to_pbs.py @@ -0,0 +1,31 @@ +"""add browser type to pbs + +Revision ID: 18a4ed894511 +Revises: 3545c24f02f6 +Create Date: 2026-01-07 07:35:47.209857+00:00 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa + +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = "18a4ed894511" +down_revision: Union[str, None] = "3545c24f02f6" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column("persistent_browser_sessions", sa.Column("browser_type", sa.String(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("persistent_browser_sessions", "browser_type") + # ### end Alembic commands ### diff --git a/skyvern/forge/sdk/db/agent_db.py b/skyvern/forge/sdk/db/agent_db.py index 8c8d1bfd..9cffa6dd 100644 --- a/skyvern/forge/sdk/db/agent_db.py +++ b/skyvern/forge/sdk/db/agent_db.py @@ -97,7 +97,11 @@ from skyvern.forge.sdk.schemas.organizations import ( Organization, OrganizationAuthToken, ) -from skyvern.forge.sdk.schemas.persistent_browser_sessions import Extensions, PersistentBrowserSession +from skyvern.forge.sdk.schemas.persistent_browser_sessions import ( + Extensions, + PersistentBrowserSession, + PersistentBrowserType, +) from skyvern.forge.sdk.schemas.runs import Run from skyvern.forge.sdk.schemas.task_generations import TaskGeneration from skyvern.forge.sdk.schemas.task_v2 import TaskV2, TaskV2Status, Thought, ThoughtType @@ -4666,6 +4670,7 @@ class AgentDB(BaseAlchemyDB): timeout_minutes: int | None = None, proxy_location: ProxyLocationInput = ProxyLocation.RESIDENTIAL, extensions: list[Extensions] | None = None, + browser_type: PersistentBrowserType | None = None, ) -> PersistentBrowserSession: """Create a new persistent browser session.""" extensions_str: list[str] | None = ( @@ -4680,6 +4685,7 @@ class AgentDB(BaseAlchemyDB): timeout_minutes=timeout_minutes, proxy_location=_serialize_proxy_location(proxy_location), extensions=extensions_str, + browser_type=browser_type.value if browser_type else None, ) session.add(browser_session) await session.commit() diff --git a/skyvern/forge/sdk/db/models.py b/skyvern/forge/sdk/db/models.py index 6596b6fc..968ee5f3 100644 --- a/skyvern/forge/sdk/db/models.py +++ b/skyvern/forge/sdk/db/models.py @@ -855,6 +855,7 @@ class PersistentBrowserSessionModel(Base): ecs_task_arn = Column(String, nullable=True) proxy_location = Column(String, nullable=True) extensions = Column(JSON, nullable=True) + browser_type = Column(String, nullable=True) started_at = Column(DateTime, nullable=True) completed_at = Column(DateTime, nullable=True) created_at = Column(DateTime, default=datetime.datetime.utcnow, nullable=False, index=True) diff --git a/skyvern/forge/sdk/routes/browser_sessions.py b/skyvern/forge/sdk/routes/browser_sessions.py index 7878912c..458b9e87 100644 --- a/skyvern/forge/sdk/routes/browser_sessions.py +++ b/skyvern/forge/sdk/routes/browser_sessions.py @@ -94,6 +94,7 @@ async def create_browser_session( timeout_minutes=browser_session_request.timeout, proxy_location=browser_session_request.proxy_location, extensions=browser_session_request.extensions, + browser_type=browser_session_request.browser_type, ) return await BrowserSessionResponse.from_browser_session(browser_session) diff --git a/skyvern/forge/sdk/schemas/persistent_browser_sessions.py b/skyvern/forge/sdk/schemas/persistent_browser_sessions.py index dd2b78c4..c25870ec 100644 --- a/skyvern/forge/sdk/schemas/persistent_browser_sessions.py +++ b/skyvern/forge/sdk/schemas/persistent_browser_sessions.py @@ -26,6 +26,11 @@ def is_final_status(status: str | None) -> bool: return status in FINAL_STATUSES +class PersistentBrowserType(StrEnum): + MSEdge = "msedge" + Chrome = "chrome" + + class Extensions(StrEnum): AdBlocker = "ad-blocker" CaptchaSolver = "captcha-solver" @@ -49,6 +54,7 @@ class PersistentBrowserSession(BaseModel): modified_at: datetime deleted_at: datetime | None = None extensions: list[Extensions] | None = None + browser_type: PersistentBrowserType | None = None class AddressablePersistentBrowserSession(PersistentBrowserSession): diff --git a/skyvern/schemas/browser_sessions.py b/skyvern/schemas/browser_sessions.py index 20633276..144609ce 100644 --- a/skyvern/schemas/browser_sessions.py +++ b/skyvern/schemas/browser_sessions.py @@ -2,7 +2,7 @@ from pydantic import BaseModel, Field from skyvern.client.types.workflow_definition_yaml_blocks_item import WorkflowDefinitionYamlBlocksItem from skyvern.client.types.workflow_definition_yaml_parameters_item import WorkflowDefinitionYamlParametersItem_Workflow -from skyvern.forge.sdk.schemas.persistent_browser_sessions import Extensions +from skyvern.forge.sdk.schemas.persistent_browser_sessions import Extensions, PersistentBrowserType from skyvern.schemas.docs.doc_strings import PROXY_LOCATION_DOC_STRING from skyvern.schemas.runs import ProxyLocation @@ -28,6 +28,11 @@ class CreateBrowserSessionRequest(BaseModel): description="A list of extensions to install in the browser session.", ) + browser_type: PersistentBrowserType | None = Field( + default=None, + description="The type of browser to use for the session.", + ) + class ProcessBrowserSessionRecordingRequest(BaseModel): compressed_chunks: list[str] = Field( diff --git a/skyvern/webeye/persistent_sessions_manager.py b/skyvern/webeye/persistent_sessions_manager.py index 6311bdd8..0d5dca5d 100644 --- a/skyvern/webeye/persistent_sessions_manager.py +++ b/skyvern/webeye/persistent_sessions_manager.py @@ -16,6 +16,7 @@ from skyvern.forge.sdk.schemas.persistent_browser_sessions import ( Extensions, PersistentBrowserSession, PersistentBrowserSessionStatus, + PersistentBrowserType, is_final_status, ) from skyvern.schemas.runs import ProxyLocation, ProxyLocationInput @@ -258,6 +259,7 @@ class PersistentSessionsManager: timeout_minutes: int | None = None, proxy_location: ProxyLocationInput = ProxyLocation.RESIDENTIAL, extensions: list[Extensions] | None = None, + browser_type: PersistentBrowserType | None = None, ) -> PersistentBrowserSession: """Create a new browser session for an organization and return its ID with the browser state.""" @@ -273,6 +275,7 @@ class PersistentSessionsManager: timeout_minutes=timeout_minutes, proxy_location=proxy_location, extensions=extensions, + browser_type=browser_type, ) return browser_session_db diff --git a/skyvern/webeye/schemas.py b/skyvern/webeye/schemas.py index c5955d3d..17104546 100644 --- a/skyvern/webeye/schemas.py +++ b/skyvern/webeye/schemas.py @@ -10,7 +10,11 @@ from skyvern.config import settings from skyvern.constants import GET_DOWNLOADED_FILES_TIMEOUT from skyvern.forge.sdk.artifact.storage.base import BaseStorage from skyvern.forge.sdk.schemas.files import FileInfo -from skyvern.forge.sdk.schemas.persistent_browser_sessions import Extensions, PersistentBrowserSession +from skyvern.forge.sdk.schemas.persistent_browser_sessions import ( + Extensions, + PersistentBrowserSession, + PersistentBrowserType, +) LOG = structlog.get_logger() @@ -50,6 +54,10 @@ class BrowserSessionResponse(BaseModel): None, description="A list of extensions installed in the browser session.", ) + browser_type: PersistentBrowserType | None = Field( + default=None, + description="The type of browser used for the session.", + ) vnc_streaming_supported: bool = Field(False, description="Whether the browser session supports VNC streaming") download_path: str | None = Field(None, description="The path where the browser session downloads files") downloaded_files: list[FileInfo] | None = Field( @@ -131,4 +139,5 @@ class BrowserSessionResponse(BaseModel): downloaded_files=downloaded_files, recordings=recordings, extensions=browser_session.extensions, + browser_type=browser_session.browser_type, )