From 2687e6d7d55dbe7585a7276d1512ae80d6de4350 Mon Sep 17 00:00:00 2001 From: stlc-bot Date: Mon, 26 Oct 2026 14:30:02 +0000 Subject: [PATCH] Build SDK Stainless-Generated-From: 19bb7c295e6e0080c56005a6555134d2dddccd87 --- api.md | 2 +- .../resources/assistant/conversations.py | 30 ++++-- .../assistant/conversation_history_params.py | 7 +- .../conversation_history_response.py | 96 +++++++++++++++---- .../assistant/test_conversations.py | 34 +++++-- 5 files changed, 127 insertions(+), 42 deletions(-) diff --git a/api.md b/api.md index 091dc53e..cae99f8d 100644 --- a/api.md +++ b/api.md @@ -938,7 +938,7 @@ Methods: - client.assistant.conversations.abort(\*\*params) -> ConversationAbortResponse - client.assistant.conversations.answer_permission(\*\*params) -> ConversationAnswerPermissionResponse - client.assistant.conversations.answer_question(\*\*params) -> ConversationAnswerQuestionResponse -- client.assistant.conversations.history(\*\*params) -> ConversationHistoryResponse +- client.assistant.conversations.history(id, \*\*params) -> ConversationHistoryResponse - client.assistant.conversations.reject_question(\*\*params) -> ConversationRejectQuestionResponse - client.assistant.conversations.send(\*\*params) -> ConversationSendResponse - client.assistant.conversations.stream(\*\*params) -> str diff --git a/src/mobilerun_sdk/resources/assistant/conversations.py b/src/mobilerun_sdk/resources/assistant/conversations.py index ef5c5e6b..1ebdef85 100644 --- a/src/mobilerun_sdk/resources/assistant/conversations.py +++ b/src/mobilerun_sdk/resources/assistant/conversations.py @@ -376,8 +376,9 @@ def answer_question( def history( self, + id: str, *, - session_id: str, + before: str | Omit = omit, limit: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -388,10 +389,12 @@ def history( ) -> ConversationHistoryResponse: """Return the user's chat history for the given session. - History remains readable - after the session is no longer active. + Inactive chat sessions + return 404; workflow transcripts remain readable after completion. Args: + before: Any real row in this session; its containing turn is excluded. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -400,8 +403,10 @@ def history( timeout: Override the client-level default timeout for this request, in seconds """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return self._get( - "/assistant/chat/messages", + path_template("/assistant/chat/sessions/{id}/messages", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -409,7 +414,7 @@ def history( timeout=timeout, query=maybe_transform( { - "session_id": session_id, + "before": before, "limit": limit, }, conversation_history_params.ConversationHistoryParams, @@ -892,8 +897,9 @@ async def answer_question( async def history( self, + id: str, *, - session_id: str, + before: str | Omit = omit, limit: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -904,10 +910,12 @@ async def history( ) -> ConversationHistoryResponse: """Return the user's chat history for the given session. - History remains readable - after the session is no longer active. + Inactive chat sessions + return 404; workflow transcripts remain readable after completion. Args: + before: Any real row in this session; its containing turn is excluded. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -916,8 +924,10 @@ async def history( timeout: Override the client-level default timeout for this request, in seconds """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return await self._get( - "/assistant/chat/messages", + path_template("/assistant/chat/sessions/{id}/messages", id=id), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -925,7 +935,7 @@ async def history( timeout=timeout, query=await async_maybe_transform( { - "session_id": session_id, + "before": before, "limit": limit, }, conversation_history_params.ConversationHistoryParams, diff --git a/src/mobilerun_sdk/types/assistant/conversation_history_params.py b/src/mobilerun_sdk/types/assistant/conversation_history_params.py index ecf0dbe0..52718603 100644 --- a/src/mobilerun_sdk/types/assistant/conversation_history_params.py +++ b/src/mobilerun_sdk/types/assistant/conversation_history_params.py @@ -2,14 +2,13 @@ from __future__ import annotations -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo +from typing_extensions import TypedDict __all__ = ["ConversationHistoryParams"] class ConversationHistoryParams(TypedDict, total=False): - session_id: Required[Annotated[str, PropertyInfo(alias="sessionId")]] + before: str + """Any real row in this session; its containing turn is excluded.""" limit: int diff --git a/src/mobilerun_sdk/types/assistant/conversation_history_response.py b/src/mobilerun_sdk/types/assistant/conversation_history_response.py index 046105e2..9b5d30db 100644 --- a/src/mobilerun_sdk/types/assistant/conversation_history_response.py +++ b/src/mobilerun_sdk/types/assistant/conversation_history_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import TYPE_CHECKING, Dict, List, Optional +from typing import TYPE_CHECKING, Dict, List, Union, Optional from datetime import datetime from typing_extensions import Literal @@ -10,15 +10,53 @@ __all__ = [ "ConversationHistoryResponse", - "Message", - "MessagePart", - "MessageMetadata", - "MessageMetadataSteer", - "TurnState", + "Agent", + "AgentProfile", + "AgentProfileAvatarConfig", + "Data", + "DataPart", + "DataMetadata", + "DataMetadataSteer", + "Turn", + "TurnTurnState", ] -class MessagePart(BaseModel): +class AgentProfileAvatarConfig(BaseModel): + """ + Configuration of a `blob` avatar: its seed and optional user-chosen palette color. A color-only config retains the default seed fallback. + """ + + color: Optional[ + Literal["slate", "red", "orange", "amber", "lime", "green", "teal", "cyan", "blue", "indigo", "violet", "pink"] + ] = None + + seed: Union[str, int, None] = None + + +class AgentProfile(BaseModel): + avatar_config: Optional[AgentProfileAvatarConfig] = FieldInfo(alias="avatarConfig", default=None) + """ + Configuration of a `blob` avatar: its seed and optional user-chosen palette + color. A color-only config retains the default seed fallback. + """ + + avatar_kind: Optional[Literal["blob"]] = FieldInfo(alias="avatarKind", default=None) + + display_name: Optional[str] = FieldInfo(alias="displayName", default=None) + + +class Agent(BaseModel): + """ + Session Agent identity, present on every page; null only when the session has no Agent. + """ + + id: str + + profile: AgentProfile + + +class DataPart(BaseModel): type: str if TYPE_CHECKING: @@ -34,7 +72,7 @@ def __getattr__(self, attr: str) -> object: ... __pydantic_extra__: Dict[str, object] -class MessageMetadataSteer(BaseModel): +class DataMetadataSteer(BaseModel): """ Steer user rows appear directly above the collapsed assistant group of their turn, matching live cloud ordering. """ @@ -50,14 +88,14 @@ class MessageMetadataSteer(BaseModel): drop_reason: Optional[Literal["turn_closed", "aborted"]] = FieldInfo(alias="dropReason", default=None) -class MessageMetadata(BaseModel): +class DataMetadata(BaseModel): agent: Optional[str] = None agent_message_id: Optional[str] = FieldInfo(alias="agentMessageId", default=None) agent_session_id: Optional[str] = FieldInfo(alias="agentSessionId", default=None) - steer: Optional[MessageMetadataSteer] = None + steer: Optional[DataMetadataSteer] = None """ Steer user rows appear directly above the collapsed assistant group of their turn, matching live cloud ordering. @@ -66,10 +104,10 @@ class MessageMetadata(BaseModel): turn_anchor_message_id: Optional[str] = FieldInfo(alias="turnAnchorMessageId", default=None) -class Message(BaseModel): +class Data(BaseModel): id: str - parts: List[MessagePart] + parts: List[DataPart] role: Literal["user", "assistant", "system"] @@ -79,7 +117,7 @@ class Message(BaseModel): feedback: Optional[bool] = None - metadata: Optional[MessageMetadata] = None + metadata: Optional[DataMetadata] = None source: Optional[Literal["cloud", "telegram", "api", "workflow", "notification"]] = None @@ -91,7 +129,7 @@ class Message(BaseModel): """Deprecated: use createdBy.""" -class TurnState(BaseModel): +class TurnTurnState(BaseModel): id: str abort_requested: bool = FieldInfo(alias="abortRequested") @@ -101,6 +139,7 @@ class TurnState(BaseModel): claim_held: bool = FieldInfo(alias="claimHeld") outcome: Optional[str] = None + """Outcome of the latest turn, or null while it is still open.""" phase: Literal["created", "running", "closed", "delivered", "failed"] @@ -111,13 +150,32 @@ class TurnState(BaseModel): started_at: str = FieldInfo(alias="startedAt") -class ConversationHistoryResponse(BaseModel): - messages: List[Message] +class Turn(BaseModel): + """Newest-page turn snapshot; null when before is supplied.""" turn_active: bool = FieldInfo(alias="turnActive") + """Whether this session owns an in-flight turn.""" + + turn_state: Optional[TurnTurnState] = FieldInfo(alias="turnState", default=None) + + +class ConversationHistoryResponse(BaseModel): + agent: Optional[Agent] = None + """ + Session Agent identity, present on every page; null only when the session has no + Agent. + """ + + data: List[Data] + + first_id: Optional[str] = FieldInfo(alias="firstId", default=None) + """Oldest real row in the page; pass as before to load older turns.""" - last_turn_outcome: Optional[str] = FieldInfo(alias="lastTurnOutcome", default=None) + has_more: bool = FieldInfo(alias="hasMore") + """Older whole turns exist.""" - truncated: Optional[bool] = None + last_id: Optional[str] = FieldInfo(alias="lastId", default=None) + """Newest real row in the page, before continuation collapse or synthetic rows.""" - turn_state: Optional[TurnState] = FieldInfo(alias="turnState", default=None) + turn: Optional[Turn] = None + """Newest-page turn snapshot; null when before is supplied.""" diff --git a/tests/api_resources/assistant/test_conversations.py b/tests/api_resources/assistant/test_conversations.py index eec108db..c6f18f51 100644 --- a/tests/api_resources/assistant/test_conversations.py +++ b/tests/api_resources/assistant/test_conversations.py @@ -284,7 +284,7 @@ def test_streaming_response_answer_question(self, client: Mobilerun) -> None: @parametrize def test_method_history(self, client: Mobilerun) -> None: conversation = client.assistant.conversations.history( - session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(ConversationHistoryResponse, conversation, path=["response"]) @@ -292,7 +292,8 @@ def test_method_history(self, client: Mobilerun) -> None: @parametrize def test_method_history_with_all_params(self, client: Mobilerun) -> None: conversation = client.assistant.conversations.history( - session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + before="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", limit=1, ) assert_matches_type(ConversationHistoryResponse, conversation, path=["response"]) @@ -301,7 +302,7 @@ def test_method_history_with_all_params(self, client: Mobilerun) -> None: @parametrize def test_raw_response_history(self, client: Mobilerun) -> None: response = client.assistant.conversations.with_raw_response.history( - session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True @@ -313,7 +314,7 @@ def test_raw_response_history(self, client: Mobilerun) -> None: @parametrize def test_streaming_response_history(self, client: Mobilerun) -> None: with client.assistant.conversations.with_streaming_response.history( - session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -323,6 +324,14 @@ def test_streaming_response_history(self, client: Mobilerun) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_history(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.assistant.conversations.with_raw_response.history( + id="", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_reject_question(self, client: Mobilerun) -> None: @@ -700,7 +709,7 @@ async def test_streaming_response_answer_question(self, async_client: AsyncMobil @parametrize async def test_method_history(self, async_client: AsyncMobilerun) -> None: conversation = await async_client.assistant.conversations.history( - session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert_matches_type(ConversationHistoryResponse, conversation, path=["response"]) @@ -708,7 +717,8 @@ async def test_method_history(self, async_client: AsyncMobilerun) -> None: @parametrize async def test_method_history_with_all_params(self, async_client: AsyncMobilerun) -> None: conversation = await async_client.assistant.conversations.history( - session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + before="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", limit=1, ) assert_matches_type(ConversationHistoryResponse, conversation, path=["response"]) @@ -717,7 +727,7 @@ async def test_method_history_with_all_params(self, async_client: AsyncMobilerun @parametrize async def test_raw_response_history(self, async_client: AsyncMobilerun) -> None: response = await async_client.assistant.conversations.with_raw_response.history( - session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True @@ -729,7 +739,7 @@ async def test_raw_response_history(self, async_client: AsyncMobilerun) -> None: @parametrize async def test_streaming_response_history(self, async_client: AsyncMobilerun) -> None: async with async_client.assistant.conversations.with_streaming_response.history( - session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -739,6 +749,14 @@ async def test_streaming_response_history(self, async_client: AsyncMobilerun) -> assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_history(self, async_client: AsyncMobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.assistant.conversations.with_raw_response.history( + id="", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_reject_question(self, async_client: AsyncMobilerun) -> None: