Metadata-Version: 2.4
Name: moduna
Version: 0.1.6
Summary: Python OpenTelemetry helpers for Moduna AI traces.
Author: Moduna
License: MIT
Requires-Python: >=3.10
Requires-Dist: opentelemetry-api>=1.25.0
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.25.0
Requires-Dist: opentelemetry-sdk>=1.25.0
Provides-Extra: dev
Requires-Dist: basedpyright>=1.39.6; extra == 'dev'
Requires-Dist: build>=1.2.0; extra == 'dev'
Requires-Dist: langchain-google-genai>=4.0.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: python-dotenv>=1.0.0; extra == 'dev'
Requires-Dist: ruff>=0.8.0; extra == 'dev'
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.2.0; extra == 'langchain'
Description-Content-Type: text/markdown

# moduna

[![PyPI version](https://img.shields.io/pypi/v/moduna.svg)](https://pypi.org/project/moduna/)
[![Python versions](https://img.shields.io/pypi/pyversions/moduna.svg)](https://pypi.org/project/moduna/)
[![Package status](https://img.shields.io/pypi/status/moduna.svg)](https://pypi.org/project/moduna/)
[![License](https://img.shields.io/pypi/l/moduna.svg)](https://github.com/Moduna-AI/python-otel-sdk/blob/main/pyproject.toml)
[![GitHub release](https://img.shields.io/github/v/release/Moduna-AI/python-otel-sdk.svg)](https://github.com/Moduna-AI/python-otel-sdk/releases)
[![Upload Python Package](https://github.com/Moduna-AI/python-otel-sdk/actions/workflows/python-publish.yml/badge.svg)](https://github.com/Moduna-AI/python-otel-sdk/actions/workflows/python-publish.yml)
[![Downloads](https://img.shields.io/pypi/dm/moduna.svg)](https://pypi.org/project/moduna/)

Python OpenTelemetry helpers for Moduna AI traces.

`moduna` makes Moduna tracing easy to add with one import and one instantiation.
It configures OpenTelemetry once, exports traces to Moduna over OTLP HTTP, and
provides ergonomic helpers for Python LangChain applications.

## Installation

Install from PyPI:

```bash
pip install moduna
```

For LangChain callback support, install the optional LangChain dependency:

```bash
pip install "moduna[langchain]"
```

The PyPI distribution is `moduna`; the Python import package is `moduna_otel`.

When working from this repository, use `uv`:

```bash
uv sync --extra dev --extra langchain
```

## Getting Started

Set your Moduna API key with an environment variable:

```bash
export MODUNA_API_KEY="md_live_..."
```

Create the SDK once near application startup:

```python
from moduna_otel import ModunaOTEL

otel = ModunaOTEL(
    agent_name="support-agent",
    framework="langchain",
)
```

You can also pass the API key directly:

```python
from moduna_otel import ModunaOTEL

otel = ModunaOTEL(
    agent_name="support-agent",
    framework="langchain",
    api_key="md_live_...",
)
```

Multiple `ModunaOTEL(...)` instances share the same OpenTelemetry provider, so
creating per-module wrappers will not create duplicate exporters.

## LangChain

Create a LangChain callback handler and pass it into your model or chain call:

```python
from moduna_otel import ModunaOTEL

otel = ModunaOTEL(
    agent_name="support-agent",
    framework="langchain",
)

handler = otel.langchain_handler(
    {
        "conversation_id": "conversation-123",
        "session_id": "session-456",
    }
)

result = chain.invoke(
    {"input": "Summarize this ticket"},
    config={
        "callbacks": [handler],
        "metadata": {
            "conversationId": "conversation-123",
            "sessionId": "session-456",
        },
    },
)
```

The handler records LLM/chat model spans, prompts, completions, token usage when
available, streamed token events, Moduna conversation/session attributes, and
errors.

For applications that use global LangChain callbacks, registration is available
as a best-effort helper:

```python
otel.register_global_langchain_handler(
    {
        "conversation_id": "conversation-123",
        "session_id": "session-456",
    }
)
```

LangChain global callback APIs vary across versions. If global registration is
not available in your installed LangChain version, Moduna logs one warning and
continues without breaking application code.

## Manual Instrumentation

Use `instrument()` to wrap custom model calls or application work in a Moduna
CLIENT span:

```python
from moduna_otel import ModunaOTEL

otel = ModunaOTEL(agent_name="support-agent", framework="langchain")


def call_model(span):
    span.set_attribute("app.operation", "ticket-summary")
    return model.invoke("Summarize this ticket")


result = otel.instrument(
    "support-agent.summary",
    call_model,
    {
        "conversation_id": "conversation-123",
        "session_id": "session-456",
    },
)
```

If the callback raises an exception, the exception is recorded on the span and
then re-raised.

## Configuration

`ModunaOTEL` accepts keyword arguments:

```python
ModunaOTEL(
    agent_name="support-agent",
    framework="langchain",  # Python currently supports LangChain
    api_key=None,           # defaults to MODUNA_API_KEY
    headers=None,           # extra OTLP HTTP headers
    auto_shutdown=True,     # flush on process exit
)
```

It also accepts a mapping:

```python
otel = ModunaOTEL(
    {
        "agentName": "support-agent",
        "framework": "langchain",
        "autoShutdown": True,
    }
)
```

## Development

Install development dependencies:

```bash
uv sync --extra dev --extra langchain
```

Run tests:

```bash
uv run pytest
```

Format code:

```bash
uv run ruff format
```

Run the linter:

```bash
uv run ruff check
```

Build source and wheel distributions:

```bash
uv build
```

The built artifacts are written to `dist/`.

## Contributing

Contributions are welcome. Please keep changes focused and aligned with the
TypeScript SDK behavior.

Before opening a pull request:

1. Add or update focused pytest coverage for behavior changes.
2. Run `uv run pytest`.
3. Run `uv run ruff format` and `uv run ruff check`.
4. Run `uv build` for packaging changes.
5. Keep telemetry failures non-fatal to user application code.
6. Avoid broad refactors unless they are required for the change.

Useful areas for contribution include LangChain version compatibility,
additional token-usage extraction cases, and documentation examples for common
framework integrations.
