{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "context-breakdown",
  "title": "Context Breakdown",
  "description": "Where an agent context window went, with token attribution and remaining capacity.",
  "dependencies": [
    "cn@^0.3.0"
  ],
  "registryDependencies": [
    "https://pastaui.com/r/pastaui-styles.json"
  ],
  "files": [
    {
      "path": "src/components/ai/context-breakdown.tsx",
      "content": "import * as React from 'react'\n\nimport { cn } from 'cn'\n\ninterface ContextSegment {\n  id: string\n  label: string\n  tokens: number\n}\n\ninterface ContextBreakdownProps extends React.ComponentProps<'section'> {\n  compacting?: boolean\n  limit: number\n  onCompact?: () => void\n  segments: ContextSegment[]\n  warnAt?: number\n}\n\nconst segmentTones = [\n  'bg-sky-500/80 dark:bg-sky-400/70',\n  'bg-violet-500/80 dark:bg-violet-400/70',\n  'bg-amber-500/80 dark:bg-amber-400/70',\n  'bg-teal-500/80 dark:bg-teal-400/70',\n  'bg-rose-500/80 dark:bg-rose-400/70',\n]\n\nfunction ContextBreakdown({\n  className,\n  compacting = false,\n  limit,\n  onCompact,\n  segments,\n  warnAt = 0.8,\n  ...props\n}: ContextBreakdownProps) {\n  const [activeId, setActiveId] = React.useState<string>()\n  const rows = segments.map((segment, index) => ({\n    ...segment,\n    tokens: Number.isFinite(segment.tokens) ? Math.max(0, segment.tokens) : 0,\n    tone: segmentTones[index % segmentTones.length],\n  }))\n  const used = rows.reduce((sum, row) => sum + row.tokens, 0)\n  const capacity = Number.isFinite(limit) ? Math.max(0, limit) : 0\n  const available = Math.max(capacity - used, 0)\n  const total = Math.max(capacity, used)\n  const percentage = (tokens: number) => (total > 0 ? (tokens / total) * 100 : 0)\n  const warning = capacity > 0 && used / capacity >= warnAt\n  const dim = (id: string) => activeId !== undefined && activeId !== id\n\n  return (\n    <section\n      aria-label=\"Context window\"\n      data-slot=\"context-breakdown\"\n      className={cn(\n        'rounded-[16px] bg-card p-5 font-sans text-sm font-[450] tracking-[-0.05px] text-muted-foreground shadow-card',\n        className,\n      )}\n      {...props}\n    >\n      <h3 className=\"text-sm leading-5 font-medium text-muted-foreground\">Context window</h3>\n      <p className=\"mt-1 flex flex-wrap items-baseline gap-x-1.5 tabular-nums\">\n        <span className=\"text-[22px] leading-7 font-medium tracking-[-0.02em] text-foreground\">\n          {used.toLocaleString()} / {capacity.toLocaleString()}\n        </span>\n        <span className=\"text-sm text-muted-foreground\">\n          tokens · {Math.round(percentage(used))}% used\n        </span>\n      </p>\n\n      <div\n        aria-hidden=\"true\"\n        className=\"mt-4 flex h-1.5 overflow-hidden rounded-full bg-foreground/8\"\n      >\n        {rows\n          .filter((row) => row.tokens > 0)\n          .map((row) => (\n            <span\n              className={cn(\n                'h-full shrink-0 border-r border-card transition-[width,opacity] duration-500 ease-[cubic-bezier(0.23,1,0.32,1)] last:border-r-0 motion-reduce:transition-none',\n                row.tone,\n                dim(row.id) && 'opacity-30',\n              )}\n              key={row.id}\n              onPointerEnter={() => setActiveId(row.id)}\n              onPointerLeave={() => setActiveId(undefined)}\n              style={{ width: `${percentage(row.tokens)}%` }}\n            />\n          ))}\n      </div>\n\n      <ul className=\"mt-5 space-y-1 tabular-nums\">\n        {rows.map((row) => (\n          <li\n            className={cn(\n              '-mx-2 flex items-center gap-2.5 rounded-md px-2 py-1 transition-[opacity,background-color] duration-150',\n              activeId === row.id && 'bg-foreground/8',\n              dim(row.id) && 'opacity-50',\n            )}\n            key={row.id}\n            onPointerEnter={() => setActiveId(row.id)}\n            onPointerLeave={() => setActiveId(undefined)}\n          >\n            <span aria-hidden=\"true\" className={cn('size-2 shrink-0 rounded-full', row.tone)} />\n            <span className=\"min-w-0 flex-1 truncate text-foreground/80\">{row.label}</span>\n            <span className=\"text-foreground/80\">{row.tokens.toLocaleString()}</span>\n            <span className=\"w-10 text-right text-muted-foreground/70\">\n              {Math.round(percentage(row.tokens))}%\n            </span>\n          </li>\n        ))}\n        <li className=\"mt-2 flex items-center gap-2.5 border-t border-foreground/8 pt-3\">\n          <span\n            aria-hidden=\"true\"\n            className=\"size-2 shrink-0 rounded-full ring-1 ring-muted-foreground/60 ring-inset\"\n          />\n          <span className=\"min-w-0 flex-1 truncate\">Available</span>\n          <span>{available.toLocaleString()}</span>\n          <span className=\"w-10 text-right text-muted-foreground/70\">\n            {Math.round(percentage(available))}%\n          </span>\n        </li>\n      </ul>\n      <div\n        aria-live=\"polite\"\n        className={cn(\n          'grid transition-[grid-template-rows,opacity] duration-300 ease-[cubic-bezier(0.23,1,0.32,1)]',\n          warning || compacting ? 'mt-4 grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0',\n        )}\n      >\n        <div className=\"overflow-hidden\">\n          <div className=\"flex items-center gap-3 rounded-[12px] bg-foreground/8 px-3 py-2.5\">\n            <p className=\"min-w-0 flex-1 text-[13px] leading-5\">\n              {compacting\n                ? 'Summarizing older turns…'\n                : 'Approaching the limit. Older turns can be summarized to free space.'}\n            </p>\n            {onCompact && (\n              <button\n                className=\"h-7 shrink-0 rounded-full bg-card px-3 text-[13px] leading-5 text-foreground/80 transition-[opacity,scale] duration-150 outline-none hover:opacity-80 focus-visible:ring-2 focus-visible:ring-ring/40 active:scale-[0.97] disabled:opacity-50\"\n                disabled={compacting}\n                onClick={onCompact}\n                tabIndex={warning || compacting ? 0 : -1}\n                type=\"button\"\n              >\n                {compacting ? 'Compacting' : 'Compact'}\n              </button>\n            )}\n          </div>\n        </div>\n      </div>\n    </section>\n  )\n}\n\nexport { ContextBreakdown }\nexport type { ContextSegment, ContextBreakdownProps }\n",
      "type": "registry:component",
      "target": "@components/ai/context-breakdown.tsx"
    }
  ],
  "type": "registry:component"
}