// Agent card document — ported from AgentCardDocument.tsx
import { Document, Page, View, Text } from '@react-pdf/renderer';
import { AgentCardCover } from './cover.js';
import { styles, colors } from '../styles.js';
import { getScoreHexColor } from '../scoring.js';
import type {
AgentCardData,
AgentCardTool,
AgentCardKnowledgeBase,
AgentCardLLMConfig,
AgentCardEvalRun,
LifecycleStage,
V1Owner,
ComponentScoreDetail,
} from './types.js';
interface AgentCardDocumentProps {
data: AgentCardData;
}
// ---------------------------------------------------------------------------
// Shared helpers
// ---------------------------------------------------------------------------
function PageHeader({ title, pageNumber }: { title: string; pageNumber: number }) {
return (
{title}
Page {pageNumber}
);
}
function PageFooter({ generatedDate }: { generatedDate: string }) {
return (
Generated {generatedDate}
Indemn Agent Card
);
}
function ComponentScoreBadge({ label, detail }: { label: string; detail?: ComponentScoreDetail }) {
if (!detail || detail.total === 0) return null;
const rate = detail.passed / detail.total;
const pct = Math.round(rate * 100);
return (
{label}: {pct}% ({detail.passed}/{detail.total})
);
}
// ---------------------------------------------------------------------------
// Page 2: System Prompt
// ---------------------------------------------------------------------------
function SystemPromptPage({
systemPrompt,
generatedDate,
componentScore,
}: {
systemPrompt?: string;
generatedDate: string;
componentScore?: ComponentScoreDetail;
}) {
return (
System Prompt
Page 2
{systemPrompt ? (
{systemPrompt}
) : (
No system prompt configured
)}
);
}
// ---------------------------------------------------------------------------
// Page 3: Tools
// ---------------------------------------------------------------------------
function ToolsPage({
tools,
generatedDate,
componentScore,
}: {
tools: AgentCardTool[];
generatedDate: string;
componentScore?: ComponentScoreDetail;
}) {
return (
Tools ({tools.length})
Page 3
{tools.length > 0 ? (
{tools.map((tool) => (
{tool.name}
{tool.tool_name}
{tool.description && (
{tool.description}
)}
{tool.type}
))}
) : (
No tools configured
)}
);
}
// ---------------------------------------------------------------------------
// Page 4: Knowledge Bases
// ---------------------------------------------------------------------------
function KnowledgeBasesPage({
knowledgeBases,
generatedDate,
componentScore,
}: {
knowledgeBases: AgentCardKnowledgeBase[];
generatedDate: string;
componentScore?: ComponentScoreDetail;
}) {
return (
Knowledge Bases ({knowledgeBases.length})
Page 4
{knowledgeBases.length > 0 ? (
{knowledgeBases.map((kb) => (
{kb.name}
{kb.type}
{kb.document_count} documents
))}
) : (
No knowledge bases linked
)}
);
}
// ---------------------------------------------------------------------------
// Page 5: LLM Configuration
// ---------------------------------------------------------------------------
function LLMConfigPage({
llmConfig,
generatedDate,
}: {
llmConfig?: AgentCardLLMConfig;
generatedDate: string;
}) {
return (
{llmConfig ? (
Provider
{llmConfig.provider || 'N/A'}
Model
{llmConfig.model || 'N/A'}
{llmConfig.parameters && Object.keys(llmConfig.parameters).length > 0 && (
Parameters
{Object.entries(llmConfig.parameters).map(([key, value]) => (
{key.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase())}
{String(value)}
))}
)}
) : (
No LLM configuration set (using defaults)
)}
);
}
// ---------------------------------------------------------------------------
// Page 6: Evaluation History
// ---------------------------------------------------------------------------
function EvaluationHistoryPage({
runs,
generatedDate,
}: {
runs: AgentCardEvalRun[];
generatedDate: string;
}) {
const completedRuns = runs.filter(r => r.status === 'completed');
const recentRuns = completedRuns.slice(0, 10);
return (
{recentRuns.length > 0 ? (
{/* Table header */}
Date
Model
Items
Criteria
Rubric
{/* Table rows */}
{recentRuns.map((run, i) => {
const date = run.completed_at || run.created_at;
const dateStr = new Date(date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
const model = run.bot_llm_model || 'N/A';
const criteriaStr = run.criteriaScore !== null ? `${run.criteriaScore}% (${run.criteriaPassed}/${run.criteriaTotal})` : '-';
const rubricStr = run.rubricScore !== null ? `${run.rubricScore}% (${run.rubricRulesPassed}/${run.rubricRulesTotal})` : '-';
return (
{dateStr}
{model}
{run.completed}/{run.total}
{criteriaStr}
{rubricStr}
);
})}
) : (
No completed evaluation runs
)}
);
}
// ---------------------------------------------------------------------------
// Page 7: Metadata
// ---------------------------------------------------------------------------
function MetadataPage({
botId,
organizationId,
lifecycle,
owner,
generatedDate,
}: {
botId: string;
organizationId?: string;
lifecycle?: LifecycleStage;
owner?: V1Owner;
generatedDate: string;
}) {
const ownerName = owner
? [owner.firstname, owner.lastname].filter(Boolean).join(' ') || owner.email || 'Unknown'
: undefined;
const lcColors: Record = {
prototype: { bg: '#e5e7eb', text: '#4b5563' },
beta: { bg: '#fef3c7', text: '#92400e' },
published: { bg: '#d1fae5', text: '#065f46' },
};
const lc = lifecycle ? lcColors[lifecycle] || lcColors.prototype : null;
return (
{/* Row 1: Lifecycle + Owner */}
Lifecycle Stage
{lc ? (
{lifecycle!.charAt(0).toUpperCase() + lifecycle!.slice(1)}
) : (
Not set
)}
Owner
{ownerName || 'Unassigned'}
{owner?.email && ownerName !== owner.email && (
{owner.email}
)}
{/* Row 2: Bot ID + Org ID */}
Bot ID
{botId}
Organization ID
{organizationId || 'N/A'}
{/* Row 3: Generated date */}
Report Generated
{generatedDate}
);
}
// ---------------------------------------------------------------------------
// Document
// ---------------------------------------------------------------------------
export function AgentCardDocument({ data }: AgentCardDocumentProps) {
const hasEvalRuns = data.evaluationRuns && data.evaluationRuns.length > 0;
return (
{/* Page 1: Cover */}
{/* Page 2: System Prompt */}
{/* Page 3: Tools */}
{/* Page 4: Knowledge Bases */}
{/* Page 5: LLM Configuration */}
{/* Page 6: Evaluation History (only if runs exist) */}
{hasEvalRuns && (
)}
{/* Page 7 (or 6 if no eval history): Metadata */}
);
}