import { useState } from "react"; import { ChevronDown, ChevronRight, Database, Loader2, Route, Wrench } from "lucide-react"; import type { Observability, ObservabilityDataUsed } from "@/services/agenticApi"; import { formatDateTime } from "./utils"; interface MessageTraceabilityProps { observability?: Observability | null; loading?: boolean; error?: string | null; sources?: unknown[]; } function renderUnknown(value: unknown) { if (value == null) return "-"; if (typeof value === "string") return value; try { return JSON.stringify(value, null, 2); } catch { return String(value); } } function sourceLabel(source: unknown, index: number) { if (source && typeof source === "object") { const record = source as Record; return String(record.name ?? record.title ?? record.source ?? record.source_id ?? record.id ?? `Source ${index + 1}`); } return String(source ?? `Source ${index + 1}`); } function DataUsedCard({ item, index }: { item: ObservabilityDataUsed; index: number }) { return (

{item.source?.name ?? `Data source ${index + 1}`}

{item.source?.type && {item.source.type}}
{item.tables && item.tables.length > 0 && (

Tables: {item.tables.map((table) => table.name).join(", ")}

)} {item.columns_read && item.columns_read.length > 0 && (
{item.columns_read.map((column) => ( {column.table ? `${column.table}.${column.name}` : column.name} ))}
)} {item.group_by && item.group_by.length > 0 && (

Grouped by: {item.group_by.join(", ")}

)} {typeof item.rows_returned === "number" && (

Rows returned: {item.rows_returned}

)} {item.query && (
{item.query}
)}
); } export function MessageTraceability({ observability, loading, error, sources = [] }: MessageTraceabilityProps) { const [open, setOpen] = useState(false); const [detailsOpen, setDetailsOpen] = useState(false); const traceSources = observability?.sources?.length ? observability.sources : sources; const hasTrace = Boolean(observability || loading || error || traceSources.length > 0); if (!hasTrace) return null; const toolCalls = observability?.tool_calls ?? []; const dataUsed = observability?.data_used ?? []; return (
{open && (
{loading &&

Traceability is being prepared.

} {error &&

{error}

} {observability?.generated_at && (

Generated {formatDateTime(observability.generated_at)}

)} {observability?.intent && (

Intent

{observability.intent}

)} {(observability?.planning || observability?.thinking) && (
Thought and planning
{observability.thinking &&

{observability.thinking}

} {observability.planning?.goal_restated &&

{observability.planning.goal_restated}

} {observability.planning?.assumptions && observability.planning.assumptions.length > 0 && (
    {observability.planning.assumptions.map((item) =>
  • {item}
  • )}
)} {observability.planning?.steps && observability.planning.steps.length > 0 && (
{observability.planning.steps.map((step, index) => (

{step.stage ?? `Step ${step.step ?? index + 1}`}

{step.objective &&

{step.objective}

}
))}
)}
)}
Data used
{dataUsed.length === 0 ? (

No data usage recorded for this answer.

) : (
{dataUsed.map((item, index) => ( ))}
)}
{detailsOpen && ( toolCalls.length === 0 ? (

No tool call recorded for this answer.

) : (
{toolCalls.map((tool, index) => (

{tool.name}

{tool.status && {tool.status}}
{tool.summary &&

{tool.summary}

} {tool.input !== undefined && (
{renderUnknown(tool.input)}
)} {tool.output !== undefined && (
{renderUnknown(tool.output)}
)} {tool.error &&

{tool.error}

}
))}
) )}
{traceSources.length > 0 && (

Citations and sources

{traceSources.map((source, index) => ( {sourceLabel(source, index)} ))}
)}
)}
); }