Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api.md
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,7 @@ Methods:
- <code title="post /assistant/chat/abort">client.assistant.conversations.<a href="./src/mobilerun_sdk/resources/assistant/conversations.py">abort</a>(\*\*<a href="src/mobilerun_sdk/types/assistant/conversation_abort_params.py">params</a>) -> <a href="./src/mobilerun_sdk/types/assistant/conversation_abort_response.py">ConversationAbortResponse</a></code>
- <code title="post /assistant/chat/permission">client.assistant.conversations.<a href="./src/mobilerun_sdk/resources/assistant/conversations.py">answer_permission</a>(\*\*<a href="src/mobilerun_sdk/types/assistant/conversation_answer_permission_params.py">params</a>) -> <a href="./src/mobilerun_sdk/types/assistant/conversation_answer_permission_response.py">ConversationAnswerPermissionResponse</a></code>
- <code title="post /assistant/chat/question">client.assistant.conversations.<a href="./src/mobilerun_sdk/resources/assistant/conversations.py">answer_question</a>(\*\*<a href="src/mobilerun_sdk/types/assistant/conversation_answer_question_params.py">params</a>) -> <a href="./src/mobilerun_sdk/types/assistant/conversation_answer_question_response.py">ConversationAnswerQuestionResponse</a></code>
- <code title="get /assistant/chat/messages">client.assistant.conversations.<a href="./src/mobilerun_sdk/resources/assistant/conversations.py">history</a>(\*\*<a href="src/mobilerun_sdk/types/assistant/conversation_history_params.py">params</a>) -> <a href="./src/mobilerun_sdk/types/assistant/conversation_history_response.py">ConversationHistoryResponse</a></code>
- <code title="get /assistant/chat/sessions/{id}/messages">client.assistant.conversations.<a href="./src/mobilerun_sdk/resources/assistant/conversations.py">history</a>(id, \*\*<a href="src/mobilerun_sdk/types/assistant/conversation_history_params.py">params</a>) -> <a href="./src/mobilerun_sdk/types/assistant/conversation_history_response.py">ConversationHistoryResponse</a></code>
- <code title="post /assistant/chat/question/reject">client.assistant.conversations.<a href="./src/mobilerun_sdk/resources/assistant/conversations.py">reject_question</a>(\*\*<a href="src/mobilerun_sdk/types/assistant/conversation_reject_question_params.py">params</a>) -> <a href="./src/mobilerun_sdk/types/assistant/conversation_reject_question_response.py">ConversationRejectQuestionResponse</a></code>
- <code title="post /assistant/chat/message">client.assistant.conversations.<a href="./src/mobilerun_sdk/resources/assistant/conversations.py">send</a>(\*\*<a href="src/mobilerun_sdk/types/assistant/conversation_send_params.py">params</a>) -> <a href="./src/mobilerun_sdk/types/assistant/conversation_send_response.py">ConversationSendResponse</a></code>
- <code title="get /assistant/chat/stream">client.assistant.conversations.<a href="./src/mobilerun_sdk/resources/assistant/conversations.py">stream</a>(\*\*<a href="src/mobilerun_sdk/types/assistant/conversation_stream_params.py">params</a>) -> str</code>
Expand Down
30 changes: 20 additions & 10 deletions src/mobilerun_sdk/resources/assistant/conversations.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -400,16 +403,18 @@ 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,
extra_body=extra_body,
timeout=timeout,
query=maybe_transform(
{
"session_id": session_id,
"before": before,
"limit": limit,
},
conversation_history_params.ConversationHistoryParams,
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -916,16 +924,18 @@ 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,
extra_body=extra_body,
timeout=timeout,
query=await async_maybe_transform(
{
"session_id": session_id,
"before": before,
"limit": limit,
},
conversation_history_params.ConversationHistoryParams,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
96 changes: 77 additions & 19 deletions src/mobilerun_sdk/types/assistant/conversation_history_response.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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:
Expand All @@ -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.
"""
Expand All @@ -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.
Expand All @@ -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"]

Expand All @@ -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

Expand All @@ -91,7 +129,7 @@ class Message(BaseModel):
"""Deprecated: use createdBy."""


class TurnState(BaseModel):
class TurnTurnState(BaseModel):
id: str

abort_requested: bool = FieldInfo(alias="abortRequested")
Expand All @@ -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"]

Expand All @@ -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."""
34 changes: 26 additions & 8 deletions tests/api_resources/assistant/test_conversations.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,15 +284,16 @@ 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"])

@pytest.mark.skip(reason="Mock server tests are disabled")
@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"])
Expand All @@ -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
Expand All @@ -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"
Expand All @@ -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:
Expand Down Expand Up @@ -700,15 +709,16 @@ 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"])

@pytest.mark.skip(reason="Mock server tests are disabled")
@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"])
Expand All @@ -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
Expand All @@ -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"
Expand All @@ -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:
Expand Down
Loading