unique_toolkit 2026.28.0.dev5__py3-none-any.whl → 2026.28.0.dev6__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/evaluation/hallucination/constants.py +12 -0
- unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +11 -0
- unique_toolkit/agentic/evaluation/tests/test_hallucination_external_context.py +122 -0
- unique_toolkit/agentic/reference_manager/reference_manager.py +16 -0
- unique_toolkit/agentic/reference_manager/tests/test_external_context.py +35 -0
- unique_toolkit/content/schemas.py +9 -1
- {unique_toolkit-2026.28.0.dev5.dist-info → unique_toolkit-2026.28.0.dev6.dist-info}/METADATA +2 -2
- {unique_toolkit-2026.28.0.dev5.dist-info → unique_toolkit-2026.28.0.dev6.dist-info}/RECORD +9 -7
- {unique_toolkit-2026.28.0.dev5.dist-info → unique_toolkit-2026.28.0.dev6.dist-info}/WHEEL +0 -0
|
@@ -52,6 +52,18 @@ class HallucinationConfig(EvaluationMetricConfig):
|
|
|
52
52
|
default={},
|
|
53
53
|
description="Additional options to pass to the language model.",
|
|
54
54
|
)
|
|
55
|
+
max_external_context_chars_per_source: SkipJsonSchema[int] = Field(
|
|
56
|
+
default=20_000,
|
|
57
|
+
ge=0,
|
|
58
|
+
description=(
|
|
59
|
+
"Per-source character cap applied to external (non-chunk) "
|
|
60
|
+
"context texts, e.g. MCP tool output. Raw/large tool results "
|
|
61
|
+
"inflate the judge prompt and the eval-LLM call; each external "
|
|
62
|
+
"text is truncated to this many characters before being added "
|
|
63
|
+
"to the context. 0 disables truncation. Does not affect "
|
|
64
|
+
"chunk-derived context."
|
|
65
|
+
),
|
|
66
|
+
)
|
|
55
67
|
score_to_label: dict[str, str] = {
|
|
56
68
|
"LOW": "GREEN",
|
|
57
69
|
"MEDIUM": "YELLOW",
|
|
@@ -54,6 +54,17 @@ class HallucinationEvaluation(Evaluation):
|
|
|
54
54
|
reference_pattern=self.config.reference_pattern,
|
|
55
55
|
)
|
|
56
56
|
|
|
57
|
+
# Append non-chunk groundedness context (e.g. MCP tool output). These
|
|
58
|
+
# are added in full ("all retrieved output as context") rather than via
|
|
59
|
+
# source-marker selection, since they carry no [sourceN] markers.
|
|
60
|
+
external_context_texts = self._reference_manager.get_external_context_texts()
|
|
61
|
+
max_chars = self.config.max_external_context_chars_per_source
|
|
62
|
+
if max_chars > 0:
|
|
63
|
+
external_context_texts = [
|
|
64
|
+
text[:max_chars] for text in external_context_texts
|
|
65
|
+
]
|
|
66
|
+
context_texts = context_texts + external_context_texts
|
|
67
|
+
|
|
57
68
|
evaluation_result: EvaluationMetricResult = await check_hallucination(
|
|
58
69
|
company_id=self._company_id,
|
|
59
70
|
user_id=self._user_id,
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Tests that HallucinationEvaluation grounds against non-chunk context.
|
|
2
|
+
|
|
3
|
+
UN-21951: external context texts (e.g. MCP tool output) registered on the
|
|
4
|
+
ReferenceManager must be appended to the evaluation context — in addition to
|
|
5
|
+
chunk-derived context, capped by ``max_external_context_chars_per_source`` —
|
|
6
|
+
without being converted to ContentChunks.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from types import SimpleNamespace
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
from unique_toolkit.agentic.evaluation.hallucination import (
|
|
14
|
+
hallucination_evaluation as he,
|
|
15
|
+
)
|
|
16
|
+
from unique_toolkit.agentic.evaluation.hallucination.constants import (
|
|
17
|
+
HallucinationConfig,
|
|
18
|
+
SourceSelectionMode,
|
|
19
|
+
)
|
|
20
|
+
from unique_toolkit.agentic.evaluation.schemas import (
|
|
21
|
+
EvaluationMetricName,
|
|
22
|
+
EvaluationMetricResult,
|
|
23
|
+
)
|
|
24
|
+
from unique_toolkit.agentic.reference_manager.reference_manager import (
|
|
25
|
+
ReferenceManager,
|
|
26
|
+
)
|
|
27
|
+
from unique_toolkit.chat.schemas import ChatMessageRole
|
|
28
|
+
from unique_toolkit.language_model.schemas import (
|
|
29
|
+
LanguageModelStreamResponse,
|
|
30
|
+
LanguageModelStreamResponseMessage,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _make_event() -> SimpleNamespace:
|
|
35
|
+
return SimpleNamespace(
|
|
36
|
+
company_id="company_1",
|
|
37
|
+
user_id="user_1",
|
|
38
|
+
payload=SimpleNamespace(
|
|
39
|
+
user_message=SimpleNamespace(text="what is ACME revenue?"),
|
|
40
|
+
),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _make_response(text: str = "ACME revenue is 1M.") -> LanguageModelStreamResponse:
|
|
45
|
+
return LanguageModelStreamResponse(
|
|
46
|
+
message=LanguageModelStreamResponseMessage(
|
|
47
|
+
id="msg_1",
|
|
48
|
+
previous_message_id=None,
|
|
49
|
+
role=ChatMessageRole.ASSISTANT,
|
|
50
|
+
text=text,
|
|
51
|
+
chat_id="chat_1",
|
|
52
|
+
original_text=text,
|
|
53
|
+
references=None,
|
|
54
|
+
),
|
|
55
|
+
tool_calls=None,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@pytest.fixture
|
|
60
|
+
def captured_context(monkeypatch: pytest.MonkeyPatch) -> dict:
|
|
61
|
+
"""Patch check_hallucination to capture the context_texts it receives."""
|
|
62
|
+
captured: dict = {}
|
|
63
|
+
|
|
64
|
+
async def _fake_check_hallucination(*, company_id, user_id, input, config):
|
|
65
|
+
captured["context_texts"] = list(input.context_texts or [])
|
|
66
|
+
return EvaluationMetricResult(
|
|
67
|
+
name=EvaluationMetricName.HALLUCINATION,
|
|
68
|
+
value="LOW",
|
|
69
|
+
reason="grounded",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
monkeypatch.setattr(he, "check_hallucination", _fake_check_hallucination)
|
|
73
|
+
return captured
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
async def test_external_context_is_appended(captured_context: dict) -> None:
|
|
77
|
+
manager = ReferenceManager()
|
|
78
|
+
manager.add_external_context_texts(["ACME revenue: 1M"])
|
|
79
|
+
evaluation = he.HallucinationEvaluation(
|
|
80
|
+
HallucinationConfig(source_selection_mode=SourceSelectionMode.FROM_IDS),
|
|
81
|
+
_make_event(), # type: ignore[arg-type]
|
|
82
|
+
manager,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
result = await evaluation.run(_make_response())
|
|
86
|
+
|
|
87
|
+
# No chunks → context comes solely from the external (MCP) source.
|
|
88
|
+
assert captured_context["context_texts"] == ["ACME revenue: 1M"]
|
|
89
|
+
assert result.value == "LOW"
|
|
90
|
+
assert result.is_positive is True
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
async def test_external_context_is_truncated(captured_context: dict) -> None:
|
|
94
|
+
manager = ReferenceManager()
|
|
95
|
+
manager.add_external_context_texts(["x" * 100])
|
|
96
|
+
evaluation = he.HallucinationEvaluation(
|
|
97
|
+
HallucinationConfig(
|
|
98
|
+
source_selection_mode=SourceSelectionMode.FROM_IDS,
|
|
99
|
+
max_external_context_chars_per_source=10,
|
|
100
|
+
),
|
|
101
|
+
_make_event(), # type: ignore[arg-type]
|
|
102
|
+
manager,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
await evaluation.run(_make_response())
|
|
106
|
+
|
|
107
|
+
assert captured_context["context_texts"] == ["x" * 10]
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
async def test_no_external_context_preserves_chunk_only_behaviour(
|
|
111
|
+
captured_context: dict,
|
|
112
|
+
) -> None:
|
|
113
|
+
manager = ReferenceManager() # no chunks, no external context
|
|
114
|
+
evaluation = he.HallucinationEvaluation(
|
|
115
|
+
HallucinationConfig(source_selection_mode=SourceSelectionMode.FROM_IDS),
|
|
116
|
+
_make_event(), # type: ignore[arg-type]
|
|
117
|
+
manager,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
await evaluation.run(_make_response())
|
|
121
|
+
|
|
122
|
+
assert captured_context["context_texts"] == []
|
|
@@ -32,6 +32,7 @@ class ReferenceManager:
|
|
|
32
32
|
self._tool_chunks: dict[str, tool_chunks] = {}
|
|
33
33
|
self._chunks: list[ContentChunk] = []
|
|
34
34
|
self._references: list[list[ContentReference]] = []
|
|
35
|
+
self._external_context_texts: list[str] = []
|
|
35
36
|
|
|
36
37
|
def extract_referenceable_chunks(
|
|
37
38
|
self, tool_responses: list[ToolCallResponse]
|
|
@@ -47,6 +48,21 @@ class ReferenceManager:
|
|
|
47
48
|
def get_chunks(self) -> list[ContentChunk]:
|
|
48
49
|
return self._chunks
|
|
49
50
|
|
|
51
|
+
def add_external_context_texts(self, texts: list[str]) -> None:
|
|
52
|
+
"""Register groundedness context that is not backed by ContentChunks.
|
|
53
|
+
|
|
54
|
+
Some retrieval sources (e.g. MCP tool output) provide text the answer
|
|
55
|
+
is built on but are deliberately *not* modelled as ContentChunks — they
|
|
56
|
+
are a different entity from ingested document chunks and must not flow
|
|
57
|
+
through the chunk/reference pipeline. They still need to ground the
|
|
58
|
+
hallucination check, so they are stored here and appended to the
|
|
59
|
+
evaluation context alongside the chunk-derived texts.
|
|
60
|
+
"""
|
|
61
|
+
self._external_context_texts.extend(text for text in texts if text)
|
|
62
|
+
|
|
63
|
+
def get_external_context_texts(self) -> list[str]:
|
|
64
|
+
return self._external_context_texts
|
|
65
|
+
|
|
50
66
|
def get_tool_chunks(self) -> dict[str, tool_chunks]:
|
|
51
67
|
return self._tool_chunks
|
|
52
68
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Tests for non-chunk groundedness context on the ReferenceManager.
|
|
2
|
+
|
|
3
|
+
External context texts (e.g. MCP tool output, UN-21951) ground the
|
|
4
|
+
hallucination check without being modelled as ContentChunks.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from unique_toolkit.agentic.reference_manager.reference_manager import (
|
|
8
|
+
ReferenceManager,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_external_context_starts_empty() -> None:
|
|
13
|
+
manager = ReferenceManager()
|
|
14
|
+
assert manager.get_external_context_texts() == []
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_add_external_context_texts_accumulates() -> None:
|
|
18
|
+
manager = ReferenceManager()
|
|
19
|
+
manager.add_external_context_texts(["a", "b"])
|
|
20
|
+
manager.add_external_context_texts(["c"])
|
|
21
|
+
assert manager.get_external_context_texts() == ["a", "b", "c"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_add_external_context_texts_drops_empty_strings() -> None:
|
|
25
|
+
manager = ReferenceManager()
|
|
26
|
+
manager.add_external_context_texts(["keep", "", "also"])
|
|
27
|
+
assert manager.get_external_context_texts() == ["keep", "also"]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_external_context_is_independent_of_chunks() -> None:
|
|
31
|
+
manager = ReferenceManager()
|
|
32
|
+
manager.add_external_context_texts(["mcp output"])
|
|
33
|
+
# External context must not leak into the chunk pipeline.
|
|
34
|
+
assert manager.get_chunks() == []
|
|
35
|
+
assert manager.get_external_context_texts() == ["mcp output"]
|
|
@@ -215,7 +215,15 @@ class ContentReference(BaseModel):
|
|
|
215
215
|
sequence_number: int
|
|
216
216
|
source: str
|
|
217
217
|
source_id: str
|
|
218
|
-
url: str
|
|
218
|
+
url: str | None = Field(
|
|
219
|
+
default=None,
|
|
220
|
+
description=(
|
|
221
|
+
"Link target for the reference. Optional: some sources (e.g. an "
|
|
222
|
+
"opaque MCP tool result with no resource link) have no URL and "
|
|
223
|
+
"render as a display-only, non-clickable citation. Nullable "
|
|
224
|
+
"end-to-end (node-chat persists it as a nullable column)."
|
|
225
|
+
),
|
|
226
|
+
)
|
|
219
227
|
original_index: list[int] = Field(
|
|
220
228
|
default=[],
|
|
221
229
|
description="List of indices in the ChatMessage original_text this reference refers to. This is usually the id in the functionCallResponse. List type due to implementation in node-chat",
|
{unique_toolkit-2026.28.0.dev5.dist-info → unique_toolkit-2026.28.0.dev6.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-toolkit
|
|
3
|
-
Version: 2026.28.0.
|
|
3
|
+
Version: 2026.28.0.dev6
|
|
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.28.0.
|
|
19
|
+
Requires-Dist: unique-sdk>=2026.28.0.dev8,<2026.28.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
|
|
@@ -93,8 +93,8 @@ unique_toolkit/agentic/evaluation/context_relevancy/schema.py,sha256=lZd0TPzH43i
|
|
|
93
93
|
unique_toolkit/agentic/evaluation/context_relevancy/service.py,sha256=i6WA_BwHyhHDfnvK59UC0z1FgZ8EPW5OJyYLbSxNRic,8760
|
|
94
94
|
unique_toolkit/agentic/evaluation/evaluation_manager.py,sha256=4HeKsDg6tLkJXNw3kzjmVLbD-86IRzKLQSuPwYtfYBk,7992
|
|
95
95
|
unique_toolkit/agentic/evaluation/exception.py,sha256=7lcVbCyoN4Md1chNJDFxpUYyWbVrcr9dcc3TxWykJTc,115
|
|
96
|
-
unique_toolkit/agentic/evaluation/hallucination/constants.py,sha256=
|
|
97
|
-
unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py,sha256=
|
|
96
|
+
unique_toolkit/agentic/evaluation/hallucination/constants.py,sha256=uEQR-CNKmeXizDaLOLHhwTZ0iYUmFwoKeMLHPm4M0sY,3208
|
|
97
|
+
unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py,sha256=HvaaRJ4D4pz_77IT2ZbL-OMfVSEOcmcalecOPnBsiRI,4548
|
|
98
98
|
unique_toolkit/agentic/evaluation/hallucination/prompts/__init__.py,sha256=4KFYMZsB3fJUKzoiUJE1npZ0gueWgvceB32EUrN-v7A,343
|
|
99
99
|
unique_toolkit/agentic/evaluation/hallucination/prompts/system_prompt.j2,sha256=sDUX6G645Ba40D_qKu4cUI8g-sJOfG8JpZreTNFgf7M,2616
|
|
100
100
|
unique_toolkit/agentic/evaluation/hallucination/prompts/user_prompt.j2,sha256=mD_qE9fOkyc1XXrebFt097ddx8bTlA6lbY04hKSQmWs,273
|
|
@@ -106,6 +106,7 @@ unique_toolkit/agentic/evaluation/tests/fixtures.py,sha256=Q-ughTfDiAdsMKbBVGzFi
|
|
|
106
106
|
unique_toolkit/agentic/evaluation/tests/test_config.py,sha256=p7xFQ7KE_yU8jGpqYA7ntAYe5Vln33wd6nwv3FM9XfI,8327
|
|
107
107
|
unique_toolkit/agentic/evaluation/tests/test_context_relevancy_service.py,sha256=NcSOyBJ_lqYehtlraZPo9RLutCitTP76kvkuyogSD2A,9477
|
|
108
108
|
unique_toolkit/agentic/evaluation/tests/test_hallucination_constants.py,sha256=A77nRcniI7hUf640f1sTvCAibQbJE30ikbz1RX4fltw,20478
|
|
109
|
+
unique_toolkit/agentic/evaluation/tests/test_hallucination_external_context.py,sha256=mIHxQDxW7oUbvOGH5bMcoV_yKr9BZvJlgE0JYicLdsM,3949
|
|
109
110
|
unique_toolkit/agentic/evaluation/tests/test_hallucination_utils.py,sha256=ogds7jUwwGJHdabhayhEY_1JbiaVv7Fxh58TMwgbqgw,37537
|
|
110
111
|
unique_toolkit/agentic/evaluation/tests/test_output_parser.py,sha256=KfltytmvqnPWLhmZpBXqcRmnlYorw_USwM5rkLVv8so,5179
|
|
111
112
|
unique_toolkit/agentic/evaluation/tests/test_prompt_loaders.py,sha256=zBREdlKf5tdDyB8XSaNgpQv3-tuZJoYteeJrp6WMWDM,11897
|
|
@@ -138,7 +139,8 @@ unique_toolkit/agentic/message_log_manager/__init__.py,sha256=3-KY_sGkPbNoSnrzwP
|
|
|
138
139
|
unique_toolkit/agentic/message_log_manager/service.py,sha256=yXeV_70ATUJrFi_KYRJ8PRmRbo27kQjY5cjazxDFkpI,9840
|
|
139
140
|
unique_toolkit/agentic/message_log_order.py,sha256=GaZOlAkFS2BpTc72af6Nit9inm6LskBYTze5Q7dd9cs,1041
|
|
140
141
|
unique_toolkit/agentic/postprocessor/postprocessor_manager.py,sha256=zOKnyzt1JwN7Godb4g3RQUOvwaR-Eg4ygm66gkmDM50,8125
|
|
141
|
-
unique_toolkit/agentic/reference_manager/reference_manager.py,sha256=
|
|
142
|
+
unique_toolkit/agentic/reference_manager/reference_manager.py,sha256=axqjSNFoR6oGVKg_fK1D2IsA9sxvreyPutRxK17dBxI,4844
|
|
143
|
+
unique_toolkit/agentic/reference_manager/tests/test_external_context.py,sha256=FlCr8rcvrJDkVbKW6pDylSTmP0v0luH_3TGBvXm4KZw,1246
|
|
142
144
|
unique_toolkit/agentic/responses_api/__init__.py,sha256=9WTO-ef7fGE9Y1QtZJFm8Q_jkwK8Srtl-HWvpAD2Wxs,668
|
|
143
145
|
unique_toolkit/agentic/responses_api/postprocessors/code_display.py,sha256=CboLgZ4Rncz_kxRwqoq2C93pZsdylHK4jU145YodEkM,936
|
|
144
146
|
unique_toolkit/agentic/responses_api/postprocessors/generated_files.py,sha256=yVwFT8ObMVJZpUufO1jEHofAdrXm5ndsqbSepuUkNPE,1064
|
|
@@ -254,7 +256,7 @@ unique_toolkit/chat/utils.py,sha256=CsD9IER2gA1IOV0fmUOl-N0LmKvA7JP9dGrOqeOY0Gg,
|
|
|
254
256
|
unique_toolkit/content/__init__.py,sha256=nnQDfnNTEvI8-3dgWvIojoFDYU7edwd8Kloi6lMDG0M,1586
|
|
255
257
|
unique_toolkit/content/constants.py,sha256=1iy4Y67xobl5VTnJB6SxSyuoBWbdLl9244xfVMUZi5o,60
|
|
256
258
|
unique_toolkit/content/functions.py,sha256=avnlEQ1FkVz2NTbXUkafU04jzygqOJtUMQL605rEL4c,34019
|
|
257
|
-
unique_toolkit/content/schemas.py,sha256=
|
|
259
|
+
unique_toolkit/content/schemas.py,sha256=00qbe-DlUjqlf-n3QVOotZjpsj0LZNnUoPmdwyMjVHY,10667
|
|
258
260
|
unique_toolkit/content/service.py,sha256=fR93_76aPczx2voxR7cvYDs_-pxD-Mc9WP6-5IqA8ko,28301
|
|
259
261
|
unique_toolkit/content/smart_rules.py,sha256=9GlHXm63POTi4jy5hW0qUjeqy-JSeL1wIbURM1GKhc4,11481
|
|
260
262
|
unique_toolkit/content/utils.py,sha256=keDkqu_ZzQY0y_g7g_XLOza3p4XsvfqVVDI9ylM91KY,10115
|
|
@@ -402,6 +404,6 @@ unique_toolkit/short_term_memory/service.py,sha256=Qo-c9yxzC1ZEEHJyIG_vnRs_ef0SK
|
|
|
402
404
|
unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
403
405
|
unique_toolkit/smart_rules/compile.py,sha256=vRe0aMJWuVIK-VsqomgxQImzke7MDmwgSxxJfYCa7zw,1386
|
|
404
406
|
unique_toolkit/test_utilities/events.py,sha256=FLrhMh0A_mQutAUjoD0FdMcVQ4Gq31r35OVGzRjvLro,6760
|
|
405
|
-
unique_toolkit-2026.28.0.
|
|
406
|
-
unique_toolkit-2026.28.0.
|
|
407
|
-
unique_toolkit-2026.28.0.
|
|
407
|
+
unique_toolkit-2026.28.0.dev6.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
408
|
+
unique_toolkit-2026.28.0.dev6.dist-info/METADATA,sha256=hoO0ZUgIV4theG_01eSZ0nk_8iU5vBqbxVk5St6xIW0,7426
|
|
409
|
+
unique_toolkit-2026.28.0.dev6.dist-info/RECORD,,
|
|
File without changes
|