Custom Adapters
AgentDiff ships adapters for the major telemetry sources, but teams often have proprietary trace formats - an internal tracing SDK, a vendor export, a bespoke event log. The adapter registry lets you teach AgentDiff your format without forking anything.
Registering at runtime
python
from agentdiff import BaseAdapter, register_adapter, load_trace
from agentdiff.models import AgentTrace
@register_adapter("acme", aliases=("acme_tracer",))
class AcmeAdapter(BaseAdapter):
@classmethod
def from_dict(cls, data: dict) -> AgentTrace:
steps = [
build_step(span) for span in data["spans"] # your mapping
]
return AgentTrace(trace_id=..., agent_name=..., steps=steps, ...)
@classmethod
def detect(cls, data: dict) -> bool:
# Optional: lets load_trace(path) auto-detect this format.
return isinstance(data, dict) and data.get("vendor") == "acme"After registration the adapter resolves everywhere by name:
python
trace = load_trace("run.json", adapter_name="acme") # explicit
trace = load_trace("run.json") # auto-detected via detect()It also flows through configuration - [adapter] name = "acme" in
agentdiff.toml works with zero extra wiring.
Entry-point plugins (third-party packages)
If you maintain a separate package, expose adapters through the standard Python entry-point group and they are discovered automatically on first use - no registration call required in user code:
toml
# acme-sdk's pyproject.toml
[project.entry-points."agentdiff.adapters"]
acme = "acme_sdk.agentdiff:AcmeAdapter"Discovery is lazy and failure-tolerant: a broken plugin is skipped silently, and built-ins can never be shadowed.
Rules of the registry
- Names are normalized (case-insensitive;
-and spaces fold to_). - Re-registering a name requires
override=True. detect()hooks are dict-only and consulted after all built-ins, so registering an adapter never changes how existing telemetry is classified.- A broken
detect()hook is swallowed by contract - ingestion never crashes because of plugin code. - Inspect what's available with
agentdiff.available_adapters(); tests can reset state between cases withagentdiff.adapters.reset_registry().
Building a good adapter
- Map tool executions to
tool_call, model calls tollm_call, and decisions/handoffs toroutingsteps - that vocabulary drives loop detection, explanations, and the culprit locator. - Populate token usage when the source has it; cost deltas and resource gates depend on it.
- Honor error/retry/abandoned statuses in the source so WEI and the Recovery Step Ratio stay meaningful.
- Ship round-trip and fuzz tests like the built-in adapters do (see
tests/test_adapter_roundtrip.pyfor the pattern).