Skip to main content

Debug, trace, and understand your AI agents

Project description

SideSeat Python SDK

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

PyPI Python 3.10+ License: MIT

Table of Contents

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 — 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

npx sideseat

2. Install and initialize

pip install sideseat
from sideseat import SideSeat

SideSeat()

# Your agent code here — traces are captured automatically

3. View traces

Open localhost:5389 and run your agent. Traces appear in real time.

Installation

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.

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

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

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

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

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.

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

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

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

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

Global Instance

import sideseat

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

Custom Spans

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

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

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

Disabled Mode

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

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

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

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

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sideseat-1.0.5.tar.gz (86.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sideseat-1.0.5-py3-none-any.whl (17.5 kB view details)

Uploaded Python 3

File details

Details for the file sideseat-1.0.5.tar.gz.

File metadata

  • Download URL: sideseat-1.0.5.tar.gz
  • Upload date:
  • Size: 86.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.22

File hashes

Hashes for sideseat-1.0.5.tar.gz
Algorithm Hash digest
SHA256 1598f8dd844e3176258aed7a725aa41ef46bffc84f2674efc1e96d5d9b8beb9b
MD5 488e196c1baa6ada00893c4c1c6a0fe4
BLAKE2b-256 a82655baf2d65d9459425a9e4578064bef3d25f815f78302335b616883df3d54

See more details on using hashes here.

File details

Details for the file sideseat-1.0.5-py3-none-any.whl.

File metadata

  • Download URL: sideseat-1.0.5-py3-none-any.whl
  • Upload date:
  • Size: 17.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.22

File hashes

Hashes for sideseat-1.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 dc0e13a978ba4982fc7e9079c0e34832264572de3c5abd5ce8e70e7bbd8eccfb
MD5 f438d69d1e484ec0e0ea5a44baa9b2e5
BLAKE2b-256 d7265614ba1b3fae5479a790cd6cb95dee3e5221b184e9e1fc365a9334a4ad8c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page