unique_orchestrator 1.11.1__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_orchestrator might be problematic. Click here for more details.
- unique_orchestrator/config.py +401 -0
- unique_orchestrator/prompts/generic_reference_prompt.jinja2 +46 -0
- unique_orchestrator/prompts/system_prompt.jinja2 +166 -0
- unique_orchestrator/prompts/user_message_prompt.jinja2 +23 -0
- unique_orchestrator/tests/test_unique_ai_get_filtered_user_metadata.py +259 -0
- unique_orchestrator/tests/test_unique_ai_log_tool_calls.py +729 -0
- unique_orchestrator/tests/test_unique_ai_reference_order.py +134 -0
- unique_orchestrator/tests/test_unique_ai_update_debug_info_for_tool_control.py +339 -0
- unique_orchestrator/unique_ai.py +537 -0
- unique_orchestrator/unique_ai_builder.py +568 -0
- unique_orchestrator-1.11.1.dist-info/LICENSE +1 -0
- unique_orchestrator-1.11.1.dist-info/METADATA +199 -0
- unique_orchestrator-1.11.1.dist-info/RECORD +14 -0
- unique_orchestrator-1.11.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
from datetime import datetime, timezone
|
|
2
|
+
from logging import Logger
|
|
3
|
+
from typing import NamedTuple, cast
|
|
4
|
+
|
|
5
|
+
from unique_follow_up_questions.follow_up_postprocessor import (
|
|
6
|
+
FollowUpPostprocessor,
|
|
7
|
+
)
|
|
8
|
+
from unique_internal_search.uploaded_search.config import (
|
|
9
|
+
UploadedSearchConfig,
|
|
10
|
+
)
|
|
11
|
+
from unique_internal_search.uploaded_search.service import (
|
|
12
|
+
UploadedSearchTool,
|
|
13
|
+
)
|
|
14
|
+
from unique_stock_ticker.stock_ticker_postprocessor import (
|
|
15
|
+
StockTickerPostprocessor,
|
|
16
|
+
)
|
|
17
|
+
from unique_toolkit import LanguageModelService, get_async_openai_client
|
|
18
|
+
from unique_toolkit.agentic.debug_info_manager.debug_info_manager import (
|
|
19
|
+
DebugInfoManager,
|
|
20
|
+
)
|
|
21
|
+
from unique_toolkit.agentic.evaluation.evaluation_manager import EvaluationManager
|
|
22
|
+
from unique_toolkit.agentic.evaluation.hallucination.hallucination_evaluation import (
|
|
23
|
+
HallucinationEvaluation,
|
|
24
|
+
)
|
|
25
|
+
from unique_toolkit.agentic.history_manager import (
|
|
26
|
+
history_manager as history_manager_module,
|
|
27
|
+
)
|
|
28
|
+
from unique_toolkit.agentic.history_manager.history_manager import (
|
|
29
|
+
HistoryManager,
|
|
30
|
+
HistoryManagerConfig,
|
|
31
|
+
)
|
|
32
|
+
from unique_toolkit.agentic.loop_runner import (
|
|
33
|
+
BasicLoopIterationRunner,
|
|
34
|
+
BasicLoopIterationRunnerConfig,
|
|
35
|
+
LoopIterationRunner,
|
|
36
|
+
PlanningMiddleware,
|
|
37
|
+
QwenLoopIterationRunner,
|
|
38
|
+
is_qwen_model,
|
|
39
|
+
)
|
|
40
|
+
from unique_toolkit.agentic.message_log_manager.service import MessageStepLogger
|
|
41
|
+
from unique_toolkit.agentic.postprocessor.postprocessor_manager import (
|
|
42
|
+
PostprocessorManager,
|
|
43
|
+
)
|
|
44
|
+
from unique_toolkit.agentic.reference_manager.reference_manager import ReferenceManager
|
|
45
|
+
from unique_toolkit.agentic.responses_api import (
|
|
46
|
+
DisplayCodeInterpreterFilesPostProcessor,
|
|
47
|
+
ShowExecutedCodePostprocessor,
|
|
48
|
+
)
|
|
49
|
+
from unique_toolkit.agentic.thinking_manager.thinking_manager import (
|
|
50
|
+
ThinkingManager,
|
|
51
|
+
ThinkingManagerConfig,
|
|
52
|
+
)
|
|
53
|
+
from unique_toolkit.agentic.tools.a2a import (
|
|
54
|
+
A2AManager,
|
|
55
|
+
ExtendedSubAgentToolConfig,
|
|
56
|
+
SubAgentDisplaySpec,
|
|
57
|
+
SubAgentEvaluationService,
|
|
58
|
+
SubAgentEvaluationSpec,
|
|
59
|
+
SubAgentReferencesPostprocessor,
|
|
60
|
+
SubAgentResponsesDisplayPostprocessor,
|
|
61
|
+
SubAgentResponsesPostprocessorConfig,
|
|
62
|
+
SubAgentResponseWatcher,
|
|
63
|
+
)
|
|
64
|
+
from unique_toolkit.agentic.tools.config import ToolBuildConfig
|
|
65
|
+
from unique_toolkit.agentic.tools.mcp.manager import MCPManager
|
|
66
|
+
from unique_toolkit.agentic.tools.openai_builtin.base import OpenAIBuiltInToolName
|
|
67
|
+
from unique_toolkit.agentic.tools.tool_manager import (
|
|
68
|
+
OpenAIBuiltInToolManager,
|
|
69
|
+
ResponsesApiToolManager,
|
|
70
|
+
ToolManager,
|
|
71
|
+
ToolManagerConfig,
|
|
72
|
+
)
|
|
73
|
+
from unique_toolkit.agentic.tools.tool_progress_reporter import ToolProgressReporter
|
|
74
|
+
from unique_toolkit.app.schemas import ChatEvent, McpServer
|
|
75
|
+
from unique_toolkit.chat.service import ChatService
|
|
76
|
+
from unique_toolkit.content import Content
|
|
77
|
+
from unique_toolkit.content.service import ContentService
|
|
78
|
+
from unique_toolkit.protocols.support import ResponsesSupportCompleteWithReferences
|
|
79
|
+
|
|
80
|
+
from unique_orchestrator.config import UniqueAIConfig
|
|
81
|
+
from unique_orchestrator.unique_ai import UniqueAI, UniqueAIResponsesApi
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
async def build_unique_ai(
|
|
85
|
+
event: ChatEvent,
|
|
86
|
+
logger: Logger,
|
|
87
|
+
config: UniqueAIConfig,
|
|
88
|
+
debug_info_manager: DebugInfoManager,
|
|
89
|
+
) -> UniqueAI | UniqueAIResponsesApi:
|
|
90
|
+
common_components = _build_common(event, logger, config)
|
|
91
|
+
|
|
92
|
+
if config.agent.experimental.responses_api_config.use_responses_api:
|
|
93
|
+
return await _build_responses(
|
|
94
|
+
event=event,
|
|
95
|
+
logger=logger,
|
|
96
|
+
config=config,
|
|
97
|
+
debug_info_manager=debug_info_manager,
|
|
98
|
+
common_components=common_components,
|
|
99
|
+
)
|
|
100
|
+
else:
|
|
101
|
+
return _build_completions(
|
|
102
|
+
event=event,
|
|
103
|
+
logger=logger,
|
|
104
|
+
config=config,
|
|
105
|
+
debug_info_manager=debug_info_manager,
|
|
106
|
+
common_components=common_components,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class _CommonComponents(NamedTuple):
|
|
111
|
+
chat_service: ChatService
|
|
112
|
+
content_service: ContentService
|
|
113
|
+
uploaded_documents: list[Content]
|
|
114
|
+
thinking_manager: ThinkingManager
|
|
115
|
+
reference_manager: ReferenceManager
|
|
116
|
+
history_manager: HistoryManager
|
|
117
|
+
evaluation_manager: EvaluationManager
|
|
118
|
+
postprocessor_manager: PostprocessorManager
|
|
119
|
+
message_step_logger: MessageStepLogger
|
|
120
|
+
response_watcher: SubAgentResponseWatcher
|
|
121
|
+
# Tool Manager Components
|
|
122
|
+
tool_progress_reporter: ToolProgressReporter
|
|
123
|
+
tool_manager_config: ToolManagerConfig
|
|
124
|
+
mcp_manager: MCPManager
|
|
125
|
+
a2a_manager: A2AManager
|
|
126
|
+
mcp_servers: list[McpServer]
|
|
127
|
+
loop_iteration_runner: LoopIterationRunner
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _build_common(
|
|
131
|
+
event: ChatEvent,
|
|
132
|
+
logger: Logger,
|
|
133
|
+
config: UniqueAIConfig,
|
|
134
|
+
) -> _CommonComponents:
|
|
135
|
+
chat_service = ChatService(event)
|
|
136
|
+
|
|
137
|
+
content_service = ContentService.from_event(event)
|
|
138
|
+
|
|
139
|
+
uploaded_documents = content_service.get_documents_uploaded_to_chat()
|
|
140
|
+
|
|
141
|
+
response_watcher = SubAgentResponseWatcher()
|
|
142
|
+
|
|
143
|
+
tool_progress_reporter = ToolProgressReporter(
|
|
144
|
+
chat_service=chat_service,
|
|
145
|
+
config=config.agent.services.tool_progress_reporter_config,
|
|
146
|
+
)
|
|
147
|
+
thinking_manager_config = ThinkingManagerConfig(
|
|
148
|
+
thinking_steps_display=config.agent.experimental.thinking_steps_display
|
|
149
|
+
)
|
|
150
|
+
thinking_manager = ThinkingManager(
|
|
151
|
+
logger=logger,
|
|
152
|
+
config=thinking_manager_config,
|
|
153
|
+
tool_progress_reporter=tool_progress_reporter,
|
|
154
|
+
chat_service=chat_service,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
reference_manager = ReferenceManager()
|
|
158
|
+
|
|
159
|
+
history_manager_config = HistoryManagerConfig(
|
|
160
|
+
experimental_features=history_manager_module.ExperimentalFeatures(),
|
|
161
|
+
percent_of_max_tokens_for_history=config.agent.input_token_distribution.percent_for_history,
|
|
162
|
+
language_model=config.space.language_model,
|
|
163
|
+
uploaded_content_config=config.agent.services.uploaded_content_config,
|
|
164
|
+
)
|
|
165
|
+
history_manager = HistoryManager(
|
|
166
|
+
logger,
|
|
167
|
+
event,
|
|
168
|
+
history_manager_config,
|
|
169
|
+
config.space.language_model,
|
|
170
|
+
reference_manager,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
evaluation_manager = EvaluationManager(logger=logger, chat_service=chat_service)
|
|
174
|
+
if config.agent.services.evaluation_config:
|
|
175
|
+
evaluation_manager.add_evaluation(
|
|
176
|
+
HallucinationEvaluation(
|
|
177
|
+
config.agent.services.evaluation_config.hallucination_config,
|
|
178
|
+
event,
|
|
179
|
+
reference_manager,
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
mcp_manager = MCPManager(
|
|
184
|
+
mcp_servers=event.payload.mcp_servers,
|
|
185
|
+
event=event,
|
|
186
|
+
tool_progress_reporter=tool_progress_reporter,
|
|
187
|
+
)
|
|
188
|
+
a2a_manager = A2AManager(
|
|
189
|
+
logger=logger,
|
|
190
|
+
tool_progress_reporter=tool_progress_reporter,
|
|
191
|
+
response_watcher=response_watcher,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
tool_manager_config = ToolManagerConfig(
|
|
195
|
+
tools=config.space.tools,
|
|
196
|
+
max_tool_calls=config.agent.experimental.loop_configuration.max_tool_calls_per_iteration,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
postprocessor_manager = PostprocessorManager(
|
|
200
|
+
logger=logger,
|
|
201
|
+
chat_service=chat_service,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
if config.agent.services.stock_ticker_config is not None:
|
|
205
|
+
postprocessor_manager.add_postprocessor(
|
|
206
|
+
StockTickerPostprocessor(
|
|
207
|
+
config=config.agent.services.stock_ticker_config,
|
|
208
|
+
event=event,
|
|
209
|
+
)
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
if (
|
|
213
|
+
config.agent.services.follow_up_questions_config
|
|
214
|
+
and config.agent.services.follow_up_questions_config.number_of_questions > 0
|
|
215
|
+
):
|
|
216
|
+
# Should run last to make sure the follow up questions are displayed last.
|
|
217
|
+
postprocessor_manager.set_last_postprocessor(
|
|
218
|
+
FollowUpPostprocessor(
|
|
219
|
+
logger=logger,
|
|
220
|
+
config=config.agent.services.follow_up_questions_config,
|
|
221
|
+
event=event,
|
|
222
|
+
historyManager=history_manager,
|
|
223
|
+
llm_service=LanguageModelService.from_event(event),
|
|
224
|
+
)
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
loop_iteration_runner = _build_loop_iteration_runner(
|
|
228
|
+
config=config,
|
|
229
|
+
history_manager=history_manager,
|
|
230
|
+
llm_service=LanguageModelService.from_event(event),
|
|
231
|
+
chat_service=chat_service,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
return _CommonComponents(
|
|
235
|
+
chat_service=chat_service,
|
|
236
|
+
content_service=content_service,
|
|
237
|
+
uploaded_documents=uploaded_documents,
|
|
238
|
+
thinking_manager=thinking_manager,
|
|
239
|
+
reference_manager=reference_manager,
|
|
240
|
+
history_manager=history_manager,
|
|
241
|
+
evaluation_manager=evaluation_manager,
|
|
242
|
+
tool_progress_reporter=tool_progress_reporter,
|
|
243
|
+
mcp_manager=mcp_manager,
|
|
244
|
+
a2a_manager=a2a_manager,
|
|
245
|
+
tool_manager_config=tool_manager_config,
|
|
246
|
+
mcp_servers=event.payload.mcp_servers,
|
|
247
|
+
postprocessor_manager=postprocessor_manager,
|
|
248
|
+
response_watcher=response_watcher,
|
|
249
|
+
message_step_logger=MessageStepLogger(chat_service),
|
|
250
|
+
loop_iteration_runner=loop_iteration_runner,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
async def _build_responses(
|
|
255
|
+
event: ChatEvent,
|
|
256
|
+
logger: Logger,
|
|
257
|
+
config: UniqueAIConfig,
|
|
258
|
+
common_components: _CommonComponents,
|
|
259
|
+
debug_info_manager: DebugInfoManager,
|
|
260
|
+
) -> UniqueAIResponsesApi:
|
|
261
|
+
client = get_async_openai_client().copy(
|
|
262
|
+
default_headers={
|
|
263
|
+
"x-model": config.space.language_model.name,
|
|
264
|
+
"x-user-id": event.user_id,
|
|
265
|
+
"x-company-id": event.company_id,
|
|
266
|
+
"x-assistant-id": event.payload.assistant_id,
|
|
267
|
+
"x-chat-id": event.payload.chat_id,
|
|
268
|
+
}
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
assert config.agent.experimental.responses_api_config is not None
|
|
272
|
+
|
|
273
|
+
code_interpreter_config = (
|
|
274
|
+
config.agent.experimental.responses_api_config.code_interpreter
|
|
275
|
+
)
|
|
276
|
+
postprocessor_manager = common_components.postprocessor_manager
|
|
277
|
+
tool_names = [tool.name for tool in config.space.tools]
|
|
278
|
+
|
|
279
|
+
if code_interpreter_config is not None:
|
|
280
|
+
if OpenAIBuiltInToolName.CODE_INTERPRETER not in tool_names:
|
|
281
|
+
logger.info("Automatically adding code interpreter to the tools")
|
|
282
|
+
config = config.model_copy(deep=True)
|
|
283
|
+
config.space.tools.append(
|
|
284
|
+
ToolBuildConfig(
|
|
285
|
+
name=OpenAIBuiltInToolName.CODE_INTERPRETER,
|
|
286
|
+
configuration=code_interpreter_config.tool_config,
|
|
287
|
+
)
|
|
288
|
+
)
|
|
289
|
+
common_components.tool_manager_config.tools = config.space.tools
|
|
290
|
+
|
|
291
|
+
if code_interpreter_config.executed_code_display_config is not None:
|
|
292
|
+
postprocessor_manager.add_postprocessor(
|
|
293
|
+
ShowExecutedCodePostprocessor(
|
|
294
|
+
config=code_interpreter_config.executed_code_display_config
|
|
295
|
+
)
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
postprocessor_manager.add_postprocessor(
|
|
299
|
+
DisplayCodeInterpreterFilesPostProcessor(
|
|
300
|
+
client=client,
|
|
301
|
+
content_service=common_components.content_service,
|
|
302
|
+
config=code_interpreter_config.generated_files_config,
|
|
303
|
+
user_id=event.user_id,
|
|
304
|
+
company_id=event.company_id,
|
|
305
|
+
chat_id=event.payload.chat_id,
|
|
306
|
+
chat_service=common_components.chat_service,
|
|
307
|
+
)
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
builtin_tool_manager = await OpenAIBuiltInToolManager.build_manager(
|
|
311
|
+
uploaded_files=common_components.uploaded_documents,
|
|
312
|
+
content_service=common_components.content_service,
|
|
313
|
+
user_id=event.user_id,
|
|
314
|
+
company_id=event.company_id,
|
|
315
|
+
chat_id=event.payload.chat_id,
|
|
316
|
+
client=client,
|
|
317
|
+
tool_configs=config.space.tools,
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
tool_manager = ResponsesApiToolManager(
|
|
321
|
+
logger=logger,
|
|
322
|
+
config=common_components.tool_manager_config,
|
|
323
|
+
event=event,
|
|
324
|
+
tool_progress_reporter=common_components.tool_progress_reporter,
|
|
325
|
+
mcp_manager=common_components.mcp_manager,
|
|
326
|
+
a2a_manager=common_components.a2a_manager,
|
|
327
|
+
builtin_tool_manager=builtin_tool_manager,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
postprocessor_manager = common_components.postprocessor_manager
|
|
331
|
+
|
|
332
|
+
class ResponsesStreamingHandler(ResponsesSupportCompleteWithReferences):
|
|
333
|
+
def complete_with_references(self, *args, **kwargs):
|
|
334
|
+
return common_components.chat_service.complete_responses_with_references(
|
|
335
|
+
*args, **kwargs
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
async def complete_with_references_async(self, *args, **kwargs):
|
|
339
|
+
return await common_components.chat_service.complete_responses_with_references_async(
|
|
340
|
+
*args, **kwargs
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
streaming_handler = ResponsesStreamingHandler()
|
|
344
|
+
|
|
345
|
+
_add_sub_agents_postprocessor(
|
|
346
|
+
postprocessor_manager=postprocessor_manager,
|
|
347
|
+
tool_manager=tool_manager,
|
|
348
|
+
config=config,
|
|
349
|
+
response_watcher=common_components.response_watcher,
|
|
350
|
+
)
|
|
351
|
+
_add_sub_agents_evaluation(
|
|
352
|
+
evaluation_manager=common_components.evaluation_manager,
|
|
353
|
+
tool_manager=tool_manager,
|
|
354
|
+
config=config,
|
|
355
|
+
event=event,
|
|
356
|
+
response_watcher=common_components.response_watcher,
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
return UniqueAIResponsesApi(
|
|
360
|
+
event=event,
|
|
361
|
+
config=config,
|
|
362
|
+
logger=logger,
|
|
363
|
+
chat_service=common_components.chat_service,
|
|
364
|
+
content_service=common_components.content_service,
|
|
365
|
+
tool_manager=tool_manager,
|
|
366
|
+
thinking_manager=common_components.thinking_manager,
|
|
367
|
+
streaming_handler=streaming_handler,
|
|
368
|
+
history_manager=common_components.history_manager,
|
|
369
|
+
reference_manager=common_components.reference_manager,
|
|
370
|
+
evaluation_manager=common_components.evaluation_manager,
|
|
371
|
+
postprocessor_manager=postprocessor_manager,
|
|
372
|
+
debug_info_manager=debug_info_manager,
|
|
373
|
+
message_step_logger=common_components.message_step_logger,
|
|
374
|
+
mcp_servers=event.payload.mcp_servers,
|
|
375
|
+
loop_iteration_runner=common_components.loop_iteration_runner,
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def _build_completions(
|
|
380
|
+
event: ChatEvent,
|
|
381
|
+
logger: Logger,
|
|
382
|
+
config: UniqueAIConfig,
|
|
383
|
+
common_components: _CommonComponents,
|
|
384
|
+
debug_info_manager: DebugInfoManager,
|
|
385
|
+
) -> UniqueAI:
|
|
386
|
+
# Uploaded content behavior is always to force uploaded search tool:
|
|
387
|
+
# 1. Add it to forced tools if there are tool choices.
|
|
388
|
+
# 2. Simply force it if there are no tool choices.
|
|
389
|
+
# 3. Not available if not uploaded documents.
|
|
390
|
+
now = datetime.now(timezone.utc)
|
|
391
|
+
UPLOADED_DOCUMENTS_VALID = [
|
|
392
|
+
doc
|
|
393
|
+
for doc in common_components.uploaded_documents
|
|
394
|
+
if doc.expired_at is None or doc.expired_at > now
|
|
395
|
+
]
|
|
396
|
+
UPLOADED_DOCUMENTS_EXPIRED = [
|
|
397
|
+
doc
|
|
398
|
+
for doc in common_components.uploaded_documents
|
|
399
|
+
if doc.expired_at is not None and doc.expired_at <= now
|
|
400
|
+
]
|
|
401
|
+
TOOL_CHOICES = len(event.payload.tool_choices) > 0
|
|
402
|
+
|
|
403
|
+
if UPLOADED_DOCUMENTS_EXPIRED:
|
|
404
|
+
logger.info(
|
|
405
|
+
f"Number of expired uploaded documents: {len(UPLOADED_DOCUMENTS_EXPIRED)}"
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
if UPLOADED_DOCUMENTS_VALID:
|
|
409
|
+
logger.info(
|
|
410
|
+
f"Number of valid uploaded documents: {len(UPLOADED_DOCUMENTS_VALID)}"
|
|
411
|
+
)
|
|
412
|
+
common_components.tool_manager_config.tools.append(
|
|
413
|
+
ToolBuildConfig(
|
|
414
|
+
name=UploadedSearchTool.name,
|
|
415
|
+
display_name=UploadedSearchTool.name,
|
|
416
|
+
configuration=UploadedSearchConfig(),
|
|
417
|
+
)
|
|
418
|
+
)
|
|
419
|
+
if TOOL_CHOICES and UPLOADED_DOCUMENTS_VALID:
|
|
420
|
+
event.payload.tool_choices.append(str(UploadedSearchTool.name))
|
|
421
|
+
|
|
422
|
+
tool_manager = ToolManager(
|
|
423
|
+
logger=logger,
|
|
424
|
+
config=common_components.tool_manager_config,
|
|
425
|
+
event=event,
|
|
426
|
+
tool_progress_reporter=common_components.tool_progress_reporter,
|
|
427
|
+
mcp_manager=common_components.mcp_manager,
|
|
428
|
+
a2a_manager=common_components.a2a_manager,
|
|
429
|
+
)
|
|
430
|
+
if not TOOL_CHOICES and UPLOADED_DOCUMENTS_VALID:
|
|
431
|
+
tool_manager.add_forced_tool(UploadedSearchTool.name)
|
|
432
|
+
|
|
433
|
+
postprocessor_manager = common_components.postprocessor_manager
|
|
434
|
+
|
|
435
|
+
_add_sub_agents_postprocessor(
|
|
436
|
+
postprocessor_manager=postprocessor_manager,
|
|
437
|
+
tool_manager=tool_manager,
|
|
438
|
+
config=config,
|
|
439
|
+
response_watcher=common_components.response_watcher,
|
|
440
|
+
)
|
|
441
|
+
_add_sub_agents_evaluation(
|
|
442
|
+
evaluation_manager=common_components.evaluation_manager,
|
|
443
|
+
tool_manager=tool_manager,
|
|
444
|
+
config=config,
|
|
445
|
+
event=event,
|
|
446
|
+
response_watcher=common_components.response_watcher,
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
return UniqueAI(
|
|
450
|
+
event=event,
|
|
451
|
+
config=config,
|
|
452
|
+
logger=logger,
|
|
453
|
+
chat_service=common_components.chat_service,
|
|
454
|
+
content_service=common_components.content_service,
|
|
455
|
+
tool_manager=tool_manager,
|
|
456
|
+
thinking_manager=common_components.thinking_manager,
|
|
457
|
+
history_manager=common_components.history_manager,
|
|
458
|
+
reference_manager=common_components.reference_manager,
|
|
459
|
+
streaming_handler=common_components.chat_service,
|
|
460
|
+
evaluation_manager=common_components.evaluation_manager,
|
|
461
|
+
postprocessor_manager=postprocessor_manager,
|
|
462
|
+
debug_info_manager=debug_info_manager,
|
|
463
|
+
mcp_servers=event.payload.mcp_servers,
|
|
464
|
+
message_step_logger=common_components.message_step_logger,
|
|
465
|
+
loop_iteration_runner=common_components.loop_iteration_runner,
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def _add_sub_agents_postprocessor(
|
|
470
|
+
postprocessor_manager: PostprocessorManager,
|
|
471
|
+
tool_manager: ToolManager | ResponsesApiToolManager,
|
|
472
|
+
config: UniqueAIConfig,
|
|
473
|
+
response_watcher: SubAgentResponseWatcher,
|
|
474
|
+
) -> None:
|
|
475
|
+
sub_agents = tool_manager.sub_agents
|
|
476
|
+
if len(sub_agents) > 0:
|
|
477
|
+
display_config = SubAgentResponsesPostprocessorConfig(
|
|
478
|
+
sleep_time_before_update=config.agent.experimental.sub_agents_config.sleep_time_before_update,
|
|
479
|
+
)
|
|
480
|
+
display_specs = []
|
|
481
|
+
for tool in sub_agents:
|
|
482
|
+
tool_config = cast(
|
|
483
|
+
ExtendedSubAgentToolConfig, tool.settings.configuration
|
|
484
|
+
) # (BeforeValidator of ToolBuildConfig)
|
|
485
|
+
|
|
486
|
+
display_specs.append(
|
|
487
|
+
SubAgentDisplaySpec(
|
|
488
|
+
assistant_id=tool_config.assistant_id,
|
|
489
|
+
display_name=tool.display_name(),
|
|
490
|
+
display_config=tool_config.response_display_config,
|
|
491
|
+
)
|
|
492
|
+
)
|
|
493
|
+
reference_postprocessor = SubAgentReferencesPostprocessor(
|
|
494
|
+
response_watcher=response_watcher,
|
|
495
|
+
)
|
|
496
|
+
sub_agent_responses_postprocessor = SubAgentResponsesDisplayPostprocessor(
|
|
497
|
+
config=display_config,
|
|
498
|
+
response_watcher=response_watcher,
|
|
499
|
+
display_specs=display_specs,
|
|
500
|
+
)
|
|
501
|
+
postprocessor_manager.add_postprocessor(reference_postprocessor)
|
|
502
|
+
postprocessor_manager.add_postprocessor(sub_agent_responses_postprocessor)
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
def _add_sub_agents_evaluation(
|
|
506
|
+
evaluation_manager: EvaluationManager,
|
|
507
|
+
tool_manager: ToolManager | ResponsesApiToolManager,
|
|
508
|
+
config: UniqueAIConfig,
|
|
509
|
+
event: ChatEvent,
|
|
510
|
+
response_watcher: SubAgentResponseWatcher,
|
|
511
|
+
) -> None:
|
|
512
|
+
sub_agents = tool_manager.sub_agents
|
|
513
|
+
if (
|
|
514
|
+
len(sub_agents) > 0
|
|
515
|
+
and config.agent.experimental.sub_agents_config.evaluation_config is not None
|
|
516
|
+
):
|
|
517
|
+
evaluation_specs = []
|
|
518
|
+
for tool in sub_agents:
|
|
519
|
+
tool_config = cast(
|
|
520
|
+
ExtendedSubAgentToolConfig, tool.settings.configuration
|
|
521
|
+
) # (BeforeValidator of ToolBuildConfig)
|
|
522
|
+
|
|
523
|
+
evaluation_specs.append(
|
|
524
|
+
SubAgentEvaluationSpec(
|
|
525
|
+
assistant_id=tool_config.assistant_id,
|
|
526
|
+
display_name=tool.display_name(),
|
|
527
|
+
config=tool_config.evaluation_config,
|
|
528
|
+
)
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
sub_agent_evaluation = SubAgentEvaluationService(
|
|
532
|
+
config=config.agent.experimental.sub_agents_config.evaluation_config,
|
|
533
|
+
language_model_service=LanguageModelService.from_event(event),
|
|
534
|
+
evaluation_specs=evaluation_specs,
|
|
535
|
+
response_watcher=response_watcher,
|
|
536
|
+
)
|
|
537
|
+
evaluation_manager.add_evaluation(sub_agent_evaluation)
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def _build_loop_iteration_runner(
|
|
541
|
+
config: UniqueAIConfig,
|
|
542
|
+
history_manager: HistoryManager,
|
|
543
|
+
llm_service: LanguageModelService,
|
|
544
|
+
chat_service: ChatService,
|
|
545
|
+
) -> LoopIterationRunner:
|
|
546
|
+
runner = BasicLoopIterationRunner(
|
|
547
|
+
config=BasicLoopIterationRunnerConfig(
|
|
548
|
+
max_loop_iterations=config.agent.max_loop_iterations
|
|
549
|
+
)
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
if is_qwen_model(model=config.space.language_model):
|
|
553
|
+
runner = QwenLoopIterationRunner(
|
|
554
|
+
qwen_forced_tool_call_instruction=config.agent.experimental.loop_configuration.model_specific.qwen.forced_tool_call_instruction,
|
|
555
|
+
qwen_last_iteration_instruction=config.agent.experimental.loop_configuration.model_specific.qwen.last_iteration_instruction,
|
|
556
|
+
max_loop_iterations=config.agent.max_loop_iterations,
|
|
557
|
+
chat_service=chat_service,
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
if config.agent.experimental.loop_configuration.planning_config is not None:
|
|
561
|
+
runner = PlanningMiddleware(
|
|
562
|
+
loop_runner=runner,
|
|
563
|
+
config=config.agent.experimental.loop_configuration.planning_config,
|
|
564
|
+
history_manager=history_manager,
|
|
565
|
+
llm_service=llm_service,
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
return runner
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
`unique_toolkit` is covered by the [`Unique License v1`](https://github.com/Unique-AG/license/releases/tag/unique-license.v1), unless the/a header or a nested LICENSE specifies another license.
|