diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 345168d4..1aec2271 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.137.0" + ".": "0.138.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3de0febb..9a10048c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.138.0](https://github.com/kernel/kernel-python-sdk/compare/v0.137.0...v0.138.0) (2026-10-30) + + +### Features + +* Pause managed auth logins for human verification on unsolvable captchas ([e3b8dd1](https://github.com/kernel/kernel-python-sdk/commit/e3b8dd14505bb5c630111e2eaf14591864d3e31c)) + ## [0.137.0](https://github.com/kernel/kernel-python-sdk/compare/v0.136.0...v0.137.0) (2026-10-29) diff --git a/pyproject.toml b/pyproject.toml index b811df5d..74974ceb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.137.0" +version = "0.138.0" description = "The official Python library for the kernel API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/kernel/_version.py b/src/kernel/_version.py index 5a9d3ffb..41dc1d41 100644 --- a/src/kernel/_version.py +++ b/src/kernel/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "kernel" -__version__ = "0.137.0" # x-release-please-version +__version__ = "0.138.0" # x-release-please-version diff --git a/src/kernel/resources/auth/connections.py b/src/kernel/resources/auth/connections.py index 909dd27d..9bdba815 100644 --- a/src/kernel/resources/auth/connections.py +++ b/src/kernel/resources/auth/connections.py @@ -72,6 +72,7 @@ def create( credential: connection_create_params.Credential | Omit = omit, health_check_interval: int | Omit = omit, health_checks: bool | Omit = omit, + hitl: bool | Omit = omit, login_url: str | Omit = omit, proxy: connection_create_params.Proxy | Omit = omit, record_session: bool | Omit = omit, @@ -150,6 +151,12 @@ def create( the automatic flow (since re-auth is only triggered by a failed scheduled health check). Defaults to true. + hitl: Whether a login blocked by a CAPTCHA the browser cannot solve pauses for a + person instead of failing. The flow moves to AWAITING_HUMAN_INTERVENTION with a + `human_intervention` choice; the person completes the challenge in + `live_view_url`, then submits that choice to resume. Reauthentication never + pauses. Defaults to false. + login_url: Optional login page URL to skip discovery proxy: Deprecated. Use browser.proxy. Retained during migration for existing clients. @@ -183,6 +190,7 @@ def create( "credential": credential, "health_check_interval": health_check_interval, "health_checks": health_checks, + "hitl": hitl, "login_url": login_url, "proxy": proxy, "record_session": record_session, @@ -246,6 +254,7 @@ def update( credential: connection_update_params.Credential | Omit = omit, health_check_interval: int | Omit = omit, health_checks: bool | Omit = omit, + hitl: bool | Omit = omit, login_url: str | Omit = omit, proxy: connection_update_params.Proxy | Omit = omit, record_session: bool | Omit = omit, @@ -297,6 +306,9 @@ def update( on the automatic flow (since re-auth is only triggered by a failed scheduled health check). + hitl: Whether a login blocked by a CAPTCHA the browser cannot solve pauses for a + person instead of failing + login_url: Login page URL. Set to empty string to clear. proxy: Deprecated. Use browser.proxy. Retained during migration for existing clients. @@ -328,6 +340,7 @@ def update( "credential": credential, "health_check_interval": health_check_interval, "health_checks": health_checks, + "hitl": hitl, "login_url": login_url, "proxy": proxy, "record_session": record_session, @@ -736,6 +749,7 @@ async def create( credential: connection_create_params.Credential | Omit = omit, health_check_interval: int | Omit = omit, health_checks: bool | Omit = omit, + hitl: bool | Omit = omit, login_url: str | Omit = omit, proxy: connection_create_params.Proxy | Omit = omit, record_session: bool | Omit = omit, @@ -814,6 +828,12 @@ async def create( the automatic flow (since re-auth is only triggered by a failed scheduled health check). Defaults to true. + hitl: Whether a login blocked by a CAPTCHA the browser cannot solve pauses for a + person instead of failing. The flow moves to AWAITING_HUMAN_INTERVENTION with a + `human_intervention` choice; the person completes the challenge in + `live_view_url`, then submits that choice to resume. Reauthentication never + pauses. Defaults to false. + login_url: Optional login page URL to skip discovery proxy: Deprecated. Use browser.proxy. Retained during migration for existing clients. @@ -847,6 +867,7 @@ async def create( "credential": credential, "health_check_interval": health_check_interval, "health_checks": health_checks, + "hitl": hitl, "login_url": login_url, "proxy": proxy, "record_session": record_session, @@ -910,6 +931,7 @@ async def update( credential: connection_update_params.Credential | Omit = omit, health_check_interval: int | Omit = omit, health_checks: bool | Omit = omit, + hitl: bool | Omit = omit, login_url: str | Omit = omit, proxy: connection_update_params.Proxy | Omit = omit, record_session: bool | Omit = omit, @@ -961,6 +983,9 @@ async def update( on the automatic flow (since re-auth is only triggered by a failed scheduled health check). + hitl: Whether a login blocked by a CAPTCHA the browser cannot solve pauses for a + person instead of failing + login_url: Login page URL. Set to empty string to clear. proxy: Deprecated. Use browser.proxy. Retained during migration for existing clients. @@ -992,6 +1017,7 @@ async def update( "credential": credential, "health_check_interval": health_check_interval, "health_checks": health_checks, + "hitl": hitl, "login_url": login_url, "proxy": proxy, "record_session": record_session, diff --git a/src/kernel/types/auth/connection_create_params.py b/src/kernel/types/auth/connection_create_params.py index bf0ac55b..01fcac7b 100644 --- a/src/kernel/types/auth/connection_create_params.py +++ b/src/kernel/types/auth/connection_create_params.py @@ -104,6 +104,15 @@ class ConnectionCreateParams(TypedDict, total=False): triggered by a failed scheduled health check). Defaults to true. """ + hitl: bool + """ + Whether a login blocked by a CAPTCHA the browser cannot solve pauses for a + person instead of failing. The flow moves to AWAITING_HUMAN_INTERVENTION with a + `human_intervention` choice; the person completes the challenge in + `live_view_url`, then submits that choice to resume. Reauthentication never + pauses. Defaults to false. + """ + login_url: str """Optional login page URL to skip discovery""" diff --git a/src/kernel/types/auth/connection_follow_response.py b/src/kernel/types/auth/connection_follow_response.py index c7690794..7dac9b23 100644 --- a/src/kernel/types/auth/connection_follow_response.py +++ b/src/kernel/types/auth/connection_follow_response.py @@ -31,9 +31,20 @@ class ManagedAuthStateEventChoice(BaseModel): """Human-readable choice label.""" type: Literal[ - "mfa_method", "sso_provider", "sign_in_method", "auth_method", "identifier_method", "account", "other" + "mfa_method", + "sso_provider", + "sign_in_method", + "auth_method", + "identifier_method", + "account", + "human_intervention", + "other", ] - """Choice type.""" + """Choice type. + + A `human_intervention` choice confirms the person finished the challenge in the + live view. + """ context: Optional[str] = None """Context captured for a choice.""" @@ -181,7 +192,14 @@ class ManagedAuthStateEvent(BaseModel): flow_status: Literal["IN_PROGRESS", "SUCCESS", "FAILED", "EXPIRED", "CANCELED"] """Current flow status.""" - flow_step: Literal["DISCOVERING", "AWAITING_INPUT", "AWAITING_EXTERNAL_ACTION", "SUBMITTING", "COMPLETED"] + flow_step: Literal[ + "DISCOVERING", + "AWAITING_INPUT", + "AWAITING_EXTERNAL_ACTION", + "AWAITING_HUMAN_INTERVENTION", + "SUBMITTING", + "COMPLETED", + ] """Current step in the flow.""" timestamp: datetime diff --git a/src/kernel/types/auth/connection_update_params.py b/src/kernel/types/auth/connection_update_params.py index 36a9a9f8..b16831f5 100644 --- a/src/kernel/types/auth/connection_update_params.py +++ b/src/kernel/types/auth/connection_update_params.py @@ -73,6 +73,12 @@ class ConnectionUpdateParams(TypedDict, total=False): only triggered by a failed scheduled health check). """ + hitl: bool + """ + Whether a login blocked by a CAPTCHA the browser cannot solve pauses for a + person instead of failing + """ + login_url: str """Login page URL. Set to empty string to clear.""" diff --git a/src/kernel/types/auth/managed_auth.py b/src/kernel/types/auth/managed_auth.py index aab06668..d6a36e88 100644 --- a/src/kernel/types/auth/managed_auth.py +++ b/src/kernel/types/auth/managed_auth.py @@ -133,9 +133,20 @@ class Choice(BaseModel): """Human-readable choice label.""" type: Literal[ - "mfa_method", "sso_provider", "sign_in_method", "auth_method", "identifier_method", "account", "other" + "mfa_method", + "sso_provider", + "sign_in_method", + "auth_method", + "identifier_method", + "account", + "human_intervention", + "other", ] - """Choice type.""" + """Choice type. + + A `human_intervention` choice confirms the person finished the challenge in the + live view. + """ context: Optional[str] = None """Context captured for a choice.""" @@ -308,6 +319,12 @@ class ManagedAuth(BaseModel): domain: str """Target domain for authentication""" + hitl: bool + """ + Whether a login blocked by a CAPTCHA the browser cannot solve pauses at + AWAITING_HUMAN_INTERVENTION so a person can complete it in the live view. + """ + profile_name: str """Name of the profile associated with this auth connection""" @@ -506,7 +523,14 @@ class ManagedAuth(BaseModel): """Current flow status (null when no flow in progress)""" flow_step: Optional[ - Literal["DISCOVERING", "AWAITING_INPUT", "AWAITING_EXTERNAL_ACTION", "SUBMITTING", "COMPLETED"] + Literal[ + "DISCOVERING", + "AWAITING_INPUT", + "AWAITING_EXTERNAL_ACTION", + "AWAITING_HUMAN_INTERVENTION", + "SUBMITTING", + "COMPLETED", + ] ] = None """Current step in the flow (null when no flow in progress)""" diff --git a/tests/api_resources/auth/test_connections.py b/tests/api_resources/auth/test_connections.py index f4bf875f..3dded1fc 100644 --- a/tests/api_resources/auth/test_connections.py +++ b/tests/api_resources/auth/test_connections.py @@ -113,6 +113,7 @@ def test_method_create_with_all_params(self, client: Kernel) -> None: }, health_check_interval=3600, health_checks=True, + hitl=False, login_url="https://netflix.com/login", proxy={ "id": "id", @@ -281,6 +282,7 @@ def test_method_update_with_all_params(self, client: Kernel) -> None: }, health_check_interval=3600, health_checks=True, + hitl=False, login_url="https://netflix.com/login", proxy={ "id": "id", @@ -782,6 +784,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncKernel) -> }, health_check_interval=3600, health_checks=True, + hitl=False, login_url="https://netflix.com/login", proxy={ "id": "id", @@ -950,6 +953,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncKernel) -> }, health_check_interval=3600, health_checks=True, + hitl=False, login_url="https://netflix.com/login", proxy={ "id": "id",