Add the agent History tab -- every user's conversations with this
agent, with rating, summaries, topic tags, and filters (user, date range,
sentiment, topics). The transcript panel shows the conversation the way the
chat did: attachments the user and agent exchanged, the Retrieved
Documents the answer cited, the tools it called, and a per-turn
Show Details panel with the model, temperature and request context.
Includes a pagination slot and an optional export. This is one tab in the
wider agent-settings family. All tabs share the same
AgentSettingsProvider wrapper.




Common setup (brand, conventions, env files, verification): see docs/skill-setup.md.
Prerequisites
- Auth must be set up first (
/iblai-vibe-auth) - MCP server + skills configured (
@iblai/mcpin.mcp.json) AgentSettingsProvidermust wrap the route (see/iblai-vibe-agent-settingStep 2 if not already set up)- Ask the user for a real
mentorId(agent UUID). Do NOT invent one.
Step 1: Check Environment
Before proceeding, check for an iblai.env in the project root. Look for
PLATFORM, DOMAIN, and TOKEN variables. If the file does not exist or
is missing these variables, tell the user:
"You need an iblai.env with your platform configuration. Download the
template and fill in your values:
curl -o iblai.env https://raw.githubusercontent.com/iblai/vibe/refs/heads/main/iblai.env"
Step 2: Mount AgentHistoryTab
// app/(app)/agents/[mentorId]/history/page.tsx
"use client";
import { AgentHistoryTab } from "@iblai/iblai-js/web-containers/next";
export default function AgentHistoryPage() {
return (
<div className="flex h-full flex-col bg-white">
<AgentHistoryTab />
</div>
);
}
With Markdown rendering and export
import ReactMarkdown from "react-markdown";
<AgentHistoryTab
renderMessageContent={(content) => <ReactMarkdown>{content}</ReactMarkdown>}
onExport={(filters) => {
console.log("export with filters", filters);
}}
isExporting={false}
/>;
With pagination
<AgentHistoryTab
PaginationComponent={({ currentPage, totalPages, onPageChange, disabled }) => (
<MyPagination
page={currentPage}
total={totalPages}
onChange={onPageChange}
disabled={disabled}
/>
)}
/>;
Step 3: Customize Labels (Optional)
import { AgentHistoryTab } from "@iblai/iblai-js/web-containers/next";
<AgentHistoryTab
labels={{
header: { title: "Mentor conversations" },
}}
/>;
Step 4: Use MCP Tools for Customization
get_component_info("AgentHistoryTab")
get_component_info("AgentSettingsProvider")
<AgentHistoryTab> Props
Import from @iblai/iblai-js/web-containers/next.
| Prop | Type | Required | Description |
|---|---|---|---|
labels |
DeepPartial<HistoryTabLabels> |
No | Override user-visible strings |
renderMessageContent |
(content: string) => ReactNode |
No | Render AI messages as rich text. Defaults to plain text |
PaginationComponent |
ComponentType<{ currentPage, totalPages, onPageChange, disabled, disableNumberedButtons? }> |
No | Custom pagination. Without it no pagination UI renders |
onExport |
(filters: ChatHistoryFilter) => void |
No | Called with current filters when Export is clicked |
isExporting |
boolean |
No | Whether an export is in progress |
currentSPA |
string |
No | The SPA the host runs in, forwarded to the profile dialog a user link opens ('lms' / 'skills' add the Gradebook tab there) |
What the transcript panel shows
Admin transcripts carry more than the text of the turn. The tab renders
each piece with the same component the live chat uses, and shows nothing
where the backend sent nothing — so an agent without RAG or tools reads as
a plain transcript. The org-wide Transcripts tab
(/iblai-vibe-analytics)
renders the identical panel over the same payload.
| In the transcript | What it is |
|---|---|
| Attachments | Files and images exchanged on a turn (human_files / ai_files), as the chat's file cards. The presigned url opens them; an attachment-only turn has empty text |
| Retrieved Documents | The chunks the answer cited, with source, snippet and relevance score — the chat's own RetrievedDocumentsButton / DocumentSidebar, handed this turn's (or the conversation's) documents instead of a live session's |
| Used N tools | The turn's tool calls, in the chat's tool-call record (name, input, output) |
| Show Details | A collapsible panel per AI turn: Metadata (model — with the provider's logo — temperature, client) and Request Context (session, flow, org, pathway, system prompt, file references …) |
| Row badges | On the conversation list, how many documents and tool calls the whole conversation used |
Platform names, not wire names: enable_artifacts shows as Canvas,
is_proactive as Proactive Prompt, grading_context as Grader,
document_filter as Datasets. Unknown keys are humanised
(caller_verified → "Caller Verified"), so a new backend field appears
without an SDK release.
The conversation owner's name comes from the shared identity rule
(resolveUserIdentity): a real full name, else email, else username, else
the anonymous label — so a row never reads as a raw id. Clicking it opens
the same profile dialog the Management tab opens.
Related Exports
From @iblai/iblai-js/web-containers/next:
HistoryTabLabels-- type for the full label bundle.
From @iblai/iblai-js/web-containers — the transcript pieces this tab is
built from, for custom history UI on the same payloads:
TranscriptTurnDetails/TranscriptRollupBadges— the per-turn Show Details panel and the list-row document/tool badges.TranscriptTurnDetailstakesrenderDocuments/renderToolCalls/renderModel/renderFilesslots so a host can swap in its own chat UI, plustenantKey+mentorIdso the model badge can resolve its provider logo off the mentor SPA.RetrievedDocumentsButton,DocumentSidebar— the retrieved-documents dialog and rail. One component serves every surface: passsessionIdto fetch a live chat's vector results, ordocumentsto show a transcript's (toRetrievedDocumentsconverts the payload);labelswaps the button text for a compact "Documents · N" chip.ToolCallIndicator,getFriendlyToolName,getQueryLabel,formatResult— the tool-call record.TranscriptFileCards— attachment cards (name,contentType,url).LlmModelBadge— the model chip with the provider logo.summarizeTranscriptTurns,conversationDocuments,toRetrievedDocuments,toToolCallInfos,toRollupCount,humanizeFieldName,formatFileSize— the helpers that turn the API payload into those props.resolveUserIdentity(+UserIdentitySource,ResolvedUserIdentity) — the shared "what do we call this user" rule.UserProfileLink,UserProfileDialog— the profile viewer a user link opens.
Step 5: Verify
Run /iblai-vibe-ops-test before telling the user the work is ready:
pnpm build-- must pass with zero errorspnpm test-- vitest must pass- Start dev server and touch test:
pnpm dev & npx playwright screenshot http://localhost:3000/agents/<id>/history /tmp/agent-history.png
Important Notes
- Redux store: Must include
mentorReducerandmentorMiddleware initializeDataLayer(): 5 args (v1.2+)@reduxjs/toolkit: Deduplicated via webpack aliases innext.config.ts- Peer deps:
sonnerand@iblai/iblai-web-mentormust be installed (pnpm add sonner @iblai/iblai-web-mentor) - Shared provider:
AgentSettingsProvidermust wrap the route at a layout level. See/iblai-vibe-agent-settingStep 2 for the full snippet. - The extra context is backend-driven: attachments, documents, tool
calls and metadata come from the admin
chat-history/payload. Nothing renders when a field is null or empty, so older conversations (recorded before the backend attached per-turn context) simply read as plain transcripts — that is not a wiring bug. - Presigned attachment URLs expire. A file card opens the
urlthe payload carried; re-fetch the conversation rather than caching them. - Related surfaces: the signed-in user's own history is
/iblai-vibe-history(one user, every agent); the org-wide Transcripts tab with the same panel is/iblai-vibe-analytics. - Brand guidelines: BRAND.md