Installation
pip install sentrial
# With LangChain support
pip install sentrial langchain-core
Quick Start
import sentrial
# Configure (or set SENTRIAL_API_KEY env var)
sentrial.configure(api_key="sentrial_live_xxx")
# Track an interaction
interaction = sentrial.begin(
user_id="user_123",
event="chat_message",
input="User's question"
)
# Your agent logic...
response = agent.run(user_input)
# Finish with outcome
interaction.finish(output=response, success=True)
Module Functions
Configure the default Sentrial client.
sentrial.configure(
api_key: str = None, # API key (or use SENTRIAL_API_KEY env)
api_url: str = None, # API URL (default: https://api.sentrial.com)
fail_silently: bool = True, # If True, SDK errors are logged but won't crash your app
pii: bool | PiiConfig = None, # PII redaction (pass True to auto-fetch from server)
batching: bool | BatcherConfig = None, # Event batching for high-throughput agents
)
sentrial.begin()
Begin tracking an interaction. Returns an Interaction object.
Custom event ID (auto-generated if omitted).
Conversation ID for grouping.
interaction = sentrial.begin(
user_id="user_12345",
event="support_request",
input="Help me reset my password",
convo_id="conv_789",
metadata={"channel": "web_chat"}
)
Interaction Class
Returned by sentrial.begin(). Provides methods to track events and finish the interaction.
interaction.finish()
Finish the interaction and record final metrics.
interaction.finish(
output: str = None, # Output/response from interaction
success: bool = True, # Whether it succeeded
failure_reason: str = None, # Reason if success=False
estimated_cost: float = None, # Cost in USD
custom_metrics: dict = None, # Custom metrics
duration_ms: int = None, # Duration in milliseconds (auto-calculated if omitted)
prompt_tokens: int = None, # Prompt tokens used
completion_tokens: int = None, # Completion tokens used
total_tokens: int = None # Total tokens used
)
# Success example
interaction.finish(
output="Password reset email sent!",
success=True,
estimated_cost=0.023,
custom_metrics={"satisfaction": 4.5}
)
# Failure example
interaction.finish(
success=False,
failure_reason="User not found in database"
)
Track a tool call within the interaction.
interaction.track_tool_call(
tool_name="search_knowledge_base",
tool_input={"query": "password reset"},
tool_output={"results": ["KB-001", "KB-002"]},
reasoning="User needs password help",
estimated_cost=0.001
)
interaction.track_decision()
Track an agent decision.
interaction.track_decision(
reasoning="Will search KB before escalating",
alternatives=["escalate_to_human", "ask_clarifying_question"],
confidence=0.92
)
SentrialClient Class
For full control over session management.
Constructor
from sentrial import SentrialClient
client = SentrialClient(
api_key: str = None, # API key (or SENTRIAL_API_KEY env)
api_url: str = None # API URL (or SENTRIAL_API_URL env)
)
client.create_session()
Create a new tracking session. Returns the session ID.
session_id = client.create_session(
name: str, # Descriptive name
agent_name: str, # Agent identifier (for grouping)
user_id: str, # External user ID
parent_session_id: str = None, # Parent session ID (for sub-sessions)
convo_id: str = None, # Conversation ID (for grouping)
metadata: dict = None # Custom metadata
) -> str
client.track_tool_call(
session_id: str,
tool_name: str,
tool_input: dict,
tool_output: dict,
reasoning: str = None,
estimated_cost: float = 0.0,
tool_error: dict = None, # Error details if the tool call failed
token_count: int = None, # Tokens used by the tool call
trace_id: str = None, # Trace ID for distributed tracing
span_id: str = None, # Span ID for distributed tracing
metadata: dict = None # Additional metadata
) -> dict
client.track_decision()
client.track_decision(
session_id: str,
reasoning: str,
alternatives: list[str] = None,
confidence: float = None,
estimated_cost: float = 0.0,
token_count: int = None
) -> dict
client.complete_session()
Complete a session with final metrics.
client.complete_session(
session_id: str,
success: bool = True,
failure_reason: str = None,
estimated_cost: float = None,
custom_metrics: dict = None,
duration_ms: int = None,
prompt_tokens: int = None,
completion_tokens: int = None,
total_tokens: int = None,
user_input: str = None, # End-user input for this session
assistant_output: str = None # Agent/assistant response
) -> dict
client.track_error()
client.track_error(
session_id: str,
error_message: str,
error_type: str = None, # e.g. "ValueError", "APIError"
tool_name: str = None, # Tool that caused the error
stack_trace: str = None, # Stack trace for debugging
metadata: dict = None
) -> dict
LLM Auto-Wrappers
Automatically track all LLM calls with token counts, cost, and latency.
from openai import OpenAI
from sentrial import wrap_openai, configure
configure(api_key="sentrial_live_xxx")
# Wrap your LLM client — all calls are now auto-tracked
client = wrap_openai(OpenAI())
interaction = sentrial.begin(user_id="user_123", event="chat", input=user_query)
# This call is automatically tracked
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": user_query}]
)
interaction.finish(output=response.choices[0].message.content)
Also available: wrap_anthropic(client), wrap_google(model), wrap_llm(client) (auto-detect).
Decorators
from sentrial import tool, session, configure
configure(api_key="sentrial_live_xxx")
@tool("search_kb")
def search_knowledge_base(query: str) -> dict:
"""Automatically tracked — inputs, outputs, errors, duration."""
return kb.search(query)
@session("support-agent")
def handle_request(user_id: str, message: str) -> str:
"""Auto-creates session, tracks all @tool calls inside."""
results = search_knowledge_base(message)
return format_response(results)
# Works with async too
@session("async-agent")
async def handle_async(user_id: str, message: str) -> str:
results = await async_search(message)
return results
Context Manager
from sentrial import SentrialClient
client = SentrialClient(api_key="sentrial_live_xxx")
# Auto-finishes on exit, tracks success/failure
with client.begin(user_id="user_123", event="chat", input="Hello") as interaction:
response = agent.run("Hello")
interaction.set_output(response)
# Also works with async (use AsyncSentrialClient or module-level begin_async)
async_client = AsyncSentrialClient(api_key="sentrial_live_xxx")
async with async_client.begin(user_id="user_123", event="chat") as interaction:
response = await agent.run("Hello")
interaction.set_output(response)
Event Batching
Queue tracking calls and flush periodically to reduce HTTP overhead.
from sentrial import configure, BatcherConfig
# Simple: just enable batching
configure(api_key="sentrial_live_xxx", batching=True)
# Advanced: customize flush behavior
configure(
api_key="sentrial_live_xxx",
batching=BatcherConfig(
enabled=True,
flush_interval=2.0, # Flush every 2s (default: 1.0)
flush_threshold=20, # Flush after 20 events (default: 10)
max_queue_size=500, # Drop events if queue exceeds this (default: 1000)
)
)
# Flush manually before shutdown
client.flush()
client.shutdown()
PII Redaction
Automatically redact sensitive data before it leaves your infrastructure.
# Auto-fetch your org's PII config from the server
configure(api_key="sentrial_live_xxx", pii=True)
# Or configure locally
from sentrial.redact import PiiConfig, PiiBuiltinPatterns, PiiCustomPattern
from sentrial import SentrialClient
client = SentrialClient(
api_key="sentrial_live_xxx",
pii=PiiConfig(
enabled=True,
mode="label", # "label" | "hash" | "remove"
fields=["user_input", "assistant_output", "metadata", "reasoning"],
builtin_patterns=PiiBuiltinPatterns(
emails=True,
phones=True,
ssns=True,
credit_cards=True,
),
custom_patterns=[
PiiCustomPattern(label="api_key", pattern=r"sk-[a-zA-Z0-9]{32,}"),
],
),
)
Cost Calculation Helpers
Static methods to calculate LLM API costs.
calculate_openai_cost()
cost = SentrialClient.calculate_openai_cost(
model="gpt-4o",
input_tokens=1000,
output_tokens=500
)
# Returns: 0.0075 (USD)
calculate_anthropic_cost()
cost = SentrialClient.calculate_anthropic_cost(
model="claude-sonnet-4",
input_tokens=1000,
output_tokens=500
)
# Returns: 0.0105 (USD)
calculate_google_cost()
cost = SentrialClient.calculate_google_cost(
model="gemini-2.0-flash",
input_tokens=1000,
output_tokens=500
)
Async Support
All SDK classes have async equivalents for use with asyncio.
import sentrial
# Async module-level API
sentrial.configure(api_key="sentrial_live_xxx")
interaction = await sentrial.begin_async(
user_id="user_123",
event="chat_message",
input="User's question"
)
response = await agent.run(user_input)
await interaction.finish(output=response)
# Async client
from sentrial import AsyncSentrialClient
client = AsyncSentrialClient(api_key="sentrial_live_xxx")
session_id = await client.create_session(
name="Async session",
agent_name="my-agent",
user_id="user_123"
)
await client.track_tool_call(
session_id=session_id,
tool_name="search",
tool_input={"query": "test"},
tool_output={"results": []}
)
await client.complete_session(session_id=session_id, success=True)
client.flush()
Flush any queued events immediately. No-op if batching is not enabled.
client.shutdown()
Shut down the event batcher, flushing remaining events. Call this before your process exits to ensure all events are sent.
LangChain Integration
Next Steps