From 76dee03d215481de6ee42b2cba631b5f5893c1a3 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 19:58:01 +0000 Subject: [PATCH 1/5] feat: Square UKP and Hypeman placement load factors Stainless-Generated-From: 65cfe5b8da1de339f51b2027237b88f0746f376b --- src/kernel/types/analysis.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/kernel/types/analysis.py b/src/kernel/types/analysis.py index 34184ae4..6ce7c3b1 100644 --- a/src/kernel/types/analysis.py +++ b/src/kernel/types/analysis.py @@ -31,3 +31,9 @@ class Analysis(BaseModel): status: Literal["running", "completed", "failed", "canceled", "expired"] """Lifecycle status of a background analysis.""" + + intent: Optional[str] = None + """The workload description supplied for this analysis. + + Null when the analysis only tested connectivity. + """ From 37d5e9c3d5db76bece8f8ba8d5358b939bc79315 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2026 20:48:48 +0000 Subject: [PATCH 2/5] feat: Add processor-bound AgentCard preparation contracts Stainless-Generated-From: 1b2956dd517385b95316303d9f6b5e962f8d2a40 --- api.md | 1 + src/kernel/resources/vaults/items.py | 20 ++++++------ src/kernel/types/vaults/__init__.py | 1 + .../vaults/agentcard_checkout_preparation.py | 7 ++-- .../vaults/agentcard_prepared_processor.py | 7 ++++ .../types/vaults/card_vault_item_state.py | 2 +- .../vaults/item_perform_operation_params.py | 12 +++---- ...kout_vault_item_operation_request_param.py | 14 ++++---- .../vaults/vault_checkout_context_param.py | 28 +++++++++++----- tests/api_resources/vaults/test_items.py | 32 +++++++++++++++++++ 10 files changed, 90 insertions(+), 34 deletions(-) create mode 100644 src/kernel/types/vaults/agentcard_prepared_processor.py diff --git a/api.md b/api.md index fdb9696b..dc22d102 100644 --- a/api.md +++ b/api.md @@ -526,6 +526,7 @@ Types: from kernel.types.vaults import ( AgentcardCheckoutAuthorization, AgentcardCheckoutPreparation, + AgentcardPreparedProcessor, AuthorizeVaultItemOperationRequest, CardVaultItemSpec, CardVaultItemState, diff --git a/src/kernel/resources/vaults/items.py b/src/kernel/resources/vaults/items.py index ea0fbf83..cd53e796 100644 --- a/src/kernel/resources/vaults/items.py +++ b/src/kernel/resources/vaults/items.py @@ -511,11 +511,11 @@ def perform_operation( leave the outcome unknown; do not automatically retry. Args: - checkout: Required when preparing an unused AgentCard card for Square. Consent is bound to - this browser and declared merchant origin, not a tab. Wait for the item's - ready_to_submit status before native Pay and submit within its readiness - deadline. Unused preparations expire automatically; every preparation is - single-use, including after failure or expiry. + checkout: Required when preparing an unused AgentCard card for a supported tokenization + processor. Consent is bound to this browser and declared merchant origin, not a + tab. Wait for the item's ready_to_submit status before native Pay and submit + within its readiness deadline. Unused preparations expire automatically; every + preparation is single-use, including after failure or expiry. extra_headers: Send extra headers @@ -1274,11 +1274,11 @@ async def perform_operation( leave the outcome unknown; do not automatically retry. Args: - checkout: Required when preparing an unused AgentCard card for Square. Consent is bound to - this browser and declared merchant origin, not a tab. Wait for the item's - ready_to_submit status before native Pay and submit within its readiness - deadline. Unused preparations expire automatically; every preparation is - single-use, including after failure or expiry. + checkout: Required when preparing an unused AgentCard card for a supported tokenization + processor. Consent is bound to this browser and declared merchant origin, not a + tab. Wait for the item's ready_to_submit status before native Pay and submit + within its readiness deadline. Unused preparations expire automatically; every + preparation is single-use, including after failure or expiry. extra_headers: Send extra headers diff --git a/src/kernel/types/vaults/__init__.py b/src/kernel/types/vaults/__init__.py index 9188791e..e2dd28eb 100644 --- a/src/kernel/types/vaults/__init__.py +++ b/src/kernel/types/vaults/__init__.py @@ -24,6 +24,7 @@ from .credential_vault_item_spec import CredentialVaultItemSpec as CredentialVaultItemSpec from .credential_vault_field_type import CredentialVaultFieldType as CredentialVaultFieldType from .credential_vault_item_state import CredentialVaultItemState as CredentialVaultItemState +from .agentcard_prepared_processor import AgentcardPreparedProcessor as AgentcardPreparedProcessor from .credential_collection_action import CredentialCollectionAction as CredentialCollectionAction from .credential_vault_field_state import CredentialVaultFieldState as CredentialVaultFieldState from .vault_checkout_context_param import VaultCheckoutContextParam as VaultCheckoutContextParam diff --git a/src/kernel/types/vaults/agentcard_checkout_preparation.py b/src/kernel/types/vaults/agentcard_checkout_preparation.py index 8296b2fd..7f9da71f 100644 --- a/src/kernel/types/vaults/agentcard_checkout_preparation.py +++ b/src/kernel/types/vaults/agentcard_checkout_preparation.py @@ -5,12 +5,13 @@ from typing_extensions import Literal from ..._models import BaseModel +from .agentcard_prepared_processor import AgentcardPreparedProcessor __all__ = ["AgentcardCheckoutPreparation"] class AgentcardCheckoutPreparation(BaseModel): - """One-use Square checkout preparation. + """One-use processor-bound checkout preparation. Keep the approval page open through token handoff. The amount is display-only and does not constrain the merchant's eventual charge. """ @@ -19,10 +20,12 @@ class AgentcardCheckoutPreparation(BaseModel): created_at: datetime - environment: Literal["production", "sandbox"] + environment: Literal["production", "sandbox", "shared"] merchant_origin: str + psp: AgentcardPreparedProcessor + status: Literal["creating", "awaiting_approval", "ready", "consumed", "cancelled", "expired", "unknown"] """ Preparation consumed means egress claimed the preparation and it cannot be diff --git a/src/kernel/types/vaults/agentcard_prepared_processor.py b/src/kernel/types/vaults/agentcard_prepared_processor.py new file mode 100644 index 00000000..ebf94c86 --- /dev/null +++ b/src/kernel/types/vaults/agentcard_prepared_processor.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal, TypeAlias + +__all__ = ["AgentcardPreparedProcessor"] + +AgentcardPreparedProcessor: TypeAlias = Literal["square", "braintree", "worldpay", "bambora", "mercado_pago"] diff --git a/src/kernel/types/vaults/card_vault_item_state.py b/src/kernel/types/vaults/card_vault_item_state.py index 98459762..4785f3ac 100644 --- a/src/kernel/types/vaults/card_vault_item_state.py +++ b/src/kernel/types/vaults/card_vault_item_state.py @@ -112,7 +112,7 @@ class AgentCardCardState(BaseModel): masks: Optional[AgentCardCardStateMasks] = None preparation: Optional[AgentcardCheckoutPreparation] = None - """One-use Square checkout preparation. + """One-use processor-bound checkout preparation. Keep the approval page open through token handoff. The amount is display-only and does not constrain the merchant's eventual charge. diff --git a/src/kernel/types/vaults/item_perform_operation_params.py b/src/kernel/types/vaults/item_perform_operation_params.py index 33c38043..c1fb80c9 100644 --- a/src/kernel/types/vaults/item_perform_operation_params.py +++ b/src/kernel/types/vaults/item_perform_operation_params.py @@ -33,12 +33,12 @@ class PrepareCheckoutVaultItemOperationRequest(TypedDict, total=False): id_or_name: Required[str] checkout: Required[VaultCheckoutContextParam] - """Required when preparing an unused AgentCard card for Square. - - Consent is bound to this browser and declared merchant origin, not a tab. Wait - for the item's ready_to_submit status before native Pay and submit within its - readiness deadline. Unused preparations expire automatically; every preparation - is single-use, including after failure or expiry. + """ + Required when preparing an unused AgentCard card for a supported tokenization + processor. Consent is bound to this browser and declared merchant origin, not a + tab. Wait for the item's ready_to_submit status before native Pay and submit + within its readiness deadline. Unused preparations expire automatically; every + preparation is single-use, including after failure or expiry. """ type: Required[Literal["prepare_checkout"]] diff --git a/src/kernel/types/vaults/prepare_checkout_vault_item_operation_request_param.py b/src/kernel/types/vaults/prepare_checkout_vault_item_operation_request_param.py index 9900c513..72fdb4d2 100644 --- a/src/kernel/types/vaults/prepare_checkout_vault_item_operation_request_param.py +++ b/src/kernel/types/vaults/prepare_checkout_vault_item_operation_request_param.py @@ -10,18 +10,18 @@ class PrepareCheckoutVaultItemOperationRequestParam(TypedDict, total=False): - """Prepare an unused AgentCard card for Square checkout. + """Prepare an unused AgentCard card for a supported tokenization checkout. Deliver the returned approval URL and keep the approval page open. Poll the item until ready_to_submit, then submit native Pay before preparation.expires_at. Readiness lasts at most 30 seconds. Unused preparations expire automatically. Preparations are single-use even after failure or expiry; do not automatically retry and reconcile uncertain outcomes with the merchant. """ checkout: Required[VaultCheckoutContextParam] - """Required when preparing an unused AgentCard card for Square. - - Consent is bound to this browser and declared merchant origin, not a tab. Wait - for the item's ready_to_submit status before native Pay and submit within its - readiness deadline. Unused preparations expire automatically; every preparation - is single-use, including after failure or expiry. + """ + Required when preparing an unused AgentCard card for a supported tokenization + processor. Consent is bound to this browser and declared merchant origin, not a + tab. Wait for the item's ready_to_submit status before native Pay and submit + within its readiness deadline. Unused preparations expire automatically; every + preparation is single-use, including after failure or expiry. """ type: Required[Literal["prepare_checkout"]] diff --git a/src/kernel/types/vaults/vault_checkout_context_param.py b/src/kernel/types/vaults/vault_checkout_context_param.py index 8b08c40c..f5fda5db 100644 --- a/src/kernel/types/vaults/vault_checkout_context_param.py +++ b/src/kernel/types/vaults/vault_checkout_context_param.py @@ -4,24 +4,36 @@ from typing_extensions import Literal, Required, TypedDict +from .agentcard_prepared_processor import AgentcardPreparedProcessor + __all__ = ["VaultCheckoutContextParam"] class VaultCheckoutContextParam(TypedDict, total=False): - """Required when preparing an unused AgentCard card for Square. - - Consent is bound to this browser and declared merchant origin, not a tab. Wait for the item's ready_to_submit status before native Pay and submit within its readiness deadline. Unused preparations expire automatically; every preparation is single-use, including after failure or expiry. + """ + Required when preparing an unused AgentCard card for a supported tokenization processor. Consent is bound to this browser and declared merchant origin, not a tab. Wait for the item's ready_to_submit status before native Pay and submit within its readiness deadline. Unused preparations expire automatically; every preparation is single-use, including after failure or expiry. """ browser_id: Required[str] """Active browser session with this vault bound to it.""" - environment: Required[Literal["production", "sandbox"]] - """Square environment, independent of the AgentCard credential mode.""" + environment: Required[Literal["production", "sandbox", "shared"]] + """ + Use production or sandbox for Square, Braintree and Worldpay; shared for Bambora + and Mercado Pago. Shared endpoints do not establish test mode. Merchant + credentials/configuration determine processor test mode, independently of the + AgentCard credential mode. + """ merchant_origin: Required[str] - """Canonical HTTPS origin of the top-level merchant document, not the Square - iframe. + """ + Canonical HTTPS origin of the top-level merchant document, not a processor + iframe. HTTP localhost is accepted for tests. + """ + + psp: AgentcardPreparedProcessor + """Tokenization processor. - HTTP localhost is accepted for tests. + Omit for Square compatibility. Non-Square processors require multi-processor + preparation enablement. """ diff --git a/tests/api_resources/vaults/test_items.py b/tests/api_resources/vaults/test_items.py index 1eeb98e3..b80631eb 100644 --- a/tests/api_resources/vaults/test_items.py +++ b/tests/api_resources/vaults/test_items.py @@ -604,6 +604,22 @@ def test_method_perform_operation_overload_3(self, client: Kernel) -> None: ) assert_matches_type(VaultItemOperationResponse, item, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_perform_operation_with_all_params_overload_3(self, client: Kernel) -> None: + item = client.vaults.items.perform_operation( + key="key", + id_or_name="id_or_name", + checkout={ + "browser_id": "browser_id", + "environment": "production", + "merchant_origin": "merchant_origin", + "psp": "square", + }, + type="prepare_checkout", + ) + assert_matches_type(VaultItemOperationResponse, item, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_raw_response_perform_operation_overload_3(self, client: Kernel) -> None: @@ -1793,6 +1809,22 @@ async def test_method_perform_operation_overload_3(self, async_client: AsyncKern ) assert_matches_type(VaultItemOperationResponse, item, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_perform_operation_with_all_params_overload_3(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.perform_operation( + key="key", + id_or_name="id_or_name", + checkout={ + "browser_id": "browser_id", + "environment": "production", + "merchant_origin": "merchant_origin", + "psp": "square", + }, + type="prepare_checkout", + ) + assert_matches_type(VaultItemOperationResponse, item, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_raw_response_perform_operation_overload_3(self, async_client: AsyncKernel) -> None: From afe2feaf2dcea1f4fc160d66cfe9f3711b61a447 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Wed, 16 Sep 2026 00:43:42 +0000 Subject: [PATCH 3/5] feat: Polish and publish the Config Registry API Stainless-Generated-From: c13de5a1ff00481bd0125cfd74527f4bae1a301f --- .stats.yml | 2 +- api.md | 1 + .../resources/config_registry/analyses.py | 86 +++++++++++++++++++ .../config_registry/config_registry.py | 10 ++- .../types/config_registry_resolve_params.py | 5 +- src/kernel/types/evidence.py | 10 +-- src/kernel/types/recommendation.py | 13 ++- .../config_registry/test_analyses.py | 84 ++++++++++++++++++ 8 files changed, 191 insertions(+), 20 deletions(-) diff --git a/.stats.yml b/.stats.yml index a0ee50ed..88ce9db5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 163 +configured_endpoints: 164 diff --git a/api.md b/api.md index dc22d102..0679de62 100644 --- a/api.md +++ b/api.md @@ -109,6 +109,7 @@ Methods: - client.config_registry.analyses.retrieve(id) -> ConfigRegistryResponse - client.config_registry.analyses.list(\*\*params) -> SyncOffsetPagination[AnalysisSummary] +- client.config_registry.analyses.cancel(id) -> ConfigRegistryResponse # Browsers diff --git a/src/kernel/resources/config_registry/analyses.py b/src/kernel/resources/config_registry/analyses.py index c0cbd2c7..3d975f32 100644 --- a/src/kernel/resources/config_registry/analyses.py +++ b/src/kernel/resources/config_registry/analyses.py @@ -126,6 +126,43 @@ def list( model=AnalysisSummary, ) + def cancel( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ConfigRegistryResponse: + """Requests cancellation of a running project-scoped analysis. + + Cancellation is + asynchronous; poll the analysis until its status becomes canceled. Repeating the + request after the analysis reaches a terminal state returns the existing + outcome. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + path_template("/config-registry/analyses/{id}/cancel", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConfigRegistryResponse, + ) + class AsyncAnalysesResource(AsyncAPIResource): """Resolve browser and proxy recommendations for bot-protected sites.""" @@ -230,6 +267,43 @@ def list( model=AnalysisSummary, ) + async def cancel( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ConfigRegistryResponse: + """Requests cancellation of a running project-scoped analysis. + + Cancellation is + asynchronous; poll the analysis until its status becomes canceled. Repeating the + request after the analysis reaches a terminal state returns the existing + outcome. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + path_template("/config-registry/analyses/{id}/cancel", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConfigRegistryResponse, + ) + class AnalysesResourceWithRawResponse: def __init__(self, analyses: AnalysesResource) -> None: @@ -241,6 +315,9 @@ def __init__(self, analyses: AnalysesResource) -> None: self.list = to_raw_response_wrapper( analyses.list, ) + self.cancel = to_raw_response_wrapper( + analyses.cancel, + ) class AsyncAnalysesResourceWithRawResponse: @@ -253,6 +330,9 @@ def __init__(self, analyses: AsyncAnalysesResource) -> None: self.list = async_to_raw_response_wrapper( analyses.list, ) + self.cancel = async_to_raw_response_wrapper( + analyses.cancel, + ) class AnalysesResourceWithStreamingResponse: @@ -265,6 +345,9 @@ def __init__(self, analyses: AnalysesResource) -> None: self.list = to_streamed_response_wrapper( analyses.list, ) + self.cancel = to_streamed_response_wrapper( + analyses.cancel, + ) class AsyncAnalysesResourceWithStreamingResponse: @@ -277,3 +360,6 @@ def __init__(self, analyses: AsyncAnalysesResource) -> None: self.list = async_to_streamed_response_wrapper( analyses.list, ) + self.cancel = async_to_streamed_response_wrapper( + analyses.cancel, + ) diff --git a/src/kernel/resources/config_registry/config_registry.py b/src/kernel/resources/config_registry/config_registry.py index 27a8766c..39faa9f5 100644 --- a/src/kernel/resources/config_registry/config_registry.py +++ b/src/kernel/resources/config_registry/config_registry.py @@ -190,8 +190,9 @@ def resolve( any non-HTTPS destination as off-site and will not drive an http one. Kernel uses it to drive the browser further into the site, where it can observe protections that only appear once a session interacts. When this target already - has a verified configuration, the run confirms that one instead of re-deriving - the whole matrix, so supplying an intent narrows what can be recommended. + has a recommended configuration, the run confirms that one instead of + re-deriving the whole matrix, so supplying an intent narrows what can be + recommended. extra_headers: Send extra headers @@ -374,8 +375,9 @@ async def resolve( any non-HTTPS destination as off-site and will not drive an http one. Kernel uses it to drive the browser further into the site, where it can observe protections that only appear once a session interacts. When this target already - has a verified configuration, the run confirms that one instead of re-deriving - the whole matrix, so supplying an intent narrows what can be recommended. + has a recommended configuration, the run confirms that one instead of + re-deriving the whole matrix, so supplying an intent narrows what can be + recommended. extra_headers: Send extra headers diff --git a/src/kernel/types/config_registry_resolve_params.py b/src/kernel/types/config_registry_resolve_params.py index 2c0ecc00..e1a063dc 100644 --- a/src/kernel/types/config_registry_resolve_params.py +++ b/src/kernel/types/config_registry_resolve_params.py @@ -27,6 +27,7 @@ class ConfigRegistryResolveParams(TypedDict, total=False): any non-HTTPS destination as off-site and will not drive an http one. Kernel uses it to drive the browser further into the site, where it can observe protections that only appear once a session interacts. When this target already - has a verified configuration, the run confirms that one instead of re-deriving - the whole matrix, so supplying an intent narrows what can be recommended. + has a recommended configuration, the run confirms that one instead of + re-deriving the whole matrix, so supplying an intent narrows what can be + recommended. """ diff --git a/src/kernel/types/evidence.py b/src/kernel/types/evidence.py index 1a777de9..c53f2842 100644 --- a/src/kernel/types/evidence.py +++ b/src/kernel/types/evidence.py @@ -30,9 +30,9 @@ class Evidence(BaseModel): success_rate: float """Accessed trials divided by judged trials. Inconclusive trials are excluded.""" - last_verified_at: Optional[datetime] = None - """Most recent contributing run where this config met the success threshold. - - Omitted for knowledge assembled from runs that did not independently meet the - threshold. + last_supported_at: Optional[datetime] = None + """ + Most recent contributing run whose evidence supported recommending this + configuration. Omitted when no individual run independently met the + recommendation threshold. """ diff --git a/src/kernel/types/recommendation.py b/src/kernel/types/recommendation.py index 74b1761a..e7d21b8e 100644 --- a/src/kernel/types/recommendation.py +++ b/src/kernel/types/recommendation.py @@ -17,7 +17,11 @@ class Recommendation(BaseModel): evidence: Evidence match_scope: Literal["exact", "host", "domain"] - """Specificity of knowledge matched for this recommendation.""" + """Specificity of knowledge matched for this recommendation. + + Exact matches use knowledge for the requested target; host and domain matches + use broader fallback knowledge. + """ matched_target: str """Target value that supplied the recommendation.""" @@ -26,10 +30,3 @@ class Recommendation(BaseModel): """Proxy recipe for the recommended browser.""" type: Literal["recommendation"] - - verification: Literal["verified", "inferred"] - """ - Exact matches meet the evidence threshold; host and domain fallbacks are - inferred. Check evidence.last_verified_at for successful verification age and - last_observed_at for the latest evidence. - """ diff --git a/tests/api_resources/config_registry/test_analyses.py b/tests/api_resources/config_registry/test_analyses.py index 50b608df..0a9c8607 100644 --- a/tests/api_resources/config_registry/test_analyses.py +++ b/tests/api_resources/config_registry/test_analyses.py @@ -98,6 +98,48 @@ def test_streaming_response_list(self, client: Kernel) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_cancel(self, client: Kernel) -> None: + analysis = client.config_registry.analyses.cancel( + "id", + ) + assert_matches_type(ConfigRegistryResponse, analysis, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_cancel(self, client: Kernel) -> None: + response = client.config_registry.analyses.with_raw_response.cancel( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + analysis = response.parse() + assert_matches_type(ConfigRegistryResponse, analysis, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_cancel(self, client: Kernel) -> None: + with client.config_registry.analyses.with_streaming_response.cancel( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + analysis = response.parse() + assert_matches_type(ConfigRegistryResponse, analysis, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_cancel(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.config_registry.analyses.with_raw_response.cancel( + "", + ) + class TestAsyncAnalyses: parametrize = pytest.mark.parametrize( @@ -183,3 +225,45 @@ async def test_streaming_response_list(self, async_client: AsyncKernel) -> None: assert_matches_type(AsyncOffsetPagination[AnalysisSummary], analysis, path=["response"]) assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_cancel(self, async_client: AsyncKernel) -> None: + analysis = await async_client.config_registry.analyses.cancel( + "id", + ) + assert_matches_type(ConfigRegistryResponse, analysis, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_cancel(self, async_client: AsyncKernel) -> None: + response = await async_client.config_registry.analyses.with_raw_response.cancel( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + analysis = await response.parse() + assert_matches_type(ConfigRegistryResponse, analysis, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_cancel(self, async_client: AsyncKernel) -> None: + async with async_client.config_registry.analyses.with_streaming_response.cancel( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + analysis = await response.parse() + assert_matches_type(ConfigRegistryResponse, analysis, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_cancel(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.config_registry.analyses.with_raw_response.cancel( + "", + ) From 82a475dae250abce535476386be88033a5314656 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Wed, 16 Sep 2026 17:17:47 +0000 Subject: [PATCH 4/5] feat: Add start_url to browser session updates Stainless-Generated-From: 245527a0a5fccc56447f7227e933bc235a78cfe4 --- src/kernel/resources/browsers/browsers.py | 14 ++++++++++++++ src/kernel/types/browser_create_response.py | 2 +- src/kernel/types/browser_list_response.py | 2 +- src/kernel/types/browser_pool_acquire_response.py | 2 +- src/kernel/types/browser_retrieve_response.py | 2 +- src/kernel/types/browser_update_params.py | 8 ++++++++ src/kernel/types/browser_update_response.py | 2 +- .../types/invocation_list_browsers_response.py | 2 +- src/kernel/types/vaults/card_vault_item_state.py | 7 +++++-- .../fill_vault_item_operation_request_param.py | 7 +++---- src/kernel/types/vaults/vault_item.py | 4 ++++ .../types/vaults/vault_item_operation_response.py | 4 ++++ tests/api_resources/test_browsers.py | 2 ++ 13 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/kernel/resources/browsers/browsers.py b/src/kernel/resources/browsers/browsers.py index 219dd462..49dc4063 100644 --- a/src/kernel/resources/browsers/browsers.py +++ b/src/kernel/resources/browsers/browsers.py @@ -394,6 +394,7 @@ def update( profile: BrowserProfile | Omit = omit, proxy: BrowserProxyConfigParam | Omit = omit, proxy_id: Optional[str] | Omit = omit, + start_url: str | Omit = omit, tags: Optional[TagsParam] | Omit = omit, telemetry: Optional[browser_update_params.Telemetry] | Omit = omit, viewport: browser_update_params.Viewport | Omit = omit, @@ -428,6 +429,11 @@ def update( proxy_id: ID of the proxy to use. Omit to leave unchanged, set to empty string to remove proxy. Deprecated in favor of proxy. + start_url: Optional URL to navigate the browser to after applying this update. When a + profile is loaded in the same update, this overrides the profile's restored + tabs. Navigation is best-effort, so failures do not fail the update. Omit or set + to an empty string to leave the current page unchanged. + tags: User-defined key-value tags for the browser session. Omit to leave unchanged. Provide a map to replace the entire tag set (full replace, not a merge). Set to an empty object ({}) to clear all tags. Up to 50 pairs. @@ -459,6 +465,7 @@ def update( "profile": profile, "proxy": proxy, "proxy_id": proxy_id, + "start_url": start_url, "tags": tags, "telemetry": telemetry, "viewport": viewport, @@ -1024,6 +1031,7 @@ async def update( profile: BrowserProfile | Omit = omit, proxy: BrowserProxyConfigParam | Omit = omit, proxy_id: Optional[str] | Omit = omit, + start_url: str | Omit = omit, tags: Optional[TagsParam] | Omit = omit, telemetry: Optional[browser_update_params.Telemetry] | Omit = omit, viewport: browser_update_params.Viewport | Omit = omit, @@ -1058,6 +1066,11 @@ async def update( proxy_id: ID of the proxy to use. Omit to leave unchanged, set to empty string to remove proxy. Deprecated in favor of proxy. + start_url: Optional URL to navigate the browser to after applying this update. When a + profile is loaded in the same update, this overrides the profile's restored + tabs. Navigation is best-effort, so failures do not fail the update. Omit or set + to an empty string to leave the current page unchanged. + tags: User-defined key-value tags for the browser session. Omit to leave unchanged. Provide a map to replace the entire tag set (full replace, not a merge). Set to an empty object ({}) to clear all tags. Up to 50 pairs. @@ -1089,6 +1102,7 @@ async def update( "profile": profile, "proxy": proxy, "proxy_id": proxy_id, + "start_url": start_url, "tags": tags, "telemetry": telemetry, "viewport": viewport, diff --git a/src/kernel/types/browser_create_response.py b/src/kernel/types/browser_create_response.py index 678bcbcb..a5e674f7 100644 --- a/src/kernel/types/browser_create_response.py +++ b/src/kernel/types/browser_create_response.py @@ -106,7 +106,7 @@ class BrowserCreateResponse(BaseModel): """ start_url: Optional[str] = None - """URL the session was asked to navigate to on creation, if any. + """URL the session was most recently asked to navigate to, if any. Recorded for debugging. Navigation is fire-and-forget — the URL is dispatched to the browser without waiting for it to load, and any errors (DNS failure, bad diff --git a/src/kernel/types/browser_list_response.py b/src/kernel/types/browser_list_response.py index aa281a39..3cc62ebe 100644 --- a/src/kernel/types/browser_list_response.py +++ b/src/kernel/types/browser_list_response.py @@ -106,7 +106,7 @@ class BrowserListResponse(BaseModel): """ start_url: Optional[str] = None - """URL the session was asked to navigate to on creation, if any. + """URL the session was most recently asked to navigate to, if any. Recorded for debugging. Navigation is fire-and-forget — the URL is dispatched to the browser without waiting for it to load, and any errors (DNS failure, bad diff --git a/src/kernel/types/browser_pool_acquire_response.py b/src/kernel/types/browser_pool_acquire_response.py index d472b5e0..c223c927 100644 --- a/src/kernel/types/browser_pool_acquire_response.py +++ b/src/kernel/types/browser_pool_acquire_response.py @@ -106,7 +106,7 @@ class BrowserPoolAcquireResponse(BaseModel): """ start_url: Optional[str] = None - """URL the session was asked to navigate to on creation, if any. + """URL the session was most recently asked to navigate to, if any. Recorded for debugging. Navigation is fire-and-forget — the URL is dispatched to the browser without waiting for it to load, and any errors (DNS failure, bad diff --git a/src/kernel/types/browser_retrieve_response.py b/src/kernel/types/browser_retrieve_response.py index e6881ab1..936b41c6 100644 --- a/src/kernel/types/browser_retrieve_response.py +++ b/src/kernel/types/browser_retrieve_response.py @@ -106,7 +106,7 @@ class BrowserRetrieveResponse(BaseModel): """ start_url: Optional[str] = None - """URL the session was asked to navigate to on creation, if any. + """URL the session was most recently asked to navigate to, if any. Recorded for debugging. Navigation is fire-and-forget — the URL is dispatched to the browser without waiting for it to load, and any errors (DNS failure, bad diff --git a/src/kernel/types/browser_update_params.py b/src/kernel/types/browser_update_params.py index e7769e61..c0592e28 100644 --- a/src/kernel/types/browser_update_params.py +++ b/src/kernel/types/browser_update_params.py @@ -59,6 +59,14 @@ class BrowserUpdateParams(TypedDict, total=False): favor of proxy. """ + start_url: str + """Optional URL to navigate the browser to after applying this update. + + When a profile is loaded in the same update, this overrides the profile's + restored tabs. Navigation is best-effort, so failures do not fail the update. + Omit or set to an empty string to leave the current page unchanged. + """ + tags: Optional[TagsParam] """User-defined key-value tags for the browser session. diff --git a/src/kernel/types/browser_update_response.py b/src/kernel/types/browser_update_response.py index 65be1ba3..d2296c21 100644 --- a/src/kernel/types/browser_update_response.py +++ b/src/kernel/types/browser_update_response.py @@ -106,7 +106,7 @@ class BrowserUpdateResponse(BaseModel): """ start_url: Optional[str] = None - """URL the session was asked to navigate to on creation, if any. + """URL the session was most recently asked to navigate to, if any. Recorded for debugging. Navigation is fire-and-forget — the URL is dispatched to the browser without waiting for it to load, and any errors (DNS failure, bad diff --git a/src/kernel/types/invocation_list_browsers_response.py b/src/kernel/types/invocation_list_browsers_response.py index bb9d423d..a88f33f9 100644 --- a/src/kernel/types/invocation_list_browsers_response.py +++ b/src/kernel/types/invocation_list_browsers_response.py @@ -106,7 +106,7 @@ class Browser(BaseModel): """ start_url: Optional[str] = None - """URL the session was asked to navigate to on creation, if any. + """URL the session was most recently asked to navigate to, if any. Recorded for debugging. Navigation is fire-and-forget — the URL is dispatched to the browser without waiting for it to load, and any errors (DNS failure, bad diff --git a/src/kernel/types/vaults/card_vault_item_state.py b/src/kernel/types/vaults/card_vault_item_state.py index 4785f3ac..a1cb0b68 100644 --- a/src/kernel/types/vaults/card_vault_item_state.py +++ b/src/kernel/types/vaults/card_vault_item_state.py @@ -33,6 +33,11 @@ def __getattr__(self, attr: str) -> str: ... class LinkCardState(BaseModel): + """Issued Link cards retain encrypted card material for the fill operation. + + Link cards do not expose aliases or support egress substitution. + """ + provider: Literal["link"] status: Literal[ @@ -47,8 +52,6 @@ class LinkCardState(BaseModel): caller-asserted reconciliation operation. """ - aliases: Optional[VaultCardAliases] = None - domains: Optional[List[str]] = None masks: Optional[LinkCardStateMasks] = None diff --git a/src/kernel/types/vaults/fill_vault_item_operation_request_param.py b/src/kernel/types/vaults/fill_vault_item_operation_request_param.py index 1d8fc8be..012ec2b9 100644 --- a/src/kernel/types/vaults/fill_vault_item_operation_request_param.py +++ b/src/kernel/types/vaults/fill_vault_item_operation_request_param.py @@ -34,10 +34,9 @@ class FillVaultItemOperationRequestParam(TypedDict, total=False): Fill in request order and stop on the first failure. This operation is not atomic: previously filled fields are not rolled back. Never submit the form or click buttons, though input/change events may trigger site - behavior. Fill is the preferred browser-checkout path. Aliases remain an - alternative for explicitly chosen egress-substitution integrations. Do not - automatically retry or fall back to aliases after a failed or indeterminate - operation. + behavior. Link cards use fill for browser checkout and do not expose + aliases or support egress substitution. Do not automatically retry a + failed or indeterminate operation. Secret values are never returned or included in operation logs, traces, audit events, or error details. This does not prevent an agent with diff --git a/src/kernel/types/vaults/vault_item.py b/src/kernel/types/vaults/vault_item.py index 07253ea4..b9723f4a 100644 --- a/src/kernel/types/vaults/vault_item.py +++ b/src/kernel/types/vaults/vault_item.py @@ -127,6 +127,10 @@ class CardVaultItem(BaseModel): """Live payment card. Test-mode card creation is not supported.""" state: CardVaultItemState + """Issued Link cards retain encrypted card material for the fill operation. + + Link cards do not expose aliases or support egress substitution. + """ type: Literal["card"] diff --git a/src/kernel/types/vaults/vault_item_operation_response.py b/src/kernel/types/vaults/vault_item_operation_response.py index 163f73a7..33dcd8b3 100644 --- a/src/kernel/types/vaults/vault_item_operation_response.py +++ b/src/kernel/types/vaults/vault_item_operation_response.py @@ -127,6 +127,10 @@ class CardVaultItem(BaseModel): """Live payment card. Test-mode card creation is not supported.""" state: CardVaultItemState + """Issued Link cards retain encrypted card material for the fill operation. + + Link cards do not expose aliases or support egress substitution. + """ type: Literal["card"] diff --git a/tests/api_resources/test_browsers.py b/tests/api_resources/test_browsers.py index 406b0ce8..28189f15 100644 --- a/tests/api_resources/test_browsers.py +++ b/tests/api_resources/test_browsers.py @@ -207,6 +207,7 @@ def test_method_update_with_all_params(self, client: Kernel) -> None: "name": "x", }, proxy_id="proxy_id", + start_url="https://example.com", tags={ "team": "backend", "env": "staging", @@ -680,6 +681,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncKernel) -> "name": "x", }, proxy_id="proxy_id", + start_url="https://example.com", tags={ "team": "backend", "env": "staging", From bb426056a26874bd4de958d8444986e7d97fb4a0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Sep 2026 17:40:21 +0000 Subject: [PATCH 5/5] release: 0.106.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 11 +++++++++++ pyproject.toml | 2 +- src/kernel/_version.py | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 19c0e9cc..f371d275 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.104.0" + ".": "0.106.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index eb98375c..cb10a2df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## 0.106.0 (2026-09-16) + +Full Changelog: [v0.104.0...v0.106.0](https://github.com/kernel/kernel-python-sdk/compare/v0.104.0...v0.106.0) + +### Features + +* Add processor-bound AgentCard preparation contracts ([37d5e9c](https://github.com/kernel/kernel-python-sdk/commit/37d5e9c3d5db76bece8f8ba8d5358b939bc79315)) +* Add start_url to browser session updates ([82a475d](https://github.com/kernel/kernel-python-sdk/commit/82a475dae250abce535476386be88033a5314656)) +* Polish and publish the Config Registry API ([afe2fea](https://github.com/kernel/kernel-python-sdk/commit/afe2feaf2dcea1f4fc160d66cfe9f3711b61a447)) +* Square UKP and Hypeman placement load factors ([76dee03](https://github.com/kernel/kernel-python-sdk/commit/76dee03d215481de6ee42b2cba631b5f5893c1a3)) + ## [0.104.0](https://github.com/kernel/kernel-python-sdk/compare/v0.103.0...v0.104.0) (2026-09-15) diff --git a/pyproject.toml b/pyproject.toml index 6b6ca1ef..a89b3709 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.104.0" +version = "0.106.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 0a7fea06..66f10fd8 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.104.0" # x-release-please-version +__version__ = "0.106.0" # x-release-please-version