From bb39872703bd6ace1e588a54420f29a62140144b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 18:14:00 +0000 Subject: [PATCH 1/2] feat: getInvocations endpoint --- .stats.yml | 8 +- api.md | 2 + src/kernel/resources/invocations.py | 158 ++++++++++++++++++- src/kernel/types/__init__.py | 2 + src/kernel/types/invocation_list_params.py | 33 ++++ src/kernel/types/invocation_list_response.py | 47 ++++++ tests/api_resources/test_invocations.py | 86 ++++++++++ 7 files changed, 330 insertions(+), 6 deletions(-) create mode 100644 src/kernel/types/invocation_list_params.py create mode 100644 src/kernel/types/invocation_list_response.py diff --git a/.stats.yml b/.stats.yml index 4039b103..be90d46e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 50 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-5ee2116982adf46664acf84b8ba4b56ba65780983506c63d9b005dab49def757.yml -openapi_spec_hash: 42a3a519301d0e2bb2b5a71018915b55 -config_hash: 0d150b61cae2dc57d3648ceae7784966 +configured_endpoints: 51 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-8b5a722e4964d2d1dcdc34afccb6d742e1c927cbbd622264c8734f132e31a0f5.yml +openapi_spec_hash: ed101ff177c2e962653ca65acf939336 +config_hash: 49c2ff978aaa5ccb4ce324a72f116010 diff --git a/api.md b/api.md index eaef5078..dc0a70f6 100644 --- a/api.md +++ b/api.md @@ -47,6 +47,7 @@ from kernel.types import ( InvocationCreateResponse, InvocationRetrieveResponse, InvocationUpdateResponse, + InvocationListResponse, InvocationFollowResponse, ) ``` @@ -56,6 +57,7 @@ Methods: - client.invocations.create(\*\*params) -> InvocationCreateResponse - client.invocations.retrieve(id) -> InvocationRetrieveResponse - client.invocations.update(id, \*\*params) -> InvocationUpdateResponse +- client.invocations.list(\*\*params) -> SyncOffsetPagination[InvocationListResponse] - client.invocations.delete_browsers(id) -> None - client.invocations.follow(id, \*\*params) -> InvocationFollowResponse diff --git a/src/kernel/resources/invocations.py b/src/kernel/resources/invocations.py index 4d671646..ed10cf2c 100644 --- a/src/kernel/resources/invocations.py +++ b/src/kernel/resources/invocations.py @@ -7,7 +7,7 @@ import httpx -from ..types import invocation_create_params, invocation_follow_params, invocation_update_params +from ..types import invocation_list_params, invocation_create_params, invocation_follow_params, invocation_update_params from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property @@ -19,7 +19,9 @@ async_to_streamed_response_wrapper, ) from .._streaming import Stream, AsyncStream -from .._base_client import make_request_options +from ..pagination import SyncOffsetPagination, AsyncOffsetPagination +from .._base_client import AsyncPaginator, make_request_options +from ..types.invocation_list_response import InvocationListResponse from ..types.invocation_create_response import InvocationCreateResponse from ..types.invocation_follow_response import InvocationFollowResponse from ..types.invocation_update_response import InvocationUpdateResponse @@ -185,6 +187,76 @@ def update( cast_to=InvocationUpdateResponse, ) + def list( + self, + *, + action_name: str | Omit = omit, + app_name: str | Omit = omit, + deployment_id: str | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + since: str | Omit = omit, + status: Literal["queued", "running", "succeeded", "failed"] | Omit = omit, + # 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, + ) -> SyncOffsetPagination[InvocationListResponse]: + """List invocations. + + Optionally filter by application name, action name, status, + deployment ID, or start time. + + Args: + action_name: Filter results by action name. + + app_name: Filter results by application name. + + deployment_id: Filter results by deployment ID. + + limit: Limit the number of invocations to return. + + offset: Offset the number of invocations to return. + + since: Show invocations that have started since the given time (RFC timestamps or + durations like 5m). + + status: Filter results by invocation status. + + 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 + """ + return self._get_api_list( + "/invocations", + page=SyncOffsetPagination[InvocationListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "action_name": action_name, + "app_name": app_name, + "deployment_id": deployment_id, + "limit": limit, + "offset": offset, + "since": since, + "status": status, + }, + invocation_list_params.InvocationListParams, + ), + ), + model=InvocationListResponse, + ) + def delete_browsers( self, id: str, @@ -424,6 +496,76 @@ async def update( cast_to=InvocationUpdateResponse, ) + def list( + self, + *, + action_name: str | Omit = omit, + app_name: str | Omit = omit, + deployment_id: str | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + since: str | Omit = omit, + status: Literal["queued", "running", "succeeded", "failed"] | Omit = omit, + # 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, + ) -> AsyncPaginator[InvocationListResponse, AsyncOffsetPagination[InvocationListResponse]]: + """List invocations. + + Optionally filter by application name, action name, status, + deployment ID, or start time. + + Args: + action_name: Filter results by action name. + + app_name: Filter results by application name. + + deployment_id: Filter results by deployment ID. + + limit: Limit the number of invocations to return. + + offset: Offset the number of invocations to return. + + since: Show invocations that have started since the given time (RFC timestamps or + durations like 5m). + + status: Filter results by invocation status. + + 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 + """ + return self._get_api_list( + "/invocations", + page=AsyncOffsetPagination[InvocationListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "action_name": action_name, + "app_name": app_name, + "deployment_id": deployment_id, + "limit": limit, + "offset": offset, + "since": since, + "status": status, + }, + invocation_list_params.InvocationListParams, + ), + ), + model=InvocationListResponse, + ) + async def delete_browsers( self, id: str, @@ -519,6 +661,9 @@ def __init__(self, invocations: InvocationsResource) -> None: self.update = to_raw_response_wrapper( invocations.update, ) + self.list = to_raw_response_wrapper( + invocations.list, + ) self.delete_browsers = to_raw_response_wrapper( invocations.delete_browsers, ) @@ -540,6 +685,9 @@ def __init__(self, invocations: AsyncInvocationsResource) -> None: self.update = async_to_raw_response_wrapper( invocations.update, ) + self.list = async_to_raw_response_wrapper( + invocations.list, + ) self.delete_browsers = async_to_raw_response_wrapper( invocations.delete_browsers, ) @@ -561,6 +709,9 @@ def __init__(self, invocations: InvocationsResource) -> None: self.update = to_streamed_response_wrapper( invocations.update, ) + self.list = to_streamed_response_wrapper( + invocations.list, + ) self.delete_browsers = to_streamed_response_wrapper( invocations.delete_browsers, ) @@ -582,6 +733,9 @@ def __init__(self, invocations: AsyncInvocationsResource) -> None: self.update = async_to_streamed_response_wrapper( invocations.update, ) + self.list = async_to_streamed_response_wrapper( + invocations.list, + ) self.delete_browsers = async_to_streamed_response_wrapper( invocations.delete_browsers, ) diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index 0eae67cb..b14918e9 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -24,6 +24,7 @@ from .proxy_create_response import ProxyCreateResponse as ProxyCreateResponse from .deployment_list_params import DeploymentListParams as DeploymentListParams from .deployment_state_event import DeploymentStateEvent as DeploymentStateEvent +from .invocation_list_params import InvocationListParams as InvocationListParams from .invocation_state_event import InvocationStateEvent as InvocationStateEvent from .browser_create_response import BrowserCreateResponse as BrowserCreateResponse from .proxy_retrieve_response import ProxyRetrieveResponse as ProxyRetrieveResponse @@ -32,6 +33,7 @@ from .deployment_list_response import DeploymentListResponse as DeploymentListResponse from .invocation_create_params import InvocationCreateParams as InvocationCreateParams from .invocation_follow_params import InvocationFollowParams as InvocationFollowParams +from .invocation_list_response import InvocationListResponse as InvocationListResponse from .invocation_update_params import InvocationUpdateParams as InvocationUpdateParams from .browser_persistence_param import BrowserPersistenceParam as BrowserPersistenceParam from .browser_retrieve_response import BrowserRetrieveResponse as BrowserRetrieveResponse diff --git a/src/kernel/types/invocation_list_params.py b/src/kernel/types/invocation_list_params.py new file mode 100644 index 00000000..06f75ff1 --- /dev/null +++ b/src/kernel/types/invocation_list_params.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["InvocationListParams"] + + +class InvocationListParams(TypedDict, total=False): + action_name: str + """Filter results by action name.""" + + app_name: str + """Filter results by application name.""" + + deployment_id: str + """Filter results by deployment ID.""" + + limit: int + """Limit the number of invocations to return.""" + + offset: int + """Offset the number of invocations to return.""" + + since: str + """ + Show invocations that have started since the given time (RFC timestamps or + durations like 5m). + """ + + status: Literal["queued", "running", "succeeded", "failed"] + """Filter results by invocation status.""" diff --git a/src/kernel/types/invocation_list_response.py b/src/kernel/types/invocation_list_response.py new file mode 100644 index 00000000..4c265856 --- /dev/null +++ b/src/kernel/types/invocation_list_response.py @@ -0,0 +1,47 @@ +# 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__ = ["InvocationListResponse"] + + +class InvocationListResponse(BaseModel): + id: str + """ID of the invocation""" + + action_name: str + """Name of the action invoked""" + + app_name: str + """Name of the application""" + + started_at: datetime + """RFC 3339 Nanoseconds timestamp when the invocation started""" + + status: Literal["queued", "running", "succeeded", "failed"] + """Status of the invocation""" + + finished_at: Optional[datetime] = None + """ + RFC 3339 Nanoseconds timestamp when the invocation finished (null if still + running) + """ + + output: Optional[str] = None + """Output produced by the action, rendered as a JSON string. + + This could be: string, number, boolean, array, object, or null. + """ + + payload: Optional[str] = None + """Payload provided to the invocation. + + This is a string that can be parsed as JSON. + """ + + status_reason: Optional[str] = None + """Status reason""" diff --git a/tests/api_resources/test_invocations.py b/tests/api_resources/test_invocations.py index ae3b451b..1abf41d0 100644 --- a/tests/api_resources/test_invocations.py +++ b/tests/api_resources/test_invocations.py @@ -10,10 +10,12 @@ from kernel import Kernel, AsyncKernel from tests.utils import assert_matches_type from kernel.types import ( + InvocationListResponse, InvocationCreateResponse, InvocationUpdateResponse, InvocationRetrieveResponse, ) +from kernel.pagination import SyncOffsetPagination, AsyncOffsetPagination base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -171,6 +173,48 @@ def test_path_params_update(self, client: Kernel) -> None: status="succeeded", ) + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_list(self, client: Kernel) -> None: + invocation = client.invocations.list() + assert_matches_type(SyncOffsetPagination[InvocationListResponse], invocation, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Kernel) -> None: + invocation = client.invocations.list( + action_name="action_name", + app_name="app_name", + deployment_id="deployment_id", + limit=1, + offset=0, + since="2025-06-20T12:00:00Z", + status="queued", + ) + assert_matches_type(SyncOffsetPagination[InvocationListResponse], invocation, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_list(self, client: Kernel) -> None: + response = client.invocations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invocation = response.parse() + assert_matches_type(SyncOffsetPagination[InvocationListResponse], invocation, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Kernel) -> None: + with client.invocations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invocation = response.parse() + assert_matches_type(SyncOffsetPagination[InvocationListResponse], invocation, path=["response"]) + + assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="Prism tests are disabled") @parametrize def test_method_delete_browsers(self, client: Kernel) -> None: @@ -419,6 +463,48 @@ async def test_path_params_update(self, async_client: AsyncKernel) -> None: status="succeeded", ) + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncKernel) -> None: + invocation = await async_client.invocations.list() + assert_matches_type(AsyncOffsetPagination[InvocationListResponse], invocation, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None: + invocation = await async_client.invocations.list( + action_name="action_name", + app_name="app_name", + deployment_id="deployment_id", + limit=1, + offset=0, + since="2025-06-20T12:00:00Z", + status="queued", + ) + assert_matches_type(AsyncOffsetPagination[InvocationListResponse], invocation, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncKernel) -> None: + response = await async_client.invocations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + invocation = await response.parse() + assert_matches_type(AsyncOffsetPagination[InvocationListResponse], invocation, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncKernel) -> None: + async with async_client.invocations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + invocation = await response.parse() + assert_matches_type(AsyncOffsetPagination[InvocationListResponse], invocation, path=["response"]) + + assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="Prism tests are disabled") @parametrize async def test_method_delete_browsers(self, async_client: AsyncKernel) -> None: From e58487cf13c3745bd1c402f132c5d27cc34d9ae8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 18:17:56 +0000 Subject: [PATCH 2/2] release: 0.11.4 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/kernel/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 53327971..536ca316 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.11.3" + ".": "0.11.4" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index adcaaf22..90f11cad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.11.4 (2025-09-25) + +Full Changelog: [v0.11.3...v0.11.4](https://github.com/onkernel/kernel-python-sdk/compare/v0.11.3...v0.11.4) + +### Features + +* getInvocations endpoint ([bb39872](https://github.com/onkernel/kernel-python-sdk/commit/bb39872703bd6ace1e588a54420f29a62140144b)) + ## 0.11.3 (2025-09-24) Full Changelog: [v0.11.2...v0.11.3](https://github.com/onkernel/kernel-python-sdk/compare/v0.11.2...v0.11.3) diff --git a/pyproject.toml b/pyproject.toml index e5bcc8f8..c45dd071 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.11.3" +version = "0.11.4" 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 408c4e47..acdc6580 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.11.3" # x-release-please-version +__version__ = "0.11.4" # x-release-please-version