unique_toolkit 1.8.1__py3-none-any.whl → 1.23.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.

Potentially problematic release.


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

Files changed (105) hide show
  1. unique_toolkit/__init__.py +20 -0
  2. unique_toolkit/_common/api_calling/human_verification_manager.py +121 -28
  3. unique_toolkit/_common/chunk_relevancy_sorter/config.py +3 -3
  4. unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +2 -5
  5. unique_toolkit/_common/default_language_model.py +9 -3
  6. unique_toolkit/_common/docx_generator/__init__.py +7 -0
  7. unique_toolkit/_common/docx_generator/config.py +12 -0
  8. unique_toolkit/_common/docx_generator/schemas.py +80 -0
  9. unique_toolkit/_common/docx_generator/service.py +252 -0
  10. unique_toolkit/_common/docx_generator/template/Doc Template.docx +0 -0
  11. unique_toolkit/_common/endpoint_builder.py +138 -117
  12. unique_toolkit/_common/endpoint_requestor.py +240 -14
  13. unique_toolkit/_common/exception.py +20 -0
  14. unique_toolkit/_common/feature_flags/schema.py +1 -5
  15. unique_toolkit/_common/referencing.py +53 -0
  16. unique_toolkit/_common/string_utilities.py +52 -1
  17. unique_toolkit/_common/tests/test_referencing.py +521 -0
  18. unique_toolkit/_common/tests/test_string_utilities.py +506 -0
  19. unique_toolkit/_common/utils/files.py +43 -0
  20. unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +16 -6
  21. unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py +278 -0
  22. unique_toolkit/agentic/evaluation/config.py +3 -2
  23. unique_toolkit/agentic/evaluation/context_relevancy/service.py +2 -2
  24. unique_toolkit/agentic/evaluation/evaluation_manager.py +9 -5
  25. unique_toolkit/agentic/evaluation/hallucination/constants.py +1 -1
  26. unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +26 -3
  27. unique_toolkit/agentic/history_manager/history_manager.py +14 -11
  28. unique_toolkit/agentic/history_manager/loop_token_reducer.py +3 -4
  29. unique_toolkit/agentic/history_manager/utils.py +10 -87
  30. unique_toolkit/agentic/postprocessor/postprocessor_manager.py +107 -16
  31. unique_toolkit/agentic/reference_manager/reference_manager.py +1 -1
  32. unique_toolkit/agentic/responses_api/__init__.py +19 -0
  33. unique_toolkit/agentic/responses_api/postprocessors/code_display.py +63 -0
  34. unique_toolkit/agentic/responses_api/postprocessors/generated_files.py +145 -0
  35. unique_toolkit/agentic/responses_api/stream_handler.py +15 -0
  36. unique_toolkit/agentic/tools/a2a/__init__.py +18 -2
  37. unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +2 -0
  38. unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +3 -3
  39. unique_toolkit/agentic/tools/a2a/evaluation/config.py +1 -1
  40. unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +143 -91
  41. unique_toolkit/agentic/tools/a2a/manager.py +7 -1
  42. unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +11 -3
  43. unique_toolkit/agentic/tools/a2a/postprocessing/_display_utils.py +185 -0
  44. unique_toolkit/agentic/tools/a2a/postprocessing/_ref_utils.py +73 -0
  45. unique_toolkit/agentic/tools/a2a/postprocessing/config.py +21 -0
  46. unique_toolkit/agentic/tools/a2a/postprocessing/display.py +180 -0
  47. unique_toolkit/agentic/tools/a2a/postprocessing/references.py +101 -0
  48. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display_utils.py +1335 -0
  49. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_ref_utils.py +603 -0
  50. unique_toolkit/agentic/tools/a2a/prompts.py +46 -0
  51. unique_toolkit/agentic/tools/a2a/response_watcher/__init__.py +6 -0
  52. unique_toolkit/agentic/tools/a2a/response_watcher/service.py +91 -0
  53. unique_toolkit/agentic/tools/a2a/tool/config.py +15 -5
  54. unique_toolkit/agentic/tools/a2a/tool/service.py +69 -36
  55. unique_toolkit/agentic/tools/config.py +16 -2
  56. unique_toolkit/agentic/tools/factory.py +4 -0
  57. unique_toolkit/agentic/tools/mcp/tool_wrapper.py +7 -35
  58. unique_toolkit/agentic/tools/openai_builtin/__init__.py +11 -0
  59. unique_toolkit/agentic/tools/openai_builtin/base.py +30 -0
  60. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py +8 -0
  61. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py +57 -0
  62. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py +230 -0
  63. unique_toolkit/agentic/tools/openai_builtin/manager.py +62 -0
  64. unique_toolkit/agentic/tools/test/test_mcp_manager.py +95 -7
  65. unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +240 -0
  66. unique_toolkit/agentic/tools/tool.py +0 -11
  67. unique_toolkit/agentic/tools/tool_manager.py +337 -122
  68. unique_toolkit/agentic/tools/tool_progress_reporter.py +81 -15
  69. unique_toolkit/agentic/tools/utils/__init__.py +18 -0
  70. unique_toolkit/agentic/tools/utils/execution/execution.py +8 -4
  71. unique_toolkit/agentic/tools/utils/source_handling/schema.py +1 -1
  72. unique_toolkit/chat/__init__.py +8 -1
  73. unique_toolkit/chat/deprecated/service.py +232 -0
  74. unique_toolkit/chat/functions.py +54 -40
  75. unique_toolkit/chat/rendering.py +34 -0
  76. unique_toolkit/chat/responses_api.py +461 -0
  77. unique_toolkit/chat/schemas.py +1 -1
  78. unique_toolkit/chat/service.py +96 -1569
  79. unique_toolkit/content/functions.py +116 -1
  80. unique_toolkit/content/schemas.py +59 -0
  81. unique_toolkit/content/service.py +5 -37
  82. unique_toolkit/content/smart_rules.py +301 -0
  83. unique_toolkit/framework_utilities/langchain/client.py +27 -3
  84. unique_toolkit/framework_utilities/openai/client.py +12 -1
  85. unique_toolkit/framework_utilities/openai/message_builder.py +85 -1
  86. unique_toolkit/language_model/default_language_model.py +3 -0
  87. unique_toolkit/language_model/functions.py +25 -9
  88. unique_toolkit/language_model/infos.py +72 -4
  89. unique_toolkit/language_model/schemas.py +246 -40
  90. unique_toolkit/protocols/support.py +91 -9
  91. unique_toolkit/services/__init__.py +7 -0
  92. unique_toolkit/services/chat_service.py +1630 -0
  93. unique_toolkit/services/knowledge_base.py +861 -0
  94. unique_toolkit/smart_rules/compile.py +56 -301
  95. unique_toolkit/test_utilities/events.py +197 -0
  96. {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/METADATA +173 -3
  97. {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/RECORD +99 -67
  98. unique_toolkit/agentic/tools/a2a/postprocessing/_display.py +0 -122
  99. unique_toolkit/agentic/tools/a2a/postprocessing/_utils.py +0 -19
  100. unique_toolkit/agentic/tools/a2a/postprocessing/postprocessor.py +0 -230
  101. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_consolidate_references.py +0 -665
  102. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display.py +0 -391
  103. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_postprocessor_reference_functions.py +0 -256
  104. {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/LICENSE +0 -0
  105. {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/WHEEL +0 -0
@@ -16,7 +16,7 @@ P = ParamSpec("P")
16
16
  R = TypeVar("R")
17
17
 
18
18
 
19
- logger = logging.getLogger(__name__)
19
+ _logger = logging.getLogger(__name__)
20
20
 
21
21
 
22
22
  class Result(Generic[R]):
@@ -87,7 +87,7 @@ class SafeTaskExecutor:
87
87
  self._ignored_exceptions = tuple(ignored_exceptions)
88
88
  self._log_exceptions = log_exceptions
89
89
  self._log_exc_info = log_exc_info
90
- self._logger = logger
90
+ self._logger = logger or _logger
91
91
 
92
92
  def execute(
93
93
  self, f: Callable[P, R], *args: P.args, **kwargs: P.kwargs
@@ -98,7 +98,9 @@ class SafeTaskExecutor:
98
98
  if isinstance(e, self._ignored_exceptions):
99
99
  raise e
100
100
  if self._log_exceptions:
101
- logger.error(f"Error in {f.__name__}: {e}", exc_info=self._log_exc_info)
101
+ self._logger.error(
102
+ f"Error in {f.__name__}: {e}", exc_info=self._log_exc_info
103
+ )
102
104
  return Result(False, exception=e)
103
105
 
104
106
  async def execute_async(
@@ -110,7 +112,9 @@ class SafeTaskExecutor:
110
112
  if isinstance(e, self._ignored_exceptions):
111
113
  raise e
112
114
  if self._log_exceptions:
113
- logger.error(f"Error in {f.__name__}: {e}", exc_info=self._log_exc_info)
115
+ self._logger.error(
116
+ f"Error in {f.__name__}: {e}", exc_info=self._log_exc_info
117
+ )
114
118
  return Result(False, exception=e)
115
119
 
116
120
 
@@ -1,7 +1,7 @@
1
1
  # default schema follows logic in node-ingestion-worker: https://github.com/Unique-AG/monorepo/blob/76b4923611199a80abf9304639b3aa0538ec41ed/node/apps/node-ingestion-worker/src/ingestors/lib/text-manipulations.ts#L181C17-L181C28
2
2
  from pydantic import BaseModel
3
3
 
4
- from unique_toolkit.agentic.tools.config import get_configuration_dict
4
+ from unique_toolkit._common.pydantic_helpers import get_configuration_dict
5
5
 
6
6
  SOURCE_TEMPLATE = "<source${index}>${document}${info}${text}</source${index}>"
7
7
  SECTIONS = {
@@ -1,3 +1,5 @@
1
+ import warnings
2
+
1
3
  from .constants import DOMAIN_NAME as DOMAIN_NAME
2
4
  from .schemas import ChatMessage as ChatMessage
3
5
  from .schemas import ChatMessageAssessment as ChatMessageAssessment
@@ -5,7 +7,12 @@ from .schemas import ChatMessageAssessmentLabel as ChatMessageAssessmentLabel
5
7
  from .schemas import ChatMessageAssessmentStatus as ChatMessageAssessmentStatus
6
8
  from .schemas import ChatMessageAssessmentType as ChatMessageAssessmentType
7
9
  from .schemas import ChatMessageRole as ChatMessageRole
8
- from .service import ChatService as ChatService
10
+
11
+ # Import ChatService with deprecation warning suppressed for internal use
12
+ with warnings.catch_warnings():
13
+ warnings.simplefilter("ignore", DeprecationWarning)
14
+ from .service import ChatService as ChatService
15
+
9
16
  from .utils import (
10
17
  convert_chat_history_to_injectable_string as convert_chat_history_to_injectable_string,
11
18
  )
@@ -0,0 +1,232 @@
1
+ from typing_extensions import deprecated
2
+
3
+ from unique_toolkit.app.schemas import ChatEvent, Event
4
+ from unique_toolkit.chat.functions import (
5
+ modify_message,
6
+ )
7
+
8
+
9
+ class ChatServiceDeprecated:
10
+ def __init__(self, event: ChatEvent | Event):
11
+ self._event = event
12
+ self._company_id: str = event.company_id
13
+ self._user_id: str = event.user_id
14
+ self._assistant_message_id: str = event.payload.assistant_message.id
15
+ self._user_message_id: str = event.payload.user_message.id
16
+ self._chat_id: str = event.payload.chat_id
17
+ self._assistant_id: str = event.payload.assistant_id
18
+ self._user_message_text: str = event.payload.user_message.text
19
+
20
+ @property
21
+ @deprecated(
22
+ "The event property is deprecated and will be removed in a future version.",
23
+ )
24
+ def event(self) -> Event | ChatEvent:
25
+ """Get the event object (deprecated).
26
+
27
+ Returns:
28
+ Event | BaseEvent | None: The event object.
29
+
30
+ """
31
+ return self._event
32
+
33
+ @property
34
+ @deprecated(
35
+ "The company_id property is deprecated and will be removed in a future version.",
36
+ )
37
+ def company_id(self) -> str:
38
+ """Get the company identifier (deprecated).
39
+
40
+ Returns:
41
+ str | None: The company identifier.
42
+
43
+ """
44
+ return self._company_id
45
+
46
+ @company_id.setter
47
+ @deprecated(
48
+ "The company_id setter is deprecated and will be removed in a future version.",
49
+ )
50
+ def company_id(self, value: str) -> None:
51
+ """Set the company identifier (deprecated).
52
+
53
+ Args:
54
+ value (str | None): The company identifier.
55
+
56
+ """
57
+ self._company_id = value
58
+
59
+ @property
60
+ @deprecated(
61
+ "The user_id property is deprecated and will be removed in a future version.",
62
+ )
63
+ def user_id(self) -> str:
64
+ """Get the user identifier (deprecated).
65
+
66
+ Returns:
67
+ str | None: The user identifier.
68
+
69
+ """
70
+ return self._user_id
71
+
72
+ @user_id.setter
73
+ @deprecated(
74
+ "The user_id setter is deprecated and will be removed in a future version.",
75
+ )
76
+ def user_id(self, value: str) -> None:
77
+ """Set the user identifier (deprecated).
78
+
79
+ Args:
80
+ value (str | None): The user identifier.
81
+
82
+ """
83
+ self._user_id = value
84
+
85
+ @property
86
+ @deprecated(
87
+ "The assistant_message_id property is deprecated and will be removed in a future version.",
88
+ )
89
+ def assistant_message_id(self) -> str:
90
+ """Get the assistant message identifier (deprecated).
91
+
92
+ Returns:
93
+ str | None: The assistant message identifier.
94
+
95
+ """
96
+ return self._assistant_message_id
97
+
98
+ @assistant_message_id.setter
99
+ @deprecated(
100
+ "The assistant_message_id setter is deprecated and will be removed in a future version.",
101
+ )
102
+ def assistant_message_id(self, value: str) -> None:
103
+ """Set the assistant message identifier (deprecated).
104
+
105
+ Args:
106
+ value (str | None): The assistant message identifier.
107
+
108
+ """
109
+ self._assistant_message_id = value
110
+
111
+ @property
112
+ @deprecated(
113
+ "The user_message_id property is deprecated and will be removed in a future version.",
114
+ )
115
+ def user_message_id(self) -> str:
116
+ """Get the user message identifier (deprecated).
117
+
118
+ Returns:
119
+ str | None: The user message identifier.
120
+
121
+ """
122
+ return self._user_message_id
123
+
124
+ @user_message_id.setter
125
+ @deprecated(
126
+ "The user_message_id setter is deprecated and will be removed in a future version.",
127
+ )
128
+ def user_message_id(self, value: str) -> None:
129
+ """Set the user message identifier (deprecated).
130
+
131
+ Args:
132
+ value (str | None): The user message identifier.
133
+
134
+ """
135
+ self._user_message_id = value
136
+
137
+ @property
138
+ @deprecated(
139
+ "The chat_id property is deprecated and will be removed in a future version.",
140
+ )
141
+ def chat_id(self) -> str:
142
+ """Get the chat identifier (deprecated).
143
+
144
+ Returns:
145
+ str | None: The chat identifier.
146
+
147
+ """
148
+ return self._chat_id
149
+
150
+ @chat_id.setter
151
+ @deprecated(
152
+ "The chat_id setter is deprecated and will be removed in a future version.",
153
+ )
154
+ def chat_id(self, value: str) -> None:
155
+ """Set the chat identifier (deprecated).
156
+
157
+ Args:
158
+ value (str | None): The chat identifier.
159
+
160
+ """
161
+ self._chat_id = value
162
+
163
+ @property
164
+ @deprecated(
165
+ "The assistant_id property is deprecated and will be removed in a future version.",
166
+ )
167
+ def assistant_id(self) -> str:
168
+ """Get the assistant identifier (deprecated).
169
+
170
+ Returns:
171
+ str | None: The assistant identifier.
172
+
173
+ """
174
+ return self._assistant_id
175
+
176
+ @assistant_id.setter
177
+ @deprecated(
178
+ "The assistant_id setter is deprecated and will be removed in a future version.",
179
+ )
180
+ def assistant_id(self, value: str) -> None:
181
+ """Set the assistant identifier (deprecated).
182
+
183
+ Args:
184
+ value (str | None): The assistant identifier.
185
+
186
+ """
187
+ self._assistant_id = value
188
+
189
+ @property
190
+ @deprecated(
191
+ "The user_message_text property is deprecated and will be removed in a future version.",
192
+ )
193
+ def user_message_text(self) -> str:
194
+ """Get the user message text (deprecated).
195
+
196
+ Returns:
197
+ str | None: The user message text.
198
+
199
+ """
200
+ return self._user_message_text
201
+
202
+ @user_message_text.setter
203
+ @deprecated(
204
+ "The user_message_text setter is deprecated and will be removed in a future version.",
205
+ )
206
+ def user_message_text(self, value: str) -> None:
207
+ """Set the user message text (deprecated).
208
+
209
+ Args:
210
+ value (str | None): The user message text.
211
+
212
+ """
213
+ self._user_message_text = value
214
+
215
+ @deprecated("Use `replace_debug_info`")
216
+ def update_debug_info(self, debug_info: dict):
217
+ """Updates the debug information for the chat session.
218
+
219
+ Args:
220
+ debug_info (dict): The new debug information.
221
+
222
+ """
223
+ return modify_message(
224
+ user_id=self._user_id,
225
+ company_id=self._company_id,
226
+ assistant_message_id=self._assistant_message_id,
227
+ chat_id=self._chat_id,
228
+ user_message_id=self._user_message_id,
229
+ user_message_text=self._user_message_text,
230
+ assistant=False,
231
+ debug_info=debug_info,
232
+ )
@@ -1,13 +1,18 @@
1
1
  import logging
2
2
  import re
3
- from typing import Any
3
+ from typing import Any, Sequence
4
4
 
5
5
  import unique_sdk
6
+ from openai.types.chat import ChatCompletionToolChoiceOptionParam
7
+ from openai.types.chat.chat_completion_message_param import ChatCompletionMessageParam
8
+ from pydantic import BaseModel
6
9
  from typing_extensions import deprecated
7
10
  from unique_sdk._list_object import ListObject
8
11
 
9
12
  from unique_toolkit._common import _time_utils
10
- from unique_toolkit.chat.constants import DEFAULT_MAX_MESSAGES
13
+ from unique_toolkit.chat.constants import (
14
+ DEFAULT_MAX_MESSAGES,
15
+ )
11
16
  from unique_toolkit.chat.schemas import (
12
17
  ChatMessage,
13
18
  ChatMessageAssessment,
@@ -30,10 +35,11 @@ from unique_toolkit.language_model.constants import (
30
35
  DEFAULT_COMPLETE_TIMEOUT,
31
36
  )
32
37
  from unique_toolkit.language_model.functions import (
33
- ChatCompletionMessageParam,
34
38
  _prepare_all_completions_params_util,
35
39
  )
36
- from unique_toolkit.language_model.infos import LanguageModelName
40
+ from unique_toolkit.language_model.infos import (
41
+ LanguageModelName,
42
+ )
37
43
  from unique_toolkit.language_model.schemas import (
38
44
  LanguageModelMessages,
39
45
  LanguageModelStreamResponse,
@@ -761,8 +767,9 @@ def stream_complete_with_references(
761
767
  debug_info: dict | None = None,
762
768
  temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
763
769
  timeout: int = DEFAULT_COMPLETE_TIMEOUT,
764
- tools: list[LanguageModelTool | LanguageModelToolDescription] | None = None,
770
+ tools: Sequence[LanguageModelTool | LanguageModelToolDescription] | None = None,
765
771
  start_text: str | None = None,
772
+ tool_choice: ChatCompletionToolChoiceOptionParam | None = None,
766
773
  other_options: dict | None = None,
767
774
  ) -> LanguageModelStreamResponse:
768
775
  """Streams a completion synchronously.
@@ -795,6 +802,7 @@ def stream_complete_with_references(
795
802
  temperature=temperature,
796
803
  tools=tools,
797
804
  other_options=other_options,
805
+ tool_choice=tool_choice,
798
806
  content_chunks=content_chunks or [],
799
807
  )
800
808
  )
@@ -871,7 +879,8 @@ async def stream_complete_with_references_async(
871
879
  debug_info: dict | None = None,
872
880
  temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
873
881
  timeout: int = DEFAULT_COMPLETE_TIMEOUT,
874
- tools: list[LanguageModelTool | LanguageModelToolDescription] | None = None,
882
+ tools: Sequence[LanguageModelTool | LanguageModelToolDescription] | None = None,
883
+ tool_choice: ChatCompletionToolChoiceOptionParam | None = None,
875
884
  start_text: str | None = None,
876
885
  other_options: dict | None = None,
877
886
  ) -> LanguageModelStreamResponse:
@@ -889,6 +898,7 @@ async def stream_complete_with_references_async(
889
898
  model_name=model_name,
890
899
  temperature=temperature,
891
900
  tools=tools,
901
+ tool_choice=tool_choice,
892
902
  other_options=other_options,
893
903
  content_chunks=content_chunks or [],
894
904
  )
@@ -916,6 +926,12 @@ async def stream_complete_with_references_async(
916
926
  raise e
917
927
 
918
928
 
929
+ def _get_model_dump_or_none(model: BaseModel | None) -> dict | None:
930
+ if model is None:
931
+ return None
932
+ return model.model_dump()
933
+
934
+
919
935
  def create_message_log(
920
936
  user_id: str,
921
937
  company_id: str,
@@ -948,6 +964,9 @@ def create_message_log(
948
964
 
949
965
  """
950
966
  try:
967
+ references_list = (
968
+ map_references_with_original_index(references) if references else None
969
+ )
951
970
  message_log = unique_sdk.MessageLog.create(
952
971
  user_id=user_id,
953
972
  company_id=company_id,
@@ -955,13 +974,9 @@ def create_message_log(
955
974
  text=text,
956
975
  status=status.value,
957
976
  order=order,
958
- details=details.model_dump() if details else None,
959
- uncitedReferences=uncited_references.model_dump()
960
- if uncited_references
961
- else None,
962
- references=map_references_with_original_index(references)
963
- if references
964
- else [], # type: ignore
977
+ details=_get_model_dump_or_none(details),
978
+ uncitedReferences=_get_model_dump_or_none(uncited_references),
979
+ references=references_list, # type: ignore
965
980
  )
966
981
  return MessageLog(**message_log)
967
982
  except Exception as e:
@@ -1001,6 +1016,9 @@ async def create_message_log_async(
1001
1016
 
1002
1017
  """
1003
1018
  try:
1019
+ references_list = (
1020
+ map_references_with_original_index(references) if references else None
1021
+ )
1004
1022
  message_log = await unique_sdk.MessageLog.create_async(
1005
1023
  user_id=user_id,
1006
1024
  company_id=company_id,
@@ -1008,13 +1026,9 @@ async def create_message_log_async(
1008
1026
  text=text,
1009
1027
  status=status.value,
1010
1028
  order=order,
1011
- details=details.model_dump() if details else None,
1012
- uncitedReferences=uncited_references.model_dump()
1013
- if uncited_references
1014
- else None,
1015
- references=map_references_with_original_index(references)
1016
- if references
1017
- else [], # type: ignore
1029
+ details=_get_model_dump_or_none(details),
1030
+ uncitedReferences=_get_model_dump_or_none(uncited_references),
1031
+ references=references_list, # type: ignore
1018
1032
  )
1019
1033
  return MessageLog(**message_log)
1020
1034
  except Exception as e:
@@ -1054,6 +1068,9 @@ def update_message_log(
1054
1068
 
1055
1069
  """
1056
1070
  try:
1071
+ references_list = (
1072
+ map_references_with_original_index(references) if references else None
1073
+ )
1057
1074
  message_log = unique_sdk.MessageLog.update(
1058
1075
  user_id=user_id,
1059
1076
  company_id=company_id,
@@ -1061,13 +1078,9 @@ def update_message_log(
1061
1078
  text=text,
1062
1079
  status=status.value if status else None,
1063
1080
  order=order,
1064
- details=details.model_dump() if details else None,
1065
- uncitedReferences=uncited_references.model_dump()
1066
- if uncited_references
1067
- else None,
1068
- references=map_references_with_original_index(references)
1069
- if references
1070
- else [], # type: ignore
1081
+ details=_get_model_dump_or_none(details),
1082
+ uncitedReferences=_get_model_dump_or_none(uncited_references),
1083
+ references=references_list, # type: ignore
1071
1084
  )
1072
1085
  return MessageLog(**message_log)
1073
1086
  except Exception as e:
@@ -1107,6 +1120,9 @@ async def update_message_log_async(
1107
1120
 
1108
1121
  """
1109
1122
  try:
1123
+ references_list = (
1124
+ map_references_with_original_index(references) if references else None
1125
+ )
1110
1126
  message_log = await unique_sdk.MessageLog.update_async(
1111
1127
  user_id=user_id,
1112
1128
  company_id=company_id,
@@ -1114,13 +1130,9 @@ async def update_message_log_async(
1114
1130
  text=text,
1115
1131
  status=status.value if status else None,
1116
1132
  order=order,
1117
- details=details.model_dump() if details else None,
1118
- uncitedReferences=uncited_references.model_dump()
1119
- if uncited_references
1120
- else None,
1121
- references=map_references_with_original_index(references)
1122
- if references
1123
- else [], # type: ignore
1133
+ details=_get_model_dump_or_none(details),
1134
+ uncitedReferences=_get_model_dump_or_none(uncited_references),
1135
+ references=references_list, # type: ignore
1124
1136
  )
1125
1137
  return MessageLog(**message_log)
1126
1138
  except Exception as e:
@@ -1280,7 +1292,7 @@ def update_message_execution(
1280
1292
  user_id: str,
1281
1293
  company_id: str,
1282
1294
  message_id: str,
1283
- status: MessageExecutionUpdateStatus,
1295
+ status: MessageExecutionUpdateStatus | None = None,
1284
1296
  seconds_remaining: int | None = None,
1285
1297
  percentage_completed: int | None = None,
1286
1298
  ) -> MessageExecution:
@@ -1290,7 +1302,7 @@ def update_message_execution(
1290
1302
  user_id (str): The user ID.
1291
1303
  company_id (str): The company ID.
1292
1304
  message_id (str): The ID of the message to update execution for.
1293
- status (MessageExecutionUpdateStatus): The updated status (COMPLETED or FAILED).
1305
+ status (MessageExecutionUpdateStatus | None): The updated status (COMPLETED or FAILED). Defaults to None.
1294
1306
  seconds_remaining (int | None): Updated estimated seconds remaining.
1295
1307
  percentage_completed (int | None): Updated percentage of completion (0-100).
1296
1308
 
@@ -1302,11 +1314,12 @@ def update_message_execution(
1302
1314
 
1303
1315
  """
1304
1316
  try:
1317
+ status_value = status.value if status else None
1305
1318
  message_execution = unique_sdk.MessageExecution.update(
1306
1319
  user_id=user_id,
1307
1320
  company_id=company_id,
1308
1321
  messageId=message_id,
1309
- status=status.value,
1322
+ status=status_value,
1310
1323
  secondsRemaining=seconds_remaining,
1311
1324
  percentageCompleted=percentage_completed,
1312
1325
  )
@@ -1320,7 +1333,7 @@ async def update_message_execution_async(
1320
1333
  user_id: str,
1321
1334
  company_id: str,
1322
1335
  message_id: str,
1323
- status: MessageExecutionUpdateStatus,
1336
+ status: MessageExecutionUpdateStatus | None = None,
1324
1337
  seconds_remaining: int | None = None,
1325
1338
  percentage_completed: int | None = None,
1326
1339
  ) -> MessageExecution:
@@ -1330,7 +1343,7 @@ async def update_message_execution_async(
1330
1343
  user_id (str): The user ID.
1331
1344
  company_id (str): The company ID.
1332
1345
  message_id (str): The ID of the message to update execution for.
1333
- status (MessageExecutionUpdateStatus): The updated status (COMPLETED or FAILED).
1346
+ status (MessageExecutionUpdateStatus | None): The updated status (COMPLETED or FAILED). Defaults to None.
1334
1347
  seconds_remaining (int | None): Updated estimated seconds remaining.
1335
1348
  percentage_completed (int | None): Updated percentage of completion (0-100).
1336
1349
 
@@ -1342,11 +1355,12 @@ async def update_message_execution_async(
1342
1355
 
1343
1356
  """
1344
1357
  try:
1358
+ status_value = status.value if status else None
1345
1359
  message_execution = await unique_sdk.MessageExecution.update_async(
1346
1360
  user_id=user_id,
1347
1361
  company_id=company_id,
1348
1362
  messageId=message_id,
1349
- status=status.value,
1363
+ status=status_value,
1350
1364
  secondsRemaining=seconds_remaining,
1351
1365
  percentageCompleted=percentage_completed,
1352
1366
  )
@@ -0,0 +1,34 @@
1
+ from urllib.parse import quote
2
+
3
+
4
+ def create_prompt_button_string(
5
+ *,
6
+ button_text: str,
7
+ next_user_message: str,
8
+ ) -> str:
9
+ """
10
+ Create a prompt button string.
11
+
12
+ Args:
13
+ button_text: The text of the button.
14
+ next_user_message: The message to send when the button is clicked.
15
+
16
+ Returns:
17
+ A string that can be used to create a prompt button.
18
+ A prompt button includes the `next_user_message` to the user prompt windown.
19
+ """
20
+ next_user_message = quote(next_user_message)
21
+ return f"[{button_text}](https://prompt={next_user_message})"
22
+
23
+
24
+ def create_latex_formula_string(latex_expression: str) -> str:
25
+ """
26
+ Create a LaTeX string.
27
+
28
+ Args:
29
+ latex_expression: The LaTeX expression to create.
30
+
31
+ Returns:
32
+ A string that can be used to create a LaTeX string.
33
+ """
34
+ return f"\\[{latex_expression}\\]"