official router v1 (#2013)

This commit is contained in:
Shuchang Zheng
2025-03-24 23:16:10 -07:00
committed by GitHub
parent 166cfb6366
commit dcb2b47be4
7 changed files with 81 additions and 20 deletions

View File

@@ -9,9 +9,9 @@ from skyvern.forge.sdk.db.enums import OrganizationAuthTokenType
from skyvern.forge.sdk.schemas.organizations import Organization from skyvern.forge.sdk.schemas.organizations import Organization
from skyvern.forge.sdk.schemas.task_v2 import TaskV2, TaskV2Request, TaskV2Status from skyvern.forge.sdk.schemas.task_v2 import TaskV2, TaskV2Request, TaskV2Status
from skyvern.forge.sdk.schemas.tasks import CreateTaskResponse, Task, TaskRequest, TaskResponse, TaskStatus from skyvern.forge.sdk.schemas.tasks import CreateTaskResponse, Task, TaskRequest, TaskResponse, TaskStatus
from skyvern.forge.sdk.services import task_v2_service
from skyvern.forge.sdk.services.org_auth_token_service import API_KEY_LIFETIME from skyvern.forge.sdk.services.org_auth_token_service import API_KEY_LIFETIME
from skyvern.forge.sdk.workflow.models.workflow import WorkflowRunStatus from skyvern.forge.sdk.workflow.models.workflow import WorkflowRunStatus
from skyvern.services import task_v2_service
from skyvern.utils import migrate_db from skyvern.utils import migrate_db

View File

@@ -18,7 +18,7 @@ from skyvern.forge import app as forge_app
from skyvern.forge.sdk.core import skyvern_context from skyvern.forge.sdk.core import skyvern_context
from skyvern.forge.sdk.core.skyvern_context import SkyvernContext 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, v2_router 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.streaming import websocket_router
from skyvern.forge.sdk.routes.totp import totp_router from skyvern.forge.sdk.routes.totp import totp_router
@@ -66,6 +66,7 @@ def get_agent_app() -> FastAPI:
allow_headers=["*"], allow_headers=["*"],
) )
app.include_router(official_api_router, prefix="/v1")
app.include_router(base_router, prefix="/api/v1") app.include_router(base_router, prefix="/api/v1")
app.include_router(v2_router, prefix="/api/v2") app.include_router(v2_router, prefix="/api/v2")
app.include_router(websocket_router, prefix="/api/v1/stream") app.include_router(websocket_router, prefix="/api/v1/stream")

View File

@@ -9,8 +9,8 @@ from skyvern.forge.sdk.core import skyvern_context
from skyvern.forge.sdk.core.skyvern_context import SkyvernContext from skyvern.forge.sdk.core.skyvern_context import SkyvernContext
from skyvern.forge.sdk.schemas.task_v2 import TaskV2Status from skyvern.forge.sdk.schemas.task_v2 import TaskV2Status
from skyvern.forge.sdk.schemas.tasks import TaskStatus from skyvern.forge.sdk.schemas.tasks import TaskStatus
from skyvern.forge.sdk.services import task_v2_service
from skyvern.forge.sdk.workflow.models.workflow import WorkflowRunStatus from skyvern.forge.sdk.workflow.models.workflow import WorkflowRunStatus
from skyvern.services import task_v2_service
LOG = structlog.get_logger() LOG = structlog.get_logger()

View File

@@ -53,7 +53,7 @@ from skyvern.forge.sdk.schemas.tasks import (
TaskStatus, TaskStatus,
) )
from skyvern.forge.sdk.schemas.workflow_runs import WorkflowRunTimeline from skyvern.forge.sdk.schemas.workflow_runs import WorkflowRunTimeline
from skyvern.forge.sdk.services import org_auth_service, task_run_service, task_v2_service from skyvern.forge.sdk.services import org_auth_service, task_run_service
from skyvern.forge.sdk.workflow.exceptions import ( from skyvern.forge.sdk.workflow.exceptions import (
FailedToCreateWorkflow, FailedToCreateWorkflow,
FailedToUpdateWorkflow, FailedToUpdateWorkflow,
@@ -71,12 +71,12 @@ from skyvern.forge.sdk.workflow.models.workflow import (
WorkflowStatus, WorkflowStatus,
) )
from skyvern.forge.sdk.workflow.models.yaml import WorkflowCreateYAMLRequest from skyvern.forge.sdk.workflow.models.yaml import WorkflowCreateYAMLRequest
from skyvern.schemas.runs import RunEngine, TaskRunRequest, TaskRunResponse, TaskRunStatus from skyvern.schemas.runs import RunEngine, TaskRunRequest, TaskRunResponse
from skyvern.services import task_v1_service from skyvern.services import task_v1_service, task_v2_service
from skyvern.webeye.actions.actions import Action from skyvern.webeye.actions.actions import Action
from skyvern.webeye.schemas import BrowserSessionResponse from skyvern.webeye.schemas import BrowserSessionResponse
official_router = APIRouter() official_api_router = APIRouter()
base_router = APIRouter() base_router = APIRouter()
v2_router = APIRouter() v2_router = APIRouter()
@@ -1497,8 +1497,15 @@ async def _flatten_workflow_run_timeline(organization_id: str, workflow_run_id:
return final_workflow_run_block_timeline return final_workflow_run_block_timeline
@official_router.post("/tasks") @official_api_router.post(
@official_router.post("/tasks/", include_in_schema=False) "/tasks",
tags=["agent"],
openapi_extra={
"x-fern-sdk-group-name": "agent",
"x-fern-sdk-method-name": "run_task",
},
)
@official_api_router.post("/tasks/", include_in_schema=False)
async def run_task( async def run_task(
request: Request, request: Request,
background_tasks: BackgroundTasks, background_tasks: BackgroundTasks,
@@ -1506,6 +1513,9 @@ async def run_task(
current_org: Organization = Depends(org_auth_service.get_current_org), current_org: Organization = Depends(org_auth_service.get_current_org),
x_api_key: Annotated[str | None, Header()] = None, x_api_key: Annotated[str | None, Header()] = None,
) -> TaskRunResponse: ) -> TaskRunResponse:
analytics.capture("skyvern-oss-run-task", data={"url": run_request.url})
await PermissionCheckerFactory.get_instance().check(current_org, browser_session_id=run_request.browser_session_id)
if run_request.engine == RunEngine.skyvern_v1: if run_request.engine == RunEngine.skyvern_v1:
# create task v1 # create task v1
# if there's no url, call task generation first to generate the url, data schema if any # if there's no url, call task generation first to generate the url, data schema if any
@@ -1566,10 +1576,49 @@ async def run_task(
) )
if run_request.engine == RunEngine.skyvern_v2: if run_request.engine == RunEngine.skyvern_v2:
# create task v2 # create task v2
raise NotImplementedError("Skyvern v2 is not implemented") try:
return TaskRunResponse( task_v2 = await task_v2_service.initialize_task_v2(
run_id="run_id", organization=current_org,
status=TaskRunStatus.queued, user_prompt=run_request.goal,
created_at=datetime.datetime.now(datetime.UTC), user_url=run_request.url,
updated_at=datetime.datetime.now(datetime.UTC), totp_identifier=run_request.totp_identifier,
) totp_verification_url=run_request.totp_url,
webhook_callback_url=run_request.webhook_url,
proxy_location=run_request.proxy_location,
publish_workflow=run_request.publish_workflow,
extracted_information_schema=run_request.data_extraction_schema,
error_code_mapping=run_request.error_code_mapping,
create_task_run=True,
)
except LLMProviderError:
LOG.error("LLM failure to initialize task v2", exc_info=True)
raise HTTPException(
status_code=500, detail="Skyvern LLM failure to initialize task v2. Please try again later."
)
await AsyncExecutorFactory.get_executor().execute_task_v2(
request=request,
background_tasks=background_tasks,
organization_id=current_org.organization_id,
task_v2_id=task_v2.observer_cruise_id,
max_steps_override=run_request.max_steps,
browser_session_id=run_request.browser_session_id,
)
return TaskRunResponse(
run_id=task_v2.observer_cruise_id,
title=run_request.title,
status=str(task_v2.status),
engine=RunEngine.skyvern_v2,
goal=task_v2.prompt,
url=task_v2.url,
output=task_v2.output,
failure_reason=task_v2.failure_reason,
webhook_url=task_v2.webhook_callback_url,
totp_identifier=task_v2.totp_identifier,
totp_url=task_v2.totp_verification_url,
proxy_location=task_v2.proxy_location,
error_code_mapping=task_v2.error_code_mapping,
data_extraction_schema=task_v2.extracted_information_schema,
created_at=task_v2.created_at,
modified_at=task_v2.modified_at,
)
raise HTTPException(status_code=400, detail=f"Invalid agent engine: {run_request.engine}")

View File

@@ -2417,8 +2417,8 @@ class TaskV2Block(Block):
browser_session_id: str | None = None, browser_session_id: str | None = None,
**kwargs: dict, **kwargs: dict,
) -> BlockResult: ) -> BlockResult:
from skyvern.forge.sdk.services import task_v2_service
from skyvern.forge.sdk.workflow.models.workflow import WorkflowRunStatus from skyvern.forge.sdk.workflow.models.workflow import WorkflowRunStatus
from skyvern.services import task_v2_service
workflow_run_context = self.get_workflow_run_context(workflow_run_id) workflow_run_context = self.get_workflow_run_context(workflow_run_id)
try: try:
@@ -2452,7 +2452,7 @@ class TaskV2Block(Block):
if not workflow_run: if not workflow_run:
raise ValueError(f"WorkflowRun not found {workflow_run_id} when running TaskV2Block") raise ValueError(f"WorkflowRun not found {workflow_run_id} when running TaskV2Block")
task_v2 = await task_v2_service.initialize_task_v2( task_v2 = await task_v2_service.initialize_task_v2(
organization, organization=organization,
user_prompt=self.prompt, user_prompt=self.prompt,
user_url=self.url, user_url=self.url,
parent_workflow_run_id=workflow_run_id, parent_workflow_run_id=workflow_run_id,

View File

@@ -2,7 +2,9 @@ from datetime import datetime
from enum import StrEnum from enum import StrEnum
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
from pydantic import BaseModel from pydantic import BaseModel, field_validator
from skyvern.forge.sdk.core.validators import validate_url
class ProxyLocation(StrEnum): class ProxyLocation(StrEnum):
@@ -113,6 +115,15 @@ class TaskRunRequest(BaseModel):
totp_identifier: str | None = None totp_identifier: str | None = None
totp_url: str | None = None totp_url: str | None = None
browser_session_id: str | None = None browser_session_id: str | None = None
publish_workflow: bool = False
@field_validator("url", "webhook_url", "totp_url")
@classmethod
def validate_urls(cls, url: str | None) -> str | None:
if url is None:
return None
return validate_url(url)
class TaskRunResponse(BaseModel): class TaskRunResponse(BaseModel):

View File

@@ -95,9 +95,9 @@ async def initialize_task_v2(
webhook_callback_url: str | None = None, webhook_callback_url: str | None = None,
publish_workflow: bool = False, publish_workflow: bool = False,
parent_workflow_run_id: str | None = None, parent_workflow_run_id: str | None = None,
create_task_run: bool = False,
extracted_information_schema: dict | list | str | None = None, extracted_information_schema: dict | list | str | None = None,
error_code_mapping: dict | None = None, error_code_mapping: dict | None = None,
create_task_run: bool = False,
) -> TaskV2: ) -> TaskV2:
task_v2 = await app.DATABASE.create_task_v2( task_v2 = await app.DATABASE.create_task_v2(
prompt=user_prompt, prompt=user_prompt,