Rename old router to legacy_base_router (#2048)
Co-authored-by: Suchintan Singh <suchintansingh@gmail.com>
This commit is contained in:
@@ -46,7 +46,7 @@ class RunTask(SkyvernTaskBaseTool):
|
||||
if url is not None:
|
||||
task_request.url = url
|
||||
|
||||
return await self.agent.run_task_v1(task_request=task_request, timeout_seconds=self.run_task_timeout_seconds)
|
||||
return await self.agent.run_task(task_request=task_request, timeout_seconds=self.run_task_timeout_seconds)
|
||||
|
||||
async def _arun_task_v2(self, user_prompt: str, url: str | None = None) -> TaskV2:
|
||||
task_request = TaskV2Request(user_prompt=user_prompt, url=url)
|
||||
@@ -72,7 +72,7 @@ class DispatchTask(SkyvernTaskBaseTool):
|
||||
if url is not None:
|
||||
task_request.url = url
|
||||
|
||||
return await self.agent.create_task_v1(task_request=task_request)
|
||||
return await self.agent.create_task(task_request=task_request)
|
||||
|
||||
async def _arun_task_v2(self, user_prompt: str, url: str | None = None) -> TaskV2:
|
||||
task_request = TaskV2Request(user_prompt=user_prompt, url=url)
|
||||
|
||||
@@ -104,7 +104,7 @@ class SkyvernTaskToolSpec(BaseToolSpec):
|
||||
if url is not None:
|
||||
task_request.url = url
|
||||
|
||||
return await self.agent.run_task_v1(task_request=task_request, timeout_seconds=self.run_task_timeout_seconds)
|
||||
return await self.agent.run_task(task_request=task_request, timeout_seconds=self.run_task_timeout_seconds)
|
||||
|
||||
async def dispatch_task_v1(self, user_prompt: str, url: Optional[str] = None) -> CreateTaskResponse:
|
||||
task_generation = await self._generate_v1_task_request(user_prompt=user_prompt)
|
||||
@@ -112,7 +112,7 @@ class SkyvernTaskToolSpec(BaseToolSpec):
|
||||
if url is not None:
|
||||
task_request.url = url
|
||||
|
||||
return await self.agent.create_task_v1(task_request=task_request)
|
||||
return await self.agent.create_task(task_request=task_request)
|
||||
|
||||
async def get_task_v1(self, task_id: str) -> TaskResponse | None:
|
||||
return await self.agent.get_task(task_id=task_id)
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
import asyncio
|
||||
import os
|
||||
import subprocess
|
||||
from typing import Any, cast
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from skyvern.agent.client import SkyvernClient
|
||||
from skyvern.agent.constants import DEFAULT_AGENT_HEARTBEAT_INTERVAL, DEFAULT_AGENT_TIMEOUT
|
||||
from skyvern.config import settings
|
||||
from skyvern.forge import app
|
||||
from skyvern.forge.sdk.core import security, skyvern_context
|
||||
from skyvern.forge.sdk.core.hashing import generate_url_hash
|
||||
from skyvern.forge.sdk.core.skyvern_context import SkyvernContext
|
||||
from skyvern.forge.sdk.db.enums import OrganizationAuthTokenType
|
||||
from skyvern.forge.sdk.schemas.organizations import Organization
|
||||
@@ -18,58 +11,14 @@ from skyvern.forge.sdk.schemas.task_v2 import TaskV2, TaskV2Request, TaskV2Statu
|
||||
from skyvern.forge.sdk.schemas.tasks import CreateTaskResponse, Task, TaskRequest, TaskResponse, TaskStatus
|
||||
from skyvern.forge.sdk.services.org_auth_token_service import API_KEY_LIFETIME
|
||||
from skyvern.forge.sdk.workflow.models.workflow import WorkflowRunStatus
|
||||
from skyvern.schemas.runs import ProxyLocation, RunEngine, RunResponse, RunType, TaskRunResponse
|
||||
from skyvern.services import run_service, task_v1_service, task_v2_service
|
||||
from skyvern.services import task_v2_service
|
||||
from skyvern.utils import migrate_db
|
||||
|
||||
|
||||
class SkyvernAgent:
|
||||
def __init__(
|
||||
self,
|
||||
base_url: str | None = None,
|
||||
api_key: str | None = None,
|
||||
cdp_url: str | None = None,
|
||||
browser_path: str | None = None,
|
||||
browser_type: str | None = None,
|
||||
) -> None:
|
||||
self.skyvern_client: SkyvernClient | None = None
|
||||
if base_url is None and api_key is None:
|
||||
# TODO: run at the root wherever the code is initiated
|
||||
load_dotenv(".env")
|
||||
migrate_db()
|
||||
# TODO: will this change the already imported settings?
|
||||
# TODO: maybe refresh the settings
|
||||
|
||||
self.cdp_url = cdp_url
|
||||
if browser_path:
|
||||
# TODO validate browser_path
|
||||
# Supported Browsers: Google Chrome, Brave Browser, Microsoft Edge, Firefox
|
||||
if "Chrome" in browser_path or "Brave" in browser_path or "Edge" in browser_path:
|
||||
result = subprocess.Popen(
|
||||
["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", "--remote-debugging-port=9222"]
|
||||
)
|
||||
if result.returncode != 0:
|
||||
raise Exception(f"Failed to open browser. browser_path: {browser_path}")
|
||||
|
||||
self.cdp_url = "http://127.0.0.1:9222"
|
||||
settings.BROWSER_TYPE = "cdp-connect"
|
||||
settings.BROWSER_REMOTE_DEBUGGING_URL = self.cdp_url
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Unsupported browser or invalid path: {browser_path}. "
|
||||
"Here's a list of supported browsers Skyvern can connect to: Google Chrome, Brave Browser, Microsoft Edge, Firefox."
|
||||
)
|
||||
elif base_url is None and api_key is None:
|
||||
if not browser_type:
|
||||
if "BROWSER_TYPE" not in os.environ:
|
||||
raise Exception("browser type is missing")
|
||||
browser_type = os.environ["BROWSER_TYPE"]
|
||||
|
||||
settings.BROWSER_TYPE = browser_type
|
||||
elif base_url and api_key:
|
||||
self.client = SkyvernClient(base_url=base_url, api_key=api_key)
|
||||
else:
|
||||
raise ValueError("base_url and api_key must be both provided")
|
||||
def __init__(self) -> None:
|
||||
load_dotenv(".env")
|
||||
migrate_db()
|
||||
|
||||
async def _get_organization(self) -> Organization:
|
||||
organization = await app.DATABASE.get_organization_by_domain("skyvern.local")
|
||||
@@ -92,7 +41,7 @@ class SkyvernAgent:
|
||||
)
|
||||
return organization
|
||||
|
||||
async def _run_task(self, organization: Organization, task: Task, max_steps: int | None = None) -> None:
|
||||
async def _run_task(self, organization: Organization, task: Task) -> None:
|
||||
org_auth_token = await app.DATABASE.get_valid_org_auth_token(
|
||||
organization_id=organization.organization_id,
|
||||
token_type=OrganizationAuthTokenType.api,
|
||||
@@ -109,23 +58,13 @@ class SkyvernAgent:
|
||||
status=TaskStatus.running,
|
||||
organization_id=organization.organization_id,
|
||||
)
|
||||
try:
|
||||
skyvern_context.set(
|
||||
SkyvernContext(
|
||||
organization_id=organization.organization_id,
|
||||
task_id=task.task_id,
|
||||
max_steps_override=max_steps,
|
||||
)
|
||||
)
|
||||
|
||||
step, _, _ = await app.agent.execute_step(
|
||||
organization=organization,
|
||||
task=updated_task,
|
||||
step=step,
|
||||
api_key=org_auth_token.token if org_auth_token else None,
|
||||
)
|
||||
finally:
|
||||
skyvern_context.reset()
|
||||
step, _, _ = await app.agent.execute_step(
|
||||
organization=organization,
|
||||
task=updated_task,
|
||||
step=step,
|
||||
api_key=org_auth_token.token if org_auth_token else None,
|
||||
)
|
||||
|
||||
async def _run_task_v2(self, organization: Organization, task_v2: TaskV2) -> None:
|
||||
# mark task v2 as queued
|
||||
@@ -146,15 +85,22 @@ class SkyvernAgent:
|
||||
task_v2_id=task_v2.observer_cruise_id,
|
||||
)
|
||||
|
||||
async def create_task_v1(
|
||||
async def create_task(
|
||||
self,
|
||||
task_request: TaskRequest,
|
||||
) -> CreateTaskResponse:
|
||||
organization = await self._get_organization()
|
||||
|
||||
created_task = await app.agent.create_task(task_request, organization.organization_id)
|
||||
skyvern_context.set(
|
||||
SkyvernContext(
|
||||
organization_id=organization.organization_id,
|
||||
task_id=created_task.task_id,
|
||||
max_steps_override=created_task.max_steps_per_run,
|
||||
)
|
||||
)
|
||||
|
||||
asyncio.create_task(self._run_task(organization, created_task, max_steps=task_request.max_steps_per_run))
|
||||
asyncio.create_task(self._run_task(organization, created_task))
|
||||
return CreateTaskResponse(task_id=created_task.task_id)
|
||||
|
||||
async def get_task(
|
||||
@@ -192,12 +138,12 @@ class SkyvernAgent:
|
||||
task=task, last_step=latest_step, failure_reason=failure_reason, need_browser_log=True
|
||||
)
|
||||
|
||||
async def run_task_v1(
|
||||
async def run_task(
|
||||
self,
|
||||
task_request: TaskRequest,
|
||||
timeout_seconds: int = 600,
|
||||
) -> TaskResponse:
|
||||
created_task = await self.create_task_v1(task_request)
|
||||
created_task = await self.create_task(task_request)
|
||||
|
||||
async with asyncio.timeout(timeout_seconds):
|
||||
while True:
|
||||
@@ -241,148 +187,3 @@ class SkyvernAgent:
|
||||
if refreshed_task_v2.status.is_final():
|
||||
return refreshed_task_v2
|
||||
await asyncio.sleep(1)
|
||||
|
||||
############### officially supported interfaces ###############
|
||||
async def get_run(self, run_id: str) -> RunResponse | None:
|
||||
if not self.client:
|
||||
organization = await self._get_organization()
|
||||
return await run_service.get_run_response(run_id, organization_id=organization.organization_id)
|
||||
|
||||
return await self.client.get_run(run_id)
|
||||
|
||||
async def run_task(
|
||||
self,
|
||||
prompt: str,
|
||||
engine: RunEngine = RunEngine.skyvern_v1,
|
||||
url: str | None = None,
|
||||
webhook_url: str | None = None,
|
||||
totp_identifier: str | None = None,
|
||||
totp_url: str | None = None,
|
||||
title: str | None = None,
|
||||
error_code_mapping: dict[str, str] | None = None,
|
||||
data_extraction_schema: dict[str, Any] | None = None,
|
||||
proxy_location: ProxyLocation | None = None,
|
||||
max_steps: int | None = None,
|
||||
wait_for_completion: bool = True,
|
||||
timeout: float = DEFAULT_AGENT_TIMEOUT,
|
||||
browser_session_id: str | None = None,
|
||||
) -> TaskRunResponse:
|
||||
if not self.client:
|
||||
if engine == RunEngine.skyvern_v1:
|
||||
data_extraction_goal = None
|
||||
data_extraction_schema = data_extraction_schema
|
||||
navigation_goal = prompt
|
||||
navigation_payload = None
|
||||
organization = await self._get_organization()
|
||||
if not url:
|
||||
task_generation = await task_v1_service.generate_task(
|
||||
user_prompt=prompt,
|
||||
organization=organization,
|
||||
)
|
||||
url = task_generation.url
|
||||
navigation_goal = task_generation.navigation_goal or prompt
|
||||
navigation_payload = task_generation.navigation_payload
|
||||
data_extraction_goal = task_generation.data_extraction_goal
|
||||
data_extraction_schema = data_extraction_schema or task_generation.extracted_information_schema
|
||||
|
||||
task_request = TaskRequest(
|
||||
title=title,
|
||||
url=url,
|
||||
navigation_goal=navigation_goal,
|
||||
navigation_payload=navigation_payload,
|
||||
data_extraction_goal=data_extraction_goal,
|
||||
extracted_information_schema=data_extraction_schema,
|
||||
error_code_mapping=error_code_mapping,
|
||||
proxy_location=proxy_location,
|
||||
)
|
||||
|
||||
if wait_for_completion:
|
||||
created_task = await app.agent.create_task(task_request, organization.organization_id)
|
||||
url_hash = generate_url_hash(task_request.url)
|
||||
await app.DATABASE.create_task_run(
|
||||
task_run_type=RunType.task_v1,
|
||||
organization_id=organization.organization_id,
|
||||
run_id=created_task.task_id,
|
||||
title=task_request.title,
|
||||
url=task_request.url,
|
||||
url_hash=url_hash,
|
||||
)
|
||||
try:
|
||||
await self._run_task(organization, created_task)
|
||||
run_obj = await self.get_run(run_id=created_task.task_id)
|
||||
return cast(TaskRunResponse, run_obj)
|
||||
except Exception:
|
||||
# TODO: better error handling and logging
|
||||
run_obj = await self.get_run(run_id=created_task.task_id)
|
||||
return cast(TaskRunResponse, run_obj)
|
||||
else:
|
||||
create_task_resp = await self.create_task_v1(task_request)
|
||||
run_obj = await self.get_run(run_id=create_task_resp.task_id)
|
||||
return cast(TaskRunResponse, run_obj)
|
||||
elif engine == RunEngine.skyvern_v2:
|
||||
# initialize task v2
|
||||
organization = await self._get_organization()
|
||||
|
||||
task_v2 = await task_v2_service.initialize_task_v2(
|
||||
organization=organization,
|
||||
user_prompt=prompt,
|
||||
user_url=url,
|
||||
totp_identifier=totp_identifier,
|
||||
totp_verification_url=totp_url,
|
||||
webhook_callback_url=webhook_url,
|
||||
proxy_location=proxy_location,
|
||||
publish_workflow=False,
|
||||
extracted_information_schema=data_extraction_schema,
|
||||
error_code_mapping=error_code_mapping,
|
||||
create_task_run=True,
|
||||
)
|
||||
|
||||
if wait_for_completion:
|
||||
await self._run_task_v2(organization, task_v2)
|
||||
run_obj = await self.get_run(run_id=task_v2.observer_cruise_id)
|
||||
return cast(TaskRunResponse, run_obj)
|
||||
else:
|
||||
asyncio.create_task(self._run_task_v2(organization, task_v2))
|
||||
run_obj = await self.get_run(run_id=task_v2.observer_cruise_id)
|
||||
return cast(TaskRunResponse, run_obj)
|
||||
else:
|
||||
raise ValueError("Local mode is not supported for this method")
|
||||
|
||||
task_run = await self.client.run_task(
|
||||
prompt=prompt,
|
||||
engine=engine,
|
||||
url=url,
|
||||
webhook_url=webhook_url,
|
||||
totp_identifier=totp_identifier,
|
||||
totp_url=totp_url,
|
||||
title=title,
|
||||
error_code_mapping=error_code_mapping,
|
||||
proxy_location=proxy_location,
|
||||
max_steps=max_steps,
|
||||
)
|
||||
|
||||
if wait_for_completion:
|
||||
async with asyncio.timeout(timeout):
|
||||
while True:
|
||||
task_run = await self.client.get_run(task_run.run_id)
|
||||
if task_run.status.is_final():
|
||||
return task_run
|
||||
await asyncio.sleep(DEFAULT_AGENT_HEARTBEAT_INTERVAL)
|
||||
return task_run
|
||||
|
||||
async def run_workflow(
|
||||
self,
|
||||
workflow_id: str,
|
||||
parameters: dict[str, Any],
|
||||
webhook_url: str | None = None,
|
||||
totp_identifier: str | None = None,
|
||||
totp_url: str | None = None,
|
||||
title: str | None = None,
|
||||
error_code_mapping: dict[str, str] | None = None,
|
||||
proxy_location: ProxyLocation | None = None,
|
||||
max_steps: int | None = None,
|
||||
wait_for_completion: bool = True,
|
||||
timeout: float = DEFAULT_AGENT_TIMEOUT,
|
||||
browser_session_id: str | None = None,
|
||||
) -> None:
|
||||
raise NotImplementedError("Running workflows is currently not supported with skyvern SDK.")
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
DEFAULT_AGENT_TIMEOUT = 1800 # 30 minutes
|
||||
DEFAULT_AGENT_HEARTBEAT_INTERVAL = 10 # 10 seconds
|
||||
@@ -18,9 +18,7 @@ from skyvern.forge import app as forge_app
|
||||
from skyvern.forge.sdk.core import skyvern_context
|
||||
from skyvern.forge.sdk.core.skyvern_context import SkyvernContext
|
||||
from skyvern.forge.sdk.db.exceptions import NotFoundError
|
||||
from skyvern.forge.sdk.routes.agent_protocol import base_router, official_api_router, v2_router
|
||||
from skyvern.forge.sdk.routes.streaming import websocket_router
|
||||
from skyvern.forge.sdk.routes.totp import totp_router
|
||||
from skyvern.forge.sdk.routes.routers import base_router, legacy_base_router, legacy_v2_router
|
||||
|
||||
LOG = structlog.get_logger()
|
||||
|
||||
@@ -66,11 +64,9 @@ def get_agent_app() -> FastAPI:
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
app.include_router(official_api_router, prefix="/v1")
|
||||
app.include_router(base_router, prefix="/api/v1")
|
||||
app.include_router(v2_router, prefix="/api/v2")
|
||||
app.include_router(websocket_router, prefix="/api/v1/stream")
|
||||
app.include_router(totp_router, prefix="/api/v1/totp")
|
||||
app.include_router(base_router, prefix="/v1")
|
||||
app.include_router(legacy_base_router, prefix="/api/v1")
|
||||
app.include_router(legacy_v2_router, prefix="/api/v2")
|
||||
app.openapi = custom_openapi
|
||||
|
||||
app.add_middleware(
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
from skyvern.forge.sdk.routes import agent_protocol # noqa: F401
|
||||
from skyvern.forge.sdk.routes import browser_sessions # noqa: F401
|
||||
from skyvern.forge.sdk.routes import streaming # noqa: F401
|
||||
from skyvern.forge.sdk.routes import totp # noqa: F401
|
||||
|
||||
@@ -6,18 +6,7 @@ from typing import Annotated, Any
|
||||
|
||||
import structlog
|
||||
import yaml
|
||||
from fastapi import (
|
||||
APIRouter,
|
||||
BackgroundTasks,
|
||||
Depends,
|
||||
Header,
|
||||
HTTPException,
|
||||
Query,
|
||||
Request,
|
||||
Response,
|
||||
UploadFile,
|
||||
status,
|
||||
)
|
||||
from fastapi import BackgroundTasks, Depends, Header, HTTPException, Query, Request, Response, UploadFile, status
|
||||
from fastapi.responses import ORJSONResponse
|
||||
|
||||
from skyvern import analytics
|
||||
@@ -33,6 +22,7 @@ from skyvern.forge.sdk.core.security import generate_skyvern_signature
|
||||
from skyvern.forge.sdk.db.enums import OrganizationAuthTokenType
|
||||
from skyvern.forge.sdk.executor.factory import AsyncExecutorFactory
|
||||
from skyvern.forge.sdk.models import Step
|
||||
from skyvern.forge.sdk.routes.routers import base_router, legacy_base_router, legacy_v2_router
|
||||
from skyvern.forge.sdk.schemas.ai_suggestions import AISuggestionBase, AISuggestionRequest
|
||||
from skyvern.forge.sdk.schemas.organizations import (
|
||||
GetOrganizationAPIKeysResponse,
|
||||
@@ -73,11 +63,6 @@ from skyvern.forge.sdk.workflow.models.yaml import WorkflowCreateYAMLRequest
|
||||
from skyvern.schemas.runs import RunEngine, RunResponse, RunType, TaskRunRequest, TaskRunResponse
|
||||
from skyvern.services import run_service, task_v1_service, task_v2_service
|
||||
from skyvern.webeye.actions.actions import Action
|
||||
from skyvern.webeye.schemas import BrowserSessionResponse
|
||||
|
||||
official_api_router = APIRouter()
|
||||
base_router = APIRouter()
|
||||
v2_router = APIRouter()
|
||||
|
||||
LOG = structlog.get_logger()
|
||||
|
||||
@@ -103,15 +88,16 @@ class AISuggestionType(str, Enum):
|
||||
DATA_SCHEMA = "data_schema"
|
||||
|
||||
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/webhook",
|
||||
tags=["server"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "server",
|
||||
"x-fern-sdk-method-name": "webhook",
|
||||
},
|
||||
include_in_schema=False,
|
||||
)
|
||||
@base_router.post("/webhook/", include_in_schema=False)
|
||||
@legacy_base_router.post("/webhook/", include_in_schema=False)
|
||||
async def webhook(
|
||||
request: Request,
|
||||
x_skyvern_signature: Annotated[str | None, Header()] = None,
|
||||
@@ -148,7 +134,7 @@ async def webhook(
|
||||
return Response(content="webhook validation", status_code=200)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/heartbeat",
|
||||
tags=["server"],
|
||||
openapi_extra={
|
||||
@@ -156,7 +142,7 @@ async def webhook(
|
||||
"x-fern-sdk-method-name": "heartbeat",
|
||||
},
|
||||
)
|
||||
@base_router.get("/heartbeat/", include_in_schema=False)
|
||||
@legacy_base_router.get("/heartbeat/", include_in_schema=False)
|
||||
async def heartbeat() -> Response:
|
||||
"""
|
||||
Check if the server is running.
|
||||
@@ -164,7 +150,7 @@ async def heartbeat() -> Response:
|
||||
return Response(content="Server is running.", status_code=200)
|
||||
|
||||
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/tasks",
|
||||
tags=["agent"],
|
||||
response_model=CreateTaskResponse,
|
||||
@@ -173,7 +159,7 @@ async def heartbeat() -> Response:
|
||||
"x-fern-sdk-method-name": "run_task_v1",
|
||||
},
|
||||
)
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/tasks/",
|
||||
response_model=CreateTaskResponse,
|
||||
include_in_schema=False,
|
||||
@@ -200,7 +186,7 @@ async def run_task_v1(
|
||||
return CreateTaskResponse(task_id=created_task.task_id)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/tasks/{task_id}",
|
||||
tags=["agent"],
|
||||
response_model=TaskResponse,
|
||||
@@ -209,7 +195,7 @@ async def run_task_v1(
|
||||
"x-fern-sdk-method-name": "get_task_v1",
|
||||
},
|
||||
)
|
||||
@base_router.get("/tasks/{task_id}/", response_model=TaskResponse, include_in_schema=False)
|
||||
@legacy_base_router.get("/tasks/{task_id}/", response_model=TaskResponse, include_in_schema=False)
|
||||
async def get_task_v1(
|
||||
task_id: str,
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
@@ -248,7 +234,7 @@ async def get_task_v1(
|
||||
)
|
||||
|
||||
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/tasks/{task_id}/cancel",
|
||||
tags=["agent"],
|
||||
openapi_extra={
|
||||
@@ -256,7 +242,7 @@ async def get_task_v1(
|
||||
"x-fern-sdk-method-name": "cancel_task",
|
||||
},
|
||||
)
|
||||
@base_router.post("/tasks/{task_id}/cancel/", include_in_schema=False)
|
||||
@legacy_base_router.post("/tasks/{task_id}/cancel/", include_in_schema=False)
|
||||
async def cancel_task(
|
||||
task_id: str,
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
@@ -276,7 +262,7 @@ async def cancel_task(
|
||||
await app.agent.execute_task_webhook(task=task, last_step=latest_step, api_key=x_api_key)
|
||||
|
||||
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/workflows/runs/{workflow_run_id}/cancel",
|
||||
tags=["agent"],
|
||||
openapi_extra={
|
||||
@@ -284,7 +270,7 @@ async def cancel_task(
|
||||
"x-fern-sdk-method-name": "cancel_workflow_run",
|
||||
},
|
||||
)
|
||||
@base_router.post("/workflows/runs/{workflow_run_id}/cancel/", include_in_schema=False)
|
||||
@legacy_base_router.post("/workflows/runs/{workflow_run_id}/cancel/", include_in_schema=False)
|
||||
async def cancel_workflow_run(
|
||||
workflow_run_id: str,
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
@@ -316,7 +302,7 @@ async def cancel_workflow_run(
|
||||
await app.WORKFLOW_SERVICE.execute_workflow_webhook(workflow_run, api_key=x_api_key)
|
||||
|
||||
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/tasks/{task_id}/retry_webhook",
|
||||
tags=["agent"],
|
||||
response_model=TaskResponse,
|
||||
@@ -325,7 +311,7 @@ async def cancel_workflow_run(
|
||||
"x-fern-sdk-method-name": "retry_webhook",
|
||||
},
|
||||
)
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/tasks/{task_id}/retry_webhook/",
|
||||
response_model=TaskResponse,
|
||||
include_in_schema=False,
|
||||
@@ -354,7 +340,7 @@ async def retry_webhook(
|
||||
return await app.agent.build_task_response(task=task_obj, last_step=latest_step)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/tasks",
|
||||
tags=["agent"],
|
||||
response_model=list[Task],
|
||||
@@ -363,7 +349,7 @@ async def retry_webhook(
|
||||
"x-fern-sdk-method-name": "get_tasks",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/tasks/",
|
||||
response_model=list[Task],
|
||||
include_in_schema=False,
|
||||
@@ -411,7 +397,7 @@ async def get_tasks(
|
||||
return ORJSONResponse([(await app.agent.build_task_response(task=task)).model_dump() for task in tasks])
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/runs",
|
||||
tags=["agent"],
|
||||
response_model=list[WorkflowRun | Task],
|
||||
@@ -420,7 +406,7 @@ async def get_tasks(
|
||||
"x-fern-sdk-method-name": "get_runs",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/runs/",
|
||||
response_model=list[WorkflowRun | Task],
|
||||
include_in_schema=False,
|
||||
@@ -441,7 +427,7 @@ async def get_runs(
|
||||
return ORJSONResponse([run.model_dump() for run in runs])
|
||||
|
||||
|
||||
@official_api_router.get(
|
||||
@base_router.get(
|
||||
"/runs/{run_id}",
|
||||
tags=["agent"],
|
||||
response_model=RunResponse,
|
||||
@@ -450,7 +436,7 @@ async def get_runs(
|
||||
"x-fern-sdk-method-name": "get_run",
|
||||
},
|
||||
)
|
||||
@official_api_router.get(
|
||||
@base_router.get(
|
||||
"/runs/{run_id}/",
|
||||
response_model=RunResponse,
|
||||
include_in_schema=False,
|
||||
@@ -468,7 +454,7 @@ async def get_run(
|
||||
return run_response
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/tasks/{task_id}/steps",
|
||||
tags=["agent"],
|
||||
response_model=list[Step],
|
||||
@@ -477,7 +463,7 @@ async def get_run(
|
||||
"x-fern-sdk-method-name": "get_steps",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/tasks/{task_id}/steps/",
|
||||
response_model=list[Step],
|
||||
include_in_schema=False,
|
||||
@@ -496,7 +482,7 @@ async def get_steps(
|
||||
return ORJSONResponse([step.model_dump(exclude_none=True) for step in steps])
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/{entity_type}/{entity_id}/artifacts",
|
||||
tags=["agent"],
|
||||
response_model=list[Artifact],
|
||||
@@ -505,7 +491,7 @@ async def get_steps(
|
||||
"x-fern-sdk-method-name": "get_artifacts",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/{entity_type}/{entity_id}/artifacts/",
|
||||
response_model=list[Artifact],
|
||||
include_in_schema=False,
|
||||
@@ -560,7 +546,7 @@ async def get_artifacts(
|
||||
return ORJSONResponse([artifact.model_dump() for artifact in artifacts])
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/tasks/{task_id}/steps/{step_id}/artifacts",
|
||||
tags=["agent"],
|
||||
response_model=list[Artifact],
|
||||
@@ -569,7 +555,7 @@ async def get_artifacts(
|
||||
"x-fern-sdk-method-name": "get_step_artifacts",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/tasks/{task_id}/steps/{step_id}/artifacts/",
|
||||
response_model=list[Artifact],
|
||||
include_in_schema=False,
|
||||
@@ -605,7 +591,7 @@ async def get_step_artifacts(
|
||||
return ORJSONResponse([artifact.model_dump() for artifact in artifacts])
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/tasks/{task_id}/actions",
|
||||
response_model=list[Action],
|
||||
tags=["agent"],
|
||||
@@ -614,7 +600,7 @@ async def get_step_artifacts(
|
||||
"x-fern-sdk-method-name": "get_actions",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/tasks/{task_id}/actions/",
|
||||
response_model=list[Action],
|
||||
include_in_schema=False,
|
||||
@@ -628,7 +614,7 @@ async def get_actions(
|
||||
return actions
|
||||
|
||||
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/workflows/{workflow_id}/run",
|
||||
response_model=RunWorkflowResponse,
|
||||
tags=["agent"],
|
||||
@@ -637,7 +623,7 @@ async def get_actions(
|
||||
"x-fern-sdk-method-name": "run_workflow",
|
||||
},
|
||||
)
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/workflows/{workflow_id}/run/",
|
||||
response_model=RunWorkflowResponse,
|
||||
include_in_schema=False,
|
||||
@@ -703,7 +689,7 @@ async def run_workflow(
|
||||
)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/runs",
|
||||
response_model=list[WorkflowRun],
|
||||
tags=["agent"],
|
||||
@@ -712,7 +698,7 @@ async def run_workflow(
|
||||
"x-fern-sdk-method-name": "get_workflow_runs",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/runs/",
|
||||
response_model=list[WorkflowRun],
|
||||
include_in_schema=False,
|
||||
@@ -732,7 +718,7 @@ async def get_workflow_runs(
|
||||
)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/{workflow_id}/runs",
|
||||
response_model=list[WorkflowRun],
|
||||
tags=["agent"],
|
||||
@@ -741,7 +727,7 @@ async def get_workflow_runs(
|
||||
"x-fern-sdk-method-name": "get_workflow_runs_by_id",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/{workflow_id}/runs/",
|
||||
response_model=list[WorkflowRun],
|
||||
include_in_schema=False,
|
||||
@@ -763,7 +749,7 @@ async def get_workflow_runs_by_id(
|
||||
)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/{workflow_id}/runs/{workflow_run_id}",
|
||||
tags=["agent"],
|
||||
openapi_extra={
|
||||
@@ -771,7 +757,7 @@ async def get_workflow_runs_by_id(
|
||||
"x-fern-sdk-method-name": "get_workflow_run_with_workflow_id",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/{workflow_id}/runs/{workflow_run_id}/",
|
||||
include_in_schema=False,
|
||||
)
|
||||
@@ -797,7 +783,7 @@ async def get_workflow_run_with_workflow_id(
|
||||
return return_dict
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/{workflow_id}/runs/{workflow_run_id}/timeline",
|
||||
tags=["agent"],
|
||||
openapi_extra={
|
||||
@@ -805,7 +791,7 @@ async def get_workflow_run_with_workflow_id(
|
||||
"x-fern-sdk-method-name": "get_workflow_run_timeline",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/{workflow_id}/runs/{workflow_run_id}/timeline/",
|
||||
include_in_schema=False,
|
||||
)
|
||||
@@ -818,7 +804,7 @@ async def get_workflow_run_timeline(
|
||||
return await _flatten_workflow_run_timeline(current_org.organization_id, workflow_run_id)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/runs/{workflow_run_id}",
|
||||
response_model=WorkflowRunResponse,
|
||||
tags=["agent"],
|
||||
@@ -827,7 +813,7 @@ async def get_workflow_run_timeline(
|
||||
"x-fern-sdk-method-name": "get_workflow_run",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/runs/{workflow_run_id}/",
|
||||
response_model=WorkflowRunResponse,
|
||||
include_in_schema=False,
|
||||
@@ -843,7 +829,7 @@ async def get_workflow_run(
|
||||
)
|
||||
|
||||
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/workflows",
|
||||
openapi_extra={
|
||||
"requestBody": {
|
||||
@@ -856,7 +842,7 @@ async def get_workflow_run(
|
||||
response_model=Workflow,
|
||||
tags=["agent"],
|
||||
)
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/workflows/",
|
||||
openapi_extra={
|
||||
"requestBody": {
|
||||
@@ -890,7 +876,7 @@ async def create_workflow(
|
||||
raise FailedToCreateWorkflow(str(e))
|
||||
|
||||
|
||||
@base_router.put(
|
||||
@legacy_base_router.put(
|
||||
"/workflows/{workflow_permanent_id}",
|
||||
openapi_extra={
|
||||
"requestBody": {
|
||||
@@ -903,7 +889,7 @@ async def create_workflow(
|
||||
response_model=Workflow,
|
||||
tags=["agent"],
|
||||
)
|
||||
@base_router.put(
|
||||
@legacy_base_router.put(
|
||||
"/workflows/{workflow_permanent_id}/",
|
||||
openapi_extra={
|
||||
"requestBody": {
|
||||
@@ -945,7 +931,7 @@ async def update_workflow(
|
||||
raise FailedToUpdateWorkflow(workflow_permanent_id, f"<{type(e).__name__}: {str(e)}>")
|
||||
|
||||
|
||||
@base_router.delete(
|
||||
@legacy_base_router.delete(
|
||||
"/workflows/{workflow_permanent_id}",
|
||||
tags=["agent"],
|
||||
openapi_extra={
|
||||
@@ -953,7 +939,7 @@ async def update_workflow(
|
||||
"x-fern-sdk-method-name": "delete_workflow",
|
||||
},
|
||||
)
|
||||
@base_router.delete("/workflows/{workflow_permanent_id}/", include_in_schema=False)
|
||||
@legacy_base_router.delete("/workflows/{workflow_permanent_id}/", include_in_schema=False)
|
||||
async def delete_workflow(
|
||||
workflow_permanent_id: str,
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
@@ -962,7 +948,7 @@ async def delete_workflow(
|
||||
await app.WORKFLOW_SERVICE.delete_workflow_by_permanent_id(workflow_permanent_id, current_org.organization_id)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows",
|
||||
response_model=list[Workflow],
|
||||
tags=["agent"],
|
||||
@@ -971,7 +957,7 @@ async def delete_workflow(
|
||||
"x-fern-sdk-method-name": "get_workflows",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/",
|
||||
response_model=list[Workflow],
|
||||
include_in_schema=False,
|
||||
@@ -1020,7 +1006,7 @@ async def get_workflows(
|
||||
)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/templates",
|
||||
response_model=list[Workflow],
|
||||
tags=["agent"],
|
||||
@@ -1029,7 +1015,7 @@ async def get_workflows(
|
||||
"x-fern-sdk-method-name": "get_workflow_templates",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/templates/",
|
||||
response_model=list[Workflow],
|
||||
include_in_schema=False,
|
||||
@@ -1048,7 +1034,7 @@ async def get_workflow_templates() -> list[Workflow]:
|
||||
return workflows
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/workflows/{workflow_permanent_id}",
|
||||
response_model=Workflow,
|
||||
tags=["agent"],
|
||||
@@ -1057,7 +1043,7 @@ async def get_workflow_templates() -> list[Workflow]:
|
||||
"x-fern-sdk-method-name": "get_workflow",
|
||||
},
|
||||
)
|
||||
@base_router.get("/workflows/{workflow_permanent_id}/", response_model=Workflow, include_in_schema=False)
|
||||
@legacy_base_router.get("/workflows/{workflow_permanent_id}/", response_model=Workflow, include_in_schema=False)
|
||||
async def get_workflow(
|
||||
workflow_permanent_id: str,
|
||||
version: int | None = None,
|
||||
@@ -1076,7 +1062,7 @@ async def get_workflow(
|
||||
)
|
||||
|
||||
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/suggest/{ai_suggestion_type}",
|
||||
include_in_schema=False,
|
||||
tags=["agent"],
|
||||
@@ -1085,7 +1071,7 @@ async def get_workflow(
|
||||
"x-fern-sdk-method-name": "suggest",
|
||||
},
|
||||
)
|
||||
@base_router.post("/suggest/{ai_suggestion_type}/", include_in_schema=False)
|
||||
@legacy_base_router.post("/suggest/{ai_suggestion_type}/", include_in_schema=False)
|
||||
async def suggest(
|
||||
ai_suggestion_type: AISuggestionType,
|
||||
data: AISuggestionRequest,
|
||||
@@ -1114,7 +1100,7 @@ async def suggest(
|
||||
raise HTTPException(status_code=400, detail="Failed to suggest data schema. Please try again later.")
|
||||
|
||||
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/generate/task",
|
||||
tags=["agent"],
|
||||
openapi_extra={
|
||||
@@ -1122,7 +1108,7 @@ async def suggest(
|
||||
"x-fern-sdk-method-name": "generate_task",
|
||||
},
|
||||
)
|
||||
@base_router.post("/generate/task/", include_in_schema=False)
|
||||
@legacy_base_router.post("/generate/task/", include_in_schema=False)
|
||||
async def generate_task(
|
||||
data: GenerateTaskRequest,
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
@@ -1134,7 +1120,7 @@ async def generate_task(
|
||||
)
|
||||
|
||||
|
||||
@base_router.put(
|
||||
@legacy_base_router.put(
|
||||
"/organizations",
|
||||
tags=["server"],
|
||||
openapi_extra={
|
||||
@@ -1142,7 +1128,7 @@ async def generate_task(
|
||||
"x-fern-sdk-method-name": "update_organization",
|
||||
},
|
||||
)
|
||||
@base_router.put(
|
||||
@legacy_base_router.put(
|
||||
"/organizations",
|
||||
include_in_schema=False,
|
||||
)
|
||||
@@ -1156,7 +1142,7 @@ async def update_organization(
|
||||
)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/organizations",
|
||||
tags=["server"],
|
||||
openapi_extra={
|
||||
@@ -1164,7 +1150,7 @@ async def update_organization(
|
||||
"x-fern-sdk-method-name": "get_organizations",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/organizations/",
|
||||
include_in_schema=False,
|
||||
)
|
||||
@@ -1174,7 +1160,7 @@ async def get_organizations(
|
||||
return GetOrganizationsResponse(organizations=[current_org])
|
||||
|
||||
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/organizations/{organization_id}/apikeys/",
|
||||
tags=["server"],
|
||||
openapi_extra={
|
||||
@@ -1182,7 +1168,7 @@ async def get_organizations(
|
||||
"x-fern-sdk-method-name": "get_api_keys",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
@legacy_base_router.get(
|
||||
"/organizations/{organization_id}/apikeys",
|
||||
include_in_schema=False,
|
||||
)
|
||||
@@ -1215,7 +1201,7 @@ async def _validate_file_size(file: UploadFile) -> UploadFile:
|
||||
return file
|
||||
|
||||
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/upload_file",
|
||||
tags=["server"],
|
||||
openapi_extra={
|
||||
@@ -1223,7 +1209,7 @@ async def _validate_file_size(file: UploadFile) -> UploadFile:
|
||||
"x-fern-sdk-method-name": "upload_file",
|
||||
},
|
||||
)
|
||||
@base_router.post(
|
||||
@legacy_base_router.post(
|
||||
"/upload_file/",
|
||||
include_in_schema=False,
|
||||
)
|
||||
@@ -1268,7 +1254,7 @@ async def upload_file(
|
||||
)
|
||||
|
||||
|
||||
@v2_router.post(
|
||||
@legacy_v2_router.post(
|
||||
"/tasks",
|
||||
tags=["agent"],
|
||||
openapi_extra={
|
||||
@@ -1276,7 +1262,7 @@ async def upload_file(
|
||||
"x-fern-sdk-method-name": "run_task_v2",
|
||||
},
|
||||
)
|
||||
@v2_router.post(
|
||||
@legacy_v2_router.post(
|
||||
"/tasks/",
|
||||
include_in_schema=False,
|
||||
)
|
||||
@@ -1327,7 +1313,7 @@ async def run_task_v2(
|
||||
return task_v2.model_dump(by_alias=True)
|
||||
|
||||
|
||||
@v2_router.get(
|
||||
@legacy_v2_router.get(
|
||||
"/tasks/{task_id}",
|
||||
tags=["agent"],
|
||||
openapi_extra={
|
||||
@@ -1335,7 +1321,7 @@ async def run_task_v2(
|
||||
"x-fern-sdk-method-name": "get_task_v2",
|
||||
},
|
||||
)
|
||||
@v2_router.get(
|
||||
@legacy_v2_router.get(
|
||||
"/tasks/{task_id}/",
|
||||
include_in_schema=False,
|
||||
)
|
||||
@@ -1349,102 +1335,6 @@ async def get_task_v2(
|
||||
return task_v2.model_dump(by_alias=True)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
"/browser_sessions/{browser_session_id}",
|
||||
response_model=BrowserSessionResponse,
|
||||
tags=["session"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "session",
|
||||
"x-fern-sdk-method-name": "get_browser_session",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
"/browser_sessions/{browser_session_id}/",
|
||||
response_model=BrowserSessionResponse,
|
||||
include_in_schema=False,
|
||||
)
|
||||
async def get_browser_session(
|
||||
browser_session_id: str,
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
) -> BrowserSessionResponse:
|
||||
analytics.capture("skyvern-oss-agent-workflow-run-get")
|
||||
browser_session = await app.PERSISTENT_SESSIONS_MANAGER.get_session(
|
||||
browser_session_id,
|
||||
current_org.organization_id,
|
||||
)
|
||||
if not browser_session:
|
||||
raise HTTPException(status_code=404, detail=f"Browser session {browser_session_id} not found")
|
||||
return BrowserSessionResponse.from_browser_session(browser_session)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
"/browser_sessions",
|
||||
response_model=list[BrowserSessionResponse],
|
||||
tags=["session"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "session",
|
||||
"x-fern-sdk-method-name": "get_browser_sessions",
|
||||
},
|
||||
)
|
||||
@base_router.get(
|
||||
"/browser_sessions/",
|
||||
response_model=list[BrowserSessionResponse],
|
||||
include_in_schema=False,
|
||||
)
|
||||
async def get_browser_sessions(
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
) -> list[BrowserSessionResponse]:
|
||||
"""Get all active browser sessions for the organization"""
|
||||
analytics.capture("skyvern-oss-agent-browser-sessions-get")
|
||||
browser_sessions = await app.PERSISTENT_SESSIONS_MANAGER.get_active_sessions(current_org.organization_id)
|
||||
return [BrowserSessionResponse.from_browser_session(browser_session) for browser_session in browser_sessions]
|
||||
|
||||
|
||||
@base_router.post(
|
||||
"/browser_sessions",
|
||||
response_model=BrowserSessionResponse,
|
||||
tags=["session"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "session",
|
||||
"x-fern-sdk-method-name": "create_browser_session",
|
||||
},
|
||||
)
|
||||
@base_router.post(
|
||||
"/browser_sessions/",
|
||||
response_model=BrowserSessionResponse,
|
||||
include_in_schema=False,
|
||||
)
|
||||
async def create_browser_session(
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
) -> BrowserSessionResponse:
|
||||
browser_session = await app.PERSISTENT_SESSIONS_MANAGER.create_session(current_org.organization_id)
|
||||
return BrowserSessionResponse.from_browser_session(browser_session)
|
||||
|
||||
|
||||
@base_router.post(
|
||||
"/browser_sessions/{session_id}/close",
|
||||
tags=["session"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "session",
|
||||
"x-fern-sdk-method-name": "close_browser_session",
|
||||
},
|
||||
)
|
||||
@base_router.post(
|
||||
"/browser_sessions/{session_id}/close/",
|
||||
include_in_schema=False,
|
||||
)
|
||||
async def close_browser_session(
|
||||
session_id: str,
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
) -> ORJSONResponse:
|
||||
await app.PERSISTENT_SESSIONS_MANAGER.close_session(current_org.organization_id, session_id)
|
||||
return ORJSONResponse(
|
||||
content={"message": "Browser session closed"},
|
||||
status_code=200,
|
||||
media_type="application/json",
|
||||
)
|
||||
|
||||
|
||||
async def _flatten_workflow_run_timeline(organization_id: str, workflow_run_id: str) -> list[WorkflowRunTimeline]:
|
||||
"""
|
||||
Get the timeline workflow runs including the nested workflow runs in a flattened list
|
||||
@@ -1494,15 +1384,21 @@ async def _flatten_workflow_run_timeline(organization_id: str, workflow_run_id:
|
||||
return final_workflow_run_block_timeline
|
||||
|
||||
|
||||
@official_api_router.post(
|
||||
@base_router.post(
|
||||
"/tasks",
|
||||
tags=["agent"],
|
||||
tags=["Agent"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "agent",
|
||||
"x-fern-sdk-method-name": "run_task",
|
||||
},
|
||||
description="Run a task",
|
||||
summary="Run a task",
|
||||
responses={
|
||||
200: {"description": "Successfully run task"},
|
||||
400: {"description": "Invalid agent engine"},
|
||||
},
|
||||
)
|
||||
@official_api_router.post("/tasks/", include_in_schema=False)
|
||||
@base_router.post("/tasks/", include_in_schema=False)
|
||||
async def run_task(
|
||||
request: Request,
|
||||
background_tasks: BackgroundTasks,
|
||||
|
||||
165
skyvern/forge/sdk/routes/browser_sessions.py
Normal file
165
skyvern/forge/sdk/routes/browser_sessions.py
Normal file
@@ -0,0 +1,165 @@
|
||||
from fastapi import Depends, HTTPException
|
||||
from fastapi.responses import ORJSONResponse
|
||||
|
||||
from skyvern import analytics
|
||||
from skyvern.forge import app
|
||||
from skyvern.forge.sdk.routes.routers import base_router, legacy_base_router
|
||||
from skyvern.forge.sdk.schemas.organizations import Organization
|
||||
from skyvern.forge.sdk.services import org_auth_service
|
||||
from skyvern.webeye.schemas import BrowserSessionResponse
|
||||
|
||||
|
||||
@base_router.get(
|
||||
"/browser_sessions/{browser_session_id}",
|
||||
response_model=BrowserSessionResponse,
|
||||
tags=["Browser Sessions"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "browser_session",
|
||||
"x-fern-sdk-method-name": "get_browser_session",
|
||||
},
|
||||
description="Get details about a specific browser session by ID",
|
||||
summary="Get browser session details",
|
||||
responses={
|
||||
200: {"description": "Successfully retrieved browser session details"},
|
||||
404: {"description": "Browser session not found"},
|
||||
401: {"description": "Unauthorized - Invalid or missing authentication"},
|
||||
},
|
||||
)
|
||||
@legacy_base_router.get(
|
||||
"/browser_sessions/{browser_session_id}",
|
||||
response_model=BrowserSessionResponse,
|
||||
tags=["session"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "session",
|
||||
"x-fern-sdk-method-name": "get_browser_session",
|
||||
},
|
||||
)
|
||||
@legacy_base_router.get(
|
||||
"/browser_sessions/{browser_session_id}/",
|
||||
response_model=BrowserSessionResponse,
|
||||
include_in_schema=False,
|
||||
)
|
||||
async def get_browser_session(
|
||||
browser_session_id: str,
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
) -> BrowserSessionResponse:
|
||||
analytics.capture("skyvern-oss-agent-browser-session-get")
|
||||
browser_session = await app.PERSISTENT_SESSIONS_MANAGER.get_session(
|
||||
browser_session_id,
|
||||
current_org.organization_id,
|
||||
)
|
||||
if not browser_session:
|
||||
raise HTTPException(status_code=404, detail=f"Browser session {browser_session_id} not found")
|
||||
return BrowserSessionResponse.from_browser_session(browser_session)
|
||||
|
||||
|
||||
@base_router.get(
|
||||
"/browser_sessions",
|
||||
response_model=list[BrowserSessionResponse],
|
||||
tags=["Browser Sessions"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "browser_session",
|
||||
"x-fern-sdk-method-name": "get_browser_sessions",
|
||||
},
|
||||
description="Get all active browser sessions for the organization",
|
||||
summary="Get all active browser sessions",
|
||||
responses={
|
||||
200: {"description": "Successfully retrieved all active browser sessions"},
|
||||
401: {"description": "Unauthorized - Invalid or missing authentication"},
|
||||
},
|
||||
)
|
||||
@legacy_base_router.get(
|
||||
"/browser_sessions",
|
||||
response_model=list[BrowserSessionResponse],
|
||||
tags=["session"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "browser_sessions",
|
||||
"x-fern-sdk-method-name": "get_browser_sessions",
|
||||
},
|
||||
)
|
||||
@legacy_base_router.get(
|
||||
"/browser_sessions/",
|
||||
response_model=list[BrowserSessionResponse],
|
||||
include_in_schema=False,
|
||||
)
|
||||
async def get_browser_sessions(
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
) -> list[BrowserSessionResponse]:
|
||||
"""Get all active browser sessions for the organization"""
|
||||
analytics.capture("skyvern-oss-agent-browser-sessions-get")
|
||||
browser_sessions = await app.PERSISTENT_SESSIONS_MANAGER.get_active_sessions(current_org.organization_id)
|
||||
return [BrowserSessionResponse.from_browser_session(browser_session) for browser_session in browser_sessions]
|
||||
|
||||
|
||||
@base_router.post(
|
||||
"/browser_sessions",
|
||||
response_model=BrowserSessionResponse,
|
||||
tags=["Browser Sessions"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "browser_session",
|
||||
"x-fern-sdk-method-name": "create_browser_session",
|
||||
},
|
||||
description="Create a new browser session",
|
||||
summary="Create a new browser session",
|
||||
responses={
|
||||
200: {"description": "Successfully created browser session"},
|
||||
401: {"description": "Unauthorized - Invalid or missing authentication"},
|
||||
},
|
||||
)
|
||||
@legacy_base_router.post(
|
||||
"/browser_sessions",
|
||||
response_model=BrowserSessionResponse,
|
||||
tags=["Browser Sessions"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "session",
|
||||
"x-fern-sdk-method-name": "create_browser_session",
|
||||
},
|
||||
)
|
||||
@legacy_base_router.post(
|
||||
"/browser_sessions/",
|
||||
response_model=BrowserSessionResponse,
|
||||
include_in_schema=False,
|
||||
)
|
||||
async def create_browser_session(
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
) -> BrowserSessionResponse:
|
||||
browser_session = await app.PERSISTENT_SESSIONS_MANAGER.create_session(current_org.organization_id)
|
||||
return BrowserSessionResponse.from_browser_session(browser_session)
|
||||
|
||||
|
||||
@base_router.post(
|
||||
"/browser_sessions/{browser_session_id}/close",
|
||||
tags=["Browser Sessions"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "browser_session",
|
||||
"x-fern-sdk-method-name": "close_browser_session",
|
||||
},
|
||||
description="Close a browser session",
|
||||
summary="Close a browser session",
|
||||
responses={
|
||||
200: {"description": "Successfully closed browser session"},
|
||||
401: {"description": "Unauthorized - Invalid or missing authentication"},
|
||||
},
|
||||
)
|
||||
@legacy_base_router.post(
|
||||
"/browser_sessions/{browser_session_id}/close",
|
||||
tags=["Browser Sessions"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "browser_session",
|
||||
"x-fern-sdk-method-name": "close_browser_session",
|
||||
},
|
||||
)
|
||||
@legacy_base_router.post(
|
||||
"/browser_sessions/{browser_session_id}/close/",
|
||||
include_in_schema=False,
|
||||
)
|
||||
async def close_browser_session(
|
||||
browser_session_id: str,
|
||||
current_org: Organization = Depends(org_auth_service.get_current_org),
|
||||
) -> ORJSONResponse:
|
||||
await app.PERSISTENT_SESSIONS_MANAGER.close_session(current_org.organization_id, browser_session_id)
|
||||
return ORJSONResponse(
|
||||
content={"message": "Browser session closed"},
|
||||
status_code=200,
|
||||
media_type="application/json",
|
||||
)
|
||||
5
skyvern/forge/sdk/routes/routers.py
Normal file
5
skyvern/forge/sdk/routes/routers.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
base_router = APIRouter()
|
||||
legacy_base_router = APIRouter(include_in_schema=False)
|
||||
legacy_v2_router = APIRouter(include_in_schema=False)
|
||||
@@ -3,21 +3,21 @@ import base64
|
||||
from datetime import datetime
|
||||
|
||||
import structlog
|
||||
from fastapi import APIRouter, WebSocket, WebSocketDisconnect
|
||||
from fastapi import WebSocket, WebSocketDisconnect
|
||||
from pydantic import ValidationError
|
||||
from websockets.exceptions import ConnectionClosedOK
|
||||
|
||||
from skyvern.forge import app
|
||||
from skyvern.forge.sdk.routes.routers import legacy_base_router
|
||||
from skyvern.forge.sdk.schemas.tasks import TaskStatus
|
||||
from skyvern.forge.sdk.services.org_auth_service import get_current_org
|
||||
from skyvern.forge.sdk.workflow.models.workflow import WorkflowRunStatus
|
||||
|
||||
LOG = structlog.get_logger()
|
||||
websocket_router = APIRouter()
|
||||
STREAMING_TIMEOUT = 300
|
||||
|
||||
|
||||
@websocket_router.websocket("/tasks/{task_id}")
|
||||
@legacy_base_router.websocket("/stream/tasks/{task_id}")
|
||||
async def task_stream(
|
||||
websocket: WebSocket,
|
||||
task_id: str,
|
||||
@@ -119,7 +119,7 @@ async def task_stream(
|
||||
return
|
||||
|
||||
|
||||
@websocket_router.websocket("/workflow_runs/{workflow_run_id}")
|
||||
@legacy_base_router.websocket("/stream/workflow_runs/{workflow_run_id}")
|
||||
async def workflow_run_streaming(
|
||||
websocket: WebSocket,
|
||||
workflow_run_id: str,
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import structlog
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi import Depends, HTTPException
|
||||
|
||||
from skyvern.forge import app
|
||||
from skyvern.forge.prompts import prompt_engine
|
||||
from skyvern.forge.sdk.routes.routers import legacy_base_router
|
||||
from skyvern.forge.sdk.schemas.organizations import Organization
|
||||
from skyvern.forge.sdk.schemas.totp_codes import TOTPCode, TOTPCodeCreate
|
||||
from skyvern.forge.sdk.services import org_auth_service
|
||||
|
||||
LOG = structlog.get_logger()
|
||||
totp_router = APIRouter()
|
||||
|
||||
|
||||
@totp_router.post(
|
||||
"",
|
||||
@legacy_base_router.post(
|
||||
"/totp",
|
||||
tags=["agent"],
|
||||
openapi_extra={
|
||||
"x-fern-sdk-group-name": "agent",
|
||||
"x-fern-sdk-method-name": "send_totp_code",
|
||||
},
|
||||
)
|
||||
@totp_router.post("/", include_in_schema=False)
|
||||
@legacy_base_router.post("/totp/", include_in_schema=False)
|
||||
async def send_totp_code(
|
||||
data: TOTPCodeCreate, curr_org: Organization = Depends(org_auth_service.get_current_org)
|
||||
) -> TOTPCode:
|
||||
|
||||
@@ -3,6 +3,7 @@ from enum import StrEnum
|
||||
from typing import Any, List
|
||||
|
||||
from pydantic import BaseModel, field_validator
|
||||
from typing_extensions import deprecated
|
||||
|
||||
from skyvern.forge.sdk.schemas.files import FileInfo
|
||||
from skyvern.forge.sdk.schemas.task_v2 import TaskV2
|
||||
@@ -13,6 +14,7 @@ from skyvern.schemas.runs import ProxyLocation
|
||||
from skyvern.utils.url_validators import validate_url
|
||||
|
||||
|
||||
@deprecated("Use WorkflowRunRequest instead")
|
||||
class WorkflowRequestBody(BaseModel):
|
||||
data: dict[str, Any] | None = None
|
||||
proxy_location: ProxyLocation | None = None
|
||||
@@ -29,6 +31,7 @@ class WorkflowRequestBody(BaseModel):
|
||||
return validate_url(url)
|
||||
|
||||
|
||||
@deprecated("Use WorkflowRunResponse instead")
|
||||
class RunWorkflowResponse(BaseModel):
|
||||
workflow_id: str
|
||||
workflow_run_id: str
|
||||
|
||||
@@ -9,12 +9,12 @@ from skyvern.utils.url_validators import validate_url
|
||||
|
||||
|
||||
class ProxyLocation(StrEnum):
|
||||
RESIDENTIAL = "RESIDENTIAL"
|
||||
US_CA = "US-CA"
|
||||
US_NY = "US-NY"
|
||||
US_TX = "US-TX"
|
||||
US_FL = "US-FL"
|
||||
US_WA = "US-WA"
|
||||
RESIDENTIAL = "RESIDENTIAL"
|
||||
RESIDENTIAL_ES = "RESIDENTIAL_ES"
|
||||
RESIDENTIAL_IE = "RESIDENTIAL_IE"
|
||||
RESIDENTIAL_GB = "RESIDENTIAL_GB"
|
||||
@@ -113,23 +113,56 @@ class RunStatus(StrEnum):
|
||||
|
||||
|
||||
class TaskRunRequest(BaseModel):
|
||||
prompt: str
|
||||
url: str | None = None
|
||||
title: str | None = None
|
||||
engine: RunEngine = RunEngine.skyvern_v2
|
||||
proxy_location: ProxyLocation | None = None
|
||||
data_extraction_schema: dict | list | str | None = None
|
||||
error_code_mapping: dict[str, str] | None = None
|
||||
max_steps: int | None = None
|
||||
webhook_url: str | None = None
|
||||
totp_identifier: str | None = None
|
||||
totp_url: str | None = None
|
||||
browser_session_id: str | None = None
|
||||
publish_workflow: bool = False
|
||||
prompt: str = Field(description="The goal or task description for Skyvern to accomplish")
|
||||
url: str | None = Field(
|
||||
default=None,
|
||||
description="The starting URL for the task. If not provided, Skyvern will attempt to determine an appropriate URL",
|
||||
)
|
||||
title: str | None = Field(default=None, description="Optional title for the task")
|
||||
engine: RunEngine = Field(
|
||||
default=RunEngine.skyvern_v2, description="The Skyvern engine version to use for this task"
|
||||
)
|
||||
proxy_location: ProxyLocation = Field(
|
||||
default=ProxyLocation.RESIDENTIAL, description="Geographic Proxy location to route the browser traffic through"
|
||||
)
|
||||
data_extraction_schema: dict | list | str | None = Field(
|
||||
default=None, description="Schema defining what data should be extracted from the webpage"
|
||||
)
|
||||
error_code_mapping: dict[str, str] | None = Field(
|
||||
default=None, description="Custom mapping of error codes to error messages if Skyvern encounters an error"
|
||||
)
|
||||
max_steps: int | None = Field(
|
||||
default=None, description="Maximum number of steps the task can take before timing out"
|
||||
)
|
||||
webhook_url: str | None = Field(
|
||||
default=None, description="URL to send task status updates to after a run is finished"
|
||||
)
|
||||
totp_identifier: str | None = Field(
|
||||
default=None,
|
||||
description="Identifier for TOTP (Time-based One-Time Password) authentication if codes are being pushed to Skyvern",
|
||||
)
|
||||
totp_url: str | None = Field(
|
||||
default=None,
|
||||
description="URL for TOTP authentication setup if Skyvern should be polling endpoint for 2FA codes",
|
||||
)
|
||||
browser_session_id: str | None = Field(
|
||||
default=None,
|
||||
description="ID of an existing browser session to reuse, having it continue from the current screen state",
|
||||
)
|
||||
publish_workflow: bool = Field(default=False, description="Whether to publish this task as a reusable workflow. ")
|
||||
|
||||
@field_validator("url", "webhook_url", "totp_url")
|
||||
@classmethod
|
||||
def validate_urls(cls, url: str | None) -> str | None:
|
||||
"""
|
||||
Validates that URLs provided to Skyvern are properly formatted.
|
||||
|
||||
Args:
|
||||
url: The URL for Skyvern to validate
|
||||
|
||||
Returns:
|
||||
The validated URL or None if no URL was provided
|
||||
"""
|
||||
if url is None:
|
||||
return None
|
||||
|
||||
@@ -137,13 +170,27 @@ class TaskRunRequest(BaseModel):
|
||||
|
||||
|
||||
class WorkflowRunRequest(BaseModel):
|
||||
title: str | None = None
|
||||
parameters: dict[str, Any] | None = None
|
||||
proxy_location: ProxyLocation | None = None
|
||||
webhook_url: str | None = None
|
||||
totp_url: str | None = None
|
||||
totp_identifier: str | None = None
|
||||
browser_session_id: str | None = None
|
||||
workflow_id: str = Field(description="ID of the workflow to run")
|
||||
title: str | None = Field(default=None, description="Optional title for this workflow run")
|
||||
parameters: dict[str, Any] = Field(default={}, description="Parameters to pass to the workflow")
|
||||
proxy_location: ProxyLocation = Field(
|
||||
default=ProxyLocation.RESIDENTIAL, description="Location of proxy to use for this workflow run"
|
||||
)
|
||||
webhook_url: str | None = Field(
|
||||
default=None, description="URL to send workflow status updates to after a run is finished"
|
||||
)
|
||||
totp_url: str | None = Field(
|
||||
default=None,
|
||||
description="URL for TOTP authentication setup if Skyvern should be polling endpoint for 2FA codes",
|
||||
)
|
||||
totp_identifier: str | None = Field(
|
||||
default=None,
|
||||
description="Identifier for TOTP (Time-based One-Time Password) authentication if codes are being pushed to Skyvern",
|
||||
)
|
||||
browser_session_id: str | None = Field(
|
||||
default=None,
|
||||
description="ID of an existing browser session to reuse, having it continue from the current screen state",
|
||||
)
|
||||
|
||||
@field_validator("webhook_url", "totp_url")
|
||||
@classmethod
|
||||
@@ -154,22 +201,30 @@ class WorkflowRunRequest(BaseModel):
|
||||
|
||||
|
||||
class BaseRunResponse(BaseModel):
|
||||
run_id: str
|
||||
status: RunStatus
|
||||
output: dict | list | str | None = None
|
||||
failure_reason: str | None = None
|
||||
created_at: datetime
|
||||
modified_at: datetime
|
||||
run_id: str = Field(description="Unique identifier for this run")
|
||||
status: RunStatus = Field(description="Current status of the run")
|
||||
output: dict | list | str | None = Field(
|
||||
default=None, description="Output data from the run, if any. Format depends on the schema in the input"
|
||||
)
|
||||
failure_reason: str | None = Field(default=None, description="Reason for failure if the run failed")
|
||||
created_at: datetime = Field(description="Timestamp when this run was created")
|
||||
modified_at: datetime = Field(description="Timestamp when this run was last modified")
|
||||
|
||||
|
||||
class TaskRunResponse(BaseRunResponse):
|
||||
run_type: Literal[RunType.task_v1, RunType.task_v2]
|
||||
run_request: TaskRunRequest | None = None
|
||||
run_type: Literal[RunType.task_v1, RunType.task_v2] = Field(
|
||||
description="Type of task run - either task_v1 or task_v2"
|
||||
)
|
||||
run_request: TaskRunRequest | None = Field(
|
||||
default=None, description="The original request parameters used to start this task run"
|
||||
)
|
||||
|
||||
|
||||
class WorkflowRunResponse(BaseRunResponse):
|
||||
run_type: Literal[RunType.workflow_run]
|
||||
run_request: WorkflowRunRequest | None = None
|
||||
run_type: Literal[RunType.workflow_run] = Field(description="Type of run - always workflow_run for workflow runs")
|
||||
run_request: WorkflowRunRequest | None = Field(
|
||||
default=None, description="The original request parameters used to start this workflow run"
|
||||
)
|
||||
|
||||
|
||||
RunResponse = Annotated[Union[TaskRunResponse, WorkflowRunResponse], Field(discriminator="run_type")]
|
||||
|
||||
@@ -101,16 +101,16 @@ class PersistentSessionsManager:
|
||||
await self.database.mark_persistent_browser_session_deleted(session_id, organization_id)
|
||||
self._browser_sessions.pop(session_id, None)
|
||||
|
||||
async def close_session(self, organization_id: str, session_id: str) -> None:
|
||||
async def close_session(self, organization_id: str, browser_session_id: str) -> None:
|
||||
"""Close a specific browser session."""
|
||||
browser_session = self._browser_sessions.get(session_id)
|
||||
browser_session = self._browser_sessions.get(browser_session_id)
|
||||
if browser_session:
|
||||
LOG.info(
|
||||
"Closing browser session",
|
||||
organization_id=organization_id,
|
||||
session_id=session_id,
|
||||
session_id=browser_session_id,
|
||||
)
|
||||
self._browser_sessions.pop(session_id, None)
|
||||
self._browser_sessions.pop(browser_session_id, None)
|
||||
|
||||
try:
|
||||
await browser_session.browser_state.close()
|
||||
@@ -118,23 +118,23 @@ class PersistentSessionsManager:
|
||||
LOG.info(
|
||||
"Browser context already closed",
|
||||
organization_id=organization_id,
|
||||
session_id=session_id,
|
||||
session_id=browser_session_id,
|
||||
)
|
||||
except Exception:
|
||||
LOG.warning(
|
||||
"Error while closing browser session",
|
||||
organization_id=organization_id,
|
||||
session_id=session_id,
|
||||
session_id=browser_session_id,
|
||||
exc_info=True,
|
||||
)
|
||||
else:
|
||||
LOG.info(
|
||||
"Browser session not found in memory, marking as deleted in database",
|
||||
organization_id=organization_id,
|
||||
session_id=session_id,
|
||||
session_id=browser_session_id,
|
||||
)
|
||||
|
||||
await self.database.mark_persistent_browser_session_deleted(session_id, organization_id)
|
||||
await self.database.mark_persistent_browser_session_deleted(browser_session_id, organization_id)
|
||||
|
||||
async def close_all_sessions(self, organization_id: str) -> None:
|
||||
"""Close all browser sessions for an organization."""
|
||||
|
||||
@@ -2,24 +2,37 @@ from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from skyvern.forge.sdk.schemas.persistent_browser_sessions import PersistentBrowserSession
|
||||
|
||||
|
||||
class BrowserSessionResponse(BaseModel):
|
||||
session_id: str
|
||||
organization_id: str
|
||||
runnable_type: str | None = None
|
||||
runnable_id: str | None = None
|
||||
created_at: datetime
|
||||
modified_at: datetime
|
||||
deleted_at: datetime | None = None
|
||||
"""Response model for browser session information."""
|
||||
|
||||
browser_session_id: str = Field(description="Unique identifier for the browser session")
|
||||
organization_id: str = Field(description="ID of the organization that owns this session")
|
||||
runnable_type: str | None = Field(
|
||||
None, description="Type of runnable associated with this session (workflow, task etc)"
|
||||
)
|
||||
runnable_id: str | None = Field(None, description="ID of the associated runnable")
|
||||
created_at: datetime = Field(description="Timestamp when the session was created")
|
||||
modified_at: datetime = Field(description="Timestamp when the session was last modified")
|
||||
deleted_at: datetime | None = Field(None, description="Timestamp when the session was deleted, if applicable")
|
||||
|
||||
@classmethod
|
||||
def from_browser_session(cls, browser_session: PersistentBrowserSession) -> BrowserSessionResponse:
|
||||
"""
|
||||
Creates a BrowserSessionResponse from a PersistentBrowserSession object.
|
||||
|
||||
Args:
|
||||
browser_session: The persistent browser session to convert
|
||||
|
||||
Returns:
|
||||
BrowserSessionResponse: The converted response object
|
||||
"""
|
||||
return cls(
|
||||
session_id=browser_session.persistent_browser_session_id,
|
||||
browser_session_id=browser_session.persistent_browser_session_id,
|
||||
organization_id=browser_session.organization_id,
|
||||
runnable_type=browser_session.runnable_type,
|
||||
runnable_id=browser_session.runnable_id,
|
||||
|
||||
Reference in New Issue
Block a user