diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fe941d15..c3e137b1 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.79.0" + ".": "0.80.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 3807b2f3..9e326663 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 127 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-e04362b2c82b88f4f7fb43209c764fa9fdf37fe98932e142547be43a1e99c50b.yml -openapi_spec_hash: b16e79bfd6cac36090c815a8184b9e09 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-5b9eb5cdadbc7a5f404f5c2cec40f726e5fece54bf8e2dd29ab5c7700eb44f0e.yml +openapi_spec_hash: 63dd0798a4c0ed6477af50fff397f5dc config_hash: 77ee715aa17061166f9a02b264a21b8d diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c25a068..7d7eda18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.80.0 (2026-07-17) + +Full Changelog: [v0.79.0...v0.80.0](https://github.com/kernel/kernel-python-sdk/compare/v0.79.0...v0.80.0) + +### Features + +* Add example to ProxyCheckRequest.url so API reference sample shows it ([2a288ca](https://github.com/kernel/kernel-python-sdk/commit/2a288ca546da7760cdc16e566260fd440ae36fb7)) +* **managed-auth:** add TS CUA worker contract (KERNEL-1456) ([de2fc59](https://github.com/kernel/kernel-python-sdk/commit/de2fc590e00152328ac6a4f5165da0fb727644bb)) + ## 0.79.0 (2026-07-15) Full Changelog: [v0.78.1...v0.79.0](https://github.com/kernel/kernel-python-sdk/compare/v0.78.1...v0.79.0) diff --git a/pyproject.toml b/pyproject.toml index 7727ba08..e6a19285 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.79.0" +version = "0.80.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 73b9f569..222542c7 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.79.0" # x-release-please-version +__version__ = "0.80.0" # x-release-please-version diff --git a/src/kernel/resources/auth/connections.py b/src/kernel/resources/auth/connections.py index 30f8dca8..05de4f04 100644 --- a/src/kernel/resources/auth/connections.py +++ b/src/kernel/resources/auth/connections.py @@ -505,8 +505,10 @@ def submit( self, id: str, *, + field_values: Dict[str, str] | Omit = omit, fields: Dict[str, str] | Omit = omit, mfa_option_id: str | Omit = omit, + selected_choice_id: str | Omit = omit, sign_in_option_id: str | Omit = omit, sso_button_selector: str | Omit = omit, sso_provider: str | Omit = omit, @@ -523,10 +525,14 @@ def submit( progress and get results. Args: + field_values: Canonical map of field ID to submitted value. + fields: Map of field name to value mfa_option_id: The MFA method type to select (when mfa_options were returned) + selected_choice_id: Canonical choice ID selected by the user. + sign_in_option_id: The sign-in option ID to select (when sign_in_options were returned) sso_button_selector: XPath selector for the SSO button to click (ODA). Use sso_provider instead for @@ -549,8 +555,10 @@ def submit( path_template("/auth/connections/{id}/submit", id=id), body=maybe_transform( { + "field_values": field_values, "fields": fields, "mfa_option_id": mfa_option_id, + "selected_choice_id": selected_choice_id, "sign_in_option_id": sign_in_option_id, "sso_button_selector": sso_button_selector, "sso_provider": sso_provider, @@ -1088,8 +1096,10 @@ async def submit( self, id: str, *, + field_values: Dict[str, str] | Omit = omit, fields: Dict[str, str] | Omit = omit, mfa_option_id: str | Omit = omit, + selected_choice_id: str | Omit = omit, sign_in_option_id: str | Omit = omit, sso_button_selector: str | Omit = omit, sso_provider: str | Omit = omit, @@ -1106,10 +1116,14 @@ async def submit( progress and get results. Args: + field_values: Canonical map of field ID to submitted value. + fields: Map of field name to value mfa_option_id: The MFA method type to select (when mfa_options were returned) + selected_choice_id: Canonical choice ID selected by the user. + sign_in_option_id: The sign-in option ID to select (when sign_in_options were returned) sso_button_selector: XPath selector for the SSO button to click (ODA). Use sso_provider instead for @@ -1132,8 +1146,10 @@ async def submit( path_template("/auth/connections/{id}/submit", id=id), body=await async_maybe_transform( { + "field_values": field_values, "fields": fields, "mfa_option_id": mfa_option_id, + "selected_choice_id": selected_choice_id, "sign_in_option_id": sign_in_option_id, "sso_button_selector": sso_button_selector, "sso_provider": sso_provider, diff --git a/src/kernel/types/auth/connection_follow_response.py b/src/kernel/types/auth/connection_follow_response.py index 1cd1a141..7d6dfc63 100644 --- a/src/kernel/types/auth/connection_follow_response.py +++ b/src/kernel/types/auth/connection_follow_response.py @@ -12,13 +12,36 @@ __all__ = [ "ConnectionFollowResponse", "ManagedAuthStateEvent", + "ManagedAuthStateEventChoice", "ManagedAuthStateEventDiscoveredField", + "ManagedAuthStateEventField", "ManagedAuthStateEventMfaOption", "ManagedAuthStateEventPendingSSOButton", "ManagedAuthStateEventSignInOption", ] +class ManagedAuthStateEventChoice(BaseModel): + """Canonical auth-flow choice awaiting user selection.""" + + id: str + """Stable choice identifier for canonical submit.""" + + label: str + """Human-readable choice label.""" + + type: Literal[ + "mfa_method", "sso_provider", "sign_in_method", "auth_method", "identifier_method", "account", "other" + ] + """Choice type.""" + + description: Optional[str] = None + """Additional context for the choice.""" + + observed_selector: Optional[str] = None + """Selector for the visible choice, when available.""" + + class ManagedAuthStateEventDiscoveredField(BaseModel): """A discovered form field""" @@ -53,6 +76,28 @@ class ManagedAuthStateEventDiscoveredField(BaseModel): """Whether field is required""" +class ManagedAuthStateEventField(BaseModel): + """Canonical field awaiting user input.""" + + id: str + """Stable field identifier for canonical submit.""" + + ref: str + """Credential reference name to store the submitted value under.""" + + type: Literal["identifier", "password", "code", "totp_code", "totp_secret", "text"] + """Managed-auth field type.""" + + label: Optional[str] = None + """Human-readable label shown to the user.""" + + observed_selector: Optional[str] = None + """Selector for the visible field, when available.""" + + required: Optional[bool] = None + """Whether this field is required.""" + + class ManagedAuthStateEventMfaOption(BaseModel): """An MFA method option for verification""" @@ -118,6 +163,13 @@ class ManagedAuthStateEvent(BaseModel): timestamp: datetime """Time the state was reported.""" + choices: Optional[List[ManagedAuthStateEventChoice]] = None + """Canonical choices awaiting selection. + + Prefer this over pending_sso_buttons, mfa_options, and sign_in_options when + present. + """ + discovered_fields: Optional[List[ManagedAuthStateEventDiscoveredField]] = None """ Fields awaiting input (present when flow_step=AWAITING_INPUT; may also be @@ -136,6 +188,12 @@ class ManagedAuthStateEvent(BaseModel): flow_step=AWAITING_EXTERNAL_ACTION). """ + fields: Optional[List[ManagedAuthStateEventField]] = None + """Canonical fields awaiting input. + + Prefer this over discovered_fields when present. + """ + flow_type: Optional[Literal["LOGIN", "REAUTH"]] = None """Type of the current flow.""" diff --git a/src/kernel/types/auth/connection_submit_params.py b/src/kernel/types/auth/connection_submit_params.py index f785b856..19861ed8 100644 --- a/src/kernel/types/auth/connection_submit_params.py +++ b/src/kernel/types/auth/connection_submit_params.py @@ -9,12 +9,18 @@ class ConnectionSubmitParams(TypedDict, total=False): + field_values: Dict[str, str] + """Canonical map of field ID to submitted value.""" + fields: Dict[str, str] """Map of field name to value""" mfa_option_id: str """The MFA method type to select (when mfa_options were returned)""" + selected_choice_id: str + """Canonical choice ID selected by the user.""" + sign_in_option_id: str """The sign-in option ID to select (when sign_in_options were returned)""" diff --git a/src/kernel/types/auth/managed_auth.py b/src/kernel/types/auth/managed_auth.py index 3addc5e0..6dfb8401 100644 --- a/src/kernel/types/auth/managed_auth.py +++ b/src/kernel/types/auth/managed_auth.py @@ -6,7 +6,37 @@ from ..._models import BaseModel -__all__ = ["ManagedAuth", "Credential", "DiscoveredField", "MfaOption", "PendingSSOButton", "SignInOption"] +__all__ = [ + "ManagedAuth", + "Choice", + "Credential", + "DiscoveredField", + "Field", + "MfaOption", + "PendingSSOButton", + "SignInOption", +] + + +class Choice(BaseModel): + """Canonical auth-flow choice awaiting user selection.""" + + id: str + """Stable choice identifier for canonical submit.""" + + label: str + """Human-readable choice label.""" + + type: Literal[ + "mfa_method", "sso_provider", "sign_in_method", "auth_method", "identifier_method", "account", "other" + ] + """Choice type.""" + + description: Optional[str] = None + """Additional context for the choice.""" + + observed_selector: Optional[str] = None + """Selector for the visible choice, when available.""" class Credential(BaseModel): @@ -65,6 +95,28 @@ class DiscoveredField(BaseModel): """Whether field is required""" +class Field(BaseModel): + """Canonical field awaiting user input.""" + + id: str + """Stable field identifier for canonical submit.""" + + ref: str + """Credential reference name to store the submitted value under.""" + + type: Literal["identifier", "password", "code", "totp_code", "totp_secret", "text"] + """Managed-auth field type.""" + + label: Optional[str] = None + """Human-readable label shown to the user.""" + + observed_selector: Optional[str] = None + """Selector for the visible field, when available.""" + + required: Optional[bool] = None + """Whether this field is required.""" + + class MfaOption(BaseModel): """An MFA method option for verification""" @@ -243,6 +295,13 @@ class ManagedAuth(BaseModel): automatically """ + choices: Optional[List[Choice]] = None + """Canonical choices awaiting selection. + + Prefer this over pending_sso_buttons, mfa_options, and sign_in_options when + present. + """ + credential: Optional[Credential] = None """Reference to credentials for the auth connection. Use one of: @@ -269,6 +328,12 @@ class ManagedAuth(BaseModel): flow_step=awaiting_external_action) """ + fields: Optional[List[Field]] = None + """Canonical fields awaiting input. + + Prefer this over discovered_fields when present. + """ + flow_expires_at: Optional[datetime] = None """When the current flow expires (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 b92cd790..8bdbc9ad 100644 --- a/tests/api_resources/auth/test_connections.py +++ b/tests/api_resources/auth/test_connections.py @@ -386,11 +386,16 @@ def test_method_submit(self, client: Kernel) -> None: def test_method_submit_with_all_params(self, client: Kernel) -> None: connection = client.auth.connections.submit( id="id", + field_values={ + "field_email": "user@example.com", + "field_password": "secret", + }, fields={ "email": "user@example.com", "password": "secret", }, mfa_option_id="sms", + selected_choice_id="google", sign_in_option_id="work-account", sso_button_selector="xpath=//button[contains(text(), 'Continue with Google')]", sso_provider="google", @@ -853,11 +858,16 @@ async def test_method_submit(self, async_client: AsyncKernel) -> None: async def test_method_submit_with_all_params(self, async_client: AsyncKernel) -> None: connection = await async_client.auth.connections.submit( id="id", + field_values={ + "field_email": "user@example.com", + "field_password": "secret", + }, fields={ "email": "user@example.com", "password": "secret", }, mfa_option_id="sms", + selected_choice_id="google", sign_in_option_id="work-account", sso_button_selector="xpath=//button[contains(text(), 'Continue with Google')]", sso_provider="google", diff --git a/tests/api_resources/test_proxies.py b/tests/api_resources/test_proxies.py index cbe6e355..bdc48364 100644 --- a/tests/api_resources/test_proxies.py +++ b/tests/api_resources/test_proxies.py @@ -252,7 +252,7 @@ def test_method_check(self, client: Kernel) -> None: def test_method_check_with_all_params(self, client: Kernel) -> None: proxy = client.proxies.check( id="id", - url="url", + url="https://example.com", ) assert_matches_type(ProxyCheckResponse, proxy, path=["response"]) @@ -524,7 +524,7 @@ async def test_method_check(self, async_client: AsyncKernel) -> None: async def test_method_check_with_all_params(self, async_client: AsyncKernel) -> None: proxy = await async_client.proxies.check( id="id", - url="url", + url="https://example.com", ) assert_matches_type(ProxyCheckResponse, proxy, path=["response"])