Metadata-Version: 2.4
Name: agentscope-otel-langfuse
Version: 0.1.1
Summary: Langfuse OpenTelemetry tracing integration for AgentScope applications
Author: JLPAY AI Team
License-Expression: MIT
Project-URL: Homepage, https://gitlab.jlpay.com/ai-agent/apps/internal/regulation-assistant-agent
Project-URL: Repository, https://gitlab.jlpay.com/ai-agent/apps/internal/regulation-assistant-agent
Project-URL: Issues, https://gitlab.jlpay.com/ai-agent/apps/internal/regulation-assistant-agent/-/issues
Keywords: agentscope,langfuse,opentelemetry,otel,llmops,tracing
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: agentscope>=1.0.11
Requires-Dist: opentelemetry-api>=1.20.0
Requires-Dist: opentelemetry-sdk>=1.20.0
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.20.0
Dynamic: license-file

# agentscope-otel-langfuse

Langfuse OpenTelemetry tracing integration for AgentScope applications.

This package initializes an OpenTelemetry tracer provider, enables AgentScope's built-in LLM tracing, and adds Langfuse-compatible trace attributes for sessions, users, inputs, outputs, token usage, resource metadata, and Kubernetes metadata.

## Features

- OTLP/HTTP trace export to an OpenTelemetry Collector or Langfuse-compatible endpoint.
- AgentScope `@trace_llm` activation when supported by the installed AgentScope version.
- Request-level root traces with `trace_request()`.
- Langfuse session/user/input/output mapping.
- Token usage attributes using `gen_ai.usage.*`.
- Kubernetes metadata support via Downward API environment variables.
- `OTEL_RESOURCE_ATTRIBUTES` support, mirrored into Langfuse trace metadata.
- No-op behavior when tracing is disabled, so callers do not need telemetry conditionals.

## Installation

```bash
pip install agentscope-otel-langfuse
```

For local development from this repository:

```bash
pip install -e ./agentscope-otel-langfuse
```

## Quick Start

```python
from agentscope_otel_langfuse import OTelConfig, init, trace_request

init(
    OTelConfig.from_env(
        service_name="my-agentscope-app",
    )
)

with trace_request(
    session_id="session-001",
    user_id="user-001",
    user_input="hello",
) as trace:
    result = "world"
    trace.set_output(result)
    trace.set_usage({"input_tokens": 12, "output_tokens": 8})
```

Async usage:

```python
async with trace_request(session_id=sid, user_id=uid, user_input=prompt) as trace:
    response = await agent(messages)
    trace.set_output(response)
    trace.set_usage({"input_tokens": 100, "output_tokens": 50})
```

## Configuration

Environment variables:

| Variable | Required | Description |
| --- | --- | --- |
| `OTEL_ENABLED` | No | Set to `true` to enable tracing. Defaults to `false`. |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | Yes, when enabled | OTLP HTTP endpoint. `/v1/traces` is appended automatically if omitted. |
| `OTEL_RESOURCE_ATTRIBUTES` | No | Comma-separated OTel resource attributes, for example `deployment.environment=prod,service.version=1.2.3`. |

Explicit values passed to `OTelConfig.from_env()` override environment variables:

```python
config = OTelConfig.from_env(
    service_name="payment-regulation-agent",
    enabled=True,
    endpoint="http://otel-collector:4318",
)
init(config)
```

## Kubernetes Metadata

The SDK reads these optional environment variables and writes them as OTel resource attributes:

| Environment variable | OTel resource attribute |
| --- | --- |
| `K8S_POD_NAME` | `k8s.pod.name` |
| `K8S_POD_NAMESPACE` | `k8s.namespace.name` |
| `K8S_POD_UID` | `k8s.pod.uid` |
| `K8S_POD_IP` | `k8s.pod.ip` |
| `K8S_NODE_NAME` | `k8s.node.name` |
| `K8S_DEPLOYMENT_NAME` | `k8s.deployment.name` |
| `K8S_POD_LABEL_APP` | `k8s.pod.label.app` |
| `K8S_POD_LABEL_VERSION` | `k8s.pod.label.version` |
| `K8S_POD_LABEL_ENV` | `k8s.pod.label.env` |

Example Kubernetes env configuration:

```yaml
env:
  - name: OTEL_ENABLED
    value: "true"
  - name: OTEL_EXPORTER_OTLP_ENDPOINT
    value: "http://otel-collector:4318"
  - name: K8S_POD_NAME
    valueFrom:
      fieldRef:
        fieldPath: metadata.name
  - name: K8S_POD_NAMESPACE
    valueFrom:
      fieldRef:
        fieldPath: metadata.namespace
  - name: K8S_POD_UID
    valueFrom:
      fieldRef:
        fieldPath: metadata.uid
  - name: K8S_POD_IP
    valueFrom:
      fieldRef:
        fieldPath: status.podIP
  - name: K8S_NODE_NAME
    valueFrom:
      fieldRef:
        fieldPath: spec.nodeName
  - name: K8S_DEPLOYMENT_NAME
    value: "payment-regulation-agent"
  - name: OTEL_RESOURCE_ATTRIBUTES
    value: "deployment.environment=prod,service.version=1.2.3"
```

## Langfuse Metadata Mapping

Kubernetes and resource attributes are written twice:

- As OTel resource attributes, for backend/collector compatibility.
- As Langfuse metadata attributes on the root span, so they are visible in Langfuse trace metadata.

For example:

| Source attribute | Langfuse span attribute |
| --- | --- |
| `k8s.namespace.name=prod` | `langfuse.trace.metadata.k8s_namespace_name=prod` |
| `k8s.pod.name=agent-abc` | `langfuse.trace.metadata.k8s_pod_name=agent-abc` |
| `service.name=my-app` | `langfuse.trace.metadata.service_name=my-app` |
| `deployment.environment=prod` | `langfuse.trace.metadata.deployment_environment=prod` |

The same keys are also written under `langfuse.observation.metadata.*` for observation-level visibility.

## API

### `OTelConfig`

```python
OTelConfig(enabled: bool, endpoint: str | None, service_name: str)
```

Use `OTelConfig.from_env()` to resolve environment variables and explicit overrides.

### `init(config)`

Initializes OpenTelemetry tracing and activates AgentScope LLM tracing when available.

Returns a tracer object, or `None` when tracing is disabled or cannot be initialized.

### `trace_request(...)`

Creates a sync/async context manager for a request-level root trace.

```python
with trace_request(session_id=sid, user_id=uid, user_input=text) as trace:
    trace.set_output(output)
    trace.set_usage({"input_tokens": 1, "output_tokens": 2})
```

### `RequestTrace`

Methods:

- `set_output(output)`
- `set_file_outputs(files)`
- `set_usage(usage)`
- `set_error()`
- `finish(error=False)`

## Troubleshooting

If traces do not appear:

1. Confirm `OTEL_ENABLED=true`.
2. Confirm `OTEL_EXPORTER_OTLP_ENDPOINT` points to an OTLP HTTP traces endpoint or collector base URL.
3. Check application logs for `OTel tracer initialised`.
4. Verify your collector exports to Langfuse correctly.

If Kubernetes attributes do not appear in Langfuse:

1. Confirm the Kubernetes env vars are present in the running container.
2. Confirm a request root span is created via `trace_request()`.
3. Look for metadata keys such as `k8s_namespace_name`, `k8s_pod_name`, and `deployment_environment` in Langfuse trace metadata.

## Build and Publish

```bash
python -m pip install --upgrade build twine
python -m build
python -m twine check dist/*
python -m twine upload dist/*
```

For TestPyPI:

```bash
python -m twine upload --repository testpypi dist/*
```
