unique_toolkit 2026.30.0.dev3__py3-none-any.whl → 2026.30.0.dev5__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/config.py +36 -0
- unique_toolkit/agentic/tools/mcp/tool_wrapper.py +8 -7
- unique_toolkit/app/__init__.py +3 -0
- unique_toolkit/app/schemas.py +43 -0
- {unique_toolkit-2026.30.0.dev3.dist-info → unique_toolkit-2026.30.0.dev5.dist-info}/METADATA +2 -2
- {unique_toolkit-2026.30.0.dev3.dist-info → unique_toolkit-2026.30.0.dev5.dist-info}/RECORD +7 -7
- {unique_toolkit-2026.30.0.dev3.dist-info → unique_toolkit-2026.30.0.dev5.dist-info}/WHEEL +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from collections.abc import Sequence
|
|
2
3
|
from enum import StrEnum
|
|
3
4
|
from typing import Annotated, Any, Generic
|
|
4
5
|
|
|
@@ -98,6 +99,16 @@ class ToolBuildConfig(BaseModel, Generic[T]):
|
|
|
98
99
|
|
|
99
100
|
is_enabled: bool = Field(default=True)
|
|
100
101
|
|
|
102
|
+
config_error: str | None = Field(
|
|
103
|
+
default=None,
|
|
104
|
+
exclude=True,
|
|
105
|
+
description=(
|
|
106
|
+
"Set when this tool's stored configuration failed to resolve and was "
|
|
107
|
+
"demoted to a disabled BaseToolConfig fallback. None for tools that are "
|
|
108
|
+
"valid, including tools that are deliberately disabled."
|
|
109
|
+
),
|
|
110
|
+
)
|
|
111
|
+
|
|
101
112
|
@model_validator(mode="before")
|
|
102
113
|
def initialize_config_based_on_tool_name(
|
|
103
114
|
cls,
|
|
@@ -115,6 +126,16 @@ class ToolBuildConfig(BaseModel, Generic[T]):
|
|
|
115
126
|
if not isinstance(value, dict):
|
|
116
127
|
return value
|
|
117
128
|
|
|
129
|
+
# config_error must only ever be set by this validator's own demotion
|
|
130
|
+
# path below. Since this is a plain field on a model with
|
|
131
|
+
# populate_by_name + a camelCase alias generator, an externally
|
|
132
|
+
# supplied config_error/configError (e.g. a stray key on a stored
|
|
133
|
+
# payload) would otherwise pass straight through untouched on every
|
|
134
|
+
# non-demotion return path and make a perfectly healthy tool look
|
|
135
|
+
# misconfigured to collect_tool_configuration_errors.
|
|
136
|
+
value.pop("config_error", None)
|
|
137
|
+
value.pop("configError", None)
|
|
138
|
+
|
|
118
139
|
is_mcp_tool = _is_mcp_tool_payload(value)
|
|
119
140
|
mcp_configuration = value.get("configuration", {})
|
|
120
141
|
|
|
@@ -168,8 +189,23 @@ class ToolBuildConfig(BaseModel, Generic[T]):
|
|
|
168
189
|
)
|
|
169
190
|
value["is_enabled"] = False
|
|
170
191
|
value["isEnabled"] = False
|
|
192
|
+
value["config_error"] = f"Tool '{tool_name}' has invalid configuration."
|
|
171
193
|
_ensure_base_tool_config(value)
|
|
172
194
|
return value
|
|
173
195
|
|
|
174
196
|
value["configuration"] = config
|
|
175
197
|
return value
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def collect_tool_configuration_errors(
|
|
201
|
+
tools: Sequence["ToolBuildConfig[Any]"],
|
|
202
|
+
) -> list[str]:
|
|
203
|
+
"""Return the config_error message for every tool demoted due to an invalid config.
|
|
204
|
+
|
|
205
|
+
`initialize_config_based_on_tool_name` never raises: a tool whose stored
|
|
206
|
+
configuration is invalid is silently disabled with a BaseToolConfig fallback so
|
|
207
|
+
that one broken tool cannot take down the whole space. Callers that need to
|
|
208
|
+
surface these failures instead of ignoring them (e.g. to fail a chat request the
|
|
209
|
+
way an invalid configuration used to) can use this helper to recover the list.
|
|
210
|
+
"""
|
|
211
|
+
return [tool.config_error for tool in tools if tool.config_error]
|
|
@@ -89,13 +89,14 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
|
|
|
89
89
|
def tool_description_for_system_prompt(self) -> str:
|
|
90
90
|
"""Return tool description for system prompt"""
|
|
91
91
|
# Not using jinja here to keep it simple and not import new packages.
|
|
92
|
-
|
|
93
|
-
f"**MCP Server**: {self._mcp_server.name}
|
|
94
|
-
f"**Tool Name**: {self.name}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
92
|
+
lines = [
|
|
93
|
+
f"**MCP Server**: {self._mcp_server.name}",
|
|
94
|
+
f"**Tool Name**: {self.name}",
|
|
95
|
+
]
|
|
96
|
+
if self._mcp_tool.system_prompt:
|
|
97
|
+
lines.append(self._mcp_tool.system_prompt)
|
|
98
|
+
|
|
99
|
+
return "\n".join(lines)
|
|
99
100
|
|
|
100
101
|
def tool_description_for_user_prompt(self) -> str:
|
|
101
102
|
return self._mcp_tool.user_prompt or ""
|
unique_toolkit/app/__init__.py
CHANGED
unique_toolkit/app/schemas.py
CHANGED
|
@@ -89,6 +89,45 @@ class BaseEvent(BaseModel, Generic[FilterOptionsT]):
|
|
|
89
89
|
###
|
|
90
90
|
|
|
91
91
|
|
|
92
|
+
class McpReferenceMapping(BaseModel):
|
|
93
|
+
"""Optional per-tool rule for destructuring a list-returning MCP result into
|
|
94
|
+
individual citation references. A Unique-specific override; when unset the
|
|
95
|
+
generic citation heuristic is used. Paths are dotted (dict keys and numeric
|
|
96
|
+
list indices), e.g. ``"issues"`` or ``"fields.summary"``.
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
model_config = model_config
|
|
100
|
+
|
|
101
|
+
list_path: Optional[str] = Field(
|
|
102
|
+
default=None,
|
|
103
|
+
description="Dotted path to the array of records, e.g. 'issues' or 'result.items'.",
|
|
104
|
+
)
|
|
105
|
+
title_path: Optional[str] = Field(
|
|
106
|
+
default=None,
|
|
107
|
+
description="Dotted path to each record's title, e.g. 'key' or 'fields.summary'.",
|
|
108
|
+
)
|
|
109
|
+
title_template: Optional[str] = Field(
|
|
110
|
+
default=None,
|
|
111
|
+
description="Optional title template with {dotted.path} tokens, e.g. '{key} — {fields.summary}'. Takes precedence over title_path.",
|
|
112
|
+
)
|
|
113
|
+
details_path: Optional[str] = Field(
|
|
114
|
+
default=None,
|
|
115
|
+
description="Optional dotted path to a details line for each record.",
|
|
116
|
+
)
|
|
117
|
+
title_from_text: Optional[bool] = Field(
|
|
118
|
+
default=None,
|
|
119
|
+
description="Title from the leading text line instead of a field/template: for a single plain-text document (e.g. a fetched Markdown doc) or each plain-text item of a list.",
|
|
120
|
+
)
|
|
121
|
+
title_text_path: Optional[str] = Field(
|
|
122
|
+
default=None,
|
|
123
|
+
description="When titling a list of objects from text, the dotted path to the text field within each item (e.g. 'content'); leave unset when each list item is itself a plain string.",
|
|
124
|
+
)
|
|
125
|
+
title_max_chars: Optional[int] = Field(
|
|
126
|
+
default=None,
|
|
127
|
+
description="Max length of the title derived via title_from_text (default 120).",
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
|
|
92
131
|
class McpTool(BaseModel):
|
|
93
132
|
model_config = model_config
|
|
94
133
|
|
|
@@ -117,6 +156,10 @@ class McpTool(BaseModel):
|
|
|
117
156
|
default=None,
|
|
118
157
|
description="An optional tool format information. This is a Unique specific field.",
|
|
119
158
|
)
|
|
159
|
+
reference_mapping: Optional[McpReferenceMapping] = Field(
|
|
160
|
+
default=None,
|
|
161
|
+
description="Optional rule for destructuring a list-returning result into individual citation references. This is a Unique specific field.",
|
|
162
|
+
)
|
|
120
163
|
is_connected: bool = Field(
|
|
121
164
|
description="Whether the tool is connected to the MCP server. This is a Unique specific field.",
|
|
122
165
|
)
|
{unique_toolkit-2026.30.0.dev3.dist-info → unique_toolkit-2026.30.0.dev5.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-toolkit
|
|
3
|
-
Version: 2026.30.0.
|
|
3
|
+
Version: 2026.30.0.dev5
|
|
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>
|
|
@@ -16,7 +16,7 @@ Requires-Dist: sseclient>=0.0.27,<0.0.28
|
|
|
16
16
|
Requires-Dist: openai>=1.105.0,<3
|
|
17
17
|
Requires-Dist: platformdirs>=4.0.0,<5
|
|
18
18
|
Requires-Dist: pillow>=12.1.1
|
|
19
|
-
Requires-Dist: unique-sdk>=2026.30.0.
|
|
19
|
+
Requires-Dist: unique-sdk>=2026.30.0.dev1,<2026.30.0rc0
|
|
20
20
|
Requires-Dist: jambo>=0.1.2,<0.2
|
|
21
21
|
Requires-Dist: jinja2>=3.1.6,<4
|
|
22
22
|
Requires-Dist: docxtpl>=0.20.1,<0.21
|
|
@@ -176,7 +176,7 @@ unique_toolkit/agentic/tools/a2a/tool/config.py,sha256=v4rZQU42RjUTC5Md-Cye1rUIW
|
|
|
176
176
|
unique_toolkit/agentic/tools/a2a/tool/service.py,sha256=5jOtXSU9oggG1dVUd7PAb3hd_-MLyGnSR5_lUQvYPfA,22160
|
|
177
177
|
unique_toolkit/agentic/tools/a2a/tool/test/test_service_utils.py,sha256=x4leRxnGgqD-XyXPkW2z1ekv4Ja7EStXd-24LGadPZA,24858
|
|
178
178
|
unique_toolkit/agentic/tools/agent_chunks_hanlder.py,sha256=eO0g46wZOQlmWqYYVGiszRVe8K2LX-9qW30ZCdGg5eE,1943
|
|
179
|
-
unique_toolkit/agentic/tools/config.py,sha256=
|
|
179
|
+
unique_toolkit/agentic/tools/config.py,sha256=AOtBn2tL1rIoPPzl1csAHLD5aetYqPL-jAqkIoSBxyE,7468
|
|
180
180
|
unique_toolkit/agentic/tools/experimental/__init__.py,sha256=ArEcXHGPtMRNsDnsyo9v1fev0EZWdJ6D7NWdPEFLQKM,956
|
|
181
181
|
unique_toolkit/agentic/tools/experimental/ask_user_tool/__init__.py,sha256=B8srRVw4vMLa4dZE5yoF1Bqpjlv8moh_m-dP2BVRjDc,375
|
|
182
182
|
unique_toolkit/agentic/tools/experimental/ask_user_tool/config.py,sha256=z95ZaxkMvsmjVaUYWWZrvpD21-Us1KNUrMgXzpF4uo4,5923
|
|
@@ -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=6rrJ83dSzyiteOPXl5ZTca8hSPkH8aOGNjI41IcRp78,15544
|
|
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=Ob5n1S6HduFbI5RsjIklasRjoKsgCwh840KAb6p2IaI,1858
|
|
@@ -230,7 +230,7 @@ unique_toolkit/agentic_table/__init__.py,sha256=bTMTBUomZysXhMtP9Rnzk6hVa2lZ7Xmr
|
|
|
230
230
|
unique_toolkit/agentic_table/schemas.py,sha256=IhVVSWZyDVIeyVoiP-FWp26MWwXv8oL4KFPTzeQquCc,12568
|
|
231
231
|
unique_toolkit/agentic_table/service.py,sha256=26hblR33Vp8FWWMgtaQCJ0IQT8hmGzGCQy86BDi2wOo,19670
|
|
232
232
|
unique_toolkit/agentic_table/synthetic_chat_event.py,sha256=MylvYuhx5CVt2DbPetzV0sR8GlkL218DmNFi7A6RYVs,2373
|
|
233
|
-
unique_toolkit/app/__init__.py,sha256=
|
|
233
|
+
unique_toolkit/app/__init__.py,sha256=qear5ErW3smLDATxtnUsgkX3f177zsn65ixVW8T0JVE,1641
|
|
234
234
|
unique_toolkit/app/chat_event_filter_options_settings.py,sha256=W0Ydio1UeED5_xqaTzbcGzK2tH4EpA1WHUzdF-iWpqI,364
|
|
235
235
|
unique_toolkit/app/dev_util.py,sha256=cHDuC6jtaptdVISbtMmOCqRTTWBPeCoIUQvUQvcmVyY,5517
|
|
236
236
|
unique_toolkit/app/fast_api_factory.py,sha256=ffoi6h_PD2_DaAuKZNd_DNS53RA0VXJKzGhsDta5SvM,5801
|
|
@@ -240,7 +240,7 @@ unique_toolkit/app/init_logging.py,sha256=Lv0FuEiUmxvtV2yovjD0gWNIvLdsi2xdMFeEiN
|
|
|
240
240
|
unique_toolkit/app/init_sdk.py,sha256=5_oDoETr6akwYyBCb0ivTdMNu3SVgPSkrXcDS6ELyY8,2269
|
|
241
241
|
unique_toolkit/app/performance/async_tasks.py,sha256=8Xv5kEmmFDJO7YyyBxv4e7bcNgq-3z_E2_4z1Yn9EqU,1970
|
|
242
242
|
unique_toolkit/app/performance/async_wrapper.py,sha256=yVVcRDkcdyfjsxro-N29SBvi-7773wnfDplef6-y8xw,1077
|
|
243
|
-
unique_toolkit/app/schemas.py,sha256=
|
|
243
|
+
unique_toolkit/app/schemas.py,sha256=_jHuLDZO9YSP0xf-1AxNVorWYg2NgWfNZ9yXpGt2DHE,18518
|
|
244
244
|
unique_toolkit/app/unique_settings.py,sha256=-bYvxwCw_DvhSViHXgc-pYoNboxhHB8VG2L9YNPiDHU,26861
|
|
245
245
|
unique_toolkit/app/verification.py,sha256=GxFFwcJMy25fCA_Xe89wKW7bgqOu8PAs5y8QpHF0GSc,3861
|
|
246
246
|
unique_toolkit/app/webhook.py,sha256=evpxLDnvz7P3D7-TV1XBkl8WcoldXpjOkw3tvFRxHr0,2368
|
|
@@ -406,6 +406,6 @@ unique_toolkit/short_term_memory/service.py,sha256=2JMBEBn6GoyK-a0xvdcWpPft-3C74
|
|
|
406
406
|
unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
407
407
|
unique_toolkit/smart_rules/compile.py,sha256=vRe0aMJWuVIK-VsqomgxQImzke7MDmwgSxxJfYCa7zw,1386
|
|
408
408
|
unique_toolkit/test_utilities/events.py,sha256=FLrhMh0A_mQutAUjoD0FdMcVQ4Gq31r35OVGzRjvLro,6760
|
|
409
|
-
unique_toolkit-2026.30.0.
|
|
410
|
-
unique_toolkit-2026.30.0.
|
|
411
|
-
unique_toolkit-2026.30.0.
|
|
409
|
+
unique_toolkit-2026.30.0.dev5.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
410
|
+
unique_toolkit-2026.30.0.dev5.dist-info/METADATA,sha256=4UB6dPpbvtoQdDASGwf3Ld_iqYFiLTy98BnyqmU3wOg,7426
|
|
411
|
+
unique_toolkit-2026.30.0.dev5.dist-info/RECORD,,
|
|
File without changes
|