Spaces:
Sleeping
Sleeping
| import { Activity, Database, ListChecks, Wrench } from "lucide-react"; | |
| import type { Observability } from "@/services/agenticApi"; | |
| import { EmptyState, ErrorState, LoadingState } from "./AnalysisStates"; | |
| interface ObservabilityPanelProps { | |
| observability: Observability | null; | |
| loading?: boolean; | |
| error?: string | null; | |
| } | |
| export function ObservabilityPanel({ observability, loading, error }: ObservabilityPanelProps) { | |
| if (loading) return <LoadingState label="Loading observability" />; | |
| if (error) return <ErrorState title="Observability unavailable" message={error} />; | |
| if (!observability) return <EmptyState title="No observability yet" description="It appears after an AI answer completes." />; | |
| return ( | |
| <section className="space-y-4"> | |
| <div className="flex items-center gap-2"> | |
| <Activity className="h-4 w-4 text-slate-600" /> | |
| <h3 className="text-sm font-semibold text-slate-900">Observability</h3> | |
| </div> | |
| {observability.planning && ( | |
| <div className="rounded-lg border border-slate-200 bg-white p-3"> | |
| <div className="mb-2 flex items-center gap-2 text-xs font-semibold uppercase tracking-wide text-slate-500"> | |
| <ListChecks className="h-3.5 w-3.5" /> Planning | |
| </div> | |
| {observability.planning.goal_restated && <p className="text-sm leading-6 text-slate-700">{observability.planning.goal_restated}</p>} | |
| {observability.planning.steps && observability.planning.steps.length > 0 && ( | |
| <ol className="mt-2 space-y-1 text-xs text-slate-600"> | |
| {observability.planning.steps.map((step, index) => ( | |
| <li key={`${step.stage}-${index}`}>{step.step ?? index + 1}. {step.objective ?? step.stage}</li> | |
| ))} | |
| </ol> | |
| )} | |
| </div> | |
| )} | |
| {observability.thinking && ( | |
| <div className="rounded-lg border border-slate-200 bg-white p-3"> | |
| <p className="text-xs font-semibold uppercase tracking-wide text-slate-500">Thinking summary</p> | |
| <p className="mt-2 text-sm leading-6 text-slate-700">{observability.thinking}</p> | |
| </div> | |
| )} | |
| <div className="rounded-lg border border-slate-200 bg-white p-3"> | |
| <div className="mb-2 flex items-center gap-2 text-xs font-semibold uppercase tracking-wide text-slate-500"> | |
| <Wrench className="h-3.5 w-3.5" /> Tool calls | |
| </div> | |
| {observability.tool_calls.length === 0 ? ( | |
| <p className="text-xs text-slate-500">No tools were used.</p> | |
| ) : ( | |
| <div className="space-y-2"> | |
| {observability.tool_calls.map((tool, index) => ( | |
| <div key={`${tool.name}-${index}`} className="rounded-md bg-slate-50 px-3 py-2"> | |
| <p className="text-sm font-medium text-slate-800">{tool.name}</p> | |
| <p className="text-xs text-slate-500">{tool.status ?? "completed"}</p> | |
| </div> | |
| ))} | |
| </div> | |
| )} | |
| </div> | |
| <div className="rounded-lg border border-slate-200 bg-white p-3"> | |
| <div className="mb-2 flex items-center gap-2 text-xs font-semibold uppercase tracking-wide text-slate-500"> | |
| <Database className="h-3.5 w-3.5" /> Sources | |
| </div> | |
| {observability.sources.length === 0 ? ( | |
| <p className="text-xs text-slate-500">No sources attached.</p> | |
| ) : ( | |
| <pre className="max-h-44 overflow-auto rounded-md bg-slate-950 p-3 text-[11px] leading-5 text-slate-100"> | |
| {JSON.stringify(observability.sources, null, 2)} | |
| </pre> | |
| )} | |
| </div> | |
| </section> | |
| ); | |
| } | |