unique_toolkit 2026.34.0.dev7__py3-none-any.whl → 2026.34.0.dev9__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/app/unique_settings.py +13 -2
- unique_toolkit/monitoring/__init__.py +4 -0
- unique_toolkit/monitoring/tracing.py +69 -1
- {unique_toolkit-2026.34.0.dev7.dist-info → unique_toolkit-2026.34.0.dev9.dist-info}/METADATA +4 -2
- {unique_toolkit-2026.34.0.dev7.dist-info → unique_toolkit-2026.34.0.dev9.dist-info}/RECORD +6 -6
- {unique_toolkit-2026.34.0.dev7.dist-info → unique_toolkit-2026.34.0.dev9.dist-info}/WHEEL +0 -0
|
@@ -379,7 +379,18 @@ class UniqueApi(BaseSettings):
|
|
|
379
379
|
)
|
|
380
380
|
|
|
381
381
|
@staticmethod
|
|
382
|
-
def _legacy_base_path(hostname: str | None) -> str:
|
|
382
|
+
def _legacy_base_path(hostname: str | None, port: int | None = None) -> str:
|
|
383
|
+
# ponytail: root path inferred from unique-api hostname / local :8096;
|
|
384
|
+
# ceiling = service rename or non-8096 local bind; upgrade = explicit ApiType.
|
|
385
|
+
if hostname and "unique-api" in hostname:
|
|
386
|
+
return ""
|
|
387
|
+
if (
|
|
388
|
+
hostname
|
|
389
|
+
and port == 8096
|
|
390
|
+
and (hostname in ("localhost", "127.0.0.1") or "localhost" in hostname)
|
|
391
|
+
):
|
|
392
|
+
return ""
|
|
393
|
+
|
|
383
394
|
base_path = "/public/chat"
|
|
384
395
|
if hostname and (
|
|
385
396
|
"gateway.qa.unique" in hostname or "gateway.unique" in hostname
|
|
@@ -409,7 +420,7 @@ class UniqueApi(BaseSettings):
|
|
|
409
420
|
case ApiType.INTERNAL:
|
|
410
421
|
base_path = "public"
|
|
411
422
|
case ApiType.LEGACY:
|
|
412
|
-
base_path = self._legacy_base_path(parsed.hostname)
|
|
423
|
+
base_path = self._legacy_base_path(parsed.hostname, parsed.port)
|
|
413
424
|
|
|
414
425
|
return parsed, base_path
|
|
415
426
|
|
|
@@ -4,6 +4,8 @@ from unique_toolkit.monitoring.tracing import (
|
|
|
4
4
|
TracingSettings,
|
|
5
5
|
configure_tracing,
|
|
6
6
|
inject_trace_headers,
|
|
7
|
+
instrument_fastapi_app,
|
|
8
|
+
instrument_requests,
|
|
7
9
|
)
|
|
8
10
|
|
|
9
11
|
__all__ = [
|
|
@@ -12,6 +14,8 @@ __all__ = [
|
|
|
12
14
|
"TracingSettings",
|
|
13
15
|
"configure_tracing",
|
|
14
16
|
"inject_trace_headers",
|
|
17
|
+
"instrument_fastapi_app",
|
|
18
|
+
"instrument_requests",
|
|
15
19
|
]
|
|
16
20
|
|
|
17
21
|
_MONITORING_AVAILABLE = False
|
|
@@ -9,7 +9,10 @@ from typing import TYPE_CHECKING, ClassVar, Self, TypeAlias, cast
|
|
|
9
9
|
from pydantic import AliasChoices, Field
|
|
10
10
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
11
11
|
|
|
12
|
+
from unique_toolkit.app.find_env_file import find_env_file
|
|
13
|
+
|
|
12
14
|
if TYPE_CHECKING:
|
|
15
|
+
from fastapi import FastAPI # pyright: ignore[reportMissingImports]
|
|
13
16
|
from opentelemetry.trace.propagation.tracecontext import (
|
|
14
17
|
TraceContextTextMapPropagator,
|
|
15
18
|
)
|
|
@@ -25,6 +28,10 @@ _OTEL_EXTRA_MESSAGE = (
|
|
|
25
28
|
"OpenTelemetry tracing requires the unique_toolkit[otel] extra. "
|
|
26
29
|
"Install it with: uv add 'unique-toolkit[otel]'"
|
|
27
30
|
)
|
|
31
|
+
_FASTAPI_EXTRA_MESSAGE = (
|
|
32
|
+
"FastAPI instrumentation requires the unique_toolkit[fastapi] extra. "
|
|
33
|
+
"Install it with: uv add 'unique-toolkit[fastapi]'"
|
|
34
|
+
)
|
|
28
35
|
|
|
29
36
|
|
|
30
37
|
class TraceExporter(StrEnum):
|
|
@@ -42,6 +49,8 @@ class TracingSettings(BaseSettings):
|
|
|
42
49
|
env_prefix="OTEL_",
|
|
43
50
|
env_ignore_empty=True,
|
|
44
51
|
extra="ignore",
|
|
52
|
+
env_file=find_env_file(".env", required=False),
|
|
53
|
+
env_file_encoding="utf-8",
|
|
45
54
|
)
|
|
46
55
|
|
|
47
56
|
traces_exporter: TraceExporter | None = None
|
|
@@ -90,6 +99,11 @@ def _missing_otel_extra() -> ImportError:
|
|
|
90
99
|
return ImportError(_OTEL_EXTRA_MESSAGE)
|
|
91
100
|
|
|
92
101
|
|
|
102
|
+
def _missing_fastapi_extra() -> ImportError:
|
|
103
|
+
"""Create a consistent error for an unavailable optional FastAPI dependency."""
|
|
104
|
+
return ImportError(_FASTAPI_EXTRA_MESSAGE)
|
|
105
|
+
|
|
106
|
+
|
|
93
107
|
def _trace_context_propagator() -> TraceContextTextMapPropagator:
|
|
94
108
|
"""Return a W3C trace-context propagator without forwarding baggage."""
|
|
95
109
|
try:
|
|
@@ -165,9 +179,12 @@ def configure_tracing(
|
|
|
165
179
|
|
|
166
180
|
try:
|
|
167
181
|
from opentelemetry import trace
|
|
182
|
+
from opentelemetry.baggage.propagation import W3CBaggagePropagator
|
|
168
183
|
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
169
184
|
OTLPSpanExporter,
|
|
170
185
|
)
|
|
186
|
+
from opentelemetry.propagate import set_global_textmap
|
|
187
|
+
from opentelemetry.propagators.composite import CompositePropagator
|
|
171
188
|
from opentelemetry.sdk.resources import Resource
|
|
172
189
|
from opentelemetry.sdk.trace import TracerProvider
|
|
173
190
|
from opentelemetry.sdk.trace.export import (
|
|
@@ -176,6 +193,9 @@ def configure_tracing(
|
|
|
176
193
|
SimpleSpanProcessor,
|
|
177
194
|
)
|
|
178
195
|
from opentelemetry.trace import ProxyTracerProvider
|
|
196
|
+
from opentelemetry.trace.propagation.tracecontext import (
|
|
197
|
+
TraceContextTextMapPropagator,
|
|
198
|
+
)
|
|
179
199
|
except ImportError as error:
|
|
180
200
|
raise _missing_otel_extra() from error
|
|
181
201
|
|
|
@@ -196,6 +216,54 @@ def configure_tracing(
|
|
|
196
216
|
if exporter is TraceExporter.CONSOLE:
|
|
197
217
|
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
|
|
198
218
|
else:
|
|
199
|
-
|
|
219
|
+
# Sizing pinned to match the Node services' instrumentation.ts.
|
|
220
|
+
provider.add_span_processor(
|
|
221
|
+
BatchSpanProcessor(
|
|
222
|
+
OTLPSpanExporter(),
|
|
223
|
+
max_queue_size=2048,
|
|
224
|
+
max_export_batch_size=512,
|
|
225
|
+
schedule_delay_millis=5000,
|
|
226
|
+
)
|
|
227
|
+
)
|
|
200
228
|
trace.set_tracer_provider(provider)
|
|
229
|
+
# Trace-context + baggage, the shared subset of the Node services' propagator.
|
|
230
|
+
set_global_textmap(
|
|
231
|
+
CompositePropagator([TraceContextTextMapPropagator(), W3CBaggagePropagator()])
|
|
232
|
+
)
|
|
201
233
|
return True
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def instrument_fastapi_app(app: FastAPI, *, excluded_urls: str | None = None) -> None:
|
|
237
|
+
"""Trace inbound requests for an already-created FastAPI app instance.
|
|
238
|
+
|
|
239
|
+
Uses ``FastAPIInstrumentor.instrument_app`` rather than the global
|
|
240
|
+
``FastAPIInstrumentor().instrument()``: the global form swaps out the
|
|
241
|
+
``fastapi.FastAPI`` class, so it only takes effect for app objects created
|
|
242
|
+
afterward. Instrumenting the instance has no such ordering requirement.
|
|
243
|
+
"""
|
|
244
|
+
try:
|
|
245
|
+
import fastapi # noqa: F401 # pyright: ignore[reportMissingImports, reportUnusedImport]
|
|
246
|
+
except ImportError as error:
|
|
247
|
+
# opentelemetry-instrumentation-fastapi imports fastapi internally, so without
|
|
248
|
+
# this explicit check its own ImportError would be misreported below as a
|
|
249
|
+
# missing otel extra when fastapi itself is what's actually missing.
|
|
250
|
+
raise _missing_fastapi_extra() from error
|
|
251
|
+
|
|
252
|
+
try:
|
|
253
|
+
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
|
|
254
|
+
except ImportError as error:
|
|
255
|
+
raise _missing_otel_extra() from error
|
|
256
|
+
FastAPIInstrumentor.instrument_app(app, excluded_urls=excluded_urls)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def instrument_requests() -> None:
|
|
260
|
+
"""Trace outbound calls made with the ``requests`` library.
|
|
261
|
+
|
|
262
|
+
Patches ``requests`` at module level, so callers that already imported it
|
|
263
|
+
are still covered.
|
|
264
|
+
"""
|
|
265
|
+
try:
|
|
266
|
+
from opentelemetry.instrumentation.requests import RequestsInstrumentor
|
|
267
|
+
except ImportError as error:
|
|
268
|
+
raise _missing_otel_extra() from error
|
|
269
|
+
RequestsInstrumentor().instrument()
|
{unique_toolkit-2026.34.0.dev7.dist-info → unique_toolkit-2026.34.0.dev9.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-toolkit
|
|
3
|
-
Version: 2026.34.0.
|
|
3
|
+
Version: 2026.34.0.dev9
|
|
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.34.0.
|
|
19
|
+
Requires-Dist: unique-sdk>=2026.34.0.dev4,<2026.34.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
|
|
@@ -44,6 +44,8 @@ Requires-Dist: langchain-core>=1.0.0,<2 ; extra == 'langchain'
|
|
|
44
44
|
Requires-Dist: prometheus-client>=0.24.1,<1 ; extra == 'monitoring'
|
|
45
45
|
Requires-Dist: opentelemetry-sdk>=1.27,<2 ; extra == 'otel'
|
|
46
46
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.27,<2 ; extra == 'otel'
|
|
47
|
+
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.65b0,<1 ; extra == 'otel'
|
|
48
|
+
Requires-Dist: opentelemetry-instrumentation-requests>=0.65b0,<1 ; extra == 'otel'
|
|
47
49
|
Requires-Python: >=3.12
|
|
48
50
|
Provides-Extra: fastapi
|
|
49
51
|
Provides-Extra: langchain
|
|
@@ -251,7 +251,7 @@ unique_toolkit/app/init_sdk.py,sha256=5_oDoETr6akwYyBCb0ivTdMNu3SVgPSkrXcDS6ELyY
|
|
|
251
251
|
unique_toolkit/app/performance/async_tasks.py,sha256=8Xv5kEmmFDJO7YyyBxv4e7bcNgq-3z_E2_4z1Yn9EqU,1970
|
|
252
252
|
unique_toolkit/app/performance/async_wrapper.py,sha256=yVVcRDkcdyfjsxro-N29SBvi-7773wnfDplef6-y8xw,1077
|
|
253
253
|
unique_toolkit/app/schemas.py,sha256=_jHuLDZO9YSP0xf-1AxNVorWYg2NgWfNZ9yXpGt2DHE,18518
|
|
254
|
-
unique_toolkit/app/unique_settings.py,sha256
|
|
254
|
+
unique_toolkit/app/unique_settings.py,sha256=dfqqh1Nv2JaqL3fePndmuRAfJcARzImdwSOO1J3KS1E,27318
|
|
255
255
|
unique_toolkit/app/verification.py,sha256=GxFFwcJMy25fCA_Xe89wKW7bgqOu8PAs5y8QpHF0GSc,3861
|
|
256
256
|
unique_toolkit/app/webhook.py,sha256=evpxLDnvz7P3D7-TV1XBkl8WcoldXpjOkw3tvFRxHr0,2368
|
|
257
257
|
unique_toolkit/chat/__init__.py,sha256=-239hRT9x8fJ5rL_qvGAhnxLO_F7gToTVVLo0wZbesU,1722
|
|
@@ -402,11 +402,11 @@ unique_toolkit/language_model/service.py,sha256=hDoJBBgG_wWs8WuC_c8tnmK8cNu8o5Eh
|
|
|
402
402
|
unique_toolkit/language_model/settings.py,sha256=7szohExI-qmTfUf2Zp5AB5TzrsZy1UekAGyXx_UaPMc,1524
|
|
403
403
|
unique_toolkit/language_model/stream_transform.py,sha256=iNNGpLY_7G6Bpp9Y4KtbIkQm3WB4yZt75BXcqx0DVkI,2775
|
|
404
404
|
unique_toolkit/language_model/utils.py,sha256=bPQ4l6_YO71w-zaIPanUUmtbXC1_hCvLK0tAFc3VCRc,1902
|
|
405
|
-
unique_toolkit/monitoring/__init__.py,sha256=
|
|
405
|
+
unique_toolkit/monitoring/__init__.py,sha256=XHRzPx4LKcbKruRrf_gNv50amhvhy8Go2IkOoHMuLsw,1486
|
|
406
406
|
unique_toolkit/monitoring/gunicorn.py,sha256=urTFFS5zYHKoxb1TEQHcLqb2byi-aYgFRHGwgYRzYYI,844
|
|
407
407
|
unique_toolkit/monitoring/middleware.py,sha256=MNsUuKgt74mSnUwttXTB_AxX546Pz2zKoAP9OewVrwQ,4531
|
|
408
408
|
unique_toolkit/monitoring/registry.py,sha256=De2Bx5QBBRJQY2MM3xtntiJ2JU2FoKkVT7rNMG7ewgA,5874
|
|
409
|
-
unique_toolkit/monitoring/tracing.py,sha256=
|
|
409
|
+
unique_toolkit/monitoring/tracing.py,sha256=0lmLuQjyyC3iFpNTw8rOyCpEZ6PTvp16nVbzcO9d2sQ,10043
|
|
410
410
|
unique_toolkit/protocols/support.py,sha256=x5edzbBmKAUuvm3oLFh52gkgQsqR5LU7M0t8RHK0DZk,5161
|
|
411
411
|
unique_toolkit/services/__init__.py,sha256=b9Wl7Wvz1JmZDbDexIZzBoXZ0wscXuczGAH8LoL-Qak,572
|
|
412
412
|
unique_toolkit/services/chat_service.py,sha256=6lVMSwvi2ztPebK6meo9BVLOL_Wdje5wPSUBp5dMZIg,99268
|
|
@@ -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.34.0.
|
|
424
|
-
unique_toolkit-2026.34.0.
|
|
425
|
-
unique_toolkit-2026.34.0.
|
|
423
|
+
unique_toolkit-2026.34.0.dev9.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
424
|
+
unique_toolkit-2026.34.0.dev9.dist-info/METADATA,sha256=u_HrX_80XqfWG54ud1CwTxBiJF2lKD0L9Go050etA4c,7821
|
|
425
|
+
unique_toolkit-2026.34.0.dev9.dist-info/RECORD,,
|
|
File without changes
|