diff --git a/api.md b/api.md
index 091dc53..cae99f8 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 ef5c5e6..1ebdef8 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 ecf0dbe..5271860 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 046105e..9b5d30d 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 eec108d..c6f18f5 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: