unique_toolkit 2026.46.0.dev2__py3-none-any.whl → 2026.46.0.dev4__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/_common/experimental/write_up_agent/services/generation_handler/service.py +3 -4
- unique_toolkit/_common/experimental/write_up_agent/services/template_handler/service.py +3 -2
- unique_toolkit/_common/utils/jinja/render.py +2 -3
- unique_toolkit/_common/utils/jinja/sandbox.py +18 -0
- unique_toolkit/_common/utils/jinja/schema.py +2 -2
- unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +4 -2
- unique_toolkit/language_model/model_costs.py +31 -4
- {unique_toolkit-2026.46.0.dev2.dist-info → unique_toolkit-2026.46.0.dev4.dist-info}/METADATA +1 -1
- {unique_toolkit-2026.46.0.dev2.dist-info → unique_toolkit-2026.46.0.dev4.dist-info}/RECORD +10 -9
- {unique_toolkit-2026.46.0.dev2.dist-info → unique_toolkit-2026.46.0.dev4.dist-info}/WHEEL +0 -0
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
import logging
|
|
4
4
|
from typing import Any, Callable
|
|
5
5
|
|
|
6
|
-
from jinja2 import Template
|
|
7
|
-
|
|
8
6
|
from unique_toolkit._common.experimental.write_up_agent.schemas import (
|
|
9
7
|
GroupData,
|
|
10
8
|
ProcessedGroup,
|
|
@@ -21,6 +19,7 @@ from unique_toolkit._common.experimental.write_up_agent.services.generation_hand
|
|
|
21
19
|
PromptBuildError,
|
|
22
20
|
TokenLimitError,
|
|
23
21
|
)
|
|
22
|
+
from unique_toolkit._common.utils.jinja.sandbox import sandboxed_template
|
|
24
23
|
from unique_toolkit.language_model import LanguageModelService
|
|
25
24
|
from unique_toolkit.language_model.builder import MessagesBuilder
|
|
26
25
|
|
|
@@ -285,14 +284,14 @@ class GenerationHandler:
|
|
|
285
284
|
"""
|
|
286
285
|
try:
|
|
287
286
|
# Build system prompt
|
|
288
|
-
system_prompt =
|
|
287
|
+
system_prompt = sandboxed_template(
|
|
289
288
|
self._config.prompts_config.system_prompt_template
|
|
290
289
|
).render(
|
|
291
290
|
common_instruction=self._config.common_instruction,
|
|
292
291
|
)
|
|
293
292
|
|
|
294
293
|
# Build user prompt with section name
|
|
295
|
-
user_prompt =
|
|
294
|
+
user_prompt = sandboxed_template(
|
|
296
295
|
self._config.prompts_config.user_prompt_template
|
|
297
296
|
).render(
|
|
298
297
|
section_name=section_name,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Template handler service."""
|
|
2
2
|
|
|
3
|
-
from jinja2 import
|
|
3
|
+
from jinja2 import TemplateError
|
|
4
4
|
|
|
5
5
|
from unique_toolkit._common.experimental.write_up_agent.schemas import (
|
|
6
6
|
GroupData,
|
|
@@ -18,6 +18,7 @@ from unique_toolkit._common.experimental.write_up_agent.services.template_handle
|
|
|
18
18
|
from unique_toolkit._common.experimental.write_up_agent.services.template_handler.utils import (
|
|
19
19
|
parse_template,
|
|
20
20
|
)
|
|
21
|
+
from unique_toolkit._common.utils.jinja.sandbox import sandboxed_template
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
# TODO [UN-16142]: Simplify template logic
|
|
@@ -44,7 +45,7 @@ class TemplateHandler:
|
|
|
44
45
|
self._template = template
|
|
45
46
|
|
|
46
47
|
try:
|
|
47
|
-
self._jinja_template =
|
|
48
|
+
self._jinja_template = sandboxed_template(template, lstrip_blocks=True)
|
|
48
49
|
except TemplateError as e:
|
|
49
50
|
snippet = template[:100] + "..." if len(template) > 100 else template
|
|
50
51
|
raise TemplateParsingError(
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
|
|
3
|
+
from unique_toolkit._common.utils.jinja.sandbox import sandboxed_template
|
|
5
4
|
from unique_toolkit._common.utils.jinja.schema import Jinja2PromptParams
|
|
6
5
|
|
|
7
6
|
|
|
@@ -15,4 +14,4 @@ def render_template(
|
|
|
15
14
|
|
|
16
15
|
params.update(kwargs)
|
|
17
16
|
|
|
18
|
-
return
|
|
17
|
+
return sandboxed_template(template, lstrip_blocks=True).render(**params)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from functools import cache
|
|
2
|
+
|
|
3
|
+
from jinja2 import Template
|
|
4
|
+
from jinja2.sandbox import SandboxedEnvironment
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@cache
|
|
8
|
+
def _sandboxed_environment(*, lstrip_blocks: bool) -> SandboxedEnvironment:
|
|
9
|
+
return SandboxedEnvironment(lstrip_blocks=lstrip_blocks)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def sandboxed_template(source: str, *, lstrip_blocks: bool = False) -> Template:
|
|
13
|
+
"""Compile a Jinja template under Jinja's sandbox restrictions.
|
|
14
|
+
|
|
15
|
+
Use this for templates that come from configuration. An expression the
|
|
16
|
+
sandbox rejects raises ``jinja2.exceptions.SecurityError``.
|
|
17
|
+
"""
|
|
18
|
+
return _sandboxed_environment(lstrip_blocks=lstrip_blocks).from_string(source)
|
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
from datetime import date, datetime
|
|
4
4
|
from typing import Annotated, Any
|
|
5
5
|
|
|
6
|
-
from jinja2 import Template
|
|
7
6
|
from pydantic import (
|
|
8
7
|
BaseModel,
|
|
9
8
|
ConfigDict,
|
|
@@ -12,6 +11,7 @@ from pydantic import (
|
|
|
12
11
|
WrapSerializer,
|
|
13
12
|
)
|
|
14
13
|
|
|
14
|
+
from unique_toolkit._common.utils.jinja.sandbox import sandboxed_template
|
|
15
15
|
from unique_toolkit.agentic.tools.tool import Tool
|
|
16
16
|
|
|
17
17
|
|
|
@@ -21,7 +21,7 @@ class Jinja2PromptParams(BaseModel):
|
|
|
21
21
|
def render_template(self, template: str) -> str:
|
|
22
22
|
params = self.model_dump(exclude_none=True, mode="json")
|
|
23
23
|
|
|
24
|
-
return
|
|
24
|
+
return sandboxed_template(template, lstrip_blocks=True).render(**params)
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class ToolPromptParams(Jinja2PromptParams):
|
|
@@ -2,10 +2,10 @@ import logging
|
|
|
2
2
|
from typing import Any, NamedTuple, override
|
|
3
3
|
|
|
4
4
|
import unique_sdk
|
|
5
|
-
from jinja2 import Template
|
|
6
5
|
from pydantic import BaseModel
|
|
7
6
|
|
|
8
7
|
from unique_toolkit._common.execution import failsafe
|
|
8
|
+
from unique_toolkit._common.utils.jinja.sandbox import sandboxed_template
|
|
9
9
|
from unique_toolkit.agentic.evaluation.evaluation_manager import Evaluation
|
|
10
10
|
from unique_toolkit.agentic.evaluation.exception import EvaluatorException
|
|
11
11
|
from unique_toolkit.agentic.evaluation.schemas import (
|
|
@@ -292,7 +292,9 @@ class SubAgentEvaluationService(Evaluation):
|
|
|
292
292
|
MessagesBuilder()
|
|
293
293
|
.system_message_append(self._config.summarization_system_message)
|
|
294
294
|
.user_message_append(
|
|
295
|
-
|
|
295
|
+
sandboxed_template(
|
|
296
|
+
self._config.summarization_user_message_template
|
|
297
|
+
).render(
|
|
296
298
|
sub_agents=sub_agents_display_data,
|
|
297
299
|
)
|
|
298
300
|
)
|
|
@@ -145,7 +145,12 @@ def calculate_invocation_cost_usd(
|
|
|
145
145
|
token_usage: LanguageModelTokenUsage,
|
|
146
146
|
catalog: ModelCostCatalog | None = None,
|
|
147
147
|
) -> float | None:
|
|
148
|
-
"""Calculate invocation cost
|
|
148
|
+
"""Calculate invocation cost, pricing cache reads and writes at their own rates.
|
|
149
|
+
|
|
150
|
+
Mirrors node-chat's ``ModelCostService.computeSpent`` so debug-info spend and
|
|
151
|
+
the platform ledger agree. Cache reads and writes are counted inside
|
|
152
|
+
``prompt_tokens``; a row without a cache rate bills them at ``input``.
|
|
153
|
+
"""
|
|
149
154
|
|
|
150
155
|
if token_usage.prompt_tokens is None or token_usage.completion_tokens is None:
|
|
151
156
|
return None
|
|
@@ -163,10 +168,32 @@ def calculate_invocation_cost_usd(
|
|
|
163
168
|
if model_cost is None:
|
|
164
169
|
return None
|
|
165
170
|
|
|
166
|
-
|
|
167
|
-
|
|
171
|
+
prompt_tokens = token_usage.prompt_tokens
|
|
172
|
+
cache_read_tokens = min(token_usage.cached_tokens or 0, prompt_tokens)
|
|
173
|
+
cache_write_tokens = min(
|
|
174
|
+
token_usage.cache_write_tokens or 0, prompt_tokens - cache_read_tokens
|
|
175
|
+
)
|
|
176
|
+
uncached_tokens = prompt_tokens - cache_read_tokens - cache_write_tokens
|
|
177
|
+
cache_read_rate = (
|
|
178
|
+
model_cost.cached_input
|
|
179
|
+
if model_cost.cached_input is not None
|
|
180
|
+
else model_cost.input
|
|
168
181
|
)
|
|
182
|
+
# The usage payload does not say which TTL a write used; node-chat bills an
|
|
183
|
+
# unsplit write at the 5-minute rate too.
|
|
184
|
+
cache_write_rate = (
|
|
185
|
+
model_cost.cache_write
|
|
186
|
+
if model_cost.cache_write is not None
|
|
187
|
+
else model_cost.input
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
input_multiplier, completion_multiplier = model_cost.multipliers_for(prompt_tokens)
|
|
169
191
|
return (
|
|
170
|
-
|
|
192
|
+
(
|
|
193
|
+
uncached_tokens * model_cost.input
|
|
194
|
+
+ cache_read_tokens * cache_read_rate
|
|
195
|
+
+ cache_write_tokens * cache_write_rate
|
|
196
|
+
)
|
|
197
|
+
* input_multiplier
|
|
171
198
|
+ token_usage.completion_tokens * model_cost.completion * completion_multiplier
|
|
172
199
|
) / _TOKENS_PER_MILLION
|
{unique_toolkit-2026.46.0.dev2.dist-info → unique_toolkit-2026.46.0.dev4.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-toolkit
|
|
3
|
-
Version: 2026.46.0.
|
|
3
|
+
Version: 2026.46.0.dev4
|
|
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>
|
|
@@ -50,11 +50,11 @@ unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/e
|
|
|
50
50
|
unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/config.py,sha256=ep8NJNyBEbKIN7FudkeAfFaHzl1JygJxfNR2Ab0MHU0,1153
|
|
51
51
|
unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/system_prompt.j2,sha256=U66WhKnA-_AHM-APCzHVRn2bu5rZMqRwyZ2kvAmF2xA,674
|
|
52
52
|
unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/user_prompt.j2,sha256=9OMngS80URT4g96c0pYWjIcZn2Jn-C2aSFUdE7uIfCs,709
|
|
53
|
-
unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/service.py,sha256=
|
|
53
|
+
unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/service.py,sha256=oQKWdMs370R7TlwIjwGskgq6U6-g94RGO1irDYESp9E,12231
|
|
54
54
|
unique_toolkit/_common/experimental/write_up_agent/services/template_handler/__init__.py,sha256=dyUAoV0uL-eEtSQQQ7XV8YMnNvwcyowiquZrgbhzNII,800
|
|
55
55
|
unique_toolkit/_common/experimental/write_up_agent/services/template_handler/default_template.j2,sha256=mL2l4rvrQFEHvjZ8uf2uQFujoKsnT1CoYHbEC45zHDY,1036
|
|
56
56
|
unique_toolkit/_common/experimental/write_up_agent/services/template_handler/exceptions.py,sha256=FGkJsbEeLwGDtFROH0TMxMFeXo4zfF40pXbLk6peYAo,1256
|
|
57
|
-
unique_toolkit/_common/experimental/write_up_agent/services/template_handler/service.py,sha256=
|
|
57
|
+
unique_toolkit/_common/experimental/write_up_agent/services/template_handler/service.py,sha256=PLxJQfK-aTr5wIpRXzx0t5IT5kZKE4vwZhY-iGTK5z8,6568
|
|
58
58
|
unique_toolkit/_common/experimental/write_up_agent/services/template_handler/utils.py,sha256=FeJhTAU7AUlSFCfFwmEzzI22PtAdFJluzsGeiEPK49Q,6393
|
|
59
59
|
unique_toolkit/_common/experimental/write_up_agent/utils.py,sha256=I_OCDXCxY6uZk_fNQg_bIXHwjnN7ND_ngcisThnGGIc,739
|
|
60
60
|
unique_toolkit/_common/feature_flags/schema.py,sha256=X32VqH4VMK7bhEfSd8Wbddl8FVs7Gh7ucuIEbmqc4Kw,268
|
|
@@ -74,8 +74,9 @@ unique_toolkit/_common/utils/__init__.py,sha256=qHrEy-3zkbFPdGFriRscPbGKuQfOuPi3
|
|
|
74
74
|
unique_toolkit/_common/utils/files.py,sha256=cPJU3Y5DlAbdakPaF1vICOCOujMHESrP4b3RCJjtGj4,5871
|
|
75
75
|
unique_toolkit/_common/utils/image/encode.py,sha256=IJhtTcIT_azhiDsPp15oYs2LPze2l-sGlZrJASHrDVI,658
|
|
76
76
|
unique_toolkit/_common/utils/jinja/helpers.py,sha256=UQWj0hFMtnuUFYDJ8NKbEblvYE8DrWX1o7fKQU3H9IQ,262
|
|
77
|
-
unique_toolkit/_common/utils/jinja/render.py,sha256=
|
|
78
|
-
unique_toolkit/_common/utils/jinja/
|
|
77
|
+
unique_toolkit/_common/utils/jinja/render.py,sha256=D48hVbDcaGz_O01Xgawd3fBgbFIiZkThShZyjN96nBo,537
|
|
78
|
+
unique_toolkit/_common/utils/jinja/sandbox.py,sha256=UAT5Au8pEDAwrZcseDc3m7uFpLx_3vtLQ4Ureqv0Jlc,633
|
|
79
|
+
unique_toolkit/_common/utils/jinja/schema.py,sha256=uyGGN1uvcGTBBujs8KUrnMMND73MNC5YGJkSETVyUCo,2007
|
|
79
80
|
unique_toolkit/_common/utils/jinja/utils.py,sha256=0SrwN6qfLlRJrl38HG7qsMr5-DwpABNnM9LpqpMgwUA,2814
|
|
80
81
|
unique_toolkit/_common/utils/structured_output/__init__.py,sha256=nm_orZrlCXL0FPLUg0Jv6Ty1flXPkCgZ9caAWaS8rz8,38
|
|
81
82
|
unique_toolkit/_common/utils/structured_output/schema.py,sha256=Tp7kDYcmKtnUhcuRkH86TSYhylRff0ZZJYb2dLkISts,131
|
|
@@ -157,7 +158,7 @@ unique_toolkit/agentic/tools/a2a/config.py,sha256=f0nkNaFpYYX1SC2n0ZtsO8r9_oYhor
|
|
|
157
158
|
unique_toolkit/agentic/tools/a2a/evaluation/__init__.py,sha256=Efso468EQ4UANv140qcrRPCdX98-OQJfnrLqhgJ9pfE,412
|
|
158
159
|
unique_toolkit/agentic/tools/a2a/evaluation/_utils.py,sha256=-fvd14FdEnQETGq-GRk7zdgJvsQt7_1UnM0T5kWEzgc,1947
|
|
159
160
|
unique_toolkit/agentic/tools/a2a/evaluation/config.py,sha256=DLdDXWiXqkRgl-lmoSJxeMiXMScA4PFu2xVuMAqTHyA,2358
|
|
160
|
-
unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py,sha256=
|
|
161
|
+
unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py,sha256=dGd1CurVAdRqGfFV8Tx-WNyJ_8eA5wJEOiPQbgn1hiQ,11008
|
|
161
162
|
unique_toolkit/agentic/tools/a2a/evaluation/summarization_user_message.j2,sha256=acP1YqD_sCy6DT0V2EIfhQTmaUKeqpeWNJ7RGgceo8I,271
|
|
162
163
|
unique_toolkit/agentic/tools/a2a/manager.py,sha256=B5y69urCFCD2ROfAO2mTa-rCJRxUpOJpipPXL7ugpDI,3655
|
|
163
164
|
unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py,sha256=aVtUBPN7kDrqA6Bze34AbqQpcBBqpvfyJG-xF65w7R0,659
|
|
@@ -401,7 +402,7 @@ unique_toolkit/language_model/errors.py,sha256=0nm4psGCGJM2B7LIyKXy7WuswRzwARIgI
|
|
|
401
402
|
unique_toolkit/language_model/functions.py,sha256=6Le6dDm9su6xk3sQ8IPiyUn2tf1qvzxHVUhyTTgP8Kw,28109
|
|
402
403
|
unique_toolkit/language_model/infos.py,sha256=IAwSmmFEdX51bYXsx62XQqJ4wwaJMz7fGf3nsNcHlZE,183833
|
|
403
404
|
unique_toolkit/language_model/invocation_stats.py,sha256=CQbpUz394IsVd8eNTB1gPSMt5f0UXmkN1amNsqtAW6U,5857
|
|
404
|
-
unique_toolkit/language_model/model_costs.py,sha256=
|
|
405
|
+
unique_toolkit/language_model/model_costs.py,sha256=AVHAuMTzsglzusWsVF_xwBVEndST-TVCVi0H49OhdvE,7419
|
|
405
406
|
unique_toolkit/language_model/prompt.py,sha256=JSawaLjQg3VR-E2fK8engFyJnNdk21zaO8pPIodzN4Q,3991
|
|
406
407
|
unique_toolkit/language_model/provider_token_count.py,sha256=mS597Mvrc7EsAc9iJSmASIEwvETSPLtIEsWxusPrQVc,5337
|
|
407
408
|
unique_toolkit/language_model/reference.py,sha256=T3wr2jP_uRg5wKVIbKqLbxJlcgxfbZQGq3XdjbQ2kSo,6984
|
|
@@ -429,6 +430,6 @@ unique_toolkit/short_term_memory/service.py,sha256=2JMBEBn6GoyK-a0xvdcWpPft-3C74
|
|
|
429
430
|
unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
430
431
|
unique_toolkit/smart_rules/compile.py,sha256=vRe0aMJWuVIK-VsqomgxQImzke7MDmwgSxxJfYCa7zw,1386
|
|
431
432
|
unique_toolkit/test_utilities/events.py,sha256=FLrhMh0A_mQutAUjoD0FdMcVQ4Gq31r35OVGzRjvLro,6760
|
|
432
|
-
unique_toolkit-2026.46.0.
|
|
433
|
-
unique_toolkit-2026.46.0.
|
|
434
|
-
unique_toolkit-2026.46.0.
|
|
433
|
+
unique_toolkit-2026.46.0.dev4.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
434
|
+
unique_toolkit-2026.46.0.dev4.dist-info/METADATA,sha256=S3pb1MeBajfmMuiG1-DzzHjYwlu1YKRqAbgpw0XhhWA,7821
|
|
435
|
+
unique_toolkit-2026.46.0.dev4.dist-info/RECORD,,
|
|
File without changes
|