diff --git a/.stats.yml b/.stats.yml index 6de88712..33d57b57 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 12 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/arcade-ai%2Farcade-engine-2e241e72cb7992ad6ef82cde7a5b013da7773618a4c3e65c4804f49bf1fa9aac.yml +configured_endpoints: 14 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/arcade-ai%2Farcade-engine-c089b91b0e1c2bc2e6a5bd42454c82a162957011f1d8469c680a82ff05ee9ec9.yml diff --git a/api.md b/api.md index 77126cba..1fb480a3 100644 --- a/api.md +++ b/api.md @@ -102,5 +102,11 @@ from arcadepy.types import ( UpdateWorkerRequest, WorkerHealthResponse, WorkerResponse, + WorkerListResponse, ) ``` + +Methods: + +- client.worker.create(\*\*params) -> WorkerResponse +- client.worker.list() -> WorkerListResponse diff --git a/src/arcadepy/_client.py b/src/arcadepy/_client.py index 3bf6f549..4d3ce344 100644 --- a/src/arcadepy/_client.py +++ b/src/arcadepy/_client.py @@ -24,7 +24,7 @@ get_async_library, ) from ._version import __version__ -from .resources import auth, health +from .resources import auth, health, worker from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import ArcadeError, APIStatusError from ._base_client import ( @@ -43,6 +43,7 @@ class Arcade(SyncAPIClient): health: health.HealthResource chat: chat.ChatResource tools: tools.ToolsResource + worker: worker.WorkerResource with_raw_response: ArcadeWithRawResponse with_streaming_response: ArcadeWithStreamedResponse @@ -104,6 +105,7 @@ def __init__( self.health = health.HealthResource(self) self.chat = chat.ChatResource(self) self.tools = tools.ToolsResource(self) + self.worker = worker.WorkerResource(self) self.with_raw_response = ArcadeWithRawResponse(self) self.with_streaming_response = ArcadeWithStreamedResponse(self) @@ -217,6 +219,7 @@ class AsyncArcade(AsyncAPIClient): health: health.AsyncHealthResource chat: chat.AsyncChatResource tools: tools.AsyncToolsResource + worker: worker.AsyncWorkerResource with_raw_response: AsyncArcadeWithRawResponse with_streaming_response: AsyncArcadeWithStreamedResponse @@ -278,6 +281,7 @@ def __init__( self.health = health.AsyncHealthResource(self) self.chat = chat.AsyncChatResource(self) self.tools = tools.AsyncToolsResource(self) + self.worker = worker.AsyncWorkerResource(self) self.with_raw_response = AsyncArcadeWithRawResponse(self) self.with_streaming_response = AsyncArcadeWithStreamedResponse(self) @@ -392,6 +396,7 @@ def __init__(self, client: Arcade) -> None: self.health = health.HealthResourceWithRawResponse(client.health) self.chat = chat.ChatResourceWithRawResponse(client.chat) self.tools = tools.ToolsResourceWithRawResponse(client.tools) + self.worker = worker.WorkerResourceWithRawResponse(client.worker) class AsyncArcadeWithRawResponse: @@ -400,6 +405,7 @@ def __init__(self, client: AsyncArcade) -> None: self.health = health.AsyncHealthResourceWithRawResponse(client.health) self.chat = chat.AsyncChatResourceWithRawResponse(client.chat) self.tools = tools.AsyncToolsResourceWithRawResponse(client.tools) + self.worker = worker.AsyncWorkerResourceWithRawResponse(client.worker) class ArcadeWithStreamedResponse: @@ -408,6 +414,7 @@ def __init__(self, client: Arcade) -> None: self.health = health.HealthResourceWithStreamingResponse(client.health) self.chat = chat.ChatResourceWithStreamingResponse(client.chat) self.tools = tools.ToolsResourceWithStreamingResponse(client.tools) + self.worker = worker.WorkerResourceWithStreamingResponse(client.worker) class AsyncArcadeWithStreamedResponse: @@ -416,6 +423,7 @@ def __init__(self, client: AsyncArcade) -> None: self.health = health.AsyncHealthResourceWithStreamingResponse(client.health) self.chat = chat.AsyncChatResourceWithStreamingResponse(client.chat) self.tools = tools.AsyncToolsResourceWithStreamingResponse(client.tools) + self.worker = worker.AsyncWorkerResourceWithStreamingResponse(client.worker) Client = Arcade diff --git a/src/arcadepy/resources/__init__.py b/src/arcadepy/resources/__init__.py index 648d6b2e..2c5b8eef 100644 --- a/src/arcadepy/resources/__init__.py +++ b/src/arcadepy/resources/__init__.py @@ -32,6 +32,14 @@ HealthResourceWithStreamingResponse, AsyncHealthResourceWithStreamingResponse, ) +from .worker import ( + WorkerResource, + AsyncWorkerResource, + WorkerResourceWithRawResponse, + AsyncWorkerResourceWithRawResponse, + WorkerResourceWithStreamingResponse, + AsyncWorkerResourceWithStreamingResponse, +) __all__ = [ "AuthResource", @@ -58,4 +66,10 @@ "AsyncToolsResourceWithRawResponse", "ToolsResourceWithStreamingResponse", "AsyncToolsResourceWithStreamingResponse", + "WorkerResource", + "AsyncWorkerResource", + "WorkerResourceWithRawResponse", + "AsyncWorkerResourceWithRawResponse", + "WorkerResourceWithStreamingResponse", + "AsyncWorkerResourceWithStreamingResponse", ] diff --git a/src/arcadepy/resources/worker.py b/src/arcadepy/resources/worker.py new file mode 100644 index 00000000..827013d0 --- /dev/null +++ b/src/arcadepy/resources/worker.py @@ -0,0 +1,235 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import worker_create_params +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._utils import ( + maybe_transform, + async_maybe_transform, +) +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.worker_response import WorkerResponse +from ..types.worker_list_response import WorkerListResponse + +__all__ = ["WorkerResource", "AsyncWorkerResource"] + + +class WorkerResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> WorkerResourceWithRawResponse: + """ + 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/ArcadeAI/arcade-py#accessing-raw-response-data-eg-headers + """ + return WorkerResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> WorkerResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/ArcadeAI/arcade-py#with_streaming_response + """ + return WorkerResourceWithStreamingResponse(self) + + def create( + self, + *, + id: str, + enabled: bool, + http: worker_create_params.HTTP | NotGiven = NOT_GIVEN, + # 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, + ) -> WorkerResponse: + """ + Create a worker + + 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 + """ + return self._post( + "/v1/admin/workers", + body=maybe_transform( + { + "id": id, + "enabled": enabled, + "http": http, + }, + worker_create_params.WorkerCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WorkerResponse, + ) + + def list( + 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, + ) -> WorkerListResponse: + """List all workers with their definitions""" + return self._get( + "/v1/admin/workers", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WorkerListResponse, + ) + + +class AsyncWorkerResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncWorkerResourceWithRawResponse: + """ + 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/ArcadeAI/arcade-py#accessing-raw-response-data-eg-headers + """ + return AsyncWorkerResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncWorkerResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/ArcadeAI/arcade-py#with_streaming_response + """ + return AsyncWorkerResourceWithStreamingResponse(self) + + async def create( + self, + *, + id: str, + enabled: bool, + http: worker_create_params.HTTP | NotGiven = NOT_GIVEN, + # 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, + ) -> WorkerResponse: + """ + Create a worker + + 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 + """ + return await self._post( + "/v1/admin/workers", + body=await async_maybe_transform( + { + "id": id, + "enabled": enabled, + "http": http, + }, + worker_create_params.WorkerCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WorkerResponse, + ) + + async def list( + 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, + ) -> WorkerListResponse: + """List all workers with their definitions""" + return await self._get( + "/v1/admin/workers", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WorkerListResponse, + ) + + +class WorkerResourceWithRawResponse: + def __init__(self, worker: WorkerResource) -> None: + self._worker = worker + + self.create = to_raw_response_wrapper( + worker.create, + ) + self.list = to_raw_response_wrapper( + worker.list, + ) + + +class AsyncWorkerResourceWithRawResponse: + def __init__(self, worker: AsyncWorkerResource) -> None: + self._worker = worker + + self.create = async_to_raw_response_wrapper( + worker.create, + ) + self.list = async_to_raw_response_wrapper( + worker.list, + ) + + +class WorkerResourceWithStreamingResponse: + def __init__(self, worker: WorkerResource) -> None: + self._worker = worker + + self.create = to_streamed_response_wrapper( + worker.create, + ) + self.list = to_streamed_response_wrapper( + worker.list, + ) + + +class AsyncWorkerResourceWithStreamingResponse: + def __init__(self, worker: AsyncWorkerResource) -> None: + self._worker = worker + + self.create = async_to_streamed_response_wrapper( + worker.create, + ) + self.list = async_to_streamed_response_wrapper( + worker.list, + ) diff --git a/src/arcadepy/types/__init__.py b/src/arcadepy/types/__init__.py index 77e592f3..e01175e0 100644 --- a/src/arcadepy/types/__init__.py +++ b/src/arcadepy/types/__init__.py @@ -15,10 +15,13 @@ from .health_schema import HealthSchema as HealthSchema from .tool_execution import ToolExecution as ToolExecution from .tool_definition import ToolDefinition as ToolDefinition +from .worker_response import WorkerResponse as WorkerResponse from .tool_list_params import ToolListParams as ToolListParams from .auth_status_params import AuthStatusParams as AuthStatusParams from .chat_message_param import ChatMessageParam as ChatMessageParam from .tool_execute_params import ToolExecuteParams as ToolExecuteParams +from .worker_create_params import WorkerCreateParams as WorkerCreateParams +from .worker_list_response import WorkerListResponse as WorkerListResponse from .auth_authorize_params import AuthAuthorizeParams as AuthAuthorizeParams from .execute_tool_response import ExecuteToolResponse as ExecuteToolResponse from .tool_authorize_params import ToolAuthorizeParams as ToolAuthorizeParams diff --git a/src/arcadepy/types/worker_create_params.py b/src/arcadepy/types/worker_create_params.py new file mode 100644 index 00000000..d08266e3 --- /dev/null +++ b/src/arcadepy/types/worker_create_params.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["WorkerCreateParams", "HTTP"] + + +class WorkerCreateParams(TypedDict, total=False): + id: Required[str] + + enabled: Required[bool] + + http: HTTP + + +class HTTP(TypedDict, total=False): + retry: Required[int] + + secret: Required[str] + + timeout: Required[int] + + uri: Required[str] diff --git a/src/arcadepy/types/worker_list_response.py b/src/arcadepy/types/worker_list_response.py new file mode 100644 index 00000000..9a7b24c5 --- /dev/null +++ b/src/arcadepy/types/worker_list_response.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel +from .worker_response import WorkerResponse + +__all__ = ["WorkerListResponse"] + + +class WorkerListResponse(BaseModel): + items: Optional[List[WorkerResponse]] = None + + limit: Optional[int] = None + + offset: Optional[int] = None + + page_count: Optional[int] = None + + total_count: Optional[int] = None diff --git a/src/arcadepy/types/worker_response.py b/src/arcadepy/types/worker_response.py new file mode 100644 index 00000000..0f7f434d --- /dev/null +++ b/src/arcadepy/types/worker_response.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["WorkerResponse", "HTTP", "HTTPSecret"] + + +class HTTPSecret(BaseModel): + binding: Optional[Literal["static", "tenant", "organization", "account"]] = None + + editable: Optional[bool] = None + + exists: Optional[bool] = None + + hint: Optional[str] = None + + value: Optional[str] = None + + +class HTTP(BaseModel): + retry: Optional[int] = None + + secret: Optional[HTTPSecret] = None + + timeout: Optional[int] = None + + uri: Optional[str] = None + + +class WorkerResponse(BaseModel): + id: Optional[str] = None + + enabled: Optional[bool] = None + + http: Optional[HTTP] = None + + type: Optional[str] = None diff --git a/tests/api_resources/test_worker.py b/tests/api_resources/test_worker.py new file mode 100644 index 00000000..34682074 --- /dev/null +++ b/tests/api_resources/test_worker.py @@ -0,0 +1,168 @@ +# 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 arcadepy import Arcade, AsyncArcade +from tests.utils import assert_matches_type +from arcadepy.types import WorkerResponse, WorkerListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestWorker: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Arcade) -> None: + worker = client.worker.create( + id="id", + enabled=True, + ) + assert_matches_type(WorkerResponse, worker, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Arcade) -> None: + worker = client.worker.create( + id="id", + enabled=True, + http={ + "retry": 0, + "secret": "secret", + "timeout": 1, + "uri": "uri", + }, + ) + assert_matches_type(WorkerResponse, worker, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Arcade) -> None: + response = client.worker.with_raw_response.create( + id="id", + enabled=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + worker = response.parse() + assert_matches_type(WorkerResponse, worker, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Arcade) -> None: + with client.worker.with_streaming_response.create( + id="id", + enabled=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + worker = response.parse() + assert_matches_type(WorkerResponse, worker, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_list(self, client: Arcade) -> None: + worker = client.worker.list() + assert_matches_type(WorkerListResponse, worker, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Arcade) -> None: + response = client.worker.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + worker = response.parse() + assert_matches_type(WorkerListResponse, worker, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Arcade) -> None: + with client.worker.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + worker = response.parse() + assert_matches_type(WorkerListResponse, worker, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncWorker: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncArcade) -> None: + worker = await async_client.worker.create( + id="id", + enabled=True, + ) + assert_matches_type(WorkerResponse, worker, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncArcade) -> None: + worker = await async_client.worker.create( + id="id", + enabled=True, + http={ + "retry": 0, + "secret": "secret", + "timeout": 1, + "uri": "uri", + }, + ) + assert_matches_type(WorkerResponse, worker, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncArcade) -> None: + response = await async_client.worker.with_raw_response.create( + id="id", + enabled=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + worker = await response.parse() + assert_matches_type(WorkerResponse, worker, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncArcade) -> None: + async with async_client.worker.with_streaming_response.create( + id="id", + enabled=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + worker = await response.parse() + assert_matches_type(WorkerResponse, worker, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_list(self, async_client: AsyncArcade) -> None: + worker = await async_client.worker.list() + assert_matches_type(WorkerListResponse, worker, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncArcade) -> None: + response = await async_client.worker.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + worker = await response.parse() + assert_matches_type(WorkerListResponse, worker, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncArcade) -> None: + async with async_client.worker.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + worker = await response.parse() + assert_matches_type(WorkerListResponse, worker, path=["response"]) + + assert cast(Any, response.is_closed) is True