From 5b74e460198b174e69f0bf690b01f216e89b3dd0 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2026 20:38:21 +0000 Subject: [PATCH 1/2] feat: chore(stlc): seal custom-code tracking files Stainless-Generated-From: 6d79f6bf702d5e653e96eb43611b7593c0c3620b --- .stats.yml | 2 +- api.md | 12 ++ src/kernel/resources/organization/__init__.py | 14 ++ .../resources/organization/entitlements.py | 147 +++++++++++++ .../resources/organization/organization.py | 38 ++++ src/kernel/types/organization/__init__.py | 1 + .../types/organization/org_entitlements.py | 199 ++++++++++++++++++ .../organization/test_entitlements.py | 80 +++++++ 8 files changed, 492 insertions(+), 1 deletion(-) create mode 100644 src/kernel/resources/organization/entitlements.py create mode 100644 src/kernel/types/organization/org_entitlements.py create mode 100644 tests/api_resources/organization/test_entitlements.py diff --git a/.stats.yml b/.stats.yml index 98f97da5..f9d1086b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 139 +configured_endpoints: 140 diff --git a/api.md b/api.md index 62ade185..fda90ce0 100644 --- a/api.md +++ b/api.md @@ -472,6 +472,18 @@ Methods: # Organization +## Entitlements + +Types: + +```python +from kernel.types.organization import OrgEntitlements +``` + +Methods: + +- client.organization.entitlements.retrieve() -> OrgEntitlements + ## Limits Types: diff --git a/src/kernel/resources/organization/__init__.py b/src/kernel/resources/organization/__init__.py index 68c28d60..ae6da711 100644 --- a/src/kernel/resources/organization/__init__.py +++ b/src/kernel/resources/organization/__init__.py @@ -8,6 +8,14 @@ LimitsResourceWithStreamingResponse, AsyncLimitsResourceWithStreamingResponse, ) +from .entitlements import ( + EntitlementsResource, + AsyncEntitlementsResource, + EntitlementsResourceWithRawResponse, + AsyncEntitlementsResourceWithRawResponse, + EntitlementsResourceWithStreamingResponse, + AsyncEntitlementsResourceWithStreamingResponse, +) from .organization import ( OrganizationResource, AsyncOrganizationResource, @@ -18,6 +26,12 @@ ) __all__ = [ + "EntitlementsResource", + "AsyncEntitlementsResource", + "EntitlementsResourceWithRawResponse", + "AsyncEntitlementsResourceWithRawResponse", + "EntitlementsResourceWithStreamingResponse", + "AsyncEntitlementsResourceWithStreamingResponse", "LimitsResource", "AsyncLimitsResource", "LimitsResourceWithRawResponse", diff --git a/src/kernel/resources/organization/entitlements.py b/src/kernel/resources/organization/entitlements.py new file mode 100644 index 00000000..05dc90f8 --- /dev/null +++ b/src/kernel/resources/organization/entitlements.py @@ -0,0 +1,147 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.organization.org_entitlements import OrgEntitlements + +__all__ = ["EntitlementsResource", "AsyncEntitlementsResource"] + + +class EntitlementsResource(SyncAPIResource): + """Read and manage organization-level limits.""" + + @cached_property + def with_raw_response(self) -> EntitlementsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return EntitlementsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> EntitlementsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return EntitlementsResourceWithStreamingResponse(self) + + def retrieve( + self, + *, + # 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, + ) -> OrgEntitlements: + """ + Get the authenticated organization's effective feature access and constraints + after applying its plan, active trial treatment, plan status, and + organization-specific overrides. Null constraint values mean unlimited. + """ + return self._get( + "/org/entitlements", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OrgEntitlements, + ) + + +class AsyncEntitlementsResource(AsyncAPIResource): + """Read and manage organization-level limits.""" + + @cached_property + def with_raw_response(self) -> AsyncEntitlementsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncEntitlementsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncEntitlementsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return AsyncEntitlementsResourceWithStreamingResponse(self) + + async def retrieve( + self, + *, + # 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, + ) -> OrgEntitlements: + """ + Get the authenticated organization's effective feature access and constraints + after applying its plan, active trial treatment, plan status, and + organization-specific overrides. Null constraint values mean unlimited. + """ + return await self._get( + "/org/entitlements", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=OrgEntitlements, + ) + + +class EntitlementsResourceWithRawResponse: + def __init__(self, entitlements: EntitlementsResource) -> None: + self._entitlements = entitlements + + self.retrieve = to_raw_response_wrapper( + entitlements.retrieve, + ) + + +class AsyncEntitlementsResourceWithRawResponse: + def __init__(self, entitlements: AsyncEntitlementsResource) -> None: + self._entitlements = entitlements + + self.retrieve = async_to_raw_response_wrapper( + entitlements.retrieve, + ) + + +class EntitlementsResourceWithStreamingResponse: + def __init__(self, entitlements: EntitlementsResource) -> None: + self._entitlements = entitlements + + self.retrieve = to_streamed_response_wrapper( + entitlements.retrieve, + ) + + +class AsyncEntitlementsResourceWithStreamingResponse: + def __init__(self, entitlements: AsyncEntitlementsResource) -> None: + self._entitlements = entitlements + + self.retrieve = async_to_streamed_response_wrapper( + entitlements.retrieve, + ) diff --git a/src/kernel/resources/organization/organization.py b/src/kernel/resources/organization/organization.py index 21163122..78ad5624 100644 --- a/src/kernel/resources/organization/organization.py +++ b/src/kernel/resources/organization/organization.py @@ -12,11 +12,24 @@ ) from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource +from .entitlements import ( + EntitlementsResource, + AsyncEntitlementsResource, + EntitlementsResourceWithRawResponse, + AsyncEntitlementsResourceWithRawResponse, + EntitlementsResourceWithStreamingResponse, + AsyncEntitlementsResourceWithStreamingResponse, +) __all__ = ["OrganizationResource", "AsyncOrganizationResource"] class OrganizationResource(SyncAPIResource): + @cached_property + def entitlements(self) -> EntitlementsResource: + """Read and manage organization-level limits.""" + return EntitlementsResource(self._client) + @cached_property def limits(self) -> LimitsResource: """Read and manage organization-level limits.""" @@ -43,6 +56,11 @@ def with_streaming_response(self) -> OrganizationResourceWithStreamingResponse: class AsyncOrganizationResource(AsyncAPIResource): + @cached_property + def entitlements(self) -> AsyncEntitlementsResource: + """Read and manage organization-level limits.""" + return AsyncEntitlementsResource(self._client) + @cached_property def limits(self) -> AsyncLimitsResource: """Read and manage organization-level limits.""" @@ -72,6 +90,11 @@ class OrganizationResourceWithRawResponse: def __init__(self, organization: OrganizationResource) -> None: self._organization = organization + @cached_property + def entitlements(self) -> EntitlementsResourceWithRawResponse: + """Read and manage organization-level limits.""" + return EntitlementsResourceWithRawResponse(self._organization.entitlements) + @cached_property def limits(self) -> LimitsResourceWithRawResponse: """Read and manage organization-level limits.""" @@ -82,6 +105,11 @@ class AsyncOrganizationResourceWithRawResponse: def __init__(self, organization: AsyncOrganizationResource) -> None: self._organization = organization + @cached_property + def entitlements(self) -> AsyncEntitlementsResourceWithRawResponse: + """Read and manage organization-level limits.""" + return AsyncEntitlementsResourceWithRawResponse(self._organization.entitlements) + @cached_property def limits(self) -> AsyncLimitsResourceWithRawResponse: """Read and manage organization-level limits.""" @@ -92,6 +120,11 @@ class OrganizationResourceWithStreamingResponse: def __init__(self, organization: OrganizationResource) -> None: self._organization = organization + @cached_property + def entitlements(self) -> EntitlementsResourceWithStreamingResponse: + """Read and manage organization-level limits.""" + return EntitlementsResourceWithStreamingResponse(self._organization.entitlements) + @cached_property def limits(self) -> LimitsResourceWithStreamingResponse: """Read and manage organization-level limits.""" @@ -102,6 +135,11 @@ class AsyncOrganizationResourceWithStreamingResponse: def __init__(self, organization: AsyncOrganizationResource) -> None: self._organization = organization + @cached_property + def entitlements(self) -> AsyncEntitlementsResourceWithStreamingResponse: + """Read and manage organization-level limits.""" + return AsyncEntitlementsResourceWithStreamingResponse(self._organization.entitlements) + @cached_property def limits(self) -> AsyncLimitsResourceWithStreamingResponse: """Read and manage organization-level limits.""" diff --git a/src/kernel/types/organization/__init__.py b/src/kernel/types/organization/__init__.py index d2411f9a..415d132a 100644 --- a/src/kernel/types/organization/__init__.py +++ b/src/kernel/types/organization/__init__.py @@ -3,4 +3,5 @@ from __future__ import annotations from .org_limits import OrgLimits as OrgLimits +from .org_entitlements import OrgEntitlements as OrgEntitlements from .limit_update_params import LimitUpdateParams as LimitUpdateParams diff --git a/src/kernel/types/organization/org_entitlements.py b/src/kernel/types/organization/org_entitlements.py new file mode 100644 index 00000000..c940cbef --- /dev/null +++ b/src/kernel/types/organization/org_entitlements.py @@ -0,0 +1,199 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = [ + "OrgEntitlements", + "Features", + "FeaturesBrowserExtensions", + "FeaturesBrowserPools", + "FeaturesBrowserReplays", + "FeaturesCredentialProviders", + "FeaturesCredentials", + "FeaturesCustomProxies", + "FeaturesFileIo", + "FeaturesGPU", + "FeaturesManagedAuth", + "FeaturesManagedProxies", + "FeaturesProfiles", + "FeaturesProxyBypassHosts", + "Limits", + "Plan", +] + + +class FeaturesBrowserExtensions(BaseModel): + enabled: bool + """Whether browser extensions are available.""" + + max_stored_per_org: Optional[int] = None + """Maximum active custom extensions the organization may store. + + Null means unlimited. Loading stored extensions into a browser is not + plan-limited. + """ + + +class FeaturesBrowserPools(BaseModel): + enabled: bool + """Whether the organization is entitled to use this feature.""" + + +class FeaturesBrowserReplays(BaseModel): + enabled: bool + """Whether browser replay recording is available.""" + + retention_days: int + """Number of days browser replays are retained, matching the replay reaper policy.""" + + +class FeaturesCredentialProviders(BaseModel): + enabled: bool + """Whether the organization is entitled to use this feature.""" + + +class FeaturesCredentials(BaseModel): + enabled: bool + """Whether the organization is entitled to use this feature.""" + + +class FeaturesCustomProxies(BaseModel): + enabled: bool + """Whether the organization is entitled to use this feature.""" + + +class FeaturesFileIo(BaseModel): + enabled: bool + """Whether the organization is entitled to use this feature.""" + + +class FeaturesGPU(BaseModel): + enabled: bool + """Whether the organization is entitled to use this feature.""" + + +class FeaturesManagedAuth(BaseModel): + enabled: bool + """Whether managed auth is available.""" + + health_check_interval_default_seconds: int + """ + Effective interval in seconds used when a connection is created without an + explicit health-check interval. + """ + + health_check_interval_max_seconds: int + """Maximum accepted managed auth health-check interval in seconds.""" + + health_check_interval_min_seconds: int + """Minimum accepted managed auth health-check interval in seconds.""" + + max_connections: Optional[int] = None + """Maximum active managed auth connections in the organization. + + Null means unlimited. + """ + + +class FeaturesManagedProxies(BaseModel): + enabled: bool + """Whether the organization is entitled to use this feature.""" + + +class FeaturesProfiles(BaseModel): + enabled: bool + """Whether the organization is entitled to use this feature.""" + + +class FeaturesProxyBypassHosts(BaseModel): + enabled: bool + """Whether the organization is entitled to use this feature.""" + + +class Features(BaseModel): + browser_extensions: FeaturesBrowserExtensions + + browser_pools: FeaturesBrowserPools + + browser_replays: FeaturesBrowserReplays + + credential_providers: FeaturesCredentialProviders + + credentials: FeaturesCredentials + + custom_proxies: FeaturesCustomProxies + + file_io: FeaturesFileIo + + gpu: FeaturesGPU + + managed_auth: FeaturesManagedAuth + + managed_proxies: FeaturesManagedProxies + + profiles: FeaturesProfiles + + proxy_bypass_hosts: FeaturesProxyBypassHosts + + +class Limits(BaseModel): + default_max_concurrent_invocations_per_app: int + """ + Effective org-level default concurrent invocation ceiling for apps without an + app-specific override. App-specific overrides are not represented here. + """ + + max_concurrent_browsers: int + """ + Effective organization-wide ceiling shared by on-demand browsers and browser + pool reservations. + """ + + max_concurrent_invocations: int + """Effective organization-wide concurrent app invocation ceiling.""" + + +class Plan(BaseModel): + id: Literal["FREE", "HOBBYIST", "START_UP", "ENTERPRISE"] + """The organization's contractual plan identifier. + + Use the resolved feature and limit values, not this field, for access decisions. + """ + + effective_id: Literal["FREE", "HOBBYIST", "START_UP", "ENTERPRISE"] + """The plan used to resolve plan-based access. + + Active trials resolve to START_UP regardless of the contractual plan. + """ + + is_trialing: bool + """Whether the organization is currently within its trial period.""" + + status: Optional[Literal["NEEDS_PAYMENT_METHOD", "ACTIVE", "CANCELED", "UNPAID"]] = None + """ + Current billing status of the contractual plan, or null when no billing status + is recorded. Status-sensitive feature values already account for it. + """ + + trial_ends_at: Optional[datetime] = None + """Configured trial end timestamp, or null when the organization has no trial. + + A past timestamp may be returned when is_trialing is false. + """ + + +class OrgEntitlements(BaseModel): + """Effective feature access and constraints for the authenticated organization. + + Values already include trial treatment, plan status, and organization-specific overrides; consumers should use these resolved values instead of comparing plan IDs. + """ + + features: Features + + limits: Limits + + plan: Plan diff --git a/tests/api_resources/organization/test_entitlements.py b/tests/api_resources/organization/test_entitlements.py new file mode 100644 index 00000000..d788bc66 --- /dev/null +++ b/tests/api_resources/organization/test_entitlements.py @@ -0,0 +1,80 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from kernel import Kernel, AsyncKernel +from tests.utils import assert_matches_type +from kernel.types.organization import OrgEntitlements + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestEntitlements: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Kernel) -> None: + entitlement = client.organization.entitlements.retrieve() + assert_matches_type(OrgEntitlements, entitlement, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Kernel) -> None: + response = client.organization.entitlements.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + entitlement = response.parse() + assert_matches_type(OrgEntitlements, entitlement, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Kernel) -> None: + with client.organization.entitlements.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + entitlement = response.parse() + assert_matches_type(OrgEntitlements, entitlement, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncEntitlements: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncKernel) -> None: + entitlement = await async_client.organization.entitlements.retrieve() + assert_matches_type(OrgEntitlements, entitlement, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncKernel) -> None: + response = await async_client.organization.entitlements.with_raw_response.retrieve() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + entitlement = await response.parse() + assert_matches_type(OrgEntitlements, entitlement, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncKernel) -> None: + async with async_client.organization.entitlements.with_streaming_response.retrieve() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + entitlement = await response.parse() + assert_matches_type(OrgEntitlements, entitlement, path=["response"]) + + assert cast(Any, response.is_closed) is True From 15ece029ba208c6affaf0bdbf920bf3094a37a56 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2026 20:42:27 +0000 Subject: [PATCH 2/2] release: 0.92.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ pyproject.toml | 2 +- src/kernel/_version.py | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 29c535cb..0114ce37 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.91.0" + ".": "0.92.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b641f09..fb983168 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.92.0](https://github.com/kernel/kernel-python-sdk/compare/v0.91.0...v0.92.0) (2026-08-17) + + +### Features + +* chore(stlc): seal custom-code tracking files ([5b74e46](https://github.com/kernel/kernel-python-sdk/commit/5b74e460198b174e69f0bf690b01f216e89b3dd0)) + ## [0.91.0](https://github.com/kernel/kernel-python-sdk/compare/v0.90.0...v0.91.0) (2026-08-14) diff --git a/pyproject.toml b/pyproject.toml index 1c078ba3..dbb578c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.91.0" +version = "0.92.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 06739f24..ce129655 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.91.0" # x-release-please-version +__version__ = "0.92.0" # x-release-please-version