@invergent/agent-chat-react 1.4.10 → 1.4.11

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
@@ -18,6 +18,7 @@ import Ansi from 'ansi-to-react';
18
18
  import { getUsage } from 'tokenlens';
19
19
  import { Command as Command$1 } from 'cmdk';
20
20
  import { nanoid } from 'nanoid';
21
+ import { formatDistanceToNow } from 'date-fns';
21
22
 
22
23
  // src/agent-chat.tsx
23
24
  var AgentChatAdapterContext = createContext(null);
@@ -7822,17 +7823,10 @@ function mergeTreeNodes(groups) {
7822
7823
  }
7823
7824
  return Array.from(byId.values());
7824
7825
  }
7825
- function statusColor(status) {
7826
- switch (status) {
7827
- case "active":
7828
- return "default";
7829
- case "completed":
7830
- return "secondary";
7831
- case "failed":
7832
- return "destructive";
7833
- default:
7834
- return "outline";
7835
- }
7826
+ function formatSessionTime(value) {
7827
+ const date = new Date(value);
7828
+ if (Number.isNaN(date.getTime())) return "";
7829
+ return formatDistanceToNow(date, { addSuffix: true });
7836
7830
  }
7837
7831
  function TreeNodeRow({
7838
7832
  entry,
@@ -7849,6 +7843,11 @@ function TreeNodeRow({
7849
7843
  const hasChildren = entry.children.length > 0;
7850
7844
  const isActive = entry.id === activeSessionId;
7851
7845
  const isRunning = entry.status === "active";
7846
+ const title = entry.title ?? "New session";
7847
+ const subtitle = [
7848
+ entry.model ?? "default",
7849
+ formatSessionTime(entry.updatedAt)
7850
+ ].filter(Boolean).join(" \xB7 ");
7852
7851
  return /* @__PURE__ */ jsxs(Fragment, { children: [
7853
7852
  /* @__PURE__ */ jsxs(
7854
7853
  "div",
@@ -7860,16 +7859,16 @@ function TreeNodeRow({
7860
7859
  if (e.key === "Enter" || e.key === " ") onSelect(entry.id);
7861
7860
  },
7862
7861
  className: cn(
7863
- "group flex items-center gap-1.5 py-1.5 pr-1 rounded cursor-pointer text-sm transition-colors",
7864
- isActive ? "bg-line text-foreground" : "hover:bg-input text-subtle hover:text-foreground"
7862
+ "group flex items-center gap-2 w-full py-2 pr-2 text-left cursor-pointer transition-colors border-l-2",
7863
+ isActive ? "bg-line text-foreground border-l-primary" : "bg-transparent text-subtle hover:bg-input hover:text-foreground border-l-transparent"
7865
7864
  ),
7866
- style: { paddingLeft: `${depth * 12 + 4}px` },
7865
+ style: { paddingLeft: `${depth * 12 + 12}px` },
7867
7866
  children: [
7868
7867
  hasChildren ? /* @__PURE__ */ jsx(
7869
7868
  "button",
7870
7869
  {
7871
7870
  type: "button",
7872
- className: "p-0.5 rounded hover:bg-line",
7871
+ className: "p-0.5 rounded hover:bg-line shrink-0",
7873
7872
  onClick: (e) => {
7874
7873
  e.stopPropagation();
7875
7874
  setExpanded(!expanded);
@@ -7879,17 +7878,9 @@ function TreeNodeRow({
7879
7878
  children: expanded ? /* @__PURE__ */ jsx(ChevronDownIcon, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ jsx(ChevronRightIcon, { className: "w-3.5 h-3.5" })
7880
7879
  }
7881
7880
  ) : /* @__PURE__ */ jsx("span", { className: "w-4 h-4 shrink-0" }),
7882
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 flex items-center gap-1.5", children: [
7883
- /* @__PURE__ */ jsx("span", { className: "truncate", children: entry.title ?? "session" }),
7884
- entry.agentType && /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "h-4 px-1.5 text-[10px]", children: entry.agentType }),
7885
- /* @__PURE__ */ jsx(
7886
- Badge,
7887
- {
7888
- variant: statusColor(entry.status),
7889
- className: "h-4 px-1.5 text-[10px]",
7890
- children: entry.status
7891
- }
7892
- )
7881
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
7882
+ /* @__PURE__ */ jsx("div", { className: "text-sm truncate", children: title }),
7883
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-faint truncate", children: subtitle })
7893
7884
  ] }),
7894
7885
  isRunning && canStop && /* @__PURE__ */ jsx(
7895
7886
  "button",
@@ -7961,6 +7952,7 @@ function SessionTreePanel({
7961
7952
  const mounted = useRef(true);
7962
7953
  const requestId = useRef(0);
7963
7954
  const lastFingerprint = useRef("");
7955
+ const resetContext = useRef(null);
7964
7956
  const refetch = useCallback(
7965
7957
  async (opts) => {
7966
7958
  const canLoadSessionList = Boolean(agentId && adapter.listSessions);
@@ -8015,12 +8007,17 @@ function SessionTreePanel({
8015
8007
  };
8016
8008
  }, []);
8017
8009
  useEffect(() => {
8018
- setNodes([]);
8010
+ const previous = resetContext.current;
8011
+ const shouldReset = !previous || previous.adapter !== adapter || previous.agentId !== agentId || previous.sessionListLimit !== sessionListLimit;
8012
+ resetContext.current = { adapter, agentId, sessionListLimit };
8013
+ if (shouldReset) {
8014
+ setNodes([]);
8015
+ setHasEverLoaded(false);
8016
+ lastFingerprint.current = "";
8017
+ }
8019
8018
  setError(null);
8020
- setHasEverLoaded(false);
8021
- lastFingerprint.current = "";
8022
8019
  void refetch();
8023
- }, [refetch, sessionId]);
8020
+ }, [adapter, agentId, refetch, sessionListLimit]);
8024
8021
  const runningCount = useMemo(
8025
8022
  () => nodes.filter((n) => n.status === "active").length,
8026
8023
  [nodes]
@@ -8072,12 +8069,23 @@ function SessionTreePanel({
8072
8069
  const topLevel = hideRoot ? roots.flatMap((r) => r.children) : roots;
8073
8070
  if (topLevel.length === 0) return null;
8074
8071
  return /* @__PURE__ */ jsxs("div", { className: "border-t border-line", children: [
8075
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-3 py-2 text-xs font-semibold uppercase tracking-wide text-faint", children: [
8072
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-3 py-2 text-xs font-semibold uppercase tracking-wide", children: [
8076
8073
  /* @__PURE__ */ jsx(UsersIcon, { className: "w-3.5 h-3.5" }),
8077
8074
  /* @__PURE__ */ jsx("span", { children: title }),
8078
8075
  runningCount > 0 && /* @__PURE__ */ jsx(Badge, { variant: "default", className: "h-4 px-1.5 text-[10px] ml-auto", children: runningCount })
8079
8076
  ] }),
8080
- loading && /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs text-faint", children: "Loading..." }),
8077
+ loading && /* @__PURE__ */ jsx(
8078
+ "div",
8079
+ {
8080
+ className: "px-3 py-2",
8081
+ role: "status",
8082
+ "aria-label": "Loading sessions",
8083
+ children: /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
8084
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-28" }),
8085
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-20" })
8086
+ ] })
8087
+ }
8088
+ ),
8081
8089
  error && /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs text-destructive", children: error }),
8082
8090
  !error && /* @__PURE__ */ jsx("div", { className: "px-1 pb-2", children: topLevel.map((entry) => /* @__PURE__ */ jsx(
8083
8091
  TreeNodeRow,