unique_toolkit 1.11.2__py3-none-any.whl → 1.11.4__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.
@@ -714,6 +714,7 @@ class ChatService(ChatServiceDeprecated):
714
714
 
715
715
  def create_message_log(
716
716
  self,
717
+ *,
717
718
  message_id: str,
718
719
  text: str,
719
720
  status: MessageLogStatus,
@@ -754,6 +755,7 @@ class ChatService(ChatServiceDeprecated):
754
755
 
755
756
  async def create_message_log_async(
756
757
  self,
758
+ *,
757
759
  message_id: str,
758
760
  text: str,
759
761
  status: MessageLogStatus,
@@ -794,6 +796,7 @@ class ChatService(ChatServiceDeprecated):
794
796
 
795
797
  def update_message_log(
796
798
  self,
799
+ *,
797
800
  message_log_id: str,
798
801
  order: int,
799
802
  text: str | None = None,
@@ -834,6 +837,7 @@ class ChatService(ChatServiceDeprecated):
834
837
 
835
838
  async def update_message_log_async(
836
839
  self,
840
+ *,
837
841
  message_log_id: str,
838
842
  order: int,
839
843
  text: str | None = None,
@@ -874,6 +878,7 @@ class ChatService(ChatServiceDeprecated):
874
878
 
875
879
  def create_assistant_message_log(
876
880
  self,
881
+ *,
877
882
  text: str,
878
883
  status: MessageLogStatus,
879
884
  order: int,
@@ -912,6 +917,7 @@ class ChatService(ChatServiceDeprecated):
912
917
 
913
918
  async def create_assistant_message_log_async(
914
919
  self,
920
+ *,
915
921
  text: str,
916
922
  status: MessageLogStatus,
917
923
  order: int,
@@ -953,6 +959,7 @@ class ChatService(ChatServiceDeprecated):
953
959
 
954
960
  def create_message_execution(
955
961
  self,
962
+ *,
956
963
  message_id: str,
957
964
  type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
958
965
  seconds_remaining: int | None = None,
@@ -985,6 +992,7 @@ class ChatService(ChatServiceDeprecated):
985
992
 
986
993
  async def create_message_execution_async(
987
994
  self,
995
+ *,
988
996
  message_id: str,
989
997
  type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
990
998
  seconds_remaining: int | None = None,
@@ -1017,6 +1025,7 @@ class ChatService(ChatServiceDeprecated):
1017
1025
 
1018
1026
  def get_message_execution(
1019
1027
  self,
1028
+ *,
1020
1029
  message_id: str,
1021
1030
  ) -> MessageExecution:
1022
1031
  """Gets a message execution by message ID synchronously.
@@ -1039,6 +1048,7 @@ class ChatService(ChatServiceDeprecated):
1039
1048
 
1040
1049
  async def get_message_execution_async(
1041
1050
  self,
1051
+ *,
1042
1052
  message_id: str,
1043
1053
  ) -> MessageExecution:
1044
1054
  """Gets a message execution by message ID asynchronously.
@@ -1061,6 +1071,7 @@ class ChatService(ChatServiceDeprecated):
1061
1071
 
1062
1072
  def update_message_execution(
1063
1073
  self,
1074
+ *,
1064
1075
  message_id: str,
1065
1076
  status: MessageExecutionUpdateStatus,
1066
1077
  seconds_remaining: int | None = None,
@@ -1092,6 +1103,7 @@ class ChatService(ChatServiceDeprecated):
1092
1103
 
1093
1104
  async def update_message_execution_async(
1094
1105
  self,
1106
+ *,
1095
1107
  message_id: str,
1096
1108
  status: MessageExecutionUpdateStatus,
1097
1109
  seconds_remaining: int | None = None,
@@ -1123,6 +1135,7 @@ class ChatService(ChatServiceDeprecated):
1123
1135
 
1124
1136
  def create_assistant_message_execution(
1125
1137
  self,
1138
+ *,
1126
1139
  type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
1127
1140
  seconds_remaining: int | None = None,
1128
1141
  percentage_completed: int | None = None,
@@ -1152,6 +1165,7 @@ class ChatService(ChatServiceDeprecated):
1152
1165
 
1153
1166
  async def create_assistant_message_execution_async(
1154
1167
  self,
1168
+ *,
1155
1169
  type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
1156
1170
  seconds_remaining: int | None = None,
1157
1171
  percentage_completed: int | None = None,
@@ -1211,6 +1225,7 @@ class ChatService(ChatServiceDeprecated):
1211
1225
 
1212
1226
  def update_assistant_message_execution(
1213
1227
  self,
1228
+ *,
1214
1229
  status: MessageExecutionUpdateStatus,
1215
1230
  seconds_remaining: int | None = None,
1216
1231
  percentage_completed: int | None = None,
@@ -1240,6 +1255,7 @@ class ChatService(ChatServiceDeprecated):
1240
1255
 
1241
1256
  async def update_assistant_message_execution_async(
1242
1257
  self,
1258
+ *,
1243
1259
  status: MessageExecutionUpdateStatus,
1244
1260
  seconds_remaining: int | None = None,
1245
1261
  percentage_completed: int | None = None,
@@ -0,0 +1,301 @@
1
+ import re
2
+ from datetime import datetime, timedelta, timezone
3
+ from enum import Enum
4
+ from typing import Any, Dict, List, Mapping, Self, Union
5
+
6
+ from pydantic import AliasChoices, BaseModel, Field
7
+ from pydantic.config import ConfigDict
8
+
9
+
10
+ class Operator(str, Enum):
11
+ EQUALS = "equals"
12
+ NOT_EQUALS = "notEquals"
13
+ GREATER_THAN = "greaterThan"
14
+ GREATER_THAN_OR_EQUAL = "greaterThanOrEqual"
15
+ LESS_THAN = "lessThan"
16
+ LESS_THAN_OR_EQUAL = "lessThanOrEqual"
17
+ IN = "in"
18
+ NOT_IN = "notIn"
19
+ CONTAINS = "contains"
20
+ NOT_CONTAINS = "notContains"
21
+ IS_NULL = "isNull"
22
+ IS_NOT_NULL = "isNotNull"
23
+ IS_EMPTY = "isEmpty"
24
+ IS_NOT_EMPTY = "isNotEmpty"
25
+ NESTED = "nested"
26
+
27
+
28
+ class BaseStatement(BaseModel):
29
+ model_config = ConfigDict(serialize_by_alias=True)
30
+
31
+ def with_variables(
32
+ self,
33
+ user_metadata: Mapping[str, Union[str, int, bool]],
34
+ tool_parameters: Mapping[str, Union[str, int, bool]],
35
+ ) -> Self:
36
+ return self._fill_in_variables(user_metadata, tool_parameters)
37
+
38
+ def is_compiled(self) -> bool:
39
+ # Serialize the object to json string
40
+ json_str = self.model_dump_json()
41
+ # Check if the json string has <T> or <T+> or <T-> or <toolParameters or <userMetadata
42
+ return (
43
+ "<T>" in json_str
44
+ or "<T+" in json_str
45
+ or "<T-" in json_str
46
+ or "<toolParameters" in json_str
47
+ or "<userMetadata" in json_str
48
+ )
49
+
50
+ def _fill_in_variables(
51
+ self,
52
+ user_metadata: Mapping[str, Union[str, int, bool]],
53
+ tool_parameters: Mapping[str, Union[str, int, bool]],
54
+ ) -> Self:
55
+ return self.model_copy()
56
+
57
+
58
+ class Statement(BaseStatement):
59
+ operator: Operator
60
+ value: Union[str, int, bool, list[str], "AndStatement", "OrStatement"]
61
+ path: List[str] = Field(default_factory=list)
62
+
63
+ def _fill_in_variables(
64
+ self,
65
+ user_metadata: Mapping[str, Union[str, int, bool]],
66
+ tool_parameters: Mapping[str, Union[str, int, bool]],
67
+ ) -> Self:
68
+ new_stmt = self.model_copy()
69
+ new_stmt.value = eval_operator(self, user_metadata, tool_parameters)
70
+ return new_stmt
71
+
72
+
73
+ class AndStatement(BaseStatement):
74
+ and_list: List[Union["Statement", "AndStatement", "OrStatement"]] = Field(
75
+ validation_alias=AliasChoices("and", "and_list"), serialization_alias="and"
76
+ )
77
+
78
+ def _fill_in_variables(
79
+ self,
80
+ user_metadata: Mapping[str, Union[str, int, bool]],
81
+ tool_parameters: Mapping[str, Union[str, int, bool]],
82
+ ) -> Self:
83
+ new_stmt = self.model_copy()
84
+ new_stmt.and_list = [
85
+ sub_query._fill_in_variables(user_metadata, tool_parameters)
86
+ for sub_query in self.and_list
87
+ ]
88
+ return new_stmt
89
+
90
+
91
+ class OrStatement(BaseStatement):
92
+ or_list: List[Union["Statement", "AndStatement", "OrStatement"]] = Field(
93
+ validation_alias=AliasChoices("or", "or_list"), serialization_alias="or"
94
+ )
95
+
96
+ def _fill_in_variables(
97
+ self,
98
+ user_metadata: Mapping[str, Union[str, int, bool]],
99
+ tool_parameters: Mapping[str, Union[str, int, bool]],
100
+ ) -> Self:
101
+ new_stmt = self.model_copy()
102
+ new_stmt.or_list = [
103
+ sub_query._fill_in_variables(user_metadata, tool_parameters)
104
+ for sub_query in self.or_list
105
+ ]
106
+ return new_stmt
107
+
108
+
109
+ # Update the forward references
110
+ Statement.model_rebuild()
111
+ AndStatement.model_rebuild()
112
+ OrStatement.model_rebuild()
113
+
114
+
115
+ UniqueQL = Union[Statement, AndStatement, OrStatement]
116
+
117
+
118
+ def is_array_of_strings(value: Any) -> bool:
119
+ return isinstance(value, list) and all(isinstance(item, str) for item in value)
120
+
121
+
122
+ def eval_operator(
123
+ query: Statement,
124
+ user_metadata: Mapping[str, Union[str, int, bool]],
125
+ tool_parameters: Mapping[str, Union[str, int, bool]],
126
+ ) -> Any:
127
+ if query.operator in [
128
+ Operator.EQUALS,
129
+ Operator.NOT_EQUALS,
130
+ Operator.GREATER_THAN,
131
+ Operator.GREATER_THAN_OR_EQUAL,
132
+ Operator.LESS_THAN,
133
+ Operator.LESS_THAN_OR_EQUAL,
134
+ Operator.CONTAINS,
135
+ Operator.NOT_CONTAINS,
136
+ ]:
137
+ return binary_operator(query.value, user_metadata, tool_parameters)
138
+ elif query.operator in [Operator.IS_NULL, Operator.IS_NOT_NULL]:
139
+ return null_operator(query.value, user_metadata, tool_parameters)
140
+ elif query.operator in [Operator.IS_EMPTY, Operator.IS_NOT_EMPTY]:
141
+ return empty_operator(query.operator, user_metadata, tool_parameters)
142
+ elif query.operator == Operator.NESTED:
143
+ return eval_nested_operator(query.value, user_metadata, tool_parameters)
144
+ elif query.operator in [Operator.IN, Operator.NOT_IN]:
145
+ return array_operator(query.value, user_metadata, tool_parameters)
146
+ else:
147
+ raise ValueError(f"Operator {query.operator} not supported")
148
+
149
+
150
+ def eval_nested_operator(
151
+ value: Any,
152
+ user_metadata: Mapping[str, Union[str, int, bool]],
153
+ tool_parameters: Mapping[str, Union[str, int, bool]],
154
+ ) -> Union[AndStatement, OrStatement]:
155
+ if not isinstance(value, (AndStatement, OrStatement)):
156
+ raise ValueError("Nested operator must be an AndStatement or OrStatement")
157
+ return value._fill_in_variables(user_metadata, tool_parameters)
158
+
159
+
160
+ def binary_operator(
161
+ value: Any,
162
+ user_metadata: Mapping[str, Union[str, int, bool]],
163
+ tool_parameters: Mapping[str, Union[str, int, bool]],
164
+ ) -> Any:
165
+ return replace_variables(value, user_metadata, tool_parameters)
166
+
167
+
168
+ def array_operator(
169
+ value: Any,
170
+ user_metadata: Mapping[str, Union[str, int, bool]],
171
+ tool_parameters: Mapping[str, Union[str, int, bool]],
172
+ ) -> Any:
173
+ if is_array_of_strings(value):
174
+ return [
175
+ replace_variables(item, user_metadata, tool_parameters) for item in value
176
+ ]
177
+ return value
178
+
179
+
180
+ def null_operator(
181
+ value: Any,
182
+ user_metadata: Mapping[str, Union[str, int, bool]],
183
+ tool_parameters: Mapping[str, Union[str, int, bool]],
184
+ ) -> Any:
185
+ return value # do nothing for now. No variables to replace
186
+
187
+
188
+ def empty_operator(
189
+ operator: Operator,
190
+ user_metadata: Mapping[str, Union[str, int, bool]],
191
+ tool_parameters: Mapping[str, Union[str, int, bool]],
192
+ ) -> Any:
193
+ """Handle IS_EMPTY and IS_NOT_EMPTY operators."""
194
+ if operator == Operator.IS_EMPTY:
195
+ return ""
196
+ elif operator == Operator.IS_NOT_EMPTY:
197
+ return "not_empty"
198
+ return None
199
+
200
+
201
+ def calculate_current_date() -> str:
202
+ """Calculate current date in UTC with seconds precision."""
203
+ return datetime.now(timezone.utc).isoformat(timespec="seconds")
204
+
205
+
206
+ def calculate_earlier_date(input_str: str) -> str:
207
+ match = re.search(r"<T-(\d+)>", input_str)
208
+ if not match:
209
+ return calculate_current_date() # Return current date if no match
210
+ days = int(match.group(1))
211
+ return (datetime.now(timezone.utc) - timedelta(days=days)).isoformat(
212
+ timespec="seconds"
213
+ )
214
+
215
+
216
+ def calculate_later_date(input_str: str) -> str:
217
+ match = re.search(r"<T\+(\d+)>", input_str) # Note: escaped + in regex
218
+ if not match:
219
+ return calculate_current_date() # Return current date if no match
220
+ days = int(match.group(1))
221
+ return (datetime.now(timezone.utc) + timedelta(days=days)).isoformat(
222
+ timespec="seconds"
223
+ )
224
+
225
+
226
+ def replace_variables(
227
+ value: Any,
228
+ user_metadata: Mapping[str, Union[str, int, bool]],
229
+ tool_parameters: Mapping[str, Union[str, int, bool]],
230
+ ) -> Any:
231
+ if isinstance(value, str):
232
+ if "||" in value:
233
+ return get_fallback_values(value, user_metadata, tool_parameters)
234
+ elif value == "<T>":
235
+ return calculate_current_date()
236
+ elif "<T-" in value:
237
+ return calculate_earlier_date(value)
238
+ elif "<T+" in value:
239
+ return calculate_later_date(value)
240
+
241
+ value = replace_tool_parameters_patterns(value, tool_parameters)
242
+ value = replace_user_metadata_patterns(value, user_metadata)
243
+
244
+ if value == "":
245
+ return value
246
+ try:
247
+ return int(value)
248
+ except ValueError:
249
+ if value.lower() in ["true", "false"]:
250
+ return value.lower() == "true"
251
+ return value
252
+ return value
253
+
254
+
255
+ def replace_tool_parameters_patterns(
256
+ value: str, tool_parameters: Dict[str, Union[str, int, bool]]
257
+ ) -> str:
258
+ def replace_match(match):
259
+ param_name = match.group(1)
260
+ return str(tool_parameters.get(param_name, ""))
261
+
262
+ return re.sub(r"<toolParameters\.(\w+)>", replace_match, value)
263
+
264
+
265
+ def replace_user_metadata_patterns(
266
+ value: str, user_metadata: Dict[str, Union[str, int, bool]]
267
+ ) -> str:
268
+ def replace_match(match):
269
+ param_name = match.group(1)
270
+ return str(user_metadata.get(param_name, ""))
271
+
272
+ return re.sub(r"<userMetadata\.(\w+)>", replace_match, value)
273
+
274
+
275
+ def get_fallback_values(
276
+ value: str,
277
+ user_metadata: Mapping[str, Union[str, int, bool]],
278
+ tool_parameters: Mapping[str, Union[str, int, bool]],
279
+ ) -> Any:
280
+ values = value.split("||")
281
+ for val in values:
282
+ data = replace_variables(val, user_metadata, tool_parameters)
283
+ if data != "":
284
+ return data
285
+ return values
286
+
287
+
288
+ # Example usage:
289
+ def parse_uniqueql(json_data: Dict[str, Any]) -> UniqueQL:
290
+ if "operator" in json_data:
291
+ return Statement.model_validate(json_data)
292
+ elif "or" in json_data:
293
+ return OrStatement.model_validate(
294
+ {"or": [parse_uniqueql(item) for item in json_data["or"]]}
295
+ )
296
+ elif "and" in json_data:
297
+ return AndStatement.model_validate(
298
+ {"and": [parse_uniqueql(item) for item in json_data["and"]]}
299
+ )
300
+ else:
301
+ raise ValueError("Invalid UniqueQL format")
@@ -1,301 +1,56 @@
1
- import re
2
- from datetime import datetime, timedelta, timezone
3
- from enum import Enum
4
- from typing import Any, Dict, List, Self, Union
5
-
6
- from pydantic import AliasChoices, BaseModel, Field
7
- from pydantic.config import ConfigDict
8
-
9
-
10
- class Operator(str, Enum):
11
- EQUALS = "equals"
12
- NOT_EQUALS = "notEquals"
13
- GREATER_THAN = "greaterThan"
14
- GREATER_THAN_OR_EQUAL = "greaterThanOrEqual"
15
- LESS_THAN = "lessThan"
16
- LESS_THAN_OR_EQUAL = "lessThanOrEqual"
17
- IN = "in"
18
- NOT_IN = "notIn"
19
- CONTAINS = "contains"
20
- NOT_CONTAINS = "notContains"
21
- IS_NULL = "isNull"
22
- IS_NOT_NULL = "isNotNull"
23
- IS_EMPTY = "isEmpty"
24
- IS_NOT_EMPTY = "isNotEmpty"
25
- NESTED = "nested"
26
-
27
-
28
- class BaseStatement(BaseModel):
29
- model_config = ConfigDict(serialize_by_alias=True)
30
-
31
- def with_variables(
32
- self,
33
- user_metadata: Dict[str, Union[str, int, bool]],
34
- tool_parameters: Dict[str, Union[str, int, bool]],
35
- ) -> Self:
36
- return self._fill_in_variables(user_metadata, tool_parameters)
37
-
38
- def is_compiled(self) -> bool:
39
- # Serialize the object to json string
40
- json_str = self.model_dump_json()
41
- # Check if the json string has <T> or <T+> or <T-> or <toolParameters or <userMetadata
42
- return (
43
- "<T>" in json_str
44
- or "<T+" in json_str
45
- or "<T-" in json_str
46
- or "<toolParameters" in json_str
47
- or "<userMetadata" in json_str
48
- )
49
-
50
- def _fill_in_variables(
51
- self,
52
- user_metadata: Dict[str, Union[str, int, bool]],
53
- tool_parameters: Dict[str, Union[str, int, bool]],
54
- ) -> Self:
55
- return self.model_copy()
56
-
57
-
58
- class Statement(BaseStatement):
59
- operator: Operator
60
- value: Union[str, int, bool, list[str], "AndStatement", "OrStatement"]
61
- path: List[str] = Field(default_factory=list)
62
-
63
- def _fill_in_variables(
64
- self,
65
- user_metadata: Dict[str, Union[str, int, bool]],
66
- tool_parameters: Dict[str, Union[str, int, bool]],
67
- ) -> Self:
68
- new_stmt = self.model_copy()
69
- new_stmt.value = eval_operator(self, user_metadata, tool_parameters)
70
- return new_stmt
71
-
72
-
73
- class AndStatement(BaseStatement):
74
- and_list: List[Union["Statement", "AndStatement", "OrStatement"]] = Field(
75
- alias="and", validation_alias=AliasChoices("and", "and_list")
76
- )
77
-
78
- def _fill_in_variables(
79
- self,
80
- user_metadata: Dict[str, Union[str, int, bool]],
81
- tool_parameters: Dict[str, Union[str, int, bool]],
82
- ) -> Self:
83
- new_stmt = self.model_copy()
84
- new_stmt.and_list = [
85
- sub_query._fill_in_variables(user_metadata, tool_parameters)
86
- for sub_query in self.and_list
87
- ]
88
- return new_stmt
89
-
90
-
91
- class OrStatement(BaseStatement):
92
- or_list: List[Union["Statement", "AndStatement", "OrStatement"]] = Field(
93
- alias="or", validation_alias=AliasChoices("or", "or_list")
94
- )
95
-
96
- def _fill_in_variables(
97
- self,
98
- user_metadata: Dict[str, Union[str, int, bool]],
99
- tool_parameters: Dict[str, Union[str, int, bool]],
100
- ) -> Self:
101
- new_stmt = self.model_copy()
102
- new_stmt.or_list = [
103
- sub_query._fill_in_variables(user_metadata, tool_parameters)
104
- for sub_query in self.or_list
105
- ]
106
- return new_stmt
107
-
108
-
109
- # Update the forward references
110
- Statement.model_rebuild()
111
- AndStatement.model_rebuild()
112
- OrStatement.model_rebuild()
113
-
114
-
115
- UniqueQL = Union[Statement, AndStatement, OrStatement]
116
-
117
-
118
- def is_array_of_strings(value: Any) -> bool:
119
- return isinstance(value, list) and all(isinstance(item, str) for item in value)
120
-
121
-
122
- def eval_operator(
123
- query: Statement,
124
- user_metadata: Dict[str, Union[str, int, bool]],
125
- tool_parameters: Dict[str, Union[str, int, bool]],
126
- ) -> Any:
127
- if query.operator in [
128
- Operator.EQUALS,
129
- Operator.NOT_EQUALS,
130
- Operator.GREATER_THAN,
131
- Operator.GREATER_THAN_OR_EQUAL,
132
- Operator.LESS_THAN,
133
- Operator.LESS_THAN_OR_EQUAL,
134
- Operator.CONTAINS,
135
- Operator.NOT_CONTAINS,
136
- ]:
137
- return binary_operator(query.value, user_metadata, tool_parameters)
138
- elif query.operator in [Operator.IS_NULL, Operator.IS_NOT_NULL]:
139
- return null_operator(query.value, user_metadata, tool_parameters)
140
- elif query.operator in [Operator.IS_EMPTY, Operator.IS_NOT_EMPTY]:
141
- return empty_operator(query.operator, user_metadata, tool_parameters)
142
- elif query.operator == Operator.NESTED:
143
- return eval_nested_operator(query.value, user_metadata, tool_parameters)
144
- elif query.operator in [Operator.IN, Operator.NOT_IN]:
145
- return array_operator(query.value, user_metadata, tool_parameters)
146
- else:
147
- raise ValueError(f"Operator {query.operator} not supported")
148
-
149
-
150
- def eval_nested_operator(
151
- value: Any,
152
- user_metadata: Dict[str, Union[str, int, bool]],
153
- tool_parameters: Dict[str, Union[str, int, bool]],
154
- ) -> Union[AndStatement, OrStatement]:
155
- if not isinstance(value, (AndStatement, OrStatement)):
156
- raise ValueError("Nested operator must be an AndStatement or OrStatement")
157
- return value._fill_in_variables(user_metadata, tool_parameters)
158
-
159
-
160
- def binary_operator(
161
- value: Any,
162
- user_metadata: Dict[str, Union[str, int, bool]],
163
- tool_parameters: Dict[str, Union[str, int, bool]],
164
- ) -> Any:
165
- return replace_variables(value, user_metadata, tool_parameters)
166
-
167
-
168
- def array_operator(
169
- value: Any,
170
- user_metadata: Dict[str, Union[str, int, bool]],
171
- tool_parameters: Dict[str, Union[str, int, bool]],
172
- ) -> Any:
173
- if is_array_of_strings(value):
174
- return [
175
- replace_variables(item, user_metadata, tool_parameters) for item in value
176
- ]
177
- return value
178
-
179
-
180
- def null_operator(
181
- value: Any,
182
- user_metadata: Dict[str, Union[str, int, bool]],
183
- tool_parameters: Dict[str, Union[str, int, bool]],
184
- ) -> Any:
185
- return value # do nothing for now. No variables to replace
186
-
187
-
188
- def empty_operator(
189
- operator: Operator,
190
- user_metadata: Dict[str, Union[str, int, bool]],
191
- tool_parameters: Dict[str, Union[str, int, bool]],
192
- ) -> Any:
193
- """Handle IS_EMPTY and IS_NOT_EMPTY operators."""
194
- if operator == Operator.IS_EMPTY:
195
- return ""
196
- elif operator == Operator.IS_NOT_EMPTY:
197
- return "not_empty"
198
- return None
199
-
200
-
201
- def calculate_current_date() -> str:
202
- """Calculate current date in UTC with seconds precision."""
203
- return datetime.now(timezone.utc).isoformat(timespec="seconds")
204
-
205
-
206
- def calculate_earlier_date(input_str: str) -> str:
207
- match = re.search(r"<T-(\d+)>", input_str)
208
- if not match:
209
- return calculate_current_date() # Return current date if no match
210
- days = int(match.group(1))
211
- return (datetime.now(timezone.utc) - timedelta(days=days)).isoformat(
212
- timespec="seconds"
213
- )
214
-
215
-
216
- def calculate_later_date(input_str: str) -> str:
217
- match = re.search(r"<T\+(\d+)>", input_str) # Note: escaped + in regex
218
- if not match:
219
- return calculate_current_date() # Return current date if no match
220
- days = int(match.group(1))
221
- return (datetime.now(timezone.utc) + timedelta(days=days)).isoformat(
222
- timespec="seconds"
223
- )
224
-
225
-
226
- def replace_variables(
227
- value: Any,
228
- user_metadata: Dict[str, Union[str, int, bool]],
229
- tool_parameters: Dict[str, Union[str, int, bool]],
230
- ) -> Any:
231
- if isinstance(value, str):
232
- if "||" in value:
233
- return get_fallback_values(value, user_metadata, tool_parameters)
234
- elif value == "<T>":
235
- return calculate_current_date()
236
- elif "<T-" in value:
237
- return calculate_earlier_date(value)
238
- elif "<T+" in value:
239
- return calculate_later_date(value)
240
-
241
- value = replace_tool_parameters_patterns(value, tool_parameters)
242
- value = replace_user_metadata_patterns(value, user_metadata)
243
-
244
- if value == "":
245
- return value
246
- try:
247
- return int(value)
248
- except ValueError:
249
- if value.lower() in ["true", "false"]:
250
- return value.lower() == "true"
251
- return value
252
- return value
253
-
254
-
255
- def replace_tool_parameters_patterns(
256
- value: str, tool_parameters: Dict[str, Union[str, int, bool]]
257
- ) -> str:
258
- def replace_match(match):
259
- param_name = match.group(1)
260
- return str(tool_parameters.get(param_name, ""))
261
-
262
- return re.sub(r"<toolParameters\.(\w+)>", replace_match, value)
263
-
264
-
265
- def replace_user_metadata_patterns(
266
- value: str, user_metadata: Dict[str, Union[str, int, bool]]
267
- ) -> str:
268
- def replace_match(match):
269
- param_name = match.group(1)
270
- return str(user_metadata.get(param_name, ""))
271
-
272
- return re.sub(r"<userMetadata\.(\w+)>", replace_match, value)
273
-
274
-
275
- def get_fallback_values(
276
- value: str,
277
- user_metadata: Dict[str, Union[str, int, bool]],
278
- tool_parameters: Dict[str, Union[str, int, bool]],
279
- ) -> Any:
280
- values = value.split("||")
281
- for val in values:
282
- data = replace_variables(val, user_metadata, tool_parameters)
283
- if data != "":
284
- return data
285
- return values
286
-
287
-
288
- # Example usage:
289
- def parse_uniqueql(json_data: Dict[str, Any]) -> UniqueQL:
290
- if "operator" in json_data:
291
- return Statement.model_validate(json_data)
292
- elif "or" in json_data:
293
- return OrStatement.model_validate(
294
- {"or": [parse_uniqueql(item) for item in json_data["or"]]}
295
- )
296
- elif "and" in json_data:
297
- return AndStatement.model_validate(
298
- {"and": [parse_uniqueql(item) for item in json_data["and"]]}
299
- )
300
- else:
301
- raise ValueError("Invalid UniqueQL format")
1
+ import warnings
2
+
3
+ from unique_toolkit.content.smart_rules import (
4
+ AndStatement,
5
+ BaseStatement,
6
+ Operator,
7
+ OrStatement,
8
+ Statement,
9
+ UniqueQL,
10
+ array_operator,
11
+ binary_operator,
12
+ calculate_current_date,
13
+ calculate_earlier_date,
14
+ calculate_later_date,
15
+ empty_operator,
16
+ eval_nested_operator,
17
+ eval_operator,
18
+ get_fallback_values,
19
+ is_array_of_strings,
20
+ null_operator,
21
+ parse_uniqueql,
22
+ replace_tool_parameters_patterns,
23
+ replace_user_metadata_patterns,
24
+ replace_variables,
25
+ )
26
+
27
+ warnings.warn(
28
+ "unique_toolkit.smart_rules.compile is deprecated. "
29
+ "Please use unique_toolkit.content.smart_rules instead.",
30
+ DeprecationWarning,
31
+ stacklevel=2,
32
+ )
33
+
34
+ __all__ = [
35
+ "AndStatement",
36
+ "BaseStatement",
37
+ "Operator",
38
+ "OrStatement",
39
+ "Statement",
40
+ "UniqueQL",
41
+ "array_operator",
42
+ "binary_operator",
43
+ "calculate_current_date",
44
+ "calculate_earlier_date",
45
+ "calculate_later_date",
46
+ "empty_operator",
47
+ "eval_nested_operator",
48
+ "eval_operator",
49
+ "get_fallback_values",
50
+ "is_array_of_strings",
51
+ "null_operator",
52
+ "parse_uniqueql",
53
+ "replace_tool_parameters_patterns",
54
+ "replace_user_metadata_patterns",
55
+ "replace_variables",
56
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 1.11.2
3
+ Version: 1.11.4
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Cedric Klinkert
@@ -118,6 +118,14 @@ All notable changes to this project will be documented in this file.
118
118
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
119
119
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
120
120
 
121
+
122
+ ## [1.11.4] - 2026-10-06
123
+ - Make newer `MessageExecution` and `MessageLog` method keyword only
124
+
125
+ ## [1.11.3] - 2026-10-06
126
+ - Move smart rules to content
127
+ - Add to documentation
128
+
121
129
  ## [1.11.2] - 2025-10-07
122
130
  - Fix for empty metadata filter at info retrieval
123
131
 
@@ -135,6 +143,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
135
143
  ## [1.9.1] - 2025-10-06
136
144
  - Switch default model used in evaluation service from `GPT-3.5-turbo (0125)` to `GPT-4o (1120)`
137
145
 
146
+
138
147
  ## [1.9.0] - 2026-10-04
139
148
  - Define the RequestContext and add aihttp/httpx requestors
140
149
 
@@ -107,7 +107,7 @@ unique_toolkit/chat/constants.py,sha256=05kq6zjqUVB2d6_P7s-90nbljpB3ryxwCI-CAz0r
107
107
  unique_toolkit/chat/deprecated/service.py,sha256=CYwzXi7OB0RjHd73CO2jq8SlpdBmDYLatzPFkb5sA0k,6529
108
108
  unique_toolkit/chat/functions.py,sha256=qxBjxIFoko5vyQNJDYpIkMtBhEGGcSlWn6fkAY-dFVE,45213
109
109
  unique_toolkit/chat/schemas.py,sha256=u3WPdMkOlmwPGHUueQC-nk8k-QkM7ZSUcU0f-32g6Uc,6718
110
- unique_toolkit/chat/service.py,sha256=fHiaHWHe4BJDwUX6bw6uzpxmk8E07Hyi5rz3QR75xNs,54454
110
+ unique_toolkit/chat/service.py,sha256=ZiVQiNBv54GKdPeiPKCmFzdkt0poLKxAuQejtu7p8lE,54630
111
111
  unique_toolkit/chat/state.py,sha256=Cjgwv_2vhDFbV69xxsn7SefhaoIAEqLx3ferdVFCnOg,1445
112
112
  unique_toolkit/chat/utils.py,sha256=ihm-wQykBWhB4liR3LnwPVPt_qGW6ETq21Mw4HY0THE,854
113
113
  unique_toolkit/content/__init__.py,sha256=EdJg_A_7loEtCQf4cah3QARQreJx6pdz89Rm96YbMVg,940
@@ -115,6 +115,7 @@ unique_toolkit/content/constants.py,sha256=1iy4Y67xobl5VTnJB6SxSyuoBWbdLl9244xfV
115
115
  unique_toolkit/content/functions.py,sha256=6Z9fOEsngJaT1R5DgoeRl5z06RavYgCxiAAPjkw-NKI,21100
116
116
  unique_toolkit/content/schemas.py,sha256=YmZa6ddjf6_RvDFGPovamLd0YX99am9nzWYrKHo8-Hg,5579
117
117
  unique_toolkit/content/service.py,sha256=i7wN_wYjF8NBZHBcpcA5XRlMRGntuw3mlVoudAoGQRk,23293
118
+ unique_toolkit/content/smart_rules.py,sha256=z2gHToPrdyj3HqO8Uu-JE5G2ClvJPuhR2XERmmkgoug,9668
118
119
  unique_toolkit/content/utils.py,sha256=qNVmHTuETaPNGqheg7TbgPr1_1jbNHDc09N5RrmUIyo,7901
119
120
  unique_toolkit/embedding/__init__.py,sha256=uUyzjonPvuDCYsvXCIt7ErQXopLggpzX-MEQd3_e2kE,250
120
121
  unique_toolkit/embedding/constants.py,sha256=Lj8-Lcy1FvuC31PM9Exq7vaFuxQV4pEI1huUMFX-J2M,52
@@ -147,8 +148,8 @@ unique_toolkit/short_term_memory/functions.py,sha256=3WiK-xatY5nh4Dr5zlDUye1k3E6
147
148
  unique_toolkit/short_term_memory/schemas.py,sha256=OhfcXyF6ACdwIXW45sKzjtZX_gkcJs8FEZXcgQTNenw,1406
148
149
  unique_toolkit/short_term_memory/service.py,sha256=5PeVBu1ZCAfyDb2HLVvlmqSbyzBBuE9sI2o9Aajqjxg,8884
149
150
  unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
150
- unique_toolkit/smart_rules/compile.py,sha256=cxWjb2dxEI2HGsakKdVCkSNi7VK9mr08w5sDcFCQyWI,9553
151
- unique_toolkit-1.11.2.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
152
- unique_toolkit-1.11.2.dist-info/METADATA,sha256=IdERxyqJO7c7OzqAkm1CrB5sXxC2Wu96_VAXakkjvgo,35670
153
- unique_toolkit-1.11.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
154
- unique_toolkit-1.11.2.dist-info/RECORD,,
151
+ unique_toolkit/smart_rules/compile.py,sha256=Ozhh70qCn2yOzRWr9d8WmJeTo7AQurwd3tStgBMPFLA,1246
152
+ unique_toolkit-1.11.4.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
153
+ unique_toolkit-1.11.4.dist-info/METADATA,sha256=nhVP6zWNPT1ZyPLFs7aTVRklPbTFIcXNmMBMGPwsUA4,35846
154
+ unique_toolkit-1.11.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
155
+ unique_toolkit-1.11.4.dist-info/RECORD,,