unique_toolkit 0.5.55__py3-none-any.whl → 0.6.1__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.

Potentially problematic release.


This version of unique_toolkit might be problematic. Click here for more details.

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 +805 -0
  7. unique_toolkit/chat/schemas.py +11 -11
  8. unique_toolkit/chat/service.py +483 -432
  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 +229 -0
  26. unique_toolkit/language_model/service.py +76 -343
  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.1.dist-info}/METADATA +38 -8
  32. unique_toolkit-0.6.1.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.1.dist-info}/LICENSE +0 -0
  35. {unique_toolkit-0.5.55.dist-info → unique_toolkit-0.6.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,805 @@
1
+ import logging
2
+ import re
3
+ from typing import Any, Dict, List, cast
4
+
5
+ import unique_sdk
6
+ from unique_sdk._list_object import ListObject
7
+
8
+ from unique_toolkit._common import _time_utils
9
+ from unique_toolkit.chat.constants import DEFAULT_MAX_MESSAGES
10
+ from unique_toolkit.chat.schemas import (
11
+ ChatMessage,
12
+ ChatMessageAssessment,
13
+ ChatMessageAssessmentLabel,
14
+ ChatMessageAssessmentStatus,
15
+ ChatMessageAssessmentType,
16
+ ChatMessageRole,
17
+ )
18
+ from unique_toolkit.content.schemas import ContentChunk, ContentReference
19
+ from unique_toolkit.content.utils import count_tokens
20
+ from unique_toolkit.language_model.constants import (
21
+ DEFAULT_COMPLETE_TEMPERATURE,
22
+ DEFAULT_COMPLETE_TIMEOUT,
23
+ )
24
+ from unique_toolkit.language_model.functions import _prepare_completion_params_util
25
+ from unique_toolkit.language_model.infos import LanguageModelName
26
+ from unique_toolkit.language_model.schemas import (
27
+ LanguageModelMessages,
28
+ LanguageModelStreamResponse,
29
+ LanguageModelTool,
30
+ )
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+
35
+ def modify_message(
36
+ user_id: str,
37
+ company_id: str,
38
+ assistant_message_id: str,
39
+ chat_id: str,
40
+ user_message_id: str,
41
+ user_message_text: str,
42
+ assistant: bool,
43
+ content: str | None = None,
44
+ original_content: str | None = None,
45
+ references: list[ContentReference] | None = None,
46
+ debug_info: dict | None = None,
47
+ message_id: str | None = None,
48
+ set_completed_at: bool = False,
49
+ ) -> ChatMessage:
50
+ """
51
+ Modifies a chat message synchronously.
52
+
53
+ Args:
54
+ user_id (str): The user ID.
55
+ company_id (str): The company ID.
56
+ assistant_message_id (str): The assistant message ID.
57
+ chat_id (str): The chat ID.
58
+ user_message_id (str): The user message ID.
59
+ user_message_text (str): The user message text.
60
+ assistant (bool): Whether the message is an assistant message.
61
+ content (str, optional): The new content for the message.
62
+ original_content (str, optional): The original content for the message.
63
+ message_id (str, optional): The message ID. Defaults to None, then the ChatState assistant message id is used.
64
+ references (list[ContentReference]): list of ContentReference objects. Defaults to None.
65
+ debug_info (dict[str, Any]], optional): Debug information. Defaults to None.
66
+ set_completed_at (bool, optional): Whether to set the completedAt field with the current date time. Defaults to False.
67
+
68
+ Returns:
69
+ ChatMessage: The modified message.
70
+
71
+ Raises:
72
+ Exception: If the modification fails.
73
+ """
74
+ try:
75
+ params = _construct_message_modify_params(
76
+ user_id=user_id,
77
+ company_id=company_id,
78
+ assistant_message_id=assistant_message_id,
79
+ chat_id=chat_id,
80
+ user_message_id=user_message_id,
81
+ user_message_text=user_message_text,
82
+ assistant=assistant,
83
+ content=content,
84
+ original_content=original_content,
85
+ references=references,
86
+ debug_info=debug_info,
87
+ message_id=message_id,
88
+ set_completed_at=set_completed_at,
89
+ )
90
+ message = unique_sdk.Message.modify(**params)
91
+ return ChatMessage(**message)
92
+ except Exception as e:
93
+ logger.error(f"Failed to modify user message: {e}")
94
+ raise e
95
+
96
+
97
+ async def modify_message_async(
98
+ user_id: str,
99
+ company_id: str,
100
+ assistant_message_id: str,
101
+ chat_id: str,
102
+ user_message_id: str,
103
+ user_message_text: str,
104
+ assistant: bool,
105
+ content: str | None = None,
106
+ original_content: str | None = None,
107
+ references: list[ContentReference] | None = None,
108
+ debug_info: dict | None = None,
109
+ message_id: str | None = None,
110
+ set_completed_at: bool = False,
111
+ ) -> ChatMessage:
112
+ """
113
+ Modifies a chat message asynchronously.
114
+
115
+ Args:
116
+ user_id (str): The user ID.
117
+ company_id (str): The company ID.
118
+ assistant_message_id (str): The assistant message ID.
119
+ chat_id (str): The chat ID.
120
+ user_message_id (str): The user message ID.
121
+ user_message_text (str): The user message text.
122
+ assistant (bool): Whether the message is an assistant message.
123
+ content (str, optional): The new content for the message.
124
+ original_content (str, optional): The original content for the message.
125
+ message_id (str, optional): The message ID. Defaults to None, then the ChatState assistant message id is used.
126
+ references (list[ContentReference]): list of ContentReference objects. Defaults to None.
127
+ debug_info (dict[str, Any]], optional): Debug information. Defaults to None.
128
+ set_completed_at (bool, optional): Whether to set the completedAt field with the current date time. Defaults to False.
129
+
130
+ Returns:
131
+ ChatMessage: The modified message.
132
+
133
+ Raises:
134
+ Exception: If the modification fails.
135
+ """
136
+ try:
137
+ params = _construct_message_modify_params(
138
+ user_id=user_id,
139
+ company_id=company_id,
140
+ assistant_message_id=assistant_message_id,
141
+ chat_id=chat_id,
142
+ user_message_id=user_message_id,
143
+ user_message_text=user_message_text,
144
+ assistant=assistant,
145
+ content=content,
146
+ original_content=original_content,
147
+ references=references,
148
+ debug_info=debug_info,
149
+ message_id=message_id,
150
+ set_completed_at=set_completed_at,
151
+ )
152
+ message = await unique_sdk.Message.modify_async(**params)
153
+ return ChatMessage(**message)
154
+ except Exception as e:
155
+ logger.error(f"Failed to modify user message: {e}")
156
+ raise e
157
+
158
+
159
+ def map_references(references: List[ContentReference]) -> List[Dict[str, Any]]:
160
+ return [
161
+ {
162
+ "name": ref.name,
163
+ "url": ref.url,
164
+ "sequenceNumber": ref.sequence_number,
165
+ "sourceId": ref.source_id,
166
+ "source": ref.source,
167
+ }
168
+ for ref in references
169
+ ]
170
+
171
+
172
+ def _construct_message_modify_params(
173
+ user_id: str,
174
+ company_id: str,
175
+ assistant_message_id: str,
176
+ chat_id: str,
177
+ user_message_id: str,
178
+ user_message_text: str,
179
+ assistant: bool = True,
180
+ content: str | None = None,
181
+ original_content: str | None = None,
182
+ references: list[ContentReference] | None = None,
183
+ debug_info: dict | None = None,
184
+ message_id: str | None = None,
185
+ set_completed_at: bool = False,
186
+ ) -> Dict[str, Any]:
187
+ completed_at_datetime = None
188
+
189
+ if message_id:
190
+ # Message ID specified. No need to guess
191
+ message_id = message_id
192
+ elif assistant:
193
+ # Assistant message ID
194
+ message_id = assistant_message_id
195
+ else:
196
+ message_id = user_message_id
197
+ if content is None:
198
+ content = user_message_text
199
+
200
+ if set_completed_at:
201
+ completed_at_datetime = _time_utils.get_datetime_now()
202
+
203
+ params = {
204
+ "user_id": user_id,
205
+ "company_id": company_id,
206
+ "id": message_id,
207
+ "chatId": chat_id,
208
+ "text": content,
209
+ "originalText": original_content,
210
+ "references": map_references(references) if references else [],
211
+ "debugInfo": debug_info,
212
+ "completedAt": completed_at_datetime,
213
+ }
214
+ return params
215
+
216
+
217
+ def create_message(
218
+ user_id: str,
219
+ company_id: str,
220
+ chat_id: str,
221
+ assistant_id: str,
222
+ role: ChatMessageRole,
223
+ content: str | None = None,
224
+ original_content: str | None = None,
225
+ references: list[ContentReference] | None = None,
226
+ debug_info: dict | None = None,
227
+ set_completed_at: bool | None = False,
228
+ ):
229
+ """
230
+ Creates a message in the chat session synchronously.
231
+
232
+ Args:
233
+ user_id (str): The user ID.
234
+ company_id (str): The company ID.
235
+ chat_id (str): The chat ID.
236
+ assistant_id (str): The assistant ID.
237
+ role (ChatMessageRole): The role of the message.
238
+ content (str, optional): The content for the message. Defaults to None.
239
+ original_content (str, optional): The original content for the message. Defaults to None.
240
+ references (list[ContentReference], optional): list of ContentReference objects. Defaults to None.
241
+ debug_info (dict[str, Any]], optional): Debug information. Defaults to None.
242
+ set_completed_at (Optional[bool]): Whether to set the completedAt field with the current date time. Defaults to False.
243
+
244
+ Returns:
245
+ ChatMessage: The created message.
246
+
247
+ Raises:
248
+ Exception: If the creation fails.
249
+ """
250
+ if original_content is None:
251
+ original_content = content
252
+
253
+ try:
254
+ params = _construct_message_create_params(
255
+ user_id=user_id,
256
+ company_id=company_id,
257
+ chat_id=chat_id,
258
+ assistant_id=assistant_id,
259
+ role=role,
260
+ content=content,
261
+ original_content=original_content,
262
+ references=references,
263
+ debug_info=debug_info,
264
+ set_completed_at=set_completed_at,
265
+ )
266
+
267
+ message = unique_sdk.Message.create(**params)
268
+ return ChatMessage(**message)
269
+ except Exception as e:
270
+ logger.error(f"Failed to create assistant message: {e}")
271
+ raise e
272
+
273
+
274
+ async def create_message_async(
275
+ user_id: str,
276
+ company_id: str,
277
+ chat_id: str,
278
+ assistant_id: str,
279
+ role: ChatMessageRole,
280
+ content: str | None = None,
281
+ original_content: str | None = None,
282
+ references: list[ContentReference] | None = None,
283
+ debug_info: dict | None = None,
284
+ set_completed_at: bool | None = False,
285
+ ):
286
+ """
287
+ Creates a message in the chat session synchronously.
288
+
289
+ Args:
290
+ user_id (str): The user ID.
291
+ company_id (str): The company ID.
292
+ chat_id (str): The chat ID.
293
+ assistant_id (str): The assistant ID.
294
+ role (ChatMessageRole): The role of the message.
295
+ content (str, optional): The content for the message. Defaults to None.
296
+ original_content (str, optional): The original content for the message. Defaults to None.
297
+ references (list[ContentReference], optional): list of ContentReference objects. Defaults to None.
298
+ debug_info (dict[str, Any]], optional): Debug information. Defaults to None.
299
+ set_completed_at (Optional[bool]): Whether to set the completedAt field with the current date time. Defaults to False.
300
+
301
+ Returns:
302
+ ChatMessage: The created message.
303
+
304
+ Raises:
305
+ Exception: If the creation fails.
306
+ """
307
+ if original_content is None:
308
+ original_content = content
309
+
310
+ try:
311
+ params = _construct_message_create_params(
312
+ user_id=user_id,
313
+ company_id=company_id,
314
+ chat_id=chat_id,
315
+ assistant_id=assistant_id,
316
+ role=role,
317
+ content=content,
318
+ original_content=original_content,
319
+ references=references,
320
+ debug_info=debug_info,
321
+ set_completed_at=set_completed_at,
322
+ )
323
+
324
+ message = await unique_sdk.Message.create_async(**params)
325
+ return ChatMessage(**message)
326
+ except Exception as e:
327
+ logger.error(f"Failed to create assistant message: {e}")
328
+ raise e
329
+
330
+
331
+ def _construct_message_create_params(
332
+ user_id: str,
333
+ company_id: str,
334
+ chat_id: str,
335
+ assistant_id: str,
336
+ role: ChatMessageRole,
337
+ content: str | None = None,
338
+ original_content: str | None = None,
339
+ references: list[ContentReference] | None = None,
340
+ debug_info: dict | None = None,
341
+ set_completed_at: bool | None = False,
342
+ ) -> Dict[str, Any]:
343
+ if original_content is None:
344
+ original_content = content
345
+
346
+ return {
347
+ "user_id": user_id,
348
+ "company_id": company_id,
349
+ "assistantId": assistant_id,
350
+ "role": role.value.upper(),
351
+ "chatId": chat_id,
352
+ "text": content,
353
+ "originalText": original_content,
354
+ "references": map_references(references) if references else [],
355
+ "debugInfo": debug_info,
356
+ "completedAt": _time_utils.get_datetime_now() if set_completed_at else None,
357
+ }
358
+
359
+
360
+ def get_selection_from_history(
361
+ full_history: list[ChatMessage],
362
+ max_tokens: int,
363
+ max_messages=DEFAULT_MAX_MESSAGES,
364
+ ) -> List[ChatMessage]:
365
+ messages = full_history[-max_messages:]
366
+ filtered_messages = [m for m in messages if m.content]
367
+ mapped_messages = []
368
+
369
+ for m in filtered_messages:
370
+ m.content = re.sub(r"<sup>\d+</sup>", "", m.content or "")
371
+ m.role = (
372
+ ChatMessageRole.ASSISTANT
373
+ if m.role == ChatMessageRole.ASSISTANT
374
+ else ChatMessageRole.USER
375
+ )
376
+ mapped_messages.append(m)
377
+
378
+ return pick_messages_in_reverse_for_token_window(
379
+ messages=mapped_messages,
380
+ limit=max_tokens,
381
+ )
382
+
383
+
384
+ def map_to_chat_messages(messages: list[dict]) -> List[ChatMessage]:
385
+ return [ChatMessage(**msg) for msg in messages]
386
+
387
+
388
+ def pick_messages_in_reverse_for_token_window(
389
+ messages: list[ChatMessage],
390
+ limit: int,
391
+ ) -> List[ChatMessage]:
392
+ if len(messages) < 1 or limit < 1:
393
+ return []
394
+
395
+ last_index = len(messages) - 1
396
+ token_count = count_tokens(messages[last_index].content or "")
397
+ while token_count > limit:
398
+ logger.debug(
399
+ f"Limit too low for the initial message. Last message TokenCount {token_count} available tokens {limit} - cutting message in half until it fits"
400
+ )
401
+ content = messages[last_index].content or ""
402
+ messages[last_index].content = content[: len(content) // 2] + "..."
403
+ token_count = count_tokens(messages[last_index].content or "")
404
+
405
+ while token_count <= limit and last_index > 0:
406
+ token_count = count_tokens(
407
+ "".join([msg.content or "" for msg in messages[:last_index]])
408
+ )
409
+ if token_count <= limit:
410
+ last_index -= 1
411
+
412
+ last_index = max(0, last_index)
413
+ return messages[last_index:]
414
+
415
+
416
+ def list_messages(
417
+ event_user_id, event_company_id, chat_id: str
418
+ ) -> ListObject[unique_sdk.Message]:
419
+ try:
420
+ messages = unique_sdk.Message.list(
421
+ user_id=event_user_id,
422
+ company_id=event_company_id,
423
+ chatId=chat_id,
424
+ )
425
+ return messages
426
+ except Exception as e:
427
+ logger.error(f"Failed to list chat history: {e}")
428
+ raise e
429
+
430
+
431
+ async def list_messages_async(
432
+ event_user_id: str, event_company_id: str, chat_id: str
433
+ ) -> ListObject[unique_sdk.Message]:
434
+ try:
435
+ messages = await unique_sdk.Message.list_async(
436
+ user_id=event_user_id,
437
+ company_id=event_company_id,
438
+ chatId=chat_id,
439
+ )
440
+ return messages
441
+ except Exception as e:
442
+ logger.error(f"Failed to list chat history: {e}")
443
+ raise e
444
+
445
+
446
+ def get_full_history(
447
+ event_user_id, event_company_id, event_payload_chat_id
448
+ ) -> List[ChatMessage]:
449
+ messages = list_messages(event_user_id, event_company_id, event_payload_chat_id)
450
+ messages = filter_valid_messages(messages)
451
+
452
+ return map_to_chat_messages(messages)
453
+
454
+
455
+ async def get_full_history_async(
456
+ event_user_id, event_company_id, event_payload_chat_id
457
+ ) -> List[ChatMessage]:
458
+ messages = await list_messages_async(
459
+ event_user_id, event_company_id, event_payload_chat_id
460
+ )
461
+ messages = filter_valid_messages(messages)
462
+
463
+ return map_to_chat_messages(messages)
464
+
465
+
466
+ def filter_valid_messages(
467
+ messages: ListObject[unique_sdk.Message],
468
+ ) -> List[Dict[str, Any]]:
469
+ SYSTEM_MESSAGE_PREFIX = "[SYSTEM] "
470
+
471
+ # Remove the last two messages
472
+ messages = messages["data"][:-2] # type: ignore
473
+ filtered_messages = []
474
+ for message in messages:
475
+ if message["text"] is None:
476
+ continue
477
+ elif SYSTEM_MESSAGE_PREFIX in message["text"]:
478
+ continue
479
+ else:
480
+ filtered_messages.append(message)
481
+
482
+ return filtered_messages
483
+
484
+
485
+ def create_message_assessment(
486
+ user_id: str,
487
+ company_id: str,
488
+ assistant_message_id: str,
489
+ status: ChatMessageAssessmentStatus,
490
+ type: ChatMessageAssessmentType,
491
+ title: str | None = None,
492
+ explanation: str | None = None,
493
+ label: ChatMessageAssessmentLabel | None = None,
494
+ is_visible: bool = True,
495
+ ) -> ChatMessageAssessment:
496
+ """
497
+ Creates a message assessment for an assistant message synchronously.
498
+
499
+ Args:
500
+ user_id (str): The user ID.
501
+ company_id (str): The company ID.
502
+ assistant_message_id (str): The ID of the assistant message to assess
503
+ status (ChatMessageAssessmentStatus): The status of the assessment (e.g. "DONE")
504
+ type (ChatMessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
505
+ title (str | None): The title of the assessment
506
+ explanation (str | None): Explanation of the assessment
507
+ label (ChatMessageAssessmentLabel | None): The assessment label (e.g. "NEGATIVE")
508
+ is_visible (bool): Whether the assessment is visible to users. Defaults to True.
509
+
510
+ Returns:
511
+ ChatMessageAssessment: The created message assessment
512
+
513
+ Raises:
514
+ Exception: If the creation fails
515
+ """
516
+ try:
517
+ assessment = unique_sdk.MessageAssessment.create(
518
+ user_id=user_id,
519
+ company_id=company_id,
520
+ messageId=assistant_message_id,
521
+ status=status.name,
522
+ explanation=explanation,
523
+ label=label.name if label else None,
524
+ title=title,
525
+ type=type.name,
526
+ isVisible=is_visible,
527
+ )
528
+ return ChatMessageAssessment(**assessment)
529
+ except Exception as e:
530
+ logger.error(f"Failed to create message assessment: {e}")
531
+ raise e
532
+
533
+
534
+ async def create_message_assessment_async(
535
+ user_id: str,
536
+ company_id: str,
537
+ assistant_message_id: str,
538
+ status: ChatMessageAssessmentStatus,
539
+ type: ChatMessageAssessmentType,
540
+ title: str | None = None,
541
+ explanation: str | None = None,
542
+ label: ChatMessageAssessmentLabel | None = None,
543
+ is_visible: bool = True,
544
+ ) -> ChatMessageAssessment:
545
+ """
546
+ Creates a message assessment for an assistant message asynchronously.
547
+
548
+ Args:
549
+ user_id (str): The user ID.
550
+ company_id (str): The company ID.
551
+ assistant_message_id (str): The ID of the assistant message to assess
552
+ status (ChatMessageAssessmentStatus): The status of the assessment (e.g. "DONE")
553
+ type (ChatMessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
554
+ title (str | None): The title of the assessment
555
+ explanation (str | None): Explanation of the assessment
556
+ label (ChatMessageAssessmentLabel | None): The assessment label (e.g. "NEGATIVE")
557
+ is_visible (bool): Whether the assessment is visible to users. Defaults to True.
558
+
559
+ Returns:
560
+ MessageAssessment: The created message assessment
561
+
562
+ Raises:
563
+ Exception: If the creation fails
564
+ """
565
+ try:
566
+ assessment = await unique_sdk.MessageAssessment.create_async(
567
+ user_id=user_id,
568
+ company_id=company_id,
569
+ messageId=assistant_message_id,
570
+ status=status.name,
571
+ explanation=explanation,
572
+ label=label.name if label else None,
573
+ title=title,
574
+ type=type.name,
575
+ isVisible=is_visible,
576
+ )
577
+ return ChatMessageAssessment(**assessment)
578
+ except Exception as e:
579
+ logger.error(f"Failed to create message assessment: {e}")
580
+ raise e
581
+
582
+
583
+ def modify_message_assessment(
584
+ user_id: str,
585
+ company_id: str,
586
+ assistant_message_id: str,
587
+ status: ChatMessageAssessmentStatus,
588
+ type: ChatMessageAssessmentType,
589
+ title: str | None = None,
590
+ explanation: str | None = None,
591
+ label: ChatMessageAssessmentLabel | None = None,
592
+ ) -> ChatMessageAssessment:
593
+ """
594
+ Modifies a message assessment for an assistant message synchronously.
595
+
596
+ Args:
597
+ user_id (str): The user ID.
598
+ company_id (str): The company ID.
599
+ assistant_message_id (str): The ID of the assistant message to assess
600
+ status (MessageAssessmentStatus): The status of the assessment (e.g. "DONE")
601
+ title (str | None): The title of the assessment
602
+ explanation (str | None): Explanation of the assessment
603
+ label (ChatMessageAssessmentLabel | None): The assessment label (e.g. "NEGATIVE")
604
+ type (ChatMessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
605
+
606
+ Returns:
607
+ dict: The modified message assessment
608
+
609
+ Raises:
610
+ Exception: If the modification fails
611
+ """
612
+ try:
613
+ assessment = unique_sdk.MessageAssessment.modify(
614
+ user_id=user_id,
615
+ company_id=company_id,
616
+ messageId=assistant_message_id,
617
+ status=status.name,
618
+ title=title,
619
+ explanation=explanation,
620
+ label=label.name if label else None,
621
+ type=type.name,
622
+ )
623
+ return ChatMessageAssessment(**assessment)
624
+ except Exception as e:
625
+ logger.error(f"Failed to modify message assessment: {e}")
626
+ raise e
627
+
628
+
629
+ async def modify_message_assessment_async(
630
+ user_id: str,
631
+ company_id: str,
632
+ assistant_message_id: str,
633
+ type: ChatMessageAssessmentType,
634
+ title: str | None = None,
635
+ status: ChatMessageAssessmentStatus | None = None,
636
+ explanation: str | None = None,
637
+ label: ChatMessageAssessmentLabel | None = None,
638
+ ) -> ChatMessageAssessment:
639
+ """
640
+ Modifies a message assessment for an assistant message asynchronously.
641
+
642
+ Args:
643
+ user_id (str): The user ID.
644
+ company_id (str): The company ID.
645
+ assistant_message_id (str): The ID of the assistant message to assess
646
+ type (MessageAssessmentType): The type of assessment (e.g. "HALLUCINATION")
647
+ title (str | None): The title of the assessment
648
+ status (MessageAssessmentStatus): The status of the assessment (e.g. "DONE")
649
+ explanation (str | None): Explanation of the assessment
650
+ label (MessageAssessmentLabel | None): The assessment label (e.g. "NEGATIVE")
651
+
652
+ Returns:
653
+ MessageAssessment: The modified message assessment
654
+
655
+ Raises:
656
+ Exception: If the modification fails
657
+ """
658
+ try:
659
+ assessment = await unique_sdk.MessageAssessment.modify_async(
660
+ user_id=user_id,
661
+ company_id=company_id,
662
+ messageId=assistant_message_id,
663
+ status=status.name if status else None,
664
+ title=title,
665
+ explanation=explanation,
666
+ label=label.name if label else None,
667
+ type=type.name,
668
+ )
669
+ return ChatMessageAssessment(**assessment)
670
+ except Exception as e:
671
+ logger.error(f"Failed to modify message assessment: {e}")
672
+ raise e
673
+
674
+
675
+ def stream_complete_to_chat(
676
+ company_id: str,
677
+ user_id: str,
678
+ assistant_message_id: str,
679
+ user_message_id: str,
680
+ chat_id: str,
681
+ assistant_id: str,
682
+ messages: LanguageModelMessages,
683
+ model_name: LanguageModelName | str,
684
+ content_chunks: list[ContentChunk] = [],
685
+ debug_info: dict = {},
686
+ temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
687
+ timeout: int = DEFAULT_COMPLETE_TIMEOUT,
688
+ tools: list[LanguageModelTool] | None = None,
689
+ start_text: str | None = None,
690
+ other_options: dict | None = None,
691
+ ) -> LanguageModelStreamResponse:
692
+ """
693
+ Streams a completion synchronously.
694
+
695
+ Args:
696
+ company_id (str): The company ID associated with the request.
697
+ user_id (str): The user ID for the request.
698
+ assistant_message_id (str): The assistant message ID.
699
+ user_message_id (str): The user message ID.
700
+ chat_id (str): The chat ID.
701
+ assistant_id (str): The assistant ID.
702
+ messages (LanguageModelMessages): The messages to complete.
703
+ model_name (LanguageModelName | str): The model name.
704
+ content_chunks (list[ContentChunk]): Content chunks for context.
705
+ debug_info (dict): Debug information.
706
+ temperature (float): Temperature setting.
707
+ timeout (int): Timeout in milliseconds.
708
+ tools (Optional[list[LanguageModelTool]]): Optional tools.
709
+ start_text (Optional[str]): Starting text.
710
+ other_options (Optional[dict]): Additional options.
711
+
712
+ Returns:
713
+ LanguageModelStreamResponse: The streaming response object.
714
+ """
715
+ options, model, messages_dict, search_context = _prepare_completion_params_util(
716
+ messages=messages,
717
+ model_name=model_name,
718
+ temperature=temperature,
719
+ tools=tools,
720
+ other_options=other_options,
721
+ content_chunks=content_chunks,
722
+ )
723
+
724
+ try:
725
+ response = unique_sdk.Integrated.chat_stream_completion(
726
+ user_id=user_id,
727
+ company_id=company_id,
728
+ assistantMessageId=assistant_message_id,
729
+ userMessageId=user_message_id,
730
+ messages=cast(
731
+ list[unique_sdk.Integrated.ChatCompletionRequestMessage],
732
+ messages_dict,
733
+ ),
734
+ chatId=chat_id,
735
+ searchContext=search_context,
736
+ model=model,
737
+ timeout=timeout,
738
+ assistantId=assistant_id,
739
+ debugInfo=debug_info,
740
+ options=options, # type: ignore
741
+ startText=start_text,
742
+ )
743
+ return LanguageModelStreamResponse(**response)
744
+ except Exception as e:
745
+ logger.error(f"Error streaming completion: {e}")
746
+ raise e
747
+
748
+
749
+ async def stream_complete_to_chat_async(
750
+ company_id: str,
751
+ user_id: str,
752
+ assistant_message_id: str,
753
+ user_message_id: str,
754
+ chat_id: str,
755
+ assistant_id: str,
756
+ messages: LanguageModelMessages,
757
+ model_name: LanguageModelName | str,
758
+ content_chunks: list[ContentChunk] = [],
759
+ debug_info: dict = {},
760
+ temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
761
+ timeout: int = DEFAULT_COMPLETE_TIMEOUT,
762
+ tools: list[LanguageModelTool] | None = None,
763
+ start_text: str | None = None,
764
+ other_options: dict | None = None,
765
+ ) -> LanguageModelStreamResponse:
766
+ """
767
+ Streams a completion asynchronously.
768
+
769
+ Args: [same as stream_complete]
770
+
771
+ Returns:
772
+ LanguageModelStreamResponse: The streaming response object.
773
+ """
774
+ options, model, messages_dict, search_context = _prepare_completion_params_util(
775
+ messages=messages,
776
+ model_name=model_name,
777
+ temperature=temperature,
778
+ tools=tools,
779
+ other_options=other_options,
780
+ content_chunks=content_chunks,
781
+ )
782
+
783
+ try:
784
+ response = await unique_sdk.Integrated.chat_stream_completion_async(
785
+ user_id=user_id,
786
+ company_id=company_id,
787
+ assistantMessageId=assistant_message_id,
788
+ userMessageId=user_message_id,
789
+ messages=cast(
790
+ list[unique_sdk.Integrated.ChatCompletionRequestMessage],
791
+ messages_dict,
792
+ ),
793
+ chatId=chat_id,
794
+ searchContext=search_context,
795
+ model=model,
796
+ timeout=timeout,
797
+ assistantId=assistant_id,
798
+ debugInfo=debug_info,
799
+ options=options, # type: ignore
800
+ startText=start_text,
801
+ )
802
+ return LanguageModelStreamResponse(**response)
803
+ except Exception as e:
804
+ logger.error(f"Error streaming completion: {e}")
805
+ raise e