From 1150ae23ac16b8753db1b460848b568b6dbb7f98 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 15:14:47 +0000 Subject: [PATCH 1/4] chore(docs): grammar improvements --- SECURITY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index d1d63ece..139038e4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,11 +16,11 @@ before making any information public. ## Reporting Non-SDK Related Security Issues If you encounter security issues that are not directly related to SDKs but pertain to the services -or products provided by Retell please follow the respective company's security reporting guidelines. +or products provided by Retell, please follow the respective company's security reporting guidelines. ### Retell Terms and Policies -Please contact support@retellai.com for any questions or concerns regarding security of our services. +Please contact support@retellai.com for any questions or concerns regarding the security of our services. --- From 23ede995ee4a9bc114ecdea0b6196136de4ee912 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 16:38:00 +0000 Subject: [PATCH 2/4] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 30033785..52229504 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 34 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/retell%2Ftoddlzt-633b45cdafc58dc79176efac962c92d1ccd20ce82aebf4bb2ceae65954fbc9da.yml -openapi_spec_hash: ac81b4183a73b711bb9e646027f2998c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/retell%2Ftoddlzt-33c92a2f7908f82088c3cad1076ac008f22cc41d25cbdbcd23b005bfd5e5ab3d.yml +openapi_spec_hash: 3df26020335431e67fdaa9c3865a6a81 config_hash: 9d9a24bf8bb4553cbb30ce59eb910b2f From 23a1a741da36c5507778680f56589600434e6f2b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 16:57:42 +0000 Subject: [PATCH 3/4] feat(api): api update --- .stats.yml | 4 +- api.md | 16 + src/retell/_client.py | 10 +- src/retell/resources/__init__.py | 14 + src/retell/resources/chat.py | 519 ++++++++++++++++++ src/retell/types/__init__.py | 5 + .../chat_create_chat_completion_params.py | 15 + .../chat_create_chat_completion_response.py | 121 ++++ src/retell/types/chat_create_params.py | 31 ++ src/retell/types/chat_list_response.py | 10 + src/retell/types/chat_response.py | 221 ++++++++ tests/api_resources/test_chat.py | 378 +++++++++++++ 12 files changed, 1341 insertions(+), 3 deletions(-) create mode 100644 src/retell/resources/chat.py create mode 100644 src/retell/types/chat_create_chat_completion_params.py create mode 100644 src/retell/types/chat_create_chat_completion_response.py create mode 100644 src/retell/types/chat_create_params.py create mode 100644 src/retell/types/chat_list_response.py create mode 100644 src/retell/types/chat_response.py create mode 100644 tests/api_resources/test_chat.py diff --git a/.stats.yml b/.stats.yml index 52229504..5d83c560 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 34 +configured_endpoints: 39 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/retell%2Ftoddlzt-33c92a2f7908f82088c3cad1076ac008f22cc41d25cbdbcd23b005bfd5e5ab3d.yml openapi_spec_hash: 3df26020335431e67fdaa9c3865a6a81 -config_hash: 9d9a24bf8bb4553cbb30ce59eb910b2f +config_hash: f4bc63f2350a2a4988750b41a0737f9d diff --git a/api.md b/api.md index 6ca6e62b..10223ae6 100644 --- a/api.md +++ b/api.md @@ -16,6 +16,22 @@ Methods: - client.call.create_web_call(\*\*params) -> WebCallResponse - client.call.register_phone_call(\*\*params) -> PhoneCallResponse +# Chat + +Types: + +```python +from retell.types import ChatResponse, ChatListResponse, ChatCreateChatCompletionResponse +``` + +Methods: + +- client.chat.create(\*\*params) -> ChatResponse +- client.chat.retrieve(chat_id) -> ChatResponse +- client.chat.list() -> ChatListResponse +- client.chat.create_chat_completion(\*\*params) -> ChatCreateChatCompletionResponse +- client.chat.end(chat_id) -> None + # PhoneNumber Types: diff --git a/src/retell/_client.py b/src/retell/_client.py index c9519b1d..909697b9 100644 --- a/src/retell/_client.py +++ b/src/retell/_client.py @@ -21,7 +21,7 @@ ) from ._utils import is_given, get_async_library from ._version import __version__ -from .resources import llm, call, agent, voice, batch_call, concurrency, phone_number, knowledge_base +from .resources import llm, call, chat, agent, voice, batch_call, concurrency, phone_number, knowledge_base from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import APIStatusError from ._base_client import ( @@ -36,6 +36,7 @@ class Retell(SyncAPIClient): call: call.CallResource + chat: chat.ChatResource phone_number: phone_number.PhoneNumberResource agent: agent.AgentResource llm: llm.LlmResource @@ -92,6 +93,7 @@ def __init__( ) self.call = call.CallResource(self) + self.chat = chat.ChatResource(self) self.phone_number = phone_number.PhoneNumberResource(self) self.agent = agent.AgentResource(self) self.llm = llm.LlmResource(self) @@ -211,6 +213,7 @@ def _make_status_error( class AsyncRetell(AsyncAPIClient): call: call.AsyncCallResource + chat: chat.AsyncChatResource phone_number: phone_number.AsyncPhoneNumberResource agent: agent.AsyncAgentResource llm: llm.AsyncLlmResource @@ -267,6 +270,7 @@ def __init__( ) self.call = call.AsyncCallResource(self) + self.chat = chat.AsyncChatResource(self) self.phone_number = phone_number.AsyncPhoneNumberResource(self) self.agent = agent.AsyncAgentResource(self) self.llm = llm.AsyncLlmResource(self) @@ -385,6 +389,7 @@ def _make_status_error( class RetellWithRawResponse: def __init__(self, client: Retell) -> None: self.call = call.CallResourceWithRawResponse(client.call) + self.chat = chat.ChatResourceWithRawResponse(client.chat) self.phone_number = phone_number.PhoneNumberResourceWithRawResponse(client.phone_number) self.agent = agent.AgentResourceWithRawResponse(client.agent) self.llm = llm.LlmResourceWithRawResponse(client.llm) @@ -397,6 +402,7 @@ def __init__(self, client: Retell) -> None: class AsyncRetellWithRawResponse: def __init__(self, client: AsyncRetell) -> None: self.call = call.AsyncCallResourceWithRawResponse(client.call) + self.chat = chat.AsyncChatResourceWithRawResponse(client.chat) self.phone_number = phone_number.AsyncPhoneNumberResourceWithRawResponse(client.phone_number) self.agent = agent.AsyncAgentResourceWithRawResponse(client.agent) self.llm = llm.AsyncLlmResourceWithRawResponse(client.llm) @@ -409,6 +415,7 @@ def __init__(self, client: AsyncRetell) -> None: class RetellWithStreamedResponse: def __init__(self, client: Retell) -> None: self.call = call.CallResourceWithStreamingResponse(client.call) + self.chat = chat.ChatResourceWithStreamingResponse(client.chat) self.phone_number = phone_number.PhoneNumberResourceWithStreamingResponse(client.phone_number) self.agent = agent.AgentResourceWithStreamingResponse(client.agent) self.llm = llm.LlmResourceWithStreamingResponse(client.llm) @@ -421,6 +428,7 @@ def __init__(self, client: Retell) -> None: class AsyncRetellWithStreamedResponse: def __init__(self, client: AsyncRetell) -> None: self.call = call.AsyncCallResourceWithStreamingResponse(client.call) + self.chat = chat.AsyncChatResourceWithStreamingResponse(client.chat) self.phone_number = phone_number.AsyncPhoneNumberResourceWithStreamingResponse(client.phone_number) self.agent = agent.AsyncAgentResourceWithStreamingResponse(client.agent) self.llm = llm.AsyncLlmResourceWithStreamingResponse(client.llm) diff --git a/src/retell/resources/__init__.py b/src/retell/resources/__init__.py index cdf93c2a..4853c11f 100644 --- a/src/retell/resources/__init__.py +++ b/src/retell/resources/__init__.py @@ -16,6 +16,14 @@ CallResourceWithStreamingResponse, AsyncCallResourceWithStreamingResponse, ) +from .chat import ( + ChatResource, + AsyncChatResource, + ChatResourceWithRawResponse, + AsyncChatResourceWithRawResponse, + ChatResourceWithStreamingResponse, + AsyncChatResourceWithStreamingResponse, +) from .agent import ( AgentResource, AsyncAgentResource, @@ -72,6 +80,12 @@ "AsyncCallResourceWithRawResponse", "CallResourceWithStreamingResponse", "AsyncCallResourceWithStreamingResponse", + "ChatResource", + "AsyncChatResource", + "ChatResourceWithRawResponse", + "AsyncChatResourceWithRawResponse", + "ChatResourceWithStreamingResponse", + "AsyncChatResourceWithStreamingResponse", "PhoneNumberResource", "AsyncPhoneNumberResource", "PhoneNumberResourceWithRawResponse", diff --git a/src/retell/resources/chat.py b/src/retell/resources/chat.py new file mode 100644 index 00000000..0589378a --- /dev/null +++ b/src/retell/resources/chat.py @@ -0,0 +1,519 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict + +import httpx + +from ..types import chat_create_params, chat_create_chat_completion_params +from .._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.chat_response import ChatResponse +from ..types.chat_list_response import ChatListResponse +from ..types.chat_create_chat_completion_response import ChatCreateChatCompletionResponse + +__all__ = ["ChatResource", "AsyncChatResource"] + + +class ChatResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ChatResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/RetellAI/retell-python-sdk#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/RetellAI/retell-python-sdk#with_streaming_response + """ + return ChatResourceWithStreamingResponse(self) + + def create( + self, + *, + agent_id: str, + agent_version: int | NotGiven = NOT_GIVEN, + metadata: object | NotGiven = NOT_GIVEN, + retell_llm_dynamic_variables: Dict[str, object] | 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, + ) -> ChatResponse: + """ + Create a chat session + + Args: + agent_id: The chat agent to use for the call. + + agent_version: The version of the chat agent to use for the call. + + metadata: An arbitrary object for storage purpose only. You can put anything here like + your internal customer id associated with the chat. Not used for processing. You + can later get this field from the chat object. + + retell_llm_dynamic_variables: Add optional dynamic variables in key value pairs of string that injects into + your Response Engine prompt and tool description. Only applicable for Response + Engine. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/create-chat", + body=maybe_transform( + { + "agent_id": agent_id, + "agent_version": agent_version, + "metadata": metadata, + "retell_llm_dynamic_variables": retell_llm_dynamic_variables, + }, + chat_create_params.ChatCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatResponse, + ) + + def retrieve( + self, + chat_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, + ) -> ChatResponse: + """ + Retrieve details of a specific chat + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + return self._get( + f"/get-chat/{chat_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatResponse, + ) + + def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ChatListResponse: + """List all chats""" + return self._get( + "/list-chat", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatListResponse, + ) + + def create_chat_completion( + self, + *, + chat_id: str, + content: 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, + ) -> ChatCreateChatCompletionResponse: + """ + Create a chat completion message + + Args: + chat_id: Unique id of the chat to create completion. + + content: user message to generate agent chat completion. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/create-chat-completion", + body=maybe_transform( + { + "chat_id": chat_id, + "content": content, + }, + chat_create_chat_completion_params.ChatCreateChatCompletionParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatCreateChatCompletionResponse, + ) + + def end( + self, + chat_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, + ) -> None: + """ + End an ongoing chat + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._patch( + f"/end-chat/{chat_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncChatResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncChatResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/RetellAI/retell-python-sdk#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/RetellAI/retell-python-sdk#with_streaming_response + """ + return AsyncChatResourceWithStreamingResponse(self) + + async def create( + self, + *, + agent_id: str, + agent_version: int | NotGiven = NOT_GIVEN, + metadata: object | NotGiven = NOT_GIVEN, + retell_llm_dynamic_variables: Dict[str, object] | 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, + ) -> ChatResponse: + """ + Create a chat session + + Args: + agent_id: The chat agent to use for the call. + + agent_version: The version of the chat agent to use for the call. + + metadata: An arbitrary object for storage purpose only. You can put anything here like + your internal customer id associated with the chat. Not used for processing. You + can later get this field from the chat object. + + retell_llm_dynamic_variables: Add optional dynamic variables in key value pairs of string that injects into + your Response Engine prompt and tool description. Only applicable for Response + Engine. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/create-chat", + body=await async_maybe_transform( + { + "agent_id": agent_id, + "agent_version": agent_version, + "metadata": metadata, + "retell_llm_dynamic_variables": retell_llm_dynamic_variables, + }, + chat_create_params.ChatCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatResponse, + ) + + async def retrieve( + self, + chat_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, + ) -> ChatResponse: + """ + Retrieve details of a specific chat + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + return await self._get( + f"/get-chat/{chat_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatResponse, + ) + + async def list( + self, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> ChatListResponse: + """List all chats""" + return await self._get( + "/list-chat", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatListResponse, + ) + + async def create_chat_completion( + self, + *, + chat_id: str, + content: 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, + ) -> ChatCreateChatCompletionResponse: + """ + Create a chat completion message + + Args: + chat_id: Unique id of the chat to create completion. + + content: user message to generate agent chat completion. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/create-chat-completion", + body=await async_maybe_transform( + { + "chat_id": chat_id, + "content": content, + }, + chat_create_chat_completion_params.ChatCreateChatCompletionParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ChatCreateChatCompletionResponse, + ) + + async def end( + self, + chat_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, + ) -> None: + """ + End an ongoing chat + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not chat_id: + raise ValueError(f"Expected a non-empty value for `chat_id` but received {chat_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._patch( + f"/end-chat/{chat_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class ChatResourceWithRawResponse: + def __init__(self, chat: ChatResource) -> None: + self._chat = chat + + self.create = to_raw_response_wrapper( + chat.create, + ) + self.retrieve = to_raw_response_wrapper( + chat.retrieve, + ) + self.list = to_raw_response_wrapper( + chat.list, + ) + self.create_chat_completion = to_raw_response_wrapper( + chat.create_chat_completion, + ) + self.end = to_raw_response_wrapper( + chat.end, + ) + + +class AsyncChatResourceWithRawResponse: + def __init__(self, chat: AsyncChatResource) -> None: + self._chat = chat + + self.create = async_to_raw_response_wrapper( + chat.create, + ) + self.retrieve = async_to_raw_response_wrapper( + chat.retrieve, + ) + self.list = async_to_raw_response_wrapper( + chat.list, + ) + self.create_chat_completion = async_to_raw_response_wrapper( + chat.create_chat_completion, + ) + self.end = async_to_raw_response_wrapper( + chat.end, + ) + + +class ChatResourceWithStreamingResponse: + def __init__(self, chat: ChatResource) -> None: + self._chat = chat + + self.create = to_streamed_response_wrapper( + chat.create, + ) + self.retrieve = to_streamed_response_wrapper( + chat.retrieve, + ) + self.list = to_streamed_response_wrapper( + chat.list, + ) + self.create_chat_completion = to_streamed_response_wrapper( + chat.create_chat_completion, + ) + self.end = to_streamed_response_wrapper( + chat.end, + ) + + +class AsyncChatResourceWithStreamingResponse: + def __init__(self, chat: AsyncChatResource) -> None: + self._chat = chat + + self.create = async_to_streamed_response_wrapper( + chat.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + chat.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + chat.list, + ) + self.create_chat_completion = async_to_streamed_response_wrapper( + chat.create_chat_completion, + ) + self.end = async_to_streamed_response_wrapper( + chat.end, + ) diff --git a/src/retell/types/__init__.py b/src/retell/types/__init__.py index 2bf8324c..37049118 100644 --- a/src/retell/types/__init__.py +++ b/src/retell/types/__init__.py @@ -4,6 +4,7 @@ from .llm_response import LlmResponse as LlmResponse from .call_response import CallResponse as CallResponse +from .chat_response import ChatResponse as ChatResponse from .agent_response import AgentResponse as AgentResponse from .voice_response import VoiceResponse as VoiceResponse from .call_list_params import CallListParams as CallListParams @@ -13,6 +14,8 @@ from .web_call_response import WebCallResponse as WebCallResponse from .call_list_response import CallListResponse as CallListResponse from .call_update_params import CallUpdateParams as CallUpdateParams +from .chat_create_params import ChatCreateParams as ChatCreateParams +from .chat_list_response import ChatListResponse as ChatListResponse from .agent_create_params import AgentCreateParams as AgentCreateParams from .agent_list_response import AgentListResponse as AgentListResponse from .agent_update_params import AgentUpdateParams as AgentUpdateParams @@ -35,4 +38,6 @@ from .concurrency_retrieve_response import ConcurrencyRetrieveResponse as ConcurrencyRetrieveResponse from .call_register_phone_call_params import CallRegisterPhoneCallParams as CallRegisterPhoneCallParams from .knowledge_base_add_sources_params import KnowledgeBaseAddSourcesParams as KnowledgeBaseAddSourcesParams +from .chat_create_chat_completion_params import ChatCreateChatCompletionParams as ChatCreateChatCompletionParams from .batch_call_create_batch_call_params import BatchCallCreateBatchCallParams as BatchCallCreateBatchCallParams +from .chat_create_chat_completion_response import ChatCreateChatCompletionResponse as ChatCreateChatCompletionResponse diff --git a/src/retell/types/chat_create_chat_completion_params.py b/src/retell/types/chat_create_chat_completion_params.py new file mode 100644 index 00000000..eadfb846 --- /dev/null +++ b/src/retell/types/chat_create_chat_completion_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ChatCreateChatCompletionParams"] + + +class ChatCreateChatCompletionParams(TypedDict, total=False): + chat_id: Required[str] + """Unique id of the chat to create completion.""" + + content: Required[str] + """user message to generate agent chat completion.""" diff --git a/src/retell/types/chat_create_chat_completion_response.py b/src/retell/types/chat_create_chat_completion_response.py new file mode 100644 index 00000000..161c43d3 --- /dev/null +++ b/src/retell/types/chat_create_chat_completion_response.py @@ -0,0 +1,121 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from .._models import BaseModel + +__all__ = [ + "ChatCreateChatCompletionResponse", + "Message", + "MessageMessage", + "MessageToolCallInvocationMessage", + "MessageToolCallResultMessage", + "MessageNodeTransitionMessage", + "MessageStateTransitionMessage", +] + + +class MessageMessage(BaseModel): + content: str + """Content of the message""" + + created_timestamp: int + """Create timestamp of the message""" + + message_id: str + """Unique id ot the message""" + + role: Literal["agent", "user"] + """Documents whether this message is sent by agent or user.""" + + +class MessageToolCallInvocationMessage(BaseModel): + arguments: str + """Arguments for this tool call, it's a stringified JSON object.""" + + message_id: str + """Unique id ot the message""" + + name: str + """Name of the function in this tool call.""" + + role: Literal["tool_call_invocation"] + """This is a tool call invocation.""" + + tool_call_id: str + """Tool call id, globally unique.""" + + created_timestamp: Optional[int] = None + """Create timestamp of the message""" + + +class MessageToolCallResultMessage(BaseModel): + content: str + """Result of the tool call, can be a string, a stringified json, etc.""" + + created_timestamp: int + """Create timestamp of the message""" + + message_id: str + """Unique id ot the message""" + + role: Literal["tool_call_result"] + """This is result of a tool call.""" + + tool_call_id: str + """Tool call id, globally unique.""" + + +class MessageNodeTransitionMessage(BaseModel): + created_timestamp: int + """Create timestamp of the message""" + + message_id: str + """Unique id ot the message""" + + role: Literal["node_transition"] + """This is node transition.""" + + former_node_id: Optional[str] = None + """Former node id""" + + former_node_name: Optional[str] = None + """Former node name""" + + new_node_id: Optional[str] = None + """New node id""" + + new_node_name: Optional[str] = None + """New node name""" + + +class MessageStateTransitionMessage(BaseModel): + created_timestamp: int + """Create timestamp of the message""" + + message_id: str + """Unique id ot the message""" + + role: Literal["state_transition"] + """This is state transition for .""" + + former_state_name: Optional[str] = None + """Former state name""" + + new_state_name: Optional[str] = None + """New state name""" + + +Message: TypeAlias = Union[ + MessageMessage, + MessageToolCallInvocationMessage, + MessageToolCallResultMessage, + MessageNodeTransitionMessage, + MessageStateTransitionMessage, +] + + +class ChatCreateChatCompletionResponse(BaseModel): + messages: List[Message] + """Transcript of the chat completion weaved with tool call invocation and results.""" diff --git a/src/retell/types/chat_create_params.py b/src/retell/types/chat_create_params.py new file mode 100644 index 00000000..61a59ae9 --- /dev/null +++ b/src/retell/types/chat_create_params.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict +from typing_extensions import Required, TypedDict + +__all__ = ["ChatCreateParams"] + + +class ChatCreateParams(TypedDict, total=False): + agent_id: Required[str] + """The chat agent to use for the call.""" + + agent_version: int + """The version of the chat agent to use for the call.""" + + metadata: object + """An arbitrary object for storage purpose only. + + You can put anything here like your internal customer id associated with the + chat. Not used for processing. You can later get this field from the chat + object. + """ + + retell_llm_dynamic_variables: Dict[str, object] + """ + Add optional dynamic variables in key value pairs of string that injects into + your Response Engine prompt and tool description. Only applicable for Response + Engine. + """ diff --git a/src/retell/types/chat_list_response.py b/src/retell/types/chat_list_response.py new file mode 100644 index 00000000..2135f413 --- /dev/null +++ b/src/retell/types/chat_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 .chat_response import ChatResponse + +__all__ = ["ChatListResponse"] + +ChatListResponse: TypeAlias = List[ChatResponse] diff --git a/src/retell/types/chat_response.py b/src/retell/types/chat_response.py new file mode 100644 index 00000000..53eaa8c2 --- /dev/null +++ b/src/retell/types/chat_response.py @@ -0,0 +1,221 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = [ + "ChatResponse", + "ChatAnalysis", + "ChatCost", + "ChatCostProductCost", + "MessageWithToolCall", + "MessageWithToolCallMessage", + "MessageWithToolCallToolCallInvocationMessage", + "MessageWithToolCallToolCallResultMessage", + "MessageWithToolCallNodeTransitionMessage", + "MessageWithToolCallStateTransitionMessage", +] + + +class ChatAnalysis(BaseModel): + chat_successful: Optional[bool] = None + """ + Whether the agent seems to have a successful chat with the user, where the agent + finishes the task, and the call was complete without being cutoff. + """ + + chat_summary: Optional[str] = None + """A high level summary of the chat.""" + + custom_analysis_data: Optional[object] = None + """ + Custom analysis data that was extracted based on the schema defined in chat + agent post chat analysis data. Can be empty if nothing is specified. + """ + + user_sentiment: Optional[Literal["Negative", "Positive", "Neutral", "Unknown"]] = None + """Sentiment of the user in the chat.""" + + +class ChatCostProductCost(BaseModel): + cost: float + """Cost for the product in cents for the duration of the call.""" + + product: str + """Product name that has a cost associated with it.""" + + unit_price: float = FieldInfo(alias="unitPrice") + """Unit price of the product in cents per second.""" + + +class ChatCost(BaseModel): + combined_cost: Optional[float] = None + """Combined cost of all individual costs in cents""" + + product_costs: Optional[List[ChatCostProductCost]] = None + """List of products with their unit prices and costs in cents""" + + +class MessageWithToolCallMessage(BaseModel): + content: str + """Content of the message""" + + created_timestamp: int + """Create timestamp of the message""" + + message_id: str + """Unique id ot the message""" + + role: Literal["agent", "user"] + """Documents whether this message is sent by agent or user.""" + + +class MessageWithToolCallToolCallInvocationMessage(BaseModel): + arguments: str + """Arguments for this tool call, it's a stringified JSON object.""" + + message_id: str + """Unique id ot the message""" + + name: str + """Name of the function in this tool call.""" + + role: Literal["tool_call_invocation"] + """This is a tool call invocation.""" + + tool_call_id: str + """Tool call id, globally unique.""" + + created_timestamp: Optional[int] = None + """Create timestamp of the message""" + + +class MessageWithToolCallToolCallResultMessage(BaseModel): + content: str + """Result of the tool call, can be a string, a stringified json, etc.""" + + created_timestamp: int + """Create timestamp of the message""" + + message_id: str + """Unique id ot the message""" + + role: Literal["tool_call_result"] + """This is result of a tool call.""" + + tool_call_id: str + """Tool call id, globally unique.""" + + +class MessageWithToolCallNodeTransitionMessage(BaseModel): + created_timestamp: int + """Create timestamp of the message""" + + message_id: str + """Unique id ot the message""" + + role: Literal["node_transition"] + """This is node transition.""" + + former_node_id: Optional[str] = None + """Former node id""" + + former_node_name: Optional[str] = None + """Former node name""" + + new_node_id: Optional[str] = None + """New node id""" + + new_node_name: Optional[str] = None + """New node name""" + + +class MessageWithToolCallStateTransitionMessage(BaseModel): + created_timestamp: int + """Create timestamp of the message""" + + message_id: str + """Unique id ot the message""" + + role: Literal["state_transition"] + """This is state transition for .""" + + former_state_name: Optional[str] = None + """Former state name""" + + new_state_name: Optional[str] = None + """New state name""" + + +MessageWithToolCall: TypeAlias = Union[ + MessageWithToolCallMessage, + MessageWithToolCallToolCallInvocationMessage, + MessageWithToolCallToolCallResultMessage, + MessageWithToolCallNodeTransitionMessage, + MessageWithToolCallStateTransitionMessage, +] + + +class ChatResponse(BaseModel): + agent_id: str + """Corresponding chat agent id of this chat.""" + + chat_id: str + """Unique id of the chat.""" + + chat_status: Literal["ongoing", "ended", "error"] + """Status of chat. + + - `ongoing`: Chat session is ongoing, chat agent can receive new message and + generate response. + + - `ended`: Chat session has ended can not generate new response. + + - `error`: Chat encountered error. + """ + + chat_analysis: Optional[ChatAnalysis] = None + """ + Post chat analysis that includes information such as sentiment, status, summary, + and custom defined data to extract. Available after chat ends. Subscribe to + `chat_analyzed` webhook event type to receive it once ready. + """ + + chat_cost: Optional[ChatCost] = None + + end_timestamp: Optional[int] = None + """End timestamp (milliseconds since epoch) of the chat. + + Available after chat ends. + """ + + message_with_tool_calls: Optional[List[MessageWithToolCall]] = None + """Transcript of the chat weaved with tool call invocation and results.""" + + metadata: Optional[object] = None + """An arbitrary object for storage purpose only. + + You can put anything here like your internal customer id associated with the + chat. Not used for processing. You can later get this field from the chat + object. + """ + + retell_llm_dynamic_variables: Optional[Dict[str, object]] = None + """ + Add optional dynamic variables in key value pairs of string that injects into + your Response Engine prompt and tool description. Only applicable for Response + Engine. + """ + + start_timestamp: Optional[int] = None + """Begin timestamp (milliseconds since epoch) of the chat. + + Available after chat starts. + """ + + transcript: Optional[str] = None + """Transcription of the chat.""" diff --git a/tests/api_resources/test_chat.py b/tests/api_resources/test_chat.py new file mode 100644 index 00000000..67c52f1e --- /dev/null +++ b/tests/api_resources/test_chat.py @@ -0,0 +1,378 @@ +# 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 retell import Retell, AsyncRetell +from tests.utils import assert_matches_type +from retell.types import ( + ChatResponse, + ChatListResponse, + ChatCreateChatCompletionResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestChat: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Retell) -> None: + chat = client.chat.create( + agent_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + ) + assert_matches_type(ChatResponse, chat, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Retell) -> None: + chat = client.chat.create( + agent_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + agent_version=1, + metadata={}, + retell_llm_dynamic_variables={"customer_name": "bar"}, + ) + assert_matches_type(ChatResponse, chat, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Retell) -> None: + response = client.chat.with_raw_response.create( + agent_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = response.parse() + assert_matches_type(ChatResponse, chat, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Retell) -> None: + with client.chat.with_streaming_response.create( + agent_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = response.parse() + assert_matches_type(ChatResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_retrieve(self, client: Retell) -> None: + chat = client.chat.retrieve( + "16b980523634a6dc504898cda492e939", + ) + assert_matches_type(ChatResponse, chat, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: Retell) -> None: + response = client.chat.with_raw_response.retrieve( + "16b980523634a6dc504898cda492e939", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = response.parse() + assert_matches_type(ChatResponse, chat, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: Retell) -> None: + with client.chat.with_streaming_response.retrieve( + "16b980523634a6dc504898cda492e939", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = response.parse() + assert_matches_type(ChatResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_retrieve(self, client: Retell) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + client.chat.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_list(self, client: Retell) -> None: + chat = client.chat.list() + assert_matches_type(ChatListResponse, chat, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: Retell) -> None: + response = client.chat.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = response.parse() + assert_matches_type(ChatListResponse, chat, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: Retell) -> None: + with client.chat.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = response.parse() + assert_matches_type(ChatListResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_create_chat_completion(self, client: Retell) -> None: + chat = client.chat.create_chat_completion( + chat_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + content="hi how are you doing?", + ) + assert_matches_type(ChatCreateChatCompletionResponse, chat, path=["response"]) + + @parametrize + def test_raw_response_create_chat_completion(self, client: Retell) -> None: + response = client.chat.with_raw_response.create_chat_completion( + chat_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + content="hi how are you doing?", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = response.parse() + assert_matches_type(ChatCreateChatCompletionResponse, chat, path=["response"]) + + @parametrize + def test_streaming_response_create_chat_completion(self, client: Retell) -> None: + with client.chat.with_streaming_response.create_chat_completion( + chat_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + content="hi how are you doing?", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = response.parse() + assert_matches_type(ChatCreateChatCompletionResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_end(self, client: Retell) -> None: + chat = client.chat.end( + "16b980523634a6dc504898cda492e939", + ) + assert chat is None + + @parametrize + def test_raw_response_end(self, client: Retell) -> None: + response = client.chat.with_raw_response.end( + "16b980523634a6dc504898cda492e939", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = response.parse() + assert chat is None + + @parametrize + def test_streaming_response_end(self, client: Retell) -> None: + with client.chat.with_streaming_response.end( + "16b980523634a6dc504898cda492e939", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = response.parse() + assert chat is None + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_end(self, client: Retell) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + client.chat.with_raw_response.end( + "", + ) + + +class TestAsyncChat: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncRetell) -> None: + chat = await async_client.chat.create( + agent_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + ) + assert_matches_type(ChatResponse, chat, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncRetell) -> None: + chat = await async_client.chat.create( + agent_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + agent_version=1, + metadata={}, + retell_llm_dynamic_variables={"customer_name": "bar"}, + ) + assert_matches_type(ChatResponse, chat, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncRetell) -> None: + response = await async_client.chat.with_raw_response.create( + agent_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = await response.parse() + assert_matches_type(ChatResponse, chat, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncRetell) -> None: + async with async_client.chat.with_streaming_response.create( + agent_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = await response.parse() + assert_matches_type(ChatResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_retrieve(self, async_client: AsyncRetell) -> None: + chat = await async_client.chat.retrieve( + "16b980523634a6dc504898cda492e939", + ) + assert_matches_type(ChatResponse, chat, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncRetell) -> None: + response = await async_client.chat.with_raw_response.retrieve( + "16b980523634a6dc504898cda492e939", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = await response.parse() + assert_matches_type(ChatResponse, chat, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncRetell) -> None: + async with async_client.chat.with_streaming_response.retrieve( + "16b980523634a6dc504898cda492e939", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = await response.parse() + assert_matches_type(ChatResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncRetell) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + await async_client.chat.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncRetell) -> None: + chat = await async_client.chat.list() + assert_matches_type(ChatListResponse, chat, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncRetell) -> None: + response = await async_client.chat.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = await response.parse() + assert_matches_type(ChatListResponse, chat, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncRetell) -> None: + async with async_client.chat.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = await response.parse() + assert_matches_type(ChatListResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_create_chat_completion(self, async_client: AsyncRetell) -> None: + chat = await async_client.chat.create_chat_completion( + chat_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + content="hi how are you doing?", + ) + assert_matches_type(ChatCreateChatCompletionResponse, chat, path=["response"]) + + @parametrize + async def test_raw_response_create_chat_completion(self, async_client: AsyncRetell) -> None: + response = await async_client.chat.with_raw_response.create_chat_completion( + chat_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + content="hi how are you doing?", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = await response.parse() + assert_matches_type(ChatCreateChatCompletionResponse, chat, path=["response"]) + + @parametrize + async def test_streaming_response_create_chat_completion(self, async_client: AsyncRetell) -> None: + async with async_client.chat.with_streaming_response.create_chat_completion( + chat_id="oBeDLoLOeuAbiuaMFXRtDOLriTJ5tSxD", + content="hi how are you doing?", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = await response.parse() + assert_matches_type(ChatCreateChatCompletionResponse, chat, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_end(self, async_client: AsyncRetell) -> None: + chat = await async_client.chat.end( + "16b980523634a6dc504898cda492e939", + ) + assert chat is None + + @parametrize + async def test_raw_response_end(self, async_client: AsyncRetell) -> None: + response = await async_client.chat.with_raw_response.end( + "16b980523634a6dc504898cda492e939", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + chat = await response.parse() + assert chat is None + + @parametrize + async def test_streaming_response_end(self, async_client: AsyncRetell) -> None: + async with async_client.chat.with_streaming_response.end( + "16b980523634a6dc504898cda492e939", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + chat = await response.parse() + assert chat is None + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_end(self, async_client: AsyncRetell) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `chat_id` but received ''"): + await async_client.chat.with_raw_response.end( + "", + ) From e2cbf2e4ed9393c4bf7977d14b2dcf817dda2a60 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 16:58:16 +0000 Subject: [PATCH 4/4] release: 4.31.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/retell/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ba2c94bf..a95c8527 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.30.0" + ".": "4.31.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4656c76f..8e7d4995 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 4.31.0 (2025-05-22) + +Full Changelog: [v4.30.0...v4.31.0](https://github.com/RetellAI/retell-python-sdk/compare/v4.30.0...v4.31.0) + +### Features + +* **api:** api update ([23a1a74](https://github.com/RetellAI/retell-python-sdk/commit/23a1a741da36c5507778680f56589600434e6f2b)) + + +### Chores + +* **docs:** grammar improvements ([1150ae2](https://github.com/RetellAI/retell-python-sdk/commit/1150ae23ac16b8753db1b460848b568b6dbb7f98)) + ## 4.30.0 (2025-05-15) Full Changelog: [v4.29.0...v4.30.0](https://github.com/RetellAI/retell-python-sdk/compare/v4.29.0...v4.30.0) diff --git a/pyproject.toml b/pyproject.toml index 759cd47b..f0a64608 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "retell-sdk" -version = "4.30.0" +version = "4.31.0" description = "The official Python library for the retell API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/retell/_version.py b/src/retell/_version.py index f8b21fac..8be660c9 100644 --- a/src/retell/_version.py +++ b/src/retell/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "retell" -__version__ = "4.30.0" # x-release-please-version +__version__ = "4.31.0" # x-release-please-version