Skip to main content
Zeptar records every call between a user and an agent as a conversation. The conversation history surface lets you filter that record, open a single call, read its transcript turn by turn, see exactly which knowledge-base chunks informed each agent reply, and label calls for follow-up. The same record is the source of truth your team uses to investigate regressions, audit what the agent actually said, and decide whether a branch is ready to merge into Main.
Per-turn latency, LLM credit, and call-cost columns are populated by the analysis pipeline that runs at the end of a call. Conversations still in progress, and conversations recorded before analysis was enabled for the agent, show an em-dash for those fields.

Overview

A conversation is created the moment an agent dispatch starts. It carries:
  • the agent that handled the call,
  • the branch the call was served from (resolved through the conversation’s agent_version_id — every conversation pins the immutable version that ran),
  • a transcript built up as turns arrive from the agent runtime,
  • per-agent-turn retrieval sources — the knowledge-base chunks the LLM was given as context for that reply,
  • an LLM-generated summary and call status when the post-call analysis pipeline finishes.
Conversations are organization-scoped: a session without an active organization can’t see any conversations, and a session in organization A can never see organization B’s calls. Cross-tenant lookups return 404 with no enumeration difference between “wrong org” and “doesn’t exist.”

Anatomy of a conversation

The history surface breaks down into four pieces, built on the same @zeptar/ui primitives — Table, Badge, Dropdown — used elsewhere in the dashboard.

List

The list page (/agents/conversations) renders one row per conversation, newest first. The default columns are: Additional columns — Conversation ID, Language, Direction, Source, Version, Tools — are available from the Customize-table panel but off by default.

Detail

Opening a row routes to /agents/conversations/[conversationId]. The detail layout is two columns:
  • Main column — header (title, branch badge, copy-id button, prev/next chevrons, Add-tag button), audio bar, and three tabs: Overview, Transcription, Client data.
  • Right sidebar — metadata: date, text-only flag, environment, connection duration, call cost, LLM credits, LLM cost. Collapsible.

Transcription

The Transcription tab is the screen most teams spend the most time on. Each turn renders as a bubble with:
  • the turn timestamp relative to the start of the call,
  • the role (agent on the left, user on the right),
  • the text the participant said,
  • a row of metric pillsASR on user turns, LLM / TTS / RAG on agent turns. Any pill that doesn’t apply to a role is hidden rather than dashed.
  • a sources pill on every agent turn that used retrieval — 1 source, 3 sources, etc. Click to expand.

Client data

The Client-data tab surfaces what the SDK sent alongside the dispatch — current environment, language overrides, and any other per-call overrides the client passed on POST /v1/agents/{agentId}/conversations. Useful when you’re chasing “the agent behaved differently for this user” — it’s almost always an override.

Filtering and customizing the table

The filter rail sits directly under the page title. Add filters with the trailing Add filter button; each chip you add is dismissible. The MVP filter set covers:
  • Agent — narrow to one agent across all branches.
  • Branch — narrow to one branch on one agent.
  • Date range — inclusive start/end (ISO strings on the wire).
  • Statussuccessful / failed / unknown.
  • Duration — min and max, in whole seconds.
  • Directioninbound (user dialled) vs outbound (agent dialled out). Not all transports populate this.
  • Language — IETF tag (en, de, …).
Filter state is reflected in the URL (?branch_id=…&status=…) so a filtered view is shareable as a link. The list endpoint accepts the same names as query params — see the API overview. Customize table (the trailing button on the filter rail) opens a popover that lets you reorder columns, toggle non-default columns on, switch the Date format between relative and absolute, and hide ongoing & processing calls. Choices persist in the browser per user.

Per-turn retrieval

The clearest signal that the knowledge base is doing useful work is the per-turn Sources affordance. Every agent turn that triggered retrieval carries a sources pill. Clicking it expands an inline panel under the bubble (not a modal) titled Sources — Used RAG chunks, with one row per chunk:
  • Document title — the source document the chunk came from.
  • Chunk number — the chunk’s position in the document.
  • Similarity — the embedding cosine score we observed at retrieval time. We snapshot this on the conversation row so the displayed ranking matches what the agent saw, even if the chunk is later re-embedded.
  • Show — opens a centred Document Chunk Preview modal with the full chunk body and an Open link that routes to the source document in the knowledge base.
If a document is later deleted from the knowledge base, the row goes with it (the retrieval-source FK cascades). A conversation older than its sources will simply render the sources pill with a smaller count.

Tags

Tags are user-supplied free-form labels attached to a single conversation. They’re the canonical way to flag calls for follow-up — flaky, bug, escalate, demo, whatever vocabulary your team agrees on.
  • Add a tag from the conversation header. The first tag opens an inline input; subsequent tags append to the row.
  • Tags are per conversation, not per branch or per agent. A tag’s label is unique inside one conversation but the same label can be re-used across conversations.
  • Tags are organization-scoped. A label used in organization A is not visible to organization B.
  • Removing a tag is DELETE /v1/conversations/{id}/tags/{tagId} — deletes the row, doesn’t soft-delete.
There’s no central tag dictionary in v1 — labels are free-form strings. If your team wants a controlled vocabulary, agree on the strings out-of-band and use the Tag filter on the list page to scope to one label at a time.

Limits & costs

Two cost surfaces show up on the detail page’s right sidebar. LLM credits — the dollar-equivalent we bill for the LLM tokens consumed in the call (input + output + cached, summed across every turn). The Overview tab also shows the same number broken down by $/min so you can compare against your model’s published rate. Call cost — the total credit charge for the call. This rolls up:
  • LLM credits (above),
  • ASR (speech recognition) credits,
  • TTS (speech synthesis) credits,
  • agent runtime time (the minutes a LiveKit worker held the room).
The two columns can disagree by a meaningful amount on short calls because runtime time has a floor — a 3-second call still pays for room provisioning. Use the per-minute breakdown rather than the absolute total when comparing voices or LLM choices. Both fields are populated by the analysis pipeline at the end of a call. Anything still showing is either in-flight, analysis-pending, or pre-dates the metric being tracked on this agent.

Audio

The audio waveform and player controls render whenever a recording is available for the call. Whether a recording exists for any given call depends on:
  1. Your plan — recording is opt-in on lower tiers.
  2. Your organization’s recording policy — admins can disable recording for compliance reasons, in which case the agent runtime never persists the audio in the first place.
  3. Your per-call client overrides — an SDK caller can suppress recording for a single call.
When audio is unavailable, the waveform stays visible as a placeholder and the controls show “The conversation audio is not available.” The transcript is always available regardless of recording policy. The audio player’s More options menu exposes Download audio (audio file, signed S3 URL, expires in 15 minutes) and Copy transcript (plain-text turns, role-prefixed). Use the SDK if you need the raw transcript programmatically — the copy-transcript affordance is for manual review.

What’s next

  • Evaluation criteria — server-side eval that drives the successful / failed verdict instead of treating it as a free-form analysis output. Lands after the criteria-editor spec.
  • Conversation-level dynamic variables — surfacing per-call variables the SDK passed on dispatch_envelope_v1 directly in the Client-data tab.
  • Tools — calling-out per-turn tool invocations as their own affordance alongside RAG sources.
  • Tag dictionary — opt-in controlled vocabulary, so misspelled tags don’t fragment your filter set.
See the Conversations API reference for the endpoint surface, and the Branches overview for how conversations associate with branches and versions.