A unified read, query, and export layer for LLM and AI-agent traces.
Project description
traceport
Read agent conversations from any supported observability provider through one consistent API.
Trace providers store the same conversation in very different shapes: runs, records, observations,
spans, and cumulative message histories. traceport normalizes those records into sessions with one
readable, chronological transcript:
from traceport import TraceClient
client = TraceClient.from_env("langsmith")
sessions = client.list_sessions(project="Branna", since="7d")
session = client.get_session(sessions[0].id, project="Branna")
for event in session.agent_traces:
print(event.time, event.name, event.type, event.content)
session.agent_traces removes repeated cumulative histories while preserving system prompts, human
messages, paired tool calls, AI messages, and the timestamp where each event first appeared.
Install
Use uv and install only the provider extras you need:
uv add 'traceport[langsmith]'
uv add 'traceport[logfire]'
uv add 'traceport[langfuse]'
uv add 'traceport[phoenix]'
Install MCP support alongside a provider:
uv add 'traceport[mcp,langsmith]'
Helicone uses the core httpx dependency and does not require an extra.
When developing Traceport itself:
cd packages/traceport
uv sync --extra langsmith
Core Model
Traceport's primary hierarchy is:
Session
├── agent_traces readable, deduplicated conversation
└── full_traces complete provider executions
└── spans full normalized telemetry
session.agent_traces
Despite the name, agent_traces is a flat list[AgentSpan]. Each event has four fields:
class AgentSpan:
name: str
type: Literal[
"system_prompt",
"human_message",
"tool_call",
"ai_message",
]
content: str | AgentToolCall
time: datetime | None
For example:
2026-06-21 23:12:05+00:00 System system_prompt You are a concise assistant.
2026-06-21 23:12:05+00:00 Human human_message Count to three in Spanish.
2026-06-21 23:12:05+00:00 ChatOpenAI ai_message uno, dos, tres
2026-06-21 23:12:11+00:00 Human human_message And in German?
2026-06-21 23:12:11+00:00 ChatOpenAI ai_message eins, zwei, drei
Providers such as LangSmith often include the complete conversation history in every later trace. Traceport runs transcript extraction across the whole session, deduplicates repeated messages, and keeps the timestamp from the first trace where each event appeared.
Tool invocations and results are paired into one event:
for event in session.agent_traces:
if event.type == "tool_call":
call = event.content
print(call.name)
print(call.input)
print(call.output)
AgentToolCall contains:
class AgentToolCall:
name: str
input: Any | None
output: Any | None
session.full_traces
Use full traces only when you need observability details:
for trace in session.full_traces:
print(trace.id, trace.name, trace.status, trace.latency_ms)
for span in trace.spans:
print(span.id, span.name, span.span_kind, span.model)
Full traces preserve supporting HTTP, database, chain, and infrastructure spans. Untouched provider
records remain available through each model's raw escape hatch, but raw is excluded from normal
model serialization.
session.model_dump() returns the lightweight session summary. It intentionally excludes both the
computed transcript and the potentially large full_traces payload.
Sessions
list_sessions() returns lightweight summaries and defaults to sessions containing agent activity:
sessions = client.list_sessions(
project="Branna",
since="7d",
agent_only=True,
limit=100,
scan_limit=500,
)
for ref in sessions:
print(ref.id, ref.trace_count, ref.agent_span_count, ref.status)
get_session() hydrates the selected session:
session = client.get_session(sessions[0].id, project="Branna")
Traceport uses provider-native session, thread, or conversation identifiers when available. If a
provider does not expose one, the trace becomes a synthetic session with ID trace:<trace-id>.
Some providers can identify agent sessions natively. Others use a bounded candidate scan. Set
scan_limit to control the maximum work. Traceport emits ScanLimitWarning if the bound may have
truncated the result set.
Individual Traces
Use trace-level APIs when you need one specific provider execution rather than the entire conversation:
refs = client.list_traces(
project="Branna",
since="24h",
agent_only=True,
error=False,
limit=50,
)
trace = client.get_trace(refs[0].id, project="Branna")
for event in trace.agent_spans:
print(event.time, event.type, event.content)
trace.agent_spans applies the same readable extraction to one trace. trace.spans contains its
complete telemetry.
Provider-independent filtering is available through F:
from traceport import F
traces = client.query_traces(
F.project("Branna")
& F.since("24h")
& F.has_agent_spans()
& F.model_contains("gpt"),
limit=100,
)
Supported filters include project, time range, status, model, latency, cost, metadata, name, and agent-span presence. Unsupported native predicates are post-filtered after normalization rather than silently ignored.
Provider Configuration
| Provider | Required environment variables | Optional | Extra |
|---|---|---|---|
| LangSmith | LANGSMITH_API_KEY |
LANGSMITH_ENDPOINT, LANGSMITH_WORKSPACE_ID |
langsmith |
| Logfire | LOGFIRE_READ_TOKEN |
LOGFIRE_BASE_URL, LOGFIRE_PROJECT, LOGFIRE_ENVIRONMENT |
logfire |
| Langfuse | LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY |
LANGFUSE_HOST, LANGFUSE_PROJECT |
langfuse |
| Phoenix | PHOENIX_COLLECTOR_ENDPOINT, PHOENIX_PROJECT_NAME |
PHOENIX_API_KEY |
phoenix |
| Braintrust | BRAINTRUST_API_KEY |
BRAINTRUST_API_URL, BRAINTRUST_PROJECT_ID |
braintrust |
| Weave | WANDB_API_KEY, WEAVE_PROJECT |
— | weave |
| Helicone | HELICONE_API_KEY |
HELICONE_BASE_URL |
core |
| Datadog | DD_API_KEY, DD_APP_KEY |
DD_SITE |
datadog |
Example:
export LANGSMITH_API_KEY=...
export LANGSMITH_PROJECT=Branna
client = TraceClient.from_env("langsmith")
sessions = client.list_sessions(project="Branna", since="7d")
Provider Capabilities
| Provider | Read method | Session identity | Agent discovery |
|---|---|---|---|
memory |
In-memory | Native or synthetic | Complete reference behavior |
langsmith |
Runs SDK | Thread metadata | Bounded hydration |
logfire |
SQL records | OTel/GenAI attributes | Native SQL child-record query |
langfuse |
SDK and observations API | Native session ID | Bounded hydration |
phoenix |
Spans API | session.id |
OpenInference kinds |
braintrust |
BTQL | Session/thread metadata | Bounded hydration |
weave |
Calls SDK | Session/thread metadata or synthetic | Bounded hydration |
helicone |
REST requests | Native session ID | Native; every request is an LLM call |
datadog |
Planned | Planned | Planned |
All active adapters preserve complete telemetry after an agent session is selected. Filtering a
session for agent activity never removes its supporting spans from full_traces.
MCP Server
The MCP server is intentionally small and transcript-focused. Each server process reads one provider and one project and exposes exactly two read-only tools:
list_sessions(since="7d", until=None, error=None, limit=20)get_session(session_id)
get_session returns the session summary and one flat agent_traces transcript. MCP never exposes
full_traces, normalized spans, raw provider records, trace filters, or exporters.
Install MCP with the provider extra:
uv add 'traceport[mcp,langsmith]'
The generic stdio command is:
export TRACEPORT_PROVIDER=langsmith
export TRACEPORT_PROJECT=Branna
export LANGSMITH_API_KEY=...
uv run traceport-mcp
FastMCP uses stdio by default. An MCP stdio process must write only MCP protocol messages to
stdout; diagnostic logging belongs on stderr.
Codex with a local checkout
Add a server with the Codex CLI:
codex mcp add traceport-langsmith \
--env TRACEPORT_PROVIDER=langsmith \
--env TRACEPORT_PROJECT=Branna \
--env LANGSMITH_API_KEY=... \
-- uv run \
--directory /absolute/path/to/packages/traceport \
--extra mcp \
--extra langsmith \
traceport-mcp
Or add the equivalent TOML from
examples/mcp.codex.toml to ~/.codex/config.toml or a trusted
project's .codex/config.toml.
Codex with the published package
codex mcp add traceport-langsmith \
--env TRACEPORT_PROVIDER=langsmith \
--env TRACEPORT_PROJECT=Branna \
--env LANGSMITH_API_KEY=... \
-- uvx --from 'traceport[mcp,langsmith]' traceport-mcp
Run one named MCP server per provider/project combination:
traceport-branna-langsmith
traceport-production-logfire
The server instructs clients to list sessions before hydration, starts with a seven-day window, defaults to 20 results, caps requests at 100, and warns clients not to repeat identical calls because observability providers may rate-limit reads.
Export Full Traces
Export is available through the Python API for full observability workflows:
trace = session.full_traces[0]
client.export_trace(trace, format="json")
client.export_trace(trace, format="otel")
client.export_trace(trace, format="openinference")
OpenInference is the default format and emits OTLP JSON with normalized OpenInference attributes.
Local Testing
The memory adapter provides deterministic offline behavior:
from traceport import Span, SpanKind, Trace, TraceClient
from traceport.adapters.memory import MemoryAdapter
trace = Trace(
id="trace-1",
session_id="session-1",
provider="memory",
spans=[
Span(
id="span-1",
trace_id="trace-1",
name="chat.completion",
span_kind=SpanKind.LLM,
inputs=[{"role": "user", "content": "hello"}],
outputs=[{"role": "assistant", "content": "hi"}],
)
],
)
client = TraceClient(adapter=MemoryAdapter([trace]))
session = client.get_session("session-1")
print(session.agent_traces)
Development
cd packages/traceport
UV_CACHE_DIR=/tmp/uv-cache uv sync
UV_CACHE_DIR=/tmp/uv-cache uv run ruff format src tests
UV_CACHE_DIR=/tmp/uv-cache uv run ruff check src tests
UV_CACHE_DIR=/tmp/uv-cache uv run mypy src
UV_CACHE_DIR=/tmp/uv-cache uv run pytest
UV_CACHE_DIR=/tmp/uv-cache uv build
No live provider calls run in CI. Provider behavior is covered with scrubbed fixtures.
Third-party adapters can register through the traceport.adapters entry point:
[project.entry-points."traceport.adapters"]
acme = "acme_traceport:AcmeAdapter"
Adapters must subclass traceport.adapters.BaseAdapter. Unsupported filters must be translated,
post-filtered against normalized traces, or rejected with UnsupportedFilterError.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file traceport-0.1.0.tar.gz.
File metadata
- Download URL: traceport-0.1.0.tar.gz
- Upload date:
- Size: 45.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9038a9b322285eda5c7fb1872bcc84680524791784df44d3da1e0f420ff23ba6
|
|
| MD5 |
bc30e8093750b27ca0002c4b2b2dd832
|
|
| BLAKE2b-256 |
8e55cb74da6c2d684efacfe1d5fa69234306a6796e4ef04bc725b02caebc1a9b
|
Provenance
The following attestation bundles were made for traceport-0.1.0.tar.gz:
Publisher:
publish.yml on TheValmarAI/traceport
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
traceport-0.1.0.tar.gz -
Subject digest:
9038a9b322285eda5c7fb1872bcc84680524791784df44d3da1e0f420ff23ba6 - Sigstore transparency entry: 2137426498
- Sigstore integration time:
-
Permalink:
TheValmarAI/traceport@8820edfc7bfe2dbd6de3d09aad027f23de31c100 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/TheValmarAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8820edfc7bfe2dbd6de3d09aad027f23de31c100 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file traceport-0.1.0-py3-none-any.whl.
File metadata
- Download URL: traceport-0.1.0-py3-none-any.whl
- Upload date:
- Size: 60.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8fa078696ff80a7444c6c5b928296ad9c2c0e40dab178d63c169d0af21a49539
|
|
| MD5 |
f2a132897e0d102bbac6b5f6da50c9b9
|
|
| BLAKE2b-256 |
0d57d16fe4be5e137927429f6953242b23bf21fafffb5a42b9754c2a98c4b8f5
|
Provenance
The following attestation bundles were made for traceport-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on TheValmarAI/traceport
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
traceport-0.1.0-py3-none-any.whl -
Subject digest:
8fa078696ff80a7444c6c5b928296ad9c2c0e40dab178d63c169d0af21a49539 - Sigstore transparency entry: 2137426899
- Sigstore integration time:
-
Permalink:
TheValmarAI/traceport@8820edfc7bfe2dbd6de3d09aad027f23de31c100 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/TheValmarAI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8820edfc7bfe2dbd6de3d09aad027f23de31c100 -
Trigger Event:
workflow_dispatch
-
Statement type: