unique_toolkit 0.8.28__py3-none-any.whl → 0.8.29__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.
@@ -196,6 +196,10 @@ class ChatEventPayload(BaseModel):
196
196
  default_factory=list,
197
197
  description="A list of MCP servers with tools available for the chat session.",
198
198
  )
199
+ message_execution_id: str | None = Field(
200
+ default=None,
201
+ description="The message execution id for triggering the chat event. Originates from the message execution service.",
202
+ )
199
203
 
200
204
  @field_validator("raw_scope_rules", mode="before")
201
205
  def validate_scope_rules(cls, value: dict[str, Any] | None) -> UniqueQL | None:
@@ -15,6 +15,13 @@ from unique_toolkit.chat.schemas import (
15
15
  ChatMessageAssessmentStatus,
16
16
  ChatMessageAssessmentType,
17
17
  ChatMessageRole,
18
+ MessageExecution,
19
+ MessageExecutionType,
20
+ MessageExecutionUpdateStatus,
21
+ MessageLog,
22
+ MessageLogDetails,
23
+ MessageLogStatus,
24
+ MessageLogUncitedReferences,
18
25
  )
19
26
  from unique_toolkit.content.schemas import ContentChunk, ContentReference
20
27
  from unique_toolkit.content.utils import count_tokens
@@ -174,6 +181,26 @@ def map_references(references: list[ContentReference]) -> list[dict[str, Any]]:
174
181
  ]
175
182
 
176
183
 
184
+ def map_references_with_original_index(
185
+ references: list[ContentReference],
186
+ ) -> list[dict[str, Any]]:
187
+ """Maps ContentReference objects to dict format for MessageLog API (complete format).
188
+
189
+ This function includes all fields including originalIndex for APIs that support it.
190
+ """
191
+ return [
192
+ {
193
+ "name": ref.name,
194
+ "url": ref.url,
195
+ "sequenceNumber": ref.sequence_number,
196
+ "sourceId": ref.source_id,
197
+ "source": ref.source,
198
+ "originalIndex": ref.original_index,
199
+ }
200
+ for ref in references
201
+ ]
202
+
203
+
177
204
  def _construct_message_modify_params(
178
205
  user_id: str,
179
206
  company_id: str,
@@ -887,3 +914,443 @@ async def stream_complete_with_references_async(
887
914
  except Exception as e:
888
915
  logger.error(f"Error streaming completion: {e}")
889
916
  raise e
917
+
918
+
919
+ def create_message_log(
920
+ user_id: str,
921
+ company_id: str,
922
+ message_id: str,
923
+ text: str,
924
+ status: MessageLogStatus,
925
+ order: int,
926
+ details: MessageLogDetails | None = None,
927
+ uncited_references: MessageLogUncitedReferences | None = None,
928
+ references: list[ContentReference] | None = None,
929
+ ) -> MessageLog:
930
+ """Creates a message log synchronously.
931
+
932
+ Args:
933
+ user_id (str): The user ID.
934
+ company_id (str): The company ID.
935
+ message_id (str): The ID of the message this log belongs to.
936
+ text (str): The log text content.
937
+ status (MessageLogStatus): The status of this log entry.
938
+ order (int): The order/sequence number of this log entry.
939
+ details (MessageLogDetails | None): Additional details about this log entry.
940
+ uncited_references (MessageLogUncitedReferences | None): References that are not cited.
941
+ references (list[ContentReference] | None): List of references for this log.
942
+
943
+ Returns:
944
+ MessageLog: The created message log.
945
+
946
+ Raises:
947
+ Exception: If the creation fails.
948
+
949
+ """
950
+ try:
951
+ message_log = unique_sdk.MessageLog.create(
952
+ user_id=user_id,
953
+ company_id=company_id,
954
+ messageId=message_id,
955
+ text=text,
956
+ status=status.value,
957
+ 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
965
+ )
966
+ return MessageLog(**message_log)
967
+ except Exception as e:
968
+ logger.error(f"Failed to create message log: {e}")
969
+ raise e
970
+
971
+
972
+ async def create_message_log_async(
973
+ user_id: str,
974
+ company_id: str,
975
+ message_id: str,
976
+ text: str,
977
+ status: MessageLogStatus,
978
+ order: int,
979
+ details: MessageLogDetails | None = None,
980
+ uncited_references: MessageLogUncitedReferences | None = None,
981
+ references: list[ContentReference] | None = None,
982
+ ) -> MessageLog:
983
+ """Creates a message log asynchronously.
984
+
985
+ Args:
986
+ user_id (str): The user ID.
987
+ company_id (str): The company ID.
988
+ message_id (str): The ID of the message this log belongs to.
989
+ text (str): The log text content.
990
+ status (MessageLogStatus): The status of this log entry.
991
+ order (int): The order/sequence number of this log entry.
992
+ details (MessageLogDetails | None): Additional details about this log entry.
993
+ uncited_references (MessageLogUncitedReferences | None): References that are not cited.
994
+ references (list[ContentReference] | None): List of references for this log.
995
+
996
+ Returns:
997
+ MessageLog: The created message log.
998
+
999
+ Raises:
1000
+ Exception: If the creation fails.
1001
+
1002
+ """
1003
+ try:
1004
+ message_log = await unique_sdk.MessageLog.create_async(
1005
+ user_id=user_id,
1006
+ company_id=company_id,
1007
+ messageId=message_id,
1008
+ text=text,
1009
+ status=status.value,
1010
+ 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
1018
+ )
1019
+ return MessageLog(**message_log)
1020
+ except Exception as e:
1021
+ logger.error(f"Failed to create message log: {e}")
1022
+ raise e
1023
+
1024
+
1025
+ def update_message_log(
1026
+ user_id: str,
1027
+ company_id: str,
1028
+ message_log_id: str,
1029
+ order: int,
1030
+ text: str | None = None,
1031
+ status: MessageLogStatus | None = None,
1032
+ details: MessageLogDetails | None = None,
1033
+ uncited_references: MessageLogUncitedReferences | None = None,
1034
+ references: list[ContentReference] | None = None,
1035
+ ) -> MessageLog:
1036
+ """Updates a message log synchronously.
1037
+
1038
+ Args:
1039
+ user_id (str): The user ID.
1040
+ company_id (str): The company ID.
1041
+ message_log_id (str): The ID of the message log to update.
1042
+ order (int): The order/sequence number (required).
1043
+ text (str | None): The updated log text content.
1044
+ status (MessageLogStatus | None): The updated status.
1045
+ details (MessageLogDetails | None): Updated additional details.
1046
+ uncited_references (MessageLogUncitedReferences | None): Updated uncited references.
1047
+ references (list[ContentReference] | None): Updated list of references.
1048
+
1049
+ Returns:
1050
+ MessageLog: The updated message log.
1051
+
1052
+ Raises:
1053
+ Exception: If the update fails.
1054
+
1055
+ """
1056
+ try:
1057
+ message_log = unique_sdk.MessageLog.update(
1058
+ user_id=user_id,
1059
+ company_id=company_id,
1060
+ message_log_id=message_log_id,
1061
+ text=text,
1062
+ status=status.value if status else None,
1063
+ 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
1071
+ )
1072
+ return MessageLog(**message_log)
1073
+ except Exception as e:
1074
+ logger.error(f"Failed to update message log: {e}")
1075
+ raise e
1076
+
1077
+
1078
+ async def update_message_log_async(
1079
+ user_id: str,
1080
+ company_id: str,
1081
+ message_log_id: str,
1082
+ order: int,
1083
+ text: str | None = None,
1084
+ status: MessageLogStatus | None = None,
1085
+ details: MessageLogDetails | None = None,
1086
+ uncited_references: MessageLogUncitedReferences | None = None,
1087
+ references: list[ContentReference] | None = None,
1088
+ ) -> MessageLog:
1089
+ """Updates a message log asynchronously.
1090
+
1091
+ Args:
1092
+ user_id (str): The user ID.
1093
+ company_id (str): The company ID.
1094
+ message_log_id (str): The ID of the message log to update.
1095
+ order (int): The order/sequence number (required).
1096
+ text (str | None): The updated log text content.
1097
+ status (MessageLogStatus | None): The updated status.
1098
+ details (MessageLogDetails | None): Updated additional details.
1099
+ uncited_references (MessageLogUncitedReferences | None): Updated uncited references.
1100
+ references (list[ContentReference] | None): Updated list of references.
1101
+
1102
+ Returns:
1103
+ MessageLog: The updated message log.
1104
+
1105
+ Raises:
1106
+ Exception: If the update fails.
1107
+
1108
+ """
1109
+ try:
1110
+ message_log = await unique_sdk.MessageLog.update_async(
1111
+ user_id=user_id,
1112
+ company_id=company_id,
1113
+ message_log_id=message_log_id,
1114
+ text=text,
1115
+ status=status.value if status else None,
1116
+ 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
1124
+ )
1125
+ return MessageLog(**message_log)
1126
+ except Exception as e:
1127
+ logger.error(f"Failed to update message log: {e}")
1128
+ raise e
1129
+
1130
+
1131
+ def create_message_execution(
1132
+ user_id: str,
1133
+ company_id: str,
1134
+ message_id: str,
1135
+ chat_id: str,
1136
+ type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
1137
+ seconds_remaining: int | None = None,
1138
+ percentage_completed: int | None = None,
1139
+ ) -> MessageExecution:
1140
+ """Creates a message execution synchronously.
1141
+
1142
+ Args:
1143
+ user_id (str): The user ID.
1144
+ company_id (str): The company ID.
1145
+ message_id (str): The ID of the message this execution belongs to.
1146
+ chat_id (str): The chat ID.
1147
+ type (MessageExecutionType): The type of execution. Defaults to DEEP_RESEARCH.
1148
+ seconds_remaining (int | None): Estimated seconds remaining for completion.
1149
+ percentage_completed (int | None): Percentage of completion (0-100).
1150
+
1151
+ Returns:
1152
+ MessageExecution: The created message execution.
1153
+
1154
+ Raises:
1155
+ Exception: If the creation fails.
1156
+
1157
+ """
1158
+ try:
1159
+ message_execution = unique_sdk.MessageExecution.create(
1160
+ user_id=user_id,
1161
+ company_id=company_id,
1162
+ messageId=message_id,
1163
+ chatId=chat_id,
1164
+ type=type.value,
1165
+ secondsRemaining=seconds_remaining,
1166
+ percentageCompleted=percentage_completed,
1167
+ )
1168
+ return MessageExecution(**message_execution)
1169
+ except Exception as e:
1170
+ logger.error(f"Failed to create message execution: {e}")
1171
+ raise e
1172
+
1173
+
1174
+ async def create_message_execution_async(
1175
+ user_id: str,
1176
+ company_id: str,
1177
+ message_id: str,
1178
+ chat_id: str,
1179
+ type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
1180
+ seconds_remaining: int | None = None,
1181
+ percentage_completed: int | None = None,
1182
+ ) -> MessageExecution:
1183
+ """Creates a message execution asynchronously.
1184
+
1185
+ Args:
1186
+ user_id (str): The user ID.
1187
+ company_id (str): The company ID.
1188
+ message_id (str): The ID of the message this execution belongs to.
1189
+ chat_id (str): The chat ID.
1190
+ type (MessageExecutionType): The type of execution. Defaults to DEEP_RESEARCH.
1191
+ seconds_remaining (int | None): Estimated seconds remaining for completion.
1192
+ percentage_completed (int | None): Percentage of completion (0-100).
1193
+
1194
+ Returns:
1195
+ MessageExecution: The created message execution.
1196
+
1197
+ Raises:
1198
+ Exception: If the creation fails.
1199
+
1200
+ """
1201
+ try:
1202
+ message_execution = await unique_sdk.MessageExecution.create_async(
1203
+ user_id=user_id,
1204
+ company_id=company_id,
1205
+ messageId=message_id,
1206
+ chatId=chat_id,
1207
+ type=type.value,
1208
+ secondsRemaining=seconds_remaining,
1209
+ percentageCompleted=percentage_completed,
1210
+ )
1211
+ return MessageExecution(**message_execution)
1212
+ except Exception as e:
1213
+ logger.error(f"Failed to create message execution: {e}")
1214
+ raise e
1215
+
1216
+
1217
+ def get_message_execution(
1218
+ user_id: str,
1219
+ company_id: str,
1220
+ message_id: str,
1221
+ ) -> MessageExecution:
1222
+ """Gets a message execution by message ID synchronously.
1223
+
1224
+ Args:
1225
+ user_id (str): The user ID.
1226
+ company_id (str): The company ID.
1227
+ message_id (str): The ID of the message to get execution for.
1228
+
1229
+ Returns:
1230
+ MessageExecution: The message execution.
1231
+
1232
+ Raises:
1233
+ Exception: If the retrieval fails.
1234
+
1235
+ """
1236
+ try:
1237
+ message_execution = unique_sdk.MessageExecution.get(
1238
+ user_id=user_id,
1239
+ company_id=company_id,
1240
+ messageId=message_id,
1241
+ )
1242
+ return MessageExecution(**message_execution)
1243
+ except Exception as e:
1244
+ logger.error(f"Failed to get message execution: {e}")
1245
+ raise e
1246
+
1247
+
1248
+ async def get_message_execution_async(
1249
+ user_id: str,
1250
+ company_id: str,
1251
+ message_id: str,
1252
+ ) -> MessageExecution:
1253
+ """Gets a message execution by message ID asynchronously.
1254
+
1255
+ Args:
1256
+ user_id (str): The user ID.
1257
+ company_id (str): The company ID.
1258
+ message_id (str): The ID of the message to get execution for.
1259
+
1260
+ Returns:
1261
+ MessageExecution: The message execution.
1262
+
1263
+ Raises:
1264
+ Exception: If the retrieval fails.
1265
+
1266
+ """
1267
+ try:
1268
+ message_execution = await unique_sdk.MessageExecution.get_async(
1269
+ user_id=user_id,
1270
+ company_id=company_id,
1271
+ messageId=message_id,
1272
+ )
1273
+ return MessageExecution(**message_execution)
1274
+ except Exception as e:
1275
+ logger.error(f"Failed to get message execution: {e}")
1276
+ raise e
1277
+
1278
+
1279
+ def update_message_execution(
1280
+ user_id: str,
1281
+ company_id: str,
1282
+ message_id: str,
1283
+ status: MessageExecutionUpdateStatus,
1284
+ seconds_remaining: int | None = None,
1285
+ percentage_completed: int | None = None,
1286
+ ) -> MessageExecution:
1287
+ """Updates a message execution synchronously.
1288
+
1289
+ Args:
1290
+ user_id (str): The user ID.
1291
+ company_id (str): The company ID.
1292
+ message_id (str): The ID of the message to update execution for.
1293
+ status (MessageExecutionUpdateStatus): The updated status (COMPLETED or FAILED).
1294
+ seconds_remaining (int | None): Updated estimated seconds remaining.
1295
+ percentage_completed (int | None): Updated percentage of completion (0-100).
1296
+
1297
+ Returns:
1298
+ MessageExecution: The updated message execution.
1299
+
1300
+ Raises:
1301
+ Exception: If the update fails.
1302
+
1303
+ """
1304
+ try:
1305
+ message_execution = unique_sdk.MessageExecution.update(
1306
+ user_id=user_id,
1307
+ company_id=company_id,
1308
+ messageId=message_id,
1309
+ status=status.value,
1310
+ secondsRemaining=seconds_remaining,
1311
+ percentageCompleted=percentage_completed,
1312
+ )
1313
+ return MessageExecution(**message_execution)
1314
+ except Exception as e:
1315
+ logger.error(f"Failed to update message execution: {e}")
1316
+ raise e
1317
+
1318
+
1319
+ async def update_message_execution_async(
1320
+ user_id: str,
1321
+ company_id: str,
1322
+ message_id: str,
1323
+ status: MessageExecutionUpdateStatus,
1324
+ seconds_remaining: int | None = None,
1325
+ percentage_completed: int | None = None,
1326
+ ) -> MessageExecution:
1327
+ """Updates a message execution asynchronously.
1328
+
1329
+ Args:
1330
+ user_id (str): The user ID.
1331
+ company_id (str): The company ID.
1332
+ message_id (str): The ID of the message to update execution for.
1333
+ status (MessageExecutionUpdateStatus): The updated status (COMPLETED or FAILED).
1334
+ seconds_remaining (int | None): Updated estimated seconds remaining.
1335
+ percentage_completed (int | None): Updated percentage of completion (0-100).
1336
+
1337
+ Returns:
1338
+ MessageExecution: The updated message execution.
1339
+
1340
+ Raises:
1341
+ Exception: If the update fails.
1342
+
1343
+ """
1344
+ try:
1345
+ message_execution = await unique_sdk.MessageExecution.update_async(
1346
+ user_id=user_id,
1347
+ company_id=company_id,
1348
+ messageId=message_id,
1349
+ status=status.value,
1350
+ secondsRemaining=seconds_remaining,
1351
+ percentageCompleted=percentage_completed,
1352
+ )
1353
+ return MessageExecution(**message_execution)
1354
+ except Exception as e:
1355
+ logger.error(f"Failed to update message execution: {e}")
1356
+ raise e
@@ -1,5 +1,6 @@
1
1
  from datetime import datetime
2
2
  from enum import StrEnum
3
+ from typing import Literal
3
4
 
4
5
  from humps import camelize
5
6
  from openai.types.chat import (
@@ -161,3 +162,72 @@ class ChatMessageAssessment(BaseModel):
161
162
  is_visible: bool
162
163
  created_at: datetime | None = None
163
164
  updated_at: datetime | None = None
165
+
166
+
167
+ class MessageLogStatus(StrEnum):
168
+ RUNNING = "RUNNING"
169
+ COMPLETED = "COMPLETED"
170
+ FAILED = "FAILED"
171
+
172
+
173
+ class MessageExecutionStatus(StrEnum):
174
+ PENDING = "PENDING"
175
+ RUNNING = "RUNNING"
176
+ COMPLETED = "COMPLETED"
177
+ FAILED = "FAILED"
178
+
179
+
180
+ class MessageExecutionType(StrEnum):
181
+ DEEP_RESEARCH = "DEEP_RESEARCH"
182
+
183
+
184
+ class MessageExecutionUpdateStatus(StrEnum):
185
+ COMPLETED = "COMPLETED"
186
+ FAILED = "FAILED"
187
+
188
+
189
+ class MessageLogUncitedReferences(BaseModel):
190
+ model_config = model_config
191
+ data: list[ContentReference]
192
+
193
+
194
+ class MessageLogEvent(BaseModel):
195
+ model_config = model_config
196
+ type: Literal["WebSearch", "InternalSearch"]
197
+ text: str
198
+
199
+
200
+ class MessageLogDetails(BaseModel):
201
+ model_config = model_config
202
+ data: list[MessageLogEvent] | None = None
203
+ status: str | None = Field(
204
+ default=None, description="Overarching status of the current message log"
205
+ )
206
+
207
+
208
+ class MessageLog(BaseModel):
209
+ model_config = model_config
210
+
211
+ message_log_id: str | None = None
212
+ message_id: str | None = None
213
+ status: MessageLogStatus
214
+ text: str | None = None
215
+ details: MessageLogDetails | None = None
216
+ uncited_references: MessageLogUncitedReferences | None = None
217
+ order: int
218
+ references: list[ContentReference] | None = None
219
+ created_at: datetime | None = None
220
+ updated_at: datetime | None = None
221
+
222
+
223
+ class MessageExecution(BaseModel):
224
+ model_config = model_config
225
+
226
+ message_execution_id: str | None = None
227
+ message_id: str | None = None
228
+ status: MessageExecutionStatus
229
+ type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH
230
+ seconds_remaining: int | None = None
231
+ percentage_completed: int | None = None
232
+ created_at: datetime | None = None
233
+ updated_at: datetime | None = None
@@ -14,13 +14,23 @@ from unique_toolkit.chat.functions import (
14
14
  create_message_assessment,
15
15
  create_message_assessment_async,
16
16
  create_message_async,
17
+ create_message_execution,
18
+ create_message_execution_async,
19
+ create_message_log,
20
+ create_message_log_async,
17
21
  get_full_history,
18
22
  get_full_history_async,
23
+ get_message_execution,
24
+ get_message_execution_async,
19
25
  get_selection_from_history,
20
26
  modify_message,
21
27
  modify_message_assessment,
22
28
  modify_message_assessment_async,
23
29
  modify_message_async,
30
+ update_message_execution,
31
+ update_message_execution_async,
32
+ update_message_log,
33
+ update_message_log_async,
24
34
  )
25
35
  from unique_toolkit.chat.schemas import (
26
36
  ChatMessage,
@@ -29,6 +39,13 @@ from unique_toolkit.chat.schemas import (
29
39
  ChatMessageAssessmentStatus,
30
40
  ChatMessageAssessmentType,
31
41
  ChatMessageRole,
42
+ MessageExecution,
43
+ MessageExecutionType,
44
+ MessageExecutionUpdateStatus,
45
+ MessageLog,
46
+ MessageLogDetails,
47
+ MessageLogStatus,
48
+ MessageLogUncitedReferences,
32
49
  )
33
50
  from unique_toolkit.content.schemas import ContentChunk, ContentReference
34
51
  from unique_toolkit.language_model.constants import (
@@ -896,6 +913,558 @@ class ChatService:
896
913
  label=label,
897
914
  )
898
915
 
916
+ def create_message_log(
917
+ self,
918
+ message_id: str,
919
+ text: str,
920
+ status: MessageLogStatus,
921
+ order: int,
922
+ details: MessageLogDetails | None = None,
923
+ uncited_references: MessageLogUncitedReferences | None = None,
924
+ references: list[ContentReference] | None = None,
925
+ ) -> MessageLog:
926
+ """Creates a message log for tracking execution steps synchronously.
927
+
928
+ Args:
929
+ message_id (str): The ID of the message this log belongs to
930
+ text (str): The log text content
931
+ status (MessageLogStatus): The status of this log entry
932
+ order (int): The order/sequence number of this log entry
933
+ details (MessageLogDetails | None): Additional details about this log entry
934
+ uncited_references (MessageLogUncitedReferences | None): References that are not cited
935
+ references (list[ContentReference] | None): List of references for this log
936
+
937
+ Returns:
938
+ MessageLog: The created message log
939
+
940
+ Raises:
941
+ Exception: If the creation fails
942
+
943
+ """
944
+ return create_message_log(
945
+ user_id=self._user_id,
946
+ company_id=self._company_id,
947
+ message_id=message_id,
948
+ text=text,
949
+ status=status,
950
+ order=order,
951
+ details=details,
952
+ uncited_references=uncited_references,
953
+ references=references,
954
+ )
955
+
956
+ async def create_message_log_async(
957
+ self,
958
+ message_id: str,
959
+ text: str,
960
+ status: MessageLogStatus,
961
+ order: int,
962
+ details: MessageLogDetails | None = None,
963
+ uncited_references: MessageLogUncitedReferences | None = None,
964
+ references: list[ContentReference] | None = None,
965
+ ) -> MessageLog:
966
+ """Creates a message log for tracking execution steps asynchronously.
967
+
968
+ Args:
969
+ message_id (str): The ID of the message this log belongs to
970
+ text (str): The log text content
971
+ status (MessageLogStatus): The status of this log entry
972
+ order (int): The order/sequence number of this log entry
973
+ details (MessageLogDetails | None): Additional details about this log entry
974
+ uncited_references (MessageLogUncitedReferences | None): References that are not cited
975
+ references (list[ContentReference] | None): List of references for this log
976
+
977
+ Returns:
978
+ MessageLog: The created message log
979
+
980
+ Raises:
981
+ Exception: If the creation fails
982
+
983
+ """
984
+ return await create_message_log_async(
985
+ user_id=self._user_id,
986
+ company_id=self._company_id,
987
+ message_id=message_id,
988
+ text=text,
989
+ status=status,
990
+ order=order,
991
+ details=details,
992
+ uncited_references=uncited_references,
993
+ references=references,
994
+ )
995
+
996
+ def update_message_log(
997
+ self,
998
+ message_log_id: str,
999
+ order: int,
1000
+ text: str | None = None,
1001
+ status: MessageLogStatus | None = None,
1002
+ details: MessageLogDetails | None = None,
1003
+ uncited_references: MessageLogUncitedReferences | None = None,
1004
+ references: list[ContentReference] | None = None,
1005
+ ) -> MessageLog:
1006
+ """Updates a message log synchronously.
1007
+
1008
+ Args:
1009
+ message_log_id (str): The ID of the message log to update
1010
+ order (int): The order/sequence number (required)
1011
+ text (str | None): The updated log text content
1012
+ status (MessageLogStatus | None): The updated status
1013
+ details (MessageLogDetails | None): Updated additional details
1014
+ uncited_references (MessageLogUncitedReferences | None): Updated uncited references
1015
+ references (list[ContentReference] | None): Updated list of references
1016
+
1017
+ Returns:
1018
+ MessageLog: The updated message log
1019
+
1020
+ Raises:
1021
+ Exception: If the update fails
1022
+
1023
+ """
1024
+ return update_message_log(
1025
+ user_id=self._user_id,
1026
+ company_id=self._company_id,
1027
+ message_log_id=message_log_id,
1028
+ order=order,
1029
+ text=text,
1030
+ status=status,
1031
+ details=details,
1032
+ uncited_references=uncited_references,
1033
+ references=references,
1034
+ )
1035
+
1036
+ async def update_message_log_async(
1037
+ self,
1038
+ message_log_id: str,
1039
+ order: int,
1040
+ text: str | None = None,
1041
+ status: MessageLogStatus | None = None,
1042
+ details: MessageLogDetails | None = None,
1043
+ uncited_references: MessageLogUncitedReferences | None = None,
1044
+ references: list[ContentReference] | None = None,
1045
+ ) -> MessageLog:
1046
+ """Updates a message log asynchronously.
1047
+
1048
+ Args:
1049
+ message_log_id (str): The ID of the message log to update
1050
+ order (int): The order/sequence number (required)
1051
+ text (str | None): The updated log text content
1052
+ status (MessageLogStatus | None): The updated status
1053
+ details (MessageLogDetails | None): Updated additional details
1054
+ uncited_references (MessageLogUncitedReferences | None): Updated uncited references
1055
+ references (list[ContentReference] | None): Updated list of references
1056
+
1057
+ Returns:
1058
+ MessageLog: The updated message log
1059
+
1060
+ Raises:
1061
+ Exception: If the update fails
1062
+
1063
+ """
1064
+ return await update_message_log_async(
1065
+ user_id=self._user_id,
1066
+ company_id=self._company_id,
1067
+ message_log_id=message_log_id,
1068
+ order=order,
1069
+ text=text,
1070
+ status=status,
1071
+ details=details,
1072
+ uncited_references=uncited_references,
1073
+ references=references,
1074
+ )
1075
+
1076
+ def create_assistant_message_log(
1077
+ self,
1078
+ text: str,
1079
+ status: MessageLogStatus,
1080
+ order: int,
1081
+ details: MessageLogDetails | None = None,
1082
+ uncited_references: MessageLogUncitedReferences | None = None,
1083
+ references: list[ContentReference] | None = None,
1084
+ ) -> MessageLog:
1085
+ """Creates a message log for the current assistant message synchronously.
1086
+
1087
+ This is a convenience method that uses the current assistant message ID.
1088
+
1089
+ Args:
1090
+ text (str): The log text content
1091
+ status (MessageLogStatus): The status of this log entry
1092
+ order (int): The order/sequence number of this log entry
1093
+ details (MessageLogDetails | None): Additional details about this log entry
1094
+ uncited_references (MessageLogUncitedReferences | None): References that are not cited
1095
+ references (list[ContentReference] | None): List of references for this log
1096
+
1097
+ Returns:
1098
+ MessageLog: The created message log
1099
+
1100
+ Raises:
1101
+ Exception: If the creation fails
1102
+
1103
+ """
1104
+ return self.create_message_log(
1105
+ message_id=self._assistant_message_id,
1106
+ text=text,
1107
+ status=status,
1108
+ order=order,
1109
+ details=details,
1110
+ uncited_references=uncited_references,
1111
+ references=references,
1112
+ )
1113
+
1114
+ async def create_assistant_message_log_async(
1115
+ self,
1116
+ text: str,
1117
+ status: MessageLogStatus,
1118
+ order: int,
1119
+ details: MessageLogDetails | None = None,
1120
+ uncited_references: MessageLogUncitedReferences | None = None,
1121
+ references: list[ContentReference] | None = None,
1122
+ ) -> MessageLog:
1123
+ """Creates a message log for the current assistant message asynchronously.
1124
+
1125
+ This is a convenience method that uses the current assistant message ID.
1126
+
1127
+ Args:
1128
+ text (str): The log text content
1129
+ status (MessageLogStatus): The status of this log entry
1130
+ order (int): The order/sequence number of this log entry
1131
+ details (MessageLogDetails | None): Additional details about this log entry
1132
+ uncited_references (MessageLogUncitedReferences | None): References that are not cited
1133
+ references (list[ContentReference] | None): List of references for this log
1134
+
1135
+ Returns:
1136
+ MessageLog: The created message log
1137
+
1138
+ Raises:
1139
+ Exception: If the creation fails
1140
+
1141
+ """
1142
+ return await self.create_message_log_async(
1143
+ message_id=self._assistant_message_id,
1144
+ text=text,
1145
+ status=status,
1146
+ order=order,
1147
+ details=details,
1148
+ uncited_references=uncited_references,
1149
+ references=references,
1150
+ )
1151
+
1152
+ def create_message_execution(
1153
+ self,
1154
+ message_id: str,
1155
+ type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
1156
+ seconds_remaining: int | None = None,
1157
+ percentage_completed: int | None = None,
1158
+ ) -> MessageExecution:
1159
+ """Creates a message execution for tracking long-running operations synchronously.
1160
+
1161
+ Args:
1162
+ message_id (str): The ID of the message this execution belongs to
1163
+ type (MessageExecutionType): The type of execution. Defaults to DEEP_RESEARCH.
1164
+ seconds_remaining (int | None): Estimated seconds remaining for completion
1165
+ percentage_completed (int | None): Percentage of completion (0-100)
1166
+
1167
+ Returns:
1168
+ MessageExecution: The created message execution
1169
+
1170
+ Raises:
1171
+ Exception: If the creation fails
1172
+
1173
+ """
1174
+ return create_message_execution(
1175
+ user_id=self._user_id,
1176
+ company_id=self._company_id,
1177
+ message_id=message_id,
1178
+ chat_id=self._chat_id,
1179
+ type=type,
1180
+ seconds_remaining=seconds_remaining,
1181
+ percentage_completed=percentage_completed,
1182
+ )
1183
+
1184
+ async def create_message_execution_async(
1185
+ self,
1186
+ message_id: str,
1187
+ type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
1188
+ seconds_remaining: int | None = None,
1189
+ percentage_completed: int | None = None,
1190
+ ) -> MessageExecution:
1191
+ """Creates a message execution for tracking long-running operations asynchronously.
1192
+
1193
+ Args:
1194
+ message_id (str): The ID of the message this execution belongs to
1195
+ type (MessageExecutionType): The type of execution. Defaults to DEEP_RESEARCH.
1196
+ seconds_remaining (int | None): Estimated seconds remaining for completion
1197
+ percentage_completed (int | None): Percentage of completion (0-100)
1198
+
1199
+ Returns:
1200
+ MessageExecution: The created message execution
1201
+
1202
+ Raises:
1203
+ Exception: If the creation fails
1204
+
1205
+ """
1206
+ return await create_message_execution_async(
1207
+ user_id=self._user_id,
1208
+ company_id=self._company_id,
1209
+ message_id=message_id,
1210
+ chat_id=self._chat_id,
1211
+ type=type,
1212
+ seconds_remaining=seconds_remaining,
1213
+ percentage_completed=percentage_completed,
1214
+ )
1215
+
1216
+ def get_message_execution(
1217
+ self,
1218
+ message_id: str,
1219
+ ) -> MessageExecution:
1220
+ """Gets a message execution by message ID synchronously.
1221
+
1222
+ Args:
1223
+ message_id (str): The ID of the message to get execution for
1224
+
1225
+ Returns:
1226
+ MessageExecution: The message execution
1227
+
1228
+ Raises:
1229
+ Exception: If the retrieval fails
1230
+
1231
+ """
1232
+ return get_message_execution(
1233
+ user_id=self._user_id,
1234
+ company_id=self._company_id,
1235
+ message_id=message_id,
1236
+ )
1237
+
1238
+ async def get_message_execution_async(
1239
+ self,
1240
+ message_id: str,
1241
+ ) -> MessageExecution:
1242
+ """Gets a message execution by message ID asynchronously.
1243
+
1244
+ Args:
1245
+ message_id (str): The ID of the message to get execution for
1246
+
1247
+ Returns:
1248
+ MessageExecution: The message execution
1249
+
1250
+ Raises:
1251
+ Exception: If the retrieval fails
1252
+
1253
+ """
1254
+ return await get_message_execution_async(
1255
+ user_id=self._user_id,
1256
+ company_id=self._company_id,
1257
+ message_id=message_id,
1258
+ )
1259
+
1260
+ def update_message_execution(
1261
+ self,
1262
+ message_id: str,
1263
+ status: MessageExecutionUpdateStatus,
1264
+ seconds_remaining: int | None = None,
1265
+ percentage_completed: int | None = None,
1266
+ ) -> MessageExecution:
1267
+ """Updates a message execution synchronously.
1268
+
1269
+ Args:
1270
+ message_id (str): The ID of the message to update execution for
1271
+ status (MessageExecutionUpdateStatus): The updated status (COMPLETED or FAILED)
1272
+ seconds_remaining (int | None): Updated estimated seconds remaining
1273
+ percentage_completed (int | None): Updated percentage of completion (0-100)
1274
+
1275
+ Returns:
1276
+ MessageExecution: The updated message execution
1277
+
1278
+ Raises:
1279
+ Exception: If the update fails
1280
+
1281
+ """
1282
+ return update_message_execution(
1283
+ user_id=self._user_id,
1284
+ company_id=self._company_id,
1285
+ message_id=message_id,
1286
+ status=status,
1287
+ seconds_remaining=seconds_remaining,
1288
+ percentage_completed=percentage_completed,
1289
+ )
1290
+
1291
+ async def update_message_execution_async(
1292
+ self,
1293
+ message_id: str,
1294
+ status: MessageExecutionUpdateStatus,
1295
+ seconds_remaining: int | None = None,
1296
+ percentage_completed: int | None = None,
1297
+ ) -> MessageExecution:
1298
+ """Updates a message execution asynchronously.
1299
+
1300
+ Args:
1301
+ message_id (str): The ID of the message to update execution for
1302
+ status (MessageExecutionUpdateStatus): The updated status (COMPLETED or FAILED)
1303
+ seconds_remaining (int | None): Updated estimated seconds remaining
1304
+ percentage_completed (int | None): Updated percentage of completion (0-100)
1305
+
1306
+ Returns:
1307
+ MessageExecution: The updated message execution
1308
+
1309
+ Raises:
1310
+ Exception: If the update fails
1311
+
1312
+ """
1313
+ return await update_message_execution_async(
1314
+ user_id=self._user_id,
1315
+ company_id=self._company_id,
1316
+ message_id=message_id,
1317
+ status=status,
1318
+ seconds_remaining=seconds_remaining,
1319
+ percentage_completed=percentage_completed,
1320
+ )
1321
+
1322
+ def create_assistant_message_execution(
1323
+ self,
1324
+ type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
1325
+ seconds_remaining: int | None = None,
1326
+ percentage_completed: int | None = None,
1327
+ ) -> MessageExecution:
1328
+ """Creates a message execution for the current assistant message synchronously.
1329
+
1330
+ This is a convenience method that uses the current assistant message ID.
1331
+
1332
+ Args:
1333
+ type (MessageExecutionType): The type of execution. Defaults to DEEP_RESEARCH.
1334
+ seconds_remaining (int | None): Estimated seconds remaining for completion
1335
+ percentage_completed (int | None): Percentage of completion (0-100)
1336
+
1337
+ Returns:
1338
+ MessageExecution: The created message execution
1339
+
1340
+ Raises:
1341
+ Exception: If the creation fails
1342
+
1343
+ """
1344
+ return self.create_message_execution(
1345
+ message_id=self._assistant_message_id,
1346
+ type=type,
1347
+ seconds_remaining=seconds_remaining,
1348
+ percentage_completed=percentage_completed,
1349
+ )
1350
+
1351
+ async def create_assistant_message_execution_async(
1352
+ self,
1353
+ type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
1354
+ seconds_remaining: int | None = None,
1355
+ percentage_completed: int | None = None,
1356
+ ) -> MessageExecution:
1357
+ """Creates a message execution for the current assistant message asynchronously.
1358
+
1359
+ This is a convenience method that uses the current assistant message ID.
1360
+
1361
+ Args:
1362
+ type (MessageExecutionType): The type of execution. Defaults to DEEP_RESEARCH.
1363
+ seconds_remaining (int | None): Estimated seconds remaining for completion
1364
+ percentage_completed (int | None): Percentage of completion (0-100)
1365
+
1366
+ Returns:
1367
+ MessageExecution: The created message execution
1368
+
1369
+ Raises:
1370
+ Exception: If the creation fails
1371
+
1372
+ """
1373
+ return await self.create_message_execution_async(
1374
+ message_id=self._assistant_message_id,
1375
+ type=type,
1376
+ seconds_remaining=seconds_remaining,
1377
+ percentage_completed=percentage_completed,
1378
+ )
1379
+
1380
+ def get_assistant_message_execution(self) -> MessageExecution:
1381
+ """Gets the message execution for the current assistant message synchronously.
1382
+
1383
+ This is a convenience method that uses the current assistant message ID.
1384
+
1385
+ Returns:
1386
+ MessageExecution: The message execution
1387
+
1388
+ Raises:
1389
+ Exception: If the retrieval fails
1390
+
1391
+ """
1392
+ return self.get_message_execution(message_id=self._assistant_message_id)
1393
+
1394
+ async def get_assistant_message_execution_async(self) -> MessageExecution:
1395
+ """Gets the message execution for the current assistant message asynchronously.
1396
+
1397
+ This is a convenience method that uses the current assistant message ID.
1398
+
1399
+ Returns:
1400
+ MessageExecution: The message execution
1401
+
1402
+ Raises:
1403
+ Exception: If the retrieval fails
1404
+
1405
+ """
1406
+ return await self.get_message_execution_async(
1407
+ message_id=self._assistant_message_id
1408
+ )
1409
+
1410
+ def update_assistant_message_execution(
1411
+ self,
1412
+ status: MessageExecutionUpdateStatus,
1413
+ seconds_remaining: int | None = None,
1414
+ percentage_completed: int | None = None,
1415
+ ) -> MessageExecution:
1416
+ """Updates the message execution for the current assistant message synchronously.
1417
+
1418
+ This is a convenience method that uses the current assistant message ID.
1419
+
1420
+ Args:
1421
+ status (MessageExecutionUpdateStatus): The updated status (COMPLETED or FAILED)
1422
+ seconds_remaining (int | None): Updated estimated seconds remaining
1423
+ percentage_completed (int | None): Updated percentage of completion (0-100)
1424
+
1425
+ Returns:
1426
+ MessageExecution: The updated message execution
1427
+
1428
+ Raises:
1429
+ Exception: If the update fails
1430
+
1431
+ """
1432
+ return self.update_message_execution(
1433
+ message_id=self._assistant_message_id,
1434
+ status=status,
1435
+ seconds_remaining=seconds_remaining,
1436
+ percentage_completed=percentage_completed,
1437
+ )
1438
+
1439
+ async def update_assistant_message_execution_async(
1440
+ self,
1441
+ status: MessageExecutionUpdateStatus,
1442
+ seconds_remaining: int | None = None,
1443
+ percentage_completed: int | None = None,
1444
+ ) -> MessageExecution:
1445
+ """Updates the message execution for the current assistant message asynchronously.
1446
+
1447
+ This is a convenience method that uses the current assistant message ID.
1448
+
1449
+ Args:
1450
+ status (MessageExecutionUpdateStatus): The updated status (COMPLETED or FAILED)
1451
+ seconds_remaining (int | None): Updated estimated seconds remaining
1452
+ percentage_completed (int | None): Updated percentage of completion (0-100)
1453
+
1454
+ Returns:
1455
+ MessageExecution: The updated message execution
1456
+
1457
+ Raises:
1458
+ Exception: If the update fails
1459
+
1460
+ """
1461
+ return await self.update_message_execution_async(
1462
+ message_id=self._assistant_message_id,
1463
+ status=status,
1464
+ seconds_remaining=seconds_remaining,
1465
+ percentage_completed=percentage_completed,
1466
+ )
1467
+
899
1468
  @deprecated("Use complete_with_references instead")
900
1469
  def stream_complete(
901
1470
  self,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 0.8.28
3
+ Version: 0.8.29
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Martin Fadler
@@ -114,6 +114,9 @@ All notable changes to this project will be documented in this file.
114
114
 
115
115
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
116
116
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
117
+ ## [0.8.29] - 2025-08-27
118
+ - Include `MessageExecution` and `MessageLog` in toolkit
119
+
117
120
  ## [0.8.28] - 2025-08-28
118
121
  - Fix paths for `sdk_url` and `openai_proxy` for localhost
119
122
 
@@ -14,14 +14,14 @@ unique_toolkit/app/init_logging.py,sha256=Sh26SRxOj8i8dzobKhYha2lLrkrMTHfB1V4jR3
14
14
  unique_toolkit/app/init_sdk.py,sha256=5_oDoETr6akwYyBCb0ivTdMNu3SVgPSkrXcDS6ELyY8,2269
15
15
  unique_toolkit/app/performance/async_tasks.py,sha256=H0l3OAcosLwNHZ8d2pd-Di4wHIXfclEvagi5kfqLFPA,1941
16
16
  unique_toolkit/app/performance/async_wrapper.py,sha256=yVVcRDkcdyfjsxro-N29SBvi-7773wnfDplef6-y8xw,1077
17
- unique_toolkit/app/schemas.py,sha256=uh7PR-YYXfdTnuO5V_eGrW96eJmP5tJ4jeePyU8tsNI,7888
17
+ unique_toolkit/app/schemas.py,sha256=xHdzMyZ_cgCzxCqzCJYwOCAYWkaQ9zIyZsRhDgSQnEA,8088
18
18
  unique_toolkit/app/unique_settings.py,sha256=f9Ip1yBhIJqHpuHIo3ihCW2MGyQynBggEKDzlIOIlyg,9976
19
19
  unique_toolkit/app/verification.py,sha256=GxFFwcJMy25fCA_Xe89wKW7bgqOu8PAs5y8QpHF0GSc,3861
20
20
  unique_toolkit/chat/__init__.py,sha256=LRs2G-JTVuci4lbtHTkVUiNcZcSR6uqqfnAyo7af6nY,619
21
21
  unique_toolkit/chat/constants.py,sha256=05kq6zjqUVB2d6_P7s-90nbljpB3ryxwCI-CAz0r2O4,83
22
- unique_toolkit/chat/functions.py,sha256=I6r81PpWNu-j9DvHxNFKN3V6T5E5q42FhW9kF8pJJSY,29950
23
- unique_toolkit/chat/schemas.py,sha256=ekmDzxZRnO4pF-8DAnP4JqKmYuJnSC5RpYcO7j5T3aI,4927
24
- unique_toolkit/chat/service.py,sha256=-agXxkB_cl7Mcr3aFVHbBXhO-RioiouAfoHAHmlhQJs,37981
22
+ unique_toolkit/chat/functions.py,sha256=qxBjxIFoko5vyQNJDYpIkMtBhEGGcSlWn6fkAY-dFVE,45213
23
+ unique_toolkit/chat/schemas.py,sha256=u3WPdMkOlmwPGHUueQC-nk8k-QkM7ZSUcU0f-32g6Uc,6718
24
+ unique_toolkit/chat/service.py,sha256=YT01Ol3czvopnvT1CxZUOYDxU85mxBaMt7C_lEcciDM,58162
25
25
  unique_toolkit/chat/state.py,sha256=Cjgwv_2vhDFbV69xxsn7SefhaoIAEqLx3ferdVFCnOg,1445
26
26
  unique_toolkit/chat/utils.py,sha256=ihm-wQykBWhB4liR3LnwPVPt_qGW6ETq21Mw4HY0THE,854
27
27
  unique_toolkit/content/__init__.py,sha256=EdJg_A_7loEtCQf4cah3QARQreJx6pdz89Rm96YbMVg,940
@@ -115,7 +115,7 @@ unique_toolkit/tools/utils/execution/execution.py,sha256=vjG2Y6awsGNtlvyQAGCTthQ
115
115
  unique_toolkit/tools/utils/source_handling/schema.py,sha256=vzAyf6ZWNexjMO0OrnB8y2glGkvAilmGGQXd6zcDaKw,870
116
116
  unique_toolkit/tools/utils/source_handling/source_formatting.py,sha256=C7uayNbdkNVJdEARA5CENnHtNY1SU6etlaqbgHNyxaQ,9152
117
117
  unique_toolkit/tools/utils/source_handling/tests/test_source_formatting.py,sha256=oM5ZxEgzROrnX1229KViCAFjRxl9wCTzWZoinYSHleM,6979
118
- unique_toolkit-0.8.28.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
119
- unique_toolkit-0.8.28.dist-info/METADATA,sha256=hMjsYHTpU3nvOolbSR6CO-8uMdkYZyuap3y2cue-0ck,29161
120
- unique_toolkit-0.8.28.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
121
- unique_toolkit-0.8.28.dist-info/RECORD,,
118
+ unique_toolkit-0.8.29.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
119
+ unique_toolkit-0.8.29.dist-info/METADATA,sha256=14-dyP0BCriYbAGs3mQBbGUG-SfuOmJDX6lq1Puf2Gg,29245
120
+ unique_toolkit-0.8.29.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
121
+ unique_toolkit-0.8.29.dist-info/RECORD,,