unique_orchestrator 2026.30.0.dev0__tar.gz → 2026.30.0.dev1__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.
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/PKG-INFO +2 -2
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/pyproject.toml +2 -2
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/config.py +4 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_unique_ai_plan_or_execute_include.py +41 -21
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/unique_ai_builder.py +40 -4
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/README.md +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/__init__.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/_builders/__init__.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/_builders/inject_tool_reminders.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/_builders/loop_iteration_runner.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/_builders/open_file_setup.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/_builders/skill_setup.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/prompts/generic_reference_prompt.jinja2 +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/prompts/system_prompt.jinja2 +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/prompts/user_message_prompt.jinja2 +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/settings.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_agent_config_rjsf_ui_schema.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_build_loop_iteration_runner.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_config_services_validators.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_qwen_max_loop_iterations.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_register_code_interpreter_postprocessors.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_unique_ai_async_modify.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_unique_ai_execution_timing.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_unique_ai_get_filtered_user_metadata.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_unique_ai_log_tool_calls.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_unique_ai_loop_debug_params.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_unique_ai_persist_tool_calls.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_unique_ai_reference_order.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_unique_ai_render_system_prompt_user_instructions.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/tests/test_utils_resolve_other_options.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/unique_ai.py +0 -0
- {unique_orchestrator-2026.30.0.dev0 → unique_orchestrator-2026.30.0.dev1}/unique_orchestrator/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-orchestrator
|
|
3
|
-
Version: 2026.30.0.
|
|
3
|
+
Version: 2026.30.0.dev1
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Andreas Hauri
|
|
6
6
|
Author-email: Andreas Hauri <andreas.hauri@unique.ai>
|
|
@@ -9,7 +9,7 @@ Requires-Dist: pydantic>=2.8.2,<3
|
|
|
9
9
|
Requires-Dist: pydantic-settings>=2.10.1,<3
|
|
10
10
|
Requires-Dist: typing-extensions>=4.9.0,<5
|
|
11
11
|
Requires-Dist: jinja2>=3.1.0,<4
|
|
12
|
-
Requires-Dist: unique-toolkit>=2026.30.0.
|
|
12
|
+
Requires-Dist: unique-toolkit>=2026.30.0.dev3,<2026.30.0rc0
|
|
13
13
|
Requires-Dist: unique-stock-ticker>=2026.30.0.dev0,<2026.30.0rc0
|
|
14
14
|
Requires-Dist: unique-follow-up-questions>=2026.30.0.dev0,<2026.30.0rc0
|
|
15
15
|
Requires-Dist: unique-internal-search>=2026.30.0.dev0,<2026.30.0rc0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique_orchestrator"
|
|
3
|
-
version = "2026.30.0.
|
|
3
|
+
version = "2026.30.0.dev1"
|
|
4
4
|
description = ""
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "Proprietary" }
|
|
@@ -13,7 +13,7 @@ dependencies = [
|
|
|
13
13
|
"pydantic-settings>=2.10.1,<3",
|
|
14
14
|
"typing-extensions>=4.9.0,<5",
|
|
15
15
|
"jinja2>=3.1.0,<4",
|
|
16
|
-
"unique-toolkit>=2026.30.0.
|
|
16
|
+
"unique-toolkit>=2026.30.0.dev3,<2026.30.0rc0",
|
|
17
17
|
"unique-stock-ticker>=2026.30.0.dev0,<2026.30.0rc0",
|
|
18
18
|
"unique-follow-up-questions>=2026.30.0.dev0,<2026.30.0rc0",
|
|
19
19
|
"unique-internal-search>=2026.30.0.dev0,<2026.30.0rc0",
|
|
@@ -457,6 +457,10 @@ class ExperimentalConfig(BaseToolConfig):
|
|
|
457
457
|
description="If set, the main agent will use the Responses API from OpenAI",
|
|
458
458
|
)
|
|
459
459
|
|
|
460
|
+
use_experimental_python_streaming: bool = Field(
|
|
461
|
+
default=False,
|
|
462
|
+
)
|
|
463
|
+
|
|
460
464
|
|
|
461
465
|
class UniqueAIAgentConfig(BaseToolConfig):
|
|
462
466
|
max_loop_iterations: Annotated[
|
|
@@ -9,7 +9,10 @@ from unittest.mock import AsyncMock, MagicMock
|
|
|
9
9
|
import pytest
|
|
10
10
|
from unique_toolkit.agentic.tools.tool_manager import ResponsesApiToolManager
|
|
11
11
|
|
|
12
|
-
from unique_orchestrator.unique_ai_builder import
|
|
12
|
+
from unique_orchestrator.unique_ai_builder import (
|
|
13
|
+
ResponsesStreamingHandler,
|
|
14
|
+
_ChatServiceResponsesStreaming,
|
|
15
|
+
)
|
|
13
16
|
|
|
14
17
|
|
|
15
18
|
def _make_handler(
|
|
@@ -17,15 +20,11 @@ def _make_handler(
|
|
|
17
20
|
) -> ResponsesStreamingHandler:
|
|
18
21
|
tool_manager = MagicMock(spec=ResponsesApiToolManager)
|
|
19
22
|
tool_manager.get_required_include_params.return_value = include_params
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
)
|
|
24
|
-
chat_service.complete_responses_with_references = MagicMock(
|
|
25
|
-
return_value=MagicMock()
|
|
26
|
-
)
|
|
23
|
+
inner = MagicMock()
|
|
24
|
+
inner.complete_with_references_async = AsyncMock(return_value=MagicMock())
|
|
25
|
+
inner.complete_with_references = MagicMock(return_value=MagicMock())
|
|
27
26
|
return ResponsesStreamingHandler(
|
|
28
|
-
|
|
27
|
+
inner=inner,
|
|
29
28
|
tool_manager=tool_manager,
|
|
30
29
|
)
|
|
31
30
|
|
|
@@ -45,9 +44,7 @@ async def test_responses_streaming_handler__injects_include__when_tool_manager_r
|
|
|
45
44
|
|
|
46
45
|
await handler.complete_with_references_async(messages=[], model_name="model")
|
|
47
46
|
|
|
48
|
-
call_kwargs =
|
|
49
|
-
handler._chat_service.complete_responses_with_references_async.await_args.kwargs
|
|
50
|
-
)
|
|
47
|
+
call_kwargs = handler._inner.complete_with_references_async.await_args.kwargs
|
|
51
48
|
assert call_kwargs["include"] == ["code_interpreter_call.outputs"]
|
|
52
49
|
handler._tool_manager.get_required_include_params.assert_called_once()
|
|
53
50
|
|
|
@@ -66,9 +63,7 @@ async def test_responses_streaming_handler__omits_include__when_tool_manager_ret
|
|
|
66
63
|
|
|
67
64
|
await handler.complete_with_references_async(messages=[], model_name="model")
|
|
68
65
|
|
|
69
|
-
call_kwargs =
|
|
70
|
-
handler._chat_service.complete_responses_with_references_async.await_args.kwargs
|
|
71
|
-
)
|
|
66
|
+
call_kwargs = handler._inner.complete_with_references_async.await_args.kwargs
|
|
72
67
|
assert "include" not in call_kwargs
|
|
73
68
|
|
|
74
69
|
|
|
@@ -81,9 +76,7 @@ def test_responses_streaming_handler__injects_include__sync_path() -> None:
|
|
|
81
76
|
|
|
82
77
|
handler.complete_with_references(messages=[], model_name="model")
|
|
83
78
|
|
|
84
|
-
call_kwargs =
|
|
85
|
-
handler._chat_service.complete_responses_with_references.call_args.kwargs
|
|
86
|
-
)
|
|
79
|
+
call_kwargs = handler._inner.complete_with_references.call_args.kwargs
|
|
87
80
|
assert call_kwargs["include"] == ["code_interpreter_call.outputs"]
|
|
88
81
|
|
|
89
82
|
|
|
@@ -94,7 +87,34 @@ def test_responses_streaming_handler__omits_include__sync_path_when_empty() -> N
|
|
|
94
87
|
|
|
95
88
|
handler.complete_with_references(messages=[], model_name="model")
|
|
96
89
|
|
|
97
|
-
call_kwargs =
|
|
98
|
-
handler._chat_service.complete_responses_with_references.call_args.kwargs
|
|
99
|
-
)
|
|
90
|
+
call_kwargs = handler._inner.complete_with_references.call_args.kwargs
|
|
100
91
|
assert "include" not in call_kwargs
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@pytest.mark.ai
|
|
95
|
+
@pytest.mark.asyncio
|
|
96
|
+
async def test_chat_service_responses_streaming__forwards_to_responses_methods() -> (
|
|
97
|
+
None
|
|
98
|
+
):
|
|
99
|
+
"""
|
|
100
|
+
Purpose: The legacy adapter must route the protocol's
|
|
101
|
+
`complete_with_references[_async]` to ChatService's Responses-specific
|
|
102
|
+
methods, not the Chat Completions ones.
|
|
103
|
+
Why this matters: ChatService exposes both; routing to the wrong method
|
|
104
|
+
would silently stream through the Chat Completions API.
|
|
105
|
+
"""
|
|
106
|
+
chat_service = MagicMock()
|
|
107
|
+
chat_service.complete_responses_with_references = MagicMock(
|
|
108
|
+
return_value=MagicMock()
|
|
109
|
+
)
|
|
110
|
+
chat_service.complete_responses_with_references_async = AsyncMock(
|
|
111
|
+
return_value=MagicMock()
|
|
112
|
+
)
|
|
113
|
+
adapter = _ChatServiceResponsesStreaming(chat_service)
|
|
114
|
+
|
|
115
|
+
adapter.complete_with_references(messages=[], model_name="model")
|
|
116
|
+
await adapter.complete_with_references_async(messages=[], model_name="model")
|
|
117
|
+
|
|
118
|
+
chat_service.complete_responses_with_references.assert_called_once()
|
|
119
|
+
chat_service.complete_responses_with_references_async.assert_awaited_once()
|
|
120
|
+
chat_service.complete_with_references.assert_not_called()
|
|
@@ -65,9 +65,13 @@ from unique_toolkit.agentic.tools.tool_manager import (
|
|
|
65
65
|
)
|
|
66
66
|
from unique_toolkit.agentic.tools.tool_progress_reporter import ToolProgressReporter
|
|
67
67
|
from unique_toolkit.app.schemas import ChatEvent, McpServer
|
|
68
|
+
from unique_toolkit.app.unique_settings import UniqueSettings
|
|
68
69
|
from unique_toolkit.chat.service import ChatService
|
|
69
70
|
from unique_toolkit.content import Content
|
|
70
71
|
from unique_toolkit.content.service import ContentService
|
|
72
|
+
from unique_toolkit.experimental.integrations.openai.streaming.event_routing import (
|
|
73
|
+
ResponsesCompleteWithReferences,
|
|
74
|
+
)
|
|
71
75
|
from unique_toolkit.language_model.infos import LanguageModelInfo, ModelCapabilities
|
|
72
76
|
from unique_toolkit.protocols.support import ResponsesSupportCompleteWithReferences
|
|
73
77
|
from unique_user_memory.user_memory import load_user_memory
|
|
@@ -99,14 +103,19 @@ class ResponsesStreamingHandler(ResponsesSupportCompleteWithReferences):
|
|
|
99
103
|
|
|
100
104
|
Injects `include` params from the tool manager on every call so the
|
|
101
105
|
orchestrator loop stays generic (no isinstance checks in UniqueAI).
|
|
106
|
+
|
|
107
|
+
Delegates the actual streaming to an injected
|
|
108
|
+
`ResponsesSupportCompleteWithReferences` (the event-routing
|
|
109
|
+
`ResponsesCompleteWithReferences` orchestrator), so this class only owns
|
|
110
|
+
the `include` injection.
|
|
102
111
|
"""
|
|
103
112
|
|
|
104
113
|
def __init__(
|
|
105
114
|
self,
|
|
106
|
-
|
|
115
|
+
inner: ResponsesSupportCompleteWithReferences,
|
|
107
116
|
tool_manager: ResponsesApiToolManager,
|
|
108
117
|
) -> None:
|
|
109
|
-
self.
|
|
118
|
+
self._inner: ResponsesSupportCompleteWithReferences = inner
|
|
110
119
|
self._tool_manager: ResponsesApiToolManager = tool_manager
|
|
111
120
|
|
|
112
121
|
@override
|
|
@@ -114,13 +123,26 @@ class ResponsesStreamingHandler(ResponsesSupportCompleteWithReferences):
|
|
|
114
123
|
include = self._tool_manager.get_required_include_params()
|
|
115
124
|
if include:
|
|
116
125
|
kwargs["include"] = include
|
|
117
|
-
return self.
|
|
126
|
+
return self._inner.complete_with_references(*args, **kwargs)
|
|
118
127
|
|
|
119
128
|
@override
|
|
120
129
|
async def complete_with_references_async(self, *args: Any, **kwargs: Any) -> Any:
|
|
121
130
|
include = self._tool_manager.get_required_include_params()
|
|
122
131
|
if include:
|
|
123
132
|
kwargs["include"] = include
|
|
133
|
+
return await self._inner.complete_with_references_async(*args, **kwargs)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class _ChatServiceResponsesStreaming(ResponsesSupportCompleteWithReferences):
|
|
137
|
+
def __init__(self, chat_service: ChatService) -> None:
|
|
138
|
+
self._chat_service: ChatService = chat_service
|
|
139
|
+
|
|
140
|
+
@override
|
|
141
|
+
def complete_with_references(self, *args: Any, **kwargs: Any) -> Any:
|
|
142
|
+
return self._chat_service.complete_responses_with_references(*args, **kwargs)
|
|
143
|
+
|
|
144
|
+
@override
|
|
145
|
+
async def complete_with_references_async(self, *args: Any, **kwargs: Any) -> Any:
|
|
124
146
|
return await self._chat_service.complete_responses_with_references_async(
|
|
125
147
|
*args, **kwargs
|
|
126
148
|
)
|
|
@@ -572,8 +594,22 @@ async def _build_responses(
|
|
|
572
594
|
openai_client=client,
|
|
573
595
|
)
|
|
574
596
|
|
|
597
|
+
if config.agent.experimental.use_experimental_python_streaming:
|
|
598
|
+
inner: ResponsesSupportCompleteWithReferences = ResponsesCompleteWithReferences(
|
|
599
|
+
UniqueSettings.from_chat_event(event),
|
|
600
|
+
additional_headers={
|
|
601
|
+
"x-model": config.space.language_model.name,
|
|
602
|
+
"x-user-id": event.user_id,
|
|
603
|
+
"x-company-id": event.company_id,
|
|
604
|
+
"x-assistant-id": event.payload.assistant_id,
|
|
605
|
+
"x-chat-id": event.payload.chat_id,
|
|
606
|
+
},
|
|
607
|
+
)
|
|
608
|
+
else:
|
|
609
|
+
inner = _ChatServiceResponsesStreaming(common_components.chat_service)
|
|
610
|
+
|
|
575
611
|
streaming_handler = ResponsesStreamingHandler(
|
|
576
|
-
|
|
612
|
+
inner=inner,
|
|
577
613
|
tool_manager=tool_manager,
|
|
578
614
|
)
|
|
579
615
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|