@invergent/agent-chat-react 1.6.8 → 1.7.0

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,5 +1,5 @@
1
1
  import { cn } from './chunk-QSC4UIVT.js';
2
- import { createContext, memo, useRef, useState, useEffect, useCallback, useMemo, lazy, useContext, Suspense, Children } from 'react';
2
+ import { createContext, memo, useRef, useEffect, useCallback, useMemo, useState, lazy, useContext, Suspense, Children } from 'react';
3
3
  import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, ChevronRightIcon, GitBranchIcon, XIcon, ThumbsUpIcon, ThumbsDownIcon, ActivityIcon, Loader2Icon, EyeIcon, GlobeIcon, CheckIcon, SearchIcon, ListTodoIcon, XCircleIcon, CheckCircle2Icon, Code, CopyIcon, TerminalIcon, Trash2Icon, CircleDotIcon, CircleCheckIcon, CircleXIcon, SkullIcon, ClockIcon, CheckCircleIcon, CircleIcon, InboxIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, FolderIcon, FileIcon, ChevronLeftIcon, MinusIcon, PlusIcon, CornerDownLeftIcon } from 'lucide-react';
4
4
  import { cva } from 'class-variance-authority';
5
5
  import { Collapsible as Collapsible$1, Slot, Dialog as Dialog$1, ScrollArea as ScrollArea$1, Tooltip as Tooltip$1, Tabs as Tabs$1, Popover as Popover$1, DropdownMenu as DropdownMenu$1, HoverCard as HoverCard$1, Progress as Progress$1 } from 'radix-ui';
@@ -703,8 +703,7 @@ var useReasoning = () => {
703
703
  }
704
704
  return context;
705
705
  };
706
- var AUTO_CLOSE_DELAY = 1e3;
707
- var AUTO_OPEN_DELAY = 100;
706
+ var MIN_DURATION_MS = 100;
708
707
  var MS_IN_S = 1e3;
709
708
  var Reasoning = memo(
710
709
  ({
@@ -718,7 +717,6 @@ var Reasoning = memo(
718
717
  ...props
719
718
  }) => {
720
719
  const resolvedDefaultOpen = defaultOpen ?? false;
721
- const isExplicitlyClosed = defaultOpen === false;
722
720
  const [isOpen, setIsOpen] = useControllableState({
723
721
  defaultProp: resolvedDefaultOpen,
724
722
  onChange: onOpenChange,
@@ -728,8 +726,6 @@ var Reasoning = memo(
728
726
  defaultProp: void 0,
729
727
  prop: durationProp
730
728
  });
731
- const hasEverStreamedRef = useRef(false);
732
- const [hasAutoClosed, setHasAutoClosed] = useState(false);
733
729
  const startTimeRef = useRef(null);
734
730
  useEffect(() => {
735
731
  if (isStreaming) {
@@ -739,29 +735,11 @@ var Reasoning = memo(
739
735
  } else if (startTimeRef.current !== null) {
740
736
  const elapsed = Date.now() - startTimeRef.current;
741
737
  startTimeRef.current = null;
742
- if (elapsed >= AUTO_OPEN_DELAY) {
743
- hasEverStreamedRef.current = true;
738
+ if (elapsed >= MIN_DURATION_MS) {
744
739
  setDuration(Math.ceil(elapsed / MS_IN_S));
745
740
  }
746
741
  }
747
742
  }, [isStreaming, setDuration]);
748
- useEffect(() => {
749
- if (!isStreaming || isOpen || isExplicitlyClosed) return;
750
- const timer = setTimeout(() => {
751
- hasEverStreamedRef.current = true;
752
- setIsOpen(true);
753
- }, AUTO_OPEN_DELAY);
754
- return () => clearTimeout(timer);
755
- }, [isStreaming, isOpen, setIsOpen, isExplicitlyClosed]);
756
- useEffect(() => {
757
- if (hasEverStreamedRef.current && !isStreaming && isOpen && !hasAutoClosed) {
758
- const timer = setTimeout(() => {
759
- setIsOpen(false);
760
- setHasAutoClosed(true);
761
- }, AUTO_CLOSE_DELAY);
762
- return () => clearTimeout(timer);
763
- }
764
- }, [isStreaming, isOpen, setIsOpen, hasAutoClosed]);
765
743
  const handleOpenChange = useCallback(
766
744
  (newOpen) => {
767
745
  setIsOpen(newOpen);
@@ -1183,7 +1161,7 @@ function TerminalCollapsible({ command, output, isRunning, hasError }) {
1183
1161
  className: "not-prose w-full",
1184
1162
  children: [
1185
1163
  /* @__PURE__ */ jsxs(CollapsibleTrigger, { className: "group/trigger flex w-fit items-center gap-2 text-sm transition-colors", children: [
1186
- /* @__PURE__ */ jsx("span", { className: "text-left", children: isRunning ? /* @__PURE__ */ jsx(Shimmer, { as: "span", duration: 1, children: "Running command..." }) : hasError ? /* @__PURE__ */ jsx("span", { className: "font-semibold text-destructive", children: "Command failed" }) : /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "Command result" }) }),
1164
+ /* @__PURE__ */ jsx("span", { className: "text-left", children: isRunning ? /* @__PURE__ */ jsx(Shimmer, { as: "span", duration: 1, children: "Running command..." }) : hasError ? /* @__PURE__ */ jsx("span", { className: "font-semibold text-destructive", children: "Command failed" }) : /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "Command" }) }),
1187
1165
  /* @__PURE__ */ jsx(
1188
1166
  ChevronDownIcon,
1189
1167
  {
@@ -1234,14 +1212,16 @@ function TerminalToolBlock({ tc }) {
1234
1212
  const isRunning = tc.status === "running";
1235
1213
  const result = parseTerminalResult(tc.result, tc.args);
1236
1214
  if (result) {
1237
- const output = result.output || result.error || "";
1215
+ const hasError = result.exit_code !== 0 || Boolean(result.error);
1216
+ if (hasError) return null;
1217
+ const output = result.output || "";
1238
1218
  return /* @__PURE__ */ jsx(
1239
1219
  TerminalCollapsible,
1240
1220
  {
1241
1221
  command: result.command,
1242
1222
  output,
1243
1223
  isRunning,
1244
- hasError: result.exit_code !== 0 || Boolean(result.error)
1224
+ hasError: false
1245
1225
  }
1246
1226
  );
1247
1227
  }
@@ -6384,6 +6364,10 @@ function messageToEntries(msg, isLast, artifactFallbacks) {
6384
6364
  });
6385
6365
  continue;
6386
6366
  }
6367
+ if (tc.toolName === "terminal" && tc.status !== "running") {
6368
+ const parsed = parseTerminalResult(tc.result, tc.args);
6369
+ if (parsed && (parsed.exit_code !== 0 || parsed.error)) continue;
6370
+ }
6387
6371
  entries.push({ kind: "tool", key: tc.id, tc });
6388
6372
  }
6389
6373
  }
@@ -9059,7 +9043,7 @@ function AgentChat({
9059
9043
  "div",
9060
9044
  {
9061
9045
  "data-testid": "workspace-panel-frame",
9062
- className: hasBrowserPanel ? "h-1/2 min-h-0 w-full overflow-hidden" : "min-h-0",
9046
+ className: hasBrowserPanel ? "h-1/2 min-h-0 w-full overflow-hidden" : "min-h-0 h-full",
9063
9047
  children: /* @__PURE__ */ jsx(
9064
9048
  WorkspacePanel,
9065
9049
  {
@@ -9776,10 +9760,11 @@ function formatKind(value) {
9776
9760
  if (!value) return "Scheduled";
9777
9761
  return value.split(/[_-]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
9778
9762
  }
9779
- function formatRelative2(value, label) {
9763
+ function formatRelative2(value, label, future = false) {
9780
9764
  if (!value) return null;
9781
9765
  const date = new Date(value);
9782
9766
  if (Number.isNaN(date.getTime())) return null;
9767
+ if (future && date.getTime() <= Date.now()) return `${label} due now`;
9783
9768
  return `${label} ${formatDistanceToNow(date, { addSuffix: true })}`;
9784
9769
  }
9785
9770
  function formatRuns(count) {
@@ -9826,10 +9811,10 @@ function ScheduledWorkRow({
9826
9811
  const lastSessionId = item.lastSessionId ?? null;
9827
9812
  const meta = [
9828
9813
  scheduleDisplay(item),
9829
- formatRelative2(item.nextRunAt, "Next"),
9814
+ formatRelative2(item.nextRunAt, "Next", true),
9830
9815
  formatRelative2(item.lastRunAt, "Last"),
9831
9816
  formatRuns(item.runCount),
9832
- item.expiresAt ? formatRelative2(item.expiresAt, "Expires") : null
9817
+ item.expiresAt ? formatRelative2(item.expiresAt, "Expires", true) : null
9833
9818
  ].filter(Boolean);
9834
9819
  const openLastRun = () => {
9835
9820
  if (lastSessionId) onOpenLastRun(lastSessionId);
@@ -10180,8 +10165,7 @@ function TreeNodeRow({
10180
10165
  const title = entry.title ?? fallbackSessionTitle(entry);
10181
10166
  const subtitle = [
10182
10167
  formatRunKind(entry.runKind),
10183
- entry.agentType,
10184
- entry.model ?? "default",
10168
+ entry.model ?? entry.agentType,
10185
10169
  formatSessionTime(entry.updatedAt)
10186
10170
  ].filter(Boolean).join(" \xB7 ");
10187
10171
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -10236,7 +10220,10 @@ function TreeNodeRow({
10236
10220
  "button",
10237
10221
  {
10238
10222
  type: "button",
10239
- className: "p-1 rounded opacity-0 group-hover:opacity-100 focus-visible:opacity-100 hover:bg-destructive/10 hover:text-destructive disabled:pointer-events-none disabled:opacity-50 transition-all",
10223
+ className: cn(
10224
+ "p-1 rounded hover:bg-destructive/10 hover:text-destructive disabled:pointer-events-none transition-all",
10225
+ deletingSessionId === entry.id ? "opacity-100" : "opacity-0 group-hover:opacity-100 focus-visible:opacity-100"
10226
+ ),
10240
10227
  onClick: (e) => {
10241
10228
  e.stopPropagation();
10242
10229
  onDelete(entry.id);
@@ -10244,7 +10231,7 @@ function TreeNodeRow({
10244
10231
  "aria-label": "Delete session",
10245
10232
  title: "Delete session",
10246
10233
  disabled: deletingSessionId === entry.id,
10247
- children: /* @__PURE__ */ jsx(Trash2Icon, { className: "w-3 h-3" })
10234
+ children: deletingSessionId === entry.id ? /* @__PURE__ */ jsx(Loader2Icon, { className: "w-3 h-3 animate-spin" }) : /* @__PURE__ */ jsx(Trash2Icon, { className: "w-3 h-3" })
10248
10235
  }
10249
10236
  )
10250
10237
  ]