Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.96.0"
".": "0.97.0"
}
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [0.97.0](https://github.com/kernel/kernel-python-sdk/compare/v0.96.0...v0.97.0) (2026-08-31)


### Features

* Expose captcha task and challenge outcomes ([42c33c6](https://github.com/kernel/kernel-python-sdk/commit/42c33c6e08ed6018cd93ddf6704ea70b206ca159))
* Unify managed auth reauth eligibility and blockers ([8e11fb2](https://github.com/kernel/kernel-python-sdk/commit/8e11fb2ab0b6ddddcb28af0d503489b94cfba1f0))

## [0.96.0](https://github.com/kernel/kernel-python-sdk/compare/v0.95.0...v0.96.0) (2026-08-27)


Expand Down
2 changes: 2 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ Types:
from kernel.types.browsers import (
BrowserAPICallEvent,
BrowserCallStack,
BrowserCaptchaChallengeResultEvent,
BrowserCaptchaSolveResultEvent,
BrowserCaptchaSolveStartedEvent,
BrowserCdpCommandEvent,
BrowserCdpCommandMethod,
BrowserCdpConnectEvent,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "kernel"
version = "0.96.0"
version = "0.97.0"
description = "The official Python library for the kernel API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion src/kernel/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "kernel"
__version__ = "0.96.0" # x-release-please-version
__version__ = "0.97.0" # x-release-please-version
7 changes: 5 additions & 2 deletions src/kernel/types/auth/managed_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ class ManagedAuth(BaseModel):
"has_credential",
"viable_plans_found",
"no_requirements_recorded",
"totp_reauth_allowed",
"requirements_satisfiable",
"no_prior_successful_login",
"no_credential",
Expand All @@ -400,8 +401,10 @@ class ManagedAuth(BaseModel):
- `viable_plans_found` — at least one stored login plan can be replayed
- `no_requirements_recorded` — no recorded credential requirements to fail
against
- `requirements_satisfiable` — recorded requirements can be met by the attached
credential
- `totp_reauth_allowed` — TOTP is the only recorded requirement and is safe to
attempt automatically
- `requirements_satisfiable` — recorded requirements contain no recognized
blocker

Negative values (a human must complete the login flow):

Expand Down
4 changes: 4 additions & 0 deletions src/kernel/types/browsers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
from .browser_live_view_disconnect_event import BrowserLiveViewDisconnectEvent as BrowserLiveViewDisconnectEvent
from .browser_monitor_disconnected_event import BrowserMonitorDisconnectedEvent as BrowserMonitorDisconnectedEvent
from .computer_capture_screenshot_params import ComputerCaptureScreenshotParams as ComputerCaptureScreenshotParams
from .browser_captcha_solve_started_event import BrowserCaptchaSolveStartedEvent as BrowserCaptchaSolveStartedEvent
from .browser_telemetry_categories_config import BrowserTelemetryCategoriesConfig as BrowserTelemetryCategoriesConfig
from .browser_network_loading_failed_event import BrowserNetworkLoadingFailedEvent as BrowserNetworkLoadingFailedEvent
from .browser_telemetry_cdp_control_config import BrowserTelemetryCdpControlConfig as BrowserTelemetryCdpControlConfig
Expand All @@ -99,6 +100,9 @@
from .computer_set_cursor_visibility_params import (
ComputerSetCursorVisibilityParams as ComputerSetCursorVisibilityParams,
)
from .browser_captcha_challenge_result_event import (
BrowserCaptchaChallengeResultEvent as BrowserCaptchaChallengeResultEvent,
)
from .browser_monitor_reconnect_failed_event import (
BrowserMonitorReconnectFailedEvent as BrowserMonitorReconnectFailedEvent,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import Optional
from typing_extensions import Literal

from ..._models import BaseModel
from .browser_event_source import BrowserEventSource

__all__ = ["BrowserCaptchaChallengeResultEvent", "Data"]


class Data(BaseModel):
"""Per-challenge payload.

This event is emitted once per challenge and determines its overall outcome; captcha_solve_started and captcha_solve_result describe individual tasks and may occur multiple times within the challenge.
"""

captcha_type: Literal["hcaptcha", "recaptcha_v2", "recaptcha_v3", "turnstile", "geetest", "press_and_hold", "other"]
"""Captcha kind.

Enterprise reCAPTCHA variants are grouped into their version bucket
(recaptcha_v2 or recaptcha_v3), press-and-hold challenges use press_and_hold,
and unlisted kinds use other.
"""

challenge_id: str
"""Opaque identifier shared by events for one visible challenge.

An image-grid captcha may create multiple task_id values for one challenge_id.
The same value may continue across a page reload when the challenge episode
continues. It does not indicate task ordering or challenge completion.
"""

duration_ms: float
"""
Wall-clock duration from the challenge appearing to its terminal outcome,
covering every solver attempt in between.
"""

status: Literal["solved", "failure", "timeout", "abandoned"]
"""Terminal outcome of the visible challenge.

solved: the page observed the challenge clear after a solver attempt. failure: a
terminal solver failure occurred, or all attempts ended while the challenge
remained. timeout: the challenge-level wait budget expired while the challenge
remained. abandoned: observation ended without an attributable terminal
challenge outcome. This includes a dismissed widget or page unload without a
solved signal or terminal solver outcome, and a token appearing while multiple
same-provider challenges are open, because the producer cannot attribute that
token to this visible challenge. A captcha_solve_result with the same
challenge_id may therefore report success while the challenge result reports
abandoned. A solved challenge does not prove the site accepted the token or that
the guarded action succeeded.
"""

website_host: Optional[str] = None
"""Host of the page where the challenge appeared."""

website_path: Optional[str] = None
"""Path of the page where the challenge appeared. Query string excluded."""


class BrowserCaptchaChallengeResultEvent(BaseModel):
"""A visible captcha challenge reached a terminal outcome."""

category: Literal["captcha"]

data: Data
"""Per-challenge payload.

This event is emitted once per challenge and determines its overall outcome;
captcha_solve_started and captcha_solve_result describe individual tasks and may
occur multiple times within the challenge.
"""

source: BrowserEventSource
"""Provenance metadata identifying which producer emitted the event."""

ts: int
"""Event timestamp in Unix microseconds."""

type: Literal["captcha_challenge_result"]

truncated: Optional[bool] = None
"""True if the data field was truncated due to size limits."""
25 changes: 19 additions & 6 deletions src/kernel/types/browsers/browser_captcha_solve_result_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@


class Data(BaseModel):
captcha_type: Literal["hcaptcha", "recaptcha_v2", "recaptcha_v3", "turnstile", "geetest", "other"]
"""Captcha vendor family.
captcha_type: Literal["hcaptcha", "recaptcha_v2", "recaptcha_v3", "turnstile", "geetest", "press_and_hold", "other"]
"""Captcha kind.

Provider-specific task names are normalized into this set; anything not covered
is reported as other.
Enterprise reCAPTCHA variants are grouped into their version bucket
(recaptcha_v2 or recaptcha_v3), press-and-hold challenges use press_and_hold,
and unlisted kinds use other.
"""

duration_ms: float
"""Wall-clock duration from solve start to terminal outcome."""
"""Wall-clock duration from solve start to terminal outcome.

Authoritative solve timing; do not derive it from the gap to a
captcha_solve_started event, whose delivery and ordering are not guaranteed.
"""

status: Literal["success", "failure", "timeout", "abandoned"]
"""Terminal outcome.
Expand All @@ -28,14 +33,22 @@ class Data(BaseModel):
budget. abandoned: caller cancelled or the page navigated away mid-solve.
"""

challenge_id: Optional[str] = None
"""Opaque identifier shared by events for one visible challenge.

An image-grid captcha may create multiple task_id values for one challenge_id.
The same value may continue across a page reload when the challenge episode
continues. It does not indicate task ordering or challenge completion.
"""

error_code: Optional[str] = None
"""Solver-specific error code on failure (e.g.

ERROR_CAPTCHA_UNSOLVABLE). Absent on success.
"""

task_id: Optional[str] = None
"""Solver-assigned identifier. Opaque, useful for support cross-references."""
"""Opaque identifier shared with the matching captcha_solve_started."""

website_host: Optional[str] = None
"""Host of the page where the captcha was solved."""
Expand Down
70 changes: 70 additions & 0 deletions src/kernel/types/browsers/browser_captcha_solve_started_event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import Optional
from typing_extensions import Literal

from ..._models import BaseModel
from .browser_event_source import BrowserEventSource

__all__ = ["BrowserCaptchaSolveStartedEvent", "Data"]


class Data(BaseModel):
"""Per-task payload.

A visible challenge may create multiple tasks. When present, task_id correlates this event with a captcha_solve_result, while challenge_id groups tasks from the same challenge. Events may arrive out of order or be absent, so their arrival does not indicate current solve state.
"""

captcha_type: Literal["hcaptcha", "recaptcha_v2", "recaptcha_v3", "turnstile", "geetest", "press_and_hold", "other"]
"""Captcha kind.

Enterprise reCAPTCHA variants are grouped into their version bucket
(recaptcha_v2 or recaptcha_v3), press-and-hold challenges use press_and_hold,
and unlisted kinds use other.
"""

challenge_id: Optional[str] = None
"""Opaque identifier shared by events for one visible challenge.

An image-grid captcha may create multiple task_id values for one challenge_id.
The same value may continue across a page reload when the challenge episode
continues. It does not indicate task ordering or challenge completion.
"""

task_id: Optional[str] = None
"""Opaque identifier shared with the matching captcha_solve_result."""

website_host: Optional[str] = None
"""Host of the page where the captcha is being solved.

May be empty for solver tasks that carry no page URL.
"""

website_path: Optional[str] = None
"""Path of the page where the captcha is being solved. Query string excluded."""


class BrowserCaptchaSolveStartedEvent(BaseModel):
"""A captcha solver accepted a task."""

category: Literal["captcha"]

data: Data
"""Per-task payload.

A visible challenge may create multiple tasks. When present, task_id correlates
this event with a captcha_solve_result, while challenge_id groups tasks from the
same challenge. Events may arrive out of order or be absent, so their arrival
does not indicate current solve state.
"""

source: BrowserEventSource
"""Provenance metadata identifying which producer emitted the event."""

ts: int
"""Event timestamp in Unix microseconds."""

type: Literal["captcha_solve_started"]

truncated: Optional[bool] = None
"""True if the data field was truncated due to size limits."""
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class BrowserTelemetryCategoriesConfig(BaseModel):
"""

captcha: Optional[BrowserTelemetryCategoryConfig] = None
"""Captcha solve attempt outcomes. On by default."""
"""Captcha solver tasks and visible challenge outcomes. On by default."""

connection: Optional[BrowserTelemetryCategoryConfig] = None
"""Client attach/detach lifecycle for the CDP proxy and live view. On by default."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class BrowserTelemetryCategoriesConfigParam(TypedDict, total=False):
"""

captcha: BrowserTelemetryCategoryConfigParam
"""Captcha solve attempt outcomes. On by default."""
"""Captcha solver tasks and visible challenge outcomes. On by default."""

connection: BrowserTelemetryCategoryConfigParam
"""Client attach/detach lifecycle for the CDP proxy and live view. On by default."""
Expand Down
4 changes: 4 additions & 0 deletions src/kernel/types/browsers/browser_telemetry_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@
from .browser_captcha_solve_result_event import BrowserCaptchaSolveResultEvent
from .browser_live_view_disconnect_event import BrowserLiveViewDisconnectEvent
from .browser_monitor_disconnected_event import BrowserMonitorDisconnectedEvent
from .browser_captcha_solve_started_event import BrowserCaptchaSolveStartedEvent
from .browser_network_loading_failed_event import BrowserNetworkLoadingFailedEvent
from .browser_page_dom_content_loaded_event import BrowserPageDomContentLoadedEvent
from .browser_page_navigation_settled_event import BrowserPageNavigationSettledEvent
from .browser_captcha_challenge_result_event import BrowserCaptchaChallengeResultEvent
from .browser_monitor_reconnect_failed_event import BrowserMonitorReconnectFailedEvent
from .browser_interaction_scroll_settled_event import BrowserInteractionScrollSettledEvent

Expand Down Expand Up @@ -76,7 +78,9 @@
BrowserCdpDisconnectEvent,
BrowserLiveViewConnectEvent,
BrowserLiveViewDisconnectEvent,
BrowserCaptchaSolveStartedEvent,
BrowserCaptchaSolveResultEvent,
BrowserCaptchaChallengeResultEvent,
BrowserSystemOomKillEvent,
BrowserServiceCrashedEvent,
],
Expand Down
Loading