Metadata-Version: 2.4
Name: fortifyroot-ocelle
Version: 1.0.0
Summary: FortifyRoot Ocelle SDK for LLM observability
License: Apache-2.0
License-File: LICENSE
Keywords: ocelle,llm,genai,observability,tracing,opentelemetry,langchain,openai,anthropic
Author: FortifyRoot
Author-email: sdk@fortifyroot.com
Requires-Python: >=3.10,<4
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Provides-Extra: anthropic
Provides-Extra: bedrock
Provides-Extra: datasets
Provides-Extra: google-generativeai
Provides-Extra: langchain
Provides-Extra: litellm
Provides-Extra: llamaindex
Provides-Extra: openai
Requires-Dist: aiohttp (>=3.11.11,<4.0.0)
Requires-Dist: anthropic (>=0.49,<1.0.0) ; extra == "anthropic" or extra == "bedrock"
Requires-Dist: boto3 (>=1.34.120,<2) ; extra == "bedrock"
Requires-Dist: colorama (>=0.4.6,<0.5.0)
Requires-Dist: cuid (>=0.4,<0.5)
Requires-Dist: deprecated (>=1.2.14,<2.0.0)
Requires-Dist: google-genai (>=1.0.0,<2) ; extra == "google-generativeai"
Requires-Dist: google-re2 (>=1.1)
Requires-Dist: httpx (>=0.27,<1)
Requires-Dist: inflection (>=0.5.1,<0.6.0)
Requires-Dist: jinja2 (>=3.1.5,<4.0.0)
Requires-Dist: langchain (>=0.2.5,<2.0.0) ; extra == "langchain"
Requires-Dist: langchain-openai (>=0.1.15,<2.0.0) ; extra == "langchain"
Requires-Dist: litellm (>=1.71.2,<2,!=1.82.7,!=1.82.8) ; extra == "litellm"
Requires-Dist: llama-index (>=0.14.12,<0.15.0) ; extra == "llamaindex"
Requires-Dist: openai (>=1.31.1,<3) ; extra == "openai"
Requires-Dist: opentelemetry-api (>=1.38.0,<2.0.0)
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc (>=1.38.0,<2.0.0)
Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.38.0,<2.0.0)
Requires-Dist: opentelemetry-instrumentation (>=0.59b0)
Requires-Dist: opentelemetry-instrumentation-logging (>=0.59b0)
Requires-Dist: opentelemetry-instrumentation-redis (>=0.59b0)
Requires-Dist: opentelemetry-instrumentation-requests (>=0.59b0)
Requires-Dist: opentelemetry-instrumentation-sqlalchemy (>=0.59b0)
Requires-Dist: opentelemetry-instrumentation-threading (>=0.59b0)
Requires-Dist: opentelemetry-instrumentation-urllib3 (>=0.59b0)
Requires-Dist: opentelemetry-sdk (>=1.38.0,<2.0.0)
Requires-Dist: opentelemetry-semantic-conventions (>=0.59b0)
Requires-Dist: pandas (>=1.0.0) ; extra == "datasets"
Requires-Dist: pydantic (>=1,<3)
Requires-Dist: tenacity (>=8.2.3,<10.0)
Requires-Dist: tokenizers (>=0.13.0) ; extra == "bedrock"
Requires-Dist: wrapt (>=1.14.0,<2.0.0)
Project-URL: Documentation, https://docs.fortifyroot.com
Project-URL: Repository, https://github.com/FortifyRoot/ocelle-py
Description-Content-Type: text/markdown

# FortifyRoot Ocelle

FortifyRoot Ocelle is the Python SDK for FortifyRoot LLM observability and runtime safety. Add one initialization call to your application and Ocelle will instrument supported LLM providers and frameworks, emit OpenTelemetry traces/metrics/logs to FortifyRoot, and apply configured prompt/completion safety rules before sensitive content leaves or enters your application flow.

Ocelle is built on a FortifyRoot-maintained OpenLLMetry fork, vendored into this repository for dependency isolation, safety extensions, and stable FortifyRoot packaging.

## What Ocelle Captures

- LLM request/response traces with provider, model, span hierarchy, token usage, latency, retry-attempt, and streaming timing metadata.
- Framework spans for workflows, tasks, agents, and tools through decorators and supported framework integrations.
- Optional prompt and completion content when content tracing is enabled.
- Safety findings for prompt and completion content, including masking decisions and rule metadata.
- OTLP traces, metrics, and correlated logs for FortifyRoot ingestion.

## Installation

Ocelle supports Python 3.10 and newer.

```bash
pip install fortifyroot-ocelle
```

Install only the provider/framework extras your application uses:

```bash
pip install "fortifyroot-ocelle[openai]"
pip install "fortifyroot-ocelle[openai,anthropic,langchain]"
pip install "fortifyroot-ocelle[bedrock,litellm,llamaindex]"
```

## Quick Start

```python
import fortifyroot.ocelle as ocelle

ocelle.init(
    app_name="my-llm-app",
    api_key="fr_sk_...",
    resource_attributes={"environment": "prod"},
)

from openai import OpenAI

client = OpenAI()
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello!"}],
)
```

The canonical SDK import is:

```python
import fortifyroot.ocelle as ocelle
```

The package also exposes a convenience alias:

```python
import ocelle
```

## Supported Providers And Frameworks

This table lists the launch-supported instrumentation exposed through `fortifyroot.ocelle.Instruments` and SDK extras. Package ranges are the ranges declared by this SDK; they are not a claim about the latest upstream release.

| Library / framework | Instrument | Extra | Declared package range | Sync | Async | Streaming | Safety |
|---|---|---|---|---:|---:|---:|---|
| OpenAI | `Instruments.OPENAI` | `openai` | `openai >=1.31.1,<3` | Yes | Yes | Yes | Prompt + completion, including streaming paths |
| Anthropic | `Instruments.ANTHROPIC` | `anthropic` | `anthropic >=0.49,<1.0.0` | Yes | Yes | Yes | Prompt + completion, including streaming paths |
| Google GenAI / Gemini | `Instruments.GOOGLE_GENERATIVEAI` | `google-generativeai` | `google-genai >=1.0.0,<2` | Yes | Yes | Yes | Prompt + completion, including streaming paths |
| AWS Bedrock Runtime | `Instruments.BEDROCK` | `bedrock` | `boto3 >=1.34.120,<2` | Yes | No native async client path | Yes | Prompt + completion for invoke/converse paths, including stream wrappers |
| LiteLLM | `Instruments.LITELLM` | `litellm` | `litellm >=1.71.2,<2,!=1.82.7,!=1.82.8` | Yes | Yes | Yes | Prompt + completion, including streaming paths |
| LangChain | `Instruments.LANGCHAIN` | `langchain` | `langchain >=0.2.5,<2.0.0`, `langchain-openai >=0.1.15,<2.0.0` | Yes | Yes | Provider-dependent | Prompt + completion for supported chat/LLM paths |
| LangGraph | via `Instruments.LANGCHAIN` | install with app | Covered through LangChain/OpenAI launch path | Yes | Yes | Provider-dependent | Same supported path as LangChain |
| LlamaIndex | `Instruments.LLAMA_INDEX` | `llamaindex` | `llama-index >=0.14.12,<0.15.0` | Yes | Yes | Yes | Prompt + completion, including streaming paths |

For provider-role behavior, routed providers such as OpenRouter, LiteLLM, Bedrock, Azure OpenAI, and planned/mapper-supported providers, see [Provider Support](docs/PROVIDERS.md). That document is the source of truth for what is launch-certified versus planned.

## Runtime Safety

Ocelle can poll a FortifyRoot SDK config profile and apply configured safety rules locally in the SDK. Rules can inspect prompt and completion text and currently resolve to `ALLOW` or `MASK`.

Supported safety categories are:

`PII`, `PCI`, `PHI`, `API_KEY`, `SECRET`, `PROMPT_INJECTION`, `PROFANITY`, `TOXICITY`, `VIOLENCE`, `SELF_HARM`, `CONFIDENTIAL`, and `CUSTOM`.

Rules can be backed by regex matchers, string-list matchers, or approved user-defined detectors. Masking is applied before the instrumented provider/framework returns the text to application code where the integration can safely mutate the response object or stream chunk.

Because Ocelle is open source, the SDK's enforcement flow is visible by design. Organization-specific safety policy is fetched at runtime from your FortifyRoot SDK config profile, so public code review exposes the engine and built-in defaults, not customer-specific rules.

## Configuration

### Environment Variables

| Environment variable | Description | Default |
|---|---|---|
| `FORTIFYROOT_API_KEY` | FortifyRoot API key | None |
| `FORTIFYROOT_BASE_URL` | FortifyRoot API endpoint | `https://api.fortifyroot.com` |
| `FORTIFYROOT_TRACE_CONTENT` | Capture prompt/response content | `true` |
| `FORTIFYROOT_TRACING_ENABLED` | Enable trace export | `true` |
| `FORTIFYROOT_METRICS_ENABLED` | Enable metric export | `true` |
| `FORTIFYROOT_LOGGING_ENABLED` | Enable OTLP log export and synthetic span-end logs | `false` |

When `FORTIFYROOT_LOGGING_ENABLED=true`, Python `logging` records emitted inside active spans are exported with trace/span correlation. `print(...)`, stdout, and stderr capture are not included; use Python `logging` for application logs.

### Programmatic Configuration

```python
import fortifyroot.ocelle as ocelle
from fortifyroot.ocelle import Instruments

ocelle.init(
    app_name="my-llm-app",
    api_key="fr_sk_...",
    api_endpoint="https://api.fortifyroot.com",
    trace_content=True,
    instruments={Instruments.OPENAI, Instruments.LANGCHAIN},
)
```

### Fluent API

```python
import fortifyroot.ocelle as ocelle
from opentelemetry.sdk.trace.sampling import TraceIdRatioBased

ocelle.configure() \
    .app_name("my-llm-app") \
    .api_key("fr_sk_...") \
    .trace_content(False) \
    .sampler(TraceIdRatioBased(0.1)) \
    .init()
```

## Decorators

Use decorators to add trace structure around your own application logic:

```python
from fortifyroot.ocelle import agent, task, tool, workflow

@workflow(name="document_qa")
def answer_question(document: str, question: str):
    chunks = split_document(document)
    relevant = find_relevant_chunks(chunks, question)
    return generate_answer(relevant, question)

@task(name="split_document")
def split_document(document: str):
    return chunks

@task(name="find_relevant")
def find_relevant_chunks(chunks, question):
    return relevant_chunks

@task(name="generate_answer")
def generate_answer(context, question):
    return answer
```

## Association Properties

Attach properties to traces for filtering and correlation:

```python
import fortifyroot.ocelle as ocelle

ocelle.init(app_name="my-app", api_key="fr_sk_...")

ocelle.set_association_properties({
    "user_id": "user_12345",
    "session_id": "sess_abc",
    "conversation_id": "conv_xyz",
})
```

## Network Requirements

If your app runs in a private subnet, VPC, Kubernetes cluster, or locked-down runtime, allow outbound HTTPS egress on TCP 443 to `api.fortifyroot.com`.

Ocelle exports telemetry over OTLP/HTTP to:

- `https://api.fortifyroot.com/v1/traces`
- `https://api.fortifyroot.com/v1/metrics`
- `https://api.fortifyroot.com/v1/logs`

If safety enforcement is enabled with `config_profile_id`, the SDK also polls:

- `https://api.fortifyroot.com/v1/sdk/config/{config_profile_id}`

No inbound firewall rule is required. Hosted FortifyRoot usage does not require opening OTLP ports `4317` or `4318`. Your workload still needs separate egress to whichever LLM providers it calls.

## Privacy And Content Tracing

Disable prompt and response content capture with:

```bash
export FORTIFYROOT_TRACE_CONTENT=false
```

or programmatically:

```python
import fortifyroot.ocelle as ocelle

ocelle.init(
    app_name="my-app",
    api_key="fr_sk_...",
    trace_content=False,
)
```

Safety rules can still run when configured; content tracing controls what is exported as telemetry content.

## License And Attribution

Apache License, Version 2.0.

FortifyRoot Ocelle includes code derived from [OpenLLMetry](https://github.com/traceloop/openllmetry) and `traceloop-sdk` by Traceloop, licensed under the Apache License, Version 2.0. The license text and attribution are retained in [LICENSE](LICENSE).

