unique_orchestrator 0.0.2__tar.gz → 0.0.4__tar.gz
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_orchestrator might be problematic. Click here for more details.
- {unique_orchestrator-0.0.2 → unique_orchestrator-0.0.4}/CHANGELOG.md +6 -0
- {unique_orchestrator-0.0.2 → unique_orchestrator-0.0.4}/PKG-INFO +16 -11
- {unique_orchestrator-0.0.2 → unique_orchestrator-0.0.4}/pyproject.toml +10 -15
- unique_orchestrator-0.0.4/unique_orchestrator/config.py +254 -0
- {unique_orchestrator-0.0.2 → unique_orchestrator-0.0.4}/unique_orchestrator/unique_ai.py +11 -11
- {unique_orchestrator-0.0.2 → unique_orchestrator-0.0.4}/unique_orchestrator/unique_ai_builder.py +16 -16
- unique_orchestrator-0.0.2/unique_orchestrator/config.py +0 -505
- unique_orchestrator-0.0.2/unique_orchestrator/tests/test_config.py +0 -115
- {unique_orchestrator-0.0.2 → unique_orchestrator-0.0.4}/LICENSE +0 -0
- {unique_orchestrator-0.0.2 → unique_orchestrator-0.0.4}/README.md +0 -0
- {unique_orchestrator-0.0.2 → unique_orchestrator-0.0.4}/unique_orchestrator/prompts/generic_reference_prompt.jinja2 +0 -0
- {unique_orchestrator-0.0.2 → unique_orchestrator-0.0.4}/unique_orchestrator/prompts/system_prompt.jinja2 +0 -0
- {unique_orchestrator-0.0.2 → unique_orchestrator-0.0.4}/unique_orchestrator/prompts/user_message_prompt.jinja2 +0 -0
- {unique_orchestrator-0.0.2 → unique_orchestrator-0.0.4}/unique_orchestrator/tests/test_unique_ai_reference_order.py +0 -0
|
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.0.4] - 2025-09-17
|
|
9
|
+
- Updated to latest toolkit
|
|
10
|
+
|
|
11
|
+
## [0.0.3] - 2025-09-16
|
|
12
|
+
- Cleaned configuration
|
|
13
|
+
|
|
8
14
|
## [0.0.2] - 2025-09-15
|
|
9
15
|
- Resolve dependency bug
|
|
10
16
|
|
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: unique_orchestrator
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary:
|
|
5
5
|
License: Proprietary
|
|
6
|
-
Author:
|
|
7
|
-
Author-email:
|
|
8
|
-
Requires-Python: >=3.
|
|
6
|
+
Author: Andreas Hauri
|
|
7
|
+
Author-email: andreas.hauri@unique.ai
|
|
8
|
+
Requires-Python: >=3.12,<4.0
|
|
9
9
|
Classifier: License :: Other/Proprietary License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
12
|
Requires-Dist: pydantic (>=2.8.2,<3.0.0)
|
|
14
13
|
Requires-Dist: pydantic-settings (>=2.10.1,<3.0.0)
|
|
15
14
|
Requires-Dist: pytest (>=8.4.1,<9.0.0)
|
|
16
15
|
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
17
16
|
Requires-Dist: typing-extensions (>=4.9.0,<5.0.0)
|
|
18
|
-
Requires-Dist: unique-deep-research (>=0.0.
|
|
19
|
-
Requires-Dist: unique-follow-up-questions (>=0.0.
|
|
20
|
-
Requires-Dist: unique-internal-search (>=0.0.
|
|
17
|
+
Requires-Dist: unique-deep-research (>=0.0.11,<0.0.12)
|
|
18
|
+
Requires-Dist: unique-follow-up-questions (>=0.0.5,<0.0.6)
|
|
19
|
+
Requires-Dist: unique-internal-search (>=0.0.7,<0.0.8)
|
|
21
20
|
Requires-Dist: unique-sdk (>=0.10.0,<0.11.0)
|
|
22
|
-
Requires-Dist: unique-stock-ticker (>=0.0.
|
|
23
|
-
Requires-Dist: unique-toolkit (>=0.
|
|
24
|
-
Requires-Dist: unique-web-search (>=0.1.
|
|
21
|
+
Requires-Dist: unique-stock-ticker (>=0.0.6,<0.0.7)
|
|
22
|
+
Requires-Dist: unique-toolkit (>=0.9.0,<0.10.0)
|
|
23
|
+
Requires-Dist: unique-web-search (>=0.1.3,<0.2.0)
|
|
25
24
|
Description-Content-Type: text/markdown
|
|
26
25
|
|
|
27
26
|
# Internal Search Tool
|
|
@@ -34,6 +33,12 @@ All notable changes to this project will be documented in this file.
|
|
|
34
33
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
35
34
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
36
35
|
|
|
36
|
+
## [0.0.4] - 2025-09-17
|
|
37
|
+
- Updated to latest toolkit
|
|
38
|
+
|
|
39
|
+
## [0.0.3] - 2025-09-16
|
|
40
|
+
- Cleaned configuration
|
|
41
|
+
|
|
37
42
|
## [0.0.2] - 2025-09-15
|
|
38
43
|
- Resolve dependency bug
|
|
39
44
|
|
|
@@ -1,35 +1,30 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "unique_orchestrator"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.4"
|
|
4
4
|
description = ""
|
|
5
|
-
authors = [
|
|
6
|
-
"Martin Fadler <martin.fadler@unique.ch>",
|
|
7
|
-
"Sadique Sheik <sadique@unique.ch>",
|
|
8
|
-
"Fabian Schläpfer <fabian@unique.ch>",
|
|
9
|
-
"Pascal Hauri <pascal@unique.ch>",
|
|
10
|
-
]
|
|
5
|
+
authors = ["Andreas Hauri <andreas.hauri@unique.ai>"]
|
|
11
6
|
readme = ["README.md", "CHANGELOG.md"]
|
|
12
7
|
license = "Proprietary"
|
|
13
8
|
|
|
14
9
|
[tool.poetry.dependencies]
|
|
15
|
-
python = "^3.
|
|
10
|
+
python = "^3.12"
|
|
16
11
|
typing-extensions = "^4.9.0"
|
|
17
12
|
pydantic = "^2.8.2"
|
|
18
13
|
pydantic-settings = "^2.10.1"
|
|
19
14
|
python-dotenv = "^1.0.1"
|
|
20
15
|
pytest = "^8.4.1"
|
|
21
16
|
unique-sdk = "^0.10.0"
|
|
22
|
-
unique-toolkit = "^0.
|
|
23
|
-
unique-stock-ticker = "^0.0.
|
|
24
|
-
unique-follow-up-questions = "^0.0.
|
|
25
|
-
unique-web-search = "^0.1.
|
|
26
|
-
unique-deep-research = "^0.0.
|
|
27
|
-
unique-internal-search = "^0.0.
|
|
17
|
+
unique-toolkit = "^0.9.0"
|
|
18
|
+
unique-stock-ticker = "^0.0.6"
|
|
19
|
+
unique-follow-up-questions = "^0.0.5"
|
|
20
|
+
unique-web-search = "^0.1.3"
|
|
21
|
+
unique-deep-research = "^0.0.11"
|
|
22
|
+
unique-internal-search = "^0.0.7"
|
|
28
23
|
|
|
29
24
|
|
|
30
25
|
[tool.poetry.group.dev.dependencies]
|
|
31
26
|
ruff = "^0.12.10"
|
|
32
|
-
python = "^3.
|
|
27
|
+
python = "^3.12"
|
|
33
28
|
typing-extensions = "^4.9.0"
|
|
34
29
|
pydantic = "^2.8.2"
|
|
35
30
|
pydantic-settings = "^2.10.1"
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Annotated, Any, Generic, Literal, TypeVar
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field, ValidationInfo, field_validator
|
|
6
|
+
from unique_deep_research.config import DeepResearchToolConfig
|
|
7
|
+
from unique_deep_research.service import DeepResearchTool
|
|
8
|
+
from unique_follow_up_questions.config import FollowUpQuestionsConfig
|
|
9
|
+
from unique_internal_search.config import InternalSearchConfig
|
|
10
|
+
from unique_internal_search.service import InternalSearchTool
|
|
11
|
+
from unique_stock_ticker.config import StockTickerConfig
|
|
12
|
+
from unique_toolkit._common.default_language_model import DEFAULT_GPT_4o
|
|
13
|
+
from unique_toolkit._common.validators import (
|
|
14
|
+
LMI,
|
|
15
|
+
ClipInt,
|
|
16
|
+
get_LMI_default_field,
|
|
17
|
+
)
|
|
18
|
+
from unique_toolkit.agentic.evaluation.hallucination.constants import (
|
|
19
|
+
HallucinationConfig,
|
|
20
|
+
)
|
|
21
|
+
from unique_toolkit.agentic.evaluation.schemas import EvaluationMetricName
|
|
22
|
+
from unique_toolkit.agentic.history_manager.history_manager import (
|
|
23
|
+
UploadedContentConfig,
|
|
24
|
+
)
|
|
25
|
+
from unique_toolkit.agentic.tools.config import get_configuration_dict
|
|
26
|
+
from unique_toolkit.agentic.tools.tool import ToolBuildConfig
|
|
27
|
+
from unique_web_search.config import WebSearchConfig
|
|
28
|
+
from unique_web_search.service import WebSearchTool
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SpaceType(StrEnum):
|
|
32
|
+
UNIQUE_CUSTOM = "unique_custom"
|
|
33
|
+
UNIQUE_AI = "unique_ai"
|
|
34
|
+
UNIQUE_TRANSLATION = "unique_translation"
|
|
35
|
+
UNIQUE_MAGIC_TABLE = ""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
T = TypeVar("T", bound=SpaceType)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class SpaceConfigBase(BaseModel, Generic[T]):
|
|
42
|
+
"""Base class for space configuration."""
|
|
43
|
+
|
|
44
|
+
model_config = get_configuration_dict(frozen=True)
|
|
45
|
+
type: T = Field(description="The type of the space.")
|
|
46
|
+
|
|
47
|
+
project_name: str = Field(
|
|
48
|
+
default="Unique AI",
|
|
49
|
+
description="The project name as optained from spaces 2.0",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
language_model: LMI = get_LMI_default_field(DEFAULT_GPT_4o)
|
|
53
|
+
|
|
54
|
+
custom_instructions: str = Field(
|
|
55
|
+
default="",
|
|
56
|
+
description="A custom instruction provided by the system admin.",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
tools: list[ToolBuildConfig] = Field(
|
|
60
|
+
default=[
|
|
61
|
+
ToolBuildConfig(
|
|
62
|
+
name=InternalSearchTool.name,
|
|
63
|
+
configuration=InternalSearchConfig(
|
|
64
|
+
exclude_uploaded_files=True,
|
|
65
|
+
),
|
|
66
|
+
),
|
|
67
|
+
ToolBuildConfig(
|
|
68
|
+
name=WebSearchTool.name,
|
|
69
|
+
configuration=WebSearchConfig(),
|
|
70
|
+
),
|
|
71
|
+
ToolBuildConfig(
|
|
72
|
+
name=DeepResearchTool.name,
|
|
73
|
+
configuration=DeepResearchToolConfig(),
|
|
74
|
+
),
|
|
75
|
+
],
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
@field_validator("tools", mode="after")
|
|
79
|
+
@classmethod
|
|
80
|
+
def set_input_context_size(
|
|
81
|
+
cls, tools: list[ToolBuildConfig], info: ValidationInfo
|
|
82
|
+
) -> list[ToolBuildConfig]:
|
|
83
|
+
for tool in tools:
|
|
84
|
+
if tool.name == InternalSearchTool.name:
|
|
85
|
+
tool.configuration.language_model_max_input_tokens = ( # type: ignore
|
|
86
|
+
info.data["language_model"].token_limits.token_limit_input
|
|
87
|
+
)
|
|
88
|
+
elif tool.name == WebSearchTool.name:
|
|
89
|
+
tool.configuration.language_model_max_input_tokens = ( # type: ignore
|
|
90
|
+
info.data["language_model"].token_limits.token_limit_input
|
|
91
|
+
)
|
|
92
|
+
return tools
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class UniqueAISpaceConfig(SpaceConfigBase):
|
|
96
|
+
"""Contains configuration for the entities that a space provides."""
|
|
97
|
+
|
|
98
|
+
type: Literal[SpaceType.UNIQUE_AI] = SpaceType.UNIQUE_AI
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
UniqueAISpaceConfig.model_rebuild()
|
|
102
|
+
|
|
103
|
+
LIMIT_MAX_TOOL_CALLS_PER_ITERATION = 50
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class LoopConfiguration(BaseModel):
|
|
107
|
+
model_config = get_configuration_dict()
|
|
108
|
+
|
|
109
|
+
max_tool_calls_per_iteration: Annotated[
|
|
110
|
+
int,
|
|
111
|
+
*ClipInt(min_value=1, max_value=LIMIT_MAX_TOOL_CALLS_PER_ITERATION),
|
|
112
|
+
] = 10
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class EvaluationConfig(BaseModel):
|
|
116
|
+
model_config = get_configuration_dict()
|
|
117
|
+
max_review_steps: int = 3
|
|
118
|
+
hallucination_config: HallucinationConfig = HallucinationConfig()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# ------------------------------------------------------------
|
|
122
|
+
# Space 2.0 Config
|
|
123
|
+
# ------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class UniqueAIPromptConfig(BaseModel):
|
|
127
|
+
model_config = get_configuration_dict(frozen=True)
|
|
128
|
+
|
|
129
|
+
system_prompt_template: str = Field(
|
|
130
|
+
default_factory=lambda: (
|
|
131
|
+
Path(__file__).parent / "prompts" / "system_prompt.jinja2"
|
|
132
|
+
).read_text(),
|
|
133
|
+
description="The system prompt template as a Jinja2 template string.",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
user_message_prompt_template: str = Field(
|
|
137
|
+
default_factory=lambda: (
|
|
138
|
+
Path(__file__).parent / "prompts" / "user_message_prompt.jinja2"
|
|
139
|
+
).read_text(),
|
|
140
|
+
description="The user message prompt template as a Jinja2 template string.",
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
DeactivatedNone = Annotated[
|
|
145
|
+
None,
|
|
146
|
+
Field(title="Deactivated", description="None"),
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class UniqueAIServices(BaseModel):
|
|
151
|
+
"""Determine the services the agent is using
|
|
152
|
+
|
|
153
|
+
All services are optional and can be disabled by setting them to None.
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
model_config = get_configuration_dict(frozen=True)
|
|
157
|
+
|
|
158
|
+
follow_up_questions_config: (
|
|
159
|
+
Annotated[
|
|
160
|
+
FollowUpQuestionsConfig,
|
|
161
|
+
Field(
|
|
162
|
+
title="Active",
|
|
163
|
+
),
|
|
164
|
+
]
|
|
165
|
+
| DeactivatedNone
|
|
166
|
+
) = FollowUpQuestionsConfig()
|
|
167
|
+
|
|
168
|
+
stock_ticker_config: (
|
|
169
|
+
Annotated[StockTickerConfig, Field(title="Active")] | DeactivatedNone
|
|
170
|
+
) = StockTickerConfig()
|
|
171
|
+
|
|
172
|
+
evaluation_config: (
|
|
173
|
+
Annotated[
|
|
174
|
+
EvaluationConfig,
|
|
175
|
+
Field(title="Active"),
|
|
176
|
+
]
|
|
177
|
+
| DeactivatedNone
|
|
178
|
+
) = EvaluationConfig(
|
|
179
|
+
hallucination_config=HallucinationConfig(),
|
|
180
|
+
max_review_steps=0,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
uploaded_content_config: UploadedContentConfig = UploadedContentConfig()
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class InputTokenDistributionConfig(BaseModel):
|
|
187
|
+
model_config = get_configuration_dict(frozen=True)
|
|
188
|
+
|
|
189
|
+
percent_for_history: float = Field(
|
|
190
|
+
default=0.2,
|
|
191
|
+
ge=0.0,
|
|
192
|
+
lt=1.0,
|
|
193
|
+
description="The fraction of the max input tokens that will be reserved for the history.",
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
def max_history_tokens(self, max_input_token: int) -> int:
|
|
197
|
+
return int(self.percent_for_history * max_input_token)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class ExperimentalConfig(BaseModel):
|
|
201
|
+
"""Experimental features this part of the configuration might evolve in the future continuously"""
|
|
202
|
+
|
|
203
|
+
model_config = get_configuration_dict(frozen=True)
|
|
204
|
+
|
|
205
|
+
thinking_steps_display: bool = False
|
|
206
|
+
|
|
207
|
+
# TODO: @gustavhartz, the Hallucination check should be triggered if enabled and the answer contains references.
|
|
208
|
+
force_checks_on_stream_response_references: list[EvaluationMetricName] = Field(
|
|
209
|
+
default=[EvaluationMetricName.HALLUCINATION],
|
|
210
|
+
description="A list of checks to force on references. This is used to add hallucination check to references without new tool calls.",
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# TODO: The temperature should be used via the additional_llm_options
|
|
214
|
+
# then the additional_llm_options migth should eventually be closer to the LangaugeModelInfo
|
|
215
|
+
temperature: float = Field(
|
|
216
|
+
default=0.0,
|
|
217
|
+
ge=0.0,
|
|
218
|
+
le=10.0,
|
|
219
|
+
description="The temperature to use for the LLM.",
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
additional_llm_options: dict[str, Any] = Field(
|
|
223
|
+
default={},
|
|
224
|
+
description="Additional options to pass to the LLM.",
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
loop_configuration: LoopConfiguration = LoopConfiguration(
|
|
228
|
+
max_tool_calls_per_iteration=5
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class UniqueAIAgentConfig(BaseModel):
|
|
233
|
+
model_config = get_configuration_dict(frozen=True)
|
|
234
|
+
|
|
235
|
+
max_loop_iterations: int = 8
|
|
236
|
+
|
|
237
|
+
input_token_distribution: InputTokenDistributionConfig = Field(
|
|
238
|
+
default=InputTokenDistributionConfig(),
|
|
239
|
+
description="The distribution of the input tokens.",
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
prompt_config: UniqueAIPromptConfig = UniqueAIPromptConfig()
|
|
243
|
+
|
|
244
|
+
services: UniqueAIServices = UniqueAIServices()
|
|
245
|
+
|
|
246
|
+
experimental: ExperimentalConfig = ExperimentalConfig()
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class UniqueAIConfig(BaseModel):
|
|
250
|
+
model_config = get_configuration_dict(frozen=True)
|
|
251
|
+
|
|
252
|
+
space: UniqueAISpaceConfig = UniqueAISpaceConfig()
|
|
253
|
+
|
|
254
|
+
agent: UniqueAIAgentConfig = UniqueAIAgentConfig()
|
|
@@ -2,25 +2,25 @@ from datetime import datetime
|
|
|
2
2
|
from logging import Logger
|
|
3
3
|
|
|
4
4
|
import jinja2
|
|
5
|
+
from unique_toolkit.agentic.debug_info_manager.debug_info_manager import (
|
|
6
|
+
DebugInfoManager,
|
|
7
|
+
)
|
|
8
|
+
from unique_toolkit.agentic.evaluation.evaluation_manager import EvaluationManager
|
|
9
|
+
from unique_toolkit.agentic.history_manager.history_manager import HistoryManager
|
|
10
|
+
from unique_toolkit.agentic.postprocessor.postprocessor_manager import (
|
|
11
|
+
PostprocessorManager,
|
|
12
|
+
)
|
|
13
|
+
from unique_toolkit.agentic.reference_manager.reference_manager import ReferenceManager
|
|
14
|
+
from unique_toolkit.agentic.thinking_manager.thinking_manager import ThinkingManager
|
|
15
|
+
from unique_toolkit.agentic.tools.tool_manager import ToolManager
|
|
5
16
|
from unique_toolkit.app.schemas import ChatEvent, McpServer
|
|
6
17
|
from unique_toolkit.chat.service import ChatService
|
|
7
18
|
from unique_toolkit.content.service import ContentService
|
|
8
|
-
from unique_toolkit.debug_info_manager.debug_info_manager import (
|
|
9
|
-
DebugInfoManager,
|
|
10
|
-
)
|
|
11
|
-
from unique_toolkit.evals.evaluation_manager import EvaluationManager
|
|
12
|
-
from unique_toolkit.history_manager.history_manager import HistoryManager
|
|
13
19
|
from unique_toolkit.language_model.schemas import (
|
|
14
20
|
LanguageModelAssistantMessage,
|
|
15
21
|
LanguageModelMessages,
|
|
16
22
|
LanguageModelStreamResponse,
|
|
17
23
|
)
|
|
18
|
-
from unique_toolkit.postprocessor.postprocessor_manager import (
|
|
19
|
-
PostprocessorManager,
|
|
20
|
-
)
|
|
21
|
-
from unique_toolkit.reference_manager.reference_manager import ReferenceManager
|
|
22
|
-
from unique_toolkit.thinking_manager.thinking_manager import ThinkingManager
|
|
23
|
-
from unique_toolkit.tools.tool_manager import ToolManager
|
|
24
24
|
|
|
25
25
|
from unique_orchestrator.config import UniqueAIConfig
|
|
26
26
|
|
{unique_orchestrator-0.0.2 → unique_orchestrator-0.0.4}/unique_orchestrator/unique_ai_builder.py
RENAMED
|
@@ -13,36 +13,36 @@ from unique_stock_ticker.stock_ticker_postprocessor import (
|
|
|
13
13
|
StockTickerPostprocessor,
|
|
14
14
|
)
|
|
15
15
|
from unique_toolkit import LanguageModelService
|
|
16
|
-
from unique_toolkit.
|
|
17
|
-
from unique_toolkit.chat.service import ChatService
|
|
18
|
-
from unique_toolkit.content.service import ContentService
|
|
19
|
-
from unique_toolkit.debug_info_manager.debug_info_manager import (
|
|
16
|
+
from unique_toolkit.agentic.debug_info_manager.debug_info_manager import (
|
|
20
17
|
DebugInfoManager,
|
|
21
18
|
)
|
|
22
|
-
from unique_toolkit.
|
|
23
|
-
from unique_toolkit.
|
|
19
|
+
from unique_toolkit.agentic.evaluation.evaluation_manager import EvaluationManager
|
|
20
|
+
from unique_toolkit.agentic.evaluation.hallucination.hallucination_evaluation import (
|
|
24
21
|
HallucinationEvaluation,
|
|
25
22
|
)
|
|
26
|
-
from unique_toolkit.history_manager import (
|
|
23
|
+
from unique_toolkit.agentic.history_manager import (
|
|
27
24
|
history_manager as history_manager_module,
|
|
28
25
|
)
|
|
29
|
-
from unique_toolkit.history_manager.history_manager import (
|
|
26
|
+
from unique_toolkit.agentic.history_manager.history_manager import (
|
|
30
27
|
HistoryManager,
|
|
31
28
|
HistoryManagerConfig,
|
|
32
29
|
)
|
|
33
|
-
from unique_toolkit.postprocessor.postprocessor_manager import (
|
|
30
|
+
from unique_toolkit.agentic.postprocessor.postprocessor_manager import (
|
|
34
31
|
PostprocessorManager,
|
|
35
32
|
)
|
|
36
|
-
from unique_toolkit.reference_manager.reference_manager import ReferenceManager
|
|
37
|
-
from unique_toolkit.thinking_manager.thinking_manager import (
|
|
33
|
+
from unique_toolkit.agentic.reference_manager.reference_manager import ReferenceManager
|
|
34
|
+
from unique_toolkit.agentic.thinking_manager.thinking_manager import (
|
|
38
35
|
ThinkingManager,
|
|
39
36
|
ThinkingManagerConfig,
|
|
40
37
|
)
|
|
41
|
-
from unique_toolkit.tools.a2a.manager import A2AManager
|
|
42
|
-
from unique_toolkit.tools.config import ToolBuildConfig
|
|
43
|
-
from unique_toolkit.tools.mcp.manager import MCPManager
|
|
44
|
-
from unique_toolkit.tools.tool_manager import ToolManager, ToolManagerConfig
|
|
45
|
-
from unique_toolkit.tools.tool_progress_reporter import ToolProgressReporter
|
|
38
|
+
from unique_toolkit.agentic.tools.a2a.manager import A2AManager
|
|
39
|
+
from unique_toolkit.agentic.tools.config import ToolBuildConfig
|
|
40
|
+
from unique_toolkit.agentic.tools.mcp.manager import MCPManager
|
|
41
|
+
from unique_toolkit.agentic.tools.tool_manager import ToolManager, ToolManagerConfig
|
|
42
|
+
from unique_toolkit.agentic.tools.tool_progress_reporter import ToolProgressReporter
|
|
43
|
+
from unique_toolkit.app.schemas import ChatEvent
|
|
44
|
+
from unique_toolkit.chat.service import ChatService
|
|
45
|
+
from unique_toolkit.content.service import ContentService
|
|
46
46
|
|
|
47
47
|
from unique_orchestrator.config import UniqueAIConfig
|
|
48
48
|
from unique_orchestrator.unique_ai import UniqueAI
|
|
@@ -1,505 +0,0 @@
|
|
|
1
|
-
from enum import StrEnum
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from typing import Annotated, Any, Generic, Literal, TypeVar
|
|
4
|
-
|
|
5
|
-
from pydantic import BaseModel, Field, ValidationInfo, field_validator
|
|
6
|
-
from unique_deep_research.config import DeepResearchToolConfig
|
|
7
|
-
from unique_deep_research.service import DeepResearchTool
|
|
8
|
-
from unique_follow_up_questions.config import FollowUpQuestionsConfig
|
|
9
|
-
from unique_internal_search.config import InternalSearchConfig
|
|
10
|
-
from unique_internal_search.service import InternalSearchTool
|
|
11
|
-
from unique_stock_ticker.config import StockTickerConfig
|
|
12
|
-
from unique_toolkit._common.default_language_model import DEFAULT_GPT_4o
|
|
13
|
-
from unique_toolkit._common.validators import (
|
|
14
|
-
LMI,
|
|
15
|
-
ClipInt,
|
|
16
|
-
get_LMI_default_field,
|
|
17
|
-
)
|
|
18
|
-
from unique_toolkit.evals.hallucination.constants import HallucinationConfig
|
|
19
|
-
from unique_toolkit.evals.schemas import EvaluationMetricName
|
|
20
|
-
from unique_toolkit.history_manager.history_manager import (
|
|
21
|
-
UploadedContentConfig,
|
|
22
|
-
)
|
|
23
|
-
from unique_toolkit.language_model import LanguageModelName
|
|
24
|
-
from unique_toolkit.language_model.infos import (
|
|
25
|
-
LanguageModelInfo,
|
|
26
|
-
)
|
|
27
|
-
from unique_toolkit.tools.config import get_configuration_dict
|
|
28
|
-
from unique_toolkit.tools.factory import ToolFactory
|
|
29
|
-
from unique_toolkit.tools.schemas import BaseToolConfig
|
|
30
|
-
from unique_toolkit.tools.tool import ToolBuildConfig
|
|
31
|
-
from unique_web_search.config import WebSearchConfig
|
|
32
|
-
from unique_web_search.service import WebSearchTool
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class SpaceType(StrEnum):
|
|
36
|
-
UNIQUE_CUSTOM = "unique_custom"
|
|
37
|
-
UNIQUE_AI = "unique_ai"
|
|
38
|
-
UNIQUE_TRANSLATION = "unique_translation"
|
|
39
|
-
UNIQUE_MAGIC_TABLE = ""
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
T = TypeVar("T", bound=SpaceType)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class SpaceConfigBase(BaseModel, Generic[T]):
|
|
46
|
-
"""Base class for space configuration."""
|
|
47
|
-
|
|
48
|
-
model_config = get_configuration_dict(frozen=True)
|
|
49
|
-
type: T = Field(description="The type of the space.")
|
|
50
|
-
|
|
51
|
-
project_name: str = Field(
|
|
52
|
-
default="Unique AI",
|
|
53
|
-
description="The project name as optained from spaces 2.0",
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
language_model: LMI = get_LMI_default_field(DEFAULT_GPT_4o)
|
|
57
|
-
|
|
58
|
-
custom_instructions: str = Field(
|
|
59
|
-
default="",
|
|
60
|
-
description="A custom instruction provided by the system admin.",
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
tools: list[ToolBuildConfig] = Field(
|
|
64
|
-
default=[
|
|
65
|
-
ToolBuildConfig(
|
|
66
|
-
name=InternalSearchTool.name,
|
|
67
|
-
configuration=InternalSearchConfig(
|
|
68
|
-
exclude_uploaded_files=True,
|
|
69
|
-
),
|
|
70
|
-
),
|
|
71
|
-
ToolBuildConfig(
|
|
72
|
-
name=WebSearchTool.name,
|
|
73
|
-
configuration=WebSearchConfig(),
|
|
74
|
-
),
|
|
75
|
-
ToolBuildConfig(
|
|
76
|
-
name=DeepResearchTool.name,
|
|
77
|
-
configuration=DeepResearchToolConfig(),
|
|
78
|
-
),
|
|
79
|
-
],
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
@field_validator("tools", mode="after")
|
|
83
|
-
@classmethod
|
|
84
|
-
def set_input_context_size(
|
|
85
|
-
cls, tools: list[ToolBuildConfig], info: ValidationInfo
|
|
86
|
-
) -> list[ToolBuildConfig]:
|
|
87
|
-
for tool in tools:
|
|
88
|
-
if tool.name == InternalSearchTool.name:
|
|
89
|
-
tool.configuration.language_model_max_input_tokens = ( # type: ignore
|
|
90
|
-
info.data["language_model"].token_limits.token_limit_input
|
|
91
|
-
)
|
|
92
|
-
elif tool.name == WebSearchTool.name:
|
|
93
|
-
tool.configuration.language_model_max_input_tokens = ( # type: ignore
|
|
94
|
-
info.data["language_model"].token_limits.token_limit_input
|
|
95
|
-
)
|
|
96
|
-
return tools
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
class UniqueAISpaceConfig(SpaceConfigBase):
|
|
100
|
-
"""Contains configuration for the entities that a space provides."""
|
|
101
|
-
|
|
102
|
-
type: Literal[SpaceType.UNIQUE_AI] = SpaceType.UNIQUE_AI
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
UniqueAISpaceConfig.model_rebuild()
|
|
106
|
-
|
|
107
|
-
LIMIT_LOOP_ITERATIONS = 50
|
|
108
|
-
LIMIT_MAX_TOOL_CALLS_PER_ITERATION = 50
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
class LoopConfiguration(BaseModel):
|
|
112
|
-
model_config = get_configuration_dict()
|
|
113
|
-
|
|
114
|
-
max_tool_calls_per_iteration: Annotated[
|
|
115
|
-
int,
|
|
116
|
-
*ClipInt(min_value=1, max_value=LIMIT_MAX_TOOL_CALLS_PER_ITERATION),
|
|
117
|
-
] = 10
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
class EvaluationConfig(BaseModel):
|
|
121
|
-
model_config = get_configuration_dict()
|
|
122
|
-
max_review_steps: int = 3
|
|
123
|
-
hallucination_config: HallucinationConfig = HallucinationConfig()
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
class LoopAgentTokenLimitsConfig(BaseModel):
|
|
127
|
-
model_config = get_configuration_dict()
|
|
128
|
-
|
|
129
|
-
language_model: LMI = LanguageModelInfo.from_name(
|
|
130
|
-
LanguageModelName.AZURE_GPT_4o_2024_1120
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
percent_of_max_tokens_for_history: float = Field(
|
|
134
|
-
default=0.2,
|
|
135
|
-
ge=0.0,
|
|
136
|
-
lt=1.0,
|
|
137
|
-
description="The fraction of the max input tokens that will be reserved for the history.",
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
@property
|
|
141
|
-
def max_history_tokens(self) -> int:
|
|
142
|
-
return int(
|
|
143
|
-
self.language_model.token_limits.token_limit_input
|
|
144
|
-
* self.percent_of_max_tokens_for_history,
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
class SearchAgentConfig(BaseModel):
|
|
149
|
-
"""Configure the search agent."""
|
|
150
|
-
|
|
151
|
-
model_config = get_configuration_dict(frozen=True)
|
|
152
|
-
|
|
153
|
-
language_model: LMI = LanguageModelInfo.from_name(DEFAULT_GPT_4o)
|
|
154
|
-
|
|
155
|
-
token_limits: LoopAgentTokenLimitsConfig = Field(
|
|
156
|
-
default=LoopAgentTokenLimitsConfig(percent_of_max_tokens_for_history=0.6)
|
|
157
|
-
)
|
|
158
|
-
temperature: float = 0.0
|
|
159
|
-
additional_llm_options: dict[str, Any] = Field(
|
|
160
|
-
default={},
|
|
161
|
-
description="Additional options to pass to the language model.",
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
# Space 2.0
|
|
165
|
-
project_name: str = Field(
|
|
166
|
-
default="Unique AI",
|
|
167
|
-
description="The project name as optained from spaces 2.0",
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
# Space 2.0
|
|
171
|
-
custom_instructions: str = Field(
|
|
172
|
-
default="",
|
|
173
|
-
description="A custom instruction provided by the system admin.",
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
thinking_steps_display: bool = False
|
|
177
|
-
|
|
178
|
-
##############################
|
|
179
|
-
### General Configurations
|
|
180
|
-
##############################
|
|
181
|
-
max_loop_iterations: Annotated[
|
|
182
|
-
int, *ClipInt(min_value=1, max_value=LIMIT_LOOP_ITERATIONS)
|
|
183
|
-
] = 8
|
|
184
|
-
|
|
185
|
-
loop_configuration: LoopConfiguration = LoopConfiguration()
|
|
186
|
-
|
|
187
|
-
tools: list[ToolBuildConfig] = Field(
|
|
188
|
-
default=[
|
|
189
|
-
ToolBuildConfig(
|
|
190
|
-
name=InternalSearchTool.name,
|
|
191
|
-
configuration=InternalSearchConfig(
|
|
192
|
-
exclude_uploaded_files=True,
|
|
193
|
-
),
|
|
194
|
-
),
|
|
195
|
-
ToolBuildConfig(
|
|
196
|
-
name=WebSearchTool.name,
|
|
197
|
-
configuration=WebSearchConfig(),
|
|
198
|
-
),
|
|
199
|
-
ToolBuildConfig(
|
|
200
|
-
name=DeepResearchTool.name,
|
|
201
|
-
configuration=DeepResearchToolConfig(),
|
|
202
|
-
),
|
|
203
|
-
],
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
system_prompt_template: str = Field(
|
|
207
|
-
default_factory=lambda: (
|
|
208
|
-
Path(__file__).parent / "prompts" / "system_prompt.jinja2"
|
|
209
|
-
).read_text(),
|
|
210
|
-
description="The system prompt template as a Jinja2 template string.",
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
user_message_prompt_template: str = Field(
|
|
214
|
-
default_factory=lambda: (
|
|
215
|
-
Path(__file__).parent / "prompts" / "user_message_prompt.jinja2"
|
|
216
|
-
).read_text(),
|
|
217
|
-
description="The user message prompt template as a Jinja2 template string.",
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
##############################
|
|
221
|
-
### Follow-up Questions
|
|
222
|
-
##############################
|
|
223
|
-
follow_up_questions_config: FollowUpQuestionsConfig = FollowUpQuestionsConfig()
|
|
224
|
-
|
|
225
|
-
##############################
|
|
226
|
-
### Evaluation
|
|
227
|
-
##############################
|
|
228
|
-
evaluation_config: EvaluationConfig = EvaluationConfig(
|
|
229
|
-
hallucination_config=HallucinationConfig(),
|
|
230
|
-
max_review_steps=0,
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
##############################
|
|
234
|
-
### Stock Ticker
|
|
235
|
-
##############################
|
|
236
|
-
stock_ticker_config: StockTickerConfig = StockTickerConfig()
|
|
237
|
-
|
|
238
|
-
# TODO: generalize this there should only be 1 point in the code where we do the tool check.
|
|
239
|
-
def get_tool_config(self, tool: str) -> BaseToolConfig:
|
|
240
|
-
"""Get the tool configuration by name."""
|
|
241
|
-
return ToolFactory.build_tool_config(tool)
|
|
242
|
-
|
|
243
|
-
# TODO: @gustavhartz, the Hallucination check should be triggered if enabled and the answer contains references.
|
|
244
|
-
force_checks_on_stream_response_references: list[EvaluationMetricName] = Field(
|
|
245
|
-
default=[EvaluationMetricName.HALLUCINATION],
|
|
246
|
-
description="A list of checks to force on references. This is used to add hallucination check to references without new tool calls.",
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
uploaded_content_config: UploadedContentConfig = Field(
|
|
250
|
-
default_factory=UploadedContentConfig,
|
|
251
|
-
description="The uploaded content config.",
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
# ------------------------------------------------------------
|
|
256
|
-
# Space 2.0 Config
|
|
257
|
-
# ------------------------------------------------------------
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
class UniqueAIPromptConfig(BaseModel):
|
|
261
|
-
model_config = get_configuration_dict(frozen=True)
|
|
262
|
-
|
|
263
|
-
system_prompt_template: str = Field(
|
|
264
|
-
default_factory=lambda: (
|
|
265
|
-
Path(__file__).parent / "prompts" / "system_prompt.jinja2"
|
|
266
|
-
).read_text(),
|
|
267
|
-
description="The system prompt template as a Jinja2 template string.",
|
|
268
|
-
)
|
|
269
|
-
|
|
270
|
-
user_message_prompt_template: str = Field(
|
|
271
|
-
default_factory=lambda: (
|
|
272
|
-
Path(__file__).parent / "prompts" / "user_message_prompt.jinja2"
|
|
273
|
-
).read_text(),
|
|
274
|
-
description="The user message prompt template as a Jinja2 template string.",
|
|
275
|
-
)
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
DeactivatedNone = Annotated[
|
|
279
|
-
None,
|
|
280
|
-
Field(title="Deactivated", description="None"),
|
|
281
|
-
]
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
class UniqueAIServices(BaseModel):
|
|
285
|
-
"""Determine the services the agent is using
|
|
286
|
-
|
|
287
|
-
All services are optional and can be disabled by setting them to None.
|
|
288
|
-
"""
|
|
289
|
-
|
|
290
|
-
model_config = get_configuration_dict(frozen=True)
|
|
291
|
-
|
|
292
|
-
follow_up_questions_config: (
|
|
293
|
-
Annotated[
|
|
294
|
-
FollowUpQuestionsConfig,
|
|
295
|
-
Field(
|
|
296
|
-
title="Active",
|
|
297
|
-
),
|
|
298
|
-
]
|
|
299
|
-
| DeactivatedNone
|
|
300
|
-
) = FollowUpQuestionsConfig()
|
|
301
|
-
|
|
302
|
-
stock_ticker_config: (
|
|
303
|
-
Annotated[StockTickerConfig, Field(title="Active")] | DeactivatedNone
|
|
304
|
-
) = StockTickerConfig()
|
|
305
|
-
|
|
306
|
-
evaluation_config: (
|
|
307
|
-
Annotated[
|
|
308
|
-
EvaluationConfig,
|
|
309
|
-
Field(title="Active"),
|
|
310
|
-
]
|
|
311
|
-
| DeactivatedNone
|
|
312
|
-
) = EvaluationConfig(
|
|
313
|
-
hallucination_config=HallucinationConfig(),
|
|
314
|
-
max_review_steps=0,
|
|
315
|
-
)
|
|
316
|
-
|
|
317
|
-
uploaded_content_config: UploadedContentConfig = UploadedContentConfig()
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
class InputTokenDistributionConfig(BaseModel):
|
|
321
|
-
model_config = get_configuration_dict(frozen=True)
|
|
322
|
-
|
|
323
|
-
percent_for_history: float = Field(
|
|
324
|
-
default=0.2,
|
|
325
|
-
ge=0.0,
|
|
326
|
-
lt=1.0,
|
|
327
|
-
description="The fraction of the max input tokens that will be reserved for the history.",
|
|
328
|
-
)
|
|
329
|
-
|
|
330
|
-
def max_history_tokens(self, max_input_token: int) -> int:
|
|
331
|
-
return int(self.percent_for_history * max_input_token)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
class ExperimentalConfig(BaseModel):
|
|
335
|
-
"""Experimental features this part of the configuration might evolve in the future continuously"""
|
|
336
|
-
|
|
337
|
-
model_config = get_configuration_dict(frozen=True)
|
|
338
|
-
|
|
339
|
-
thinking_steps_display: bool = False
|
|
340
|
-
|
|
341
|
-
# TODO: @gustavhartz, the Hallucination check should be triggered if enabled and the answer contains references.
|
|
342
|
-
force_checks_on_stream_response_references: list[EvaluationMetricName] = Field(
|
|
343
|
-
default=[EvaluationMetricName.HALLUCINATION],
|
|
344
|
-
description="A list of checks to force on references. This is used to add hallucination check to references without new tool calls.",
|
|
345
|
-
)
|
|
346
|
-
|
|
347
|
-
# TODO: The temperature should be used via the additional_llm_options
|
|
348
|
-
# then the additional_llm_options migth should eventually be closer to the LangaugeModelInfo
|
|
349
|
-
temperature: float = Field(
|
|
350
|
-
default=0.0,
|
|
351
|
-
ge=0.0,
|
|
352
|
-
le=10.0,
|
|
353
|
-
description="The temperature to use for the LLM.",
|
|
354
|
-
)
|
|
355
|
-
|
|
356
|
-
additional_llm_options: dict[str, Any] = Field(
|
|
357
|
-
default={},
|
|
358
|
-
description="Additional options to pass to the LLM.",
|
|
359
|
-
)
|
|
360
|
-
|
|
361
|
-
loop_configuration: LoopConfiguration = LoopConfiguration(
|
|
362
|
-
max_tool_calls_per_iteration=5
|
|
363
|
-
)
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
class UniqueAIAgentConfig(BaseModel):
|
|
367
|
-
model_config = get_configuration_dict(frozen=True)
|
|
368
|
-
|
|
369
|
-
max_loop_iterations: int = 8
|
|
370
|
-
|
|
371
|
-
input_token_distribution: InputTokenDistributionConfig = Field(
|
|
372
|
-
default=InputTokenDistributionConfig(),
|
|
373
|
-
description="The distribution of the input tokens.",
|
|
374
|
-
)
|
|
375
|
-
|
|
376
|
-
prompt_config: UniqueAIPromptConfig = UniqueAIPromptConfig()
|
|
377
|
-
|
|
378
|
-
services: UniqueAIServices = UniqueAIServices()
|
|
379
|
-
|
|
380
|
-
experimental: ExperimentalConfig = ExperimentalConfig()
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
class UniqueAIConfig(BaseModel):
|
|
384
|
-
model_config = get_configuration_dict(frozen=True)
|
|
385
|
-
|
|
386
|
-
space: UniqueAISpaceConfig = UniqueAISpaceConfig()
|
|
387
|
-
|
|
388
|
-
agent: UniqueAIAgentConfig = UniqueAIAgentConfig()
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
# ---
|
|
392
|
-
# Configuration adapter SearchAgentConfig -> UniqueAISpaceConfig
|
|
393
|
-
# --
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
def search_agent_config_to_unique_ai_space_config(
|
|
397
|
-
search_agent_config: SearchAgentConfig,
|
|
398
|
-
) -> UniqueAIConfig:
|
|
399
|
-
space = UniqueAISpaceConfig(
|
|
400
|
-
project_name=search_agent_config.project_name,
|
|
401
|
-
custom_instructions=search_agent_config.custom_instructions,
|
|
402
|
-
tools=search_agent_config.tools,
|
|
403
|
-
language_model=search_agent_config.language_model,
|
|
404
|
-
type=SpaceType.UNIQUE_AI,
|
|
405
|
-
)
|
|
406
|
-
|
|
407
|
-
prompt_config = UniqueAIPromptConfig(
|
|
408
|
-
system_prompt_template=search_agent_config.system_prompt_template,
|
|
409
|
-
user_message_prompt_template=search_agent_config.user_message_prompt_template,
|
|
410
|
-
)
|
|
411
|
-
|
|
412
|
-
services = UniqueAIServices(
|
|
413
|
-
follow_up_questions_config=search_agent_config.follow_up_questions_config,
|
|
414
|
-
evaluation_config=search_agent_config.evaluation_config,
|
|
415
|
-
stock_ticker_config=search_agent_config.stock_ticker_config,
|
|
416
|
-
uploaded_content_config=search_agent_config.uploaded_content_config,
|
|
417
|
-
)
|
|
418
|
-
|
|
419
|
-
experimental = ExperimentalConfig(
|
|
420
|
-
thinking_steps_display=search_agent_config.thinking_steps_display,
|
|
421
|
-
force_checks_on_stream_response_references=search_agent_config.force_checks_on_stream_response_references,
|
|
422
|
-
temperature=search_agent_config.temperature,
|
|
423
|
-
additional_llm_options=search_agent_config.additional_llm_options,
|
|
424
|
-
loop_configuration=search_agent_config.loop_configuration,
|
|
425
|
-
)
|
|
426
|
-
|
|
427
|
-
# Calculate remaining token percentages based on history percentage
|
|
428
|
-
|
|
429
|
-
history_percent = search_agent_config.token_limits.percent_of_max_tokens_for_history
|
|
430
|
-
|
|
431
|
-
agent = UniqueAIAgentConfig(
|
|
432
|
-
max_loop_iterations=search_agent_config.max_loop_iterations,
|
|
433
|
-
input_token_distribution=InputTokenDistributionConfig(
|
|
434
|
-
percent_for_history=history_percent,
|
|
435
|
-
),
|
|
436
|
-
prompt_config=prompt_config,
|
|
437
|
-
services=services,
|
|
438
|
-
experimental=experimental,
|
|
439
|
-
)
|
|
440
|
-
|
|
441
|
-
return UniqueAIConfig(
|
|
442
|
-
space=space,
|
|
443
|
-
agent=agent,
|
|
444
|
-
)
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
def needs_conversion_to_unique_ai_space_config(
|
|
448
|
-
configuration: dict[str, Any],
|
|
449
|
-
) -> bool:
|
|
450
|
-
"""Check if the configuration needs to be converted to the new UniqueAISpaceConfig."""
|
|
451
|
-
if (
|
|
452
|
-
"space_two_point_zero" in configuration
|
|
453
|
-
or "SpaceTwoPointZeroConfig" in configuration
|
|
454
|
-
or ("space" in configuration and "agent" in configuration)
|
|
455
|
-
):
|
|
456
|
-
return False
|
|
457
|
-
|
|
458
|
-
return True
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
if __name__ == "__main__":
|
|
462
|
-
import json
|
|
463
|
-
|
|
464
|
-
from unique_toolkit._common.utils.write_configuration import (
|
|
465
|
-
write_service_configuration,
|
|
466
|
-
)
|
|
467
|
-
|
|
468
|
-
write_service_configuration(
|
|
469
|
-
service_folderpath=Path(__file__).parent.parent,
|
|
470
|
-
write_folderpath=Path(__file__).parent,
|
|
471
|
-
config=UniqueAIConfig(),
|
|
472
|
-
sub_name="unique_ai_config",
|
|
473
|
-
)
|
|
474
|
-
|
|
475
|
-
# TODO: @cdkl Delete these models
|
|
476
|
-
# This model is only used to have the old and new models in the same json
|
|
477
|
-
# schema for the data migration in the node chat backend
|
|
478
|
-
|
|
479
|
-
# The types can be generated with quicktype.io with the following command:
|
|
480
|
-
# quicktype unique_ai_old_and_new_config.json \
|
|
481
|
-
# --src-lang schema --lang typescript \
|
|
482
|
-
# --just-types --prefer-types --explicit-unions \
|
|
483
|
-
# -o unique_ai_old_new_configuration.ts \
|
|
484
|
-
# --top-level UniqueAIOldAndNewConfig \
|
|
485
|
-
# --raw-type any
|
|
486
|
-
|
|
487
|
-
# You will need to replace the `any` type with `unknown` in the generated file.
|
|
488
|
-
# On the branch `feat/unique-ai-configuration-migration-node-chat-part`.
|
|
489
|
-
# I you further update the types you will need to adapt both branches
|
|
490
|
-
# - feat/unique-ai-configuration-migration-next-admin-part
|
|
491
|
-
# - feat/unique-ai-configuration-migration-node-chat-part
|
|
492
|
-
|
|
493
|
-
class UniqueAIOldAndNewConfig(BaseModel):
|
|
494
|
-
new: UniqueAIConfig = UniqueAIConfig()
|
|
495
|
-
old: SearchAgentConfig = SearchAgentConfig()
|
|
496
|
-
|
|
497
|
-
with open(
|
|
498
|
-
Path(__file__).parent / "unique_ai_old_and_new_config.json",
|
|
499
|
-
"w",
|
|
500
|
-
) as f:
|
|
501
|
-
json.dump(
|
|
502
|
-
UniqueAIOldAndNewConfig().model_json_schema(by_alias=True),
|
|
503
|
-
f,
|
|
504
|
-
indent=4,
|
|
505
|
-
)
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
from unique_orchestrator.config import (
|
|
2
|
-
SearchAgentConfig,
|
|
3
|
-
search_agent_config_to_unique_ai_space_config,
|
|
4
|
-
)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def test_ai_tools_conversion():
|
|
8
|
-
"""
|
|
9
|
-
AI-authored test: Validates the transfer of tool configurations.
|
|
10
|
-
|
|
11
|
-
This test ensures that:
|
|
12
|
-
1. All tools from the old config are present in the new config
|
|
13
|
-
2. Tool names are preserved exactly
|
|
14
|
-
3. Tool configurations are maintained without modification
|
|
15
|
-
|
|
16
|
-
Written by AI Assistant to verify tool configuration preservation.
|
|
17
|
-
"""
|
|
18
|
-
old_config = SearchAgentConfig()
|
|
19
|
-
new_config = search_agent_config_to_unique_ai_space_config(old_config)
|
|
20
|
-
|
|
21
|
-
assert len(new_config.space.tools) == len(old_config.tools)
|
|
22
|
-
for old_tool, new_tool in zip(old_config.tools, new_config.space.tools):
|
|
23
|
-
assert old_tool.name == new_tool.name
|
|
24
|
-
assert old_tool.configuration == new_tool.configuration
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def test_ai_services_conversion():
|
|
28
|
-
"""
|
|
29
|
-
AI-authored test: Verifies the conversion of service configurations.
|
|
30
|
-
|
|
31
|
-
This test checks that all service configurations are properly transferred:
|
|
32
|
-
1. Follow-up questions configuration
|
|
33
|
-
2. Evaluation configuration
|
|
34
|
-
3. Stock ticker configuration
|
|
35
|
-
4. Reference manager configuration
|
|
36
|
-
|
|
37
|
-
Written by AI Assistant to ensure service configuration integrity.
|
|
38
|
-
"""
|
|
39
|
-
old_config = SearchAgentConfig()
|
|
40
|
-
new_config = search_agent_config_to_unique_ai_space_config(old_config)
|
|
41
|
-
|
|
42
|
-
services = new_config.agent.services
|
|
43
|
-
assert services.follow_up_questions_config == old_config.follow_up_questions_config
|
|
44
|
-
assert services.evaluation_config == old_config.evaluation_config
|
|
45
|
-
assert services.stock_ticker_config == old_config.stock_ticker_config
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def test_ai_experimental_config_conversion():
|
|
49
|
-
"""
|
|
50
|
-
AI-authored test: Checks the conversion of experimental features.
|
|
51
|
-
|
|
52
|
-
This test verifies that:
|
|
53
|
-
1. Experimental features like thinking_steps_display are properly transferred
|
|
54
|
-
2. Boolean values are preserved accurately
|
|
55
|
-
|
|
56
|
-
Written by AI Assistant to ensure experimental feature preservation.
|
|
57
|
-
"""
|
|
58
|
-
old_config = SearchAgentConfig()
|
|
59
|
-
old_config.thinking_steps_display = True
|
|
60
|
-
new_config = search_agent_config_to_unique_ai_space_config(old_config)
|
|
61
|
-
|
|
62
|
-
assert (
|
|
63
|
-
new_config.agent.experimental.thinking_steps_display
|
|
64
|
-
== old_config.thinking_steps_display
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def test_ai_force_checks_conversion():
|
|
69
|
-
"""
|
|
70
|
-
AI-authored test: Validates the conversion of force checks configuration.
|
|
71
|
-
|
|
72
|
-
This test ensures that:
|
|
73
|
-
1. Force checks for stream response references are properly transferred
|
|
74
|
-
2. The configuration maintains its integrity during conversion
|
|
75
|
-
|
|
76
|
-
Written by AI Assistant to verify force checks preservation.
|
|
77
|
-
"""
|
|
78
|
-
old_config = SearchAgentConfig()
|
|
79
|
-
new_config = search_agent_config_to_unique_ai_space_config(old_config)
|
|
80
|
-
|
|
81
|
-
assert (
|
|
82
|
-
new_config.agent.experimental.force_checks_on_stream_response_references
|
|
83
|
-
== old_config.force_checks_on_stream_response_references
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def test_ai_custom_values_conversion():
|
|
88
|
-
"""
|
|
89
|
-
AI-authored test: Verifies the conversion of custom configuration values.
|
|
90
|
-
|
|
91
|
-
This test validates that custom values are properly transferred:
|
|
92
|
-
1. Project name
|
|
93
|
-
2. Custom instructions
|
|
94
|
-
3. Temperature settings
|
|
95
|
-
4. Loop iteration limits
|
|
96
|
-
5. Additional LLM options
|
|
97
|
-
|
|
98
|
-
Written by AI Assistant to ensure custom configuration preservation.
|
|
99
|
-
"""
|
|
100
|
-
old_config = SearchAgentConfig(
|
|
101
|
-
project_name="Custom Project",
|
|
102
|
-
custom_instructions="Custom Instructions",
|
|
103
|
-
temperature=0.8,
|
|
104
|
-
max_loop_iterations=5,
|
|
105
|
-
additional_llm_options={"some_option": "value"},
|
|
106
|
-
)
|
|
107
|
-
new_config = search_agent_config_to_unique_ai_space_config(old_config)
|
|
108
|
-
|
|
109
|
-
assert new_config.space.project_name == "Custom Project"
|
|
110
|
-
assert new_config.space.custom_instructions == "Custom Instructions"
|
|
111
|
-
assert new_config.agent.experimental.temperature == 0.8
|
|
112
|
-
assert new_config.agent.max_loop_iterations == 5
|
|
113
|
-
assert new_config.agent.experimental.additional_llm_options == {
|
|
114
|
-
"some_option": "value"
|
|
115
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|