Skip to content

Commit fb3321b

Browse files
authored
Add docstrings for _messages (#137)
1 parent 994fb9b commit fb3321b

File tree

4 files changed

+112
-5
lines changed

4 files changed

+112
-5
lines changed

src/yandex_cloud_ml_sdk/_messages/base.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,26 @@
88

99
@dataclasses.dataclass(frozen=True)
1010
class BaseMessage(BaseProtoResult[ProtoMessageTypeT_contra]):
11+
"""
12+
Abstract class for messages in Yandex Cloud ML Assistant service.
13+
14+
Provides core functionality for all message types including:
15+
- Storage and processing of message parts (text, citations, etc.)
16+
- Basic text content operations
17+
- Protocol buffer support via BaseProtoResult[ProtoMessageTypeT_contra]
18+
19+
Extended by:
20+
- Message: Complete assistant messages
21+
- PartialMessage: Intermediate message content during streaming
22+
"""
23+
#: Tuple containing message parts (can be strings or other types)
1124
parts: tuple[Any, ...]
1225

1326
@property
1427
def text(self) -> str:
28+
"""
29+
Get concatenated string of all text parts in the message by joining all string parts.
30+
"""
1531
return '\n'.join(
1632
part for part in self.parts
1733
if isinstance(part, str)

src/yandex_cloud_ml_sdk/_messages/citations.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@
2121

2222
@dataclasses.dataclass(frozen=True)
2323
class Citation(BaseProtoResult[ProtoCitation]):
24+
"""
25+
Represents a citation from search results with multiple sources.
26+
27+
A citation contains references to one or more sources from search indexes that were used
28+
to generate or support the content. This is typically used in generative AI responses
29+
to provide attribution for factual information.
30+
"""
31+
#: Tuple of Source objects referenced in this citation
2432
sources: tuple[Source, ...]
2533

2634
@classmethod
@@ -33,9 +41,15 @@ def _from_proto(cls, proto: ProtoCitation, sdk: BaseSDK) -> Citation: # type: i
3341
)
3442

3543
class Source(BaseProtoResult[ProtoSource]):
44+
"""
45+
Abstract base class for citation sources.
46+
"""
3647
@property
3748
@abc.abstractmethod
3849
def type(self) -> str:
50+
"""
51+
Get the type identifier of this source.
52+
"""
3953
pass
4054

4155
@classmethod
@@ -48,11 +62,19 @@ def _from_proto(cls, proto: ProtoSource, sdk: BaseSDK) -> Source: # type: ignor
4862

4963
@dataclasses.dataclass(frozen=True)
5064
class FileChunk(Source, BaseMessage[ProtoSource]):
65+
"""
66+
Represents a file chunk citation source.
67+
"""
68+
#: Search index this chunk belongs to
5169
search_index: BaseSearchIndex
70+
#: File this chunk belongs to (optional)
5271
file: BaseFile | None
5372

5473
@property
5574
def type(self) -> str:
75+
"""
76+
Get the type identifier for file chunks. Always returns 'filechunk'
77+
"""
5678
return 'filechunk'
5779

5880
@classmethod
@@ -85,10 +107,17 @@ def _from_proto(cls, proto: ProtoSource, sdk: BaseSDK) -> FileChunk | UnknownSou
85107

86108
@dataclasses.dataclass(frozen=True)
87109
class UnknownSource(Source):
110+
"""
111+
Represents an unknown citation source type.
112+
"""
113+
#: Description of the unknown source
88114
text: str
89115

90116
@property
91117
def type(self) -> str:
118+
"""
119+
Get the type identifier for unknown sources. Always returns 'unknown'.
120+
"""
92121
return 'unknown'
93122

94123
@classmethod

src/yandex_cloud_ml_sdk/_messages/domain.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@
1414
from yandex_cloud_ml_sdk._types.domain import BaseDomain
1515
from yandex_cloud_ml_sdk._types.message import MessageType, coerce_to_text_message_dict
1616
from yandex_cloud_ml_sdk._types.misc import UNDEFINED, UndefinedOr, get_defined_value
17+
from yandex_cloud_ml_sdk._utils.doc import doc_from
1718
from yandex_cloud_ml_sdk._utils.sync import run_sync, run_sync_generator
1819

1920
from .message import Message
2021

2122

2223
class BaseMessages(BaseDomain):
24+
"""
25+
Base class for message operations (sync and async implementations).
26+
"""
2327
_message_impl = Message
2428

2529
async def _create(
@@ -30,6 +34,14 @@ async def _create(
3034
labels: UndefinedOr[dict[str, str]] = UNDEFINED,
3135
timeout: float = 60,
3236
) -> Message:
37+
"""Create a new message.
38+
39+
:param message: Message content to create
40+
:param thread_id: ID of the thread to add message to
41+
:param labels: Optional dictionary of message labels
42+
:param timeout: The timeout, or the maximum time to wait for the request to complete in seconds.
43+
Defaults to 60 seconds.
44+
"""
3345
message_dict = coerce_to_text_message_dict(message)
3446
content = message_dict['text']
3547
author: Author | None = None
@@ -67,6 +79,14 @@ async def _get(
6779
message_id: str,
6880
timeout: float = 60,
6981
) -> Message:
82+
"""
83+
Get a message by ID.
84+
85+
:param thread_id: ID of the thread containing the message
86+
:param message_id: ID of the message to retrieve
87+
:param timeout: The timeout, or the maximum time to wait for the request to complete in seconds.
88+
Defaults to 60 seconds.
89+
"""
7090
# TODO: we need a global per-sdk cache on ids to rule out
7191
# possibility we have two Messages with same ids but different fields
7292
request = GetMessageRequest(thread_id=thread_id, message_id=message_id)
@@ -87,6 +107,13 @@ async def _list(
87107
thread_id: str,
88108
timeout: float = 60
89109
) -> AsyncIterator[Message]:
110+
"""
111+
List messages in a thread.
112+
113+
:param thread_id: ID of the thread to list messages from
114+
:param timeout: The timeout, or the maximum time to wait for the request to complete in seconds.
115+
Defaults to 60 seconds.
116+
"""
90117
request = ListMessagesRequest(thread_id=thread_id)
91118

92119
async with self._client.get_service_stub(MessageServiceStub, timeout=timeout) as stub:
@@ -98,8 +125,9 @@ async def _list(
98125
):
99126
yield self._message_impl._from_proto(proto=response, sdk=self._sdk)
100127

101-
128+
@doc_from(BaseMessages)
102129
class AsyncMessages(BaseMessages):
130+
@doc_from(BaseMessages._create)
103131
async def create(
104132
self,
105133
message: MessageType,
@@ -115,6 +143,7 @@ async def create(
115143
timeout=timeout
116144
)
117145

146+
@doc_from(BaseMessages._get)
118147
async def get(
119148
self,
120149
*,
@@ -128,6 +157,7 @@ async def get(
128157
timeout=timeout
129158
)
130159

160+
@doc_from(BaseMessages._list)
131161
async def list(
132162
self,
133163
*,
@@ -140,12 +170,14 @@ async def list(
140170
):
141171
yield message
142172

143-
173+
@doc_from(BaseMessages)
144174
class Messages(BaseMessages):
175+
145176
__get = run_sync(BaseMessages._get)
146177
__create = run_sync(BaseMessages._create)
147178
__list = run_sync_generator(BaseMessages._list)
148179

180+
@doc_from(BaseMessages._create)
149181
def create(
150182
self,
151183
message: MessageType,
@@ -161,6 +193,7 @@ def create(
161193
timeout=timeout
162194
)
163195

196+
@doc_from(BaseMessages._get)
164197
def get(
165198
self,
166199
*,
@@ -174,6 +207,7 @@ def get(
174207
timeout=timeout
175208
)
176209

210+
@doc_from(BaseMessages._list)
177211
def list(
178212
self,
179213
*,

src/yandex_cloud_ml_sdk/_messages/message.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,34 +20,57 @@
2020

2121

2222
class MessageStatus(ProtoEnumBase, enum.IntEnum):
23+
"""
24+
Enum representing possible message statuses.
25+
26+
.. note:: Values are inherited from protobuf definitions.
27+
"""
2328
MESSAGE_STATUS_UNSPECIFIED = ProtoMessage.MessageStatus.MESSAGE_STATUS_UNSPECIFIED
2429

25-
# Message was successfully created by a user or generated by an assistant.
30+
#: Message was successfully created by a user or generated by an assistant.
2631
COMPLETED = ProtoMessage.MessageStatus.COMPLETED
27-
# Message generation was truncated due to reaching the maximum allowed number of tokens.
32+
#: Message generation was truncated due to reaching the maximum allowed number of tokens.
2833
TRUNCATED = ProtoMessage.MessageStatus.TRUNCATED
29-
# Message generation was stopped because potentially sensitive content was detected either in the prompt or in the generated response.
34+
#: Message generation was stopped because potentially sensitive content was detected either in the prompt or in the generated response.
3035
FILTERED_CONTENT = ProtoMessage.MessageStatus.FILTERED_CONTENT
3136

3237

3338
@dataclasses.dataclass(frozen=True)
3439
class Author:
40+
"""
41+
Represents the author of a message.
42+
"""
43+
#: Unique identifier of the message author
3544
id: str
45+
#: Role of the author (e.g., 'user', 'assistant')
3646
role: str
3747

3848

3949
@dataclasses.dataclass(frozen=True)
4050
class Message(BaseMessage[ProtoMessage], BaseResource[ProtoMessage]):
51+
"""
52+
Represents a message in a conversation thread.
53+
"""
54+
#: ID of the thread containing this message
4155
thread_id: str
56+
#: ID of the user/assistant who created the message
4257
created_by: str
58+
#: Timestamp when the message was created
4359
created_at: datetime
60+
#: A set of labels for the message.
4461
labels: dict[str, str] | None
62+
#: Author information
4563
author: Author
64+
#: Tuple of citations in this message
4665
citations: tuple[Citation, ...]
66+
#: Current status of the message
4767
status: MessageStatus
4868

4969
@property
5070
def role(self) -> str:
71+
"""
72+
Get the role of the message author.
73+
"""
5174
return self.author.role
5275

5376
@classmethod
@@ -80,6 +103,11 @@ def _kwargs_from_message(cls, proto: ProtoMessage, sdk: BaseSDK) -> dict[str, An
80103

81104
@dataclasses.dataclass(frozen=True)
82105
class PartialMessage(BaseMessage[MessageContent], BaseResource[MessageContent]):
106+
"""
107+
Represents a partial message.
108+
Used for streaming responses where content arrives in chunks.
109+
"""
110+
83111
@classmethod
84112
def _kwargs_from_message(cls, proto: MessageContent, sdk: BaseSDK) -> dict[str, Any]: # type: ignore[override]
85113
kwargs = super()._kwargs_from_message(proto, sdk=sdk)

0 commit comments

Comments
 (0)