diff --git a/.stats.yml b/.stats.yml index c9c0ed68..e786c4a6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/arcade-ai%2Farcade-engine-2f4d672c34ee530fb7290e2fb799d907aba7d9e47030659422f4e7760625be90.yml +configured_endpoints: 8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/arcade-ai%2Farcade-engine-e021712a6bf43d1333001852981dae4a2461da7e8285a732f8adfbeb7b6d77c4.yml diff --git a/README.md b/README.md index 7dfe008a..e886bf44 100644 --- a/README.md +++ b/README.md @@ -35,13 +35,13 @@ client = Arcade( api_key=os.environ.get("ARCADE_API_KEY"), ) -tool_response = client.tools.execute( - inputs="[object Object]", +response = client.tools.execute( tool_name="Google.ListEmails", + inputs='{"n_emails": 10}', tool_version="0.1.0", user_id="user@example.com", ) -print(tool_response.invocation_id) +print(response.invocation_id) ``` While you can provide an `api_key` keyword argument, @@ -65,13 +65,13 @@ client = AsyncArcade( async def main() -> None: - tool_response = await client.tools.execute( - inputs="[object Object]", + response = await client.tools.execute( tool_name="Google.ListEmails", + inputs='{"n_emails": 10}', tool_version="0.1.0", user_id="user@example.com", ) - print(tool_response.invocation_id) + print(response.invocation_id) asyncio.run(main()) @@ -104,7 +104,7 @@ from arcadepy import Arcade client = Arcade() try: - client.chat.completions( + client.chat.completions.completions( messages=[ { "role": "user", @@ -154,7 +154,7 @@ client = Arcade( ) # Or, configure per-request: -client.with_options(max_retries=5).chat.completions( +client.with_options(max_retries=5).chat.completions.completions( messages=[ { "role": "user", @@ -184,7 +184,7 @@ client = Arcade( ) # Override per-request: -client.with_options(timeout=5.0).chat.completions( +client.with_options(timeout=5.0).chat.completions.completions( messages=[ { "role": "user", @@ -230,7 +230,7 @@ The "raw" Response object can be accessed by prefixing `.with_raw_response.` to from arcadepy import Arcade client = Arcade() -response = client.chat.with_raw_response.completions( +response = client.chat.completions.with_raw_response.completions( messages=[{ "role": "user", "content": "Hello, how can I use Arcade AI?", @@ -238,8 +238,8 @@ response = client.chat.with_raw_response.completions( ) print(response.headers.get('X-My-Header')) -chat = response.parse() # get the object that `chat.completions()` would have returned -print(chat.id) +completion = response.parse() # get the object that `chat.completions.completions()` would have returned +print(completion.id) ``` These methods return an [`APIResponse`](https://github.com/ArcadeAI/arcade-py/tree/main/src/arcadepy/_response.py) object. @@ -253,7 +253,7 @@ The above interface eagerly reads the full response body when you make the reque To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods. ```python -with client.chat.with_streaming_response.completions( +with client.chat.completions.with_streaming_response.completions( messages=[ { "role": "user", diff --git a/api.md b/api.md index 35d431bc..795764d6 100644 --- a/api.md +++ b/api.md @@ -1,7 +1,7 @@ # Shared Types ```python -from arcadepy.types import Error +from arcadepy.types import AuthorizationResponse, Error, ToolDefinition ``` # Auth @@ -9,48 +9,68 @@ from arcadepy.types import Error Types: ```python -from arcadepy.types import AuthorizationResponse +from arcadepy.types import AuthRequest ``` Methods: -- client.auth.authorize(\*\*params) -> AuthorizationResponse -- client.auth.status(\*\*params) -> AuthorizationResponse +- client.auth.authorize(\*\*params) -> AuthorizationResponse +- client.auth.status(\*\*params) -> AuthorizationResponse -# Chat +# Health Types: ```python -from arcadepy.types import ChatMessage, ChatRequest, ChatResponse +from arcadepy.types import HealthSchema ``` Methods: -- client.chat.completions(\*\*params) -> ChatResponse +- client.health.check() -> HealthSchema -# Health +# Chat Types: ```python -from arcadepy.types import HealthSchema +from arcadepy.types import ChatMessage, ChatRequest, ChatResponse, Choice, Usage ``` +## Completions + Methods: -- client.health.check() -> HealthSchema +- client.chat.completions.completions(\*\*params) -> ChatResponse # Tools Types: ```python -from arcadepy.types import AuthorizeToolRequest, ExecuteToolRequest, ToolDefinition, ToolResponse +from arcadepy.types import ( + AuthorizeToolRequest, + ExecuteToolRequest, + Inputs, + Output, + Parameter, + Requirements, + Response, + ResponseOutput, + ToolkitDefinition, + ValueSchema, + ToolListResponse, +) ``` Methods: -- client.tools.authorize(\*\*params) -> AuthorizationResponse -- client.tools.execute(\*\*params) -> ToolResponse -- client.tools.retrieve_definition(\*\*params) -> ToolDefinition +- client.tools.list(\*\*params) -> ToolListResponse +- client.tools.authorize(\*\*params) -> AuthorizationResponse +- client.tools.execute(\*\*params) -> Response + +## Definition + +Methods: + +- client.tools.definition.get(\*\*params) -> ToolDefinition diff --git a/src/arcadepy/_client.py b/src/arcadepy/_client.py index 2cf4cb44..519a3ab5 100644 --- a/src/arcadepy/_client.py +++ b/src/arcadepy/_client.py @@ -47,8 +47,8 @@ class Arcade(SyncAPIClient): auth: resources.AuthResource - chat: resources.ChatResource health: resources.HealthResource + chat: resources.ChatResource tools: resources.ToolsResource with_raw_response: ArcadeWithRawResponse with_streaming_response: ArcadeWithStreamedResponse @@ -110,8 +110,8 @@ def __init__( self._idempotency_header = "Idempotency-Key" self.auth = resources.AuthResource(self) - self.chat = resources.ChatResource(self) self.health = resources.HealthResource(self) + self.chat = resources.ChatResource(self) self.tools = resources.ToolsResource(self) self.with_raw_response = ArcadeWithRawResponse(self) self.with_streaming_response = ArcadeWithStreamedResponse(self) @@ -223,8 +223,8 @@ def _make_status_error( class AsyncArcade(AsyncAPIClient): auth: resources.AsyncAuthResource - chat: resources.AsyncChatResource health: resources.AsyncHealthResource + chat: resources.AsyncChatResource tools: resources.AsyncToolsResource with_raw_response: AsyncArcadeWithRawResponse with_streaming_response: AsyncArcadeWithStreamedResponse @@ -286,8 +286,8 @@ def __init__( self._idempotency_header = "Idempotency-Key" self.auth = resources.AsyncAuthResource(self) - self.chat = resources.AsyncChatResource(self) self.health = resources.AsyncHealthResource(self) + self.chat = resources.AsyncChatResource(self) self.tools = resources.AsyncToolsResource(self) self.with_raw_response = AsyncArcadeWithRawResponse(self) self.with_streaming_response = AsyncArcadeWithStreamedResponse(self) @@ -400,32 +400,32 @@ def _make_status_error( class ArcadeWithRawResponse: def __init__(self, client: Arcade) -> None: self.auth = resources.AuthResourceWithRawResponse(client.auth) - self.chat = resources.ChatResourceWithRawResponse(client.chat) self.health = resources.HealthResourceWithRawResponse(client.health) + self.chat = resources.ChatResourceWithRawResponse(client.chat) self.tools = resources.ToolsResourceWithRawResponse(client.tools) class AsyncArcadeWithRawResponse: def __init__(self, client: AsyncArcade) -> None: self.auth = resources.AsyncAuthResourceWithRawResponse(client.auth) - self.chat = resources.AsyncChatResourceWithRawResponse(client.chat) self.health = resources.AsyncHealthResourceWithRawResponse(client.health) + self.chat = resources.AsyncChatResourceWithRawResponse(client.chat) self.tools = resources.AsyncToolsResourceWithRawResponse(client.tools) class ArcadeWithStreamedResponse: def __init__(self, client: Arcade) -> None: self.auth = resources.AuthResourceWithStreamingResponse(client.auth) - self.chat = resources.ChatResourceWithStreamingResponse(client.chat) self.health = resources.HealthResourceWithStreamingResponse(client.health) + self.chat = resources.ChatResourceWithStreamingResponse(client.chat) self.tools = resources.ToolsResourceWithStreamingResponse(client.tools) class AsyncArcadeWithStreamedResponse: def __init__(self, client: AsyncArcade) -> None: self.auth = resources.AsyncAuthResourceWithStreamingResponse(client.auth) - self.chat = resources.AsyncChatResourceWithStreamingResponse(client.chat) self.health = resources.AsyncHealthResourceWithStreamingResponse(client.health) + self.chat = resources.AsyncChatResourceWithStreamingResponse(client.chat) self.tools = resources.AsyncToolsResourceWithStreamingResponse(client.tools) diff --git a/src/arcadepy/resources/__init__.py b/src/arcadepy/resources/__init__.py index 7ac7a1ae..648d6b2e 100644 --- a/src/arcadepy/resources/__init__.py +++ b/src/arcadepy/resources/__init__.py @@ -40,18 +40,18 @@ "AsyncAuthResourceWithRawResponse", "AuthResourceWithStreamingResponse", "AsyncAuthResourceWithStreamingResponse", - "ChatResource", - "AsyncChatResource", - "ChatResourceWithRawResponse", - "AsyncChatResourceWithRawResponse", - "ChatResourceWithStreamingResponse", - "AsyncChatResourceWithStreamingResponse", "HealthResource", "AsyncHealthResource", "HealthResourceWithRawResponse", "AsyncHealthResourceWithRawResponse", "HealthResourceWithStreamingResponse", "AsyncHealthResourceWithStreamingResponse", + "ChatResource", + "AsyncChatResource", + "ChatResourceWithRawResponse", + "AsyncChatResourceWithRawResponse", + "ChatResourceWithStreamingResponse", + "AsyncChatResourceWithStreamingResponse", "ToolsResource", "AsyncToolsResource", "ToolsResourceWithRawResponse", diff --git a/src/arcadepy/resources/auth.py b/src/arcadepy/resources/auth.py index 920786cc..467eb94c 100644 --- a/src/arcadepy/resources/auth.py +++ b/src/arcadepy/resources/auth.py @@ -19,7 +19,7 @@ async_to_streamed_response_wrapper, ) from .._base_client import make_request_options -from ..types.authorization_response import AuthorizationResponse +from ..types.shared.authorization_response import AuthorizationResponse __all__ = ["AuthResource", "AsyncAuthResource"] @@ -95,6 +95,7 @@ def status( *, authorization_id: str, scopes: str | NotGiven = NOT_GIVEN, + wait: int | 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, @@ -102,14 +103,19 @@ def status( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AuthorizationResponse: - """ - Checks the status of an ongoing authorization process for a specific tool + """Checks the status of an ongoing authorization process for a specific tool. + + If + 'wait' param is present, does not respond until either the auth status becomes + completed or the timeout is reached. Args: authorization_id: Authorization ID scopes: Scopes + wait: Timeout in seconds (max 60) + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -129,6 +135,7 @@ def status( { "authorization_id": authorization_id, "scopes": scopes, + "wait": wait, }, auth_status_params.AuthStatusParams, ), @@ -208,6 +215,7 @@ async def status( *, authorization_id: str, scopes: str | NotGiven = NOT_GIVEN, + wait: int | 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, @@ -215,14 +223,19 @@ async def status( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AuthorizationResponse: - """ - Checks the status of an ongoing authorization process for a specific tool + """Checks the status of an ongoing authorization process for a specific tool. + + If + 'wait' param is present, does not respond until either the auth status becomes + completed or the timeout is reached. Args: authorization_id: Authorization ID scopes: Scopes + wait: Timeout in seconds (max 60) + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -242,6 +255,7 @@ async def status( { "authorization_id": authorization_id, "scopes": scopes, + "wait": wait, }, auth_status_params.AuthStatusParams, ), diff --git a/src/arcadepy/resources/chat/__init__.py b/src/arcadepy/resources/chat/__init__.py new file mode 100644 index 00000000..ec960eb4 --- /dev/null +++ b/src/arcadepy/resources/chat/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .chat import ( + ChatResource, + AsyncChatResource, + ChatResourceWithRawResponse, + AsyncChatResourceWithRawResponse, + ChatResourceWithStreamingResponse, + AsyncChatResourceWithStreamingResponse, +) +from .completions import ( + CompletionsResource, + AsyncCompletionsResource, + CompletionsResourceWithRawResponse, + AsyncCompletionsResourceWithRawResponse, + CompletionsResourceWithStreamingResponse, + AsyncCompletionsResourceWithStreamingResponse, +) + +__all__ = [ + "CompletionsResource", + "AsyncCompletionsResource", + "CompletionsResourceWithRawResponse", + "AsyncCompletionsResourceWithRawResponse", + "CompletionsResourceWithStreamingResponse", + "AsyncCompletionsResourceWithStreamingResponse", + "ChatResource", + "AsyncChatResource", + "ChatResourceWithRawResponse", + "AsyncChatResourceWithRawResponse", + "ChatResourceWithStreamingResponse", + "AsyncChatResourceWithStreamingResponse", +] diff --git a/src/arcadepy/resources/chat/chat.py b/src/arcadepy/resources/chat/chat.py new file mode 100644 index 00000000..a3857eec --- /dev/null +++ b/src/arcadepy/resources/chat/chat.py @@ -0,0 +1,102 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from .completions import ( + CompletionsResource, + AsyncCompletionsResource, + CompletionsResourceWithRawResponse, + AsyncCompletionsResourceWithRawResponse, + CompletionsResourceWithStreamingResponse, + AsyncCompletionsResourceWithStreamingResponse, +) + +__all__ = ["ChatResource", "AsyncChatResource"] + + +class ChatResource(SyncAPIResource): + @cached_property + def completions(self) -> CompletionsResource: + return CompletionsResource(self._client) + + @cached_property + def with_raw_response(self) -> ChatResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + 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 ChatResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ChatResourceWithStreamingResponse: + """ + 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 ChatResourceWithStreamingResponse(self) + + +class AsyncChatResource(AsyncAPIResource): + @cached_property + def completions(self) -> AsyncCompletionsResource: + return AsyncCompletionsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncChatResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + 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 AsyncChatResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncChatResourceWithStreamingResponse: + """ + 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 AsyncChatResourceWithStreamingResponse(self) + + +class ChatResourceWithRawResponse: + def __init__(self, chat: ChatResource) -> None: + self._chat = chat + + @cached_property + def completions(self) -> CompletionsResourceWithRawResponse: + return CompletionsResourceWithRawResponse(self._chat.completions) + + +class AsyncChatResourceWithRawResponse: + def __init__(self, chat: AsyncChatResource) -> None: + self._chat = chat + + @cached_property + def completions(self) -> AsyncCompletionsResourceWithRawResponse: + return AsyncCompletionsResourceWithRawResponse(self._chat.completions) + + +class ChatResourceWithStreamingResponse: + def __init__(self, chat: ChatResource) -> None: + self._chat = chat + + @cached_property + def completions(self) -> CompletionsResourceWithStreamingResponse: + return CompletionsResourceWithStreamingResponse(self._chat.completions) + + +class AsyncChatResourceWithStreamingResponse: + def __init__(self, chat: AsyncChatResource) -> None: + self._chat = chat + + @cached_property + def completions(self) -> AsyncCompletionsResourceWithStreamingResponse: + return AsyncCompletionsResourceWithStreamingResponse(self._chat.completions) diff --git a/src/arcadepy/resources/chat/completions.py b/src/arcadepy/resources/chat/completions.py new file mode 100644 index 00000000..bacfb6e7 --- /dev/null +++ b/src/arcadepy/resources/chat/completions.py @@ -0,0 +1,310 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable +from typing_extensions import Literal + +import httpx + +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 ...types.chat import completion_completions_params +from ..._base_client import make_request_options +from ...types.chat_response import ChatResponse +from ...types.chat_message_param import ChatMessageParam + +__all__ = ["CompletionsResource", "AsyncCompletionsResource"] + + +class CompletionsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CompletionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + 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 CompletionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CompletionsResourceWithStreamingResponse: + """ + 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 CompletionsResourceWithStreamingResponse(self) + + def completions( + self, + *, + frequency_penalty: int | NotGiven = NOT_GIVEN, + logit_bias: Dict[str, int] | NotGiven = NOT_GIVEN, + logprobs: bool | NotGiven = NOT_GIVEN, + max_tokens: int | NotGiven = NOT_GIVEN, + messages: Iterable[ChatMessageParam] | NotGiven = NOT_GIVEN, + model: str | NotGiven = NOT_GIVEN, + n: int | NotGiven = NOT_GIVEN, + parallel_tool_calls: object | NotGiven = NOT_GIVEN, + presence_penalty: int | NotGiven = NOT_GIVEN, + response_format: Literal["json_object", "text"] | NotGiven = NOT_GIVEN, + seed: int | NotGiven = NOT_GIVEN, + stop: List[str] | NotGiven = NOT_GIVEN, + stream: bool | NotGiven = NOT_GIVEN, + stream_options: completion_completions_params.StreamOptions | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + tool_choice: object | NotGiven = NOT_GIVEN, + tools: object | NotGiven = NOT_GIVEN, + top_logprobs: int | NotGiven = NOT_GIVEN, + top_p: float | NotGiven = NOT_GIVEN, + user: str | 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, + idempotency_key: str | None = None, + ) -> ChatResponse: + """ + Talk to different LLM Chat APIs via OpenAI's API + + Args: + logit_bias: LogitBias is must be a token id string (specified by their token ID in the + tokenizer), not a word string. incorrect: `"logit_bias":{"You": 6}`, correct: + `"logit_bias":{"1639": 6}` refs: + https://platform.openai.com/docs/api-reference/chat/create#chat/create-logit_bias + + logprobs: LogProbs indicates whether to return log probabilities of the output tokens or + not. If true, returns the log probabilities of each output token returned in the + content of message. This option is currently not available on the + gpt-4-vision-preview model. + + parallel_tool_calls: Disable the default behavior of parallel tool calls by setting it: false. + + stream_options: Options for streaming response. Only set this when you set stream: true. + + tool_choice: This can be either a string or an ToolChoice object. + + top_logprobs: TopLogProbs is an integer between 0 and 5 specifying the number of most likely + tokens to return at each token position, each with an associated log + probability. logprobs must be set to true if this parameter is used. + + 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 + + idempotency_key: Specify a custom idempotency key for this request + """ + return self._post( + "/v1/chat/completions", + body=maybe_transform( + { + "frequency_penalty": frequency_penalty, + "logit_bias": logit_bias, + "logprobs": logprobs, + "max_tokens": max_tokens, + "messages": messages, + "model": model, + "n": n, + "parallel_tool_calls": parallel_tool_calls, + "presence_penalty": presence_penalty, + "response_format": response_format, + "seed": seed, + "stop": stop, + "stream": stream, + "stream_options": stream_options, + "temperature": temperature, + "tool_choice": tool_choice, + "tools": tools, + "top_logprobs": top_logprobs, + "top_p": top_p, + "user": user, + }, + completion_completions_params.CompletionCompletionsParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=ChatResponse, + ) + + +class AsyncCompletionsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCompletionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + 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 AsyncCompletionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCompletionsResourceWithStreamingResponse: + """ + 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 AsyncCompletionsResourceWithStreamingResponse(self) + + async def completions( + self, + *, + frequency_penalty: int | NotGiven = NOT_GIVEN, + logit_bias: Dict[str, int] | NotGiven = NOT_GIVEN, + logprobs: bool | NotGiven = NOT_GIVEN, + max_tokens: int | NotGiven = NOT_GIVEN, + messages: Iterable[ChatMessageParam] | NotGiven = NOT_GIVEN, + model: str | NotGiven = NOT_GIVEN, + n: int | NotGiven = NOT_GIVEN, + parallel_tool_calls: object | NotGiven = NOT_GIVEN, + presence_penalty: int | NotGiven = NOT_GIVEN, + response_format: Literal["json_object", "text"] | NotGiven = NOT_GIVEN, + seed: int | NotGiven = NOT_GIVEN, + stop: List[str] | NotGiven = NOT_GIVEN, + stream: bool | NotGiven = NOT_GIVEN, + stream_options: completion_completions_params.StreamOptions | NotGiven = NOT_GIVEN, + temperature: float | NotGiven = NOT_GIVEN, + tool_choice: object | NotGiven = NOT_GIVEN, + tools: object | NotGiven = NOT_GIVEN, + top_logprobs: int | NotGiven = NOT_GIVEN, + top_p: float | NotGiven = NOT_GIVEN, + user: str | 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, + idempotency_key: str | None = None, + ) -> ChatResponse: + """ + Talk to different LLM Chat APIs via OpenAI's API + + Args: + logit_bias: LogitBias is must be a token id string (specified by their token ID in the + tokenizer), not a word string. incorrect: `"logit_bias":{"You": 6}`, correct: + `"logit_bias":{"1639": 6}` refs: + https://platform.openai.com/docs/api-reference/chat/create#chat/create-logit_bias + + logprobs: LogProbs indicates whether to return log probabilities of the output tokens or + not. If true, returns the log probabilities of each output token returned in the + content of message. This option is currently not available on the + gpt-4-vision-preview model. + + parallel_tool_calls: Disable the default behavior of parallel tool calls by setting it: false. + + stream_options: Options for streaming response. Only set this when you set stream: true. + + tool_choice: This can be either a string or an ToolChoice object. + + top_logprobs: TopLogProbs is an integer between 0 and 5 specifying the number of most likely + tokens to return at each token position, each with an associated log + probability. logprobs must be set to true if this parameter is used. + + 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 + + idempotency_key: Specify a custom idempotency key for this request + """ + return await self._post( + "/v1/chat/completions", + body=await async_maybe_transform( + { + "frequency_penalty": frequency_penalty, + "logit_bias": logit_bias, + "logprobs": logprobs, + "max_tokens": max_tokens, + "messages": messages, + "model": model, + "n": n, + "parallel_tool_calls": parallel_tool_calls, + "presence_penalty": presence_penalty, + "response_format": response_format, + "seed": seed, + "stop": stop, + "stream": stream, + "stream_options": stream_options, + "temperature": temperature, + "tool_choice": tool_choice, + "tools": tools, + "top_logprobs": top_logprobs, + "top_p": top_p, + "user": user, + }, + completion_completions_params.CompletionCompletionsParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=ChatResponse, + ) + + +class CompletionsResourceWithRawResponse: + def __init__(self, completions: CompletionsResource) -> None: + self._completions = completions + + self.completions = to_raw_response_wrapper( + completions.completions, + ) + + +class AsyncCompletionsResourceWithRawResponse: + def __init__(self, completions: AsyncCompletionsResource) -> None: + self._completions = completions + + self.completions = async_to_raw_response_wrapper( + completions.completions, + ) + + +class CompletionsResourceWithStreamingResponse: + def __init__(self, completions: CompletionsResource) -> None: + self._completions = completions + + self.completions = to_streamed_response_wrapper( + completions.completions, + ) + + +class AsyncCompletionsResourceWithStreamingResponse: + def __init__(self, completions: AsyncCompletionsResource) -> None: + self._completions = completions + + self.completions = async_to_streamed_response_wrapper( + completions.completions, + ) diff --git a/src/arcadepy/resources/tools/__init__.py b/src/arcadepy/resources/tools/__init__.py new file mode 100644 index 00000000..f71184cc --- /dev/null +++ b/src/arcadepy/resources/tools/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .tools import ( + ToolsResource, + AsyncToolsResource, + ToolsResourceWithRawResponse, + AsyncToolsResourceWithRawResponse, + ToolsResourceWithStreamingResponse, + AsyncToolsResourceWithStreamingResponse, +) +from .definition import ( + DefinitionResource, + AsyncDefinitionResource, + DefinitionResourceWithRawResponse, + AsyncDefinitionResourceWithRawResponse, + DefinitionResourceWithStreamingResponse, + AsyncDefinitionResourceWithStreamingResponse, +) + +__all__ = [ + "DefinitionResource", + "AsyncDefinitionResource", + "DefinitionResourceWithRawResponse", + "AsyncDefinitionResourceWithRawResponse", + "DefinitionResourceWithStreamingResponse", + "AsyncDefinitionResourceWithStreamingResponse", + "ToolsResource", + "AsyncToolsResource", + "ToolsResourceWithRawResponse", + "AsyncToolsResourceWithRawResponse", + "ToolsResourceWithStreamingResponse", + "AsyncToolsResourceWithStreamingResponse", +] diff --git a/src/arcadepy/resources/tools/definition.py b/src/arcadepy/resources/tools/definition.py new file mode 100644 index 00000000..c7d06de0 --- /dev/null +++ b/src/arcadepy/resources/tools/definition.py @@ -0,0 +1,194 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +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 ...types.tools import definition_get_params +from ..._base_client import make_request_options +from ...types.shared.tool_definition import ToolDefinition + +__all__ = ["DefinitionResource", "AsyncDefinitionResource"] + + +class DefinitionResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DefinitionResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + 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 DefinitionResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DefinitionResourceWithStreamingResponse: + """ + 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 DefinitionResourceWithStreamingResponse(self) + + def get( + self, + *, + director_id: str, + tool_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, + ) -> ToolDefinition: + """ + Returns the arcade tool specification for a specific tool + + Args: + director_id: Director ID + + tool_id: Tool ID + + 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( + "/v1/tools/definition", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "director_id": director_id, + "tool_id": tool_id, + }, + definition_get_params.DefinitionGetParams, + ), + ), + cast_to=ToolDefinition, + ) + + +class AsyncDefinitionResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDefinitionResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + 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 AsyncDefinitionResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDefinitionResourceWithStreamingResponse: + """ + 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 AsyncDefinitionResourceWithStreamingResponse(self) + + async def get( + self, + *, + director_id: str, + tool_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, + ) -> ToolDefinition: + """ + Returns the arcade tool specification for a specific tool + + Args: + director_id: Director ID + + tool_id: Tool ID + + 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._get( + "/v1/tools/definition", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "director_id": director_id, + "tool_id": tool_id, + }, + definition_get_params.DefinitionGetParams, + ), + ), + cast_to=ToolDefinition, + ) + + +class DefinitionResourceWithRawResponse: + def __init__(self, definition: DefinitionResource) -> None: + self._definition = definition + + self.get = to_raw_response_wrapper( + definition.get, + ) + + +class AsyncDefinitionResourceWithRawResponse: + def __init__(self, definition: AsyncDefinitionResource) -> None: + self._definition = definition + + self.get = async_to_raw_response_wrapper( + definition.get, + ) + + +class DefinitionResourceWithStreamingResponse: + def __init__(self, definition: DefinitionResource) -> None: + self._definition = definition + + self.get = to_streamed_response_wrapper( + definition.get, + ) + + +class AsyncDefinitionResourceWithStreamingResponse: + def __init__(self, definition: AsyncDefinitionResource) -> None: + self._definition = definition + + self.get = async_to_streamed_response_wrapper( + definition.get, + ) diff --git a/src/arcadepy/resources/tools/tools.py b/src/arcadepy/resources/tools/tools.py new file mode 100644 index 00000000..ebfdb3da --- /dev/null +++ b/src/arcadepy/resources/tools/tools.py @@ -0,0 +1,442 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...types import tool_list_params, tool_execute_params, tool_authorize_params +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import ( + maybe_transform, + async_maybe_transform, +) +from ..._compat import cached_property +from .definition import ( + DefinitionResource, + AsyncDefinitionResource, + DefinitionResourceWithRawResponse, + AsyncDefinitionResourceWithRawResponse, + DefinitionResourceWithStreamingResponse, + AsyncDefinitionResourceWithStreamingResponse, +) +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.response import Response +from ...types.tool_list_response import ToolListResponse +from ...types.shared.authorization_response import AuthorizationResponse + +__all__ = ["ToolsResource", "AsyncToolsResource"] + + +class ToolsResource(SyncAPIResource): + @cached_property + def definition(self) -> DefinitionResource: + return DefinitionResource(self._client) + + @cached_property + def with_raw_response(self) -> ToolsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + 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 ToolsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ToolsResourceWithStreamingResponse: + """ + 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 ToolsResourceWithStreamingResponse(self) + + def list( + self, + *, + toolkit: str | 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, + ) -> ToolListResponse: + """ + Returns a list of tools, optionally filtered by toolkit or auth provider + + Args: + toolkit: Toolkit Name + + 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( + "/v1/tools/list", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"toolkit": toolkit}, tool_list_params.ToolListParams), + ), + cast_to=ToolListResponse, + ) + + def authorize( + self, + *, + tool_name: str, + user_id: str, + tool_version: str | 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, + idempotency_key: str | None = None, + ) -> AuthorizationResponse: + """ + Authorizes a user for a specific tool by name + + Args: + tool_version: Optional: if not provided, any version is used + + 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 + + idempotency_key: Specify a custom idempotency key for this request + """ + return self._post( + "/v1/tools/authorize", + body=maybe_transform( + { + "tool_name": tool_name, + "user_id": user_id, + "tool_version": tool_version, + }, + tool_authorize_params.ToolAuthorizeParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=AuthorizationResponse, + ) + + def execute( + self, + *, + tool_name: str, + inputs: str | NotGiven = NOT_GIVEN, + tool_version: str | NotGiven = NOT_GIVEN, + user_id: str | 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, + idempotency_key: str | None = None, + ) -> Response: + """ + Executes a tool by name and arguments + + Args: + inputs: Serialized JSON string + + tool_version: Optional: if not provided, any version is used + + 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 + + idempotency_key: Specify a custom idempotency key for this request + """ + return self._post( + "/v1/tools/execute", + body=maybe_transform( + { + "tool_name": tool_name, + "inputs": inputs, + "tool_version": tool_version, + "user_id": user_id, + }, + tool_execute_params.ToolExecuteParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Response, + ) + + +class AsyncToolsResource(AsyncAPIResource): + @cached_property + def definition(self) -> AsyncDefinitionResource: + return AsyncDefinitionResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncToolsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return the + 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 AsyncToolsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncToolsResourceWithStreamingResponse: + """ + 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 AsyncToolsResourceWithStreamingResponse(self) + + async def list( + self, + *, + toolkit: str | 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, + ) -> ToolListResponse: + """ + Returns a list of tools, optionally filtered by toolkit or auth provider + + Args: + toolkit: Toolkit Name + + 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._get( + "/v1/tools/list", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"toolkit": toolkit}, tool_list_params.ToolListParams), + ), + cast_to=ToolListResponse, + ) + + async def authorize( + self, + *, + tool_name: str, + user_id: str, + tool_version: str | 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, + idempotency_key: str | None = None, + ) -> AuthorizationResponse: + """ + Authorizes a user for a specific tool by name + + Args: + tool_version: Optional: if not provided, any version is used + + 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 + + idempotency_key: Specify a custom idempotency key for this request + """ + return await self._post( + "/v1/tools/authorize", + body=await async_maybe_transform( + { + "tool_name": tool_name, + "user_id": user_id, + "tool_version": tool_version, + }, + tool_authorize_params.ToolAuthorizeParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=AuthorizationResponse, + ) + + async def execute( + self, + *, + tool_name: str, + inputs: str | NotGiven = NOT_GIVEN, + tool_version: str | NotGiven = NOT_GIVEN, + user_id: str | 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, + idempotency_key: str | None = None, + ) -> Response: + """ + Executes a tool by name and arguments + + Args: + inputs: Serialized JSON string + + tool_version: Optional: if not provided, any version is used + + 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 + + idempotency_key: Specify a custom idempotency key for this request + """ + return await self._post( + "/v1/tools/execute", + body=await async_maybe_transform( + { + "tool_name": tool_name, + "inputs": inputs, + "tool_version": tool_version, + "user_id": user_id, + }, + tool_execute_params.ToolExecuteParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + idempotency_key=idempotency_key, + ), + cast_to=Response, + ) + + +class ToolsResourceWithRawResponse: + def __init__(self, tools: ToolsResource) -> None: + self._tools = tools + + self.list = to_raw_response_wrapper( + tools.list, + ) + self.authorize = to_raw_response_wrapper( + tools.authorize, + ) + self.execute = to_raw_response_wrapper( + tools.execute, + ) + + @cached_property + def definition(self) -> DefinitionResourceWithRawResponse: + return DefinitionResourceWithRawResponse(self._tools.definition) + + +class AsyncToolsResourceWithRawResponse: + def __init__(self, tools: AsyncToolsResource) -> None: + self._tools = tools + + self.list = async_to_raw_response_wrapper( + tools.list, + ) + self.authorize = async_to_raw_response_wrapper( + tools.authorize, + ) + self.execute = async_to_raw_response_wrapper( + tools.execute, + ) + + @cached_property + def definition(self) -> AsyncDefinitionResourceWithRawResponse: + return AsyncDefinitionResourceWithRawResponse(self._tools.definition) + + +class ToolsResourceWithStreamingResponse: + def __init__(self, tools: ToolsResource) -> None: + self._tools = tools + + self.list = to_streamed_response_wrapper( + tools.list, + ) + self.authorize = to_streamed_response_wrapper( + tools.authorize, + ) + self.execute = to_streamed_response_wrapper( + tools.execute, + ) + + @cached_property + def definition(self) -> DefinitionResourceWithStreamingResponse: + return DefinitionResourceWithStreamingResponse(self._tools.definition) + + +class AsyncToolsResourceWithStreamingResponse: + def __init__(self, tools: AsyncToolsResource) -> None: + self._tools = tools + + self.list = async_to_streamed_response_wrapper( + tools.list, + ) + self.authorize = async_to_streamed_response_wrapper( + tools.authorize, + ) + self.execute = async_to_streamed_response_wrapper( + tools.execute, + ) + + @cached_property + def definition(self) -> AsyncDefinitionResourceWithStreamingResponse: + return AsyncDefinitionResourceWithStreamingResponse(self._tools.definition) diff --git a/src/arcadepy/types/__init__.py b/src/arcadepy/types/__init__.py index 3ba9dbf0..4da6d4b7 100644 --- a/src/arcadepy/types/__init__.py +++ b/src/arcadepy/types/__init__.py @@ -2,17 +2,24 @@ from __future__ import annotations -from .shared import Error as Error +from .usage import Usage as Usage +from .choice import Choice as Choice +from .inputs import Inputs as Inputs +from .output import Output as Output +from .shared import Error as Error, ToolDefinition as ToolDefinition, AuthorizationResponse as AuthorizationResponse +from .response import Response as Response +from .parameter import Parameter as Parameter from .chat_message import ChatMessage as ChatMessage +from .requirements import Requirements as Requirements +from .value_schema import ValueSchema as ValueSchema from .chat_response import ChatResponse as ChatResponse from .health_schema import HealthSchema as HealthSchema -from .tool_response import ToolResponse as ToolResponse -from .tool_definition import ToolDefinition as ToolDefinition +from .response_output import ResponseOutput as ResponseOutput +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_list_response import ToolListResponse as ToolListResponse +from .toolkit_definition import ToolkitDefinition as ToolkitDefinition from .tool_execute_params import ToolExecuteParams as ToolExecuteParams from .auth_authorize_params import AuthAuthorizeParams as AuthAuthorizeParams from .tool_authorize_params import ToolAuthorizeParams as ToolAuthorizeParams -from .authorization_response import AuthorizationResponse as AuthorizationResponse -from .chat_completions_params import ChatCompletionsParams as ChatCompletionsParams -from .tool_retrieve_definition_params import ToolRetrieveDefinitionParams as ToolRetrieveDefinitionParams diff --git a/src/arcadepy/types/auth_authorize_params.py b/src/arcadepy/types/auth_authorize_params.py index d8da3d82..24b6c5ac 100644 --- a/src/arcadepy/types/auth_authorize_params.py +++ b/src/arcadepy/types/auth_authorize_params.py @@ -15,12 +15,12 @@ class AuthAuthorizeParams(TypedDict, total=False): class AuthRequirementOauth2(TypedDict, total=False): - authority: str - scopes: List[str] class AuthRequirement(TypedDict, total=False): - provider: Required[str] - oauth2: AuthRequirementOauth2 + + provider_id: str + + provider_type: str diff --git a/src/arcadepy/types/auth_status_params.py b/src/arcadepy/types/auth_status_params.py index 6026fb39..8eadbfeb 100644 --- a/src/arcadepy/types/auth_status_params.py +++ b/src/arcadepy/types/auth_status_params.py @@ -10,8 +10,11 @@ class AuthStatusParams(TypedDict, total=False): - authorization_id: Required[Annotated[str, PropertyInfo(alias="authorizationID")]] + authorization_id: Required[Annotated[str, PropertyInfo(alias="authorizationId")]] """Authorization ID""" scopes: str """Scopes""" + + wait: int + """Timeout in seconds (max 60)""" diff --git a/src/arcadepy/types/chat/__init__.py b/src/arcadepy/types/chat/__init__.py new file mode 100644 index 00000000..44798218 --- /dev/null +++ b/src/arcadepy/types/chat/__init__.py @@ -0,0 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .completion_completions_params import CompletionCompletionsParams as CompletionCompletionsParams diff --git a/src/arcadepy/types/chat/completion_completions_params.py b/src/arcadepy/types/chat/completion_completions_params.py new file mode 100644 index 00000000..a3407090 --- /dev/null +++ b/src/arcadepy/types/chat/completion_completions_params.py @@ -0,0 +1,82 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Iterable +from typing_extensions import Literal, TypedDict + +from ..chat_message_param import ChatMessageParam + +__all__ = ["CompletionCompletionsParams", "StreamOptions"] + + +class CompletionCompletionsParams(TypedDict, total=False): + frequency_penalty: int + + logit_bias: Dict[str, int] + """ + LogitBias is must be a token id string (specified by their token ID in the + tokenizer), not a word string. incorrect: `"logit_bias":{"You": 6}`, correct: + `"logit_bias":{"1639": 6}` refs: + https://platform.openai.com/docs/api-reference/chat/create#chat/create-logit_bias + """ + + logprobs: bool + """ + LogProbs indicates whether to return log probabilities of the output tokens or + not. If true, returns the log probabilities of each output token returned in the + content of message. This option is currently not available on the + gpt-4-vision-preview model. + """ + + max_tokens: int + + messages: Iterable[ChatMessageParam] + + model: str + + n: int + + parallel_tool_calls: object + """Disable the default behavior of parallel tool calls by setting it: false.""" + + presence_penalty: int + + response_format: Literal["json_object", "text"] + + seed: int + + stop: List[str] + + stream: bool + + stream_options: StreamOptions + """Options for streaming response. Only set this when you set stream: true.""" + + temperature: float + + tool_choice: object + """This can be either a string or an ToolChoice object.""" + + tools: object + + top_logprobs: int + """ + TopLogProbs is an integer between 0 and 5 specifying the number of most likely + tokens to return at each token position, each with an associated log + probability. logprobs must be set to true if this parameter is used. + """ + + top_p: float + + user: str + + +class StreamOptions(TypedDict, total=False): + include_usage: bool + """ + If set, an additional chunk will be streamed before the data: [DONE] message. + The usage field on this chunk shows the token usage statistics for the entire + request, and the choices field will always be an empty array. All other chunks + will also include a usage field, but with a null value. + """ diff --git a/src/arcadepy/types/chat_response.py b/src/arcadepy/types/chat_response.py index 04ce655e..c3fefab2 100644 --- a/src/arcadepy/types/chat_response.py +++ b/src/arcadepy/types/chat_response.py @@ -2,28 +2,11 @@ from typing import List, Optional +from .usage import Usage +from .choice import Choice from .._models import BaseModel -from .chat_message import ChatMessage -__all__ = ["ChatResponse", "Choice", "Usage"] - - -class Choice(BaseModel): - finish_reason: Optional[str] = None - - index: Optional[int] = None - - logprobs: Optional[object] = None - - message: Optional[ChatMessage] = None - - -class Usage(BaseModel): - completion_tokens: Optional[int] = None - - prompt_tokens: Optional[int] = None - - total_tokens: Optional[int] = None +__all__ = ["ChatResponse"] class ChatResponse(BaseModel): diff --git a/src/arcadepy/types/choice.py b/src/arcadepy/types/choice.py new file mode 100644 index 00000000..578f1d96 --- /dev/null +++ b/src/arcadepy/types/choice.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel +from .chat_message import ChatMessage +from .shared.authorization_response import AuthorizationResponse + +__all__ = ["Choice"] + + +class Choice(BaseModel): + finish_reason: Optional[str] = None + + index: Optional[int] = None + + logprobs: Optional[object] = None + + message: Optional[ChatMessage] = None + + tool_authorizations: Optional[List[AuthorizationResponse]] = None + + tool_messages: Optional[List[ChatMessage]] = None diff --git a/src/arcadepy/types/inputs.py b/src/arcadepy/types/inputs.py new file mode 100644 index 00000000..93f9b013 --- /dev/null +++ b/src/arcadepy/types/inputs.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel +from .parameter import Parameter + +__all__ = ["Inputs"] + + +class Inputs(BaseModel): + parameters: Optional[List[Parameter]] = None diff --git a/src/arcadepy/types/output.py b/src/arcadepy/types/output.py new file mode 100644 index 00000000..e4817bff --- /dev/null +++ b/src/arcadepy/types/output.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel +from .value_schema import ValueSchema + +__all__ = ["Output"] + + +class Output(BaseModel): + available_modes: Optional[List[str]] = None + + description: Optional[str] = None + + value_schema: Optional[ValueSchema] = None diff --git a/src/arcadepy/types/parameter.py b/src/arcadepy/types/parameter.py new file mode 100644 index 00000000..5e5c3c84 --- /dev/null +++ b/src/arcadepy/types/parameter.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel +from .value_schema import ValueSchema + +__all__ = ["Parameter"] + + +class Parameter(BaseModel): + name: str + + value_schema: ValueSchema + + description: Optional[str] = None + + inferrable: Optional[bool] = None + + required: Optional[bool] = None diff --git a/src/arcadepy/types/requirements.py b/src/arcadepy/types/requirements.py new file mode 100644 index 00000000..c792b7d3 --- /dev/null +++ b/src/arcadepy/types/requirements.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel + +__all__ = ["Requirements", "Authorization", "AuthorizationOauth2"] + + +class AuthorizationOauth2(BaseModel): + scopes: Optional[List[str]] = None + + +class Authorization(BaseModel): + oauth2: Optional[AuthorizationOauth2] = None + + provider_id: Optional[str] = None + + provider_type: Optional[str] = None + + +class Requirements(BaseModel): + authorization: Optional[Authorization] = None diff --git a/src/arcadepy/types/response.py b/src/arcadepy/types/response.py index 7a4b089e..730a70ba 100644 --- a/src/arcadepy/types/response.py +++ b/src/arcadepy/types/response.py @@ -5,32 +5,15 @@ from pydantic import Field as FieldInfo from .._models import BaseModel +from .response_output import ResponseOutput -__all__ = ["Response", "FinishedAt", "Output", "OutputError"] +__all__ = ["Response", "FinishedAt"] class FinishedAt(BaseModel): time_time: Optional[str] = FieldInfo(alias="time.Time", default=None) -class OutputError(BaseModel): - message: str - - additional_prompt_content: Optional[str] = None - - can_retry: Optional[bool] = None - - developer_message: Optional[str] = None - - retry_after_ms: Optional[int] = None - - -class Output(BaseModel): - value: object - - error: Optional[OutputError] = None - - class Response(BaseModel): invocation_id: str @@ -38,6 +21,6 @@ class Response(BaseModel): finished_at: Optional[FinishedAt] = None - output: Optional[Output] = None + output: Optional[ResponseOutput] = None success: Optional[bool] = None diff --git a/src/arcadepy/types/response_output.py b/src/arcadepy/types/response_output.py new file mode 100644 index 00000000..087b8087 --- /dev/null +++ b/src/arcadepy/types/response_output.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel +from .shared.authorization_response import AuthorizationResponse + +__all__ = ["ResponseOutput", "Error"] + + +class Error(BaseModel): + message: str + + additional_prompt_content: Optional[str] = None + + can_retry: Optional[bool] = None + + developer_message: Optional[str] = None + + retry_after_ms: Optional[int] = None + + +class ResponseOutput(BaseModel): + error: Optional[Error] = None + + requires_authorization: Optional[AuthorizationResponse] = None + + value: Optional[object] = None diff --git a/src/arcadepy/types/shared/__init__.py b/src/arcadepy/types/shared/__init__.py index 867de170..7737a0b8 100644 --- a/src/arcadepy/types/shared/__init__.py +++ b/src/arcadepy/types/shared/__init__.py @@ -1,3 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from .error import Error as Error +from .tool_definition import ToolDefinition as ToolDefinition +from .authorization_response import AuthorizationResponse as AuthorizationResponse diff --git a/src/arcadepy/types/shared/authorization_response.py b/src/arcadepy/types/shared/authorization_response.py index 6ce92789..6d08e805 100644 --- a/src/arcadepy/types/shared/authorization_response.py +++ b/src/arcadepy/types/shared/authorization_response.py @@ -1,8 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional - -from pydantic import Field as FieldInfo +from typing import Dict, List, Optional from ..._models import BaseModel @@ -12,11 +10,13 @@ class Context(BaseModel): token: Optional[str] = None + user_info: Optional[Dict[str, object]] = None + class AuthorizationResponse(BaseModel): - authorization_id: Optional[str] = FieldInfo(alias="authorizationID", default=None) + authorization_id: Optional[str] = None - authorization_url: Optional[str] = FieldInfo(alias="authorizationURL", default=None) + authorization_url: Optional[str] = None context: Optional[Context] = None diff --git a/src/arcadepy/types/shared/tool_definition.py b/src/arcadepy/types/shared/tool_definition.py new file mode 100644 index 00000000..d1897a3b --- /dev/null +++ b/src/arcadepy/types/shared/tool_definition.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..inputs import Inputs +from ..output import Output +from ..._models import BaseModel +from ..requirements import Requirements +from ..toolkit_definition import ToolkitDefinition + +__all__ = ["ToolDefinition"] + + +class ToolDefinition(BaseModel): + inputs: Inputs + + name: str + + toolkit: ToolkitDefinition + + description: Optional[str] = None + + output: Optional[Output] = None + + requirements: Optional[Requirements] = None diff --git a/src/arcadepy/types/tool_authorize_params.py b/src/arcadepy/types/tool_authorize_params.py index 6675d73c..8454bfa1 100644 --- a/src/arcadepy/types/tool_authorize_params.py +++ b/src/arcadepy/types/tool_authorize_params.py @@ -13,4 +13,4 @@ class ToolAuthorizeParams(TypedDict, total=False): user_id: Required[str] tool_version: str - """Optional: if not provided, latest version is assumed""" + """Optional: if not provided, any version is used""" diff --git a/src/arcadepy/types/tool_execute_params.py b/src/arcadepy/types/tool_execute_params.py index 77826f67..2e8fa5bc 100644 --- a/src/arcadepy/types/tool_execute_params.py +++ b/src/arcadepy/types/tool_execute_params.py @@ -8,11 +8,12 @@ class ToolExecuteParams(TypedDict, total=False): - inputs: Required[str] - """Serialized JSON string""" - tool_name: Required[str] - tool_version: Required[str] + inputs: str + """Serialized JSON string""" + + tool_version: str + """Optional: if not provided, any version is used""" - user_id: Required[str] + user_id: str diff --git a/src/arcadepy/types/tool_list_params.py b/src/arcadepy/types/tool_list_params.py new file mode 100644 index 00000000..a623f325 --- /dev/null +++ b/src/arcadepy/types/tool_list_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ToolListParams"] + + +class ToolListParams(TypedDict, total=False): + toolkit: str + """Toolkit Name""" diff --git a/src/arcadepy/types/tool_list_response.py b/src/arcadepy/types/tool_list_response.py new file mode 100644 index 00000000..9bf3889a --- /dev/null +++ b/src/arcadepy/types/tool_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .shared.tool_definition import ToolDefinition + +__all__ = ["ToolListResponse"] + +ToolListResponse: TypeAlias = List[ToolDefinition] diff --git a/src/arcadepy/types/toolkit_definition.py b/src/arcadepy/types/toolkit_definition.py new file mode 100644 index 00000000..00ab2598 --- /dev/null +++ b/src/arcadepy/types/toolkit_definition.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["ToolkitDefinition"] + + +class ToolkitDefinition(BaseModel): + name: str + + description: Optional[str] = None + + version: Optional[str] = None diff --git a/src/arcadepy/types/tools/__init__.py b/src/arcadepy/types/tools/__init__.py new file mode 100644 index 00000000..774cfc1a --- /dev/null +++ b/src/arcadepy/types/tools/__init__.py @@ -0,0 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .definition_get_params import DefinitionGetParams as DefinitionGetParams diff --git a/src/arcadepy/types/tools/definition_get_params.py b/src/arcadepy/types/tools/definition_get_params.py new file mode 100644 index 00000000..14bf163e --- /dev/null +++ b/src/arcadepy/types/tools/definition_get_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["DefinitionGetParams"] + + +class DefinitionGetParams(TypedDict, total=False): + director_id: Required[Annotated[str, PropertyInfo(alias="directorId")]] + """Director ID""" + + tool_id: Required[Annotated[str, PropertyInfo(alias="toolId")]] + """Tool ID""" diff --git a/src/arcadepy/types/usage.py b/src/arcadepy/types/usage.py new file mode 100644 index 00000000..402d410c --- /dev/null +++ b/src/arcadepy/types/usage.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["Usage"] + + +class Usage(BaseModel): + completion_tokens: Optional[int] = None + + prompt_tokens: Optional[int] = None + + total_tokens: Optional[int] = None diff --git a/src/arcadepy/types/value_schema.py b/src/arcadepy/types/value_schema.py new file mode 100644 index 00000000..76eaa838 --- /dev/null +++ b/src/arcadepy/types/value_schema.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel + +__all__ = ["ValueSchema"] + + +class ValueSchema(BaseModel): + val_type: str + + enum: Optional[List[str]] = None + + inner_val_type: Optional[str] = None diff --git a/tests/api_resources/chat/__init__.py b/tests/api_resources/chat/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/chat/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/chat/test_completions.py b/tests/api_resources/chat/test_completions.py new file mode 100644 index 00000000..1dd2b00d --- /dev/null +++ b/tests/api_resources/chat/test_completions.py @@ -0,0 +1,318 @@ +# 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 ChatResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCompletions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_completions(self, client: Arcade) -> None: + completion = client.chat.completions.completions() + assert_matches_type(ChatResponse, completion, path=["response"]) + + @parametrize + def test_method_completions_with_all_params(self, client: Arcade) -> None: + completion = client.chat.completions.completions( + frequency_penalty=0, + logit_bias={"foo": 0}, + logprobs=True, + max_tokens=0, + messages=[ + { + "content": "content", + "role": "role", + "name": "name", + "tool_call_id": "tool_call_id", + "tool_calls": [ + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + ], + }, + { + "content": "content", + "role": "role", + "name": "name", + "tool_call_id": "tool_call_id", + "tool_calls": [ + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + ], + }, + { + "content": "content", + "role": "role", + "name": "name", + "tool_call_id": "tool_call_id", + "tool_calls": [ + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + ], + }, + ], + model="model", + n=0, + parallel_tool_calls={}, + presence_penalty=0, + response_format="json_object", + seed=0, + stop=["string", "string", "string"], + stream=True, + stream_options={"include_usage": True}, + temperature=0, + tool_choice={}, + tools={}, + top_logprobs=0, + top_p=0, + user="user", + ) + assert_matches_type(ChatResponse, completion, path=["response"]) + + @parametrize + def test_raw_response_completions(self, client: Arcade) -> None: + response = client.chat.completions.with_raw_response.completions() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + completion = response.parse() + assert_matches_type(ChatResponse, completion, path=["response"]) + + @parametrize + def test_streaming_response_completions(self, client: Arcade) -> None: + with client.chat.completions.with_streaming_response.completions() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + completion = response.parse() + assert_matches_type(ChatResponse, completion, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncCompletions: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_completions(self, async_client: AsyncArcade) -> None: + completion = await async_client.chat.completions.completions() + assert_matches_type(ChatResponse, completion, path=["response"]) + + @parametrize + async def test_method_completions_with_all_params(self, async_client: AsyncArcade) -> None: + completion = await async_client.chat.completions.completions( + frequency_penalty=0, + logit_bias={"foo": 0}, + logprobs=True, + max_tokens=0, + messages=[ + { + "content": "content", + "role": "role", + "name": "name", + "tool_call_id": "tool_call_id", + "tool_calls": [ + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + ], + }, + { + "content": "content", + "role": "role", + "name": "name", + "tool_call_id": "tool_call_id", + "tool_calls": [ + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + ], + }, + { + "content": "content", + "role": "role", + "name": "name", + "tool_call_id": "tool_call_id", + "tool_calls": [ + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + { + "id": "id", + "function": { + "arguments": "arguments", + "name": "name", + }, + "type": "function", + }, + ], + }, + ], + model="model", + n=0, + parallel_tool_calls={}, + presence_penalty=0, + response_format="json_object", + seed=0, + stop=["string", "string", "string"], + stream=True, + stream_options={"include_usage": True}, + temperature=0, + tool_choice={}, + tools={}, + top_logprobs=0, + top_p=0, + user="user", + ) + assert_matches_type(ChatResponse, completion, path=["response"]) + + @parametrize + async def test_raw_response_completions(self, async_client: AsyncArcade) -> None: + response = await async_client.chat.completions.with_raw_response.completions() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + completion = await response.parse() + assert_matches_type(ChatResponse, completion, path=["response"]) + + @parametrize + async def test_streaming_response_completions(self, async_client: AsyncArcade) -> None: + async with async_client.chat.completions.with_streaming_response.completions() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + completion = await response.parse() + assert_matches_type(ChatResponse, completion, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_auth.py b/tests/api_resources/test_auth.py index d0816c46..20a4a573 100644 --- a/tests/api_resources/test_auth.py +++ b/tests/api_resources/test_auth.py @@ -9,7 +9,7 @@ from arcadepy import Arcade, AsyncArcade from tests.utils import assert_matches_type -from arcadepy.types import AuthorizationResponse +from arcadepy.types.shared import AuthorizationResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -20,7 +20,7 @@ class TestAuth: @parametrize def test_method_authorize(self, client: Arcade) -> None: auth = client.auth.authorize( - auth_requirement={"provider": "provider"}, + auth_requirement={}, user_id="user_id", ) assert_matches_type(AuthorizationResponse, auth, path=["response"]) @@ -29,11 +29,9 @@ def test_method_authorize(self, client: Arcade) -> None: def test_method_authorize_with_all_params(self, client: Arcade) -> None: auth = client.auth.authorize( auth_requirement={ - "provider": "provider", - "oauth2": { - "authority": "authority", - "scopes": ["string", "string", "string"], - }, + "oauth2": {"scopes": ["string", "string", "string"]}, + "provider_id": "provider_id", + "provider_type": "provider_type", }, user_id="user_id", ) @@ -42,7 +40,7 @@ def test_method_authorize_with_all_params(self, client: Arcade) -> None: @parametrize def test_raw_response_authorize(self, client: Arcade) -> None: response = client.auth.with_raw_response.authorize( - auth_requirement={"provider": "provider"}, + auth_requirement={}, user_id="user_id", ) @@ -54,7 +52,7 @@ def test_raw_response_authorize(self, client: Arcade) -> None: @parametrize def test_streaming_response_authorize(self, client: Arcade) -> None: with client.auth.with_streaming_response.authorize( - auth_requirement={"provider": "provider"}, + auth_requirement={}, user_id="user_id", ) as response: assert not response.is_closed @@ -68,22 +66,23 @@ def test_streaming_response_authorize(self, client: Arcade) -> None: @parametrize def test_method_status(self, client: Arcade) -> None: auth = client.auth.status( - authorization_id="authorizationID", + authorization_id="authorizationId", ) assert_matches_type(AuthorizationResponse, auth, path=["response"]) @parametrize def test_method_status_with_all_params(self, client: Arcade) -> None: auth = client.auth.status( - authorization_id="authorizationID", + authorization_id="authorizationId", scopes="scopes", + wait=0, ) assert_matches_type(AuthorizationResponse, auth, path=["response"]) @parametrize def test_raw_response_status(self, client: Arcade) -> None: response = client.auth.with_raw_response.status( - authorization_id="authorizationID", + authorization_id="authorizationId", ) assert response.is_closed is True @@ -94,7 +93,7 @@ def test_raw_response_status(self, client: Arcade) -> None: @parametrize def test_streaming_response_status(self, client: Arcade) -> None: with client.auth.with_streaming_response.status( - authorization_id="authorizationID", + authorization_id="authorizationId", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -111,7 +110,7 @@ class TestAsyncAuth: @parametrize async def test_method_authorize(self, async_client: AsyncArcade) -> None: auth = await async_client.auth.authorize( - auth_requirement={"provider": "provider"}, + auth_requirement={}, user_id="user_id", ) assert_matches_type(AuthorizationResponse, auth, path=["response"]) @@ -120,11 +119,9 @@ async def test_method_authorize(self, async_client: AsyncArcade) -> None: async def test_method_authorize_with_all_params(self, async_client: AsyncArcade) -> None: auth = await async_client.auth.authorize( auth_requirement={ - "provider": "provider", - "oauth2": { - "authority": "authority", - "scopes": ["string", "string", "string"], - }, + "oauth2": {"scopes": ["string", "string", "string"]}, + "provider_id": "provider_id", + "provider_type": "provider_type", }, user_id="user_id", ) @@ -133,7 +130,7 @@ async def test_method_authorize_with_all_params(self, async_client: AsyncArcade) @parametrize async def test_raw_response_authorize(self, async_client: AsyncArcade) -> None: response = await async_client.auth.with_raw_response.authorize( - auth_requirement={"provider": "provider"}, + auth_requirement={}, user_id="user_id", ) @@ -145,7 +142,7 @@ async def test_raw_response_authorize(self, async_client: AsyncArcade) -> None: @parametrize async def test_streaming_response_authorize(self, async_client: AsyncArcade) -> None: async with async_client.auth.with_streaming_response.authorize( - auth_requirement={"provider": "provider"}, + auth_requirement={}, user_id="user_id", ) as response: assert not response.is_closed @@ -159,22 +156,23 @@ async def test_streaming_response_authorize(self, async_client: AsyncArcade) -> @parametrize async def test_method_status(self, async_client: AsyncArcade) -> None: auth = await async_client.auth.status( - authorization_id="authorizationID", + authorization_id="authorizationId", ) assert_matches_type(AuthorizationResponse, auth, path=["response"]) @parametrize async def test_method_status_with_all_params(self, async_client: AsyncArcade) -> None: auth = await async_client.auth.status( - authorization_id="authorizationID", + authorization_id="authorizationId", scopes="scopes", + wait=0, ) assert_matches_type(AuthorizationResponse, auth, path=["response"]) @parametrize async def test_raw_response_status(self, async_client: AsyncArcade) -> None: response = await async_client.auth.with_raw_response.status( - authorization_id="authorizationID", + authorization_id="authorizationId", ) assert response.is_closed is True @@ -185,7 +183,7 @@ async def test_raw_response_status(self, async_client: AsyncArcade) -> None: @parametrize async def test_streaming_response_status(self, async_client: AsyncArcade) -> None: async with async_client.auth.with_streaming_response.status( - authorization_id="authorizationID", + authorization_id="authorizationId", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_tools.py b/tests/api_resources/test_tools.py index 8fbcf4a6..33f01552 100644 --- a/tests/api_resources/test_tools.py +++ b/tests/api_resources/test_tools.py @@ -9,11 +9,8 @@ from arcadepy import Arcade, AsyncArcade from tests.utils import assert_matches_type -from arcadepy.types import ( - ToolResponse, - ToolDefinition, - AuthorizationResponse, -) +from arcadepy.types import Response, ToolListResponse +from arcadepy.types.shared import AuthorizationResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -21,6 +18,38 @@ class TestTools: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + @parametrize + def test_method_list(self, client: Arcade) -> None: + tool = client.tools.list() + assert_matches_type(ToolListResponse, tool, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: Arcade) -> None: + tool = client.tools.list( + toolkit="toolkit", + ) + assert_matches_type(ToolListResponse, tool, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Arcade) -> None: + response = client.tools.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + tool = response.parse() + assert_matches_type(ToolListResponse, tool, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Arcade) -> None: + with client.tools.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + tool = response.parse() + assert_matches_type(ToolListResponse, tool, path=["response"]) + + assert cast(Any, response.is_closed) is True + @parametrize def test_method_authorize(self, client: Arcade) -> None: tool = client.tools.authorize( @@ -67,81 +96,80 @@ def test_streaming_response_authorize(self, client: Arcade) -> None: @parametrize def test_method_execute(self, client: Arcade) -> None: tool = client.tools.execute( - inputs="inputs", tool_name="tool_name", + ) + assert_matches_type(Response, tool, path=["response"]) + + @parametrize + def test_method_execute_with_all_params(self, client: Arcade) -> None: + tool = client.tools.execute( + tool_name="tool_name", + inputs="inputs", tool_version="tool_version", user_id="user_id", ) - assert_matches_type(ToolResponse, tool, path=["response"]) + assert_matches_type(Response, tool, path=["response"]) @parametrize def test_raw_response_execute(self, client: Arcade) -> None: response = client.tools.with_raw_response.execute( - inputs="inputs", tool_name="tool_name", - tool_version="tool_version", - user_id="user_id", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" tool = response.parse() - assert_matches_type(ToolResponse, tool, path=["response"]) + assert_matches_type(Response, tool, path=["response"]) @parametrize def test_streaming_response_execute(self, client: Arcade) -> None: with client.tools.with_streaming_response.execute( - inputs="inputs", tool_name="tool_name", - tool_version="tool_version", - user_id="user_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" tool = response.parse() - assert_matches_type(ToolResponse, tool, path=["response"]) + assert_matches_type(Response, tool, path=["response"]) assert cast(Any, response.is_closed) is True + +class TestAsyncTools: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + @parametrize - def test_method_retrieve_definition(self, client: Arcade) -> None: - tool = client.tools.retrieve_definition( - director_id="director_id", - tool_id="tool_id", - ) - assert_matches_type(ToolDefinition, tool, path=["response"]) + async def test_method_list(self, async_client: AsyncArcade) -> None: + tool = await async_client.tools.list() + assert_matches_type(ToolListResponse, tool, path=["response"]) @parametrize - def test_raw_response_retrieve_definition(self, client: Arcade) -> None: - response = client.tools.with_raw_response.retrieve_definition( - director_id="director_id", - tool_id="tool_id", + async def test_method_list_with_all_params(self, async_client: AsyncArcade) -> None: + tool = await async_client.tools.list( + toolkit="toolkit", ) + assert_matches_type(ToolListResponse, tool, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncArcade) -> None: + response = await async_client.tools.with_raw_response.list() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" - tool = response.parse() - assert_matches_type(ToolDefinition, tool, path=["response"]) + tool = await response.parse() + assert_matches_type(ToolListResponse, tool, path=["response"]) @parametrize - def test_streaming_response_retrieve_definition(self, client: Arcade) -> None: - with client.tools.with_streaming_response.retrieve_definition( - director_id="director_id", - tool_id="tool_id", - ) as response: + async def test_streaming_response_list(self, async_client: AsyncArcade) -> None: + async with async_client.tools.with_streaming_response.list() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" - tool = response.parse() - assert_matches_type(ToolDefinition, tool, path=["response"]) + tool = await response.parse() + assert_matches_type(ToolListResponse, tool, path=["response"]) assert cast(Any, response.is_closed) is True - -class TestAsyncTools: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) - @parametrize async def test_method_authorize(self, async_client: AsyncArcade) -> None: tool = await async_client.tools.authorize( @@ -188,73 +216,40 @@ async def test_streaming_response_authorize(self, async_client: AsyncArcade) -> @parametrize async def test_method_execute(self, async_client: AsyncArcade) -> None: tool = await async_client.tools.execute( - inputs="inputs", tool_name="tool_name", + ) + assert_matches_type(Response, tool, path=["response"]) + + @parametrize + async def test_method_execute_with_all_params(self, async_client: AsyncArcade) -> None: + tool = await async_client.tools.execute( + tool_name="tool_name", + inputs="inputs", tool_version="tool_version", user_id="user_id", ) - assert_matches_type(ToolResponse, tool, path=["response"]) + assert_matches_type(Response, tool, path=["response"]) @parametrize async def test_raw_response_execute(self, async_client: AsyncArcade) -> None: response = await async_client.tools.with_raw_response.execute( - inputs="inputs", tool_name="tool_name", - tool_version="tool_version", - user_id="user_id", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" tool = await response.parse() - assert_matches_type(ToolResponse, tool, path=["response"]) + assert_matches_type(Response, tool, path=["response"]) @parametrize async def test_streaming_response_execute(self, async_client: AsyncArcade) -> None: async with async_client.tools.with_streaming_response.execute( - inputs="inputs", tool_name="tool_name", - tool_version="tool_version", - user_id="user_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - tool = await response.parse() - assert_matches_type(ToolResponse, tool, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve_definition(self, async_client: AsyncArcade) -> None: - tool = await async_client.tools.retrieve_definition( - director_id="director_id", - tool_id="tool_id", - ) - assert_matches_type(ToolDefinition, tool, path=["response"]) - - @parametrize - async def test_raw_response_retrieve_definition(self, async_client: AsyncArcade) -> None: - response = await async_client.tools.with_raw_response.retrieve_definition( - director_id="director_id", - tool_id="tool_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - tool = await response.parse() - assert_matches_type(ToolDefinition, tool, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve_definition(self, async_client: AsyncArcade) -> None: - async with async_client.tools.with_streaming_response.retrieve_definition( - director_id="director_id", - tool_id="tool_id", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" tool = await response.parse() - assert_matches_type(ToolDefinition, tool, path=["response"]) + assert_matches_type(Response, tool, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/tools/__init__.py b/tests/api_resources/tools/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/tools/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/tools/test_definition.py b/tests/api_resources/tools/test_definition.py new file mode 100644 index 00000000..1e525c30 --- /dev/null +++ b/tests/api_resources/tools/test_definition.py @@ -0,0 +1,90 @@ +# 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.shared import ToolDefinition + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDefinition: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_get(self, client: Arcade) -> None: + definition = client.tools.definition.get( + director_id="directorId", + tool_id="toolId", + ) + assert_matches_type(ToolDefinition, definition, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Arcade) -> None: + response = client.tools.definition.with_raw_response.get( + director_id="directorId", + tool_id="toolId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + definition = response.parse() + assert_matches_type(ToolDefinition, definition, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Arcade) -> None: + with client.tools.definition.with_streaming_response.get( + director_id="directorId", + tool_id="toolId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + definition = response.parse() + assert_matches_type(ToolDefinition, definition, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncDefinition: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_get(self, async_client: AsyncArcade) -> None: + definition = await async_client.tools.definition.get( + director_id="directorId", + tool_id="toolId", + ) + assert_matches_type(ToolDefinition, definition, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncArcade) -> None: + response = await async_client.tools.definition.with_raw_response.get( + director_id="directorId", + tool_id="toolId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + definition = await response.parse() + assert_matches_type(ToolDefinition, definition, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncArcade) -> None: + async with async_client.tools.definition.with_streaming_response.get( + director_id="directorId", + tool_id="toolId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + definition = await response.parse() + assert_matches_type(ToolDefinition, definition, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/test_client.py b/tests/test_client.py index 04929ebb..37b24829 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -800,7 +800,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/v1/chat/completions").mock(side_effect=retry_handler) - response = client.chat.with_raw_response.completions() + response = client.chat.completions.with_raw_response.completions() assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success @@ -824,7 +824,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/v1/chat/completions").mock(side_effect=retry_handler) - response = client.chat.with_raw_response.completions(extra_headers={"x-stainless-retry-count": Omit()}) + response = client.chat.completions.with_raw_response.completions( + extra_headers={"x-stainless-retry-count": Omit()} + ) assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 @@ -847,7 +849,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/v1/chat/completions").mock(side_effect=retry_handler) - response = client.chat.with_raw_response.completions(extra_headers={"x-stainless-retry-count": "42"}) + response = client.chat.completions.with_raw_response.completions( + extra_headers={"x-stainless-retry-count": "42"} + ) assert response.http_request.headers.get("x-stainless-retry-count") == "42" @@ -1621,7 +1625,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/v1/chat/completions").mock(side_effect=retry_handler) - response = await client.chat.with_raw_response.completions() + response = await client.chat.completions.with_raw_response.completions() assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success @@ -1646,7 +1650,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/v1/chat/completions").mock(side_effect=retry_handler) - response = await client.chat.with_raw_response.completions(extra_headers={"x-stainless-retry-count": Omit()}) + response = await client.chat.completions.with_raw_response.completions( + extra_headers={"x-stainless-retry-count": Omit()} + ) assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 @@ -1670,6 +1676,8 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/v1/chat/completions").mock(side_effect=retry_handler) - response = await client.chat.with_raw_response.completions(extra_headers={"x-stainless-retry-count": "42"}) + response = await client.chat.completions.with_raw_response.completions( + extra_headers={"x-stainless-retry-count": "42"} + ) assert response.http_request.headers.get("x-stainless-retry-count") == "42"