agent-prism

agent-prism

React components for visualizing traces from AI agents

Stars: 293

Visit
 screenshot

AgentPrism is an open source library of React components designed for visualizing traces from AI agents. It helps in turning complex JSON data into clear and visual diagrams for debugging AI agents. By plugging in OpenTelemetry data, users can visualize LLM calls, tool executions, and agent workflows in a hierarchical timeline. The library is currently in alpha release and under active development, with APIs subject to change. Users can try out AgentPrism live at agent-prism.evilmartians.io to visualize and debug their own agent traces.

README:

AgentPrism

AgentPrism is an open source library of React components for visualizing traces from AI agents. Agentic traces contain perfect information about an agent’s behavior with every plan, action, and retry. But that information gets lost in a sea of JSON.

Use AgentPrism and turn traces into clear, visual diagrams for debugging AI agents. Plug in OpenTelemetry data and see your agent’s process unfold: display LLM calls, tool executions, and agent workflows in a hierarchical timeline.

⚠️ Alpha Release: This library is under active development. APIs may change.

Read this post for more AgentPrism info and testimonials.

Try AgentPrism live at agent-prism.evilmartians.io — visualize and debug your own agent traces.

https://github.com/user-attachments/assets/69e592e2-b67c-4ebc-b301-2d8b73492e0d

Storybook

storybook.agent-prism.evilmartians.io

Prerequisites

  • React 19+
  • Tailwind CSS 3
  • TypeScript

Installation

Copy the UI components to your project:

npx degit evilmartians/agent-prism/packages/ui/src/components src/components/agent-prism

Install the data and types packages:

npm install @evilmartians/agent-prism-data @evilmartians/agent-prism-types

Install required UI dependencies:

npm install @radix-ui/react-collapsible @radix-ui/react-tabs classnames lucide-react react-json-pretty react-resizable-panels

Quick Start

The simplest way to get started is with the TraceViewer component, which provides a complete trace visualization interface:

import { TraceViewer } from "./components/agent-prism/TraceViewer";
import { openTelemetrySpanAdapter } from "@evilmartians/agent-prism-data";

function App() {
  return (
    <TraceViewer
      data={[
        {
          traceRecord: yourTraceRecord,
          spans:
            openTelemetrySpanAdapter.convertRawDocumentsToSpans(yourTraceData),
        },
      ]}
    />
  );
}

The TraceViewer includes:

  • Trace List: Browse multiple traces
  • Tree View: Hierarchical span visualization with search and expand/collapse
  • Details Panel: Inspect individual span attributes
  • Responsive Design: Works on desktop and mobile

Custom Layouts

For more control, use individual components to build custom layouts:

import { useState } from "react";
import type { TraceRecord, TraceSpan } from "@evilmartians/agent-prism-types";
import { openTelemetrySpanAdapter } from "@evilmartians/agent-prism-data";

import { TraceList } from "./components/agent-prism/TraceList/TraceList";
import { TreeView } from "./components/agent-prism/TreeView";
import { DetailsView } from "./components/agent-prism/DetailsView/DetailsView";

// Mock OpenTelemetryDocument (replace with real data)
const traceData = {
  resourceSpans: [],
};

// Mock traces with all required TraceRecord fields
const traces: TraceRecord[] = [
  {
    id: "1",
    name: "Trace 1",
    spansCount: 0,
    durationMs: 0,
    agentDescription: "Mock trace 1",
  },
  {
    id: "2",
    name: "Trace 2",
    spansCount: 0,
    durationMs: 0,
    agentDescription: "Mock trace 2",
  },
];

export function App() {
  const [selectedTrace, setSelectedTrace] = useState<TraceRecord | undefined>(
    undefined,
  );
  const [selectedSpan, setSelectedSpan] = useState<TraceSpan | undefined>(
    undefined,
  );
  const [expandedSpansIds, setExpandedSpansIds] = useState<string[]>([]);

  const spans = openTelemetrySpanAdapter.convertRawDocumentsToSpans(traceData);

  return (
    <div className="grid grid-cols-3 gap-4">
      {/* Traces sidebar */}
      <TraceList
        traces={traces}
        expanded={true}
        onExpandStateChange={() => {}}
        onTraceSelect={setSelectedTrace}
        selectedTrace={selectedTrace}
      />

      {/* Tree view */}
      <TreeView
        spans={spans}
        onSpanSelect={setSelectedSpan}
        selectedSpan={selectedSpan}
        expandedSpansIds={expandedSpansIds}
        onExpandSpansIdsChange={setExpandedSpansIds}
        spanCardViewOptions={{
          expandButton: "inside",
        }}
      />

      {/* Details panel */}
      {selectedSpan && <DetailsView data={selectedSpan} />}
    </div>
  );
}

Data Integration

AgentPrism uses a normalized data format optimized for UI rendering. Transform your trace data using the provided adapters.

All adapters implement the same interface and offer some helpful methods for transforming raw data (Open Telemetry, Langfuse, and so on) and getting some info out of it.

import {
  openTelemetrySpanAdapter,
  langfuseSpanAdapter,
} from "@evilmartians/agent-prism-data";

// convert whole documents to TraceSpans (normalized view)
openTelemetrySpanAdapter.convertRawDocumentsToSpans(otlpData);

// convert single span (a.k.a. record, a.k.a. Langfuse observation)
openTelemetrySpanAdapter.convertRawSpanToTraceSpan(otlpData);

// in case you want to use TreeView component
openTelemetrySpanAdapter.convertRawSpansToSpanTree(otlpData);

// get some data for a particular observation/span (e.g. when you loaded one record)
langfuseSpanAdapter.getSpanCategory(observationData);
langfuseSpanAdapter.getSpanCost(observationData);
langfuseSpanAdapter.getSpanDuration(observationData);
langfuseSpanAdapter.getSpanInputOutput(observationData);
langfuseSpanAdapter.getSpanStatus(observationData);
langfuseSpanAdapter.getSpanTokensCount(observationData);

OTLP Format

For OpenTelemetry traces, use the OTLP adapter:

import { openTelemetrySpanAdapter } from "@evilmartians/agent-prism-data";

const spans = openTelemetrySpanAdapter.convertRawDocumentsToSpans(otlpDocument);

Langfuse Format

For handling Langfuse observations, use Langfuse adapter

import { langfuseSpanAdapter } from "@evilmartians/agent-prism-data";

const spans = langfuseSpanAdapter.convertRawDocumentsToSpans(langfuseDocument);

Expected Data Structure

The UI components expect this data shape:

interface TraceViewerData {
  traceRecord: TraceRecord; // Trace metadata (id, timestamp, status)
  spans: TraceSpan[]; // Hierarchical span tree
  badges?: BadgeProps[]; // Optional trace badges
}

Supported Attributes

AgentPrism recognizes standard semantic conventions:

  • OpenTelemetry GenAI: gen_ai.* (model, tokens, costs)
  • OpenInference: llm.*, retrieval.*
  • Standard OTEL: HTTP, database spans
  • Custom: Add your own attributes like gen_ai.usage.cost

Sample OTLP Input

{
  "resourceSpans": [
    {
      "scopeSpans": [
        {
          "spans": [
            {
              "traceId": "abc123...",
              "spanId": "def456...",
              "name": "openai.chat",
              "attributes": [
                {
                  "key": "gen_ai.request.model",
                  "value": { "stringValue": "gpt-4" }
                },
                {
                  "key": "gen_ai.usage.input_tokens",
                  "value": { "intValue": "150" }
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Component Architecture

TraceViewer (complete solution)
├── TraceList (trace selection)
├── TreeView (span hierarchy)
│   ├── SearchInput
│   ├── CollapseAndExpandControls
│   └── Individual span rows
└── DetailsView (span inspection)

Use TraceViewer for quick setup, or compose individual components for custom layouts.

Theming

Use semantic tokens for colors. The theme folder in components has 2 files:

  • theme.css - import anywhere for bundler to process. Sets CSS variables on :root
  • index.ts - exports types and agentPrismTailwindColors. Import in tailwind config:
import { agentPrismTailwindColors } from "./src/components/theme";

export default {
  theme: {
    extend: {
      colors: agentPrismTailwindColors,
    },
  },
};

Customize by changing semantic token values in theme.css. Defaults from tailwind colors (commented), but fully customizable.

Each token has 3 values (Lightness, Chroma, Hue) in Oklch format. This enables the use of oklch(var(--${agentPrismPrefix}-${name}) / <alpha-value>) in Tailwind for opacity syntax like bg-agentprism-primary/50.

Contributing

We welcome contributions to AgentPrism! Please see our Contribution Guide for details.

For Tasks:

Click tags to check more tools for each tasks

For Jobs:

Alternative AI tools for agent-prism

Similar Open Source Tools

For similar tasks

For similar jobs