TabSailTabSail

Human-assisted automation

Validate the handoff pattern using a controlled page before adapting it to a real sign-in flow.

Real login needs application-specific URLs, permissions, and success checks. Start by testing control transfer with a synthetic input. This example uses no model and no website credentials.

Install the Python SDK artifact and Playwright using the Quickstart. Save as human_step.py and run uv run python human_step.py:

import asyncio
from tabsail import AsyncTabSail, HandoffCheckpoint
from playwright.async_api import async_playwright

async def main():
    async with AsyncTabSail() as client:
        async with client.with_session(timeout_seconds=900) as session:
            async with async_playwright() as runtime:
                browser = None
                try:
                    grant = await client.sessions.connections.create(session.id)
                    browser = await runtime.chromium.connect_over_cdp(grant.url)
                    page = browser.contexts[0].pages[0]
                    await page.set_content(
                        '<label>Approval<input aria-label="Approval" value="Pending"></label>'
                    )
                    stable = await client.sessions.get(session.id)
                    checkpoint = HandoffCheckpoint.from_session(stable)
                    print(
                        "Open this session in the console, take control, "
                        "change Approval to Approved, then return to automation:",
                        session.id,
                        flush=True,
                    )
                    resumed = await client.sessions.wait_for_handoff(
                        session.id, after=checkpoint, timeout_ms=300000
                    )
                    await browser.close()
                    browser = None
                    grant = await client.sessions.connections.create(resumed.id)
                    browser = await runtime.chromium.connect_over_cdp(grant.url)
                    page = browser.contexts[0].pages[0]
                    value = await page.get_by_role("textbox", name="Approval").input_value()
                    if value != "Approved":
                        raise RuntimeError("Human step was not completed")
                    print("Human step observed; automation can continue.")
                finally:
                    if browser is not None:
                        await browser.close()

asyncio.run(main())

The expected result is the final confirmation after a person changes the field and returns control. The example obtains new browser and page objects after handoff and releases the session when finished.

Adapt to a real website

Navigate to the target sign-in page instead of setting synthetic HTML. Request or detect a handoff when MFA or another manual step is required. After resumption, inspect a site-specific authenticated marker before running the next business action.

Download required files before leaving the scope. Use Profiles for cross-session login reuse.

For a complete website workflow, see the Snipe-IT login/MFA/report example.

On this page