unique_toolkit 1.1.9__tar.gz → 1.2.0__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_toolkit-1.1.9 → unique_toolkit-1.2.0}/CHANGELOG.md +3 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/PKG-INFO +4 -1
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/pyproject.toml +1 -1
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/postprocessor/postprocessor_manager.py +3 -2
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/a2a/config.py +20 -2
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/a2a/manager.py +4 -4
- unique_toolkit-1.2.0/unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +5 -0
- unique_toolkit-1.2.0/unique_toolkit/agentic/tools/a2a/postprocessing/display.py +113 -0
- unique_toolkit-1.2.0/unique_toolkit/agentic/tools/a2a/postprocessing/postprocessor.py +204 -0
- unique_toolkit-1.2.0/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display.py +412 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/a2a/service.py +94 -25
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/config.py +10 -1
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/tool_manager.py +7 -1
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/LICENSE +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/README.md +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/_base_service.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/_time_utils.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/api_calling/human_verification_manager.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/base_model_type_attribute.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/chunk_relevancy_sorter/config.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/chunk_relevancy_sorter/exception.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/chunk_relevancy_sorter/schemas.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/chunk_relevancy_sorter/service.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/default_language_model.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/endpoint_builder.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/endpoint_requestor.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/exception.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/feature_flags/schema.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/pydantic_helpers.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/string_utilities.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/token/image_token_counting.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/token/token_counting.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/utils/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/utils/structured_output/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/utils/structured_output/schema.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/utils/write_configuration.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/validate_required_values.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/_common/validators.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/config.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/context_relevancy/prompts.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/context_relevancy/schema.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/context_relevancy/service.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/evaluation_manager.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/exception.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/hallucination/constants.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/hallucination/prompts.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/hallucination/service.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/hallucination/utils.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/output_parser.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/schemas.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/tests/test_context_relevancy_service.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/evaluation/tests/test_output_parser.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/history_manager/history_construction_with_contents.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/history_manager/history_manager.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/history_manager/loop_token_reducer.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/history_manager/utils.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/reference_manager/reference_manager.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/short_term_memory_manager/persistent_short_term_memory_manager.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/thinking_manager/thinking_manager.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/a2a/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/a2a/memory.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/a2a/schema.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/agent_chunks_hanlder.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/factory.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/mcp/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/mcp/manager.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/mcp/models.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/mcp/tool_wrapper.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/schemas.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/test/test_mcp_manager.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/tool.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/tool_progress_reporter.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/utils/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/utils/execution/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/utils/execution/execution.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/utils/source_handling/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/utils/source_handling/schema.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/utils/source_handling/source_formatting.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/agentic/tools/utils/source_handling/tests/test_source_formatting.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/app/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/app/dev_util.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/app/init_logging.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/app/init_sdk.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/app/performance/async_tasks.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/app/performance/async_wrapper.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/app/schemas.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/app/unique_settings.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/app/verification.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/chat/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/chat/constants.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/chat/functions.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/chat/schemas.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/chat/service.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/chat/state.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/chat/utils.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/content/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/content/constants.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/content/functions.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/content/schemas.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/content/service.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/content/utils.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/embedding/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/embedding/constants.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/embedding/functions.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/embedding/schemas.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/embedding/service.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/embedding/utils.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/framework_utilities/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/framework_utilities/langchain/client.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/framework_utilities/langchain/history.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/framework_utilities/openai/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/framework_utilities/openai/client.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/framework_utilities/openai/message_builder.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/framework_utilities/utils.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/language_model/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/language_model/builder.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/language_model/constants.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/language_model/functions.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/language_model/infos.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/language_model/prompt.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/language_model/reference.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/language_model/schemas.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/language_model/service.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/language_model/utils.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/protocols/support.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/short_term_memory/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/short_term_memory/constants.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/short_term_memory/functions.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/short_term_memory/schemas.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/short_term_memory/service.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/smart_rules/__init__.py +0 -0
- {unique_toolkit-1.1.9 → unique_toolkit-1.2.0}/unique_toolkit/smart_rules/compile.py +0 -0
@@ -6,6 +6,9 @@ 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
8
|
|
9
|
+
## [1.2.0] - 2025-09-24
|
10
|
+
- Add ability to display sub agent responses in the chat.
|
11
|
+
|
9
12
|
## [1.1.9] - 2025-09-24
|
10
13
|
- Fix bug in `LanguageModelFunction` to extend support mistral tool calling.
|
11
14
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: unique_toolkit
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.2.0
|
4
4
|
Summary:
|
5
5
|
License: Proprietary
|
6
6
|
Author: Cedric Klinkert
|
@@ -119,6 +119,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
119
119
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
120
120
|
|
121
121
|
|
122
|
+
## [1.2.0] - 2025-09-24
|
123
|
+
- Add ability to display sub agent responses in the chat.
|
124
|
+
|
122
125
|
## [1.1.9] - 2025-09-24
|
123
126
|
- Fix bug in `LanguageModelFunction` to extend support mistral tool calling.
|
124
127
|
|
@@ -16,10 +16,10 @@ class Postprocessor(ABC):
|
|
16
16
|
def get_name(self) -> str:
|
17
17
|
return self.name
|
18
18
|
|
19
|
-
async def run(self, loop_response: LanguageModelStreamResponse) ->
|
19
|
+
async def run(self, loop_response: LanguageModelStreamResponse) -> None:
|
20
20
|
raise NotImplementedError("Subclasses must implement this method.")
|
21
21
|
|
22
|
-
|
22
|
+
def apply_postprocessing_to_response(
|
23
23
|
self, loop_response: LanguageModelStreamResponse
|
24
24
|
) -> bool:
|
25
25
|
raise NotImplementedError(
|
@@ -102,6 +102,7 @@ class PostprocessorManager:
|
|
102
102
|
self._chat_service.modify_assistant_message(
|
103
103
|
content=loop_response.message.text,
|
104
104
|
message_id=loop_response.message.id,
|
105
|
+
references=loop_response.message.references,
|
105
106
|
)
|
106
107
|
|
107
108
|
async def execute_postprocessors(
|
@@ -1,3 +1,7 @@
|
|
1
|
+
from enum import StrEnum
|
2
|
+
|
3
|
+
from pydantic import BaseModel
|
4
|
+
|
1
5
|
from unique_toolkit.agentic.tools.config import get_configuration_dict
|
2
6
|
from unique_toolkit.agentic.tools.schemas import BaseToolConfig
|
3
7
|
|
@@ -6,22 +10,36 @@ This is the message that will be sent to the sub-agent.
|
|
6
10
|
""".strip()
|
7
11
|
|
8
12
|
|
13
|
+
class ResponseDisplayMode(StrEnum):
|
14
|
+
HIDDEN = "hidden"
|
15
|
+
DETAILS_OPEN = "details_open"
|
16
|
+
DETAILS_CLOSED = "details_closed"
|
17
|
+
|
18
|
+
|
19
|
+
class SubAgentToolDisplayConfig(BaseModel):
|
20
|
+
model_config = get_configuration_dict()
|
21
|
+
|
22
|
+
mode: ResponseDisplayMode = ResponseDisplayMode.HIDDEN
|
23
|
+
remove_from_history: bool = True
|
24
|
+
|
25
|
+
|
9
26
|
class SubAgentToolConfig(BaseToolConfig):
|
10
27
|
model_config = get_configuration_dict()
|
11
28
|
|
12
|
-
name: str = "default_name"
|
13
29
|
assistant_id: str = ""
|
14
30
|
chat_id: str | None = None
|
15
31
|
reuse_chat: bool = True
|
32
|
+
|
16
33
|
tool_description_for_system_prompt: str = ""
|
17
34
|
tool_description: str = ""
|
18
35
|
param_description_sub_agent_user_message: str = (
|
19
36
|
DEFAULT_PARAM_DESCRIPTION_SUB_AGENT_USER_MESSAGE
|
20
37
|
)
|
21
38
|
tool_format_information_for_system_prompt: str = ""
|
22
|
-
|
23
39
|
tool_description_for_user_prompt: str = ""
|
24
40
|
tool_format_information_for_user_prompt: str = ""
|
25
41
|
|
26
42
|
poll_interval: float = 1.0
|
27
43
|
max_wait: float = 120.0
|
44
|
+
|
45
|
+
response_display_config: SubAgentToolDisplayConfig = SubAgentToolDisplayConfig()
|
@@ -3,8 +3,6 @@ from logging import Logger
|
|
3
3
|
from unique_toolkit.agentic.tools.a2a.config import SubAgentToolConfig
|
4
4
|
from unique_toolkit.agentic.tools.a2a.service import SubAgentTool, ToolProgressReporter
|
5
5
|
from unique_toolkit.agentic.tools.config import ToolBuildConfig
|
6
|
-
from unique_toolkit.agentic.tools.schemas import BaseToolConfig
|
7
|
-
from unique_toolkit.agentic.tools.tool import Tool
|
8
6
|
from unique_toolkit.app.schemas import ChatEvent
|
9
7
|
|
10
8
|
|
@@ -19,7 +17,7 @@ class A2AManager:
|
|
19
17
|
|
20
18
|
def get_all_sub_agents(
|
21
19
|
self, tool_configs: list[ToolBuildConfig], event: ChatEvent
|
22
|
-
) -> tuple[list[ToolBuildConfig], list[
|
20
|
+
) -> tuple[list[ToolBuildConfig], list[SubAgentTool]]:
|
23
21
|
sub_agents = []
|
24
22
|
|
25
23
|
for tool_config in tool_configs:
|
@@ -32,13 +30,15 @@ class A2AManager:
|
|
32
30
|
)
|
33
31
|
continue
|
34
32
|
|
35
|
-
sub_agent_tool_config
|
33
|
+
sub_agent_tool_config = tool_config.configuration
|
36
34
|
|
37
35
|
sub_agents.append(
|
38
36
|
SubAgentTool(
|
39
37
|
configuration=sub_agent_tool_config,
|
40
38
|
event=event,
|
41
39
|
tool_progress_reporter=self._tool_progress_reporter,
|
40
|
+
name=tool_config.name,
|
41
|
+
display_name=tool_config.display_name,
|
42
42
|
)
|
43
43
|
)
|
44
44
|
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import re
|
2
|
+
from abc import ABC, abstractmethod
|
3
|
+
from typing import Literal, override
|
4
|
+
|
5
|
+
from unique_toolkit.agentic.tools.a2a.config import ResponseDisplayMode
|
6
|
+
|
7
|
+
|
8
|
+
class _ResponseDisplayHandler(ABC):
|
9
|
+
@abstractmethod
|
10
|
+
def build_response_display(
|
11
|
+
self, display_name: str, assistant_id: str, answer: str
|
12
|
+
) -> str:
|
13
|
+
raise NotImplementedError()
|
14
|
+
|
15
|
+
@abstractmethod
|
16
|
+
def remove_response_display(self, assistant_id: str, text: str) -> str:
|
17
|
+
raise NotImplementedError()
|
18
|
+
|
19
|
+
|
20
|
+
class _DetailsResponseDisplayHandler(_ResponseDisplayHandler):
|
21
|
+
def __init__(self, mode: Literal["open", "closed"]) -> None:
|
22
|
+
self._mode = mode
|
23
|
+
|
24
|
+
DETAILS_CLOSED_TEMPLATE = (
|
25
|
+
"<details><summary>{display_name}</summary>\n"
|
26
|
+
"\n"
|
27
|
+
'<div style="display: none;">{assistant_id}</div>\n'
|
28
|
+
"\n"
|
29
|
+
"{answer}\n"
|
30
|
+
"</details>\n"
|
31
|
+
"<br>\n"
|
32
|
+
"\n"
|
33
|
+
)
|
34
|
+
|
35
|
+
DETAILS_OPEN_TEMPLATE = (
|
36
|
+
"<details open><summary>{display_name}</summary>\n"
|
37
|
+
"\n"
|
38
|
+
'<div style="display: none;">{assistant_id}</div>\n'
|
39
|
+
"\n"
|
40
|
+
"{answer}\n"
|
41
|
+
"\n"
|
42
|
+
"</details>\n"
|
43
|
+
"<br>\n"
|
44
|
+
"\n"
|
45
|
+
)
|
46
|
+
|
47
|
+
def _get_detect_re(self, assistant_id: str) -> str:
|
48
|
+
if self._mode == "open":
|
49
|
+
return (
|
50
|
+
r"(?s)<details open>\s*"
|
51
|
+
r"<summary>(.*?)</summary>\s*"
|
52
|
+
rf"<div style=\"display: none;\">{re.escape(assistant_id)}</div>\s*"
|
53
|
+
r"(.*?)\s*"
|
54
|
+
r"</details>\s*"
|
55
|
+
r"<br>\s*"
|
56
|
+
)
|
57
|
+
else:
|
58
|
+
return (
|
59
|
+
r"(?s)<details>\s*"
|
60
|
+
r"<summary>(.*?)</summary>\s*"
|
61
|
+
rf"<div style=\"display: none;\">{re.escape(assistant_id)}</div>\s*"
|
62
|
+
r"(.*?)\s*"
|
63
|
+
r"</details>\s*"
|
64
|
+
r"<br>\s*"
|
65
|
+
)
|
66
|
+
|
67
|
+
def _get_template(self) -> str:
|
68
|
+
if self._mode == "open":
|
69
|
+
return self.DETAILS_OPEN_TEMPLATE
|
70
|
+
else:
|
71
|
+
return self.DETAILS_CLOSED_TEMPLATE
|
72
|
+
|
73
|
+
@override
|
74
|
+
def build_response_display(
|
75
|
+
self, display_name: str, assistant_id: str, answer: str
|
76
|
+
) -> str:
|
77
|
+
return self._get_template().format(
|
78
|
+
assistant_id=assistant_id, display_name=display_name, answer=answer
|
79
|
+
)
|
80
|
+
|
81
|
+
@override
|
82
|
+
def remove_response_display(self, assistant_id: str, text: str) -> str:
|
83
|
+
return re.sub(self._get_detect_re(assistant_id=assistant_id), "", text)
|
84
|
+
|
85
|
+
|
86
|
+
_DISPLAY_HANDLERS = {
|
87
|
+
ResponseDisplayMode.DETAILS_OPEN: _DetailsResponseDisplayHandler(mode="open"),
|
88
|
+
ResponseDisplayMode.DETAILS_CLOSED: _DetailsResponseDisplayHandler(mode="closed"),
|
89
|
+
}
|
90
|
+
|
91
|
+
|
92
|
+
def build_sub_agent_answer_display(
|
93
|
+
display_name: str, display_mode: ResponseDisplayMode, answer: str, assistant_id: str
|
94
|
+
) -> str:
|
95
|
+
if display_mode not in _DISPLAY_HANDLERS:
|
96
|
+
return ""
|
97
|
+
|
98
|
+
display_f = _DISPLAY_HANDLERS[display_mode]
|
99
|
+
|
100
|
+
return display_f.build_response_display(
|
101
|
+
display_name=display_name, answer=answer, assistant_id=assistant_id
|
102
|
+
)
|
103
|
+
|
104
|
+
|
105
|
+
def remove_sub_agent_answer_from_text(
|
106
|
+
display_mode: ResponseDisplayMode, text: str, assistant_id: str
|
107
|
+
) -> str:
|
108
|
+
if display_mode not in _DISPLAY_HANDLERS:
|
109
|
+
return text
|
110
|
+
|
111
|
+
display_f = _DISPLAY_HANDLERS[display_mode]
|
112
|
+
|
113
|
+
return display_f.remove_response_display(assistant_id=assistant_id, text=text)
|
@@ -0,0 +1,204 @@
|
|
1
|
+
import logging
|
2
|
+
import re
|
3
|
+
from typing import NotRequired, TypedDict, override
|
4
|
+
|
5
|
+
import unique_sdk
|
6
|
+
|
7
|
+
from unique_toolkit.agentic.postprocessor.postprocessor_manager import Postprocessor
|
8
|
+
from unique_toolkit.agentic.tools.a2a.config import (
|
9
|
+
ResponseDisplayMode,
|
10
|
+
SubAgentToolDisplayConfig,
|
11
|
+
)
|
12
|
+
from unique_toolkit.agentic.tools.a2a.postprocessing.display import (
|
13
|
+
build_sub_agent_answer_display,
|
14
|
+
remove_sub_agent_answer_from_text,
|
15
|
+
)
|
16
|
+
from unique_toolkit.agentic.tools.a2a.service import SubAgentTool
|
17
|
+
from unique_toolkit.content.schemas import ContentReference
|
18
|
+
from unique_toolkit.language_model.schemas import LanguageModelStreamResponse
|
19
|
+
|
20
|
+
logger = logging.getLogger(__name__)
|
21
|
+
|
22
|
+
SpaceMessage = unique_sdk.Space.Message
|
23
|
+
|
24
|
+
|
25
|
+
class _SubAgentMessageInfo(TypedDict):
|
26
|
+
text: str | None
|
27
|
+
references: list[unique_sdk.Space.Reference]
|
28
|
+
|
29
|
+
|
30
|
+
class _SubAgentToolInfo(TypedDict):
|
31
|
+
display_name: str
|
32
|
+
display_config: SubAgentToolDisplayConfig
|
33
|
+
response: NotRequired[_SubAgentMessageInfo]
|
34
|
+
|
35
|
+
|
36
|
+
class SubAgentResponsesPostprocessor(Postprocessor):
|
37
|
+
def __init__(
|
38
|
+
self,
|
39
|
+
user_id: str,
|
40
|
+
company_id: str,
|
41
|
+
agent_chat_id: str,
|
42
|
+
sub_agent_tools: list[SubAgentTool],
|
43
|
+
):
|
44
|
+
super().__init__(name=self.__class__.__name__)
|
45
|
+
|
46
|
+
self._user_id = user_id
|
47
|
+
self._company_id = company_id
|
48
|
+
|
49
|
+
self._agent_chat_id = agent_chat_id
|
50
|
+
|
51
|
+
self._assistant_id_to_tool_info: dict[str, _SubAgentToolInfo] = {}
|
52
|
+
|
53
|
+
for sub_agent_tool in sub_agent_tools:
|
54
|
+
sub_agent_tool.subscribe(self)
|
55
|
+
|
56
|
+
self._assistant_id_to_tool_info[sub_agent_tool.config.assistant_id] = (
|
57
|
+
_SubAgentToolInfo(
|
58
|
+
display_config=sub_agent_tool.config.response_display_config,
|
59
|
+
display_name=sub_agent_tool.display_name(),
|
60
|
+
)
|
61
|
+
)
|
62
|
+
|
63
|
+
self._sub_agent_message = None
|
64
|
+
|
65
|
+
@override
|
66
|
+
async def run(self, loop_response: LanguageModelStreamResponse) -> None:
|
67
|
+
self._sub_agent_message = await unique_sdk.Space.get_latest_message_async(
|
68
|
+
user_id=self._user_id,
|
69
|
+
company_id=self._company_id,
|
70
|
+
chat_id=self._agent_chat_id,
|
71
|
+
)
|
72
|
+
|
73
|
+
@override
|
74
|
+
def apply_postprocessing_to_response(
|
75
|
+
self, loop_response: LanguageModelStreamResponse
|
76
|
+
) -> bool:
|
77
|
+
logger.info("Adding sub agent responses to the response")
|
78
|
+
|
79
|
+
# Get responses to display
|
80
|
+
displayed = {}
|
81
|
+
for assistant_id, tool_info in self._assistant_id_to_tool_info.items():
|
82
|
+
display_mode = tool_info["display_config"].mode
|
83
|
+
|
84
|
+
if "response" not in tool_info:
|
85
|
+
logger.warning(
|
86
|
+
"No response from assistant %s",
|
87
|
+
assistant_id,
|
88
|
+
)
|
89
|
+
continue
|
90
|
+
|
91
|
+
if display_mode != ResponseDisplayMode.HIDDEN:
|
92
|
+
displayed[assistant_id] = tool_info["response"]
|
93
|
+
|
94
|
+
existing_refs = {
|
95
|
+
ref.source_id: ref.sequence_number
|
96
|
+
for ref in loop_response.message.references
|
97
|
+
}
|
98
|
+
_consolidate_references_in_place(displayed, existing_refs)
|
99
|
+
|
100
|
+
modified = len(displayed) > 0
|
101
|
+
for assistant_id, message in reversed(displayed.items()):
|
102
|
+
tool_info = self._assistant_id_to_tool_info[assistant_id]
|
103
|
+
display_mode = tool_info["display_config"].mode
|
104
|
+
display_name = tool_info["display_name"]
|
105
|
+
loop_response.message.text = (
|
106
|
+
build_sub_agent_answer_display(
|
107
|
+
display_name=display_name,
|
108
|
+
assistant_id=assistant_id,
|
109
|
+
display_mode=display_mode,
|
110
|
+
answer=message["text"],
|
111
|
+
)
|
112
|
+
+ loop_response.message.text
|
113
|
+
)
|
114
|
+
|
115
|
+
assert self._sub_agent_message is not None
|
116
|
+
|
117
|
+
loop_response.message.references.extend(
|
118
|
+
ContentReference(
|
119
|
+
message_id=self._sub_agent_message["id"],
|
120
|
+
source_id=ref["sourceId"],
|
121
|
+
url=ref["url"],
|
122
|
+
source=ref["source"],
|
123
|
+
name=ref["name"],
|
124
|
+
sequence_number=ref["sequenceNumber"],
|
125
|
+
)
|
126
|
+
for ref in message["references"]
|
127
|
+
)
|
128
|
+
|
129
|
+
return modified
|
130
|
+
|
131
|
+
@override
|
132
|
+
async def remove_from_text(self, text) -> str:
|
133
|
+
for assistant_id, tool_info in self._assistant_id_to_tool_info.items():
|
134
|
+
display_config = tool_info["display_config"]
|
135
|
+
if display_config.remove_from_history:
|
136
|
+
text = remove_sub_agent_answer_from_text(
|
137
|
+
display_mode=display_config.mode,
|
138
|
+
text=text,
|
139
|
+
assistant_id=assistant_id,
|
140
|
+
)
|
141
|
+
return text
|
142
|
+
|
143
|
+
def notify_sub_agent_response(
|
144
|
+
self, sub_agent_assistant_id: str, response: SpaceMessage
|
145
|
+
) -> None:
|
146
|
+
if sub_agent_assistant_id not in self._assistant_id_to_tool_info:
|
147
|
+
logger.warning(
|
148
|
+
"Unknown assistant id %s received, message will be ignored.",
|
149
|
+
sub_agent_assistant_id,
|
150
|
+
)
|
151
|
+
return
|
152
|
+
|
153
|
+
self._assistant_id_to_tool_info[sub_agent_assistant_id]["response"] = {
|
154
|
+
"text": response["text"],
|
155
|
+
"references": [
|
156
|
+
{
|
157
|
+
"name": ref["name"],
|
158
|
+
"url": ref["url"],
|
159
|
+
"sequenceNumber": ref["sequenceNumber"],
|
160
|
+
"originalIndex": [],
|
161
|
+
"sourceId": ref["sourceId"],
|
162
|
+
"source": ref["source"],
|
163
|
+
}
|
164
|
+
for ref in response["references"] or []
|
165
|
+
],
|
166
|
+
}
|
167
|
+
|
168
|
+
|
169
|
+
def _consolidate_references_in_place(
|
170
|
+
messages: dict[str, _SubAgentMessageInfo], existing_refs: dict[str, int]
|
171
|
+
) -> None:
|
172
|
+
start_index = max(existing_refs.values(), default=0) + 1
|
173
|
+
|
174
|
+
for assistant_id, message in messages.items():
|
175
|
+
references = message["references"]
|
176
|
+
if len(references) == 0 or message["text"] is None:
|
177
|
+
logger.info(
|
178
|
+
"Message from assistant %s does not contain any references",
|
179
|
+
assistant_id,
|
180
|
+
)
|
181
|
+
continue
|
182
|
+
|
183
|
+
references = list(sorted(references, key=lambda ref: ref["sequenceNumber"]))
|
184
|
+
|
185
|
+
message_new_refs = []
|
186
|
+
for reference in references:
|
187
|
+
source_id = reference["sourceId"]
|
188
|
+
|
189
|
+
if source_id not in existing_refs:
|
190
|
+
message_new_refs.append(reference)
|
191
|
+
existing_refs[source_id] = start_index
|
192
|
+
start_index += 1
|
193
|
+
|
194
|
+
reference_num = existing_refs[source_id]
|
195
|
+
|
196
|
+
seq_num = reference["sequenceNumber"]
|
197
|
+
message["text"] = re.sub(
|
198
|
+
rf"<sup>{seq_num}</sup>",
|
199
|
+
f"<sup>{reference_num}</sup>",
|
200
|
+
message["text"],
|
201
|
+
)
|
202
|
+
reference["sequenceNumber"] = reference_num
|
203
|
+
|
204
|
+
message["references"] = message_new_refs
|