Reasoning disclosure
A collapsed panel carrying a one-line summary and a duration. What expands is a summarised trace rather than the raw chain, because 200 words of answer buried under 800 words of working reads worse than the answer alone.
npx shadcn@latest add collapsible button
npm i lucide-react
Tokens this needs: --card, --card-foreground, --muted-foreground, --border
────────────────────────────────────────────────────────────────────────
// ReasoningDisclosure.tsx
────────────────────────────────────────────────────────────────────────
import { useState } from "react";
import { ChevronRight, Square } from "lucide-react";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
type Props = {
/** One line the viewer can read without expanding: enough to catch a
* misread question at second three. The panel prefixes "Working:", never
* "Thinking:"; this is narration produced alongside the answer, not a
* trace of the computation. */
summary: string;
/** The summarised trace, a paragraph per step. Never the raw chain. */
trace: string[];
/** The real one. A duration next to the label does more for trust than any adjective. */
durationMs: number;
/** True while the working is still arriving. Shows stop, because the viewer
* who has spotted a misread should not have to wait for the answer. */
streaming?: boolean;
onStop?: () => void;
/** Collapsed by default. The working runs longer than the answer and matters less. */
defaultOpen?: boolean;
};
const duration = (ms: number) => {
const s = Math.round(ms / 1000);
return s < 60 ? `${s}s` : `${Math.floor(s / 60)}m ${s % 60}s`;
};
export function ReasoningDisclosure({ summary, trace, durationMs, streaming = false, onStop, defaultOpen = false }: Props) {
const [open, setOpen] = useState(defaultOpen);
return (
{step} summarised, not the raw chain
Yes. The break on 28 February 2026 comes a year before the review on 1 March 2027. Notice has to be served by 31 August 2025, with rent paid up and the premises returned empty.