unique_toolkit 0.7.7__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 +28 -1
- unique_toolkit/_common/api_calling/human_verification_manager.py +343 -0
- unique_toolkit/_common/base_model_type_attribute.py +303 -0
- unique_toolkit/_common/chunk_relevancy_sorter/config.py +49 -0
- unique_toolkit/_common/chunk_relevancy_sorter/exception.py +5 -0
- unique_toolkit/_common/chunk_relevancy_sorter/schemas.py +46 -0
- unique_toolkit/_common/chunk_relevancy_sorter/service.py +374 -0
- unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +275 -0
- unique_toolkit/_common/default_language_model.py +12 -0
- 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 +305 -0
- unique_toolkit/_common/endpoint_requestor.py +430 -0
- unique_toolkit/_common/exception.py +24 -0
- unique_toolkit/_common/feature_flags/schema.py +9 -0
- unique_toolkit/_common/pydantic/rjsf_tags.py +936 -0
- unique_toolkit/_common/pydantic_helpers.py +154 -0
- unique_toolkit/_common/referencing.py +53 -0
- unique_toolkit/_common/string_utilities.py +140 -0
- unique_toolkit/_common/tests/test_referencing.py +521 -0
- unique_toolkit/_common/tests/test_string_utilities.py +506 -0
- unique_toolkit/_common/token/image_token_counting.py +67 -0
- unique_toolkit/_common/token/token_counting.py +204 -0
- unique_toolkit/_common/utils/__init__.py +1 -0
- unique_toolkit/_common/utils/files.py +43 -0
- unique_toolkit/_common/utils/structured_output/__init__.py +1 -0
- unique_toolkit/_common/utils/structured_output/schema.py +5 -0
- unique_toolkit/_common/utils/write_configuration.py +51 -0
- unique_toolkit/_common/validators.py +101 -4
- unique_toolkit/agentic/__init__.py +1 -0
- unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +28 -0
- unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py +278 -0
- unique_toolkit/agentic/evaluation/config.py +36 -0
- unique_toolkit/{evaluators → agentic/evaluation}/context_relevancy/prompts.py +25 -0
- unique_toolkit/agentic/evaluation/context_relevancy/schema.py +80 -0
- unique_toolkit/agentic/evaluation/context_relevancy/service.py +273 -0
- unique_toolkit/agentic/evaluation/evaluation_manager.py +218 -0
- unique_toolkit/agentic/evaluation/hallucination/constants.py +61 -0
- unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +111 -0
- unique_toolkit/{evaluators → agentic/evaluation}/hallucination/prompts.py +1 -1
- unique_toolkit/{evaluators → agentic/evaluation}/hallucination/service.py +16 -15
- unique_toolkit/{evaluators → agentic/evaluation}/hallucination/utils.py +30 -20
- unique_toolkit/{evaluators → agentic/evaluation}/output_parser.py +20 -2
- unique_toolkit/{evaluators → agentic/evaluation}/schemas.py +27 -7
- unique_toolkit/agentic/evaluation/tests/test_context_relevancy_service.py +253 -0
- unique_toolkit/agentic/evaluation/tests/test_output_parser.py +87 -0
- unique_toolkit/agentic/history_manager/history_construction_with_contents.py +297 -0
- unique_toolkit/agentic/history_manager/history_manager.py +242 -0
- unique_toolkit/agentic/history_manager/loop_token_reducer.py +484 -0
- unique_toolkit/agentic/history_manager/utils.py +96 -0
- unique_toolkit/agentic/postprocessor/postprocessor_manager.py +212 -0
- unique_toolkit/agentic/reference_manager/reference_manager.py +103 -0
- 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/short_term_memory_manager/persistent_short_term_memory_manager.py +141 -0
- unique_toolkit/agentic/thinking_manager/thinking_manager.py +103 -0
- unique_toolkit/agentic/tools/__init__.py +1 -0
- unique_toolkit/agentic/tools/a2a/__init__.py +36 -0
- unique_toolkit/agentic/tools/a2a/config.py +17 -0
- unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +15 -0
- unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +66 -0
- unique_toolkit/agentic/tools/a2a/evaluation/config.py +55 -0
- unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +260 -0
- unique_toolkit/agentic/tools/a2a/evaluation/summarization_user_message.j2 +9 -0
- unique_toolkit/agentic/tools/a2a/manager.py +55 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +21 -0
- 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 +45 -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/__init__.py +4 -0
- unique_toolkit/agentic/tools/a2a/tool/_memory.py +26 -0
- unique_toolkit/agentic/tools/a2a/tool/_schema.py +9 -0
- unique_toolkit/agentic/tools/a2a/tool/config.py +73 -0
- unique_toolkit/agentic/tools/a2a/tool/service.py +306 -0
- unique_toolkit/agentic/tools/agent_chunks_hanlder.py +65 -0
- unique_toolkit/agentic/tools/config.py +167 -0
- unique_toolkit/agentic/tools/factory.py +44 -0
- unique_toolkit/agentic/tools/mcp/__init__.py +4 -0
- unique_toolkit/agentic/tools/mcp/manager.py +71 -0
- unique_toolkit/agentic/tools/mcp/models.py +28 -0
- unique_toolkit/agentic/tools/mcp/tool_wrapper.py +234 -0
- 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/schemas.py +141 -0
- unique_toolkit/agentic/tools/test/test_mcp_manager.py +536 -0
- unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +445 -0
- unique_toolkit/agentic/tools/tool.py +183 -0
- unique_toolkit/agentic/tools/tool_manager.py +523 -0
- unique_toolkit/agentic/tools/tool_progress_reporter.py +285 -0
- unique_toolkit/agentic/tools/utils/__init__.py +19 -0
- unique_toolkit/agentic/tools/utils/execution/__init__.py +1 -0
- unique_toolkit/agentic/tools/utils/execution/execution.py +286 -0
- unique_toolkit/agentic/tools/utils/source_handling/__init__.py +0 -0
- unique_toolkit/agentic/tools/utils/source_handling/schema.py +21 -0
- unique_toolkit/agentic/tools/utils/source_handling/source_formatting.py +207 -0
- unique_toolkit/agentic/tools/utils/source_handling/tests/test_source_formatting.py +216 -0
- unique_toolkit/app/__init__.py +6 -0
- unique_toolkit/app/dev_util.py +180 -0
- unique_toolkit/app/init_sdk.py +32 -1
- unique_toolkit/app/schemas.py +198 -31
- unique_toolkit/app/unique_settings.py +367 -0
- unique_toolkit/chat/__init__.py +8 -1
- unique_toolkit/chat/deprecated/service.py +232 -0
- unique_toolkit/chat/functions.py +642 -77
- unique_toolkit/chat/rendering.py +34 -0
- unique_toolkit/chat/responses_api.py +461 -0
- unique_toolkit/chat/schemas.py +133 -2
- unique_toolkit/chat/service.py +115 -767
- unique_toolkit/content/functions.py +153 -4
- unique_toolkit/content/schemas.py +122 -15
- unique_toolkit/content/service.py +278 -44
- unique_toolkit/content/smart_rules.py +301 -0
- unique_toolkit/content/utils.py +8 -3
- unique_toolkit/embedding/service.py +102 -11
- unique_toolkit/framework_utilities/__init__.py +1 -0
- unique_toolkit/framework_utilities/langchain/client.py +71 -0
- unique_toolkit/framework_utilities/langchain/history.py +19 -0
- unique_toolkit/framework_utilities/openai/__init__.py +6 -0
- unique_toolkit/framework_utilities/openai/client.py +83 -0
- unique_toolkit/framework_utilities/openai/message_builder.py +229 -0
- unique_toolkit/framework_utilities/utils.py +23 -0
- unique_toolkit/language_model/__init__.py +3 -0
- unique_toolkit/language_model/builder.py +27 -11
- unique_toolkit/language_model/default_language_model.py +3 -0
- unique_toolkit/language_model/functions.py +327 -43
- unique_toolkit/language_model/infos.py +992 -50
- unique_toolkit/language_model/reference.py +242 -0
- unique_toolkit/language_model/schemas.py +475 -48
- unique_toolkit/language_model/service.py +228 -27
- unique_toolkit/protocols/support.py +145 -0
- 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/short_term_memory/service.py +178 -41
- unique_toolkit/smart_rules/__init__.py +0 -0
- unique_toolkit/smart_rules/compile.py +56 -0
- unique_toolkit/test_utilities/events.py +197 -0
- {unique_toolkit-0.7.7.dist-info → unique_toolkit-1.23.0.dist-info}/METADATA +606 -7
- unique_toolkit-1.23.0.dist-info/RECORD +182 -0
- unique_toolkit/evaluators/__init__.py +0 -1
- unique_toolkit/evaluators/config.py +0 -35
- unique_toolkit/evaluators/constants.py +0 -1
- unique_toolkit/evaluators/context_relevancy/constants.py +0 -32
- unique_toolkit/evaluators/context_relevancy/service.py +0 -53
- unique_toolkit/evaluators/context_relevancy/utils.py +0 -142
- unique_toolkit/evaluators/hallucination/constants.py +0 -41
- unique_toolkit-0.7.7.dist-info/RECORD +0 -64
- /unique_toolkit/{evaluators → agentic/evaluation}/exception.py +0 -0
- {unique_toolkit-0.7.7.dist-info → unique_toolkit-1.23.0.dist-info}/LICENSE +0 -0
- {unique_toolkit-0.7.7.dist-info → unique_toolkit-1.23.0.dist-info}/WHEEL +0 -0
|
@@ -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")
|
unique_toolkit/content/utils.py
CHANGED
|
@@ -190,9 +190,11 @@ def count_tokens(text: str, encoding_model="cl100k_base") -> int:
|
|
|
190
190
|
return len(encoding.encode(text))
|
|
191
191
|
|
|
192
192
|
|
|
193
|
-
def map_content_chunk(content_chunk: dict):
|
|
193
|
+
def map_content_chunk(content_id: str, content_key: str, content_chunk: dict):
|
|
194
194
|
return ContentChunk(
|
|
195
|
-
id=
|
|
195
|
+
id=content_id,
|
|
196
|
+
key=content_key,
|
|
197
|
+
chunk_id=content_chunk["id"],
|
|
196
198
|
text=content_chunk["text"],
|
|
197
199
|
start_page=content_chunk["startPage"],
|
|
198
200
|
end_page=content_chunk["endPage"],
|
|
@@ -206,7 +208,10 @@ def map_content(content: dict):
|
|
|
206
208
|
key=content["key"],
|
|
207
209
|
title=content["title"],
|
|
208
210
|
url=content["url"],
|
|
209
|
-
chunks=[
|
|
211
|
+
chunks=[
|
|
212
|
+
map_content_chunk(content["id"], content["key"], chunk)
|
|
213
|
+
for chunk in content["chunks"]
|
|
214
|
+
],
|
|
210
215
|
created_at=content["createdAt"],
|
|
211
216
|
updated_at=content["updatedAt"],
|
|
212
217
|
)
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
from typing import overload
|
|
2
|
+
|
|
1
3
|
from typing_extensions import deprecated
|
|
2
4
|
|
|
3
5
|
from unique_toolkit._common._base_service import BaseService
|
|
4
6
|
from unique_toolkit._common.validate_required_values import validate_required_values
|
|
5
7
|
from unique_toolkit.app.schemas import BaseEvent, Event
|
|
8
|
+
from unique_toolkit.app.unique_settings import UniqueSettings
|
|
6
9
|
from unique_toolkit.embedding.constants import DEFAULT_TIMEOUT
|
|
7
10
|
from unique_toolkit.embedding.functions import embed_texts, embed_texts_async
|
|
8
11
|
from unique_toolkit.embedding.schemas import Embeddings
|
|
@@ -11,10 +14,23 @@ from unique_toolkit.embedding.schemas import Embeddings
|
|
|
11
14
|
class EmbeddingService(BaseService):
|
|
12
15
|
"""
|
|
13
16
|
Provides methods to interact with the Embedding service.
|
|
17
|
+
"""
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
company_id
|
|
17
|
-
|
|
19
|
+
@deprecated(
|
|
20
|
+
"Use __init__ with company_id and user_id instead or use the classmethod `from_event`"
|
|
21
|
+
)
|
|
22
|
+
@overload
|
|
23
|
+
def __init__(self, event: Event | BaseEvent): ...
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
Initialize the EmbeddingService with an event (deprecated)
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
@overload
|
|
30
|
+
def __init__(self, *, company_id: str, user_id: str): ...
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
Initialize the EmbeddingService with a company_id and user_id.
|
|
18
34
|
"""
|
|
19
35
|
|
|
20
36
|
def __init__(
|
|
@@ -25,12 +41,35 @@ class EmbeddingService(BaseService):
|
|
|
25
41
|
):
|
|
26
42
|
self._event = event
|
|
27
43
|
if event:
|
|
28
|
-
self.
|
|
29
|
-
self.
|
|
44
|
+
self._company_id: str = event.company_id
|
|
45
|
+
self._user_id: str = event.user_id
|
|
30
46
|
else:
|
|
31
47
|
[company_id, user_id] = validate_required_values([company_id, user_id])
|
|
32
|
-
self.
|
|
33
|
-
self.
|
|
48
|
+
self._company_id: str = company_id
|
|
49
|
+
self._user_id: str = user_id
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def from_event(cls, event: Event | BaseEvent):
|
|
53
|
+
"""
|
|
54
|
+
Initialize the EmbeddingService with an event.
|
|
55
|
+
"""
|
|
56
|
+
return cls(company_id=event.company_id, user_id=event.user_id)
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def from_settings(cls, settings: UniqueSettings | str | None = None):
|
|
60
|
+
"""
|
|
61
|
+
Initialize the EmbeddingService with a settings object.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
if settings is None:
|
|
65
|
+
settings = UniqueSettings.from_env_auto_with_sdk_init()
|
|
66
|
+
elif isinstance(settings, str):
|
|
67
|
+
settings = UniqueSettings.from_env_auto_with_sdk_init(filename=settings)
|
|
68
|
+
|
|
69
|
+
return cls(
|
|
70
|
+
company_id=settings.auth.company_id.get_secret_value(),
|
|
71
|
+
user_id=settings.auth.user_id.get_secret_value(),
|
|
72
|
+
)
|
|
34
73
|
|
|
35
74
|
@property
|
|
36
75
|
@deprecated(
|
|
@@ -45,6 +84,58 @@ class EmbeddingService(BaseService):
|
|
|
45
84
|
"""
|
|
46
85
|
return self._event
|
|
47
86
|
|
|
87
|
+
@property
|
|
88
|
+
@deprecated(
|
|
89
|
+
"The company_id property is deprecated and will be removed in a future version."
|
|
90
|
+
)
|
|
91
|
+
def company_id(self) -> str | None:
|
|
92
|
+
"""
|
|
93
|
+
Get the company identifier (deprecated).
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
str | None: The company identifier.
|
|
97
|
+
"""
|
|
98
|
+
return self._company_id
|
|
99
|
+
|
|
100
|
+
@company_id.setter
|
|
101
|
+
@deprecated(
|
|
102
|
+
"The company_id setter is deprecated and will be removed in a future version."
|
|
103
|
+
)
|
|
104
|
+
def company_id(self, value: str) -> None:
|
|
105
|
+
"""
|
|
106
|
+
Set the company identifier (deprecated).
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
value (str | None): The company identifier.
|
|
110
|
+
"""
|
|
111
|
+
self._company_id = value
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
@deprecated(
|
|
115
|
+
"The user_id property is deprecated and will be removed in a future version."
|
|
116
|
+
)
|
|
117
|
+
def user_id(self) -> str | None:
|
|
118
|
+
"""
|
|
119
|
+
Get the user identifier (deprecated).
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
str | None: The user identifier.
|
|
123
|
+
"""
|
|
124
|
+
return self._user_id
|
|
125
|
+
|
|
126
|
+
@user_id.setter
|
|
127
|
+
@deprecated(
|
|
128
|
+
"The user_id setter is deprecated and will be removed in a future version."
|
|
129
|
+
)
|
|
130
|
+
def user_id(self, value: str) -> None:
|
|
131
|
+
"""
|
|
132
|
+
Set the user identifier (deprecated).
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
value (str | None): The user identifier.
|
|
136
|
+
"""
|
|
137
|
+
self._user_id = value
|
|
138
|
+
|
|
48
139
|
def embed_texts(
|
|
49
140
|
self,
|
|
50
141
|
texts: list[str],
|
|
@@ -64,8 +155,8 @@ class EmbeddingService(BaseService):
|
|
|
64
155
|
Exception: If an error occurs.
|
|
65
156
|
"""
|
|
66
157
|
return embed_texts(
|
|
67
|
-
user_id=self.
|
|
68
|
-
company_id=self.
|
|
158
|
+
user_id=self._user_id,
|
|
159
|
+
company_id=self._company_id,
|
|
69
160
|
texts=texts,
|
|
70
161
|
timeout=timeout,
|
|
71
162
|
)
|
|
@@ -89,8 +180,8 @@ class EmbeddingService(BaseService):
|
|
|
89
180
|
Exception: If an error occurs.
|
|
90
181
|
"""
|
|
91
182
|
return await embed_texts_async(
|
|
92
|
-
user_id=self.
|
|
93
|
-
company_id=self.
|
|
183
|
+
user_id=self._user_id,
|
|
184
|
+
company_id=self._company_id,
|
|
94
185
|
texts=texts,
|
|
95
186
|
timeout=timeout,
|
|
96
187
|
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Framework utilities for integrating with external frameworks."""
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import importlib.util
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from typing_extensions import deprecated
|
|
5
|
+
|
|
6
|
+
from unique_toolkit.app.unique_settings import UniqueSettings
|
|
7
|
+
from unique_toolkit.framework_utilities.utils import get_default_headers
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger("toolkit.framework_utilities.langchain")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class LangchainNotInstalledError(ImportError):
|
|
13
|
+
"""Raised when langchain-openai package is not installed but functionality requiring it is accessed."""
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
super().__init__(
|
|
17
|
+
"langchain-openai package is not installed. Install it with 'poetry install --with langchain'."
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
if importlib.util.find_spec("langchain_openai") is not None:
|
|
22
|
+
from langchain_openai import ChatOpenAI
|
|
23
|
+
else:
|
|
24
|
+
raise LangchainNotInstalledError()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_langchain_client(
|
|
28
|
+
*,
|
|
29
|
+
unique_settings: UniqueSettings | None = None,
|
|
30
|
+
model: str = "AZURE_GPT_4o_2024_0806",
|
|
31
|
+
additional_headers: dict[str, str] | None = None,
|
|
32
|
+
) -> ChatOpenAI:
|
|
33
|
+
"""Get a Langchain ChatOpenAI client instance.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
unique_settings: UniqueSettings instance
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
ChatOpenAI client instance
|
|
40
|
+
|
|
41
|
+
Raises:
|
|
42
|
+
LangchainNotInstalledError: If langchain-openai package is not installed
|
|
43
|
+
"""
|
|
44
|
+
if unique_settings is None:
|
|
45
|
+
unique_settings = UniqueSettings.from_env_auto()
|
|
46
|
+
|
|
47
|
+
default_headers = get_default_headers(unique_settings.app, unique_settings.auth)
|
|
48
|
+
if additional_headers is not None:
|
|
49
|
+
default_headers.update(additional_headers)
|
|
50
|
+
|
|
51
|
+
return ChatOpenAI(
|
|
52
|
+
base_url=unique_settings.api.openai_proxy_url(),
|
|
53
|
+
default_headers=default_headers,
|
|
54
|
+
model=model,
|
|
55
|
+
api_key=unique_settings.app.key,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@deprecated("Use get_langchain_client instead")
|
|
60
|
+
def get_client(
|
|
61
|
+
unique_settings: UniqueSettings | None = None, model: str = "AZURE_GPT_4o_2024_0806"
|
|
62
|
+
) -> ChatOpenAI:
|
|
63
|
+
"""Get a Langchain ChatOpenAI client instance.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
unique_settings: UniqueSettings instance
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
ChatOpenAI client instance
|
|
70
|
+
"""
|
|
71
|
+
return get_client(unique_settings, model)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
|
|
2
|
+
|
|
3
|
+
from unique_toolkit.chat import ChatMessage as UniqueMessage
|
|
4
|
+
from unique_toolkit.chat import ChatMessageRole as UniqueRole
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def unique_history_to_langchain_history(
|
|
8
|
+
unique_history: list[UniqueMessage],
|
|
9
|
+
) -> list[BaseMessage]:
|
|
10
|
+
history = []
|
|
11
|
+
for m in unique_history:
|
|
12
|
+
if m.role == UniqueRole.ASSISTANT:
|
|
13
|
+
history.append(AIMessage(content=m.content or ""))
|
|
14
|
+
elif m.role == UniqueRole.USER:
|
|
15
|
+
history.append(HumanMessage(content=m.content or ""))
|
|
16
|
+
else:
|
|
17
|
+
raise Exception("Unknown message role.")
|
|
18
|
+
|
|
19
|
+
return history
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import importlib.util
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from unique_toolkit.app.unique_settings import UniqueSettings
|
|
5
|
+
from unique_toolkit.framework_utilities.utils import get_default_headers
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger("toolkit.framework_utilities.openai")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class OpenAINotInstalledError(ImportError):
|
|
11
|
+
"""Raised when OpenAI package is not installed but functionality requiring it is accessed."""
|
|
12
|
+
|
|
13
|
+
def __init__(self):
|
|
14
|
+
super().__init__(
|
|
15
|
+
"OpenAI package is not installed. Install it with 'poetry install --with openai'."
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
if importlib.util.find_spec("openai") is not None:
|
|
20
|
+
from openai import AsyncOpenAI, OpenAI
|
|
21
|
+
else:
|
|
22
|
+
raise OpenAINotInstalledError()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_openai_client(
|
|
26
|
+
*,
|
|
27
|
+
unique_settings: UniqueSettings | None = None,
|
|
28
|
+
additional_headers: dict[str, str] | None = None,
|
|
29
|
+
) -> OpenAI:
|
|
30
|
+
"""Get an OpenAI client instance.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
env_file: Optional path to environment file
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
OpenAI client instance
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
OpenAINotInstalledError: If OpenAI package is not installed
|
|
40
|
+
"""
|
|
41
|
+
if unique_settings is None:
|
|
42
|
+
unique_settings = UniqueSettings.from_env_auto()
|
|
43
|
+
|
|
44
|
+
default_headers = get_default_headers(unique_settings.app, unique_settings.auth)
|
|
45
|
+
if additional_headers is not None:
|
|
46
|
+
default_headers.update(additional_headers)
|
|
47
|
+
|
|
48
|
+
return OpenAI(
|
|
49
|
+
api_key="dummy_key",
|
|
50
|
+
base_url=unique_settings.api.openai_proxy_url(),
|
|
51
|
+
default_headers=default_headers,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_async_openai_client(
|
|
56
|
+
*,
|
|
57
|
+
unique_settings: UniqueSettings | None = None,
|
|
58
|
+
additional_headers: dict[str, str] | None = None,
|
|
59
|
+
) -> AsyncOpenAI:
|
|
60
|
+
"""Get an async OpenAI client instance.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
unique_settings: Optional UniqueSettings instance
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
AsyncOpenAI client instance
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
OpenAINotInstalledError: If OpenAI package is not installed
|
|
70
|
+
"""
|
|
71
|
+
if unique_settings is None:
|
|
72
|
+
unique_settings = UniqueSettings.from_env_auto()
|
|
73
|
+
|
|
74
|
+
default_headers = get_default_headers(unique_settings.app, unique_settings.auth)
|
|
75
|
+
|
|
76
|
+
if additional_headers is not None:
|
|
77
|
+
default_headers.update(additional_headers)
|
|
78
|
+
|
|
79
|
+
return AsyncOpenAI(
|
|
80
|
+
api_key="dummy_key",
|
|
81
|
+
base_url=unique_settings.api.openai_proxy_url(),
|
|
82
|
+
default_headers=default_headers,
|
|
83
|
+
)
|