tai42-monitoring-langfuse
A Langfuse Monitoring backend for the TAI ecosystem. It implements both faces
of the tai42_contract.monitoring contract: the writer (spans, events,
LangChain/LangGraph callback handlers, context propagation, per-project
scoping) and the reader (metrics totals, the runtime span window, and
complete-trace reads) over a Langfuse server — cloud or self-hosted.
The TAI ecosystem
TAI is an open-source runtime for MCP tools, agents, and workflows. A
Monitoring backend is the runtime's observability provider: the framework
emits tool/hook/agent spans through the registered writer, and the
/api/observability/* routes answer dashboards from the same backend's reader.
This package is one such provider (Langfuse); any package can back the same
contract, so this repo is this provider's own full doc home, and the
documentation site covers the platform-level story:
- Observability guide: https://tai42.ai/guides/observe
- Author a monitoring backend (author guide): https://tai42.ai/guides/authors/monitoring-backend
- Ecosystem catalog: https://tai42.ai/reference/catalog
Its only tai-* dependencies are tai42-contract (the Monitoring /
MonitoringWriter / MonitoringReader protocols, the neutral data models, and
the tai42_app handle) and tai42-kit (TaiBaseSettings and the settings cache).
Beyond those it depends on the langfuse SDK, langchain, the OpenTelemetry
API, and pydantic / pydantic-settings.
Install
Requires Python 3.13+. Install from PyPI into the environment that runs the server:
uv add tai42-monitoring-langfuse
Or from source — clone this repo and add it as an editable dependency; the
tai42-* dependencies resolve in-tree from the workspace.
git clone https://github.com/tai42ai/tai42 # next to your app checkout
cd /path/to/your/app
uv add --editable ../tai42/plugins/monitoring-langfuse
Discovery
The runtime discovers this backend through the manifest's monitoring_module
field: it imports every module under the named package, and the package's
register module fires the @tai42_app.monitoring.register_monitoring decorator
as a side-effect (there is no entry-point). The decorated zero-arg builder
constructs the backend from the LANGFUSE_* environment and installs it as the
process monitoring backend:
monitoring_module: tai42_monitoring_langfuse
Selecting the module but leaving the credentials unset raises at startup —
a selected backend that cannot build is a loud failure, not a silent downgrade.
To run without monitoring, omit monitoring_module entirely (the runtime falls
back to its built-in no-op). A plain import tai42_monitoring_langfuse (library
use) does not register anything.
Configuration
Settings are read from the LANGFUSE_ environment group (see
LangfuseSettings):
| Env var | Default | Purpose |
|---|---|---|
LANGFUSE_PUBLIC_KEY |
— | Langfuse project public key (required) |
LANGFUSE_SECRET_KEY |
— | Langfuse project secret key (required) |
LANGFUSE_HOST |
— | Langfuse server URL (required) |
LANGFUSE_TIMEOUT_SECONDS |
30 |
SDK client timeout, also passed per read request |
LANGFUSE_TRACING_ENVIRONMENT |
tai |
The source marker: stamps every write as the Langfuse environment and scopes every read to it |
The source marker lets several deployments share one Langfuse project while
each reads back only its own data. get_trace is the one unscoped read — a
trace id is globally unique.
Multi-project scoping
One registered backend can hold several Langfuse projects.
Monitoring.add_project(ProjectConfig(...)) registers an extra project, and
writer.scope(public_key) binds it as the active project for a block — every
emit and read inside the block targets it. Scoping to an unregistered key
raises (a silently mis-scoped block could leak traces across projects).
writer.disable() suppresses all emission within a block.
Behavior notes
- Writer fail-safety (contract invariant): the emit methods and the
Spanhandle catch + log, never raising into application code.record_spanwithout atrace_idis the one raising precondition (a caller bug). The lifecycle/propagation methods (flush,shutdown,inject_context,get_monitoring_callbacks,scope,disable) propagate errors loudly. - Fork safety:
writer.shutdown()fully evicts every cached SDK client (not just a flush), so a forked child rebuilds a clean client on first use. - Reader:
asyncper the contract; the synchronous Langfuse API client is dispatched off the event loop, andlist_traceshydrates trace bodies concurrently (bounded, order-preserving). A trace body that fails to load is kept in place withfetch_errorset, never dropped.get_tracereturns the trace or raisesTraceNotFoundError; a transient failure (e.g. a timeout) propagates as-is — it is never mapped to "not found". - Metric sorts:
list_tracesordered bytotal_cost/latency/total_tokensranks globally through the Langfuse metrics API (trace.list cannot sort on aggregates) and requiresfrom_timestamp+limit; unsupported filter clauses on that path raiseMonitoringReadNotSupportedErrornaming the offending clauses. - Private SDK surface: the few capabilities the SDK has no public API for
(project-scope contextvar, full client eviction, explicit-time span emission,
trace attributes from a span handle) are concentrated in
tai42_monitoring_langfuse.sdk_internals, documented as version-fragile against the pinnedlangfuse~=4.0.6.
Development
uv venv --python 3.13
uv pip install --no-sources --group dev --editable .
uv run --no-sync pytest --cov --cov-report=term-missing
uv run --no-sync ruff check .
uv run --no-sync ruff format --check .
uv run --no-sync pyright
Live integration tests (pytest -m integration) hit a real Langfuse server;
they read LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY / LANGFUSE_HOST from
the environment and skip cleanly when unset.
License
Apache-2.0. See LICENSE and NOTICE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tai42_monitoring_langfuse-0.2.6.tar.gz.
File metadata
- Download URL: tai42_monitoring_langfuse-0.2.6.tar.gz
- Upload date:
- Size: 45.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c3813c5896ff48cd848e11d7e2110a8f0800c37fa5318a6be4f600d5d47c2bc
|
|
| MD5 |
e235cb2eef12c9b786d2cc638e8b6658
|
|
| BLAKE2b-256 |
81ef0157480f5e8abad889b12a119d8a49017006b21ffaa6cf705ba9d76a4f08
|
File details
Details for the file tai42_monitoring_langfuse-0.2.6-py3-none-any.whl.
File metadata
- Download URL: tai42_monitoring_langfuse-0.2.6-py3-none-any.whl
- Upload date:
- Size: 28.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1fb1b55d56e74559b5dd29bfd15fc1d80121997f1fc06ad0d1645f6385cf0b93
|
|
| MD5 |
9726adfbfcf1265204b970d9a758d107
|
|
| BLAKE2b-256 |
aa52fb5976c3468b653ff9ae9d3f210a0ec6a3eec72e18e5b7a986f892b44c54
|