@invergent/agent-chat-react 2.13.2 → 2.13.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { cn, __publicField } from './chunk-47MF6JUW.js';
2
2
  import { createContext, memo, useRef, useEffect, useCallback, useMemo, useState, useLayoutEffect, forwardRef, useId, lazy, useContext, useSyncExternalStore, Fragment as Fragment$1, Children, Suspense } from 'react';
3
- import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, CreditCard, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, PlugZapIcon, ChevronRightIcon, ArrowLeftIcon, Loader2Icon, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, ChevronLeftIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, CheckIcon, Clock, ArrowRight, ListTreeIcon, TerminalIcon, SparklesIcon, ClockIcon, PaperclipIcon, CloudIcon, HardDriveIcon, GlobeIcon, FolderIcon, IdCardIcon, PlusIcon, CopyIcon, FileIcon, MinusIcon, SearchIcon, CircleDot, XCircle, CheckCircle2, ArrowUpIcon, CircleCheckIcon, ThumbsUpIcon, ThumbsDownIcon, BookOpenIcon, GitBranchIcon, ActivityIcon, EyeIcon, ListTodoIcon, BotIcon, ListIcon, PenLineIcon, FileEditIcon, WrenchIcon, FileCodeIcon, CodeIcon, FileArchiveIcon, FileVideoIcon, FileAudioIcon, FileImageIcon, FileChartLineIcon, FileSpreadsheetIcon, XCircleIcon, CheckCircle2Icon, Code, CircleXIcon, SkullIcon, CheckCircleIcon, CircleIcon } from 'lucide-react';
3
+ import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, CreditCard, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, PlugZapIcon, ChevronRightIcon, ArrowLeftIcon, Loader2Icon, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, ChevronLeftIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, CheckIcon, Clock, ArrowRight, ListTreeIcon, TerminalIcon, SparklesIcon, ClockIcon, PaperclipIcon, CloudIcon, HardDriveIcon, GlobeIcon, FolderIcon, IdCardIcon, PlusIcon, ShrinkIcon, CopyIcon, FileIcon, MinusIcon, SearchIcon, CircleDot, XCircle, CheckCircle2, ArrowUpIcon, CircleCheckIcon, ThumbsUpIcon, ThumbsDownIcon, BookOpenIcon, GitBranchIcon, ActivityIcon, EyeIcon, ListTodoIcon, BotIcon, ListIcon, PenLineIcon, FileEditIcon, WrenchIcon, FileCodeIcon, CodeIcon, FileArchiveIcon, FileVideoIcon, FileAudioIcon, FileImageIcon, FileChartLineIcon, FileSpreadsheetIcon, XCircleIcon, CheckCircle2Icon, Code, CircleXIcon, SkullIcon, CheckCircleIcon, CircleIcon } from 'lucide-react';
4
4
  import { cva } from 'class-variance-authority';
5
5
  import { Collapsible as Collapsible$1, Slot, Tooltip as Tooltip$1, Progress as Progress$1, Tabs as Tabs$1, Dialog as Dialog$1, ScrollArea as ScrollArea$1, Popover as Popover$1 } from 'radix-ui';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -17,7 +17,7 @@ import { diffLines, diffWordsWithSpace } from 'diff';
17
17
  import AnsiImport from 'ansi-to-react';
18
18
  import { Command as Command$1 } from 'cmdk';
19
19
  import { nanoid } from 'nanoid';
20
- import { getUsage } from 'tokenlens';
20
+ import 'tokenlens';
21
21
  import 'pdfjs-dist/web/pdf_viewer.css';
22
22
  import { formatDistanceToNow } from 'date-fns';
23
23
 
@@ -841,36 +841,6 @@ var ConversationScrollButton = ({
841
841
  }
842
842
  );
843
843
  };
844
- var buttonGroupVariants = cva(
845
- "group/button-group flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 *:data-[slot=input]:px-4 has-[>[data-variant=outline]]:*:data-[slot=input-group]:border-border has-[>[data-variant=outline]]:*:data-[slot=input-group]:px-2.5 has-[>[data-variant=outline]]:*:data-[slot=select-trigger]:border-border has-[>[data-variant=outline]]:*:[[role=combobox]]:px-2.5 has-[>[data-variant=outline]]:[&>[data-slot=input-group]:has(:focus-visible)]:border-ring has-[>[data-variant=outline]]:[&>[data-slot=select-trigger]:focus-visible]:border-ring has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-none [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[>[data-variant=outline]]:[&>input]:border-border has-[>[data-variant=outline]]:[&>input:focus-visible]:border-ring",
846
- {
847
- variants: {
848
- orientation: {
849
- horizontal: "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-none!",
850
- vertical: "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-none!"
851
- }
852
- },
853
- defaultVariants: {
854
- orientation: "horizontal"
855
- }
856
- }
857
- );
858
- function ButtonGroup({
859
- className,
860
- orientation,
861
- ...props
862
- }) {
863
- return /* @__PURE__ */ jsx(
864
- "div",
865
- {
866
- role: "group",
867
- "data-slot": "button-group",
868
- "data-orientation": orientation,
869
- className: cn(buttonGroupVariants({ orientation }), className),
870
- ...props
871
- }
872
- );
873
- }
874
844
 
875
845
  // src/lib/oauth-popup.ts
876
846
  function openOAuthPopup(url) {
@@ -8173,7 +8143,7 @@ var PromptInput = ({
8173
8143
  onSubmit: handleSubmit,
8174
8144
  ref: formRef,
8175
8145
  ...props,
8176
- children: /* @__PURE__ */ jsx(BrandBeam, { size: "line", active: beamActive, strength: 0.7, borderRadius: 24, children: /* @__PURE__ */ jsx(InputGroup, { className: "overflow-hidden rounded-3xl border border-input bg-white px-4 py-2 shadow-sm dark:bg-card dark:shadow-none dark:ring-1 dark:ring-white/5 has-[textarea]:rounded-3xl has-[>[data-align=block-end]]:rounded-3xl has-[>[data-align=block-start]]:rounded-3xl", children }) })
8146
+ children: /* @__PURE__ */ jsx(BrandBeam, { size: "line", active: beamActive, strength: 0.7, children: /* @__PURE__ */ jsx(InputGroup, { className: "overflow-hidden rounded-3xl border border-input bg-white px-4 py-2 shadow-sm dark:bg-card dark:shadow-none dark:ring-1 dark:ring-white/5 has-[textarea]:rounded-3xl has-data-[align=block-end]:rounded-3xl has-data-[align=block-start]:rounded-3xl has-[>[data-align=block-end]]:rounded-3xl has-[>[data-align=block-start]]:rounded-3xl", children }) })
8177
8147
  }
8178
8148
  )
8179
8149
  ] });
@@ -8430,6 +8400,7 @@ function Progress({
8430
8400
  );
8431
8401
  }
8432
8402
  var PERCENT_MAX = 100;
8403
+ var NEARLY_FULL = 0.9;
8433
8404
  var ICON_RADIUS = 10;
8434
8405
  var ICON_VIEWBOX = 24;
8435
8406
  var ICON_CENTER = 12;
@@ -8522,167 +8493,50 @@ var ContextContentHeader = ({
8522
8493
  const total = new Intl.NumberFormat("en-US", {
8523
8494
  notation: "compact"
8524
8495
  }).format(maxTokens);
8525
- return /* @__PURE__ */ jsx("div", { className: cn("w-full space-y-2 p-3", className), ...props, children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
8526
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 text-xs", children: [
8527
- /* @__PURE__ */ jsx("p", { children: displayPct }),
8528
- /* @__PURE__ */ jsxs("p", { className: " text-muted-foreground", children: [
8496
+ const nearlyFull = usedPercent >= NEARLY_FULL;
8497
+ return /* @__PURE__ */ jsx("div", { className: cn("w-full space-y-2 px-3 py-2.5", className), ...props, children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
8498
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-3", children: [
8499
+ /* @__PURE__ */ jsx(
8500
+ "p",
8501
+ {
8502
+ className: cn(
8503
+ "text-sm font-medium tabular-nums",
8504
+ nearlyFull && "text-destructive"
8505
+ ),
8506
+ children: displayPct
8507
+ }
8508
+ ),
8509
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground tabular-nums", children: [
8529
8510
  used,
8530
8511
  " / ",
8531
8512
  total
8532
8513
  ] })
8533
8514
  ] }),
8534
- /* @__PURE__ */ jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsx(Progress, { className: "bg-muted", value: usedPercent * PERCENT_MAX }) })
8515
+ /* @__PURE__ */ jsx(
8516
+ Progress,
8517
+ {
8518
+ className: cn(
8519
+ // The primitive only clips its x-axis, which leaves the fill's
8520
+ // square end poking out of the pill at both ends.
8521
+ "h-1 overflow-hidden rounded-full bg-muted",
8522
+ // Amber, not `bg-primary`: primary is the host app's colour, and
8523
+ // the two hosts disagree — the agent web app is amber, Studio is
8524
+ // near-black — so the same bar came out black beside a Send
8525
+ // button the composer hardcodes amber. This is the composer's
8526
+ // own accent, so it reads the same wherever it is embedded.
8527
+ "[&>[data-slot=progress-indicator]]:bg-amber-500",
8528
+ nearlyFull && "[&>[data-slot=progress-indicator]]:bg-destructive"
8529
+ ),
8530
+ value: usedPercent * PERCENT_MAX
8531
+ }
8532
+ )
8535
8533
  ] }) });
8536
8534
  };
8537
8535
  var ContextContentBody = ({
8538
8536
  children,
8539
8537
  className,
8540
8538
  ...props
8541
- }) => /* @__PURE__ */ jsx("div", { className: cn("w-full p-3", className), ...props, children });
8542
- var TokensWithCost = ({
8543
- tokens,
8544
- costText
8545
- }) => /* @__PURE__ */ jsxs("span", { children: [
8546
- tokens === void 0 ? "\u2014" : new Intl.NumberFormat("en-US", {
8547
- notation: "compact"
8548
- }).format(tokens),
8549
- costText ? /* @__PURE__ */ jsxs("span", { className: "ml-2 text-muted-foreground", children: [
8550
- "\u2022 ",
8551
- costText
8552
- ] }) : null
8553
- ] });
8554
- var ContextInputUsage = ({
8555
- className,
8556
- children,
8557
- ...props
8558
- }) => {
8559
- const { usage, modelId } = useContextValue();
8560
- const inputTokens = usage?.inputTokens ?? 0;
8561
- if (children) {
8562
- return children;
8563
- }
8564
- if (!inputTokens) {
8565
- return null;
8566
- }
8567
- const inputCost = modelId ? getUsage({
8568
- modelId,
8569
- usage: { input: inputTokens, output: 0 }
8570
- }).costUSD?.totalUSD : void 0;
8571
- const inputCostText = new Intl.NumberFormat("en-US", {
8572
- currency: "USD",
8573
- style: "currency"
8574
- }).format(inputCost ?? 0);
8575
- return /* @__PURE__ */ jsxs(
8576
- "div",
8577
- {
8578
- className: cn("flex items-center justify-between text-xs", className),
8579
- ...props,
8580
- children: [
8581
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Input" }),
8582
- /* @__PURE__ */ jsx(TokensWithCost, { costText: inputCostText, tokens: inputTokens })
8583
- ]
8584
- }
8585
- );
8586
- };
8587
- var ContextOutputUsage = ({
8588
- className,
8589
- children,
8590
- ...props
8591
- }) => {
8592
- const { usage, modelId } = useContextValue();
8593
- const outputTokens = usage?.outputTokens ?? 0;
8594
- if (children) {
8595
- return children;
8596
- }
8597
- if (!outputTokens) {
8598
- return null;
8599
- }
8600
- const outputCost = modelId ? getUsage({
8601
- modelId,
8602
- usage: { input: 0, output: outputTokens }
8603
- }).costUSD?.totalUSD : void 0;
8604
- const outputCostText = new Intl.NumberFormat("en-US", {
8605
- currency: "USD",
8606
- style: "currency"
8607
- }).format(outputCost ?? 0);
8608
- return /* @__PURE__ */ jsxs(
8609
- "div",
8610
- {
8611
- className: cn("flex items-center justify-between text-xs", className),
8612
- ...props,
8613
- children: [
8614
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Output" }),
8615
- /* @__PURE__ */ jsx(TokensWithCost, { costText: outputCostText, tokens: outputTokens })
8616
- ]
8617
- }
8618
- );
8619
- };
8620
- var ContextReasoningUsage = ({
8621
- className,
8622
- children,
8623
- ...props
8624
- }) => {
8625
- const { usage, modelId } = useContextValue();
8626
- const reasoningTokens = usage?.reasoningTokens ?? 0;
8627
- if (children) {
8628
- return children;
8629
- }
8630
- if (!reasoningTokens) {
8631
- return null;
8632
- }
8633
- const reasoningCost = modelId ? getUsage({
8634
- modelId,
8635
- usage: { reasoningTokens }
8636
- }).costUSD?.totalUSD : void 0;
8637
- const reasoningCostText = new Intl.NumberFormat("en-US", {
8638
- currency: "USD",
8639
- style: "currency"
8640
- }).format(reasoningCost ?? 0);
8641
- return /* @__PURE__ */ jsxs(
8642
- "div",
8643
- {
8644
- className: cn("flex items-center justify-between text-xs", className),
8645
- ...props,
8646
- children: [
8647
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Reasoning" }),
8648
- /* @__PURE__ */ jsx(TokensWithCost, { costText: reasoningCostText, tokens: reasoningTokens })
8649
- ]
8650
- }
8651
- );
8652
- };
8653
- var ContextCacheUsage = ({
8654
- className,
8655
- children,
8656
- ...props
8657
- }) => {
8658
- const { usage, modelId } = useContextValue();
8659
- const cacheTokens = usage?.cachedInputTokens ?? 0;
8660
- if (children) {
8661
- return children;
8662
- }
8663
- if (!cacheTokens) {
8664
- return null;
8665
- }
8666
- const cacheCost = modelId ? getUsage({
8667
- modelId,
8668
- usage: { cacheReads: cacheTokens, input: 0, output: 0 }
8669
- }).costUSD?.totalUSD : void 0;
8670
- const cacheCostText = new Intl.NumberFormat("en-US", {
8671
- currency: "USD",
8672
- style: "currency"
8673
- }).format(cacheCost ?? 0);
8674
- return /* @__PURE__ */ jsxs(
8675
- "div",
8676
- {
8677
- className: cn("flex items-center justify-between text-xs", className),
8678
- ...props,
8679
- children: [
8680
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Cache" }),
8681
- /* @__PURE__ */ jsx(TokensWithCost, { costText: cacheCostText, tokens: cacheTokens })
8682
- ]
8683
- }
8684
- );
8685
- };
8539
+ }) => /* @__PURE__ */ jsx("div", { className: cn("w-full space-y-1.5 px-3 py-2.5", className), ...props, children });
8686
8540
  var itemVariants = cva(
8687
8541
  "group/item flex w-full flex-wrap items-center rounded-none border text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
8688
8542
  {
@@ -9082,6 +8936,20 @@ function SkillsEmptyState() {
9082
8936
  ] });
9083
8937
  }
9084
8938
  var TOOLS_ITEM_CLASS = "gap-3 rounded-md px-3 py-2 pointer-coarse:min-h-11 pointer-coarse:text-[15px]";
8939
+ var VIEW_MODE_SEGMENTS = [
8940
+ {
8941
+ mode: "simple",
8942
+ label: "Simple",
8943
+ icon: MessageSquareIcon,
8944
+ tooltip: "Simple \u2014 just the conversation"
8945
+ },
8946
+ {
8947
+ mode: "expert",
8948
+ label: "Advanced",
8949
+ icon: ListTreeIcon,
8950
+ tooltip: "Advanced \u2014 every step the agent took"
8951
+ }
8952
+ ];
9085
8953
  function ChatComposer(props) {
9086
8954
  return /* @__PURE__ */ jsx(PromptInputProvider, { children: /* @__PURE__ */ jsx(ChatComposerInner, { ...props }) });
9087
8955
  }
@@ -9436,6 +9304,12 @@ function ChatComposerInner({
9436
9304
  );
9437
9305
  const [contextOpen, setContextOpen] = useState(false);
9438
9306
  const contextPercentLabel = tokenUsage?.contextWindow ? `${Math.min(100, Math.round(tokenUsage.totalTokens / tokenUsage.contextWindow * 100))}%` : "0%";
9307
+ const contextBreakdown = tokenUsage ? [
9308
+ { label: "Input", tokens: tokenUsage.inputTokens },
9309
+ { label: "Output", tokens: tokenUsage.outputTokens },
9310
+ ...tokenUsage.reasoningTokens > 0 ? [{ label: "Reasoning", tokens: tokenUsage.reasoningTokens }] : [],
9311
+ ...tokenUsage.cachedInputTokens > 0 ? [{ label: "Cache", tokens: tokenUsage.cachedInputTokens }] : []
9312
+ ] : [];
9439
9313
  const canAttach = !disabled && !awaitingAnswer;
9440
9314
  const showPaneToggles = Boolean(
9441
9315
  canShowBrowser && onToggleBrowser || canShowWorkspace && onToggleWorkspace
@@ -9444,47 +9318,39 @@ function ChatComposerInner({
9444
9318
  browserProfilesEnabled && onSelectBrowserProfile && adapter.listBrowserProfiles
9445
9319
  );
9446
9320
  const showToolsPanel = canAttach || showPaneToggles || canPickProfile;
9447
- const viewModeToggle = onViewModeChange ? /* @__PURE__ */ jsxs(
9448
- ButtonGroup,
9321
+ const viewModeToggle = onViewModeChange ? /* @__PURE__ */ jsx(
9322
+ "div",
9449
9323
  {
9324
+ role: "group",
9450
9325
  "aria-label": "Chat view mode",
9451
- className: "overflow-hidden rounded-full border border-border bg-muted/40 p-0.5",
9452
- children: [
9453
- /* @__PURE__ */ jsx(
9326
+ className: "flex shrink-0 items-center gap-0.5 rounded-full bg-muted/60 p-0.5",
9327
+ children: VIEW_MODE_SEGMENTS.map(({ mode, label, icon: Icon, tooltip }) => {
9328
+ const selected = viewMode === mode;
9329
+ return /* @__PURE__ */ jsxs(
9454
9330
  PromptInputButton,
9455
9331
  {
9456
- "aria-label": "Simple view",
9457
- "aria-pressed": viewMode === "simple",
9458
- tooltip: "Simple \u2014 just the conversation",
9459
- variant: viewMode === "simple" ? "secondary" : "ghost",
9460
- onClick: () => onViewModeChange("simple"),
9461
- className: cn(
9462
- // 32px is a comfortable segment for a cursor and a miss for a
9463
- // thumb, so touch takes both halves to the 44px floor.
9464
- "size-8 rounded-full pointer-coarse:size-11",
9465
- viewMode === "simple" && "shadow-sm"
9466
- ),
9467
- children: /* @__PURE__ */ jsx(MessageSquareIcon, { className: "size-[18px] pointer-coarse:size-5" })
9468
- }
9469
- ),
9470
- /* @__PURE__ */ jsx(
9471
- PromptInputButton,
9472
- {
9473
- "aria-label": "Advanced view",
9474
- "aria-pressed": viewMode === "expert",
9475
- tooltip: "Advanced \u2014 every step the agent took",
9476
- variant: viewMode === "expert" ? "secondary" : "ghost",
9477
- onClick: () => onViewModeChange("expert"),
9332
+ size: "sm",
9333
+ "aria-label": `${label} view`,
9334
+ "aria-pressed": selected,
9335
+ tooltip,
9336
+ variant: "ghost",
9337
+ onClick: () => onViewModeChange(mode),
9478
9338
  className: cn(
9479
- // 32px is a comfortable segment for a cursor and a miss for a
9480
- // thumb, so touch takes both halves to the 44px floor.
9481
- "size-8 rounded-full pointer-coarse:size-11",
9482
- viewMode === "expert" && "shadow-sm"
9339
+ // Icon-width on a phone, word-width with a cursor; the coarse
9340
+ // bump takes the segment to the 44px touch floor either way.
9341
+ // Words, not the shouted uppercase the button base defaults to —
9342
+ // this is a label on a switch, not a call to action.
9343
+ "h-8 gap-1.5 rounded-full border-0 bg-transparent px-3.5 text-xs font-normal capitalize tracking-normal md:px-3 pointer-coarse:h-11 pointer-coarse:px-5",
9344
+ selected ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:bg-background/60 hover:text-foreground"
9483
9345
  ),
9484
- children: /* @__PURE__ */ jsx(ListTreeIcon, { className: "size-[18px] pointer-coarse:size-5" })
9485
- }
9486
- )
9487
- ]
9346
+ children: [
9347
+ /* @__PURE__ */ jsx(Icon, { className: "size-4 md:hidden" }),
9348
+ /* @__PURE__ */ jsx("span", { className: "hidden md:inline", children: label })
9349
+ ]
9350
+ },
9351
+ mode
9352
+ );
9353
+ })
9488
9354
  }
9489
9355
  ) : null;
9490
9356
  return /* @__PURE__ */ jsxs(
@@ -9701,37 +9567,44 @@ function ChatComposerInner({
9701
9567
  ),
9702
9568
  children: [
9703
9569
  /* @__PURE__ */ jsx(ContextContentHeader, {}),
9704
- /* @__PURE__ */ jsx(ContextContentBody, { children: tokenUsage.totalTokens > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
9705
- /* @__PURE__ */ jsx(ContextInputUsage, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
9706
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Input" }),
9707
- /* @__PURE__ */ jsx("span", { children: tokenUsage.inputTokens.toLocaleString() })
9708
- ] }) }),
9709
- /* @__PURE__ */ jsx(ContextOutputUsage, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
9710
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Output" }),
9711
- /* @__PURE__ */ jsx("span", { children: tokenUsage.outputTokens.toLocaleString() })
9712
- ] }) }),
9713
- tokenUsage.reasoningTokens > 0 && /* @__PURE__ */ jsx(ContextReasoningUsage, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
9714
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Reasoning" }),
9715
- /* @__PURE__ */ jsx("span", { children: tokenUsage.reasoningTokens.toLocaleString() })
9716
- ] }) }),
9717
- tokenUsage.cachedInputTokens > 0 && /* @__PURE__ */ jsx(ContextCacheUsage, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
9718
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Cache" }),
9719
- /* @__PURE__ */ jsx("span", { children: tokenUsage.cachedInputTokens.toLocaleString() })
9720
- ] }) })
9721
- ] }) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground text-center py-1", children: "Empty" }) }),
9722
- tokenUsage.totalTokens > 0 && /* @__PURE__ */ jsx("div", { className: "flex w-full items-center justify-end gap-3 bg-secondary p-2", children: /* @__PURE__ */ jsx(
9723
- Button,
9570
+ /* @__PURE__ */ jsx(ContextContentBody, { children: tokenUsage.totalTokens > 0 ? contextBreakdown.map(({ label, tokens }) => /* @__PURE__ */ jsxs(
9571
+ "div",
9724
9572
  {
9725
- type: "button",
9726
- size: "xs",
9727
- className: "pointer-coarse:h-11 pointer-coarse:px-4 pointer-coarse:text-sm",
9728
- onClick: () => {
9729
- setContextOpen(false);
9730
- onSend("/compress");
9731
- },
9732
- children: "Compress"
9733
- }
9734
- ) })
9573
+ className: "flex items-center justify-between gap-4 text-xs",
9574
+ children: [
9575
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
9576
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: tokens.toLocaleString() })
9577
+ ]
9578
+ },
9579
+ label
9580
+ )) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground text-center py-1", children: "Empty" }) }),
9581
+ tokenUsage.totalTokens > 0 && // The action the panel exists for, so it gets the panel's
9582
+ // width rather than a filled block shoved into the corner
9583
+ // of a grey bar — that bar was a second surface inside a
9584
+ // small popover, squaring its own corners off against the
9585
+ // rounded ones around it. It keeps a rule of its own
9586
+ // because the sheet form has no divide-y, and the one
9587
+ // division worth drawing is between reading and acting.
9588
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 border-t border-border px-3 py-2.5", children: [
9589
+ /* @__PURE__ */ jsxs(
9590
+ Button,
9591
+ {
9592
+ type: "button",
9593
+ size: "sm",
9594
+ variant: "outline",
9595
+ className: "w-full",
9596
+ onClick: () => {
9597
+ setContextOpen(false);
9598
+ onSend("/compress");
9599
+ },
9600
+ children: [
9601
+ /* @__PURE__ */ jsx(ShrinkIcon, {}),
9602
+ "Compress"
9603
+ ]
9604
+ }
9605
+ ),
9606
+ /* @__PURE__ */ jsx("p", { className: "text-center text-[11px] leading-snug text-muted-foreground", children: "Sums up the thread to free the window" })
9607
+ ] })
9735
9608
  ]
9736
9609
  }
9737
9610
  )