mirror of
https://github.com/Skyvern-AI/skyvern.git
synced 2025-09-02 10:41:04 +00:00
Update workflow response and webhook, bugfix: workflow is always completed (#328)
This commit is contained in:
parent
e6cee25416
commit
7d3bb704ed
3 changed files with 30 additions and 43 deletions
|
@ -491,7 +491,6 @@ async def get_workflow_run(
|
||||||
return await app.WORKFLOW_SERVICE.build_workflow_run_status_response(
|
return await app.WORKFLOW_SERVICE.build_workflow_run_status_response(
|
||||||
workflow_id=workflow_id,
|
workflow_id=workflow_id,
|
||||||
workflow_run_id=workflow_run_id,
|
workflow_run_id=workflow_run_id,
|
||||||
last_block_result=None,
|
|
||||||
organization_id=current_org.organization_id,
|
organization_id=current_org.organization_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ from pydantic import BaseModel
|
||||||
|
|
||||||
from skyvern.forge.sdk.schemas.tasks import ProxyLocation
|
from skyvern.forge.sdk.schemas.tasks import ProxyLocation
|
||||||
from skyvern.forge.sdk.workflow.exceptions import WorkflowDefinitionHasDuplicateBlockLabels
|
from skyvern.forge.sdk.workflow.exceptions import WorkflowDefinitionHasDuplicateBlockLabels
|
||||||
from skyvern.forge.sdk.workflow.models.block import BlockResult, BlockTypeVar
|
from skyvern.forge.sdk.workflow.models.block import BlockTypeVar
|
||||||
from skyvern.forge.sdk.workflow.models.parameter import PARAMETER_TYPE
|
from skyvern.forge.sdk.workflow.models.parameter import PARAMETER_TYPE
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,5 +98,4 @@ class WorkflowRunStatusResponse(BaseModel):
|
||||||
parameters: dict[str, Any]
|
parameters: dict[str, Any]
|
||||||
screenshot_urls: list[str] | None = None
|
screenshot_urls: list[str] | None = None
|
||||||
recording_url: str | None = None
|
recording_url: str | None = None
|
||||||
payload: dict[str, Any] | None = None
|
outputs: dict[str, Any] | None = None
|
||||||
output: BlockResult | None = None
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ from skyvern.forge.sdk.workflow.exceptions import (
|
||||||
WorkflowDefinitionHasReservedParameterKeys,
|
WorkflowDefinitionHasReservedParameterKeys,
|
||||||
)
|
)
|
||||||
from skyvern.forge.sdk.workflow.models.block import (
|
from skyvern.forge.sdk.workflow.models.block import (
|
||||||
BlockResult,
|
|
||||||
BlockType,
|
BlockType,
|
||||||
BlockTypeVar,
|
BlockTypeVar,
|
||||||
CodeBlock,
|
CodeBlock,
|
||||||
|
@ -204,27 +203,20 @@ class WorkflowService:
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await self.mark_workflow_run_as_failed(workflow_run_id=workflow_run.workflow_run_id)
|
await self.mark_workflow_run_as_failed(workflow_run_id=workflow_run.workflow_run_id)
|
||||||
break
|
await self.send_workflow_response(workflow=workflow, workflow_run=workflow_run, api_key=api_key)
|
||||||
|
return workflow_run
|
||||||
|
|
||||||
except Exception as e:
|
except Exception:
|
||||||
LOG.exception(
|
LOG.exception(
|
||||||
f"Error while executing workflow run {workflow_run.workflow_run_id}",
|
f"Error while executing workflow run {workflow_run.workflow_run_id}",
|
||||||
workflow_run_id=workflow_run.workflow_run_id,
|
workflow_run_id=workflow_run.workflow_run_id,
|
||||||
)
|
)
|
||||||
await self.mark_workflow_run_as_failed(workflow_run_id=workflow_run.workflow_run_id)
|
await self.mark_workflow_run_as_failed(workflow_run_id=workflow_run.workflow_run_id)
|
||||||
raise e
|
await self.send_workflow_response(workflow=workflow, workflow_run=workflow_run, api_key=api_key)
|
||||||
|
return workflow_run
|
||||||
|
|
||||||
tasks = await self.get_tasks_by_workflow_run_id(workflow_run.workflow_run_id)
|
|
||||||
await self.mark_workflow_run_as_completed(workflow_run_id=workflow_run.workflow_run_id)
|
await self.mark_workflow_run_as_completed(workflow_run_id=workflow_run.workflow_run_id)
|
||||||
|
await self.send_workflow_response(workflow=workflow, workflow_run=workflow_run, api_key=api_key)
|
||||||
await self.send_workflow_response(
|
|
||||||
workflow=workflow,
|
|
||||||
workflow_run=workflow_run,
|
|
||||||
tasks=tasks,
|
|
||||||
# TODO: We don't persist the block result for now, but we should in the case the users want to get it later
|
|
||||||
last_block_result=block_result,
|
|
||||||
api_key=api_key,
|
|
||||||
)
|
|
||||||
return workflow_run
|
return workflow_run
|
||||||
|
|
||||||
async def handle_workflow_status(self, workflow_run: WorkflowRun, tasks: list[Task]) -> WorkflowRun:
|
async def handle_workflow_status(self, workflow_run: WorkflowRun, tasks: list[Task]) -> WorkflowRun:
|
||||||
|
@ -363,7 +355,9 @@ class WorkflowService:
|
||||||
|
|
||||||
async def mark_workflow_run_as_completed(self, workflow_run_id: str) -> None:
|
async def mark_workflow_run_as_completed(self, workflow_run_id: str) -> None:
|
||||||
LOG.info(
|
LOG.info(
|
||||||
f"Marking workflow run {workflow_run_id} as completed", workflow_run_id=workflow_run_id, status="completed"
|
f"Marking workflow run {workflow_run_id} as completed",
|
||||||
|
workflow_run_id=workflow_run_id,
|
||||||
|
workflow_status="completed",
|
||||||
)
|
)
|
||||||
await app.DATABASE.update_workflow_run(
|
await app.DATABASE.update_workflow_run(
|
||||||
workflow_run_id=workflow_run_id,
|
workflow_run_id=workflow_run_id,
|
||||||
|
@ -371,7 +365,11 @@ class WorkflowService:
|
||||||
)
|
)
|
||||||
|
|
||||||
async def mark_workflow_run_as_failed(self, workflow_run_id: str) -> None:
|
async def mark_workflow_run_as_failed(self, workflow_run_id: str) -> None:
|
||||||
LOG.info(f"Marking workflow run {workflow_run_id} as failed", workflow_run_id=workflow_run_id, status="failed")
|
LOG.info(
|
||||||
|
f"Marking workflow run {workflow_run_id} as failed",
|
||||||
|
workflow_run_id=workflow_run_id,
|
||||||
|
workflow_status="failed",
|
||||||
|
)
|
||||||
await app.DATABASE.update_workflow_run(
|
await app.DATABASE.update_workflow_run(
|
||||||
workflow_run_id=workflow_run_id,
|
workflow_run_id=workflow_run_id,
|
||||||
status=WorkflowRunStatus.failed,
|
status=WorkflowRunStatus.failed,
|
||||||
|
@ -379,7 +377,9 @@ class WorkflowService:
|
||||||
|
|
||||||
async def mark_workflow_run_as_running(self, workflow_run_id: str) -> None:
|
async def mark_workflow_run_as_running(self, workflow_run_id: str) -> None:
|
||||||
LOG.info(
|
LOG.info(
|
||||||
f"Marking workflow run {workflow_run_id} as running", workflow_run_id=workflow_run_id, status="running"
|
f"Marking workflow run {workflow_run_id} as running",
|
||||||
|
workflow_run_id=workflow_run_id,
|
||||||
|
workflow_status="running",
|
||||||
)
|
)
|
||||||
await app.DATABASE.update_workflow_run(
|
await app.DATABASE.update_workflow_run(
|
||||||
workflow_run_id=workflow_run_id,
|
workflow_run_id=workflow_run_id,
|
||||||
|
@ -390,7 +390,7 @@ class WorkflowService:
|
||||||
LOG.info(
|
LOG.info(
|
||||||
f"Marking workflow run {workflow_run_id} as terminated",
|
f"Marking workflow run {workflow_run_id} as terminated",
|
||||||
workflow_run_id=workflow_run_id,
|
workflow_run_id=workflow_run_id,
|
||||||
status="terminated",
|
workflow_status="terminated",
|
||||||
)
|
)
|
||||||
await app.DATABASE.update_workflow_run(
|
await app.DATABASE.update_workflow_run(
|
||||||
workflow_run_id=workflow_run_id,
|
workflow_run_id=workflow_run_id,
|
||||||
|
@ -511,7 +511,6 @@ class WorkflowService:
|
||||||
self,
|
self,
|
||||||
workflow_id: str,
|
workflow_id: str,
|
||||||
workflow_run_id: str,
|
workflow_run_id: str,
|
||||||
last_block_result: BlockResult | None,
|
|
||||||
organization_id: str,
|
organization_id: str,
|
||||||
) -> WorkflowRunStatusResponse:
|
) -> WorkflowRunStatusResponse:
|
||||||
workflow = await self.get_workflow(workflow_id=workflow_id, organization_id=organization_id)
|
workflow = await self.get_workflow(workflow_id=workflow_id, organization_id=organization_id)
|
||||||
|
@ -555,21 +554,14 @@ class WorkflowService:
|
||||||
workflow_id=workflow_id, workflow_run_id=workflow_run_id
|
workflow_id=workflow_id, workflow_run_id=workflow_run_id
|
||||||
)
|
)
|
||||||
if output_parameter_tuples:
|
if output_parameter_tuples:
|
||||||
payload = {
|
outputs = {output_parameter.key: output.value for output_parameter, output in output_parameter_tuples}
|
||||||
output_parameter.key: wfrp.value
|
|
||||||
for output_parameter, wfrp in output_parameter_tuples
|
|
||||||
if wfrp.value is not None
|
|
||||||
}
|
|
||||||
else:
|
else:
|
||||||
payload = {
|
LOG.error(
|
||||||
task.task_id: {
|
"No output parameters found for workflow run",
|
||||||
"title": task.title,
|
workflow_id=workflow_id,
|
||||||
"extracted_information": task.extracted_information,
|
workflow_run_id=workflow_run_id,
|
||||||
"navigation_payload": task.navigation_payload,
|
)
|
||||||
"errors": await app.agent.get_task_errors(task=task),
|
outputs = None
|
||||||
}
|
|
||||||
for task in workflow_run_tasks
|
|
||||||
}
|
|
||||||
return WorkflowRunStatusResponse(
|
return WorkflowRunStatusResponse(
|
||||||
workflow_id=workflow_id,
|
workflow_id=workflow_id,
|
||||||
workflow_run_id=workflow_run_id,
|
workflow_run_id=workflow_run_id,
|
||||||
|
@ -581,20 +573,18 @@ class WorkflowService:
|
||||||
parameters=parameters_with_value,
|
parameters=parameters_with_value,
|
||||||
screenshot_urls=screenshot_urls,
|
screenshot_urls=screenshot_urls,
|
||||||
recording_url=recording_url,
|
recording_url=recording_url,
|
||||||
payload=payload,
|
outputs=outputs,
|
||||||
output=last_block_result,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async def send_workflow_response(
|
async def send_workflow_response(
|
||||||
self,
|
self,
|
||||||
workflow: Workflow,
|
workflow: Workflow,
|
||||||
workflow_run: WorkflowRun,
|
workflow_run: WorkflowRun,
|
||||||
tasks: list[Task],
|
|
||||||
last_block_result: BlockResult | None,
|
|
||||||
api_key: str | None = None,
|
api_key: str | None = None,
|
||||||
close_browser_on_completion: bool = True,
|
close_browser_on_completion: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
analytics.capture("skyvern-oss-agent-workflow-status", {"status": workflow_run.status})
|
analytics.capture("skyvern-oss-agent-workflow-status", {"status": workflow_run.status})
|
||||||
|
tasks = await self.get_tasks_by_workflow_run_id(workflow_run.workflow_run_id)
|
||||||
all_workflow_task_ids = [task.task_id for task in tasks]
|
all_workflow_task_ids = [task.task_id for task in tasks]
|
||||||
browser_state = await app.BROWSER_MANAGER.cleanup_for_workflow_run(
|
browser_state = await app.BROWSER_MANAGER.cleanup_for_workflow_run(
|
||||||
workflow_run.workflow_run_id, all_workflow_task_ids, close_browser_on_completion
|
workflow_run.workflow_run_id, all_workflow_task_ids, close_browser_on_completion
|
||||||
|
@ -608,7 +598,6 @@ class WorkflowService:
|
||||||
workflow_run_status_response = await self.build_workflow_run_status_response(
|
workflow_run_status_response = await self.build_workflow_run_status_response(
|
||||||
workflow_id=workflow.workflow_id,
|
workflow_id=workflow.workflow_id,
|
||||||
workflow_run_id=workflow_run.workflow_run_id,
|
workflow_run_id=workflow_run.workflow_run_id,
|
||||||
last_block_result=last_block_result,
|
|
||||||
organization_id=workflow.organization_id,
|
organization_id=workflow.organization_id,
|
||||||
)
|
)
|
||||||
LOG.info("Built workflow run status response", workflow_run_status_response=workflow_run_status_response)
|
LOG.info("Built workflow run status response", workflow_run_status_response=workflow_run_status_response)
|
||||||
|
@ -629,7 +618,7 @@ class WorkflowService:
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# send task_response to the webhook callback url
|
# send webhook to the webhook callback url
|
||||||
# TODO: use async requests (httpx)
|
# TODO: use async requests (httpx)
|
||||||
timestamp = str(int(datetime.utcnow().timestamp()))
|
timestamp = str(int(datetime.utcnow().timestamp()))
|
||||||
payload = workflow_run_status_response.model_dump_json()
|
payload = workflow_run_status_response.model_dump_json()
|
||||||
|
|
Loading…
Add table
Reference in a new issue