Metadata-Version: 2.5
Name: redlineai-sdk
Version: 0.3.0
Summary: Records what your AI agent did (model calls, tool calls, steps) and sends it to your Redline project.
License-Expression: MIT
Requires-Python: >=3.11
Requires-Dist: langfuse<6,>=5.0.2
Requires-Dist: openinference-instrumentation-bedrock
Requires-Dist: openinference-instrumentation-claude-agent-sdk
Requires-Dist: openinference-instrumentation-cohere
Requires-Dist: openinference-instrumentation-crewai; python_version < '3.14'
Requires-Dist: openinference-instrumentation-dspy
Requires-Dist: openinference-instrumentation-google-adk
Requires-Dist: openinference-instrumentation-google-genai
Requires-Dist: openinference-instrumentation-groq
Requires-Dist: openinference-instrumentation-haystack
Requires-Dist: openinference-instrumentation-llama-index
Requires-Dist: openinference-instrumentation-mcp
Requires-Dist: openinference-instrumentation-mistralai
Requires-Dist: openinference-instrumentation-ollama
Requires-Dist: openinference-instrumentation-openai-agents
Requires-Dist: openinference-instrumentation-smolagents
Requires-Dist: openinference-instrumentation-together
Requires-Dist: openinference-instrumentation-typesafe
Requires-Dist: openinference-instrumentation-vertexai
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.30
Requires-Dist: opentelemetry-instrumentation-anthropic
Requires-Dist: opentelemetry-instrumentation>=0.51b0
Requires-Dist: opentelemetry-sdk>=1.30
Requires-Dist: packaging
Requires-Dist: wrapt>=1.14
Provides-Extra: agno
Requires-Dist: openlit; extra == 'agno'
Provides-Extra: beeai
Requires-Dist: openinference-instrumentation-beeai; (python_version >= '3.11') and extra == 'beeai'
Description-Content-Type: text/markdown

# redlineai-sdk

Records what your AI agent did — every model call, tool call and step — and sends it to your Redline project.
The tracing API is [Langfuse's Python SDK](https://github.com/langfuse/langfuse-python) (MIT, `langfuse` 5.x), so an
agent is instrumented exactly as it would be for Langfuse.

```sh
pip install redlineai-sdk
```

```python
import redline
from redline import observe, propagate_attributes

redline.init(api_key="rl_…", url="https://your-redline-server")

@observe(as_type="agent")           # a step per call: input, output, timing, errors, nesting
def answer(question: str) -> str:
    ...                             # model calls inside are recorded too (see below)

@observe(as_type="tool")
def lookup_order(order_id: str) -> dict:
    ...

with propagate_attributes(session_id="chat-42", user_id="customer-7", tags=["support"]):
    answer("Where is my order?")    # every call in the same session_id is one conversation
```

`api_key` and `url` can come from `REDLINE_API_KEY` and `REDLINE_URL` instead. `init()` returns the client
(also `get_client()`); call `redline.flush()` before a short script exits.

## What Langfuse's SDK gives you here

| | |
| --- | --- |
| `@observe(name=, as_type=, capture_input=, capture_output=)` | a span per call; `as_type`: `span`, `generation`, `agent`, `tool`, `chain`, `retriever`, `embedding`, `evaluator`, `guardrail`, `event` |
| `propagate_attributes(session_id=, user_id=, tags=, metadata=, version=, trace_name=)` | trace fields for everything inside the block |
| `get_client().start_as_current_observation(...)`, `start_observation(...)` | spans without a decorator |
| `get_client().update_current_span(...)`, `update_current_generation(model=, usage_details=, cost_details=, ...)` | fill in the current step |
| `LangfuseMedia(content_bytes=, content_type=)` | images, audio and files, uploaded to Redline and shown in the app; set them as an observation's input, output or metadata (`update_current_generation(input=...)`) — Langfuse's SDK uploads media only from those fields |
| `redline.openai` | Langfuse's OpenAI drop-in: `from redline.openai import OpenAI` |
| `redline.langchain.CallbackHandler` | Langfuse's LangChain handler (see LangChain below) |

## Recorded without code

`init()` records the libraries your agent uses, each only when it is installed, the way Langfuse's integration
page for that library records it ([langfuse-docs](https://github.com/langfuse/langfuse-docs/tree/main/content/integrations),
`src/redline/_integrations.py`):

| Library | How (Langfuse's page) |
| --- | --- |
| OpenAI and every OpenAI-compatible API (DeepSeek, Groq, Together, Ollama, xAI, Qwen, Hugging Face…), Instructor, Ragas | Langfuse's OpenAI drop-in, switched on for every client (`model-providers/openai-py`) |
| LangChain, LangGraph, Deep Agents | Langfuse's LangChain handler on every run; session, user and tags from `propagate_attributes` or the run's metadata (`langfuse_session_id`, `langfuse_user_id`, `langfuse_tags`) (`frameworks/langchain`) |
| Anthropic | OpenLLMetry's `opentelemetry-instrumentation-anthropic` (`model-providers/anthropic`) |
| LiteLLM | LiteLLM's `langfuse_otel` callback (`frameworks/litellm-sdk`) |
| Pydantic AI | its own spans, `Agent.instrument_all()` (`frameworks/pydantic-ai`) |
| Strands, Amazon AgentCore | Strands' own spans (`frameworks/strands-agents`) |
| Microsoft Agent Framework | its own spans with sensitive data on (`frameworks/microsoft-agent-framework`) |
| LiveKit Agents | its own spans, all of them sent (`frameworks/livekit`) |
| Agno | OpenLIT's Agno instrumentor — `pip install "redlineai-sdk[agno]"` (`frameworks/agno-agents`) |
| LlamaIndex, CrewAI, OpenAI Agents, DSPy, Haystack, smolagents, Google ADK, Claude Agent SDK, Gemini, Vertex AI, Groq, TypeSafe | OpenInference instrumentors, as on their pages; BeeAI with `pip install "redlineai-sdk[beeai]"` |
| Bedrock, Mistral, Cohere, Ollama, Together SDKs, MCP | OpenInference instrumentors (Langfuse has no automatic integration for these) |
| Pipecat, Mirascope, Semantic Kernel, AutoGen | as on their Langfuse pages: Pipecat `PipelineTask(enable_tracing=True)`, Mirascope `@with_langfuse()`, AutoGen's own spans; their model calls through OpenAI are recorded by the drop-in |

Langfuse's pages switch on one integration at a time; `init()` switches on all installed ones. When one library
runs on another (LangChain, OpenAI Agents or LlamaIndex on the OpenAI client), the model client's record of a call
made inside a model call another integration records is not sent, so each model call is one generation.
Spans are sent with Langfuse's default filter (`is_default_export_span`), plus LiveKit's.

`init(auto_instrument=False)` turns all of this off.

If your app already set up OpenTelemetry, `init()` records into your tracer provider instead of replacing it.

## Scores

```python
from redline import get_client

langfuse = get_client()
langfuse.score_current_trace(name="user-feedback", value=1, data_type="BOOLEAN", comment="thumbs up")
langfuse.score_current_span(name="relevance", value=0.7)
langfuse.create_score(trace_id=..., observation_id=..., name="tone", value="friendly")  # CATEGORICAL
```

## Already on Langfuse's SDK

Keep your code and point it at Redline:

```sh
LANGFUSE_BASE_URL=https://your-redline-server
LANGFUSE_PUBLIC_KEY=pk-bt-<project id>     # shown on the Setup page
LANGFUSE_SECRET_KEY=rl_…
```

Tested with: `langfuse` 5.0.2, `langchain` 1.4 / `langchain-core` 1.6 / `langgraph` 1.2 (`create_agent`, `invoke`,
`ainvoke`, `stream`), `openai` 3.33, `openai-agents` (`Runner.run`), scores.
