Skip to content

feat(ui): agent traces tab on logs with timeline and otel setup guide - #43891

Merged
ishaan-berri merged 55 commits into
mainfrom
litellm_agent-traces-ui
Sep 30, 2026
Merged

ishaan-berri merged 55 commits into
mainfrom
litellm_agent-traces-ui

Conversation

@ishaan-berri

Copy link
Copy Markdown
Contributor

TLDR

UI only, straight to main. Needs the agent tracing backend (#43819 then #43864) to have data. Without it the tab shows the "Tracing is not enabled" guide, so it's safe to merge in any order

Problem this solves:

  • Agent traces had no clean place in the UI
  • No guide for sending OTEL traces to LiteLLM

How it solves it:

  • New Agent Traces tab on Logs, Request Logs stays default
  • Runs table with a Logfire style timeline, drag to zoom
  • Run view is just header, span tree and detail pane
  • OTEL setup guide with SDK logos and a Claude Code / Codex prompt

Intentional product change: opening Logs collapses the left nav to icons for a full screen view. The toggle still expands it

User Flow

Before: a developer sending agent traces to LiteLLM has nowhere clean to see them

  1. They open http://localhost:4000/ui/logs
  2. Only Request Logs, Audit Logs and deleted items tabs are there

After: the developer finds every agent run under Logs

  1. They open http://localhost:4000/ui/logs, the nav collapses and Request Logs is selected
  2. They click Agent Traces (New) and see the runs table with a timeline
  3. They drag across the timeline to zoom, or pick Last 7 days from the range menu
  4. They click a run and see the span tree with LLM calls, tools and subagents
  5. With no traces yet, the tab shows the OTEL setup guide instead

Pre-Submission checklist

  • I have added meaningful tests
  • The handful of test files covering my change pass locally
  • My PR passes all required CI/CD checks
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review

Screenshots / Proof of Fix

Real stack, no mocks: LangChain / Deep Agents agents export OTEL to a local proxy (POST /v1/traces), spans land in ClickHouse, the UI dev server reads them back. The runs below are real agent runs through LiteLLM

Before (3930c5b, main)

  1. Open http://localhost:4000/ui/logs
  2. Tabs are Request Logs, Audit Logs, Deleted Keys, Deleted Teams. No way to see agent runs

After (HEAD of litellm_agent-traces-ui)

Logs page

  1. Open http://localhost:4000/ui/logs. The nav collapses to icons, Request Logs is still the default, Agent Traces has a New pill

logs

Runs table and timeline

  1. Click Agent Traces. Runs table with the run histogram, range menu and Live toggle. Failed runs show a red cap

runs

  1. Drag across the timeline. The bracket shows start, end and length, and the table filters to runs in that window

zoom

Run view

  1. Click the "Should we store OTEL agent spans..." run. One line header, span tree with LLM calls, tools and subagents, detail pane with the messages

run

Setup guide (no traces yet)

  1. With zero runs the tab shows the OTEL guide: preview, SDK picker, Claude Code / Codex prompt, install, env vars, run

setup

Tests

  1. npx vitest run src/components/view_logs "src/app/(dashboard)/layout.test.tsx" -> 596 passed, eslint 0 new errors, tsc clean

Type

🆕 New Feature

Caveats (if any)

Medium

  • Runs over 1000 spans hit the Rust reader row cap and fail to load
  • Plain OTEL LangChain runs show one agent, subagent nesting relies on LangSmith attributes

Low

  • Timeline filters the loaded page client side, not a server query
  • The in-app setup guide should also get a page in litellm-docs; View docs links there

@ishaan-berri
ishaan-berri requested a review from a team September 30, 2026 18:49
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps

greptile-apps Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[Medium risk] Adds agent traces UI tab with timeline and setup guide.

The PR should not merge until users can select an older range from an empty runs view and the sidebar compatibility requirement is addressed.

Findings

  1. P1 Empty view hides time controls ▶
  2. P2 Sidebar preference resets across routes ▶
  3. P2 Pages use different time windows ▶
  4. P2 Request lookup errors are silent ▶

Summary

Adds an Agent Traces tab under Logs, with a paginated runs table, timeline, span-detail view, and OpenTelemetry setup guide. Request Logs remains the default tab, and Logs now defaults to a collapsed sidebar.

Reviews (1) · Last reviewed commit: "test(ui): cover sidebar collapse on logs"

if (traces.notEnabledDetail !== null) return <TracingSetupCard detail={traces.notEnabledDetail} />;
// Onboarding only on the first, default view; an empty range the user picked keeps its controls.
const isEmpty = !traces.isLoading && !traces.error && traces.traces.length === 0;
if (isEmpty && !rangeChanged) return <TracingSetupCard detail={null} />;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Empty view hides time controls When tracing is enabled but the default 24-hour query finds no runs, this return shows the setup card instead of the runs view. The card has no time-range control, so users cannot select Last 7 days or Last 30 days to find older runs. Keep the range controls available when the default range is empty.

const isFullBleed = FULL_BLEED_SEGMENTS.has(routeSegment);
// A manual toggle holds only for the route it was made on; full-bleed routes default to collapsed.
const [sidebarOverride, setSidebarOverride] = useState<{ segment: string; collapsed: boolean } | null>(null);
const sidebarCollapsed = sidebarOverride?.segment === routeSegment ? sidebarOverride.collapsed : isFullBleed;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Sidebar preference resets across routes The override now applies only to the route segment where the user toggled the sidebar. If they collapse it on /ui/api-keys and navigate to /ui/models, it expands again, although their choice previously persisted across dashboard routes. The repository requires a user-controlled flag for backwards-incompatible behavior changes; that requirement must be satisfied before merging.

Rule Used: What: avoid backwards-incompatible changes without user-controlled flags Why: This breaks current behaviour for users using existing functionality Example of BAD: this PR (#22164) introduced run_post_custom... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +58 to +64
queryFn: ({ pageParam }) => {
const nowMs = Date.now();
return agentTraceListCall({
accessToken,
startMs: traceWindowStartMs(startTime, endTime, isCustomDate, nowMs),
endMs: isCustomDate ? moment(endTime).valueOf() : nowMs,
cursor: pageParam as string | null,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Pages use different time windows Each page fetch calculates a fresh rolling time window, even when it uses a cursor from an earlier page. After “Load more,” live refreshes can combine pages fetched with different bounds. This can make the runs list and timeline inconsistent; use one time window for a pagination cycle or restart pagination when it advances.

Comment on lines +77 to +83
)}
{drawerOpen && logQuery.isSuccess && logQuery.data === null && (
<p className="mt-2 font-mono text-[11px] text-muted-foreground">No request log found for this call.</p>
)}
<LogDetailsDrawer
open={drawerOpen && Boolean(logQuery.data)}
onClose={() => setDrawerOpen(false)}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Request lookup errors are silent If the request-log lookup fails—for example, because the user cannot access that request—the drawer does not open. This component shows a message when a successful lookup finds nothing, but shows no message for an error, leaving “Open request log” apparently unresponsive. Show the lookup error alongside the not-found message.

@yujonglee-berri
yujonglee-berri enabled auto-merge (squash) September 30, 2026 18:59
@ishaan-berri
ishaan-berri enabled auto-merge (squash) September 30, 2026 19:02
@ishaan-berri
ishaan-berri merged commit e78845a into main Sep 30, 2026
94 of 95 checks passed
@ishaan-berri
ishaan-berri deleted the litellm_agent-traces-ui branch September 30, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants