unique-orchestrator 2026.28.0.dev2__tar.gz → 2026.28.0.dev4__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.28.0.dev4/PKG-INFO +27 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/pyproject.toml +10 -10
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/config.py +40 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_config_services_validators.py +69 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/unique_ai.py +1 -1
- unique_orchestrator-2026.28.0.dev2/PKG-INFO +0 -27
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/README.md +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/__init__.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/_builders/__init__.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/_builders/inject_tool_reminders.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/_builders/loop_iteration_runner.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/_builders/open_file_setup.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/_builders/skill_setup.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/prompts/generic_reference_prompt.jinja2 +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/prompts/system_prompt.jinja2 +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/prompts/user_message_prompt.jinja2 +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/settings.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_agent_config_rjsf_ui_schema.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_build_loop_iteration_runner.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_qwen_max_loop_iterations.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_register_code_interpreter_postprocessors.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_unique_ai_async_modify.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_unique_ai_execution_timing.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_unique_ai_get_filtered_user_metadata.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_unique_ai_log_tool_calls.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_unique_ai_loop_debug_params.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_unique_ai_persist_tool_calls.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_unique_ai_plan_or_execute_include.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_unique_ai_reference_order.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_unique_ai_render_system_prompt_user_instructions.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/tests/test_utils_resolve_other_options.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/unique_ai_builder.py +0 -0
- {unique_orchestrator-2026.28.0.dev2 → unique_orchestrator-2026.28.0.dev4}/unique_orchestrator/utils.py +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: unique-orchestrator
|
|
3
|
+
Version: 2026.28.0.dev4
|
|
4
|
+
Summary:
|
|
5
|
+
Author: Andreas Hauri
|
|
6
|
+
Author-email: Andreas Hauri <andreas.hauri@unique.ai>
|
|
7
|
+
License: Proprietary
|
|
8
|
+
Requires-Dist: pydantic>=2.8.2,<3
|
|
9
|
+
Requires-Dist: pydantic-settings>=2.10.1,<3
|
|
10
|
+
Requires-Dist: typing-extensions>=4.9.0,<5
|
|
11
|
+
Requires-Dist: jinja2>=3.1.0,<4
|
|
12
|
+
Requires-Dist: unique-toolkit>=2026.28.0.dev3,<2026.28.0rc0
|
|
13
|
+
Requires-Dist: unique-stock-ticker>=2026.28.0.dev1,<2026.28.0rc0
|
|
14
|
+
Requires-Dist: unique-follow-up-questions>=2026.28.0.dev1,<2026.28.0rc0
|
|
15
|
+
Requires-Dist: unique-internal-search>=2026.28.0.dev1,<2026.28.0rc0
|
|
16
|
+
Requires-Dist: unique-deep-research>=2026.28.0.dev1,<2026.28.0rc0
|
|
17
|
+
Requires-Dist: unique-web-search>=2026.28.0.dev1,<2026.28.0rc0
|
|
18
|
+
Requires-Dist: unique-swot>=2026.28.0.dev1,<2026.28.0rc0
|
|
19
|
+
Requires-Dist: unique-skill-tool>=2026.28.0.dev1,<2026.28.0rc0
|
|
20
|
+
Requires-Dist: unique-user-memory>=2026.28.0.dev2,<2026.28.0rc0
|
|
21
|
+
Requires-Dist: openai>=1.109.1,<3
|
|
22
|
+
Requires-Python: >=3.12, <4
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# Unique Orchestrator
|
|
26
|
+
|
|
27
|
+
Unique AI orchestrator agent to struct and direct subagents, tools and services
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique_orchestrator"
|
|
3
|
-
version = "2026.28.0.
|
|
3
|
+
version = "2026.28.0.dev4"
|
|
4
4
|
description = ""
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "Proprietary" }
|
|
@@ -13,15 +13,15 @@ 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.28.0.
|
|
17
|
-
"unique-stock-ticker>=2026.28.0.
|
|
18
|
-
"unique-follow-up-questions>=2026.28.0.
|
|
19
|
-
"unique-internal-search>=2026.28.0.
|
|
20
|
-
"unique-deep-research>=2026.28.0.
|
|
21
|
-
"unique-web-search>=2026.28.0.
|
|
22
|
-
"unique-swot>=2026.28.0.
|
|
23
|
-
"unique-skill-tool>=2026.28.0.
|
|
24
|
-
"unique-user-memory>=2026.28.0.
|
|
16
|
+
"unique-toolkit>=2026.28.0.dev3,<2026.28.0rc0",
|
|
17
|
+
"unique-stock-ticker>=2026.28.0.dev1,<2026.28.0rc0",
|
|
18
|
+
"unique-follow-up-questions>=2026.28.0.dev1,<2026.28.0rc0",
|
|
19
|
+
"unique-internal-search>=2026.28.0.dev1,<2026.28.0rc0",
|
|
20
|
+
"unique-deep-research>=2026.28.0.dev1,<2026.28.0rc0",
|
|
21
|
+
"unique-web-search>=2026.28.0.dev1,<2026.28.0rc0",
|
|
22
|
+
"unique-swot>=2026.28.0.dev1,<2026.28.0rc0",
|
|
23
|
+
"unique-skill-tool>=2026.28.0.dev1,<2026.28.0rc0",
|
|
24
|
+
"unique-user-memory>=2026.28.0.dev2,<2026.28.0rc0",
|
|
25
25
|
"openai>=1.109.1,<3",
|
|
26
26
|
]
|
|
27
27
|
|
|
@@ -37,6 +37,12 @@ from unique_toolkit.agentic.tools.a2a import (
|
|
|
37
37
|
REFERENCING_INSTRUCTIONS_FOR_USER_PROMPT,
|
|
38
38
|
)
|
|
39
39
|
from unique_toolkit.agentic.tools.a2a.evaluation import SubAgentEvaluationServiceConfig
|
|
40
|
+
from unique_toolkit.agentic.tools.experimental.ask_user_tool import (
|
|
41
|
+
AskUserTool,
|
|
42
|
+
)
|
|
43
|
+
from unique_toolkit.agentic.tools.experimental.ask_user_tool import (
|
|
44
|
+
AskUserToolConfig as BaseAskUserToolConfig,
|
|
45
|
+
)
|
|
40
46
|
from unique_toolkit.agentic.tools.experimental.open_file_tool.config import (
|
|
41
47
|
OpenFileToolConfig,
|
|
42
48
|
)
|
|
@@ -391,6 +397,13 @@ class UploadedSearchToolConfig(BaseToolConfig):
|
|
|
391
397
|
return self
|
|
392
398
|
|
|
393
399
|
|
|
400
|
+
class AskUserToolConfig(BaseAskUserToolConfig):
|
|
401
|
+
enabled: bool = Field(
|
|
402
|
+
default=False,
|
|
403
|
+
description="Enable the AskUser elicitation tool.",
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
|
|
394
407
|
class ExperimentalConfig(BaseToolConfig):
|
|
395
408
|
"""Experimental features this part of the configuration might evolve in the future continuously"""
|
|
396
409
|
|
|
@@ -431,6 +444,12 @@ class ExperimentalConfig(BaseToolConfig):
|
|
|
431
444
|
|
|
432
445
|
uploaded_search_tool_config: UploadedSearchToolConfig = UploadedSearchToolConfig()
|
|
433
446
|
|
|
447
|
+
ask_user_tool_config: AskUserToolConfig = Field(
|
|
448
|
+
title="Ask User Tool (Elicitation)",
|
|
449
|
+
description="Configuration for the AskUser tool",
|
|
450
|
+
default_factory=AskUserToolConfig,
|
|
451
|
+
)
|
|
452
|
+
|
|
434
453
|
use_responses_api: bool = Field(
|
|
435
454
|
default=False,
|
|
436
455
|
description="If set, the main agent will use the Responses API from OpenAI",
|
|
@@ -593,6 +612,27 @@ class UniqueAIConfig(BaseToolConfig):
|
|
|
593
612
|
|
|
594
613
|
return self
|
|
595
614
|
|
|
615
|
+
@model_validator(mode="after")
|
|
616
|
+
def inject_ask_user_tool(self) -> "UniqueAIConfig":
|
|
617
|
+
tool_names = [t.name for t in self.space.tools]
|
|
618
|
+
has_tool = AskUserTool.name in tool_names
|
|
619
|
+
config = self.agent.experimental.ask_user_tool_config
|
|
620
|
+
|
|
621
|
+
if config.enabled and not has_tool:
|
|
622
|
+
self.space.tools.append(
|
|
623
|
+
ToolBuildConfig(
|
|
624
|
+
name=AskUserTool.name,
|
|
625
|
+
display_name=AskUserTool.DISPLAY_NAME,
|
|
626
|
+
configuration=config,
|
|
627
|
+
)
|
|
628
|
+
)
|
|
629
|
+
elif not config.enabled and has_tool:
|
|
630
|
+
self.space.tools = [
|
|
631
|
+
t for t in self.space.tools if t.name != AskUserTool.name
|
|
632
|
+
]
|
|
633
|
+
|
|
634
|
+
return self
|
|
635
|
+
|
|
596
636
|
@property
|
|
597
637
|
def effective_max_loop_iterations(self) -> int:
|
|
598
638
|
"""Effective max loop iterations, accounting for model-specific overrides."""
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
from unique_follow_up_questions.config import FollowUpQuestionsConfig
|
|
3
3
|
from unique_stock_ticker.config import StockTickerConfig
|
|
4
|
+
from unique_toolkit.agentic.tools.experimental.ask_user_tool import (
|
|
5
|
+
AskUserTool,
|
|
6
|
+
)
|
|
4
7
|
from unique_toolkit.agentic.tools.experimental.open_file_tool.config import (
|
|
5
8
|
OpenFileToolConfig,
|
|
6
9
|
)
|
|
@@ -23,6 +26,7 @@ from unique_toolkit.language_model.schemas import LanguageModelTokenLimits
|
|
|
23
26
|
from unique_user_memory.config import UserMemoryConfig
|
|
24
27
|
|
|
25
28
|
from unique_orchestrator.config import (
|
|
29
|
+
AskUserToolConfig,
|
|
26
30
|
EvaluationConfig,
|
|
27
31
|
UniqueAIConfig,
|
|
28
32
|
UniqueAIServices,
|
|
@@ -496,3 +500,68 @@ class TestUniqueAIConfigUserMemory:
|
|
|
496
500
|
config = UniqueAIConfig(space={"allowUserMemory": True})
|
|
497
501
|
|
|
498
502
|
assert config.space.allow_user_memory is True
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
class TestUniqueAIConfigInjectAskUserToolValidator:
|
|
506
|
+
"""Tests for UniqueAIConfig.inject_ask_user_tool (AskUser)."""
|
|
507
|
+
|
|
508
|
+
def _entries(self, config: UniqueAIConfig) -> list[ToolBuildConfig]:
|
|
509
|
+
return [t for t in config.space.tools if t.name == AskUserTool.name]
|
|
510
|
+
|
|
511
|
+
def test_appends_when_enabled(self) -> None:
|
|
512
|
+
config = UniqueAIConfig(
|
|
513
|
+
space=UniqueAISpaceConfig(
|
|
514
|
+
language_model=_make_model(supports_responses_api=True),
|
|
515
|
+
tools=[],
|
|
516
|
+
),
|
|
517
|
+
agent={
|
|
518
|
+
"experimental": {
|
|
519
|
+
"ask_user_tool_config": AskUserToolConfig(enabled=True)
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
)
|
|
523
|
+
|
|
524
|
+
entries = self._entries(config)
|
|
525
|
+
assert len(entries) == 1
|
|
526
|
+
assert entries[0].name == AskUserTool.name
|
|
527
|
+
assert isinstance(entries[0].configuration, AskUserToolConfig)
|
|
528
|
+
assert entries[0].configuration.enabled is True
|
|
529
|
+
|
|
530
|
+
def test_removes_when_disabled(self) -> None:
|
|
531
|
+
config = UniqueAIConfig(
|
|
532
|
+
space=UniqueAISpaceConfig(
|
|
533
|
+
language_model=_make_model(supports_responses_api=True),
|
|
534
|
+
tools=[
|
|
535
|
+
ToolBuildConfig(
|
|
536
|
+
name=AskUserTool.name,
|
|
537
|
+
configuration=AskUserToolConfig(enabled=False),
|
|
538
|
+
)
|
|
539
|
+
],
|
|
540
|
+
),
|
|
541
|
+
agent={
|
|
542
|
+
"experimental": {
|
|
543
|
+
"ask_user_tool_config": AskUserToolConfig(enabled=False)
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
assert self._entries(config) == []
|
|
549
|
+
|
|
550
|
+
def test_idempotent_when_already_present(self) -> None:
|
|
551
|
+
existing = ToolBuildConfig(
|
|
552
|
+
name=AskUserTool.name,
|
|
553
|
+
configuration=AskUserToolConfig(enabled=True),
|
|
554
|
+
)
|
|
555
|
+
config = UniqueAIConfig(
|
|
556
|
+
space=UniqueAISpaceConfig(
|
|
557
|
+
language_model=_make_model(supports_responses_api=True),
|
|
558
|
+
tools=[existing],
|
|
559
|
+
),
|
|
560
|
+
agent={
|
|
561
|
+
"experimental": {
|
|
562
|
+
"ask_user_tool_config": AskUserToolConfig(enabled=True)
|
|
563
|
+
}
|
|
564
|
+
},
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
assert len(self._entries(config)) == 1
|
|
@@ -701,7 +701,7 @@ class UniqueAI:
|
|
|
701
701
|
# (see ``unique_skill_tool.SkillTool._log_skill_loaded``), so it is
|
|
702
702
|
# redundant and noisy to also list it here.
|
|
703
703
|
|
|
704
|
-
tool_names_not_to_log: set[str] = {"DeepResearch", "Skill"}
|
|
704
|
+
tool_names_not_to_log: set[str] = {"DeepResearch", "Skill", "AskUser"}
|
|
705
705
|
|
|
706
706
|
used_tools: dict[str, int] = {}
|
|
707
707
|
for tool_call in tool_calls:
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.3
|
|
2
|
-
Name: unique-orchestrator
|
|
3
|
-
Version: 2026.28.0.dev2
|
|
4
|
-
Summary:
|
|
5
|
-
Author: Andreas Hauri
|
|
6
|
-
Author-email: Andreas Hauri <andreas.hauri@unique.ai>
|
|
7
|
-
License: Proprietary
|
|
8
|
-
Requires-Dist: pydantic>=2.8.2,<3
|
|
9
|
-
Requires-Dist: pydantic-settings>=2.10.1,<3
|
|
10
|
-
Requires-Dist: typing-extensions>=4.9.0,<5
|
|
11
|
-
Requires-Dist: jinja2>=3.1.0,<4
|
|
12
|
-
Requires-Dist: unique-toolkit>=2026.28.0.dev0,<2026.28.0rc0
|
|
13
|
-
Requires-Dist: unique-stock-ticker>=2026.28.0.dev0,<2026.28.0rc0
|
|
14
|
-
Requires-Dist: unique-follow-up-questions>=2026.28.0.dev0,<2026.28.0rc0
|
|
15
|
-
Requires-Dist: unique-internal-search>=2026.28.0.dev0,<2026.28.0rc0
|
|
16
|
-
Requires-Dist: unique-deep-research>=2026.28.0.dev0,<2026.28.0rc0
|
|
17
|
-
Requires-Dist: unique-web-search>=2026.28.0.dev0,<2026.28.0rc0
|
|
18
|
-
Requires-Dist: unique-swot>=2026.28.0.dev0,<2026.28.0rc0
|
|
19
|
-
Requires-Dist: unique-skill-tool>=2026.28.0.dev0,<2026.28.0rc0
|
|
20
|
-
Requires-Dist: unique-user-memory>=2026.28.0.dev1,<2026.28.0rc0
|
|
21
|
-
Requires-Dist: openai>=1.109.1,<3
|
|
22
|
-
Requires-Python: >=3.12, <4
|
|
23
|
-
Description-Content-Type: text/markdown
|
|
24
|
-
|
|
25
|
-
# Unique Orchestrator
|
|
26
|
-
|
|
27
|
-
Unique AI orchestrator agent to struct and direct subagents, tools and services
|
|
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
|