Metadata-Version: 2.4
Name: sideseat
Version: 1.0.5
Summary: Debug, trace, and understand your AI agents
Project-URL: Homepage, https://sideseat.ai
Project-URL: Documentation, https://sideseat.ai/docs
Project-URL: Repository, https://github.com/sideseat/sideseat
Author-email: SideSeat <support@sideseat.ai>
License-Expression: MIT
License-File: LICENSE
Keywords: ai,llm,observability,opentelemetry,telemetry,tracing
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
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: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: opentelemetry-api>=1.20.0
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.20.0
Requires-Dist: opentelemetry-sdk>=1.20.0
Provides-Extra: all
Requires-Dist: logfire>=0.50.0; extra == 'all'
Requires-Dist: openinference-instrumentation-autogen-agentchat>=0.1.0; extra == 'all'
Requires-Dist: openinference-instrumentation-crewai>=0.1.0; extra == 'all'
Requires-Dist: openinference-instrumentation-langchain>=0.1.0; extra == 'all'
Provides-Extra: autogen
Requires-Dist: openinference-instrumentation-autogen-agentchat>=0.1.0; extra == 'autogen'
Provides-Extra: crewai
Requires-Dist: openinference-instrumentation-crewai>=0.1.0; extra == 'crewai'
Provides-Extra: dev
Requires-Dist: mypy>=1.13.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.8.0; extra == 'dev'
Provides-Extra: langchain
Requires-Dist: openinference-instrumentation-langchain>=0.1.0; extra == 'langchain'
Provides-Extra: openai-agents
Requires-Dist: logfire>=0.50.0; extra == 'openai-agents'
Provides-Extra: pydantic-ai
Requires-Dist: logfire>=0.50.0; extra == 'pydantic-ai'
Description-Content-Type: text/markdown

# SideSeat Python SDK

**AI Development Workbench** — Debug, trace, and understand your AI agents.

[![PyPI](https://img.shields.io/pypi/v/sideseat)](https://pypi.org/project/sideseat/)
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

## Table of Contents

- [What is SideSeat?](#what-is-sideseat)
- [Quick Start](#quick-start)
- [Installation](#installation)
- [Framework Examples](#framework-examples)
- [Configuration](#configuration)
- [Advanced Usage](#advanced-usage)
- [Data and Privacy](#data-and-privacy)
- [Troubleshooting](#troubleshooting)
- [API Reference](#api-reference)

## What is SideSeat?

AI agents are hard to debug. Requests fly by, context builds up, and when something fails you're left guessing.

SideSeat captures every LLM call, tool call, and agent decision, then displays them in a web UI as they happen. Run it locally during development, or deploy to your private cloud for team visibility.

Built on [OpenTelemetry](https://opentelemetry.io/) — the open standard already supported by most AI frameworks.

**Features:**

- **Zero config** — Auto-detects and instruments your AI framework
- **Real-time tracing** — Watch LLM requests and tool calls as they happen
- **Message threading** — See full conversations, tool calls, and images
- **Cost tracking** — Automatic token counting and cost calculation

**Supported frameworks:** Strands Agents, LangChain, CrewAI, AutoGen, OpenAI Agents, Google ADK, PydanticAI

## Quick Start

**Requirements:** Python 3.10+, Node.js 18+ (for the server)

**1. Start the server**

```bash
npx sideseat
```

**2. Install and initialize**

```bash
pip install sideseat
```

```python
from sideseat import SideSeat

SideSeat()

# Your agent code here — traces are captured automatically
```

**3. View traces**

Open [localhost:5389](http://localhost:5389) and run your agent. Traces appear in real time.

## Installation

```bash
pip install sideseat                    # Core SDK
pip install "sideseat[langchain]"       # + LangChain instrumentation
pip install "sideseat[crewai]"          # + CrewAI instrumentation
pip install "sideseat[autogen]"         # + AutoGen instrumentation
pip install "sideseat[openai-agents]"   # + OpenAI Agents instrumentation
pip install "sideseat[pydantic-ai]"     # + PydanticAI instrumentation
pip install "sideseat[all]"             # All frameworks
```

Strands Agents and Google ADK require only the core SDK.

## Framework Examples

SideSeat auto-detects installed frameworks in this order: Strands, LangChain, CrewAI, AutoGen, OpenAI Agents, Google ADK, PydanticAI. When multiple frameworks are installed, use the `framework` parameter to select one explicitly.

### Strands Agents

Auto-detected. No explicit framework parameter needed.

```python
from sideseat import SideSeat
from strands import Agent

SideSeat()

agent = Agent(model="anthropic.claude-sonnet-4-5-20250929-v1:0")
response = agent("What is 2+2?")
print(response)
```

### LangChain

```python
from sideseat import SideSeat, Frameworks
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage

SideSeat(framework=Frameworks.LangChain)

llm = ChatOpenAI(model="gpt-5-mini")
response = llm.invoke([HumanMessage(content="Hello!")])
print(response.content)
```

### CrewAI

```python
from sideseat import SideSeat, Frameworks
from crewai import Agent, Task, Crew

SideSeat(framework=Frameworks.CrewAI)

researcher = Agent(
    role="Researcher",
    goal="Find information",
    backstory="Expert researcher",
)
task = Task(description="Research AI trends", agent=researcher)
crew = Crew(agents=[researcher], tasks=[task])
result = crew.kickoff()
print(result)
```

### AutoGen

```python
from sideseat import SideSeat, Frameworks
from autogen import AssistantAgent, UserProxyAgent

SideSeat(framework=Frameworks.AutoGen)

llm_config = {"model": "gpt-5-mini", "api_key": "your-api-key"}
assistant = AssistantAgent("assistant", llm_config=llm_config)
user = UserProxyAgent("user", code_execution_config=False)
user.initiate_chat(assistant, message="Hello!")
```

### OpenAI Agents

```python
from sideseat import SideSeat, Frameworks
from agents import Agent, Runner

SideSeat(framework=Frameworks.OpenAIAgents)

agent = Agent(name="Assistant", instructions="You are helpful.")
result = Runner.run_sync(agent, "What is the capital of France?")
print(result.final_output)
```

### Google ADK

Auto-detected. No explicit framework parameter needed.

```python
from sideseat import SideSeat
from google.adk.agents import Agent

SideSeat()

agent = Agent(model="gemini-2.0-flash")
response = agent.generate_content("Explain quantum computing")
print(response.text)
```

### PydanticAI

```python
from sideseat import SideSeat, Frameworks
from pydantic_ai import Agent

SideSeat(framework=Frameworks.PydanticAI)

agent = Agent("openai:gpt-5-mini", system_prompt="Be concise.")
result = agent.run_sync("What is Python?")
print(result.data)
```

## Configuration

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `SIDESEAT_ENDPOINT` | `http://127.0.0.1:5388` | Server URL |
| `SIDESEAT_PROJECT` | `default` | Project identifier |
| `SIDESEAT_API_KEY` | — | Authentication key |
| `SIDESEAT_DISABLED` | `false` | Disable all telemetry |
| `SIDESEAT_DEBUG` | `false` | Enable verbose logging |

### Constructor Parameters

```python
SideSeat(
    endpoint="http://localhost:5388",
    project_id="my-project",
    api_key="pk-...",
    framework=Frameworks.LangChain,
    auto_instrument=True,
    service_name="my-app",
    service_version="1.0.0",
    enable_traces=True,
    enable_metrics=True,
    enable_logs=False,
    capture_content=True,
    encode_binary=True,
    disabled=False,
    debug=False,
)
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `endpoint` | `str` | `http://127.0.0.1:5388` | Server URL |
| `project_id` | `str` | `default` | Project identifier |
| `api_key` | `str` | `None` | Authentication key |
| `framework` | `str` | Auto-detected | Framework to instrument |
| `auto_instrument` | `bool` | `True` | Enable framework instrumentation |
| `service_name` | `str` | Framework name | Application name in traces |
| `service_version` | `str` | Framework version | Application version |
| `enable_traces` | `bool` | `True` | Export trace spans |
| `enable_metrics` | `bool` | `True` | Export metrics |
| `enable_logs` | `bool` | `False` | Export logs |
| `capture_content` | `bool` | `True` | Capture LLM prompts and responses |
| `encode_binary` | `bool` | `True` | Base64 encode binary data |
| `disabled` | `bool` | `False` | Disable all telemetry |
| `debug` | `bool` | `False` | Enable verbose logging |

**Resolution order:** Constructor → `SIDESEAT_*` env → `OTEL_*` env → defaults

## Advanced Usage

### Context Manager

```python
with SideSeat() as client:
    run_my_agent()
# Traces flushed and connection closed automatically
```

### Global Instance

```python
import sideseat

sideseat.init(project_id="my-project")  # Initialize once
client = sideseat.get_client()          # Access anywhere
sideseat.shutdown()                     # Clean up
```

### Custom Spans

```python
client = SideSeat()

with client.span("process-request") as span:
    span.set_attribute("user_id", "12345")
    result = do_work()
# Exceptions recorded automatically with stack traces
```

### Async Support

```python
import asyncio
from sideseat import SideSeat

async def main():
    with SideSeat():
        result = await my_async_agent.run("Hello")
        print(result)

asyncio.run(main())
```

### Debug Exporters

```python
client = SideSeat()
client.telemetry.setup_console_exporter()             # Print to stdout
client.telemetry.setup_file_exporter("traces.jsonl")  # Write to file
```

### Disabled Mode

```python
SideSeat(disabled=True)  # Or set SIDESEAT_DISABLED=true
```

### Existing OpenTelemetry Setup

If a `TracerProvider` already exists, SideSeat adds its exporter to the existing provider.

### Unsupported Frameworks

```python
SideSeat(auto_instrument=False)
# Use your framework's native OpenTelemetry instrumentation
```

## Data and Privacy

**What is collected:**

- Trace spans with timing and hierarchy
- LLM prompts and responses (when `capture_content=True`)
- Token counts and model names
- Errors and stack traces

**Where it goes:**

All data is sent to your self-hosted server. Nothing leaves your infrastructure.

**Resilience:**

- Up to 2,048 spans buffered in memory
- Batched exports every 5 seconds
- 30-second timeout per export
- Server downtime does not affect your application

## Troubleshooting

| Problem | Solution |
|---------|----------|
| Connection refused | Server not running. Run `npx sideseat` |
| No traces appear | Check endpoint with `SIDESEAT_DEBUG=true` |
| Wrong framework detected | Set `framework=Frameworks.X` explicitly |
| Duplicate traces | Initialize `SideSeat()` once per process |
| Import error for extras | Install extras: `pip install "sideseat[langchain]"` |

## API Reference

### SideSeat

```python
client = SideSeat(**kwargs)
```

**Properties:**

| Name | Type | Description |
|------|------|-------------|
| `config` | `Config` | Immutable configuration |
| `telemetry` | `TelemetryClient` | Access to debug exporters |
| `tracer_provider` | `TracerProvider` | OpenTelemetry tracer provider |
| `is_disabled` | `bool` | Whether telemetry is disabled |

**Methods:**

| Name | Returns | Description |
|------|---------|-------------|
| `span(name)` | `ContextManager[Span]` | Create a custom span |
| `get_tracer(name)` | `Tracer` | Get an OpenTelemetry tracer |
| `force_flush(timeout_millis)` | `bool` | Export pending spans immediately |
| `validate_connection(timeout)` | `bool` | Test server connectivity |
| `shutdown(timeout_millis)` | `None` | Flush pending spans and shut down |

### Frameworks

```python
Frameworks.Strands
Frameworks.LangChain
Frameworks.CrewAI
Frameworks.AutoGen
Frameworks.OpenAIAgents
Frameworks.GoogleADK
Frameworks.PydanticAI
```

### Module Functions

| Function | Returns | Description |
|----------|---------|-------------|
| `init(**kwargs)` | `SideSeat` | Create global instance |
| `get_client()` | `SideSeat` | Get global instance |
| `shutdown()` | `None` | Shut down global instance |
| `is_initialized()` | `bool` | Check if initialized |

### Utilities

| Function | Description |
|----------|-------------|
| `encode_value(value)` | JSON-encode a value; base64 for binary |
| `span_to_dict(span)` | Convert span to dictionary |
| `JsonFileSpanExporter` | JSONL file exporter class |

## Resources

- [Documentation](https://sideseat.ai/docs)
- [GitHub Discussions](https://github.com/sideseat/sideseat/discussions)
- [Issue Tracker](https://github.com/sideseat/sideseat/issues)

## License

[MIT](LICENSE)
