Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased¶
Nothing yet.
[0.3.1] — 2026-07-01¶
A focused release that makes failed runs unmistakable in the UI and lets MCP tool errors surface as real failures.
Added¶
register_mcp_client(..., handle_tool_errors=False). New keyword on the MCP adapter (tracesage.adapters.mcp). By default (True) an MCP tool that errors server-side returns the error as tool content — the model sees it and can recover, matching langchain-mcp-adapters' behaviour. PassFalseto make MCP tool errors raise instead, so a broken tool call fails the run and shows up as a red error node on the exact tool. MirrorsToolNode(handle_tool_errors=...)for local tools. The loader now binds tools to the server's connection config (not a transient session) so each call opens its own session — fixing aClosedResourceErrorwhen errors propagate.
Changed¶
- Failed nodes render solid red. In the topology / run-trace graph, a node that
errored is now filled solid
--errorred with a matching red glow — not just a red outline. The error styling overrides the trace-mode success/step glows, so a broken node reads unambiguously as red instead of blending toward orange. - MCP server palette recoloured. The per-server colour palette (
mcpServerColor) no longer includes red-family hues, so a healthy MCP server/tool is never confused with a failed (red) node. Red is now reserved exclusively for errors.
Fixed¶
register_mcp_clientacross langchain-mcp-adapters API variants. The tool loader falls back cleanly (get_tools(server_name=...)→ connection config → per-server session) and no longer leaks a closed session.- Example
11_supervisor_research_teamno longer raisesKeyError: 'next'— the supervisor's stop branch now always emits a routing key.
0.3.0 — 2026-06-23¶
A major UI overhaul (topology vs. run-trace, step-through replay, readable multi-server graphs), two real-world MCP example apps, and accurate per-call token attribution.
Added¶
- Topology vs. Run-trace views. A single graph pane now toggles between two layouts: Topology (the all-up system architecture, nodes in per-kind columns) and Run trace (one selected run laid out as a left → right call tree in call order). Selecting a run opens its trace; the Topology button returns to the architecture view.
- Step-through replay. Explicit Start / Pause / Resume controls plus Prev / Next manual stepping walk a run's execution on the graph. Start always restarts from the beginning; Resume only works once paused. Clicking a timeline step during replay pauses and jumps the cursor to that event.
- Run-status toasts. The UI pops a toast when a run you're watching finishes —
"Run completed" (or "Run failed: …" with the error) — driven by the
/ws/runslifecycle feed, so you don't have to keep eyes on the run list. - Per-call token usage on LLM nodes. Open an LLM node to see total Tokens in / Tokens out and a "Total tokens across N calls" line in the hero, summed per logical call (counted once, from each call's end event).
- Gmail + YouTube demo (
examples/mcp/gmail_youtube_demo/) — a ReAct agent that reads a real Gmail inbox, pulls YouTube transcripts from linked videos, and summarises them. Shipsbefore.py/after.pyso the minimal tracesage diff (a couple of imports, the setup calls, and acallbacks=kwarg) is obvious. Gmail is optional (needs Google Application Default Credentials); without it the agent runs with YouTube only.credentials.json/token.jsonare gitignored. - Trip Planner demo (
examples/mcp/trip_demo/) — a single agent planning a trip across three MCP servers (flights, weather, hotels, 7 tools each) plus a local formatting tool, showcasing per-server tool-source attribution in the topology and the "Tools by source" panel. Bundles the three stdio MCP servers — no external installs, just an LLM key. Loads a repo-root.envautomatically. examples/mcp/requirements.txtpinning the demos' dependencies.
Changed¶
- Readable graphs at scale. MCP servers get distinct colours; a server's tools are grouped and tinted by source. A large tool fan-out wraps into multiple sub-columns, and the auto-layout no longer shrinks every node to fit — it caps the zoom (~72% floor) and pans/scrolls instead, so nodes stay legible. The explicit "fit" button still zooms to show everything.
- Detailed timeline + node-drawer invocations. The timeline keeps one card per event; node and edge drawers now group a call's start (request) + end (response) into one logical invocation, so counts and token totals are never doubled.
- Step drawer is phase-aware. Opening a
*_startshows only its request; opening a*_end/*_errorshows the full completed call (request + response). - Connection liveness. The
/ws/runsfeed sends periodic heartbeats and the client tracks liveness, so the header reflects a dropped connection instead of showing a stale "connected". - UI polish: plain
START/ENDflags (no glyphs), full run id shown beside the Timeline heading, full-height collapse gutters mirroring the expand rails, and the topology-scope selector + "Tools by source" panel hidden in Run-trace mode.
Fixed¶
- Token attribution.
llm_endevents now carry the model name, so token usage (which lives on the end event) is attributed to the LLM node — previously the end events were nameless and dropped from the node's invocation set. - Demo ergonomics. Both MCP demos print the actual bound UI port (auto-port may pick 7843+ if 7842 is busy), preflight their prerequisites (MCP servers / LLM API key) and exit with clear setup instructions instead of cryptic failures.
0.2.1 — 2026-06-21¶
Multi-app quality-of-life, scoped topology, an offline-capable UI, and an onboarding/docs overhaul (honest positioning included).
Added¶
- Project name in the UI. Set
TRACESAGE_PROJECT_NAME(configproject_name) to label an app; it shows in the UI header and browser-tab title. Unset = nothing shown. Surfaced via/api/health. The bundled examples each set one so it's visible in their UI. - Auto-port. If the configured port (default 7842) is busy, the embedded UI now
auto-binds the next free port (scanning upward, then an OS-ephemeral port), so multiple
apps run at once without a clash. Config
port_auto(TRACESAGE_PORT_AUTO, default on); setFalseto pin exactlyport. Newtracer.ui_urlproperty exposes the live URL; examples print the actual bound port.tracesage serveuses the same fallback. - Scoped topology. The topology map and "Tools by source" panel now default to the
selected run (latest when none) instead of an all-time union — so a removed tool,
agent, or MCP server no longer lingers across app versions as you iterate. A toolbar
selector offers This run · Last N runs · All time (with an editable N); selecting
an older run shows that run's structure.
/api/topologyand/api/toolstake a matching?scope=run:<id>|last_n:<N>|allparam. Scoping also drops a removed MCP server's registered-but-uncalled tools (shown only if the server was active). - Troubleshooting / FAQ page (
docs/troubleshooting.md): "where are my runs?" (data-dir isolation), UUIDv7 run-id prefixes, stale-topology scoping, and the install/port gotchas — linked from the nav, quickstart, and README. - A complete, no-API-key runnable example in the quickstart (uses
FakeListChatModel), so first-time users aren't assumed to already have an agent/graph wired up. - Documented API object shapes (
Run/StoredEvent/Stats/Topology/WSMessage) field-by-field in the API reference, plus a note on the interactive/docs+/openapi.jsonendpoints.
Changed¶
- Repositioned as "local-first observability" (was "production observability") across the README, docs, site description, package metadata, and CLI help — tracesage is a local-first dev tool that bridges to your production stack via OpenTelemetry, not a hosted production-monitoring service itself. Status messaging and the "Production" docs nav updated to match.
- The UI now works fully offline. PicoCSS is vendored into the package
(
ui/vendor/pico.min.css) instead of being fetched from a CDN, so the dashboard loads with zero network calls — matching the "no external services" promise. - Install commands quote the extra (
pip install "tracesage[langchain]") throughout the docs and the adapter'sImportError, so the first command doesn't fail under zsh (the macOS default shell) withno matches found. - Onboarding points at the printed URL rather than a hardcoded
:7842, since auto-port may land elsewhere; added a per-appdata_dirtip to the quickstart. - Roadmap items are no longer pinned to specific version numbers in the docs (they read as stale promises if dates slip); framework support now clearly states LangChain/LangGraph is the only shipped adapter today.
Fixed¶
- Dropdown chevron restored on every
<select>(runs status filter, replay speed, topology scope) — a globalbackgroundshorthand had been wiping PicoCSS's native arrow. - "Tools by source" is hidden in Run-trace mode (it's a topology-level view) and shown again in Topology.
- The timeline opens at the first step of a selected run instead of jumping to the last; live tailing still re-engages when you scroll to the bottom.
- The "Last N" scope input matches the scope
<select>'s size, and the runs status filter no longer sits underneath the panel's collapse button.
0.2.0 — 2026-06-18¶
The "full picture + production bridge" release: complete request/response capture, OpenTelemetry export, per-application isolation, and a batch of UI/CLI/safety fixes.
Added¶
- OpenTelemetry (OTLP) export. Set
otlp_endpoint(envTRACESAGE_OTLP_ENDPOINT) and every event is also exported as an OTel span to a collector / Tempo / Jaeger / Datadog / Honeycomb, in addition to the local SQLite store. Mapsroot_run_id→trace,run_id→span,parent_run_id→parent, with token/error/MCP attributes. Optionaltracesage[otel]extra; best-effort and never breaks the app if the collector is down. Config:otlp_endpoint,otlp_service_name,otlp_headers. - Full request and response payloads.
*_startevents (inputs/prompts/queries) are now persisted as blobs alongside the existing*_endoutputs, so the UI step drawer shows the request and response paired together for each step. tracesage showcolour + ordering — each element kind (chain/agent/tool/llm/ retriever) renders in its own colour, MCP-backed tools are taggedmcp:<server>, and--reverseflips sibling order (default follows execution flow).python -m tracesagenow works (added__main__).- Positional args for
tracesage export [RUN_ID]andimport [INPUT](the--run-id/--inputflags still work). - Examples each write to their own data dir, demonstrating per-application isolation; new "Isolating multiple applications" docs.
Changed¶
- Topology + "Tools by source" isolation. These are computed per data dir, so
applications are kept separate by giving each its own
data_dir(documented). All bundled examples now follow this. - UI static assets are served with
Cache-Control: no-cache, so UI updates take effect on a normal reload (no more stale cachedapp.js/styles.css). tracesage runs --tagis now filtered in SQL, so it composes correctly with--limit/--offsetand the reported total.- Removed the now-unused
aiofilesruntime dependency.
Fixed¶
- Embedded UI server fails soft on a busy port. A port conflict made uvicorn call
sys.exit(1), whoseSystemExitpreviously crashed the host application; it is now contained — tracing continues without the local UI. - Auth: a non-ASCII bearer token /
?token=no longer raises (it failed open to a 500); it fails closed with 401/4401. BlobStore.read()no longer blocks the event loop (decompress + parse offloaded).- Timeline step cards: the kind label (CHAIN/TOOL/LLM/…) no longer overflows its box and overruns the timestamp.
- "Tools by source" panel: raised above the graph, clamped fully inside the pane, and re-clamped when a side pane expands (it slides over instead of being hidden).
- "Fit to view" in run-trace mode now fits the run instead of zooming out to include off-screen hidden nodes.
0.1.1 — 2026-06-16¶
Branding, docs, and packaging polish — no runtime/behaviour changes.
Added¶
- Brand logo assets under
assets/— the topology>mark +tracesagewordmark, in dark / light / transparent and square-icon variants. - The documentation site now carries the logo and favicon (MkDocs Material), and the README and docs home lead with the brand logo.
Changed¶
- UI brand wordmark is now two-tone —
tracein the accent blue,sagein green — echoing the logo's blue→green gradient (and it adapts to the light/dark theme). - README badges modernized: dropped the legacy
.svgsuffixes (more reliable rendering across viewers), license pulled live from PyPI metadata, CI badge pinned tomain, and a Docs badge added.
0.1.0 — 2026-06-16¶
First public release.
Added¶
Core pipeline¶
- LangChain
BaseCallbackHandlerintegration for chain, agent, tool, LLM, chat-model, retriever events (on_chain_start,on_chat_model_start, etc.) TraceSage.create()factory wires storage + worker + server on a single event loop- Async event queue with batched SQLite writes (50 events / 100 ms default)
- Gzipped blob storage for full event payloads (
*_ENDevents) - Pluggable
StorageBackendprotocol (SQLite implementation)
Server + UI¶
- FastAPI server with REST + WebSocket endpoints, lifespan-managed
- Endpoints:
/api/runs,/api/runs/{id}/journey,/api/runs/{id}/steps/{event_id}/full,/api/stats,/api/topology,/api/tools,/api/runs/{id}/export?format=jsonl,DELETE /api/runs/{id},/ws/trace/{run_id},/ws/runs - Single-page interactive dashboard with a custom, hand-written SVG graph view (no JS framework, no build step) — auto-laid-out, hover/click/replay
- Run list, timeline, step drawer, dark/light themes, keyboard shortcuts
- Within-run search/filter of the timeline
- WebSocket reconnect with exponential backoff (1s → 30s)
- Replay mode for runs at 1x/2x/5x speed
MCP tool-source attribution¶
tracesage.adapters.mcp.register_mcp_client(tracer, client)loads aMultiServerMCPClient's tools and attributes each to its originating MCP server (works around langchain-mcp-adapters not exposing provenance); plusregister_mcp_tools()for explicit lists andTraceSage.register_tool_source()- Tool events carry an
mcp_serverfield, persisted on the event and in anmcp_toolstable so a server's tools — including uncalled ones — appear in the topology andGET /api/toolsinventory even inservemode - UI: MCP server nodes, agent→server and server→tool edges, per-server colour rings/chips on tool nodes, a draggable, collapsible "Tools by source" panel, and a dynamic legend
- Optional extra
tracesage[mcp](langchain-mcp-adapters, mcp, langgraph), imported lazily —import tracesagenever requires it
Developer experience¶
- Kill switch:
TRACESAGE_ENABLED=false(orenabled=False) returns an inert tracer — no embedded server, no DB/worker, a no-op handler, near-zero overhead — so you can wire tracesage in once and disable it per-environment (e.g. in prod) without changing your integration - Embedded-server toggle:
start_serveris a config field (TRACESAGE_START_SERVER=false) — capture traces in prod without running the in-process UI server; view them later withtracesage serve - Trace links: a
🔍 tracesage: <url>deep link prints on each new root run (print_run_url/public_urlconfig;TraceSage.run_url()) - Zero-friction setup:
with tracesage.trace()(sync),tracesage.start()background runner, andasync with TraceSage.session(install=True)—installregisters a global LangChain handler so nocallbacks=wiring is needed - Console + notebook renderers:
tracesage show <run>prints a terminal trace tree;TraceSage.run_view()renders the live UI inline in Jupyter - Richer errors: exception type + full traceback captured on error events and
retrievable in the UI drawer /
/full - pytest plugin: the
tracesage_capturefixture (auto-registered) withassert_tool_called,assert_no_errors,total_tokens, etc. — for both sync and async tests TraceSage.flush()to await full persistence (handy in tests/notebooks)
CLI¶
tracesage serve(read-only viewer),export(JSONL dump),import,stats,runs,gc(retention),version,doctor- Developer commands:
demo,show,watch,diff,view, andserve --open
Production safety¶
- Hard fail-stop when binding non-loopback addresses without
auth_token - Bearer-token HTTP auth (skip
/api/health); constant-time comparison - CORS preflight (
OPTIONS) handled by the outermost CORS layer, never 401'd by auth - WebSocket auth via
?token=query param orSec-WebSocket-Protocolsubprotocol; per-socket send lock so catchup can't race a worker broadcast - Path-traversal guard in BlobStore (enforced on read and write)
- Per-run event cap (circuit breaker) + root-level sampling
- Bounded LRU eviction on all internal run-id maps (no memory leaks in long runs)
- Worker FK auto-creation for sub-runs (handles nested LangGraph correctly)
queue.join()waits for full persistence (not just dequeue)
Examples¶
examples/organized intogetting_started/(no-key demos),mcp/(MCP attribution), and ashowcase/gallery — 30 real before/after apps across customer support, RAG, multi-agent, MCP, reasoning loops, and finance/legal/insurance verticals
Tooling¶
- GitHub Actions CI matrix: Linux/Windows/macOS × Python 3.11/3.12/3.13
- Trusted Publishing release workflow; MkDocs documentation site
- Ruff lint config
- Crash-recovery harness (
tools/crash_recovery_test.py) and a throughput bench tool (tools/bench.py)
Known limitations¶
- Centralized multi-producer mode planned for a future release
- OpenInference / OpenTelemetry export planned for a future release
- Cost tracking and PII redaction planned for a future release
- CrewAI / AutoGen / LlamaIndex adapters planned for a future release