unique_toolkit 0.5.55__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. unique_toolkit/_common/validate_required_values.py +21 -0
  2. unique_toolkit/app/__init__.py +20 -0
  3. unique_toolkit/app/schemas.py +73 -7
  4. unique_toolkit/chat/__init__.py +5 -4
  5. unique_toolkit/chat/constants.py +3 -0
  6. unique_toolkit/chat/functions.py +661 -0
  7. unique_toolkit/chat/schemas.py +11 -11
  8. unique_toolkit/chat/service.py +273 -430
  9. unique_toolkit/content/__init__.py +1 -0
  10. unique_toolkit/content/constants.py +2 -0
  11. unique_toolkit/content/functions.py +475 -0
  12. unique_toolkit/content/service.py +163 -315
  13. unique_toolkit/content/utils.py +32 -0
  14. unique_toolkit/embedding/__init__.py +3 -0
  15. unique_toolkit/embedding/constants.py +2 -0
  16. unique_toolkit/embedding/functions.py +79 -0
  17. unique_toolkit/embedding/service.py +47 -34
  18. unique_toolkit/evaluators/__init__.py +1 -0
  19. unique_toolkit/evaluators/constants.py +1 -0
  20. unique_toolkit/evaluators/context_relevancy/constants.py +3 -3
  21. unique_toolkit/evaluators/context_relevancy/utils.py +5 -2
  22. unique_toolkit/evaluators/hallucination/utils.py +2 -1
  23. unique_toolkit/language_model/__init__.py +1 -0
  24. unique_toolkit/language_model/constants.py +4 -0
  25. unique_toolkit/language_model/functions.py +362 -0
  26. unique_toolkit/language_model/service.py +246 -293
  27. unique_toolkit/short_term_memory/__init__.py +5 -0
  28. unique_toolkit/short_term_memory/constants.py +1 -0
  29. unique_toolkit/short_term_memory/functions.py +175 -0
  30. unique_toolkit/short_term_memory/service.py +153 -27
  31. {unique_toolkit-0.5.55.dist-info → unique_toolkit-0.6.0.dist-info}/METADATA +33 -7
  32. unique_toolkit-0.6.0.dist-info/RECORD +64 -0
  33. unique_toolkit-0.5.55.dist-info/RECORD +0 -50
  34. {unique_toolkit-0.5.55.dist-info → unique_toolkit-0.6.0.dist-info}/LICENSE +0 -0
  35. {unique_toolkit-0.5.55.dist-info → unique_toolkit-0.6.0.dist-info}/WHEEL +0 -0
@@ -1,39 +1,76 @@
1
1
  import logging
2
- import re
3
2
  from typing import Optional
4
3
 
5
- import unique_sdk
6
- from unique_sdk._list_object import ListObject
4
+ from typing_extensions import deprecated
7
5
 
8
- from unique_toolkit._common import _time_utils
9
- from unique_toolkit._common._base_service import BaseService
10
- from unique_toolkit.app.schemas import Event
6
+ from unique_toolkit.app.schemas import ChatEvent, Event
7
+ from unique_toolkit.chat.constants import (
8
+ DEFAULT_MAX_MESSAGES,
9
+ DEFAULT_PERCENT_OF_MAX_TOKENS,
10
+ DOMAIN_NAME,
11
+ )
12
+ from unique_toolkit.chat.functions import (
13
+ create_message,
14
+ create_message_assessment,
15
+ create_message_assessment_async,
16
+ create_message_async,
17
+ get_full_history,
18
+ get_full_history_async,
19
+ get_selection_from_history,
20
+ modify_message,
21
+ modify_message_assessment,
22
+ modify_message_assessment_async,
23
+ modify_message_async,
24
+ )
11
25
  from unique_toolkit.chat.schemas import (
12
26
  ChatMessage,
27
+ ChatMessageAssessment,
28
+ ChatMessageAssessmentLabel,
29
+ ChatMessageAssessmentStatus,
30
+ ChatMessageAssessmentType,
13
31
  ChatMessageRole,
14
- MessageAssessment,
15
- MessageAssessmentLabel,
16
- MessageAssessmentStatus,
17
- MessageAssessmentType,
18
32
  )
19
33
  from unique_toolkit.content.schemas import ContentReference
20
- from unique_toolkit.content.utils import count_tokens
21
34
 
35
+ logger = logging.getLogger(f"toolkit.{DOMAIN_NAME}.{__name__}")
22
36
 
23
- class ChatService(BaseService):
37
+
38
+ class ChatService:
24
39
  """
25
40
  Provides all functionalities to manage the chat session.
26
41
 
27
42
  Attributes:
28
- event (Event): The Event object.
29
- logger (Optional[logging.Logger]): The logger. Defaults to None.
43
+ company_id (str | None): The company ID.
44
+ user_id (str | None): The user ID.
45
+ assistant_message_id (str | None): The assistant message ID.
46
+ user_message_id (str | None): The user message ID.
47
+ chat_id (str | None): The chat ID.
48
+ assistant_id (str | None): The assistant ID.
49
+ user_message_text (str | None): The user message text.
30
50
  """
31
51
 
32
- def __init__(self, event: Event, logger: Optional[logging.Logger] = None):
33
- super().__init__(event, logger)
52
+ def __init__(self, event: ChatEvent | Event):
53
+ self._event = event
54
+ self.company_id = event.company_id
55
+ self.user_id = event.user_id
56
+ self.assistant_message_id = event.payload.assistant_message.id
57
+ self.user_message_id = event.payload.user_message.id
58
+ self.chat_id = event.payload.chat_id
59
+ self.assistant_id = event.payload.assistant_id
60
+ self.user_message_text = event.payload.user_message.text
34
61
 
35
- DEFAULT_PERCENT_OF_MAX_TOKENS = 0.15
36
- DEFAULT_MAX_MESSAGES = 4
62
+ @property
63
+ @deprecated(
64
+ "The event property is deprecated and will be removed in a future version."
65
+ )
66
+ def event(self) -> Event | ChatEvent | None:
67
+ """
68
+ Get the event object (deprecated).
69
+
70
+ Returns:
71
+ Event | BaseEvent | None: The event object.
72
+ """
73
+ return self._event
37
74
 
38
75
  async def update_debug_info_async(self, debug_info: dict):
39
76
  """
@@ -42,14 +79,17 @@ class ChatService(BaseService):
42
79
  Args:
43
80
  debug_info (dict): The new debug information.
44
81
  """
45
- params = self._construct_message_modify_params(
46
- assistant=False, debug_info=debug_info
82
+
83
+ return await modify_message_async(
84
+ user_id=self.user_id,
85
+ company_id=self.company_id,
86
+ assistant_message_id=self.assistant_message_id,
87
+ chat_id=self.chat_id,
88
+ user_message_id=self.user_message_id,
89
+ user_message_text=self.user_message_text,
90
+ assistant=False,
91
+ debug_info=debug_info,
47
92
  )
48
- try:
49
- await unique_sdk.Message.modify_async(**params)
50
- except Exception as e:
51
- self.logger.error(f"Failed to update debug info: {e}")
52
- raise e
53
93
 
54
94
  def update_debug_info(self, debug_info: dict):
55
95
  """
@@ -58,25 +98,28 @@ class ChatService(BaseService):
58
98
  Args:
59
99
  debug_info (dict): The new debug information.
60
100
  """
61
- params = self._construct_message_modify_params(
62
- assistant=False, debug_info=debug_info
101
+
102
+ return modify_message(
103
+ user_id=self.user_id,
104
+ company_id=self.company_id,
105
+ assistant_message_id=self.assistant_message_id,
106
+ chat_id=self.chat_id,
107
+ user_message_id=self.user_message_id,
108
+ user_message_text=self.user_message_text,
109
+ assistant=False,
110
+ debug_info=debug_info,
63
111
  )
64
- try:
65
- unique_sdk.Message.modify(**params)
66
- except Exception as e:
67
- self.logger.error(f"Failed to update debug info: {e}")
68
- raise e
69
112
 
70
113
  def modify_user_message(
71
114
  self,
72
115
  content: str,
73
- references: Optional[list[ContentReference]] = None,
74
- debug_info: Optional[dict] = None,
75
- message_id: Optional[str] = None,
76
- set_completed_at: Optional[bool] = False,
116
+ references: list[ContentReference] = [],
117
+ debug_info: dict = {},
118
+ message_id: str | None = None,
119
+ set_completed_at: bool | None = False,
77
120
  ) -> ChatMessage:
78
121
  """
79
- Modifies a message in the chat session synchronously.
122
+ Modifies a user message in the chat session synchronously.
80
123
 
81
124
  Args:
82
125
  content (str): The new content for the message.
@@ -91,28 +134,28 @@ class ChatService(BaseService):
91
134
  Raises:
92
135
  Exception: If the modification fails.
93
136
  """
94
- try:
95
- params = self._construct_message_modify_params(
96
- assistant=False,
97
- content=content,
98
- references=references,
99
- debug_info=debug_info,
100
- message_id=message_id,
101
- set_completed_at=set_completed_at,
102
- )
103
- message = unique_sdk.Message.modify(**params)
104
- except Exception as e:
105
- self.logger.error(f"Failed to modify user message: {e}")
106
- raise e
107
- return ChatMessage(**message)
137
+ return modify_message(
138
+ user_id=self.user_id,
139
+ company_id=self.company_id,
140
+ assistant_message_id=self.assistant_message_id,
141
+ chat_id=self.chat_id,
142
+ user_message_id=self.user_message_id,
143
+ user_message_text=self.user_message_text,
144
+ assistant=False,
145
+ content=content,
146
+ references=references,
147
+ debug_info=debug_info,
148
+ message_id=message_id,
149
+ set_completed_at=set_completed_at or False,
150
+ )
108
151
 
109
152
  async def modify_user_message_async(
110
153
  self,
111
154
  content: str,
112
155
  references: list[ContentReference] = [],
113
156
  debug_info: dict = {},
114
- message_id: Optional[str] = None,
115
- set_completed_at: Optional[bool] = False,
157
+ message_id: str | None = None,
158
+ set_completed_at: bool | None = False,
116
159
  ) -> ChatMessage:
117
160
  """
118
161
  Modifies a message in the chat session asynchronously.
@@ -121,8 +164,8 @@ class ChatService(BaseService):
121
164
  content (str): The new content for the message.
122
165
  message_id (str, optional): The message ID. Defaults to None, then the ChatState user message id is used.
123
166
  references (list[ContentReference]): list of ContentReference objects. Defaults to None.
124
- debug_info (Optional[dict[str, Any]]], optional): Debug information. Defaults to None.
125
- set_completed_at (Optional[bool]): Whether to set the completedAt field with the current date time. Defaults to False.
167
+ debug_info (dict[str, Any]]]): Debug information. Defaults to {}.
168
+ set_completed_at (bool, optional): Whether to set the completedAt field with the current date time. Defaults to False.
126
169
 
127
170
  Returns:
128
171
  ChatMessage: The modified message.
@@ -130,20 +173,20 @@ class ChatService(BaseService):
130
173
  Raises:
131
174
  Exception: If the modification fails.
132
175
  """
133
- try:
134
- params = self._construct_message_modify_params(
135
- assistant=False,
136
- content=content,
137
- references=references,
138
- debug_info=debug_info,
139
- message_id=message_id,
140
- set_completed_at=set_completed_at,
141
- )
142
- message = await unique_sdk.Message.modify_async(**params)
143
- except Exception as e:
144
- self.logger.error(f"Failed to modify user message: {e}")
145
- raise e
146
- return ChatMessage(**message)
176
+ return await modify_message_async(
177
+ user_id=self.user_id,
178
+ company_id=self.company_id,
179
+ assistant_message_id=self.assistant_message_id,
180
+ chat_id=self.chat_id,
181
+ user_message_id=self.user_message_id,
182
+ user_message_text=self.user_message_text,
183
+ assistant=False,
184
+ content=content,
185
+ references=references,
186
+ debug_info=debug_info,
187
+ message_id=message_id,
188
+ set_completed_at=set_completed_at or False,
189
+ )
147
190
 
148
191
  def modify_assistant_message(
149
192
  self,
@@ -151,8 +194,8 @@ class ChatService(BaseService):
151
194
  original_content: str | None = None,
152
195
  references: list[ContentReference] = [],
153
196
  debug_info: dict = {},
154
- message_id: Optional[str] = None,
155
- set_completed_at: Optional[bool] = False,
197
+ message_id: str | None = None,
198
+ set_completed_at: bool | None = False,
156
199
  ) -> ChatMessage:
157
200
  """
158
201
  Modifies a message in the chat session synchronously.
@@ -171,21 +214,21 @@ class ChatService(BaseService):
171
214
  Raises:
172
215
  Exception: If the modification fails.
173
216
  """
174
- try:
175
- params = self._construct_message_modify_params(
176
- assistant=True,
177
- content=content,
178
- original_content=original_content,
179
- references=references,
180
- debug_info=debug_info,
181
- message_id=message_id,
182
- set_completed_at=set_completed_at,
183
- )
184
- message = unique_sdk.Message.modify(**params)
185
- except Exception as e:
186
- self.logger.error(f"Failed to modify assistant message: {e}")
187
- raise e
188
- return ChatMessage(**message)
217
+ return modify_message(
218
+ user_id=self.user_id,
219
+ company_id=self.company_id,
220
+ assistant_message_id=self.assistant_message_id,
221
+ chat_id=self.chat_id,
222
+ user_message_id=self.user_message_id,
223
+ user_message_text=self.user_message_text,
224
+ assistant=True,
225
+ content=content,
226
+ original_content=original_content,
227
+ references=references,
228
+ debug_info=debug_info,
229
+ message_id=message_id,
230
+ set_completed_at=set_completed_at or False,
231
+ )
189
232
 
190
233
  async def modify_assistant_message_async(
191
234
  self,
@@ -193,8 +236,8 @@ class ChatService(BaseService):
193
236
  original_content: str | None = None,
194
237
  references: list[ContentReference] = [],
195
238
  debug_info: dict = {},
196
- message_id: Optional[str] = None,
197
- set_completed_at: Optional[bool] = False,
239
+ message_id: str | None = None,
240
+ set_completed_at: bool | None = False,
198
241
  ) -> ChatMessage:
199
242
  """
200
243
  Modifies a message in the chat session asynchronously.
@@ -204,8 +247,8 @@ class ChatService(BaseService):
204
247
  original_content (str, optional): The original content for the message.
205
248
  message_id (str, optional): The message ID. Defaults to None, then the ChatState assistant message id is used.
206
249
  references (list[ContentReference]): list of ContentReference objects. Defaults to None.
207
- debug_info (Optional[dict[str, Any]]], optional): Debug information. Defaults to None.
208
- set_completed_at (Optional[bool]): Whether to set the completedAt field with the current date time. Defaults to False.
250
+ debug_info (dict[str, Any]], optional): Debug information. Defaults to None.
251
+ set_completed_at (bool, optional): Whether to set the completedAt field with the current date time. Defaults to False.
209
252
 
210
253
  Returns:
211
254
  ChatMessage: The modified message.
@@ -213,21 +256,22 @@ class ChatService(BaseService):
213
256
  Raises:
214
257
  Exception: If the modification fails.
215
258
  """
216
- try:
217
- params = self._construct_message_modify_params(
218
- assistant=True,
219
- content=content,
220
- original_content=original_content,
221
- references=references,
222
- debug_info=debug_info,
223
- message_id=message_id,
224
- set_completed_at=set_completed_at,
225
- )
226
- message = await unique_sdk.Message.modify_async(**params)
227
- except Exception as e:
228
- self.logger.error(f"Failed to modify assistant message: {e}")
229
- raise e
230
- return ChatMessage(**message)
259
+
260
+ return await modify_message_async(
261
+ user_id=self.user_id,
262
+ company_id=self.company_id,
263
+ assistant_message_id=self.assistant_message_id,
264
+ chat_id=self.chat_id,
265
+ user_message_id=self.user_message_id,
266
+ user_message_text=self.user_message_text,
267
+ assistant=True,
268
+ content=content,
269
+ original_content=original_content,
270
+ references=references,
271
+ debug_info=debug_info,
272
+ message_id=message_id,
273
+ set_completed_at=set_completed_at or False,
274
+ )
231
275
 
232
276
  def get_full_history(self) -> list[ChatMessage]:
233
277
  """
@@ -239,7 +283,11 @@ class ChatService(BaseService):
239
283
  Raises:
240
284
  Exception: If the loading fails.
241
285
  """
242
- return self._get_full_history()
286
+ return get_full_history(
287
+ event_user_id=self.user_id,
288
+ event_company_id=self.company_id,
289
+ event_payload_chat_id=self.chat_id,
290
+ )
243
291
 
244
292
  async def get_full_history_async(self) -> list[ChatMessage]:
245
293
  """
@@ -251,7 +299,11 @@ class ChatService(BaseService):
251
299
  Raises:
252
300
  Exception: If the loading fails.
253
301
  """
254
- return await self._get_full_history_async()
302
+ return await get_full_history_async(
303
+ event_user_id=self.user_id,
304
+ event_company_id=self.company_id,
305
+ event_payload_chat_id=self.chat_id,
306
+ )
255
307
 
256
308
  def get_full_and_selected_history(
257
309
  self,
@@ -273,8 +325,12 @@ class ChatService(BaseService):
273
325
  Raises:
274
326
  Exception: If the loading fails.
275
327
  """
276
- full_history = self._get_full_history()
277
- selected_history = self._get_selection_from_history(
328
+ full_history = get_full_history(
329
+ event_user_id=self.user_id,
330
+ event_company_id=self.company_id,
331
+ event_payload_chat_id=self.chat_id,
332
+ )
333
+ selected_history = get_selection_from_history(
278
334
  full_history=full_history,
279
335
  max_tokens=int(round(token_limit * percent_of_max_tokens)),
280
336
  max_messages=max_messages,
@@ -302,8 +358,12 @@ class ChatService(BaseService):
302
358
  Raises:
303
359
  Exception: If the loading fails.
304
360
  """
305
- full_history = await self._get_full_history_async()
306
- selected_history = self._get_selection_from_history(
361
+ full_history = await get_full_history_async(
362
+ event_user_id=self.user_id,
363
+ event_company_id=self.company_id,
364
+ event_payload_chat_id=self.chat_id,
365
+ )
366
+ selected_history = get_selection_from_history(
307
367
  full_history=full_history,
308
368
  max_tokens=int(round(token_limit * percent_of_max_tokens)),
309
369
  max_messages=max_messages,
@@ -335,23 +395,18 @@ class ChatService(BaseService):
335
395
  Raises:
336
396
  Exception: If the creation fails.
337
397
  """
338
- if original_content is None:
339
- original_content = content
340
-
341
- try:
342
- params = self._construct_message_create_params(
343
- content=content,
344
- original_content=original_content,
345
- references=references,
346
- debug_info=debug_info,
347
- set_completed_at=set_completed_at,
348
- )
349
-
350
- message = unique_sdk.Message.create(**params)
351
- except Exception as e:
352
- self.logger.error(f"Failed to create assistant message: {e}")
353
- raise e
354
- return ChatMessage(**message)
398
+ return create_message(
399
+ user_id=self.user_id,
400
+ company_id=self.company_id,
401
+ chat_id=self.chat_id,
402
+ assistant_id=self.assistant_id,
403
+ role=ChatMessageRole.ASSISTANT,
404
+ content=content,
405
+ original_content=original_content,
406
+ references=references,
407
+ debug_info=debug_info,
408
+ set_completed_at=set_completed_at,
409
+ )
355
410
 
356
411
  async def create_assistant_message_async(
357
412
  self,
@@ -377,233 +432,30 @@ class ChatService(BaseService):
377
432
  Raises:
378
433
  Exception: If the creation fails.
379
434
  """
380
- if original_content is None:
381
- original_content = content
382
-
383
- try:
384
- params = self._construct_message_create_params(
385
- content=content,
386
- original_content=original_content,
387
- references=references,
388
- debug_info=debug_info,
389
- set_completed_at=set_completed_at,
390
- )
391
-
392
- message = await unique_sdk.Message.create_async(**params)
393
- except Exception as e:
394
- self.logger.error(f"Failed to create assistant message: {e}")
395
- raise e
396
- return ChatMessage(**message)
397
-
398
- @staticmethod
399
- def _map_references(references: list[ContentReference]):
400
- return [
401
- {
402
- "name": ref.name,
403
- "url": ref.url,
404
- "sequenceNumber": ref.sequence_number,
405
- "sourceId": ref.source_id,
406
- "source": ref.source,
407
- }
408
- for ref in references
409
- ]
410
-
411
- def _get_full_history(self):
412
- messages = self._trigger_list_messages(self.event.payload.chat_id)
413
- messages = self._filter_valid_messages(messages)
414
-
415
- return self._map_to_chat_messages(messages)
416
-
417
- async def _get_full_history_async(self):
418
- messages = await self._trigger_list_messages_async(self.event.payload.chat_id)
419
- messages = self._filter_valid_messages(messages)
420
-
421
- return self._map_to_chat_messages(messages)
422
-
423
- @staticmethod
424
- def _filter_valid_messages(messages: ListObject[unique_sdk.Message]):
425
- SYSTEM_MESSAGE_PREFIX = "[SYSTEM] "
426
-
427
- # Remove the last two messages
428
- messages = messages["data"][:-2] # type: ignore
429
- filtered_messages = []
430
- for message in messages:
431
- if message["text"] is None:
432
- continue
433
- elif SYSTEM_MESSAGE_PREFIX in message["text"]:
434
- continue
435
- else:
436
- filtered_messages.append(message)
437
-
438
- return filtered_messages
439
-
440
- def _trigger_list_messages(self, chat_id: str):
441
- try:
442
- messages = unique_sdk.Message.list(
443
- user_id=self.event.user_id,
444
- company_id=self.event.company_id,
445
- chatId=chat_id,
446
- )
447
- return messages
448
- except Exception as e:
449
- self.logger.error(f"Failed to list chat history: {e}")
450
- raise e
451
-
452
- async def _trigger_list_messages_async(self, chat_id: str):
453
- try:
454
- messages = await unique_sdk.Message.list_async(
455
- user_id=self.event.user_id,
456
- company_id=self.event.company_id,
457
- chatId=chat_id,
458
- )
459
- return messages
460
- except Exception as e:
461
- self.logger.error(f"Failed to list chat history: {e}")
462
- raise e
463
-
464
- @staticmethod
465
- def _map_to_chat_messages(messages: list[dict]):
466
- return [ChatMessage(**msg) for msg in messages]
467
-
468
- def _get_selection_from_history(
469
- self,
470
- full_history: list[ChatMessage],
471
- max_tokens: int,
472
- max_messages=4,
473
- ):
474
- messages = full_history[-max_messages:]
475
- filtered_messages = [m for m in messages if m.content]
476
- mapped_messages = []
477
-
478
- for m in filtered_messages:
479
- m.content = re.sub(r"<sup>\d+</sup>", "", m.content)
480
- m.role = (
481
- ChatMessageRole.ASSISTANT
482
- if m.role == ChatMessageRole.ASSISTANT
483
- else ChatMessageRole.USER
484
- )
485
- mapped_messages.append(m)
486
-
487
- return self._pick_messages_in_reverse_for_token_window(
488
- messages=mapped_messages,
489
- limit=max_tokens,
490
- )
491
435
 
492
- def _pick_messages_in_reverse_for_token_window(
493
- self,
494
- messages: list[ChatMessage],
495
- limit: int,
496
- ) -> list[ChatMessage]:
497
- if len(messages) < 1 or limit < 1:
498
- return []
499
-
500
- last_index = len(messages) - 1
501
- token_count = count_tokens(messages[last_index].content)
502
- while token_count > limit:
503
- self.logger.debug(
504
- f"Limit too low for the initial message. Last message TokenCount {token_count} available tokens {limit} - cutting message in half until it fits"
505
- )
506
- content = messages[last_index].content
507
- messages[last_index].content = content[: len(content) // 2] + "..."
508
- token_count = count_tokens(messages[last_index].content)
509
-
510
- while token_count <= limit and last_index > 0:
511
- token_count = count_tokens(
512
- "".join([msg.content for msg in messages[:last_index]])
513
- )
514
- if token_count <= limit:
515
- last_index -= 1
516
-
517
- last_index = max(0, last_index)
518
- return messages[last_index:]
519
-
520
- def _construct_message_modify_params(
521
- self,
522
- assistant: bool = True,
523
- content: Optional[str] = None,
524
- original_content: Optional[str] = None,
525
- references: Optional[list[ContentReference]] = None,
526
- debug_info: Optional[dict] = None,
527
- message_id: Optional[str] = None,
528
- set_completed_at: Optional[bool] = False,
529
- ):
530
- if message_id:
531
- # Message ID specified. No need to guess
532
- message_id = message_id
533
- elif assistant:
534
- # Assistant message ID
535
- message_id = self.event.payload.assistant_message.id
536
- else:
537
- # User message ID
538
- message_id = self.event.payload.user_message.id
539
- if content is None:
540
- content = self.event.payload.user_message.text
541
-
542
- if set_completed_at:
543
- completed_at_datetime = _time_utils.get_datetime_now()
544
- else:
545
- completed_at_datetime = None
546
-
547
- params = {
548
- "user_id": self.event.user_id,
549
- "company_id": self.event.company_id,
550
- "id": message_id,
551
- "chatId": self.event.payload.chat_id,
552
- "text": content,
553
- "originalText": original_content,
554
- "references": self._map_references(references) if references else [],
555
- "debugInfo": debug_info,
556
- "completedAt": completed_at_datetime,
557
- }
558
- return params
559
-
560
- def _construct_message_create_params(
561
- self,
562
- role: ChatMessageRole = ChatMessageRole.ASSISTANT,
563
- content: Optional[str] = None,
564
- original_content: Optional[str] = None,
565
- references: Optional[list[ContentReference]] = None,
566
- debug_info: Optional[dict] = None,
567
- assistantId: Optional[str] = None,
568
- set_completed_at: Optional[bool] = False,
569
- ):
570
- if assistantId:
571
- # Assistant ID specified. No need to guess
572
- assistantId = assistantId
573
- else:
574
- assistantId = self.event.payload.assistant_id
575
-
576
- if set_completed_at:
577
- completed_at_datetime = _time_utils.get_datetime_now()
578
- else:
579
- completed_at_datetime = None
580
-
581
- if original_content is None:
582
- original_content = content
583
-
584
- params = {
585
- "user_id": self.event.user_id,
586
- "company_id": self.event.company_id,
587
- "assistantId": assistantId,
588
- "role": role.value.upper(),
589
- "chatId": self.event.payload.chat_id,
590
- "text": content,
591
- "originalText": original_content,
592
- "references": self._map_references(references) if references else [],
593
- "debugInfo": debug_info,
594
- "completedAt": completed_at_datetime,
595
- }
596
- return params
436
+ return await create_message_async(
437
+ user_id=self.user_id,
438
+ company_id=self.company_id,
439
+ chat_id=self.chat_id,
440
+ assistant_id=self.assistant_id,
441
+ role=ChatMessageRole.ASSISTANT,
442
+ content=content,
443
+ original_content=original_content,
444
+ references=references,
445
+ debug_info=debug_info,
446
+ set_completed_at=set_completed_at,
447
+ )
597
448
 
598
449
  def create_message_assessment(
599
450
  self,
600
451
  assistant_message_id: str,
601
- status: MessageAssessmentStatus,
602
- type: MessageAssessmentType,
452
+ status: ChatMessageAssessmentStatus,
453
+ type: ChatMessageAssessmentType,
454
+ title: str | None = None,
603
455
  explanation: str | None = None,
604
- label: MessageAssessmentLabel | None = None,
456
+ label: ChatMessageAssessmentLabel | None = None,
605
457
  is_visible: bool = True,
606
- ) -> MessageAssessment:
458
+ ) -> ChatMessageAssessment:
607
459
  """
608
460
  Creates a message assessment for an assistant message synchronously.
609
461
 
@@ -611,91 +463,88 @@ class ChatService(BaseService):
611
463
  assistant_message_id (str): The ID of the assistant message to assess
612
464
  status (MessageAssessmentStatus): The status of the assessment (e.g. "DONE")
613
465
  type (MessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
466
+ title (str | None): The title of the assessment
614
467
  explanation (str | None): Explanation of the assessment
615
- label (MessageAssessmentLabel | None): The assessment label (e.g. "NEGATIVE")
468
+ label (MessageAssessmentLabel | None): The assessment label (e.g. "RED")
616
469
  is_visible (bool): Whether the assessment is visible to users. Defaults to True.
617
470
 
618
471
  Returns:
619
- MessageAssessment: The created message assessment
472
+ ChatMessageAssessment: The created message assessment
620
473
 
621
474
  Raises:
622
475
  Exception: If the creation fails
623
476
  """
624
- try:
625
- assessment = unique_sdk.MessageAssessment.create(
626
- user_id=self.event.user_id,
627
- company_id=self.event.company_id,
628
- messageId=assistant_message_id,
629
- status=status.name,
630
- explanation=explanation,
631
- label=label.name if label else None,
632
- type=type.name if type else None,
633
- isVisible=is_visible,
634
- )
635
- return MessageAssessment(**assessment)
636
- except Exception as e:
637
- self.logger.error(f"Failed to create message assessment: {e}")
638
- raise e
477
+ return create_message_assessment(
478
+ user_id=self.user_id,
479
+ company_id=self.company_id,
480
+ assistant_message_id=assistant_message_id,
481
+ status=status,
482
+ type=type,
483
+ title=title,
484
+ explanation=explanation,
485
+ label=label,
486
+ is_visible=is_visible,
487
+ )
639
488
 
640
489
  async def create_message_assessment_async(
641
490
  self,
642
491
  assistant_message_id: str,
643
- status: MessageAssessmentStatus,
644
- type: MessageAssessmentType,
492
+ status: ChatMessageAssessmentStatus,
493
+ type: ChatMessageAssessmentType,
494
+ title: str | None = None,
645
495
  explanation: str | None = None,
646
- label: MessageAssessmentLabel | None = None,
496
+ label: ChatMessageAssessmentLabel | None = None,
647
497
  is_visible: bool = True,
648
- ) -> MessageAssessment:
498
+ ) -> ChatMessageAssessment:
649
499
  """
650
500
  Creates a message assessment for an assistant message asynchronously.
651
501
 
652
502
  Args:
653
503
  assistant_message_id (str): The ID of the assistant message to assess
654
- status (MessageAssessmentStatus): The status of the assessment (e.g. "DONE")
655
- type (MessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
504
+ status (ChatMessageAssessmentStatus): The status of the assessment (e.g. "DONE")
505
+ type (ChatMessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
506
+ title (str | None): The title of the assessment
656
507
  explanation (str | None): Explanation of the assessment
657
- label (MessageAssessmentLabel | None): The assessment label (e.g. "NEGATIVE")
508
+ label (ChatMessageAssessmentLabel | None): The assessment label (e.g. "RED")
658
509
  is_visible (bool): Whether the assessment is visible to users. Defaults to True.
659
510
 
660
511
  Returns:
661
- MessageAssessment: The created message assessment
512
+ ChatMessageAssessment: The created message assessment
662
513
 
663
514
  Raises:
664
515
  Exception: If the creation fails
665
516
  """
666
- try:
667
- assessment = await unique_sdk.MessageAssessment.create_async(
668
- user_id=self.event.user_id,
669
- company_id=self.event.company_id,
670
- messageId=assistant_message_id,
671
- status=status.name,
672
- explanation=explanation,
673
- label=label.name if label else None,
674
- type=type.name if type else None,
675
- isVisible=is_visible,
676
- )
677
- return MessageAssessment(**assessment)
678
- except Exception as e:
679
- self.logger.error(f"Failed to create message assessment: {e}")
680
- raise e
517
+ return await create_message_assessment_async(
518
+ user_id=self.user_id,
519
+ company_id=self.company_id,
520
+ assistant_message_id=assistant_message_id,
521
+ status=status,
522
+ type=type,
523
+ title=title,
524
+ explanation=explanation,
525
+ label=label,
526
+ is_visible=is_visible,
527
+ )
681
528
 
682
529
  def modify_message_assessment(
683
530
  self,
684
531
  assistant_message_id: str,
685
- status: MessageAssessmentStatus,
686
- type: MessageAssessmentType,
532
+ status: ChatMessageAssessmentStatus,
533
+ type: ChatMessageAssessmentType,
534
+ title: str | None = None,
687
535
  explanation: str | None = None,
688
- label: MessageAssessmentLabel | None = None,
689
- ) -> MessageAssessment:
536
+ label: ChatMessageAssessmentLabel | None = None,
537
+ ) -> ChatMessageAssessment:
690
538
  """
691
539
  Modifies a message assessment for an assistant message synchronously.
692
540
 
693
541
  Args:
694
542
  assistant_message_id (str): The ID of the assistant message to assess
695
543
  status (MessageAssessmentStatus): The status of the assessment (e.g. "DONE")
544
+ title (str | None): The title of the assessment
696
545
  explanation (str | None): Explanation of the assessment
697
- label (MessageAssessmentLabel | None): The assessment label (e.g. "NEGATIVE")
698
- type (MessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
546
+ label (ChatMessageAssessmentLabel | None): The assessment label (e.g. "RED")
547
+ type (ChatMessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
699
548
 
700
549
  Returns:
701
550
  dict: The modified message assessment
@@ -703,56 +552,50 @@ class ChatService(BaseService):
703
552
  Raises:
704
553
  Exception: If the modification fails
705
554
  """
706
- try:
707
- assessment = unique_sdk.MessageAssessment.modify(
708
- user_id=self.event.user_id,
709
- company_id=self.event.company_id,
710
- messageId=assistant_message_id,
711
- status=status.name,
712
- explanation=explanation,
713
- label=label.name if label else None,
714
- type=type.name,
715
- )
716
- return MessageAssessment(**assessment)
717
- except Exception as e:
718
- self.logger.error(f"Failed to modify message assessment: {e}")
719
- raise e
555
+ return modify_message_assessment(
556
+ user_id=self.user_id,
557
+ company_id=self.company_id,
558
+ assistant_message_id=assistant_message_id,
559
+ status=status,
560
+ type=type,
561
+ title=title,
562
+ explanation=explanation,
563
+ label=label,
564
+ )
720
565
 
721
566
  async def modify_message_assessment_async(
722
567
  self,
723
568
  assistant_message_id: str,
724
- type: MessageAssessmentType,
725
- status: MessageAssessmentStatus | None = None,
569
+ type: ChatMessageAssessmentType,
570
+ title: str | None = None,
571
+ status: ChatMessageAssessmentStatus | None = None,
726
572
  explanation: str | None = None,
727
- label: MessageAssessmentLabel | None = None,
728
- ) -> MessageAssessment:
573
+ label: ChatMessageAssessmentLabel | None = None,
574
+ ) -> ChatMessageAssessment:
729
575
  """
730
576
  Modifies a message assessment for an assistant message asynchronously.
731
577
 
732
578
  Args:
733
579
  assistant_message_id (str): The ID of the assistant message to assess
734
- status (MessageAssessmentStatus): The status of the assessment (e.g. "DONE")
580
+ status (ChatMessageAssessmentStatus): The status of the assessment (e.g. "DONE")
581
+ title (str | None): The title of the assessment
735
582
  explanation (str | None): Explanation of the assessment
736
- label (MessageAssessmentLabel | None): The assessment label (e.g. "NEGATIVE")
737
- type (MessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
583
+ label (ChatMessageAssessmentLabel | None): The assessment label (e.g. "RED")
584
+ type (ChatMessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
738
585
 
739
586
  Returns:
740
- MessageAssessment: The modified message assessment
587
+ ChatMessageAssessment: The modified message assessment
741
588
 
742
589
  Raises:
743
590
  Exception: If the modification fails
744
591
  """
745
- try:
746
- assessment = await unique_sdk.MessageAssessment.modify_async(
747
- user_id=self.event.user_id,
748
- company_id=self.event.company_id,
749
- messageId=assistant_message_id,
750
- status=status.name if status else None,
751
- explanation=explanation,
752
- label=label.name if label else None,
753
- type=type.name,
754
- )
755
- return MessageAssessment(**assessment)
756
- except Exception as e:
757
- self.logger.error(f"Failed to modify message assessment: {e}")
758
- raise e
592
+ return await modify_message_assessment_async(
593
+ user_id=self.user_id,
594
+ company_id=self.company_id,
595
+ assistant_message_id=assistant_message_id,
596
+ status=status,
597
+ type=type,
598
+ title=title,
599
+ explanation=explanation,
600
+ label=label,
601
+ )