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.
- unique_toolkit/__init__.py +20 -0
- unique_toolkit/_common/api_calling/human_verification_manager.py +121 -28
- unique_toolkit/_common/chunk_relevancy_sorter/config.py +3 -3
- unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +2 -5
- unique_toolkit/_common/default_language_model.py +9 -3
- unique_toolkit/_common/docx_generator/__init__.py +7 -0
- unique_toolkit/_common/docx_generator/config.py +12 -0
- unique_toolkit/_common/docx_generator/schemas.py +80 -0
- unique_toolkit/_common/docx_generator/service.py +252 -0
- unique_toolkit/_common/docx_generator/template/Doc Template.docx +0 -0
- unique_toolkit/_common/endpoint_builder.py +138 -117
- unique_toolkit/_common/endpoint_requestor.py +240 -14
- unique_toolkit/_common/exception.py +20 -0
- unique_toolkit/_common/feature_flags/schema.py +1 -5
- unique_toolkit/_common/referencing.py +53 -0
- unique_toolkit/_common/string_utilities.py +52 -1
- unique_toolkit/_common/tests/test_referencing.py +521 -0
- unique_toolkit/_common/tests/test_string_utilities.py +506 -0
- unique_toolkit/_common/utils/files.py +43 -0
- unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +16 -6
- unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py +278 -0
- unique_toolkit/agentic/evaluation/config.py +3 -2
- unique_toolkit/agentic/evaluation/context_relevancy/service.py +2 -2
- unique_toolkit/agentic/evaluation/evaluation_manager.py +9 -5
- unique_toolkit/agentic/evaluation/hallucination/constants.py +1 -1
- unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +26 -3
- unique_toolkit/agentic/history_manager/history_manager.py +14 -11
- unique_toolkit/agentic/history_manager/loop_token_reducer.py +3 -4
- unique_toolkit/agentic/history_manager/utils.py +10 -87
- unique_toolkit/agentic/postprocessor/postprocessor_manager.py +107 -16
- unique_toolkit/agentic/reference_manager/reference_manager.py +1 -1
- unique_toolkit/agentic/responses_api/__init__.py +19 -0
- unique_toolkit/agentic/responses_api/postprocessors/code_display.py +63 -0
- unique_toolkit/agentic/responses_api/postprocessors/generated_files.py +145 -0
- unique_toolkit/agentic/responses_api/stream_handler.py +15 -0
- unique_toolkit/agentic/tools/a2a/__init__.py +18 -2
- unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +2 -0
- unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +3 -3
- unique_toolkit/agentic/tools/a2a/evaluation/config.py +1 -1
- unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +143 -91
- unique_toolkit/agentic/tools/a2a/manager.py +7 -1
- unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +11 -3
- unique_toolkit/agentic/tools/a2a/postprocessing/_display_utils.py +185 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/_ref_utils.py +73 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/config.py +21 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/display.py +180 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/references.py +101 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display_utils.py +1335 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/test/test_ref_utils.py +603 -0
- unique_toolkit/agentic/tools/a2a/prompts.py +46 -0
- unique_toolkit/agentic/tools/a2a/response_watcher/__init__.py +6 -0
- unique_toolkit/agentic/tools/a2a/response_watcher/service.py +91 -0
- unique_toolkit/agentic/tools/a2a/tool/config.py +15 -5
- unique_toolkit/agentic/tools/a2a/tool/service.py +69 -36
- unique_toolkit/agentic/tools/config.py +16 -2
- unique_toolkit/agentic/tools/factory.py +4 -0
- unique_toolkit/agentic/tools/mcp/tool_wrapper.py +7 -35
- unique_toolkit/agentic/tools/openai_builtin/__init__.py +11 -0
- unique_toolkit/agentic/tools/openai_builtin/base.py +30 -0
- unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py +8 -0
- unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py +57 -0
- unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py +230 -0
- unique_toolkit/agentic/tools/openai_builtin/manager.py +62 -0
- unique_toolkit/agentic/tools/test/test_mcp_manager.py +95 -7
- unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +240 -0
- unique_toolkit/agentic/tools/tool.py +0 -11
- unique_toolkit/agentic/tools/tool_manager.py +337 -122
- unique_toolkit/agentic/tools/tool_progress_reporter.py +81 -15
- unique_toolkit/agentic/tools/utils/__init__.py +18 -0
- unique_toolkit/agentic/tools/utils/execution/execution.py +8 -4
- unique_toolkit/agentic/tools/utils/source_handling/schema.py +1 -1
- unique_toolkit/chat/__init__.py +8 -1
- unique_toolkit/chat/deprecated/service.py +232 -0
- unique_toolkit/chat/functions.py +54 -40
- unique_toolkit/chat/rendering.py +34 -0
- unique_toolkit/chat/responses_api.py +461 -0
- unique_toolkit/chat/schemas.py +1 -1
- unique_toolkit/chat/service.py +96 -1569
- unique_toolkit/content/functions.py +116 -1
- unique_toolkit/content/schemas.py +59 -0
- unique_toolkit/content/service.py +5 -37
- unique_toolkit/content/smart_rules.py +301 -0
- unique_toolkit/framework_utilities/langchain/client.py +27 -3
- unique_toolkit/framework_utilities/openai/client.py +12 -1
- unique_toolkit/framework_utilities/openai/message_builder.py +85 -1
- unique_toolkit/language_model/default_language_model.py +3 -0
- unique_toolkit/language_model/functions.py +25 -9
- unique_toolkit/language_model/infos.py +72 -4
- unique_toolkit/language_model/schemas.py +246 -40
- unique_toolkit/protocols/support.py +91 -9
- unique_toolkit/services/__init__.py +7 -0
- unique_toolkit/services/chat_service.py +1630 -0
- unique_toolkit/services/knowledge_base.py +861 -0
- unique_toolkit/smart_rules/compile.py +56 -301
- unique_toolkit/test_utilities/events.py +197 -0
- {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/METADATA +173 -3
- {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/RECORD +99 -67
- unique_toolkit/agentic/tools/a2a/postprocessing/_display.py +0 -122
- unique_toolkit/agentic/tools/a2a/postprocessing/_utils.py +0 -19
- unique_toolkit/agentic/tools/a2a/postprocessing/postprocessor.py +0 -230
- unique_toolkit/agentic/tools/a2a/postprocessing/test/test_consolidate_references.py +0 -665
- unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display.py +0 -391
- unique_toolkit/agentic/tools/a2a/postprocessing/test/test_postprocessor_reference_functions.py +0 -256
- {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/LICENSE +0 -0
- {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/WHEEL +0 -0
|
@@ -1,301 +1,56 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
+
]
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import random
|
|
2
|
+
import string
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from unique_toolkit.app.schemas import (
|
|
7
|
+
BaseEvent,
|
|
8
|
+
ChatEvent,
|
|
9
|
+
ChatEventAdditionalParameters,
|
|
10
|
+
ChatEventAssistantMessage,
|
|
11
|
+
ChatEventPayload,
|
|
12
|
+
ChatEventUserMessage,
|
|
13
|
+
EventName,
|
|
14
|
+
)
|
|
15
|
+
from unique_toolkit.app.unique_settings import UniqueSettings
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def generated_numeric_string(length: int) -> str:
|
|
19
|
+
return "".join(random.choices(string.digits, k=length))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def generated_alphanumeric_string(length: int) -> str:
|
|
23
|
+
return "".join(random.choices(string.ascii_letters + string.digits, k=length))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def generated_chat_id() -> str:
|
|
27
|
+
return f"chat_{generated_alphanumeric_string(16)}"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def generated_assistant_id() -> str:
|
|
31
|
+
return f"assistant_{generated_alphanumeric_string(16)}"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def generated_user_message_id() -> str:
|
|
35
|
+
return f"msg_{generated_alphanumeric_string(16)}"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TestEventFactory:
|
|
39
|
+
"""Factory for creating test event objects with sensible defaults.
|
|
40
|
+
|
|
41
|
+
Simplifies test setup by providing convenient methods to generate
|
|
42
|
+
chat events, messages, and related objects for testing.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, settings: UniqueSettings | None = None) -> None:
|
|
46
|
+
self._settings = settings
|
|
47
|
+
|
|
48
|
+
def _get_user_id(self) -> str:
|
|
49
|
+
if self._settings is None:
|
|
50
|
+
return generated_numeric_string(16)
|
|
51
|
+
else:
|
|
52
|
+
return self._settings.auth.user_id.get_secret_value()
|
|
53
|
+
|
|
54
|
+
def _get_company_id(self) -> str:
|
|
55
|
+
if self._settings is None:
|
|
56
|
+
return generated_numeric_string(16)
|
|
57
|
+
else:
|
|
58
|
+
return self._settings.auth.company_id.get_secret_value()
|
|
59
|
+
|
|
60
|
+
def get_chat_event_user_message(
|
|
61
|
+
self,
|
|
62
|
+
text: str,
|
|
63
|
+
*,
|
|
64
|
+
created_at: datetime | None = None,
|
|
65
|
+
language: str = "DE",
|
|
66
|
+
original_text: str | None = None,
|
|
67
|
+
) -> ChatEventUserMessage:
|
|
68
|
+
if created_at is None:
|
|
69
|
+
created_at = datetime.now()
|
|
70
|
+
|
|
71
|
+
return ChatEventUserMessage(
|
|
72
|
+
id=generated_user_message_id(),
|
|
73
|
+
text=text,
|
|
74
|
+
original_text=original_text or text,
|
|
75
|
+
created_at=created_at.isoformat(),
|
|
76
|
+
language=language,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def get_chat_event_assistant_message(
|
|
80
|
+
self, *, created_at: datetime | None = None
|
|
81
|
+
) -> ChatEventAssistantMessage:
|
|
82
|
+
if created_at is None:
|
|
83
|
+
created_at = datetime.now()
|
|
84
|
+
|
|
85
|
+
return ChatEventAssistantMessage(
|
|
86
|
+
id=generated_assistant_id(), created_at=created_at.isoformat()
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
def get_chat_event_additional_parameters(
|
|
90
|
+
self,
|
|
91
|
+
*,
|
|
92
|
+
translate_to_language: str | None = None,
|
|
93
|
+
content_id_to_translate: str | None = None,
|
|
94
|
+
) -> ChatEventAdditionalParameters:
|
|
95
|
+
return ChatEventAdditionalParameters(
|
|
96
|
+
translate_to_language=translate_to_language,
|
|
97
|
+
content_id_to_translate=content_id_to_translate,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def get_base_event(
|
|
101
|
+
self,
|
|
102
|
+
*,
|
|
103
|
+
event: EventName = EventName.EXTERNAL_MODULE_CHOSEN,
|
|
104
|
+
user_id: str | None = None,
|
|
105
|
+
company_id: str | None = None,
|
|
106
|
+
) -> BaseEvent:
|
|
107
|
+
return BaseEvent(
|
|
108
|
+
id=generated_alphanumeric_string(16),
|
|
109
|
+
event=event,
|
|
110
|
+
user_id=user_id or self._get_user_id(),
|
|
111
|
+
company_id=company_id or self._get_company_id(),
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def get_chat_event_payload(
|
|
115
|
+
self,
|
|
116
|
+
*,
|
|
117
|
+
name: str,
|
|
118
|
+
description: str,
|
|
119
|
+
user_message_text: str,
|
|
120
|
+
user_message_created_at: datetime | None = None,
|
|
121
|
+
user_message_language: str = "DE",
|
|
122
|
+
user_message_original_text: str | None = None,
|
|
123
|
+
assistant_message_created_at: datetime | None = None,
|
|
124
|
+
configuration: dict[str, Any] | None = None,
|
|
125
|
+
chat_id: str | None = None,
|
|
126
|
+
assistant_id: str | None = None,
|
|
127
|
+
) -> ChatEventPayload:
|
|
128
|
+
if chat_id is None:
|
|
129
|
+
chat_id = generated_chat_id()
|
|
130
|
+
|
|
131
|
+
if assistant_id is None:
|
|
132
|
+
assistant_id = generated_assistant_id()
|
|
133
|
+
|
|
134
|
+
assistant_message = self.get_chat_event_assistant_message(
|
|
135
|
+
created_at=assistant_message_created_at or datetime.now()
|
|
136
|
+
)
|
|
137
|
+
user_message = self.get_chat_event_user_message(
|
|
138
|
+
text=user_message_text,
|
|
139
|
+
created_at=user_message_created_at or datetime.now(),
|
|
140
|
+
language=user_message_language,
|
|
141
|
+
original_text=user_message_original_text,
|
|
142
|
+
)
|
|
143
|
+
return ChatEventPayload(
|
|
144
|
+
name=name,
|
|
145
|
+
description=description,
|
|
146
|
+
configuration=configuration or {},
|
|
147
|
+
chat_id=chat_id,
|
|
148
|
+
assistant_id=assistant_id,
|
|
149
|
+
user_message=user_message,
|
|
150
|
+
assistant_message=assistant_message,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
def get_chat_event(
|
|
154
|
+
self,
|
|
155
|
+
*,
|
|
156
|
+
name: str,
|
|
157
|
+
event_name: EventName = EventName.EXTERNAL_MODULE_CHOSEN,
|
|
158
|
+
description: str,
|
|
159
|
+
user_message_text: str,
|
|
160
|
+
user_message_created_at: datetime = datetime.now(),
|
|
161
|
+
user_message_language: str = "DE",
|
|
162
|
+
user_message_original_text: str | None = None,
|
|
163
|
+
assistant_message_created_at: datetime | None = None,
|
|
164
|
+
configuration: dict[str, Any] | None = None,
|
|
165
|
+
chat_id: str | None = None,
|
|
166
|
+
assistant_id: str | None = None,
|
|
167
|
+
user_id: str | None = None,
|
|
168
|
+
company_id: str | None = None,
|
|
169
|
+
version: str = "1.0",
|
|
170
|
+
) -> ChatEvent:
|
|
171
|
+
if chat_id is None:
|
|
172
|
+
chat_id = generated_chat_id()
|
|
173
|
+
|
|
174
|
+
if assistant_id is None:
|
|
175
|
+
assistant_id = generated_assistant_id()
|
|
176
|
+
|
|
177
|
+
payload = self.get_chat_event_payload(
|
|
178
|
+
name=name,
|
|
179
|
+
description=description,
|
|
180
|
+
user_message_text=user_message_text,
|
|
181
|
+
user_message_created_at=user_message_created_at,
|
|
182
|
+
user_message_language=user_message_language,
|
|
183
|
+
user_message_original_text=user_message_original_text,
|
|
184
|
+
assistant_message_created_at=assistant_message_created_at,
|
|
185
|
+
configuration=configuration or {},
|
|
186
|
+
chat_id=chat_id,
|
|
187
|
+
assistant_id=assistant_id,
|
|
188
|
+
)
|
|
189
|
+
return ChatEvent(
|
|
190
|
+
id=generated_alphanumeric_string(16),
|
|
191
|
+
event=event_name,
|
|
192
|
+
user_id=user_id or self._get_user_id(),
|
|
193
|
+
company_id=company_id or self._get_company_id(),
|
|
194
|
+
payload=payload,
|
|
195
|
+
created_at=int(datetime.now().timestamp()),
|
|
196
|
+
version=version,
|
|
197
|
+
)
|