unique_toolkit 2026.36.0.dev0__py3-none-any.whl → 2026.36.0.dev1__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.
- unique_toolkit/agentic/tools/mcp/tool_wrapper.py +51 -6
- {unique_toolkit-2026.36.0.dev0.dist-info → unique_toolkit-2026.36.0.dev1.dist-info}/METADATA +1 -1
- {unique_toolkit-2026.36.0.dev0.dist-info → unique_toolkit-2026.36.0.dev1.dist-info}/RECORD +4 -4
- {unique_toolkit-2026.36.0.dev0.dist-info → unique_toolkit-2026.36.0.dev1.dist-info}/WHEEL +0 -0
|
@@ -4,9 +4,10 @@ import json
|
|
|
4
4
|
import logging
|
|
5
5
|
import mimetypes
|
|
6
6
|
import uuid
|
|
7
|
-
from typing import Any
|
|
7
|
+
from typing import Any
|
|
8
8
|
|
|
9
9
|
import unique_sdk
|
|
10
|
+
from pydantic import ValidationError
|
|
10
11
|
|
|
11
12
|
from unique_toolkit.agentic.evaluation.schemas import EvaluationMetricName
|
|
12
13
|
from unique_toolkit.agentic.feature_flags import FeatureFlagNames
|
|
@@ -21,6 +22,7 @@ from unique_toolkit.app.schemas import ChatEvent, McpServer, McpTool
|
|
|
21
22
|
from unique_toolkit.chat.schemas import MessageLog, MessageLogStatus
|
|
22
23
|
from unique_toolkit.chat.service import ChatService
|
|
23
24
|
from unique_toolkit.content.functions import upload_content_from_bytes
|
|
25
|
+
from unique_toolkit.content.schemas import ContentChunk, ContentReference
|
|
24
26
|
from unique_toolkit.experimental.resources.feature_flags import is_flag_enabled
|
|
25
27
|
from unique_toolkit.language_model import LanguageModelService
|
|
26
28
|
from unique_toolkit.language_model.schemas import (
|
|
@@ -30,6 +32,8 @@ from unique_toolkit.language_model.schemas import (
|
|
|
30
32
|
|
|
31
33
|
logger = logging.getLogger(__name__)
|
|
32
34
|
|
|
35
|
+
REFERENCE_META_KEY = "unique.app/reference"
|
|
36
|
+
|
|
33
37
|
|
|
34
38
|
class MCPToolWrapper(Tool[MCPToolConfig]):
|
|
35
39
|
"""Wrapper class for MCP tools that implements the Tool interface"""
|
|
@@ -72,7 +76,7 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
|
|
|
72
76
|
parameters=self._mcp_tool.input_schema,
|
|
73
77
|
)
|
|
74
78
|
|
|
75
|
-
def _json_schema_to_python_type(self, schema:
|
|
79
|
+
def _json_schema_to_python_type(self, schema: dict[str, Any]) -> type:
|
|
76
80
|
"""Convert JSON schema type to Python type"""
|
|
77
81
|
json_type = schema.get("type", "string")
|
|
78
82
|
|
|
@@ -152,9 +156,14 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
|
|
|
152
156
|
# Use SDK to call the public API
|
|
153
157
|
result = await self._call_mcp_tool_via_sdk(arguments)
|
|
154
158
|
|
|
159
|
+
content_chunks, references = self._extract_structured_references(result)
|
|
155
160
|
content_str, image_data_urls = await asyncio.to_thread(
|
|
156
161
|
self._process_mcp_result, result
|
|
157
162
|
)
|
|
163
|
+
if content_chunks:
|
|
164
|
+
# Structured references already carry the text; keep any
|
|
165
|
+
# extracted images but drop the redundant flat text.
|
|
166
|
+
content_str = ""
|
|
158
167
|
|
|
159
168
|
# TODO: Why result here not applied directly to the body of the tool_response? like so how does it know the results in the history?
|
|
160
169
|
tool_response = ToolCallResponse(
|
|
@@ -167,6 +176,7 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
|
|
|
167
176
|
},
|
|
168
177
|
error_message="",
|
|
169
178
|
content=content_str,
|
|
179
|
+
content_chunks=content_chunks or None,
|
|
170
180
|
image_data_urls=image_data_urls,
|
|
171
181
|
)
|
|
172
182
|
|
|
@@ -187,6 +197,7 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
|
|
|
187
197
|
progress_message="_Completed MCP tool_",
|
|
188
198
|
status=MessageLogStatus.COMPLETED,
|
|
189
199
|
active_message_log=active_message_log,
|
|
200
|
+
references=references,
|
|
190
201
|
)
|
|
191
202
|
|
|
192
203
|
return tool_response
|
|
@@ -230,17 +241,19 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
|
|
|
230
241
|
progress_message: str | None = None,
|
|
231
242
|
status: MessageLogStatus = MessageLogStatus.RUNNING,
|
|
232
243
|
active_message_log: MessageLog | None = None,
|
|
244
|
+
references: list[ContentReference] | None = None,
|
|
233
245
|
) -> MessageLog | None:
|
|
234
246
|
return self._message_step_logger.create_or_update_message_log(
|
|
235
247
|
active_message_log=active_message_log,
|
|
236
248
|
header=self.display_name(),
|
|
237
249
|
progress_message=progress_message,
|
|
238
250
|
status=status,
|
|
251
|
+
references=references or [],
|
|
239
252
|
)
|
|
240
253
|
|
|
241
254
|
def _extract_and_validate_arguments(
|
|
242
255
|
self, tool_call: LanguageModelFunction
|
|
243
|
-
) ->
|
|
256
|
+
) -> dict[str, Any]:
|
|
244
257
|
"""
|
|
245
258
|
Extract and validate arguments from tool call, handling various formats robustly.
|
|
246
259
|
|
|
@@ -287,7 +300,39 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
|
|
|
287
300
|
f"Unexpected arguments type for MCP tool {self.name}: {type(raw_arguments)}"
|
|
288
301
|
)
|
|
289
302
|
|
|
290
|
-
def
|
|
303
|
+
def _extract_structured_references(
|
|
304
|
+
self, result: dict[str, Any]
|
|
305
|
+
) -> tuple[list[ContentChunk], list[ContentReference]]:
|
|
306
|
+
"""Opt-in: content items with valid ``unique.app/reference`` + chunk ``_meta``."""
|
|
307
|
+
chunks: list[ContentChunk] = []
|
|
308
|
+
references: list[ContentReference] = []
|
|
309
|
+
content_items = self._extract_content_items(result)
|
|
310
|
+
for item in content_items:
|
|
311
|
+
if not isinstance(item, dict) or item.get("type") != "text":
|
|
312
|
+
continue
|
|
313
|
+
meta = item.get("_meta")
|
|
314
|
+
if not isinstance(meta, dict):
|
|
315
|
+
continue
|
|
316
|
+
ref_payload = meta.get(REFERENCE_META_KEY)
|
|
317
|
+
if not isinstance(ref_payload, dict):
|
|
318
|
+
continue
|
|
319
|
+
try:
|
|
320
|
+
reference = ContentReference.model_validate(ref_payload)
|
|
321
|
+
chunk = ContentChunk.model_validate(
|
|
322
|
+
{k: v for k, v in meta.items() if k != REFERENCE_META_KEY}
|
|
323
|
+
)
|
|
324
|
+
except ValidationError:
|
|
325
|
+
self.logger.warning(
|
|
326
|
+
"MCP tool %s: ignoring invalid %s metadata",
|
|
327
|
+
self.name,
|
|
328
|
+
REFERENCE_META_KEY,
|
|
329
|
+
)
|
|
330
|
+
continue
|
|
331
|
+
references.append(reference)
|
|
332
|
+
chunks.append(chunk)
|
|
333
|
+
return chunks, references
|
|
334
|
+
|
|
335
|
+
def _process_mcp_result(self, result: dict[str, Any]) -> tuple[str, list[str]]:
|
|
291
336
|
"""Parse MCP result content array, upload images, return content string and data URLs."""
|
|
292
337
|
content_items = self._extract_content_items(result)
|
|
293
338
|
if not content_items:
|
|
@@ -327,7 +372,7 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
|
|
|
327
372
|
content_str = json.dumps(result)
|
|
328
373
|
return content_str, image_data_urls
|
|
329
374
|
|
|
330
|
-
def _extract_content_items(self, result:
|
|
375
|
+
def _extract_content_items(self, result: dict[str, Any]) -> list[Any]:
|
|
331
376
|
"""Extract content array from MCP result (handles various response shapes)."""
|
|
332
377
|
if "content" in result and isinstance(result["content"], list):
|
|
333
378
|
return result["content"]
|
|
@@ -378,7 +423,7 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
|
|
|
378
423
|
|
|
379
424
|
return data_url, content_id
|
|
380
425
|
|
|
381
|
-
async def _call_mcp_tool_via_sdk(self, arguments:
|
|
426
|
+
async def _call_mcp_tool_via_sdk(self, arguments: dict[str, Any]) -> dict[str, Any]:
|
|
382
427
|
"""Call MCP tool via SDK to public API"""
|
|
383
428
|
try:
|
|
384
429
|
self.logger.info(
|
{unique_toolkit-2026.36.0.dev0.dist-info → unique_toolkit-2026.36.0.dev1.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-toolkit
|
|
3
|
-
Version: 2026.36.0.
|
|
3
|
+
Version: 2026.36.0.dev1
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Cedric Klinkert, Martin Fadler, Sadique Sheik, Fabian Schläpfer, Pascal Hauri, Ejiroghene Oki-Peter, Rami Azouz, Ricardo Visini, Sanzio Monti
|
|
6
6
|
Author-email: Cedric Klinkert <cedric.klinkert@unique.ch>, Martin Fadler <martin.fadler@unique.ch>, Sadique Sheik <sadique@unique.ch>, Fabian Schläpfer <fabian@unique.ch>, Pascal Hauri <pascal@unique.ch>, Ejiroghene Oki-Peter <oki-peter.ejiroghene@unique.ai>, Rami Azouz <rami.ext@unique.ch>, Ricardo Visini <ricardo.visini@unique.ch>, Sanzio Monti <sanzio.monti@unique.ai>
|
|
@@ -201,7 +201,7 @@ unique_toolkit/agentic/tools/factory.py,sha256=YK9uh2EqotQFb9stsXs-A8lsNaxklTCd_
|
|
|
201
201
|
unique_toolkit/agentic/tools/mcp/__init__.py,sha256=RLF_p-LDRC7GhiB3fdCi4u3bh6V9PY_w26fg61BLyco,122
|
|
202
202
|
unique_toolkit/agentic/tools/mcp/manager.py,sha256=EfWbfNhB8Lnx2EqBgUXhK7klFLaBv2eezvYq8J0TXyo,3808
|
|
203
203
|
unique_toolkit/agentic/tools/mcp/models.py,sha256=DaBVzwJ4dqtgzm8Mv0-NOGBU04zyVe-RgWntBhkpmnE,742
|
|
204
|
-
unique_toolkit/agentic/tools/mcp/tool_wrapper.py,sha256
|
|
204
|
+
unique_toolkit/agentic/tools/mcp/tool_wrapper.py,sha256=-WZaPjhbxozrPWgwZDD48hfYIp7s1cGAKU3IXqLXFVA,17575
|
|
205
205
|
unique_toolkit/agentic/tools/names.py,sha256=MDF0ONLrxeC-iz--EtyrHAox_RN6zasxo5MSbXQYGyw,412
|
|
206
206
|
unique_toolkit/agentic/tools/openai_builtin/__init__.py,sha256=Q6d9mhsLRVF3erT2yMxLld62D3FTZ8nbovI4vLv4Nso,701
|
|
207
207
|
unique_toolkit/agentic/tools/openai_builtin/base.py,sha256=QWF-GL_fkJqzGPpxvtg69-TB_IjsrxokeJVQESzH-18,1415
|
|
@@ -420,6 +420,6 @@ unique_toolkit/short_term_memory/service.py,sha256=2JMBEBn6GoyK-a0xvdcWpPft-3C74
|
|
|
420
420
|
unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
421
421
|
unique_toolkit/smart_rules/compile.py,sha256=vRe0aMJWuVIK-VsqomgxQImzke7MDmwgSxxJfYCa7zw,1386
|
|
422
422
|
unique_toolkit/test_utilities/events.py,sha256=FLrhMh0A_mQutAUjoD0FdMcVQ4Gq31r35OVGzRjvLro,6760
|
|
423
|
-
unique_toolkit-2026.36.0.
|
|
424
|
-
unique_toolkit-2026.36.0.
|
|
425
|
-
unique_toolkit-2026.36.0.
|
|
423
|
+
unique_toolkit-2026.36.0.dev1.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
424
|
+
unique_toolkit-2026.36.0.dev1.dist-info/METADATA,sha256=TRfcAs3vlbrpma_tG96J6ZZq6eAu9L9NWGIrq2Y2eVY,7821
|
|
425
|
+
unique_toolkit-2026.36.0.dev1.dist-info/RECORD,,
|
|
File without changes
|