diff --git a/alembic/versions/2025_10_01_1116-c50ee6f26432_add_debug_session_id_to_workflow_runs_.py b/alembic/versions/2025_10_01_1116-c50ee6f26432_add_debug_session_id_to_workflow_runs_.py new file mode 100644 index 00000000..15513fa4 --- /dev/null +++ b/alembic/versions/2025_10_01_1116-c50ee6f26432_add_debug_session_id_to_workflow_runs_.py @@ -0,0 +1,31 @@ +"""add debug_session_id to workflow_runs table + +Revision ID: c50ee6f26432 +Revises: ac9d96ea0501 +Create Date: 2025-10-01 11:16:03.680233+00:00 + +""" + +from typing import Sequence, Union + +import sqlalchemy as sa + +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = "c50ee6f26432" +down_revision: Union[str, None] = "ac9d96ea0501" +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("workflow_runs", sa.Column("debug_session_id", sa.String(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("workflow_runs", "debug_session_id") + # ### end Alembic commands ### diff --git a/skyvern/forge/sdk/db/client.py b/skyvern/forge/sdk/db/client.py index 7c59c6eb..509084a1 100644 --- a/skyvern/forge/sdk/db/client.py +++ b/skyvern/forge/sdk/db/client.py @@ -1698,6 +1698,7 @@ class AgentDB: browser_address: str | None = None, sequential_key: str | None = None, run_with: str | None = None, + debug_session_id: str | None = None, ) -> WorkflowRun: try: async with self.Session() as session: @@ -1717,6 +1718,7 @@ class AgentDB: browser_address=browser_address, sequential_key=sequential_key, run_with=run_with, + debug_session_id=debug_session_id, ) session.add(workflow_run) await session.commit() diff --git a/skyvern/forge/sdk/db/models.py b/skyvern/forge/sdk/db/models.py index ae5d04e0..56baa8f8 100644 --- a/skyvern/forge/sdk/db/models.py +++ b/skyvern/forge/sdk/db/models.py @@ -290,6 +290,7 @@ class WorkflowRunModel(Base): job_id = Column(String, nullable=True) sequential_key = Column(String, nullable=True) run_with = Column(String, nullable=True) # 'agent' or 'code' + debug_session_id: Column = Column(String, nullable=True) queued_at = Column(DateTime, nullable=True) started_at = Column(DateTime, nullable=True) diff --git a/skyvern/forge/sdk/routes/agent_protocol.py b/skyvern/forge/sdk/routes/agent_protocol.py index 376140f4..e93cd931 100644 --- a/skyvern/forge/sdk/routes/agent_protocol.py +++ b/skyvern/forge/sdk/routes/agent_protocol.py @@ -991,7 +991,7 @@ async def run_block( organization=organization, template=template, workflow_permanent_id=block_run_request.workflow_id, - workflow_run_request=block_run_request, + block_run_request=block_run_request, ) browser_session_id = block_run_request.browser_session_id diff --git a/skyvern/forge/sdk/workflow/models/workflow.py b/skyvern/forge/sdk/workflow/models/workflow.py index a4ba0382..e359765b 100644 --- a/skyvern/forge/sdk/workflow/models/workflow.py +++ b/skyvern/forge/sdk/workflow/models/workflow.py @@ -126,6 +126,7 @@ class WorkflowRun(BaseModel): workflow_permanent_id: str organization_id: str browser_session_id: str | None = None + debug_session_id: str | None = None status: WorkflowRunStatus extra_http_headers: dict[str, str] | None = None proxy_location: ProxyLocation | None = None diff --git a/skyvern/forge/sdk/workflow/service.py b/skyvern/forge/sdk/workflow/service.py index 1a4041ee..b13acffc 100644 --- a/skyvern/forge/sdk/workflow/service.py +++ b/skyvern/forge/sdk/workflow/service.py @@ -148,6 +148,7 @@ class WorkflowService: version: int | None = None, max_steps_override: int | None = None, parent_workflow_run_id: str | None = None, + debug_session_id: str | None = None, ) -> WorkflowRun: """ Create a workflow run and its parameters. Validate the workflow and the organization. If there are missing @@ -181,6 +182,7 @@ class WorkflowService: organization_id=organization.organization_id, parent_workflow_run_id=parent_workflow_run_id, sequential_key=workflow.sequential_key, + debug_session_id=debug_session_id, ) LOG.info( f"Created workflow run {workflow_run.workflow_run_id} for workflow {workflow.workflow_id}", @@ -950,6 +952,7 @@ class WorkflowService: organization_id: str, parent_workflow_run_id: str | None = None, sequential_key: str | None = None, + debug_session_id: str | None = None, ) -> WorkflowRun: # validate the browser session id if workflow_request.browser_session_id: @@ -975,6 +978,7 @@ class WorkflowService: browser_address=workflow_request.browser_address, sequential_key=sequential_key, run_with=workflow_request.run_with, + debug_session_id=debug_session_id, ) async def _update_workflow_run_status( diff --git a/skyvern/schemas/runs.py b/skyvern/schemas/runs.py index 0d21870a..ea515d6c 100644 --- a/skyvern/schemas/runs.py +++ b/skyvern/schemas/runs.py @@ -378,6 +378,10 @@ class BlockRunRequest(WorkflowRunRequest): # org_id/user_id, or an override supplied by the user description="Any active outputs of blocks in a workflow being debugged", ) + debug_session_id: str | None = Field( + default=None, + description="ID of the debug session to use for this block run", + ) class ScriptRunResponse(BaseModel): diff --git a/skyvern/services/block_service.py b/skyvern/services/block_service.py index d57dae84..a50921a0 100644 --- a/skyvern/services/block_service.py +++ b/skyvern/services/block_service.py @@ -10,7 +10,7 @@ from skyvern.forge.sdk.executor.factory import AsyncExecutorFactory from skyvern.forge.sdk.schemas.organizations import Organization from skyvern.forge.sdk.workflow.models.parameter import OutputParameter from skyvern.forge.sdk.workflow.models.workflow import WorkflowRequestBody, WorkflowRun -from skyvern.schemas.runs import WorkflowRunRequest +from skyvern.schemas.runs import BlockRunRequest from skyvern.services import workflow_service LOG = structlog.get_logger() @@ -20,20 +20,20 @@ async def ensure_workflow_run( organization: Organization, template: bool, workflow_permanent_id: str, - workflow_run_request: WorkflowRunRequest, + block_run_request: BlockRunRequest, x_max_steps_override: int | None = None, ) -> WorkflowRun: context = skyvern_context.ensure_context() legacy_workflow_request = WorkflowRequestBody( - data=workflow_run_request.parameters, - proxy_location=workflow_run_request.proxy_location, - webhook_callback_url=workflow_run_request.webhook_url, - totp_identifier=workflow_run_request.totp_identifier, - totp_verification_url=workflow_run_request.totp_url, - browser_session_id=workflow_run_request.browser_session_id, - max_screenshot_scrolls=workflow_run_request.max_screenshot_scrolls, - extra_http_headers=workflow_run_request.extra_http_headers, + data=block_run_request.parameters, + proxy_location=block_run_request.proxy_location, + webhook_callback_url=block_run_request.webhook_url, + totp_identifier=block_run_request.totp_identifier, + totp_verification_url=block_run_request.totp_url, + browser_session_id=block_run_request.browser_session_id, + max_screenshot_scrolls=block_run_request.max_screenshot_scrolls, + extra_http_headers=block_run_request.extra_http_headers, ) workflow_run = await workflow_service.prepare_workflow( @@ -44,6 +44,7 @@ async def ensure_workflow_run( version=None, max_steps=x_max_steps_override, request_id=context.request_id, + debug_session_id=block_run_request.debug_session_id, ) return workflow_run diff --git a/skyvern/services/workflow_service.py b/skyvern/services/workflow_service.py index a5cefb84..09cd904d 100644 --- a/skyvern/services/workflow_service.py +++ b/skyvern/services/workflow_service.py @@ -22,6 +22,7 @@ async def prepare_workflow( version: int | None = None, max_steps: int | None = None, request_id: str | None = None, + debug_session_id: str | None = None, ) -> WorkflowRun: """ Prepare a workflow to be run. @@ -38,6 +39,7 @@ async def prepare_workflow( version=version, max_steps_override=max_steps, is_template_workflow=template, + debug_session_id=debug_session_id, ) workflow = await app.WORKFLOW_SERVICE.get_workflow_by_permanent_id(